]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
(WIP) Shell meta-command objectification done, ready for dbShell to be loaded and...
authorlarrybr <larrybr@noemail.net>
Sun, 6 Mar 2022 17:53:09 +0000 (17:53 +0000)
committerlarrybr <larrybr@noemail.net>
Sun, 6 Mar 2022 17:53:09 +0000 (17:53 +0000)
FossilOrigin-Name: a88983ecb7e2905219898e17d11de3598ee801c57b8ba32c51cb2790456a0e5b

manifest
manifest.uuid
src/shell.c.in
tool/mkshellc.tcl

index d514a66ceb8c69af775bc54c0dcf08353a3e179b..c1d97fc1e518cbdca02106e88d434ad68db13498 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C (WIP)\sshell\sextension\sload\sand\sShellState\sinternal/external\spartitioning\sin\splace,\spassing\sshell\stests\swith\strivial\sexceptions
-D 2022-03-06T03:22:13.817
+C (WIP)\sShell\smeta-command\sobjectification\sdone,\sready\sfor\sdbShell\sto\sbe\sloaded\sand\sused\sfor\sextension\smeta-commands
+D 2022-03-06T17:53:09.997
 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 da85b36617af6eee9bc1b3ecb1ef2d7b17bed3acc42b367ff9d1ee8794687532
+F src/shell.c.in b5ac2daac19a40b0359ef1c55a8916e385854a46813dd3fa41895f6b39773cc8
 F src/shext_linkage.h bff86090e82d1df3a6dd0c566324f38ac67cb75d6e72697d9a8a3065545b4f0c
 F src/sqlite.h.in e30cedf008d9c51511f4027a3739b727a588da553424748b48d2393f85dbde41
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
@@ -1883,7 +1883,7 @@ F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61
 F tool/mkopcodeh.tcl 130b88697da6ec5b89b41844d955d08fb62c2552e889dec8c7bcecb28d8f50bd
 F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
 F tool/mkpragmatab.tcl bd07bd59d45d0f3448e123d6937e9811195f9908a51e09d774609883055bfd3d
-F tool/mkshellc.tcl 36ecc5f66eab5c4687af1a0a4cb8435e9b5ab8ec9422ea63096b74453f83bf9b
+F tool/mkshellc.tcl 8b59d0312c708acb00b9242a2eb79cdf3a84d972c06bb09447599ebadc1d5cbf
 F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
 F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
@@ -1949,8 +1949,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 4c7d94d3f339d5de98ab5488e75b5dfea2c11fadb2cd44a9f6bc4e0769dbd34a
-R 4896c526cf9c30b9709825dd81bf0bdb
+P a85679d3e9e1edf71ed6308377783cdaa677c51290f644a28da9a69d429e7be9
+R ba61495e364ca7be34de1f25f5104c9e
 U larrybr
-Z 8541d8e1a52cfb449200764f60f8482a
+Z 9c5099ee4121c6747f3b8f1539d8df34
 # Remove this line to create a well-formed Fossil manifest.
index 7ba0c374f08dc460cbe7d959c21b2c92fd291436..c4e9b231e1242f76a524e88bc9d026e4c93850c4 100644 (file)
@@ -1 +1 @@
-a85679d3e9e1edf71ed6308377783cdaa677c51290f644a28da9a69d429e7be9
\ No newline at end of file
+a88983ecb7e2905219898e17d11de3598ee801c57b8ba32c51cb2790456a0e5b
\ No newline at end of file
index 1528586763a3c031544dcc3ed3485bc15b198d20..9d5d9d3011859ec3b3cc1ed299c264ca0bac0aa3 100644 (file)
@@ -247,7 +247,6 @@ static void setTextMode(FILE *file, int isOutput){
 # define setTextMode(X,Y)
 #endif
 
-static const char *(azHelp[]);
 static unsigned numCommands;
 static FILE *currentOutputFile(ShellExState *p);
 
@@ -4622,91 +4621,8 @@ DISPATCH_CONFIG[
  * Alternative is 0 and "%s\n" .
  */
 
-/*
-** Output primary (single-line) help for a known command.
-*/
-static void showPrimaryHelp(FILE *out, const char *zCmd){
-  const char **pzH;
-  int nc = strlen30(zCmd);
-  for(pzH = azHelp; *pzH != 0; ++pzH){
-    if( **pzH=='.' && strncmp(zCmd, (*pzH)+1, nc)==0 ){
-      utf8_printf(out, HELP_TEXT_FMT, *pzH);
-      break;
-    }
-  }
-}
-
-/*
-** Output various subsets of help text. These 5 are defined:
-** 1. For all commands, primary help text only.
-** 2. For all commands, complete help text.
-** 3. For multiple commands matching a pattern, primary help text only.
-** 4. For a single matched command, complete help text.
-** 5. For commands whose help contains a pattern, complete help text.
-** These variations are indicated thusly:
-** 1. zPattern is NULL
-** 2. zPattern is ""
-** 3. zPattern is a prefix matching more than one command
-** 4. zPattern is a word or prefix matching just one command
-** 5. zPattern is neither case 3 or 4 but is found in complete help text
-**
-** Return the number of matches.
-*/
-static int showHelp(FILE *out, const char *zPattern){
-  int npm = 0;
-  char *zPat = sqlite3_mprintf(".%s*", zPattern? zPattern : "");
-  const char **pzHxtra;
-  const char **pzH;
-  int nma = 0;
-  shell_check_oom(zPat);
-  for(pzH = azHelp; *pzH != 0; ++pzH){
-    /* Look for all commands or those for which zPattern is an exact prefix */
-    if( *pzH[0]=='.' ){
-      if ( sqlite3_strglob(zPat, *pzH)==0 ){
-        utf8_printf(out, HELP_TEXT_FMT, *pzH);
-        pzHxtra = pzH + 1;
-        ++npm;
-      }
-    }else if( zPattern && *zPattern==0 ){
-      utf8_printf(out, HELP_TEXT_FMT, *pzH);
-    }
-  }
-  sqlite3_free(zPat);
-  if( npm==1 ){
-    /* When zPattern is a prefix of exactly one command, then include
-    ** the secondary help of that command, (beginning at *pzHxtra.) */
-    while( *pzHxtra !=0 && *pzHxtra[0]!='.' ){
-      utf8_printf(out, HELP_TEXT_FMT, *pzHxtra++);
-    }
-  }
-  if( npm>0 )
-    return npm;
-
-  /* Having failed to match a command, look for commands whose help contains
-   * zPattern anywhere. Show the complete text of all such commands.
-   */
-  zPat = sqlite3_mprintf("%%%s%%", zPattern);
-  if( zPat==0 ) shell_out_of_memory();
-  for(pzH = azHelp; *pzH != 0;){
-    if( *pzH[0]=='.' ){
-      pzHxtra = pzH;
-      nma = 0;
-    }
-    if( sqlite3_strlike(zPat, *pzH, 0)==0 )
-      ++nma;
-    ++pzH;
-    if( nma>0 && (*pzH==0 || *pzH[0]=='.') ){
-      ++npm;
-      while( pzHxtra < pzH )
-        utf8_printf(out, HELP_TEXT_FMT, *pzHxtra++);
-    }
-  }
-  sqlite3_free(zPat);
-
-  return npm;
-}
-
-/* Forward reference */
+/* Forward references */
+static int showHelp(FILE *out, const char *zPattern, ShellExState *);
 static int process_input(ShellInState *psx);
 
 /*
@@ -6438,8 +6354,8 @@ struct ArCommand {
 /*
 ** Print a usage message for the .ar command to stderr and return SQLITE_ERROR.
 */
-static int arUsage(FILE *f){
-  showHelp(f,"archive");
+static int arUsage(FILE *f, ArCommand *pAr){
+  showHelp(f,"archive", pAr->p);
   return SQLITE_ERROR;
 }
 
@@ -6561,7 +6477,7 @@ static int arParseCommand(
                 azArg[0]);
     if( stdin_is_interactive ){
       utf8_printf(STD_ERR, "Usage:\n");
-      return arUsage(STD_ERR);
+      return arUsage(STD_ERR, pAr);
     }
   }else{
     char *z = azArg[1];
@@ -7138,7 +7054,7 @@ static int arDotCommand(
         break;
 
       case AR_CMD_HELP:
-        arUsage(cmd.out);
+        arUsage(cmd.out, &cmd);
         break;
 
       case AR_CMD_INSERT:
@@ -7919,10 +7835,6 @@ static int load_shell_extension(ShellExState *psx, const char *zFile,
 }
 #endif
 
-#ifndef OBJECTIFY_COMMANDS
-# define OBJECTIFY_COMMANDS 1 /* This value required for extensibility. */
-#endif
-
 /* Meta-command implementation functions are defined in this section.
 COMMENT  Define meta-commands and provide for their dispatch and .help text.
 COMMENT  These should be kept in command name order for coding convenience
@@ -7931,8 +7843,8 @@ COMMENT  required for dispatch and help text is effected regardless.) The
 COMMENT  effect of this configuration can be seen in generated output or by
 COMMENT  executing tool/mkshellc.tcl --parameters (or --details or --help).
 COMMENT  Generally, this section defines dispatchable functions inline and
-COMMENT  causes collection of dispatch and help table entries, to be later
-COMMENT  emitted by certain macros. (See EMIT_* further on.)
+COMMENT  causes collection of command_table entry initializers, to be later
+COMMENT  emitted by a mkshellc macro. (See EMIT_METACMD_INIT further on.)
 ** All dispatchable meta-command execute functions have this signature:
 static int someCommand(char *azArg[], int nArg, ShellExState *p, char **pzErr);
 */
@@ -8873,7 +8785,7 @@ DISPATCHABLE_COMMAND( help 3 1 2 ){
       zPat = z;
     }
   }
-  if( showHelp(ISS(p)->out, zPat)==0 ){
+  if( showHelp(ISS(p)->out, zPat, p)==0 ){
     utf8_printf(ISS(p)->out, "Nothing matches '%s'\n", azArg[1]);
   }
   /* Help pleas never fail! */
@@ -10596,7 +10508,7 @@ DISPATCHABLE_COMMAND( parameter 2 2 0 ){
   }else
 
   {  /* If no command name and arg count matches, show a syntax error */
-    showHelp(ISS(p)->out, "parameter");
+    showHelp(ISS(p)->out, "parameter", p);
     return 1;
   }
 
@@ -10773,7 +10685,7 @@ DISPATCHABLE_COMMAND( recover ? 1 7 ){
     }
     else{
       *pzErr = shellMPrintf(0,"unexpected option: %s\n", azArg[i]);
-      showHelp(out, azArg[0]);
+      showHelp(out, azArg[0], p);
       return 1;
     }
   }
@@ -11512,7 +11424,7 @@ DISPATCHABLE_COMMAND( session 3 2 0 ){
 
   /* If no command name matches, show a syntax error */
   session_syntax_error:
-    showHelp(out, "session");
+    showHelp(out, "session", p);
     return 1;
   }
   return rc;
@@ -12605,7 +12517,7 @@ DISPATCHABLE_COMMAND( wheretrace ? 1 2 ){
  */
 COLLECT_HELP_TEXT[
   ".x NAMES ...             Excecute content of some .parameter set variable(s)",
-  "   Only variables whose name begins with a letter are eligible for this."
+  "   Only variables whose name begins with a letter are eligible for this.",
 ];
 DISPATCHABLE_COMMAND( x ? 1 0 ){
   int ia, rc, nErrors = 0;
@@ -12707,29 +12619,21 @@ static VTABLE_NAME(MetaCommand) meta_cmd_VtabBuiltIn = {
 
 /* Define and populate command dispatch table. */
 static struct CommandInfo {
-#if OBJECTIFY_COMMANDS
   VTABLE_NAME(MetaCommand) *mcVtabBuiltIn;
-#endif
   const char * cmdName;
   int (*cmdDoer)(char *azArg[], int nArg, ShellExState *, char **pzErr);
   unsigned char minLen, minArgs, maxArgs;
-#if OBJECTIFY_COMMANDS
   const char *azHelp[2]; /* primary and secondary help text */
   void * pCmdData;
-#endif
-} command_table[] = {
+  } command_table[] = {
   COMMENT Emit the dispatch table entries generated and collected above.
-#if OBJECTIFY_COMMANDS
-# define META_CMD_INFO(cmd, nlenMin, minArgs, maxArgs, ht0, ht1 ) \
+#define META_CMD_INFO(cmd, nlenMin, minArgs, maxArgs, ht0, ht1 ) \
   { &meta_cmd_VtabBuiltIn, #cmd, cmd ## Command, \
     nlenMin, minArgs, maxArgs, { ht0, ht1 }, 0 \
   }
   EMIT_METACMD_INIT(2);
+#undef META_CMD_INFO
   { 0, 0, 0, 0, ~0, ~0, {0,0}, 0 }
-#else
-  EMIT_DISPATCH(2);
-  { 0, 0, 0, ~0, ~0 }
-#endif
 };
 static unsigned numCommands
   = sizeof(command_table)/sizeof(struct CommandInfo) - 1;
@@ -12763,70 +12667,207 @@ static int MetaCommand_execute(MetaCommand *pMe, ShellExState *pssx,
   return (((struct CommandInfo *)pMe)->cmdDoer)(azArgs, nArgs, pssx, pzErrMsg);
 }
 
-/*
-** Text of help messages.
-**
-** The help text for each individual command begins with a line that starts
-** with ".".  Subsequent lines are supplimental information.
-**
-** There must be two or more spaces between the end of the command and the
-** start of the description of what that command does.
-*/
-static const char *(azHelp[]) = {
-/* Template for help text indents and length:
-  ".whatever ?arg? ...      Summary of effects (limited to this line's length)",
-  "   ^ ^                   ^  ^                                              ",
-*/
-  COMMENT  Emit the help text fragments collected above via COLLECT_HELP_TEXT.
-  EMIT_HELP_TEXT(2);
-  0 /* Sentinel */
-};
+/*****************
+** MetaCommand iteration by name match, used by the .help meta-command
+** MetaCommands with matching names are produced in lexical order. Any
+** returned MetaMatchIter must eventually be passed to freeMetaMatchIter().
+*/
+typedef struct MetaMatchIter {
+  /* 0 indicates prepared statement; non-0 is the glob pattern. */
+  const char *zPattern;
+  union {
+    MetaCommand *pMC;
+    sqlite3_stmt *stmt;
+  };
+} MetaMatchIter;
 
+/* Prepare an iterator that will produce a sequence of MetaCommand
+ * pointers whose referents names match the given cmdFragment. */
+static MetaMatchIter findMatchingMetaCmds(const char *cmdFragment,
+                                          ShellExState *psx){
+  MetaMatchIter rv = { 0, 0 };
+  if( psx->dbShell==0 ){
+    rv.zPattern = sqlite3_mprintf("%s*", cmdFragment? cmdFragment : "");
+    shell_check_oom((void *)rv.zPattern);
+    rv.pMC = (MetaCommand *)command_table;
+  }else{
+    /* Prepare rv.stmt to yield results glob-matching cmdFragment. */
+  }
+  return rv;
+}
+/* Produce the next MetaCommand pointer from the iterator, or 0 if no next. */
+static MetaCommand * nextMatchingMetaCmd(MetaMatchIter *pMMI){
+  MetaCommand *rv = 0;
+  if( pMMI->zPattern!=0 ){
+    struct CommandInfo *pCI = (struct CommandInfo *)(pMMI->pMC);
+    assert(pCI>=command_table && pCI<=command_table+numCommands);
+    while( pCI<command_table+numCommands ){
+      if( sqlite3_strglob(pMMI->zPattern, pCI->cmdName)==0 ) rv = pMMI->pMC;
+      pMMI->pMC = (MetaCommand *)(++pCI);
+      if( rv!=0 ) break;
+    }
+  }else{
+    /* Future: Step the query finding matches once dbShell is loaded. */
+  }
+  return rv;
+}
+/* Release resources held by the iterator and clear it. */
+static void freeMetaMatchIter(MetaMatchIter *pMMI){
+  if( pMMI->zPattern!=0 ){
+    sqlite3_free((void *)pMMI->zPattern);
+    pMMI->zPattern = 0;
+    pMMI->pMC = 0;
+  }else{
+    sqlite3_finalize(pMMI->stmt);
+    pMMI->stmt = 0;
+  }
+}
+
+/*****************
+** MetaCommand lookup
+**
+** For the non-extended or non-extensible shell, this function does
+** a binary search of the fixed list of meta-command info structs.
+** For an extended shell, it queries the shell's DB. Either way,
+** this function returns a MetaCommand pointer if one can be found
+** with an adequate match for the given name. Here, "adequate" may
+** vary according to whether shell extensions have been loaded. If
+** not, the match must be for as many characters as set within the
+** above CommandInfo array (set via DISPATCHABLE_COMMAND macro call.)
+** If shell extensions are loaded, the match must be long enough to
+** result in a unique lookup.
+*/
+MetaCommand *findMetaCommand(const char *cmdName, ShellExState *psx,
+                             /* out */ int *nFound){
+  if( psx->dbShell!=0 ){
+    /* Future: Actually look it up (once registration is working.) */
+    *nFound = 0;
+    return 0;
+  }else{
+    int cmdLen = strlen30(cmdName);
+    struct CommandInfo *pci = 0;
+    int ixb = 0, ixe = numCommands-1;
+    while( ixb <= ixe ){
+      int ixm = (ixb+ixe)/2;
+      int md = strncmp(cmdName, command_table[ixm].cmdName, cmdLen);
+      if( md>0 ){
+        ixb = ixm+1;
+      }else if( md<0 ){
+        ixe = ixm-1;
+      }else{
+        if( command_table[ixm].minLen > cmdLen ) return 0;
+        pci = &command_table[ixm];
+        break;
+      }
+    }
+    return (MetaCommand *)pci;
+  }
+}
 
 #define NO_SUCH_COMMAND SQLITE_NOTFOUND
 /* SHELL_INVALID_ARGS defined as SQLITE_MISUSE in shext_linkage.h */
 
 /*****************
 ** Command dispatcher
-** For the non-extended or non-extensible shell, this function does
-** a binary search of the fixed list of meta-command info structs.
-** For an extended shell, it may (TBD) query the shell's DB. Either
-** way, this function retains its interface.
 ** After successful command lookup and (simple) argument checking,
-** it calls the found meta-command with the input arguments (except
+** invoke the found MetaCommand with the input arguments (except
 ** that azArg[0] is replaced with the properly spelled command name.)
 ** The return is either a dispatch error or whatever the dispatched
-** meta-command returns.
+** MetaCommand returns.
 */
 int dispatchCommand(char *azArg[], int nArg, ShellExState *psx, char **pzErr){
   const char *cmdName = azArg[0];
-  int cmdLen = strlen30(cmdName);
-  struct CommandInfo *pci = 0;
-  int ixb = 0, ixe = numCommands-1;
-  while( ixb <= ixe ){
-    int ixm = (ixb+ixe)/2;
-    int md = strncmp(cmdName, command_table[ixm].cmdName, cmdLen);
-    if( md>0 ){
-      ixb = ixm+1;
-    }else if( md<0 ){
-      ixe = ixm-1;
-    }else{
-      if( command_table[ixm].minLen > cmdLen ){
-        return NO_SUCH_COMMAND;
+  int nFound = 0, argsCheck;
+  MetaCommand *pMC = findMetaCommand(cmdName, psx, &nFound);
+  if( 0==pMC ) return NO_SUCH_COMMAND;
+  /* Future: Distinguish not found from ambiguous (due to too-short name.) */
+  argsCheck = pMC->pMethods->argsCheck(pMC, pzErr, nArg, azArg);
+  if( argsCheck!=0 ) return SHELL_INVALID_ARGS;
+  /* Replace any user-shortened command name with its whole name. */
+  azArg[0] = (char *)(pMC->pMethods->name(pMC));
+  return pMC->pMethods->execute(pMC, psx, pzErr, nArg, azArg);
+}
+
+/*
+** Output primary (single-line) help for a known command.
+*/
+static void showPrimaryHelp(FILE *out, const char *zCmd, ShellExState *psx){
+  MetaMatchIter mmi = findMatchingMetaCmds(zCmd, psx);
+  MetaCommand *pmc = nextMatchingMetaCmd(&mmi);
+  if( pmc!=0 ){
+    const char *zH = pmc->pMethods->help(pmc, 0);
+    if( zH!=0 ) utf8_printf(out, HELP_TEXT_FMT, zH);
+  }
+  freeMetaMatchIter(&mmi);
+}
+
+/*
+** Output various subsets of help text. These 5 are defined:
+** 1. For all commands, primary help text only.
+** 2. For all commands, complete help text.
+** 3. For multiple commands matching a pattern, primary help text only.
+** 4. For a single matched command, complete help text.
+** 5. For commands whose help contains a pattern, complete help text.
+** These variations are indicated thusly:
+** 1. zPattern is NULL
+** 2. zPattern is ""
+** 3. zPattern is a prefix matching more than one command
+** 4. zPattern is a word or prefix matching just one command
+** 5. zPattern is neither case 3 or 4 but is found in complete help text
+**
+** Return the number of matches.
+*/
+static int showHelp(FILE *out, const char *zPattern, ShellExState *psx){
+  u8 bNullPattern = zPattern==0;
+  u8 bEmptyPattern = (bNullPattern)? 0 : *zPattern==0;
+  int npm = 0; /* track how many matches found */
+  MetaMatchIter mmi = findMatchingMetaCmds(zPattern, psx);
+  MetaCommand *pmc, *pmcLastShown = 0;
+  char *zPat = 0;
+
+  while( 0 != (pmc = nextMatchingMetaCmd(&mmi)) ){
+    const char *zH = pmc->pMethods->help(pmc, 0);
+    if( zH!=0 ){
+      ++npm;
+      pmcLastShown = pmc;
+      utf8_printf(out, HELP_TEXT_FMT, zH);
+      if( bEmptyPattern ){
+        zH = pmc->pMethods->help(pmc, 1);
+        if( zH!=0 ){
+          utf8_printf(out, HELP_TEXT_FMT, zH);
+        }
       }
-      pci = &command_table[ixm];
-      break;
     }
   }
-  if( 0==pci ){
-    return NO_SUCH_COMMAND;
+  freeMetaMatchIter(&mmi);
+  if( npm==1 && !bEmptyPattern ){
+    /* When zPattern is a prefix of exactly one command, then emit
+     * the secondary help of that command, even if not requested,
+     * unless it was already emitted. */
+    const char *zH = pmcLastShown->pMethods->help(pmcLastShown, 1);
+    if( zH!=0 ) utf8_printf(out, HELP_TEXT_FMT, zH);
+    return npm;
   }
-  if( pci->minArgs > nArg||(pci->maxArgs > 0 && pci->maxArgs < nArg) ){
-    return SHELL_INVALID_ARGS;
+  /* If found anything with provided (or NULL or empty) pattern, it's done. */
+  if( npm>0 ) return npm;
+  /* Otherwise, look for the pattern in all of the help text and show the
+   * complete help for those meta-commands whose help matches. */
+  mmi = findMatchingMetaCmds("", psx);
+  zPat = sqlite3_mprintf("%%%s%%", zPattern);
+  shell_check_oom(zPat);
+  while( 0 != (pmc = nextMatchingMetaCmd(&mmi)) ){
+    const char *zHp = pmc->pMethods->help(pmc, 0);
+    const char *zHs = pmc->pMethods->help(pmc, 1);
+    if( (zHp!=0 && sqlite3_strlike(zPat, zHp, 0)==0)
+        || (zHs!=0 && sqlite3_strlike(zPat, zHs, 0)==0) ){
+      if( zHp ) utf8_printf(out, HELP_TEXT_FMT, zHp);
+      if( zHs ) utf8_printf(out, HELP_TEXT_FMT, zHs);
+      ++npm;
+    }
   }
-  /* Replace any user-shortened command name with its whole name. */
-  azArg[0] = (char *)pci->cmdName;
-  return (pci->cmdDoer)(azArg, nArg, psx, pzErr);
+  sqlite3_free(zPat);
+  freeMetaMatchIter(&mmi);
+  return npm;
 }
 
 /*
@@ -12942,7 +12983,7 @@ static int do_meta_command(char *zLine, ShellExState *psx){
           utf8_printf(STD_ERR, "  %s\n", zErr);
         }else{
           utf8_printf(STD_ERR, "Usage: ");
-          showPrimaryHelp(STD_ERR, azArg[0]);
+          showPrimaryHelp(STD_ERR, azArg[0], psx);
         }
       }
       rc = 1;
index 0da8fb267e61f9c2e9f08ac9a486ad45dfd1b051..2a1b8a93a07420869865d937f1f990081dd69666 100644 (file)
@@ -130,7 +130,6 @@ if {$::lineTags >= 3} {
   # which are used to get #line directives on all dispatch and help table
   # entries, and any conditionals affecting their compilation.
   array set ::cmd_help_tags {}
-  array set ::cmd_dispatch_tags {}
   array set ::cmd_conditional_tags {}
 }
 
@@ -198,7 +197,6 @@ proc emit_sync { lines ostrm precLines {fromFile ""} } {
 }
 
 array set ::cmd_help {}
-array set ::cmd_dispatch {}
 array set ::cmd_condition {}
 array set ::metacmd_init {}
 array set ::inc_type_files {}
@@ -341,8 +339,6 @@ array set ::macroTailREs [list \
   CONDITION_COMMAND {^\(\s*(\w+)\s+([^;]+)\);} \
   DISPATCH_CONFIG {^\[} \
   DISPATCHABLE_COMMAND {^\(([\w\? ]+)\)(\S)\s*$} \
-  EMIT_DISPATCH {^\((\d*)\)} \
-  EMIT_HELP_TEXT {^\((\d*)\)} \
   EMIT_METACMD_INIT {^\((\d*)\)} \
   INCLUDE {^(?:\(\s*(\w+)\s*\))|(?:\s+([\w./\\]+)\M)} \
   IGNORE_COMMANDS {^\(\s*([-+\w ]*)\)\s*;\s*} \
@@ -353,8 +349,6 @@ array set ::macroTailREs [list \
 # CONFIGURE_DISPATCH tailCapture_Empty
 # COLLECT_HELP_TEXT tailCapture_Empty
 # DISPATCHABLE_COMMAND tailCapture_ArgsGlom_TrailChar
-# EMIT_DISPATCH tailCapture_Indent
-# EMIT_HELP_TEXT tailCapture_Indent
 # EMIT_METACMD_INIT tailCapture_Indent
 # IGNORED_COMMANDS tailCapture_SignedCmdGlom
 # INCLUDE tailCapture_IncType_Filename
@@ -366,8 +360,6 @@ array set ::macroUsages [list \
   DISPATCH_CONFIG "\[\n   <NAME=value lines>\n  \];" \
   DISPATCHABLE_COMMAND \
       "( name args... ){\n   <implementation code lines>\n  }" \
-  EMIT_DISPATCH "( indent );" \
-  EMIT_HELP_TEXT "( indent );" \
   EMIT_METACMD_INIT "( indent );" \
   INCLUDE {( <inc_type> )} \
   SKIP_COMMANDS "( <signed_names> );" \
@@ -544,10 +536,8 @@ proc DISPATCHABLE_COMMAND {inSrc tailCapture ostrm} {
       set argexp [subst $::dispCfg(ARGS_SIGNATURE)]
       set fname [subst $::dispCfg(DISPATCHEE_NAME)]
       set funcOpen "$rsct $fname\($argexp\)$::lb"
-      set dispEntry [subst $::dispCfg(DISPATCH_ENTRY)]
       set mcInit [subst $::dispCfg(METACMD_INIT)]
       emit_conditionally $cmd [linsert $body 0 $funcOpen] $inSrc $ostrm
-      set ::cmd_dispatch($cmd) [list $dispEntry]
       set ::metacmd_init($cmd) $mcInit
       set_src_tags dispatch $cmd $inSrc
     }
@@ -555,15 +545,6 @@ proc DISPATCHABLE_COMMAND {inSrc tailCapture ostrm} {
   return $iAte
 }
 
-proc EMIT_DISPATCH {inSrc tailCap ostrm} {
-  # Emit the collected dispatch table entries, in command order, maybe
-  # wrapped with a conditional construct as set by CONDITION_COMMAND().
-  foreach cmd [lsort [array names ::cmd_dispatch]] {
-    emit_conditionally $cmd $::cmd_dispatch($cmd) $inSrc $ostrm $tailCap
-  }
-  return 1
-}
-
 proc EMIT_METACMD_INIT {inSrc tailCap ostrm} {
   # Emit the collected metacommand init table entries, in command order, maybe
   # wrapped with a conditional construct as set by CONDITION_COMMAND(). Prior
@@ -600,15 +581,6 @@ proc EMIT_METACMD_INIT {inSrc tailCap ostrm} {
   return 1
 }
 
-proc EMIT_HELP_TEXT {inSrc tailCap ostrm} {
-  # Emit the collected help text table entries, in command order, maybe
-  # wrapped with a conditional construct as set by CONDITION_COMMAND().
-  foreach htc [lsort [array names ::cmd_help]] {
-    emit_conditionally $htc $::cmd_help($htc) $inSrc $ostrm $tailCap
-  }
-  return 1
-}
-
 proc say_usage {macros {extra {}}} {
   puts stderr "Usage:$extra"
   foreach m $macros {puts stderr "  $m$::macroUsages($m)"}