]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Regularize CLI .mode processing
authorlarrybr <larrybr@noemail.net>
Thu, 24 Feb 2022 04:29:09 +0000 (04:29 +0000)
committerlarrybr <larrybr@noemail.net>
Thu, 24 Feb 2022 04:29:09 +0000 (04:29 +0000)
FossilOrigin-Name: 6d0557244f69e78474f9222aae95c4c47925a466aa15e5666d0ada237538e262

manifest
manifest.uuid
src/shell.c.in
test/shell1.test

index f70c7f90be6883dfb656102b6fbc5986dd624c07..da4d88a4cb135b8ffd73e5551cf8aad8fbce10a3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Sync\swith\s3.38
-D 2022-02-23T10:10:59.145
+C Regularize\sCLI\s.mode\sprocessing
+D 2022-02-24T04:29:09.586
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -555,7 +555,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
 F src/resolve.c ea935b87d6fb36c78b70cdc7b28561dc8f33f2ef37048389549c7b5ef9b0ba5e
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
 F src/select.c 3baa9dd8cf240654773c7974e2bcce398ac9dd24419c36684156963defe43b35
-F src/shell.c.in 1986c71edd5023c320d5c68a14a464cc375cf7b3d7b7fc730bd6368a89576882
+F src/shell.c.in 0b1269056aca0e71680a65dac98bd731597f97334ab7a06509eba49f4d6e5093
 F src/shext_linkage.h 5897e8140a06cb733d07a927994b30d41225eb93b5b8cf2ad0e3460cb4e95fd6
 F src/sqlite.h.in e30cedf008d9c51511f4027a3739b727a588da553424748b48d2393f85dbde41
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
@@ -1391,7 +1391,7 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69
 F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
 F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
-F test/shell1.test 8ff9d7684346a39fdd73e201d30788b5d2207fd527d83ba793f8b1a85d6f34d1
+F test/shell1.test e05b84687a531419165dd79aefcfd149e4da24532480ec93439ddfa13efdf65b
 F test/shell2.test aed8773dd236517149a6abaeccf94f066e5a0c871108e8d21889122132dd51ba
 F test/shell3.test a50628ab1d78d90889d9d3f32fb2c084ee15674771e96afe954aaa0accd1de3c
 F test/shell4.test 8f6c0fce4abed19a8a7f7262517149812a04caa905d01bdc8f5e92573504b759
@@ -1947,8 +1947,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P ec363f81ce775bb3313d08a959e1573f694f18eb4699a33a9b98ce241056292e 710de6a2137c872812effa43ea888aa77d339362ca0b6c8990d4426c8fb20689
-R 3e137f57c07bfa1d2f3bcf91d0b0c096
+P b9b27d74b93ada32ece46c9e53652f766de97f5a77fe4c34251996697374e659
+R 3b1535aa20e62ad155a398c2745a0c17
 U larrybr
-Z adaf44bd0c510479196b838bd6c2a755
+Z 1bf768e26b209b9a9f7fc853e590446e
 # Remove this line to create a well-formed Fossil manifest.
index e8894783483284ea738680c5758a9fd9cd1922db..d3eefb1647139034b21f6818dbbde9cb486d2c3d 100644 (file)
@@ -1 +1 @@
-b9b27d74b93ada32ece46c9e53652f766de97f5a77fe4c34251996697374e659
\ No newline at end of file
+6d0557244f69e78474f9222aae95c4c47925a466aa15e5666d0ada237538e262
\ No newline at end of file
index 0f6b684706b03584a9c96c51a5cf71d46b6b7549..92a773bd5349a5050a5dea41708487352bb75f4e 100644 (file)
@@ -1285,48 +1285,55 @@ static void updateSafeMode(ShellState *pSS){
 #define ShellClearFlag(P,X)  ((P)->shellFlgs&=(~(X)))
 
 /*
-** These are the allowed modes.
+** These are the allowed modes, in search order (for abbreviation matches.)
 */
 #define MODE_Line     0  /* One column per line.  Blank line between records */
 #define MODE_Column   1  /* One record per line in neat columns */
 #define MODE_List     2  /* One record per line with a separator */
-#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
-#define MODE_Html     4  /* Generate an XHTML table */
-#define MODE_Insert   5  /* Generate SQL "insert" statements */
-#define MODE_Quote    6  /* Quote values as for SQL */
-#define MODE_Tcl      7  /* Generate ANSI-C or TCL quoted elements */
-#define MODE_Csv      8  /* Quote strings, numbers are plain */
-#define MODE_Explain  9  /* Like MODE_Column, but do not truncate data */
-#define MODE_Ascii   10  /* Use ASCII unit and record separators (0x1F/0x1E) */
-#define MODE_Pretty  11  /* Pretty-print schemas */
-#define MODE_EQP     12  /* Converts EXPLAIN QUERY PLAN output into a graph */
-#define MODE_Json    13  /* Output JSON */
-#define MODE_Markdown 14 /* Markdown formatting */
-#define MODE_Table   15  /* MySQL-style table formatting */
-#define MODE_Box     16  /* Unicode box-drawing characters */
-#define MODE_Count   17  /* Output only a count of the rows of output */
-#define MODE_Off     18  /* No query output shown */
-
-static const char *modeDescr[] = {
-  "line",
-  "column",
-  "list",
-  "semi",
-  "html",
-  "insert",
-  "quote",
-  "tcl",
-  "csv",
-  "explain",
-  "ascii",
-  "prettyprint",
-  "eqp",
-  "json",
-  "markdown",
-  "table",
-  "box",
-  "count",
-  "off"
+#define MODE_Html     3  /* Generate an XHTML table */
+#define MODE_Tcl      4  /* Generate ANSI-C or TCL quoted elements */
+#define MODE_Csv      5  /* Quote strings, numbers are plain */
+#define MODE_Tab      6  /* Transitory */
+#define MODE_Insert   7  /* Generate SQL "insert" statements */
+#define MODE_Quote    8  /* Quote values as for SQL */
+#define MODE_Ascii    9  /* Use ASCII unit and record separators (0x1F/0x1E) */
+#define MODE_Markdown 10 /* Markdown formatting */
+#define MODE_Table    11 /* MySQL-style table formatting */
+#define MODE_Box      12 /* Unicode box-drawing characters */
+#define MODE_Count    13 /* Output only a count of the rows of output */
+#define MODE_Off      14 /* No query output shown */
+#define MODE_Json     15 /* Output JSON */
+#define MODE_EQP      16 /* Converts EXPLAIN QUERY PLAN output into a graph */
+#define MODE_Explain  17 /* Like MODE_Column, but do not truncate data */
+#define MODE_Pretty   18 /* Pretty-print schemas */
+#define MODE_Semi     19 /* Same as MODE_List but append ";" to each line */
+#define MODE_COUNT_OF 20
+static struct {
+  const char *zModeName;
+  u8 bDepluralize;
+  u8 bUserBlocked;
+  u8 iAliasFor;
+} modeDescr[] = {
+  { "lines", 1, 0, MODE_Line },
+  { "columns", 1, 0, MODE_Column },
+  { "list", 0, 0, MODE_List },
+  { "html", 0, 0, MODE_Html },
+  { "tcl", 0, 0, MODE_Tcl },
+  { "csv", 0, 0, MODE_Csv },
+  { "tabs", 1, 0, MODE_List },
+  { "insert", 0, 0, MODE_Insert },
+  { "quote", 0, 0, MODE_Quote },
+  { "ascii", 0, 0, MODE_Ascii },
+  { "markdown", 0, 0, MODE_Markdown },
+  { "table", 0, 0, MODE_Table },
+  { "box", 0, 0, MODE_Box },
+  { "count", 0, 0, MODE_Count },
+  { "off", 0, 0, MODE_Off },
+  { "json", 0, 0, MODE_Json },
+  { "eqp", 0, 1, MODE_EQP },
+  { "explain", 0, 1, MODE_Explain },
+  { "prettyprint", 0, 1, MODE_Pretty },
+  { "semi", 0, 1, MODE_Semi }
 };
 
 /*
@@ -9177,126 +9184,153 @@ COLLECT_HELP_TEXT[
   "     --noquote      Do not quote output text",
   "     TABLE          The name of SQL table used for \"insert\" mode",
 ];
-DISPATCHABLE_COMMAND( mode ? 1 3 ){
-  const char *zMode = 0;
+DISPATCHABLE_COMMAND( mode ? 1 0 ){
   const char *zTabname = 0;
-  int i, n2;
+  const char *zArg;
+  int i;
+  u8 foundMode = MODE_COUNT_OF, setMode = MODE_COUNT_OF;
   ColModeOpts cmOpts = ColModeOpts_default;
   for(i=1; i<nArg; i++){
-    const char *z = azArg[i];
-    if( optionMatch(z,"wrap") && i+1<nArg ){
+    zArg = azArg[i];
+    if( optionMatch(zArg,"wrap") && i+1<nArg ){
       cmOpts.iWrap = integerValue(azArg[++i]);
-    }else if( optionMatch(z,"ww") ){
+    }else if( optionMatch(zArg,"ww") ){
       cmOpts.bWordWrap = 1;
-    }else if( optionMatch(z,"wordwrap") && i+1<nArg ){
+    }else if( optionMatch(zArg,"wordwrap") && i+1<nArg ){
       cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]);
-    }else if( optionMatch(z,"quote") ){
+    }else if( optionMatch(zArg,"quote") ){
       cmOpts.bQuote = 1;
-    }else if( optionMatch(z,"noquote") ){
+    }else if( optionMatch(zArg,"noquote") ){
       cmOpts.bQuote = 0;
-    }else if( zMode==0 ){
-      zMode = z;
-      /* Apply defaults for qbox pseudo-mods. If that
-       * overwrites already-set values, user was informed of this.
-       */
-      if( strcmp(z, "qbox")==0 ){
-        ColModeOpts cmo = ColModeOpts_default_qbox;
-        zMode = "box";
-        cmOpts = cmo;
-      }
-    }else if( zTabname==0 ){
-      zTabname = z;
-    }else if( z[0]=='-' ){
-      utf8_printf(stderr, "unknown option: %s\n", z);
-      utf8_printf(stderr, "options:\n"
-                  "  --noquote\n"
-                  "  --quote\n"
-                  "  --wordwrap on/off\n"
-                  "  --wrap N\n"
-                  "  --ww\n");
-      return 1;
     }else{
-      utf8_printf(stderr, "extra argument: \"%s\"\n", z);
-      return 1;
-    }
-  }
-  if( zMode==0 ){
-    if( p->mode==MODE_Column
-        || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
-        ){
+      /* Not a known option. Check for known mode, or possibly a table name. */
+      if( foundMode==MODE_Insert && zTabname==0 ){
+        zTabname = zArg;
+      }else if( *zArg=='-' ){
+        goto flag_unknown;
+      }else{
+        int im, nza = strlen30(zArg);
+        if( foundMode!=MODE_COUNT_OF ) goto mode_badarg;
+        for( im=0; im<MODE_COUNT_OF; ++im ){
+          if( modeDescr[i].bUserBlocked ) continue;
+          if( strncmp(zArg,modeDescr[im].zModeName,nza)==0 ){
+            foundMode = (u8)im;
+            setMode = modeDescr[im].iAliasFor;
+            break;
+          }
+        }
+        if( strcmp(zArg, "qbox")==0 ){
+          ColModeOpts cmo = ColModeOpts_default_qbox;
+          foundMode = setMode = MODE_Box;
+          cmOpts = cmo;
+        }else if( im==MODE_COUNT_OF ) goto mode_unknown;
+      }
+    }
+  } /* Arg loop */
+  if( foundMode==MODE_COUNT_OF ){
+    const char *zMode;
+    int nms;
+    i = p->mode;
+    assert(i>=0 && i<MODE_COUNT_OF);
+    zMode = modeDescr[i].zModeName;
+    nms = strlen30(zMode)-modeDescr[i].bDepluralize;
+    /* Mode not specified. Show present mode (and toss any options set.) */
+    if( p->mode==MODE_Column || (p->mode>=MODE_Markdown && p->mode<=MODE_Box) ){
       raw_printf
-        (p->out,
-         "current output mode: %s --wrap %d --wordwrap %s --%squote\n",
-         modeDescr[p->mode], p->cmOpts.iWrap,
+        (p->out, "current output mode: %.*s --wrap %d --wordwrap %s --%squote\n",
+         nms, zMode, p->cmOpts.iWrap,
          p->cmOpts.bWordWrap ? "on" : "off",
          p->cmOpts.bQuote ? "" : "no");
     }else{
-      raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
-    }
-    zMode = modeDescr[p->mode];
-  }
-  n2 = strlen30(zMode);
-  if( strncmp(zMode,"lines",n2)==0 ){
-    p->mode = MODE_Line;
-    sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
-  }else if( strncmp(zMode,"columns",n2)==0 ){
-    p->mode = MODE_Column;
-    if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){
-      p->showHeader = 1;
-    }
-    sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
-    p->cmOpts = cmOpts;
-  }else if( strncmp(zMode,"list",n2)==0 ){
-    p->mode = MODE_List;
-    sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
-    sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
-  }else if( strncmp(zMode,"html",n2)==0 ){
-    p->mode = MODE_Html;
-  }else if( strncmp(zMode,"tcl",n2)==0 ){
-    p->mode = MODE_Tcl;
-    sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
-    sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
-  }else if( strncmp(zMode,"csv",n2)==0 ){
-    p->mode = MODE_Csv;
-    sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
-    sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
-  }else if( strncmp(zMode,"tabs",n2)==0 ){
-    p->mode = MODE_List;
-    sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
-  }else if( strncmp(zMode,"insert",n2)==0 ){
-    p->mode = MODE_Insert;
-    set_table_name(p, zTabname ? zTabname : "table");
-  }else if( strncmp(zMode,"quote",n2)==0 ){
-    p->mode = MODE_Quote;
-    sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
-    sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
-  }else if( strncmp(zMode,"ascii",n2)==0 ){
-    p->mode = MODE_Ascii;
-    sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
-    sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
-  }else if( strncmp(zMode,"markdown",n2)==0 ){
-    p->mode = MODE_Markdown;
-    p->cmOpts = cmOpts;
-  }else if( strncmp(zMode,"table",n2)==0 ){
-    p->mode = MODE_Table;
-    p->cmOpts = cmOpts;
-  }else if( strncmp(zMode,"box",n2)==0 ){
-    p->mode = MODE_Box;
-    p->cmOpts = cmOpts;
-  }else if( strncmp(zMode,"count",n2)==0 ){
-    p->mode = MODE_Count;
-  }else if( strncmp(zMode,"off",n2)==0 ){
-    p->mode = MODE_Off;
-  }else if( strncmp(zMode,"json",n2)==0 ){
-    p->mode = MODE_Json;
+      raw_printf(p->out, "current output mode: %.*s\n", nms, zMode);
+    }
   }else{
-    raw_printf(stderr, "Error: mode should be one of: "
-               "ascii box column csv html insert json line list markdown "
-               "qbox quote table tabs tcl\n");
-    return 1;
+    /* Effect the specified mode change. */
+    const char *zColSep = 0, *zRowSep = 0;
+    assert(setMode!=MODE_COUNT_OF);
+    switch( foundMode ){
+    case MODE_Line:
+      zRowSep = SEP_Row;
+      break;
+    case MODE_Column:
+      if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){
+        p->showHeader = 1;
+      }
+      zRowSep = SEP_Row;
+      p->cmOpts = cmOpts;
+      break;
+    case MODE_List:
+      zColSep = SEP_Column;
+      zRowSep = SEP_Row;
+      break;
+    case MODE_Html:
+      break;
+    case MODE_Tcl:
+      zColSep = SEP_Space;
+      zRowSep = SEP_Row;
+      break;
+    case MODE_Csv:
+      zColSep = SEP_Comma;
+      zRowSep = SEP_CrLf;
+      break;
+    case MODE_Tab:
+      zColSep = SEP_Tab;
+      break;
+    case MODE_Insert:
+      set_table_name(p, zTabname ? zTabname : "table");
+      break;
+    case MODE_Quote:
+      zColSep = SEP_Comma;
+      zRowSep = SEP_Row;
+      break;
+    case MODE_Ascii:
+      zColSep = SEP_Unit;
+      zRowSep = SEP_Record;
+      break;
+    case MODE_Markdown:
+      /* fall-thru */
+    case MODE_Table:
+      /* fall-thru */
+    case MODE_Box:
+      p->cmOpts = cmOpts;
+      break;
+    case MODE_Count:
+      /* fall-thru */
+    case MODE_Off:
+      /* fall-thru */
+    case MODE_Json:
+      break;
+    case MODE_Explain: case MODE_Semi: case MODE_EQP: case MODE_Pretty: default:
+      /* Modes used internally, not settable by .mode command. */
+      return 0;
+    }
+    if( zRowSep!=0 ){
+      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, zRowSep);
+    }
+    if( zColSep!=0 ){
+      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, zColSep);
+    }
+    p->mode = setMode;
   }
   p->cMode = p->mode;
   return 0;
+ flag_unknown:
+  utf8_printf(stderr, "Error: Unknown .mode option: %s\nValid options:\n%s",
+              zArg,
+              "  --noquote\n"
+              "  --quote\n"
+              "  --wordwrap on/off\n"
+              "  --wrap N\n"
+              "  --ww\n");
+  return 1;
+ mode_unknown:
+  raw_printf(stderr, "Error: Mode should be one of: "
+             "ascii box column csv html insert json line list markdown "
+             "qbox quote table tabs tcl\n");
+  return 1;
+ mode_badarg:
+  utf8_printf(stderr, "Error: Invalid .mode argument: %s\n", zArg);
+  return 1;
 }
 
 /*****************
@@ -10715,16 +10749,18 @@ DISPATCHABLE_COMMAND( show ? 1 1 ){
   utf8_printf(p->out, "%12.12s: %s\n","explain",
               p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
   utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]);
+  zOut = modeDescr[p->mode].zModeName;
+  i = strlen30(zOut) - modeDescr[p->mode].bDepluralize;
   if( p->mode==MODE_Column
       || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
       ){
     utf8_printf
-      (p->out, "%12.12s: %s --wrap %d --wordwrap %s --%squote\n", "mode",
-       modeDescr[p->mode], p->cmOpts.iWrap,
+      (p->out, "%12.12s: %.*s --wrap %d --wordwrap %s --%squote\n", "mode",
+       i, zOut, p->cmOpts.iWrap,
        p->cmOpts.bWordWrap ? "on" : "off",
        p->cmOpts.bQuote ? "" : "no");
   }else{
-    utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]);
+    utf8_printf(p->out, "%12.12s: %.*s\n","mode", i, zOut);
   }
   utf8_printf(p->out, "%12.12s: ", "nullvalue");
   output_c_string(p->out, p->nullValue);
index fee302b5ddcd0fc100ad502f5ba238b34da8053b..2aca271e371e012584a72fbeb84c4fe94cace4c7 100644 (file)
@@ -190,7 +190,7 @@ do_test shell1-2.1.3 {
   catchcmd "test.db" ".\'foo OFF\'"
 } {1 {Error: unknown command: "foo OFF"}}
 
-set modeShouldBe "Error: mode should be one of: ascii box column csv html insert json line list markdown qbox quote table tabs tcl"
+set modeShouldBe "Error: Mode should be one of: ascii box column csv html insert json line list markdown qbox quote table tabs tcl"
 
 # unbalanced quotes
 do_test shell1-2.2.1 {
@@ -466,17 +466,11 @@ do_test shell1-3.13.10 {
 do_test shell1-3.13.11 {
   # extra arguments rejected
   catchcmd "test.db" ".mode tcl BAD"
-} {1 {Error: invalid arguments for ".mode"}}
+} {1 {Error: Invalid .mode argument: BAD}}
 
-# don't allow too-partial mode type matches
+# allow partial mode type matches
 do_test shell1-3.13.12 {
   catchcmd "test.db" ".mode l"
-} [list 1 $modeShouldBe]
-do_test shell1-3.13.13 {
-  catchcmd "test.db" ".mode li"
-} [list 1 $modeShouldBe]
-do_test shell1-3.13.14 {
-  catchcmd "test.db" ".mode lin"
 } {0 {}}
 
 # .nullvalue STRING      Print STRING in place of NULL values