8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-28 03:23:03 +01:00
firebird-mirror/src/qli/dtr.cpp

660 lines
15 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Command Oriented Query Language
* MODULE: dtr.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Top level driving module
2008-12-05 02:20:14 +01:00
*
2001-05-23 15:26:42 +02:00
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
*
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#define QLI_MAIN
2004-04-29 00:36:29 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "../qli/dtr.h"
#include "../qli/parse.h"
#include "../qli/compile.h"
#include "../jrd/perf.h"
#include "../jrd/license.h"
2003-11-08 17:40:17 +01:00
#include "../jrd/ibase.h"
2003-09-19 12:26:46 +02:00
#include "../qli/exe.h"
2001-05-23 15:26:42 +02:00
#include "../qli/all_proto.h"
#include "../qli/compi_proto.h"
#include "../qli/err_proto.h"
#include "../qli/exe_proto.h"
#include "../qli/expan_proto.h"
#include "../qli/gener_proto.h"
#include "../qli/help_proto.h"
#include "../qli/lex_proto.h"
#include "../qli/meta_proto.h"
#include "../qli/parse_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/perf_proto.h"
2001-12-24 03:51:06 +01:00
#include "../include/fb_exception.h"
#include "../common/utils_proto.h"
#include "../jrd/align.h"
2001-05-23 15:26:42 +02:00
using MsgFormat::SafeArg;
2008-12-05 02:20:14 +01:00
const char* STARTUP_FILE = "HOME"; // Assume its Unix
2001-05-23 15:26:42 +02:00
2009-01-14 13:19:43 +01:00
extern TEXT* QLI_prompt;
2001-05-23 15:26:42 +02:00
2008-12-09 08:24:32 +01:00
static void enable_signals();
2003-09-10 19:52:12 +02:00
static bool process_statement(bool);
2001-05-23 15:26:42 +02:00
static void CLIB_ROUTINE signal_arith_excp(USHORT, USHORT, USHORT);
static int async_quit(const int, const int, void*);
static bool yes_no(USHORT, const TEXT*);
2001-05-23 15:26:42 +02:00
2009-05-03 16:19:35 +02:00
struct answer_t
{
2001-05-23 15:26:42 +02:00
TEXT answer[30];
2003-09-10 19:52:12 +02:00
bool value;
2003-09-19 12:26:46 +02:00
};
2001-05-23 15:26:42 +02:00
2004-12-09 03:53:19 +01:00
static bool yes_no_loaded = false;
static answer_t answer_table[] =
{
2008-12-05 02:20:14 +01:00
{ "NO", false }, // NO
{ "YES", true }, // YES
2003-09-19 12:26:46 +02:00
{ "", false }
2001-05-23 15:26:42 +02:00
};
int CLIB_ROUTINE main( int argc, char **argv)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* m a i n
*
**************************************
*
* Functional description
2008-12-05 02:20:14 +01:00
* Top level routine.
2001-05-23 15:26:42 +02:00
*
**************************************/
2009-05-05 13:45:58 +02:00
// Look at options, if any
2001-05-23 15:26:42 +02:00
Firebird::PathName startup_file = STARTUP_FILE;
2001-05-23 15:26:42 +02:00
#ifdef UNIX
2009-05-05 13:45:58 +02:00
// If a Unix system, get home directory from environment
SCHAR home_directory[MAXPATHLEN];
if (!fb_utils::readenv("HOME", startup_file))
2001-05-23 15:26:42 +02:00
startup_file = ".qli_startup";
else
startup_file.append("/.qli_startup");
2001-05-23 15:26:42 +02:00
#endif
const TEXT* application_file = NULL;
2001-05-23 15:26:42 +02:00
ALLQ_init();
LEX_init();
bool version_flag = false, flush_flag = false;
bool banner_flag = true;
2001-05-23 15:26:42 +02:00
sw_buffers = 0;
strcpy(QLI_prompt_string, "QLI> ");
strcpy(QLI_cont_string, "CON> ");
2009-05-05 13:45:58 +02:00
// Let's define the default number of columns on a machine by machine basis
QLI_columns = 80;
2006-12-08 19:38:15 +01:00
#ifdef TRUSTED_AUTH
QLI_trusted = false;
#endif
QLI_lines = 60;
QLI_name_columns = 0;
2001-05-23 15:26:42 +02:00
QLI_prompt = QLI_prompt_string;
QLI_matching_language = 0;
QLI_default_user[0] = 0;
QLI_default_password[0] = 0;
QLI_charset[0] = 0;
2003-02-09 23:59:55 +01:00
#ifdef DEV_BUILD
QLI_hex_output = false;
2001-05-23 15:26:42 +02:00
#endif
SLONG debug_value; // aparently unneeded, see usage below.
const TEXT* const* const arg_end = argv + argc;
argv++;
2009-01-10 11:51:02 +01:00
while (argv < arg_end)
{
const TEXT* p = *argv++;
2009-05-03 16:19:35 +02:00
if (*p++ != '-')
{
2003-09-10 19:52:12 +02:00
banner_flag = false;
2001-05-23 15:26:42 +02:00
LEX_pop_line();
LEX_push_string(p - 1);
continue;
}
TEXT c;
2001-05-23 15:26:42 +02:00
while (c = *p++)
2009-01-10 11:51:02 +01:00
switch (UPPER(c))
{
2001-05-23 15:26:42 +02:00
case 'A':
if (argv >= arg_end) {
2008-12-05 02:20:14 +01:00
ERRQ_msg_put(23); // Msg23 Please retry, supplying an application script file name
2001-05-23 15:26:42 +02:00
exit(FINI_ERROR);
}
application_file = *argv++;
break;
case 'B':
if (argv < arg_end && **argv != '-')
sw_buffers = atoi(*argv++);
break;
case 'F': // fetch password
2008-12-01 10:51:02 +01:00
{
if (argv >= arg_end || **argv == '-')
break;
2008-12-03 02:05:53 +01:00
const char* pwd = NULL;
2008-12-01 10:51:02 +01:00
if (fb_utils::fetchPassword(*argv++, pwd) != fb_utils::FETCH_PASS_OK)
break;
fb_utils::copy_terminate(QLI_default_password, pwd, sizeof(QLI_default_password));
}
break;
2001-05-23 15:26:42 +02:00
case 'I':
if (argv >= arg_end || **argv == '-')
startup_file = "";
2001-05-23 15:26:42 +02:00
else
startup_file = *argv++;
break;
2006-12-08 19:38:15 +01:00
#ifdef TRUSTED_AUTH
case 'K':
QLI_trusted = true;
break;
#endif
2001-05-23 15:26:42 +02:00
case 'N':
2003-09-10 19:52:12 +02:00
banner_flag = false;
2001-05-23 15:26:42 +02:00
break;
case 'P':
2008-01-15 21:15:58 +01:00
if (argv >= arg_end || **argv == '-')
2001-05-23 15:26:42 +02:00
break;
2008-01-15 21:15:58 +01:00
fb_utils::copy_terminate(QLI_default_password, fb_utils::get_passwd(*argv++),
sizeof(QLI_default_password));
break;
2001-05-23 15:26:42 +02:00
case 'T':
2003-09-10 19:52:12 +02:00
sw_trace = true;
2001-05-23 15:26:42 +02:00
break;
case 'U':
2008-01-15 21:15:58 +01:00
if (argv >= arg_end || **argv == '-')
2001-05-23 15:26:42 +02:00
break;
2008-01-15 21:15:58 +01:00
fb_utils::copy_terminate(QLI_default_user, *argv++, sizeof(QLI_default_user));
break;
2001-05-23 15:26:42 +02:00
case 'V':
2003-09-10 19:52:12 +02:00
sw_verify = true;
2001-05-23 15:26:42 +02:00
break;
case 'X':
debug_value = 1;
2003-11-08 17:40:17 +01:00
isc_set_debug(debug_value);
2001-05-23 15:26:42 +02:00
break;
2008-12-05 02:20:14 +01:00
/* This switch's name is arbitrary; since it is an internal
2001-05-23 15:26:42 +02:00
mechanism it can be changed at will */
case 'Y':
QLI_trace = true;
2001-05-23 15:26:42 +02:00
break;
case 'Z':
2003-09-10 19:52:12 +02:00
version_flag = true;
2001-05-23 15:26:42 +02:00
break;
default:
2008-12-05 02:20:14 +01:00
ERRQ_msg_put(469, SafeArg() << c);
// Msg469 qli: ignoring unknown switch %c
2001-05-23 15:26:42 +02:00
break;
}
}
enable_signals();
if (banner_flag)
2008-12-05 02:20:14 +01:00
ERRQ_msg_put(24); // Msg24 Welcome to QLI Query Language Interpreter
2001-05-23 15:26:42 +02:00
if (version_flag)
2007-04-01 15:02:46 +02:00
ERRQ_msg_put(25, SafeArg() << GDS_VERSION); // Msg25 qli version %s
2001-05-23 15:26:42 +02:00
if (application_file)
2003-09-10 19:52:12 +02:00
LEX_push_file(application_file, true);
2001-05-23 15:26:42 +02:00
if (startup_file.length())
LEX_push_file(startup_file.c_str(), false);
2001-05-23 15:26:42 +02:00
for (bool got_started = false; !got_started;)
2001-12-24 03:51:06 +01:00
{
2003-09-10 19:52:12 +02:00
got_started = true;
2001-12-24 03:51:06 +01:00
try {
PAR_token();
}
catch (const Firebird::Exception&) {
2008-12-05 02:20:14 +01:00
// try again
2003-09-10 19:52:12 +02:00
got_started = false;
2001-05-23 15:26:42 +02:00
ERRQ_pending();
}
}
QLI_error = NULL;
2009-05-05 13:45:58 +02:00
// Loop until end of file or forced exit
2001-05-23 15:26:42 +02:00
2009-05-03 16:19:35 +02:00
while (QLI_line)
{
plb* temp = QLI_default_pool = ALLQ_pool();
2001-05-23 15:26:42 +02:00
flush_flag = process_statement(flush_flag);
ERRQ_pending();
ALLQ_rlpool(temp);
}
HELP_fini();
MET_shutdown();
LEX_fini();
ALLQ_fini();
#ifdef DEBUG_GDS_ALLOC
2008-12-05 02:20:14 +01:00
/* Report any memory leaks noticed.
2001-05-23 15:26:42 +02:00
* We don't particularly care about QLI specific memory leaks, so all
* QLI allocations have been marked as "don't report". However, much
* of the test-base uses QLI so having a report when QLI finishes
* could find leaks within the engine.
*/
gds_alloc_report(0, __FILE__, __LINE__);
#endif
2003-08-12 12:00:18 +02:00
return (FINI_OK);
2001-05-23 15:26:42 +02:00
}
2008-12-09 08:24:32 +01:00
static void enable_signals()
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* e n a b l e _ s i g n a l s
*
**************************************
*
* Functional description
* Enable signals.
*
**************************************/
2003-08-12 12:00:18 +02:00
typedef void (*new_handler) (int);
2001-05-23 15:26:42 +02:00
#ifdef SIGQUIT
signal(SIGQUIT, SIG_IGN);
#endif
fb_shutdown_callback(0, async_quit, fb_shut_confirmation, 0);
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
2003-08-12 12:00:18 +02:00
signal(SIGFPE, (new_handler) signal_arith_excp);
2001-05-23 15:26:42 +02:00
}
2003-09-10 19:52:12 +02:00
static bool process_statement(bool flush_flag)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* p r o c e s s _ s t a t e m e n t
*
**************************************
*
* Functional description
* Parse, compile, and execute a single statement. If an input flush
2003-09-10 19:52:12 +02:00
* is required, return true (or status), otherwise return false.
2001-05-23 15:26:42 +02:00
*
**************************************/
2009-01-10 11:51:02 +01:00
qli_dbb* dbb;
2001-05-23 15:26:42 +02:00
2009-05-05 13:45:58 +02:00
// Clear database active flags in preparation for a new statement
2001-05-23 15:26:42 +02:00
QLI_abort = false;
2001-05-23 15:26:42 +02:00
for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next)
dbb->dbb_flags &= ~DBB_active;
2009-05-05 13:45:58 +02:00
// If the last statement wrote out anything to the terminal, skip a line
2001-05-23 15:26:42 +02:00
if (QLI_skip_line) {
2004-04-29 00:36:29 +02:00
printf("\n");
QLI_skip_line = false;
2001-05-23 15:26:42 +02:00
}
/* Enable signal handling for the next statement. Each signal will
be caught at least once, then reset to allow the user to really
kill the process */
enable_signals();
2009-05-05 13:45:58 +02:00
// Enable error unwinding and enable the unwinding environment
2001-05-23 15:26:42 +02:00
2001-12-24 03:51:06 +01:00
try {
2008-12-05 02:20:14 +01:00
2001-05-23 15:26:42 +02:00
/* Set up the appropriate prompt and get the first significant token. If
we don't get one, we're at end of file */
QLI_prompt = QLI_prompt_string;
/* This needs to be done after setting QLI_prompt to prevent
* and infinite loop in LEX/next_line.
*/
2009-05-05 13:45:58 +02:00
// If there was a prior syntax error, flush the token stream
2001-05-23 15:26:42 +02:00
if (flush_flag)
LEX_flush();
while (QLI_token->tok_keyword == KW_SEMI)
LEX_token();
PAR_real();
if (!QLI_line)
2003-09-10 19:52:12 +02:00
return false;
2001-05-23 15:26:42 +02:00
EXEC_poll_abort();
/* Mark the current token as starting the statement. This is allows
the EDIT command to find the last statement */
LEX_mark_statement();
/* Change the prompt string to the continuation prompt, and parse
the next statement */
QLI_prompt = QLI_cont_string;
2004-03-07 08:58:55 +01:00
qli_syntax* syntax_tree = PARQ_parse();
if (!syntax_tree)
2003-09-10 19:52:12 +02:00
return false;
2001-05-23 15:26:42 +02:00
EXEC_poll_abort();
2009-05-05 13:45:58 +02:00
// If the statement was EXIT, force end of file on command input
2001-05-23 15:26:42 +02:00
if (syntax_tree->syn_type == nod_exit) {
QLI_line = NULL;
2003-09-10 19:52:12 +02:00
return false;
2001-05-23 15:26:42 +02:00
}
2009-05-05 13:45:58 +02:00
// If the statement was quit, ask the user if he want to rollback
2001-05-23 15:26:42 +02:00
2009-01-10 11:51:02 +01:00
if (syntax_tree->syn_type == nod_quit)
{
2001-05-23 15:26:42 +02:00
QLI_line = NULL;
for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next)
2008-01-15 21:15:58 +01:00
{
2001-05-23 15:26:42 +02:00
if ((dbb->dbb_transaction) && (dbb->dbb_flags & DBB_updates))
2008-01-15 21:15:58 +01:00
{
2001-05-23 15:26:42 +02:00
if (yes_no(460, dbb->dbb_symbol->sym_string)) /* Msg460 Do you want to rollback updates for <dbb>? */
MET_transaction(nod_rollback, dbb);
else
MET_transaction(nod_commit, dbb);
2008-01-15 21:15:58 +01:00
}
}
2003-09-10 19:52:12 +02:00
return false;
2001-05-23 15:26:42 +02:00
}
/* Expand the statement. It will return NULL is the statement was
a command. An error will be unwound */
2008-01-15 21:15:58 +01:00
qli_nod* expanded_tree = EXP_expand(syntax_tree);
if (!expanded_tree)
2003-09-10 19:52:12 +02:00
return false;
2001-05-23 15:26:42 +02:00
2009-05-05 13:45:58 +02:00
// Compile the statement
2001-05-23 15:26:42 +02:00
2008-01-15 21:15:58 +01:00
qli_nod* execution_tree = CMPQ_compile(expanded_tree);
if (!execution_tree)
2003-09-10 19:52:12 +02:00
return false;
2001-05-23 15:26:42 +02:00
2009-05-05 13:45:58 +02:00
// Generate any BLR needed to support the request
2001-05-23 15:26:42 +02:00
2008-01-15 21:15:58 +01:00
if (!GEN_generate(execution_tree))
2003-09-10 19:52:12 +02:00
return false;
2001-05-23 15:26:42 +02:00
if (QLI_statistics)
2009-01-10 11:51:02 +01:00
{
2001-05-23 15:26:42 +02:00
for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next)
2009-01-11 01:40:46 +01:00
{
2008-12-09 08:24:32 +01:00
if (dbb->dbb_flags & DBB_active)
{
if (!dbb->dbb_statistics)
{
dbb->dbb_statistics = (int *) gds__alloc((SLONG) sizeof(PERF));
2001-05-23 15:26:42 +02:00
#ifdef DEBUG_GDS_ALLOC
2008-12-05 02:20:14 +01:00
// We don't care about QLI specific memory leaks for V4.0
gds_alloc_flag_unfreed((void *) dbb->dbb_statistics); // QLI: don't care
2001-05-23 15:26:42 +02:00
#endif
}
2009-01-10 11:51:02 +01:00
perf_get_info(&dbb->dbb_handle, (perf*) dbb->dbb_statistics);
2001-05-23 15:26:42 +02:00
}
2009-01-11 01:40:46 +01:00
}
2009-01-10 11:51:02 +01:00
}
2001-05-23 15:26:42 +02:00
2009-05-05 13:45:58 +02:00
// Execute the request, for better or worse
2001-05-23 15:26:42 +02:00
2008-01-15 21:15:58 +01:00
EXEC_top(execution_tree);
2001-05-23 15:26:42 +02:00
if (QLI_statistics)
2001-12-24 03:51:06 +01:00
{
PERF statistics;
TEXT buffer[512], report[256];
2001-05-23 15:26:42 +02:00
for (dbb = QLI_databases; dbb; dbb = dbb->dbb_next)
2001-12-24 03:51:06 +01:00
{
report[0] = 0;
2001-12-24 03:51:06 +01:00
if (dbb->dbb_flags & DBB_active)
{
ERRQ_msg_get(505, report, sizeof(report));
2008-12-05 02:20:14 +01:00
// Msg505 " reads = !r writes = !w fetches = !f marks = !m\n"
size_t used_len = strlen(report);
ERRQ_msg_get(506, report + used_len, sizeof(report) - used_len);
2008-12-05 02:20:14 +01:00
// Msg506 " elapsed = !e cpu = !u system = !s mem = !x, buffers = !b"
perf_get_info(&dbb->dbb_handle, &statistics);
2008-12-09 08:24:32 +01:00
perf_format((perf*) dbb->dbb_statistics, &statistics, report, buffer, 0);
2008-12-05 02:20:14 +01:00
ERRQ_msg_put(26, SafeArg() << dbb->dbb_filename << buffer); // Msg26 Statistics for database %s %s
QLI_skip_line = true;
2001-05-23 15:26:42 +02:00
}
2001-12-24 03:51:06 +01:00
}
}
2001-05-23 15:26:42 +02:00
2009-05-05 13:45:58 +02:00
// Release resources associated with the request
2001-05-23 15:26:42 +02:00
GEN_release();
2003-09-10 19:52:12 +02:00
return false;
2001-12-24 03:51:06 +01:00
} // try
catch (const Firebird::Exception&) {
2001-12-24 03:51:06 +01:00
GEN_release();
return true;
2001-12-24 03:51:06 +01:00
}
2001-05-23 15:26:42 +02:00
}
2009-04-28 15:48:18 +02:00
static void CLIB_ROUTINE signal_arith_excp(USHORT /*sig*/, USHORT code, USHORT /*scp*/)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s i g n a l _ a r i t h _ e x c p
*
**************************************
*
* Functional description
* Catch arithmetic exception.
*
**************************************/
USHORT msg_number;
2008-12-31 06:06:08 +01:00
#if defined(FPE_INOVF_TRAP) || defined(FPE_INTDIV_TRAP) || \
defined(FPE_FLTOVF_TRAP) || defined(FPE_FLTDIV_TRAP) || \
defined(FPE_FLTUND_TRAP) || defined(FPE_FLTOVF_FAULT) || \
defined(FPE_FLTUND_FAULT)
2008-12-31 06:06:08 +01:00
switch (code)
{
2001-05-23 15:26:42 +02:00
#ifdef FPE_INOVF_TRAP
case FPE_INTOVF_TRAP:
2008-12-05 02:20:14 +01:00
msg_number = 14; // Msg14 integer overflow
2001-05-23 15:26:42 +02:00
break;
#endif
#ifdef FPE_INTDIV_TRAP
case FPE_INTDIV_TRAP:
2008-12-05 02:20:14 +01:00
msg_number = 15; // Msg15 integer division by zero
2001-05-23 15:26:42 +02:00
break;
#endif
#ifdef FPE_FLTOVF_TRAP
case FPE_FLTOVF_TRAP:
2008-12-05 02:20:14 +01:00
msg_number = 16; // Msg16 floating overflow trap
2001-05-23 15:26:42 +02:00
break;
#endif
#ifdef FPE_FLTDIV_TRAP
case FPE_FLTDIV_TRAP:
2008-12-05 02:20:14 +01:00
msg_number = 17; // Msg17 floating division by zero
2001-05-23 15:26:42 +02:00
break;
#endif
#ifdef FPE_FLTUND_TRAP
case FPE_FLTUND_TRAP:
2008-12-05 02:20:14 +01:00
msg_number = 18; // Msg18 floating underflow trap
2001-05-23 15:26:42 +02:00
break;
#endif
#ifdef FPE_FLTOVF_FAULT
case FPE_FLTOVF_FAULT:
2008-12-05 02:20:14 +01:00
msg_number = 19; // Msg19 floating overflow fault
2001-05-23 15:26:42 +02:00
break;
#endif
#ifdef FPE_FLTUND_FAULT
case FPE_FLTUND_FAULT:
2008-12-05 02:20:14 +01:00
msg_number = 20; // Msg20 floating underflow fault
2001-05-23 15:26:42 +02:00
break;
#endif
default:
2008-12-05 02:20:14 +01:00
msg_number = 21; // Msg21 arithmetic exception
2001-05-23 15:26:42 +02:00
}
#else
msg_number = 21;
#endif
2001-05-23 15:26:42 +02:00
2001-07-12 07:46:06 +02:00
signal(SIGFPE, (void(*)(int)) signal_arith_excp);
2001-05-23 15:26:42 +02:00
IBERROR(msg_number);
}
static int async_quit(const int reason, const int, void*)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* s i g n a l _ q u i t
*
**************************************
*
* Functional description
* Stop whatever we happened to be doing.
*
**************************************/
if (reason == fb_shutrsn_signal)
{
EXEC_abort();
return FB_FAILURE;
}
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
static bool yes_no(USHORT number, const TEXT* arg1)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* y e s _ n o
*
**************************************
*
* Functional description
* Put out a prompt that expects a yes/no
* answer, and keep trying until we get an
* acceptable answer (e.g. y, Yes, N, etc.)
*
**************************************/
TEXT prompt[256];
2001-05-23 15:26:42 +02:00
ERRQ_msg_format(number, sizeof(prompt), prompt, SafeArg() << arg1);
2009-05-03 16:19:35 +02:00
if (!yes_no_loaded)
{
2004-12-09 03:53:19 +01:00
yes_no_loaded = true;
// Msg498 NO
if (!ERRQ_msg_get(498, answer_table[0].answer, sizeof(answer_table[0].answer)))
2008-12-05 02:20:14 +01:00
strcpy(answer_table[0].answer, "NO"); // default if msg_get fails
// Msg497 YES
if (!ERRQ_msg_get(497, answer_table[1].answer, sizeof(answer_table[1].answer)))
2001-05-23 15:26:42 +02:00
strcpy(answer_table[1].answer, "YES");
}
TEXT buffer[256];
2009-01-10 11:51:02 +01:00
while (true)
{
2001-05-23 15:26:42 +02:00
buffer[0] = 0;
if (!LEX_get_line(prompt, buffer, sizeof(buffer)))
2003-09-10 19:52:12 +02:00
return true;
2008-12-09 08:24:32 +01:00
for (const answer_t* response = answer_table; *response->answer != '\0'; response++)
{
const TEXT* p = buffer;
2001-05-23 15:26:42 +02:00
while (*p == ' ')
p++;
if (*p == EOF)
2003-09-10 19:52:12 +02:00
return true;
for (const TEXT* q = response->answer; *p && UPPER(*p) == *q++; p++);
2001-05-23 15:26:42 +02:00
if (!*p || *p == '\n')
return response->value;
}
}
}
#ifdef DEV_BUILD
void QLI_validate_desc(const dsc* d)
{
fb_assert(d->dsc_dtype > dtype_unknown);
fb_assert(d->dsc_dtype < DTYPE_TYPE_MAX);
ULONG addr = (ULONG) (U_IPTR) (d->dsc_address); // safely ignore higher bits even if present
USHORT ta = type_alignments[d->dsc_dtype];
if (ta > 1)
2008-12-21 00:47:25 +01:00
fb_assert((addr & (ta - 1)) == 0);
}
#endif