*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
# 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_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 COPYBUFSIZ 8192
}
if (error)
- *status_p = 1;
+ *status_p = CMD_SKIP_LINE;
else {
editFile(fname);
if ((fd = open(fname, O_RDONLY)) == -1) {
perror(fname);
if (!filename_arg)
unlink(fname);
- *status_p = 1;
+ *status_p = CMD_SKIP_LINE;
} else {
if ((cc = read(fd, query, MAX_QUERY_BUFFER)) == -1) {
perror(fname);
close(fd);
if (!filename_arg)
unlink(fname);
- *status_p = 1;
+ *status_p = CMD_SKIP_LINE;
} else {
query[cc] = '\0';
close(fd);
if (!filename_arg)
unlink(fname);
rightTrim(query);
- *status_p = 3;
+ *status_p = CMD_NEWEDIT;
}
}
}
* 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
* 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
- * 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
+ * with a connection to a new database.
+ * Returns a status:
+ * 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
*/
static int
HandleSlashCmds(PsqlSettings * settings,
char *line,
char *query)
{
- int status = 1;
+ int status = CMD_SKIP_LINE;
char *optarg;
/*
* Pointer inside the <cmd> string to the argument of the slash command,
}
if (optarg && !(settings->opt.caption = strdup(optarg))) {
perror("malloc");
- exit(1);
+ exit(CMD_TERMINATE);
}
break;
case 'c':{
lastfile = malloc(strlen(optarg + 1));
if (!lastfile) {
perror("malloc");
- exit(1);
+ exit(CMD_TERMINATE);
}
strcpy(lastfile, optarg);
} else if (!lastfile) {
free(settings->opt.fieldSep);
if (!(settings->opt.fieldSep = strdup(fs))) {
perror("malloc");
- exit(1);
+ exit(CMD_TERMINATE);
}
if (!settings->quiet)
- printf("field separater changed to '%s'\n", settings->opt.fieldSep);
+ printf("field separator changed to '%s'\n", settings->opt.fieldSep);
break;
}
case 'g': /* \g means send query */
settings->gfname = NULL;
else if (!(settings->gfname = strdup(optarg))) {
perror("malloc");
- exit(1);
+ exit(CMD_TERMINATE);
}
- status = 0;
+ status = CMD_SEND;
break;
case 'h': /* help */
{
}
break;
case 'q': /* \q is quit */
- status = 2;
+ status = CMD_TERMINATE;
break;
case 'r': /* reset(clear) the buffer */
query[0] = '\0';
free(settings->opt.fieldSep);
settings->opt.fieldSep = strdup("|");
if (!settings->quiet)
- printf("field separater changed to '%s'\n", settings->opt.fieldSep);
+ printf("field separator changed to '%s'\n", settings->opt.fieldSep);
} else {
if (settings->opt.fieldSep)
free(settings->opt.fieldSep);
settings->opt.fieldSep = strdup(DEFAULT_FIELD_SEP);
if (!settings->quiet)
- printf("field separater changed to '%s'\n", settings->opt.fieldSep);
+ printf("field separator changed to '%s'\n", settings->opt.fieldSep);
}
break;
case 'z': /* list table rights (grant/revoke) */
settings->opt.tableOpt = NULL;
else if (!(settings->opt.tableOpt = strdup(optarg))) {
perror("malloc");
- exit(1);
+ exit(CMD_TERMINATE);
}
break;
case 'x':
}
free(cmd);
return status;
-}
+} /* HandleSlashCmds() */
-/*
- * MainLoop: main processing loop for reading lines of input and sending them
- * to the backend
- *
- * this loop is re-entrant. May be called by \i command which reads input from
- * a file
+/* MainLoop()
+ * Main processing loop for reading lines of input
+ * and sending them to the backend.
*
- * db_ptr must be initialized and set
+ * This loop is re-entrant. May be called by \i command
+ * which reads input from a file.
+ * db_ptr must be initialized and set.
*/
static int
MainLoop(PsqlSettings * settings, FILE * source)
{
char *line; /* line of input */
+ char *xcomment; /* start of extended comment */
int len; /* length of the line */
char query[MAX_QUERY_BUFFER]; /* multi-line query storage */
int successResult = 1;
- int slashCmdStatus = 0;
+ int slashCmdStatus = CMD_SEND;
/*
- * slashCmdStatus can be: 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
+ * slashCmdStatus can be:
+ * CMD_UNKNOWN - send currently constructed query to backend (i.e. we got a \g)
+ * CMD_SEND - send currently constructed query to backend (i.e. we got a \g)
+ * 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;
/* We've reached the end of our command input. */
bool success;
bool in_quote;
- bool was_bslash; /* backslash */
- bool was_dash;
int paren_level;
char *query_start;
GetNextLine = gets_fromFile;
query[0] = '\0';
+ xcomment = NULL;
in_quote = false;
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) {
- if (slashCmdStatus == 3) {
+ /* just returned from editing the line? then just copy to the input buffer */
+ if (slashCmdStatus == CMD_NEWEDIT) {
paren_level = 0;
line = strdup(query);
query[0] = '\0';
+
+ /* otherwise, get another line and set interactive prompt if necessary */
} else {
if (interactive && !settings->quiet) {
- if (in_quote)
- settings->prompt[strlen(settings->prompt)-3] = '\'';
- else if (query[0] != '\0' && !querySent)
- settings->prompt[strlen(settings->prompt)-3] = '-';
- else
- settings->prompt[strlen(settings->prompt)-3] = '=';
+ if (in_quote)
+ settings->prompt[strlen(settings->prompt)-3] = PROMPT_QUOTE;
+ else if (xcomment != NULL)
+ settings->prompt[strlen(settings->prompt)-3] = PROMPT_COMMENT;
+ else if (query[0] != '\0' && !querySent)
+ settings->prompt[strlen(settings->prompt)-3] = PROMPT_CONTINUE;
+ else
+ settings->prompt[strlen(settings->prompt)-3] = PROMPT_READY;
}
line = GetNextLine(settings->prompt, source);
#ifdef HAVE_HISTORY
#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 (!settings->quiet)
printf("EOF\n"); /* Goes on prompt line */
/* remove whitespaces on the right, incl. \n's */
line = rightTrim(line);
+ /* echo back if input is from file */
if (!interactive && !settings->singleStep && !settings->quiet)
fprintf(stderr, "%s\n", line);
+ /* nothing on line after trimming? then ignore */
if (line[0] == '\0') {
free(line);
continue;
SendQuery(&success, settings, line, false, false, 0);
successResult &= success;
querySent = true;
+
} else {
- int i;
- was_bslash = false;
- was_dash = false;
+ int i;
for (i = 0; i < len; i++) {
- if (!in_quote && line[i] == '\\') {
- char hold_char = line[i];
+ if (querySent && !isspace(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';
if (query_start[0] != '\0') {
if (query[0] != '\0') {
strcat(query, "\n");
strcat(query, query_start);
- } else
+ } else {
strcpy(query, query_start);
+ };
}
line[i] = hold_char;
query_start = line + i;
break; /* handle command */
- }
- if (querySent && !isspace(line[i])) {
- query[0] = '\0';
- querySent = false;
- }
- if (!in_quote && was_dash && line[i] == '-') {
+
+ /* start an extended comment? */
+ } else if (line[i] == '/' && line[i+1] == '*') {
+ xcomment = line + i;
+ i++;
+ continue;
+
+ /* single-line comment? truncate line */
+ } else if (line[i] == '-' && line[i+1] == '-') {
/* print comment at top of query */
if (settings->singleStep)
- fprintf(stdout, "%s\n", line + i - 1);
- line[i - 1] = '\0'; /* remove comment */
+ fprintf(stdout, "%s\n", line + i);
+ line[i] = '\0'; /* remove comment */
break;
- }
- was_dash = false;
- if (!in_quote && !paren_level &&
- line[i] == ';') {
- char hold_char = line[i + 1];
+ } else if (line[i] == '\'') {
+ in_quote ^= 1;
+
+ /* semi-colon? then send query now */
+ } else if (!paren_level && line[i] == ';') {
+ char hold_char = line[i + 1];
line[i + 1] = '\0';
if (query_start[0] != '\0') {
line[i + 1] = hold_char;
query_start = line + i + 1;
querySent = true;
- }
- if (was_bslash)
- was_bslash = false;
- else if (line[i] == '\\')
- was_bslash = true;
- else if (line[i] == '\'')
- in_quote ^= 1;
- else if (!in_quote && line[i] == '(')
+
+ } else if (line[i] == '(') {
paren_level++;
- else if (!in_quote && paren_level && line[i] == ')')
+
+ } else if (paren_level && line[i] == ')') {
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] == '\\') {
slashCmdStatus = HandleSlashCmds(settings,
query_start,
query);
- if (slashCmdStatus == 1) {
+ if (slashCmdStatus == CMD_SKIP_LINE) {
if (query[0] == '\0')
paren_level = 0;
free(line);
continue;
}
- if (slashCmdStatus == 2) {
+ if (slashCmdStatus == CMD_TERMINATE) {
free(line);
break;
}
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);
successResult &= success;
+#endif
querySent = true;
}
}
} /* while */
return successResult;
-}
+} /* MainLoop() */
int
main(int argc, char **argv)