mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-25 01:23:03 +01:00
351 lines
8.0 KiB
Plaintext
351 lines
8.0 KiB
Plaintext
/*
|
|
* PROGRAM: JRD Command Oriented Query Language
|
|
* MODULE: help.epp
|
|
* DESCRIPTION: Help module.
|
|
*
|
|
* 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
|
|
*
|
|
*/
|
|
|
|
#include "firebird.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "../jrd/ibase.h"
|
|
#include "../qli/dtr.h"
|
|
#include "../qli/compile.h"
|
|
#include "../qli/parse.h"
|
|
#include "../qli/err_proto.h"
|
|
#include "../qli/help_proto.h"
|
|
#include "../qli/lex_proto.h"
|
|
#include "../jrd/gds_proto.h"
|
|
#include "../common/utils_proto.h"
|
|
#include "../common/classes/fb_string.h"
|
|
|
|
using MsgFormat::SafeArg;
|
|
|
|
|
|
const char* INDENT = " ";
|
|
const int COLUMN_WIDTH = 20;
|
|
const int RIGHT_MARGIN = 70;
|
|
|
|
const char* const TARGET = "help.fdb";
|
|
|
|
DATABASE HELP_DB = STATIC "help.fdb" RUNTIME target;
|
|
|
|
static int additional_topics(const TEXT*, const TEXT*, const TEXT*);
|
|
static void print_more(USHORT, USHORT, const TEXT**, USHORT*, const TEXT*); //, bool);
|
|
static void print_topic(USHORT, USHORT, const TEXT**, USHORT*, const TEXT*, bool);
|
|
static const TEXT* strip(const TEXT*);
|
|
|
|
|
|
void HELP_fini()
|
|
{
|
|
/**************************************
|
|
*
|
|
* H E L P _ f i n i
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
*
|
|
**************************************/
|
|
|
|
if (HELP_DB)
|
|
{
|
|
COMMIT;
|
|
FINISH;
|
|
}
|
|
}
|
|
|
|
|
|
void HELP_help( qli_syntax* node)
|
|
{
|
|
/**************************************
|
|
*
|
|
* H E L P _ h e l p
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Give the poor sucker help.
|
|
*
|
|
**************************************/
|
|
if (!HELP_DB)
|
|
{
|
|
Firebird::PathName name = fb_utils::getPrefix(fb_utils::FB_DIR_HELP, TARGET);
|
|
TEXT target[MAXPATHLEN];
|
|
name.copyTo(target, sizeof target);
|
|
READY
|
|
ON_ERROR
|
|
ERRQ_database_error(NULL, gds_status);
|
|
END_ERROR;
|
|
START_TRANSACTION;
|
|
}
|
|
|
|
USHORT max_level = 0;
|
|
const TEXT* topics[16];
|
|
const TEXT** topic = topics;
|
|
*topic++ = "QLI";
|
|
|
|
qli_name** ptr;
|
|
qli_name** end;
|
|
for (ptr = (qli_name**) node->syn_arg, end = ptr + node->syn_count; ptr < end; ptr++)
|
|
{
|
|
*topic++ = (*ptr)->nam_string;
|
|
}
|
|
|
|
print_topic(0, node->syn_count, topics, &max_level, "", false);
|
|
|
|
if (max_level < node->syn_count)
|
|
print_topic(0, node->syn_count, topics, &max_level, "", true);
|
|
}
|
|
|
|
|
|
static int additional_topics( const TEXT* parent, const TEXT* banner, const TEXT* string)
|
|
{
|
|
/**************************************
|
|
*
|
|
* a d d i t i o n a l _ t o p i c s
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Print a list of other known topics.
|
|
*
|
|
**************************************/
|
|
TEXT line[256];
|
|
|
|
// Print list of know topics. When we find the first, print the banner, if any
|
|
|
|
TEXT* ptr = line;
|
|
USHORT topics = 0;
|
|
USHORT l = strlen(parent);
|
|
|
|
FOR X IN TOPICS
|
|
WITH X.PARENT EQ parent SORTED BY X.TOPIC
|
|
if (QLI_abort)
|
|
return 0;
|
|
const TEXT* p = X.TOPIC;
|
|
while (*p && *p != ' ')
|
|
p++;
|
|
if (!(l = p - X.TOPIC))
|
|
continue;
|
|
if (++topics == 1 && banner)
|
|
printf("%s%s%s\n", banner, string, parent);
|
|
p =
|
|
line +
|
|
((ptr - line + COLUMN_WIDTH - 1) / COLUMN_WIDTH) * COLUMN_WIDTH;
|
|
if (p + l > line + RIGHT_MARGIN)
|
|
{
|
|
*ptr = 0;
|
|
printf("%s%s\n", INDENT, line);
|
|
p = ptr = line;
|
|
}
|
|
while (ptr < p)
|
|
*ptr++ = ' ';
|
|
p = X.TOPIC;
|
|
do {
|
|
*ptr++ = *p++;
|
|
} while (--l);
|
|
*ptr++ = ' ';
|
|
END_FOR;
|
|
|
|
if (ptr != line)
|
|
{
|
|
*ptr = 0;
|
|
printf("%s%s\n", INDENT, line);
|
|
}
|
|
|
|
return topics;
|
|
}
|
|
|
|
|
|
static void print_more(USHORT level,
|
|
USHORT depth,
|
|
const TEXT** topics,
|
|
USHORT* max_level,
|
|
const TEXT* parent)
|
|
//bool error_flag) // unused
|
|
{
|
|
/**************************************
|
|
*
|
|
* p r i n t _ m o r e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* We have printed a topic with additional sub-topics. Ask the user if he
|
|
* wants more.
|
|
*
|
|
**************************************/
|
|
TEXT buffer[256], topic[80], prompt[80];
|
|
|
|
ERRQ_msg_get(502, prompt, sizeof(prompt)); // Msg502 "Subtopic? "
|
|
|
|
// Prompt the user for a line
|
|
|
|
if (!LEX_get_line(prompt, buffer, sizeof(buffer)))
|
|
return;
|
|
|
|
// Upcase the response and zap the blanks
|
|
TEXT* p = topic;
|
|
topics[1] = p;
|
|
|
|
for (const TEXT* q = buffer; *q && *q != '\n'; q++)
|
|
if (*q != ' ')
|
|
*p++ = UPPER(*q);
|
|
*p = 0;
|
|
|
|
// If we got anything, print the new topic
|
|
|
|
if (p != topic)
|
|
{
|
|
print_topic(level + 1, depth + 1, topics + 1, max_level, parent, false);
|
|
// strange, it doesn't use error_flag
|
|
}
|
|
}
|
|
|
|
|
|
static void print_topic(USHORT level,
|
|
USHORT depth,
|
|
const TEXT** topics,
|
|
USHORT* max_level, const TEXT* parent, bool error_flag)
|
|
{
|
|
/**************************************
|
|
*
|
|
* p r i n t _ t o p i c
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Lookup topic in path. If we find a topic, and are not level
|
|
* zero, recurse. Otherwise print out the topic. In any case,
|
|
* remember the lowest level on which a topic was found. If the
|
|
* error flag is set, print out a list of sub-topics.
|
|
*
|
|
**************************************/
|
|
TEXT string[128], banner[128], buffer[128], prompt[80];
|
|
|
|
// Copy the parent string inserting a blank at the end
|
|
|
|
TEXT* p = string;
|
|
|
|
if (*parent)
|
|
{
|
|
const TEXT* q = parent;
|
|
while (*q)
|
|
*p++ = *q++;
|
|
*p++ = ' ';
|
|
}
|
|
|
|
TEXT* const next = p;
|
|
USHORT count = 0;
|
|
|
|
FOR X IN TOPICS
|
|
WITH X.FACILITY EQ "QLI" AND
|
|
(X.TOPIC STARTING WITH * topics AND X.PARENT EQ parent) OR
|
|
(X.TOPIC = X.FACILITY AND X.TOPIC = *topics AND X.TOPIC = X.PARENT)
|
|
count++;
|
|
END_FOR;
|
|
|
|
if (count > 1)
|
|
ERRQ_msg_put(80, SafeArg() << count << *topics); // Msg80 [%d topics matched %s]
|
|
|
|
count = 0;
|
|
|
|
FOR(LEVEL level) X IN TOPICS
|
|
WITH X.FACILITY EQ "QLI" AND
|
|
(X.TOPIC STARTING WITH * topics AND X.PARENT EQ parent) OR
|
|
(X.TOPIC = X.FACILITY AND X.TOPIC = *topics AND X.TOPIC = X.PARENT)
|
|
SORTED BY X.TOPIC
|
|
|
|
if (QLI_abort)
|
|
return;
|
|
|
|
if (count)
|
|
{
|
|
ERRQ_msg_get(503, prompt, sizeof(prompt));
|
|
// Msg503 "\ntype <cr> for next topic or <EOF> to stop: "
|
|
if (!LEX_get_line(prompt, buffer, sizeof(buffer)))
|
|
return;
|
|
}
|
|
++count;
|
|
if (level > *max_level)
|
|
*max_level = level;
|
|
p = next;
|
|
const TEXT* q = X.TOPIC;
|
|
while (*q && *q != ' ')
|
|
*p++ = *q++;
|
|
*p = 0;
|
|
if (level < depth)
|
|
print_topic(level + 1, depth, topics + 1, max_level, string, error_flag);
|
|
else
|
|
{
|
|
printf("\n%s\n\n", strip(string));
|
|
QLI_skip_line = true;
|
|
FOR B IN X.TEXT
|
|
if (QLI_abort)
|
|
return;
|
|
B.SEGMENT[B.LENGTH] = 0;
|
|
printf("%s%s", INDENT, B.SEGMENT);
|
|
END_FOR;
|
|
ERRQ_msg_format(81, sizeof(banner), banner, SafeArg() << INDENT);
|
|
// Msg81 %sSub-topics available:
|
|
if (additional_topics(string, banner, INDENT))
|
|
print_more(level, depth, topics, max_level, string); //, error_flag);
|
|
}
|
|
END_FOR;
|
|
|
|
if (!count && error_flag && level > *max_level)
|
|
{
|
|
const TEXT* path = strip(parent);
|
|
ERRQ_msg_put(82, SafeArg() << path << *topics); // Msg82 No help is available for %s %s
|
|
ERRQ_msg_format(83, sizeof(banner), banner, SafeArg() << path);
|
|
// Msg83 Sub-topics available for %s are:
|
|
additional_topics(parent, banner, path);
|
|
}
|
|
}
|
|
|
|
|
|
static const TEXT* strip( const TEXT* string)
|
|
{
|
|
/**************************************
|
|
*
|
|
* s t r i p
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Strip off the first topic in the path.
|
|
*
|
|
**************************************/
|
|
const TEXT* p = string;
|
|
|
|
while (*p != ' ')
|
|
if (!*p++)
|
|
return string;
|
|
|
|
while (*p == ' ')
|
|
if (!*p++)
|
|
return string;
|
|
|
|
return p;
|
|
}
|