Rearrange scanning code to support extended comments.
authorThomas G. Lockhart
Mon, 1 Sep 1997 06:09:53 +0000 (06:09 +0000)
committerThomas G. Lockhart
Mon, 1 Sep 1997 06:09:53 +0000 (06:09 +0000)
Use #define symbols rather than integers for scanning states.

src/bin/psql/psql.c

index 9fff389efdebc9d3fec841be7bcb2e28a8def998..191752b66fd927d759f552cffdd5b55da5fe6564 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * 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
@@ -978,28 +998,28 @@ do_edit(const char *filename_arg, char *query, int *status_p)
     }
 
     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;
        }
    }
     }
@@ -1118,17 +1138,19 @@ do_shell(const char *command)
  * 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  string to the argument of the slash command,
@@ -1188,7 +1210,7 @@ HandleSlashCmds(PsqlSettings * settings,
    }
    if (optarg && !(settings->opt.caption = strdup(optarg))) {
        perror("malloc");
-       exit(1);
+       exit(CMD_TERMINATE);
    }
    break;
     case 'c':{
@@ -1261,7 +1283,7 @@ HandleSlashCmds(PsqlSettings * settings,
        lastfile = malloc(strlen(optarg + 1));
        if (!lastfile) {
            perror("malloc");
-           exit(1);
+           exit(CMD_TERMINATE);
        }
        strcpy(lastfile, optarg);
        } else if (!lastfile) {
@@ -1293,10 +1315,10 @@ HandleSlashCmds(PsqlSettings * settings,
            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 */
@@ -1304,9 +1326,9 @@ HandleSlashCmds(PsqlSettings * settings,
        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 */
    {
@@ -1346,7 +1368,7 @@ HandleSlashCmds(PsqlSettings * settings,
    }
    break;
     case 'q':          /* \q is quit */
-   status = 2;
+   status = CMD_TERMINATE;
    break;
     case 'r':          /* reset(clear) the buffer */
    query[0] = '\0';
@@ -1369,13 +1391,13 @@ HandleSlashCmds(PsqlSettings * settings,
        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) */
@@ -1391,7 +1413,7 @@ HandleSlashCmds(PsqlSettings * settings,
        settings->opt.tableOpt = NULL;
    else if (!(settings->opt.tableOpt = strdup(optarg))) {
        perror("malloc");
-       exit(1);
+       exit(CMD_TERMINATE);
    }
    break;
     case 'x':
@@ -1407,31 +1429,33 @@ HandleSlashCmds(PsqlSettings * settings,
     }
     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;
@@ -1441,8 +1465,6 @@ MainLoop(PsqlSettings * settings, FILE * source)
     /* 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;
 
@@ -1467,24 +1489,30 @@ MainLoop(PsqlSettings * settings, FILE * source)
    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
@@ -1493,7 +1521,20 @@ MainLoop(PsqlSettings * settings, FILE * source)
 #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 */
@@ -1502,9 +1543,11 @@ MainLoop(PsqlSettings * settings, FILE * source)
        /* 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;
@@ -1516,43 +1559,65 @@ MainLoop(PsqlSettings * settings, FILE * source)
        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') {
@@ -1567,34 +1632,34 @@ MainLoop(PsqlSettings * settings, FILE * source)
            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;
        }
@@ -1617,15 +1682,23 @@ MainLoop(PsqlSettings * settings, FILE * source)
        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)