Rearrange scanning code to support extended comments.

Use #define symbols rather than integers for scanning states.
This commit is contained in:
Thomas G. Lockhart 1997-09-01 06:09:53 +00:00
parent 1bf90bc7d3
commit b776831e8b
1 changed files with 153 additions and 80 deletions

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.88 1997/08/26 17:00:06 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.89 1997/09/01 06:09:53 thomas Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -48,8 +48,28 @@
# endif # endif
#endif #endif
/* This prompt string is assumed to have at least 3 characters by code in MainLoop().
* A character two characters from the end is replaced each time by a mode character.
*/
#define PROMPT "=> " #define PROMPT "=> "
#define PROMPT_READY '='
#define PROMPT_CONTINUE '-'
#define PROMPT_COMMENT '*'
#define PROMPT_QUOTE '\''
/* Backslash command handling:
* 0 - send currently constructed query to backend (i.e. we got a \g)
* 1 - skip processing of this line, continue building up query
* 2 - terminate processing of this query entirely
* 3 - new query supplied by edit
*/
#define CMD_UNKNOWN -1
#define CMD_SEND 0
#define CMD_SKIP_LINE 1
#define CMD_TERMINATE 2
#define CMD_NEWEDIT 3
#define MAX_QUERY_BUFFER 20000 #define MAX_QUERY_BUFFER 20000
#define COPYBUFSIZ 8192 #define COPYBUFSIZ 8192
@ -978,28 +998,28 @@ do_edit(const char *filename_arg, char *query, int *status_p)
} }
if (error) if (error)
*status_p = 1; *status_p = CMD_SKIP_LINE;
else { else {
editFile(fname); editFile(fname);
if ((fd = open(fname, O_RDONLY)) == -1) { if ((fd = open(fname, O_RDONLY)) == -1) {
perror(fname); perror(fname);
if (!filename_arg) if (!filename_arg)
unlink(fname); unlink(fname);
*status_p = 1; *status_p = CMD_SKIP_LINE;
} else { } else {
if ((cc = read(fd, query, MAX_QUERY_BUFFER)) == -1) { if ((cc = read(fd, query, MAX_QUERY_BUFFER)) == -1) {
perror(fname); perror(fname);
close(fd); close(fd);
if (!filename_arg) if (!filename_arg)
unlink(fname); unlink(fname);
*status_p = 1; *status_p = CMD_SKIP_LINE;
} else { } else {
query[cc] = '\0'; query[cc] = '\0';
close(fd); close(fd);
if (!filename_arg) if (!filename_arg)
unlink(fname); unlink(fname);
rightTrim(query); rightTrim(query);
*status_p = 3; *status_p = CMD_NEWEDIT;
} }
} }
} }
@ -1118,17 +1138,19 @@ do_shell(const char *command)
* Handles all the different commands that start with \ db_ptr is a pointer to * Handles all the different commands that start with \ db_ptr is a pointer to
* the TgDb* structure line is the current input line prompt_ptr is a pointer * the TgDb* structure line is the current input line prompt_ptr is a pointer
* to the prompt string, a pointer is used because the prompt can be used * to the prompt string, a pointer is used because the prompt can be used
* with a connection to a new database returns a status: 0 - send currently * with a connection to a new database.
* constructed query to backend (i.e. we got a \g) 1 - skip processing of * Returns a status:
* this line, continue building up query 2 - terminate processing of this * 0 - send currently constructed query to backend (i.e. we got a \g)
* query entirely, 3 - new query supplied by edit * 1 - skip processing of this line, continue building up query
* 2 - terminate processing of this query entirely
* 3 - new query supplied by edit
*/ */
static int static int
HandleSlashCmds(PsqlSettings * settings, HandleSlashCmds(PsqlSettings * settings,
char *line, char *line,
char *query) char *query)
{ {
int status = 1; int status = CMD_SKIP_LINE;
char *optarg; char *optarg;
/* /*
* Pointer inside the <cmd> string to the argument of the slash command, * Pointer inside the <cmd> string to the argument of the slash command,
@ -1188,7 +1210,7 @@ HandleSlashCmds(PsqlSettings * settings,
} }
if (optarg && !(settings->opt.caption = strdup(optarg))) { if (optarg && !(settings->opt.caption = strdup(optarg))) {
perror("malloc"); perror("malloc");
exit(1); exit(CMD_TERMINATE);
} }
break; break;
case 'c':{ case 'c':{
@ -1261,7 +1283,7 @@ HandleSlashCmds(PsqlSettings * settings,
lastfile = malloc(strlen(optarg + 1)); lastfile = malloc(strlen(optarg + 1));
if (!lastfile) { if (!lastfile) {
perror("malloc"); perror("malloc");
exit(1); exit(CMD_TERMINATE);
} }
strcpy(lastfile, optarg); strcpy(lastfile, optarg);
} else if (!lastfile) { } else if (!lastfile) {
@ -1293,10 +1315,10 @@ HandleSlashCmds(PsqlSettings * settings,
free(settings->opt.fieldSep); free(settings->opt.fieldSep);
if (!(settings->opt.fieldSep = strdup(fs))) { if (!(settings->opt.fieldSep = strdup(fs))) {
perror("malloc"); perror("malloc");
exit(1); exit(CMD_TERMINATE);
} }
if (!settings->quiet) if (!settings->quiet)
printf("field separater changed to '%s'\n", settings->opt.fieldSep); printf("field separator changed to '%s'\n", settings->opt.fieldSep);
break; break;
} }
case 'g': /* \g means send query */ case 'g': /* \g means send query */
@ -1304,9 +1326,9 @@ HandleSlashCmds(PsqlSettings * settings,
settings->gfname = NULL; settings->gfname = NULL;
else if (!(settings->gfname = strdup(optarg))) { else if (!(settings->gfname = strdup(optarg))) {
perror("malloc"); perror("malloc");
exit(1); exit(CMD_TERMINATE);
} }
status = 0; status = CMD_SEND;
break; break;
case 'h': /* help */ case 'h': /* help */
{ {
@ -1346,7 +1368,7 @@ HandleSlashCmds(PsqlSettings * settings,
} }
break; break;
case 'q': /* \q is quit */ case 'q': /* \q is quit */
status = 2; status = CMD_TERMINATE;
break; break;
case 'r': /* reset(clear) the buffer */ case 'r': /* reset(clear) the buffer */
query[0] = '\0'; query[0] = '\0';
@ -1369,13 +1391,13 @@ HandleSlashCmds(PsqlSettings * settings,
free(settings->opt.fieldSep); free(settings->opt.fieldSep);
settings->opt.fieldSep = strdup("|"); settings->opt.fieldSep = strdup("|");
if (!settings->quiet) if (!settings->quiet)
printf("field separater changed to '%s'\n", settings->opt.fieldSep); printf("field separator changed to '%s'\n", settings->opt.fieldSep);
} else { } else {
if (settings->opt.fieldSep) if (settings->opt.fieldSep)
free(settings->opt.fieldSep); free(settings->opt.fieldSep);
settings->opt.fieldSep = strdup(DEFAULT_FIELD_SEP); settings->opt.fieldSep = strdup(DEFAULT_FIELD_SEP);
if (!settings->quiet) if (!settings->quiet)
printf("field separater changed to '%s'\n", settings->opt.fieldSep); printf("field separator changed to '%s'\n", settings->opt.fieldSep);
} }
break; break;
case 'z': /* list table rights (grant/revoke) */ case 'z': /* list table rights (grant/revoke) */
@ -1391,7 +1413,7 @@ HandleSlashCmds(PsqlSettings * settings,
settings->opt.tableOpt = NULL; settings->opt.tableOpt = NULL;
else if (!(settings->opt.tableOpt = strdup(optarg))) { else if (!(settings->opt.tableOpt = strdup(optarg))) {
perror("malloc"); perror("malloc");
exit(1); exit(CMD_TERMINATE);
} }
break; break;
case 'x': case 'x':
@ -1407,31 +1429,33 @@ HandleSlashCmds(PsqlSettings * settings,
} }
free(cmd); free(cmd);
return status; return status;
} } /* HandleSlashCmds() */
/* /* MainLoop()
* MainLoop: main processing loop for reading lines of input and sending them * Main processing loop for reading lines of input
* to the backend * and sending them to the backend.
* *
* this loop is re-entrant. May be called by \i command which reads input from * This loop is re-entrant. May be called by \i command
* a file * which reads input from a file.
* * db_ptr must be initialized and set.
* db_ptr must be initialized and set
*/ */
static int static int
MainLoop(PsqlSettings * settings, FILE * source) MainLoop(PsqlSettings * settings, FILE * source)
{ {
char *line; /* line of input */ char *line; /* line of input */
char *xcomment; /* start of extended comment */
int len; /* length of the line */ int len; /* length of the line */
char query[MAX_QUERY_BUFFER]; /* multi-line query storage */ char query[MAX_QUERY_BUFFER]; /* multi-line query storage */
int successResult = 1; int successResult = 1;
int slashCmdStatus = 0; int slashCmdStatus = CMD_SEND;
/* /*
* slashCmdStatus can be: 0 - send currently constructed query to backend * slashCmdStatus can be:
* (i.e. we got a \g) 1 - skip processing of this line, continue building * CMD_UNKNOWN - send currently constructed query to backend (i.e. we got a \g)
* up query 2 - terminate processing of this query entirely 3 - new query * CMD_SEND - send currently constructed query to backend (i.e. we got a \g)
* supplied by edit * CMD_SKIP_LINE - skip processing of this line, continue building up query
* CMD_TERMINATE - terminate processing of this query entirely
* CMD_NEWEDIT - new query supplied by edit
*/ */
bool querySent = false; bool querySent = false;
@ -1441,8 +1465,6 @@ MainLoop(PsqlSettings * settings, FILE * source)
/* We've reached the end of our command input. */ /* We've reached the end of our command input. */
bool success; bool success;
bool in_quote; bool in_quote;
bool was_bslash; /* backslash */
bool was_dash;
int paren_level; int paren_level;
char *query_start; char *query_start;
@ -1467,24 +1489,30 @@ MainLoop(PsqlSettings * settings, FILE * source)
GetNextLine = gets_fromFile; GetNextLine = gets_fromFile;
query[0] = '\0'; query[0] = '\0';
xcomment = NULL;
in_quote = false; in_quote = false;
paren_level = 0; paren_level = 0;
slashCmdStatus = -1; /* set default */ slashCmdStatus = CMD_UNKNOWN; /* set default */
/* main loop for getting queries and executing them */ /* main loop to get queries and execute them */
while (!eof) { while (!eof) {
if (slashCmdStatus == 3) { /* just returned from editing the line? then just copy to the input buffer */
if (slashCmdStatus == CMD_NEWEDIT) {
paren_level = 0; paren_level = 0;
line = strdup(query); line = strdup(query);
query[0] = '\0'; query[0] = '\0';
/* otherwise, get another line and set interactive prompt if necessary */
} else { } else {
if (interactive && !settings->quiet) { if (interactive && !settings->quiet) {
if (in_quote) if (in_quote)
settings->prompt[strlen(settings->prompt)-3] = '\''; settings->prompt[strlen(settings->prompt)-3] = PROMPT_QUOTE;
else if (query[0] != '\0' && !querySent) else if (xcomment != NULL)
settings->prompt[strlen(settings->prompt)-3] = '-'; settings->prompt[strlen(settings->prompt)-3] = PROMPT_COMMENT;
else else if (query[0] != '\0' && !querySent)
settings->prompt[strlen(settings->prompt)-3] = '='; settings->prompt[strlen(settings->prompt)-3] = PROMPT_CONTINUE;
else
settings->prompt[strlen(settings->prompt)-3] = PROMPT_READY;
} }
line = GetNextLine(settings->prompt, source); line = GetNextLine(settings->prompt, source);
#ifdef HAVE_HISTORY #ifdef HAVE_HISTORY
@ -1493,7 +1521,20 @@ MainLoop(PsqlSettings * settings, FILE * source)
#endif #endif
} }
query_start = line; /* query - pointer to current command
* query_start - placeholder for next command
*/
/* not currently inside an extended comment? */
if (xcomment == NULL) {
query_start = line;
/* otherwise, continue the extended comment... */
} else {
query_start = line;
xcomment = line;
};
if (line == NULL) { /* No more input. Time to quit */ if (line == NULL) { /* No more input. Time to quit */
if (!settings->quiet) if (!settings->quiet)
printf("EOF\n"); /* Goes on prompt line */ printf("EOF\n"); /* Goes on prompt line */
@ -1502,9 +1543,11 @@ MainLoop(PsqlSettings * settings, FILE * source)
/* remove whitespaces on the right, incl. \n's */ /* remove whitespaces on the right, incl. \n's */
line = rightTrim(line); line = rightTrim(line);
/* echo back if input is from file */
if (!interactive && !settings->singleStep && !settings->quiet) if (!interactive && !settings->singleStep && !settings->quiet)
fprintf(stderr, "%s\n", line); fprintf(stderr, "%s\n", line);
/* nothing on line after trimming? then ignore */
if (line[0] == '\0') { if (line[0] == '\0') {
free(line); free(line);
continue; continue;
@ -1516,43 +1559,65 @@ MainLoop(PsqlSettings * settings, FILE * source)
SendQuery(&success, settings, line, false, false, 0); SendQuery(&success, settings, line, false, false, 0);
successResult &= success; successResult &= success;
querySent = true; querySent = true;
} else { } else {
int i; int i;
was_bslash = false;
was_dash = false;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (!in_quote && line[i] == '\\') { if (querySent && !isspace(line[i])) {
char hold_char = line[i]; query[0] = '\0';
querySent = false;
}
/* inside a quote? */
if (in_quote && (line[i] != '\'')) {
continue;
/* inside an extended comment? */
} else if (xcomment != NULL) {
if (line[i] == '*' && line[i+1] == '/') {
xcomment = NULL;
i++;
};
continue;
/* possible backslash command? */
} else if (line[i] == '\\') {
char hold_char = line[i];
line[i] = '\0'; line[i] = '\0';
if (query_start[0] != '\0') { if (query_start[0] != '\0') {
if (query[0] != '\0') { if (query[0] != '\0') {
strcat(query, "\n"); strcat(query, "\n");
strcat(query, query_start); strcat(query, query_start);
} else } else {
strcpy(query, query_start); strcpy(query, query_start);
};
} }
line[i] = hold_char; line[i] = hold_char;
query_start = line + i; query_start = line + i;
break; /* handle command */ break; /* handle command */
}
if (querySent && !isspace(line[i])) { /* start an extended comment? */
query[0] = '\0'; } else if (line[i] == '/' && line[i+1] == '*') {
querySent = false; xcomment = line + i;
} i++;
if (!in_quote && was_dash && line[i] == '-') { continue;
/* single-line comment? truncate line */
} else if (line[i] == '-' && line[i+1] == '-') {
/* print comment at top of query */ /* print comment at top of query */
if (settings->singleStep) if (settings->singleStep)
fprintf(stdout, "%s\n", line + i - 1); fprintf(stdout, "%s\n", line + i);
line[i - 1] = '\0'; /* remove comment */ line[i] = '\0'; /* remove comment */
break; break;
}
was_dash = false;
if (!in_quote && !paren_level && } else if (line[i] == '\'') {
line[i] == ';') { in_quote ^= 1;
char hold_char = line[i + 1];
/* semi-colon? then send query now */
} else if (!paren_level && line[i] == ';') {
char hold_char = line[i + 1];
line[i + 1] = '\0'; line[i + 1] = '\0';
if (query_start[0] != '\0') { if (query_start[0] != '\0') {
@ -1567,34 +1632,34 @@ MainLoop(PsqlSettings * settings, FILE * source)
line[i + 1] = hold_char; line[i + 1] = hold_char;
query_start = line + i + 1; query_start = line + i + 1;
querySent = true; querySent = true;
}
if (was_bslash) } else if (line[i] == '(') {
was_bslash = false;
else if (line[i] == '\\')
was_bslash = true;
else if (line[i] == '\'')
in_quote ^= 1;
else if (!in_quote && line[i] == '(')
paren_level++; paren_level++;
else if (!in_quote && paren_level && line[i] == ')')
} else if (paren_level && line[i] == ')') {
paren_level--; paren_level--;
else if (!in_quote && line[i] == '-') };
was_dash = true;
} }
} }
slashCmdStatus = -1; /* nothing on line after trimming? then ignore */
if (line[0] == '\0') {
free(line);
continue;
}
slashCmdStatus = CMD_UNKNOWN;
if (!in_quote && query_start[0] == '\\') { if (!in_quote && query_start[0] == '\\') {
slashCmdStatus = HandleSlashCmds(settings, slashCmdStatus = HandleSlashCmds(settings,
query_start, query_start,
query); query);
if (slashCmdStatus == 1) { if (slashCmdStatus == CMD_SKIP_LINE) {
if (query[0] == '\0') if (query[0] == '\0')
paren_level = 0; paren_level = 0;
free(line); free(line);
continue; continue;
} }
if (slashCmdStatus == 2) { if (slashCmdStatus == CMD_TERMINATE) {
free(line); free(line);
break; break;
} }
@ -1617,15 +1682,23 @@ MainLoop(PsqlSettings * settings, FILE * source)
free(line); /* PURIFY */ free(line); /* PURIFY */
} }
if (slashCmdStatus == 0) { /* had a backslash-g? force the query to be sent */
if (slashCmdStatus == CMD_SEND) {
#if FALSE
if (! querySent) {
SendQuery(&success, settings, query, false, false, 0);
successResult &= success;
}
#else
SendQuery(&success, settings, query, false, false, 0); SendQuery(&success, settings, query, false, false, 0);
successResult &= success; successResult &= success;
#endif
querySent = true; querySent = true;
} }
} }
} /* while */ } /* while */
return successResult; return successResult;
} } /* MainLoop() */
int int
main(int argc, char **argv) main(int argc, char **argv)