From: larrybr Date: Sat, 3 Jul 2021 19:20:48 +0000 (+0000) Subject: Create infrastructure for dynamic shell extension. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ab5722c7da906f72b37e8554a952c285f6d4736e;p=thirdparty%2Fsqlite.git Create infrastructure for dynamic shell extension. FossilOrigin-Name: 5e7e0d4ef8665e924f499238b1469a5fc06d24f6cf96864b502e62734d92e7ee --- diff --git a/manifest b/manifest index 40a5aa83a1..5821ef2b6a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sPRAGMA\sforeign_key_check,\sensure\sthat\ssufficient\sregisters\sare\nallocated\sfor\sthe\svirtual\smachine,\seven\sif\sone\sor\smore\sforeign\skeys\sreuses\nthe\ssame\scolumn\smultiple\stimes\sand\shas\smore\scolumns\sthan\sthe\stable\sit\sis\spart\nof.\s\s[forum:/forumpost/a6b0c05277|Forum\spost\sa6b0c05277]. -D 2021-07-03T02:55:47.684 +C Create\sinfrastructure\sfor\sdynamic\sshell\sextension. +D 2021-07-03T19:20:48.689 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -545,7 +545,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c b379c5ffe3b692e9c64fa37817cc0efa204b7c9468a818309dde85fd132d9d81 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 4fa607bab6bcc580f12dbaf9c800b2250a1e408f10321a1d3bcb1dd30c447e62 -F src/shell.c.in 699910739eb7296fd47be19db71f6e5d15d0760f4352c62639d4d6cc7bd8d4cc +F src/shell.c.in ab31fb9d92ab84e1abb02a2c40e910b24434e729fa7549acbb3fee9aed5973d8 F src/sqlite.h.in ecf5aa981da30c33da3e9f353bf3ebf055d3c380c80d6a4f954e58d18ccd6df1 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h e97f4e9b509408fea4c4e9bef5a41608dfac343b4d3c7a990dedde1e19af9510 @@ -1853,7 +1853,7 @@ F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c F tool/mkopcodeh.tcl 130b88697da6ec5b89b41844d955d08fb62c2552e889dec8c7bcecb28d8f50bd F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa F tool/mkpragmatab.tcl ae5585ae76ca26e4d6ccd5ea9cdebaf5efefb318bf989497a0e846cd711d9ab1 -F tool/mkshellc.tcl 5fe7e518112b262e25726f248c0f33dd153192867453984b6af0a76a88e97cb2 +F tool/mkshellc.tcl 627d5f39b306cc335e5f29d8b24945c54a64a42e635fc8eb8c2558ba257c9844 F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f @@ -1919,7 +1919,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 55e2fbebb0a2c9991feef46f31e79b82a24de272aae836bf4d3c06ee06ef1a70 -R 6361a08fc6d48a70d5a532fc3e15d75a -U drh -Z e9d1bfeaf7de1edba9fbe2d83f57c7d8 +P 68db1ff9c44fa9c37690ce55ad304d4263ba6fac490063d9e08470de6c17cfe6 +R 347b1c92e54f1f6ec16ffdb8c5434cca +T *branch * cli_extension +T *sym-cli_extension * +T -sym-trunk * +U larrybr +Z d788ab2ca1c9950dfd92c69b64866455 diff --git a/manifest.uuid b/manifest.uuid index ae2f2c4709..f649a6ef7e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -68db1ff9c44fa9c37690ce55ad304d4263ba6fac490063d9e08470de6c17cfe6 \ No newline at end of file +5e7e0d4ef8665e924f499238b1469a5fc06d24f6cf96864b502e62734d92e7ee \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index f90822e281..5fa089b490 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -217,6 +217,7 @@ static void setTextMode(FILE *file, int isOutput){ # define setTextMode(X,Y) #endif +static const char *(azHelp[]); /* True if the timer is enabled */ static int enableTimer = 0; @@ -3849,258 +3850,6 @@ static int run_schema_dump_query( return rc; } -/* -** 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[]) = { -#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) - ".archive ... Manage SQL archives", - " Each command must have exactly one of the following options:", - " -c, --create Create a new archive", - " -u, --update Add or update files with changed mtime", - " -i, --insert Like -u but always add even if unchanged", - " -t, --list List contents of archive", - " -x, --extract Extract files from archive", - " Optional arguments:", - " -v, --verbose Print each filename as it is processed", - " -f FILE, --file FILE Use archive FILE (default is current db)", - " -a FILE, --append FILE Open FILE using the apndvfs VFS", - " -C DIR, --directory DIR Read/extract files from directory DIR", - " -n, --dryrun Show the SQL that would have occurred", - " Examples:", - " .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar", - " .ar -tf ARCHIVE # List members of ARCHIVE", - " .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE", - " See also:", - " http://sqlite.org/cli.html#sqlite_archive_support", -#endif -#ifndef SQLITE_OMIT_AUTHORIZATION - ".auth ON|OFF Show authorizer callbacks", -#endif - ".backup ?DB? FILE Backup DB (default \"main\") to FILE", - " --append Use the appendvfs", - " --async Write to FILE without journal and fsync()", - ".bail on|off Stop after hitting an error. Default OFF", - ".binary on|off Turn binary output on or off. Default OFF", - ".cd DIRECTORY Change the working directory to DIRECTORY", - ".changes on|off Show number of rows changed by SQL", - ".check GLOB Fail if output since .testcase does not match", - ".clone NEWDB Clone data into NEWDB from the existing database", - ".databases List names and files of attached databases", - ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", - ".dbinfo ?DB? Show status information about the database", - ".dump ?OBJECTS? Render database content as SQL", - " Options:", - " --data-only Output only INSERT statements", - " --newlines Allow unescaped newline characters in output", - " --nosys Omit system tables (ex: \"sqlite_stat1\")", - " --preserve-rowids Include ROWID values in the output", - " OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump", - " Additional LIKE patterns can be given in subsequent arguments", - ".echo on|off Turn command echo on or off", - ".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN", - " Other Modes:", -#ifdef SQLITE_DEBUG - " test Show raw EXPLAIN QUERY PLAN output", - " trace Like \"full\" but enable \"PRAGMA vdbe_trace\"", -#endif - " trigger Like \"full\" but also show trigger bytecode", - ".excel Display the output of next command in spreadsheet", - " --bom Put a UTF8 byte-order mark on intermediate file", - ".exit ?CODE? Exit this program with return-code CODE", - ".expert EXPERIMENTAL. Suggest indexes for queries", - ".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto", - ".filectrl CMD ... Run various sqlite3_file_control() operations", - " --schema SCHEMA Use SCHEMA instead of \"main\"", - " --help Show CMD details", - ".fullschema ?--indent? Show schema and the content of sqlite_stat tables", - ".headers on|off Turn display of headers on or off", - ".help ?-all? ?PATTERN? Show help text for PATTERN", - ".import FILE TABLE Import data from FILE into TABLE", - " Options:", - " --ascii Use \\037 and \\036 as column and row separators", - " --csv Use , and \\n as column and row separators", - " --skip N Skip the first N rows of input", - " -v \"Verbose\" - increase auxiliary output", - " Notes:", - " * If TABLE does not exist, it is created. The first row of input", - " determines the column names.", - " * If neither --csv or --ascii are used, the input mode is derived", - " from the \".mode\" output mode", - " * If FILE begins with \"|\" then it is a command that generates the", - " input text.", -#ifndef SQLITE_OMIT_TEST_CONTROL - ".imposter INDEX TABLE Create imposter table TABLE on index INDEX", -#endif - ".indexes ?TABLE? Show names of indexes", - " If TABLE is specified, only show indexes for", - " tables matching TABLE using the LIKE operator.", -#ifdef SQLITE_ENABLE_IOTRACE - ".iotrace FILE Enable I/O diagnostic logging to FILE", -#endif - ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT", - ".lint OPTIONS Report potential schema issues.", - " Options:", - " fkey-indexes Find missing foreign key indexes", -#ifndef SQLITE_OMIT_LOAD_EXTENSION - ".load FILE ?ENTRY? Load an extension library", -#endif - ".log FILE|off Turn logging on or off. FILE can be stderr/stdout", - ".mode MODE ?TABLE? Set output mode", - " MODE is one of:", - " ascii Columns/rows delimited by 0x1F and 0x1E", - " box Tables using unicode box-drawing characters", - " csv Comma-separated values", - " column Output in columns. (See .width)", - " html HTML code", - " insert SQL insert statements for TABLE", - " json Results in a JSON array", - " line One value per line", - " list Values delimited by \"|\"", - " markdown Markdown table format", - " quote Escape answers as for SQL", - " table ASCII-art table", - " tabs Tab-separated values", - " tcl TCL list elements", - ".nullvalue STRING Use STRING in place of NULL values", - ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE", - " If FILE begins with '|' then open as a pipe", - " --bom Put a UTF8 byte-order mark at the beginning", - " -e Send output to the system text editor", - " -x Send output as CSV to a spreadsheet (same as \".excel\")", -#ifdef SQLITE_DEBUG - ".oom ?--repeat M? ?N? Simulate an OOM error on the N-th allocation", -#endif - ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE", - " Options:", - " --append Use appendvfs to append database to the end of FILE", -#ifndef SQLITE_OMIT_DESERIALIZE - " --deserialize Load into memory using sqlite3_deserialize()", - " --hexdb Load the output of \"dbtotxt\" as an in-memory db", - " --maxsize N Maximum size for --hexdb or --deserialized database", -#endif - " --new Initialize FILE to an empty database", - " --nofollow Do not follow symbolic links", - " --readonly Open FILE readonly", - " --zip FILE is a ZIP archive", - ".output ?FILE? Send output to FILE or stdout if FILE is omitted", - " If FILE begins with '|' then open it as a pipe.", - " Options:", - " --bom Prefix output with a UTF8 byte-order mark", - " -e Send output to the system text editor", - " -x Send output as CSV to a spreadsheet", - ".parameter CMD ... Manage SQL parameter bindings", - " clear Erase all bindings", - " init Initialize the TEMP table that holds bindings", - " list List the current parameter bindings", - " set PARAMETER VALUE Given SQL parameter PARAMETER a value of VALUE", - " PARAMETER should start with one of: $ : @ ?", - " unset PARAMETER Remove PARAMETER from the binding table", - ".print STRING... Print literal STRING", -#ifndef SQLITE_OMIT_PROGRESS_CALLBACK - ".progress N Invoke progress handler after every N opcodes", - " --limit N Interrupt after N progress callbacks", - " --once Do no more than one progress interrupt", - " --quiet|-q No output except at interrupts", - " --reset Reset the count for each input and interrupt", -#endif - ".prompt MAIN CONTINUE Replace the standard prompts", - ".quit Exit this program", - ".read FILE Read input from FILE", -#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) - ".recover Recover as much data as possible from corrupt db.", - " --freelist-corrupt Assume the freelist is corrupt", - " --recovery-db NAME Store recovery metadata in database file NAME", - " --lost-and-found TABLE Alternative name for the lost-and-found table", - " --no-rowids Do not attempt to recover rowid values", - " that are not also INTEGER PRIMARY KEYs", -#endif - ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE", - ".save FILE Write in-memory database into FILE", - ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off", - ".schema ?PATTERN? Show the CREATE statements matching PATTERN", - " Options:", - " --indent Try to pretty-print the schema", - " --nosys Omit objects whose names start with \"sqlite_\"", - ".selftest ?OPTIONS? Run tests defined in the SELFTEST table", - " Options:", - " --init Create a new SELFTEST table", - " -v Verbose output", - ".separator COL ?ROW? Change the column and row separators", -#if defined(SQLITE_ENABLE_SESSION) - ".session ?NAME? CMD ... Create or control sessions", - " Subcommands:", - " attach TABLE Attach TABLE", - " changeset FILE Write a changeset into FILE", - " close Close one session", - " enable ?BOOLEAN? Set or query the enable bit", - " filter GLOB... Reject tables matching GLOBs", - " indirect ?BOOLEAN? Mark or query the indirect status", - " isempty Query whether the session is empty", - " list List currently open session names", - " open DB NAME Open a new session on DB", - " patchset FILE Write a patchset into FILE", - " If ?NAME? is omitted, the first defined session is used.", -#endif - ".sha3sum ... Compute a SHA3 hash of database content", - " Options:", - " --schema Also hash the sqlite_schema table", - " --sha3-224 Use the sha3-224 algorithm", - " --sha3-256 Use the sha3-256 algorithm (default)", - " --sha3-384 Use the sha3-384 algorithm", - " --sha3-512 Use the sha3-512 algorithm", - " Any other argument is a LIKE pattern for tables to hash", -#ifndef SQLITE_NOHAVE_SYSTEM - ".shell CMD ARGS... Run CMD ARGS... in a system shell", -#endif - ".show Show the current values for various settings", - ".stats ?ARG? Show stats or turn stats on or off", - " off Turn off automatic stat display", - " on Turn on automatic stat display", - " stmt Show statement stats", - " vmstep Show the virtual machine step count only", -#ifndef SQLITE_NOHAVE_SYSTEM - ".system CMD ARGS... Run CMD ARGS... in a system shell", -#endif - ".tables ?TABLE? List names of tables matching LIKE pattern TABLE", - ".testcase NAME Begin redirecting output to 'testcase-out.txt'", - ".testctrl CMD ... Run various sqlite3_test_control() operations", - " Run \".testctrl\" with no arguments for details", - ".timeout MS Try opening locked tables for MS milliseconds", - ".timer on|off Turn SQL timer on or off", -#ifndef SQLITE_OMIT_TRACE - ".trace ?OPTIONS? Output each SQL statement as it is run", - " FILE Send output to FILE", - " stdout Send output to stdout", - " stderr Send output to stderr", - " off Disable tracing", - " --expanded Expand query parameters", -#ifdef SQLITE_ENABLE_NORMALIZE - " --normalized Normal the SQL statements", -#endif - " --plain Show SQL as it is input", - " --stmt Trace statement execution (SQLITE_TRACE_STMT)", - " --profile Profile statements (SQLITE_TRACE_PROFILE)", - " --row Trace each row (SQLITE_TRACE_ROW)", - " --close Trace connection close (SQLITE_TRACE_CLOSE)", -#endif /* SQLITE_OMIT_TRACE */ -#ifdef SQLITE_DEBUG - ".unmodule NAME ... Unregister virtual table modules", - " --allexcept Unregister everything except those named", -#endif - ".vfsinfo ?AUX? Information about the top-level VFS", - ".vfslist List all available VFSes", - ".vfsname ?AUX? Print the name of the VFS stack", - ".width NUM1 NUM2 ... Set minimum column widths for columnar output", - " Negative values right-justify", -}; - /* ** Output help text. ** @@ -4111,10 +3860,10 @@ static const char *(azHelp[]) = { ** Return the number of matches. */ static int showHelp(FILE *out, const char *zPattern){ - int i = 0; - int j = 0; int n = 0; char *zPat; + const char **pzHxtra; + const char **pzH; if( zPattern==0 || zPattern[0]=='0' || strcmp(zPattern,"-a")==0 @@ -4123,19 +3872,19 @@ static int showHelp(FILE *out, const char *zPattern){ ){ /* Show all commands, but only one line per command */ if( zPattern==0 ) zPattern = ""; - for(i=0; i=2 ){ + if( showHelp(p->out, azArg[1])==0 ){ + utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]); + } + }else{ + showHelp(p->out, 0); + } + /* Help pleas never fail! */ + return 0; +} + +/* Define and populate command dispatch table. */ +static struct DispatchEntry { + const char * cmdName; + int (*cmdDoer)(char *azArg[], int nArg, ShellState *); + unsigned char minLen, minArgs, maxArgs; +} command_table[] = { + EMIT_DISPATCH(); + { 0, 0, 0, -1, -1 } +}; + +/***************** + * Command dispatcher + */ +#define NO_SUCH_COMMAND -0x7fff +#define INVALID_ARGS -0x7ffe + +int dispatchCommand(char *azArg[], int nArg, ShellState *pSS) +{ + const char *cmdName = azArg[0]; + /* A temporary, simple-minded scan */ + struct DispatchEntry *pde = command_table; + while (pde->cmdName != 0){ + if (0==strncmp(cmdName, pde->cmdName, pde->minLen)){ + if((pde->minArgs > 0 && pde->minArgs > nArg)||(pde->maxArgs > 0 && pde->maxArgs < nArg)){ + return INVALID_ARGS; + } + return (pde->cmdDoer)(azArg, nArg, pSS); + } else { ++pde; } + } + return NO_SUCH_COMMAND; +} + + /* ** If an input line begins with "." then invoke this routine to ** process that line. @@ -8095,17 +7898,6 @@ static int do_meta_command(char *zLine, ShellState *p){ } }else - if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ - if( nArg>=2 ){ - n = showHelp(p->out, azArg[1]); - if( n==0 ){ - utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]); - } - }else{ - showHelp(p->out, 0); - } - }else - if( c=='i' && strncmp(azArg[0], "import", n)==0 ){ char *zTable = 0; /* Insert data into this table */ char *zFile = 0; /* Name of file to extra content from */ @@ -10403,11 +10195,14 @@ static int do_meta_command(char *zLine, ShellState *p){ p->colWidth[j-1] = (int)integerValue(azArg[j]); } }else - + /* The meta-command is not among the specially handled ones. Dispatch it. */ { - utf8_printf(stderr, "Error: unknown command or invalid arguments: " - " \"%s\". Enter \".help\" for help\n", azArg[0]); - rc = 1; + int dispatchResult = dispatchCommand(azArg, nArg, p); + if( NO_SUCH_COMMAND==dispatchResult || INVALID_ARGS==dispatchResult ){ + utf8_printf(stderr, "Error: unknown command or invalid arguments: " + " \"%s\". Enter \".help\" for help\n", azArg[0]); + rc = 1; + } } meta_command_exit: @@ -10736,6 +10531,308 @@ static void process_sqliterc( sqlite3_free(zBuf); } +COLLECT_HELP_TEXT[ +#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) + ".archive ... Manage SQL archives", + " Each command must have exactly one of the following options:", + " -c, --create Create a new archive", + " -u, --update Add or update files with changed mtime", + " -i, --insert Like -u but always add even if unchanged", + " -t, --list List contents of archive", + " -x, --extract Extract files from archive", + " Optional arguments:", + " -v, --verbose Print each filename as it is processed", + " -f FILE, --file FILE Use archive FILE (default is current db)", + " -a FILE, --append FILE Open FILE using the apndvfs VFS", + " -C DIR, --directory DIR Read/extract files from directory DIR", + " -n, --dryrun Show the SQL that would have occurred", + " Examples:", + " .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar", + " .ar -tf ARCHIVE # List members of ARCHIVE", + " .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE", + " See also:", + " http://sqlite.org/cli.html#sqlite_archive_support", +#endif +]; +COLLECT_HELP_TEXT[ +#ifndef SQLITE_OMIT_AUTHORIZATION + ".auth ON|OFF Show authorizer callbacks", +#endif +]; +COLLECT_HELP_TEXT[ + ".backup ?DB? FILE Backup DB (default \"main\") to FILE", + " --append Use the appendvfs", + " --async Write to FILE without journal and fsync()", + ".bail on|off Stop after hitting an error. Default OFF", + ".binary on|off Turn binary output on or off. Default OFF", + ".cd DIRECTORY Change the working directory to DIRECTORY", + ".changes on|off Show number of rows changed by SQL", + ".check GLOB Fail if output since .testcase does not match", + ".clone NEWDB Clone data into NEWDB from the existing database", + ".databases List names and files of attached databases", + ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", + ".dbinfo ?DB? Show status information about the database", + ".dump ?OBJECTS? Render database content as SQL", + " Options:", + " --data-only Output only INSERT statements", + " --newlines Allow unescaped newline characters in output", + " --nosys Omit system tables (ex: \"sqlite_stat1\")", + " --preserve-rowids Include ROWID values in the output", + " OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump", + " Additional LIKE patterns can be given in subsequent arguments", + ".echo on|off Turn command echo on or off", + ".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN", + " Other Modes:", +#ifdef SQLITE_DEBUG + " test Show raw EXPLAIN QUERY PLAN output", + " trace Like \"full\" but enable \"PRAGMA vdbe_trace\"", +#endif + " trigger Like \"full\" but also show trigger bytecode", + ".excel Display the output of next command in spreadsheet", + " --bom Put a UTF8 byte-order mark on intermediate file", + ".exit ?CODE? Exit this program with return-code CODE", + ".expert EXPERIMENTAL. Suggest indexes for queries", + ".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto", + ".filectrl CMD ... Run various sqlite3_file_control() operations", + " --schema SCHEMA Use SCHEMA instead of \"main\"", + " --help Show CMD details", + ".fullschema ?--indent? Show schema and the content of sqlite_stat tables", + ".headers on|off Turn display of headers on or off", + ".import FILE TABLE Import data from FILE into TABLE", + " Options:", + " --ascii Use \\037 and \\036 as column and row separators", + " --csv Use , and \\n as column and row separators", + " --skip N Skip the first N rows of input", + " -v \"Verbose\" - increase auxiliary output", + " Notes:", + " * If TABLE does not exist, it is created. The first row of input", + " determines the column names.", + " * If neither --csv or --ascii are used, the input mode is derived", + " from the \".mode\" output mode", + " * If FILE begins with \"|\" then it is a command that generates the", + " input text.", +]; +COLLECT_HELP_TEXT[ +#ifndef SQLITE_OMIT_TEST_CONTROL + ".imposter INDEX TABLE Create imposter table TABLE on index INDEX", +#endif +]; +COLLECT_HELP_TEXT[ + ".indexes ?TABLE? Show names of indexes", + " If TABLE is specified, only show indexes for", + " tables matching TABLE using the LIKE operator.", +]; +COLLECT_HELP_TEXT[ +#ifdef SQLITE_ENABLE_IOTRACE + ".iotrace FILE Enable I/O diagnostic logging to FILE", +#endif +]; +COLLECT_HELP_TEXT[ + ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT", + ".lint OPTIONS Report potential schema issues.", + " Options:", + " fkey-indexes Find missing foreign key indexes", +]; +COLLECT_HELP_TEXT[ +#ifndef SQLITE_OMIT_LOAD_EXTENSION + ".load FILE ?ENTRY? Load an extension library", +#endif +]; +COLLECT_HELP_TEXT[ + ".log FILE|off Turn logging on or off. FILE can be stderr/stdout", + ".mode MODE ?TABLE? Set output mode", + " MODE is one of:", + " ascii Columns/rows delimited by 0x1F and 0x1E", + " box Tables using unicode box-drawing characters", + " csv Comma-separated values", + " column Output in columns. (See .width)", + " html HTML
code", + " insert SQL insert statements for TABLE", + " json Results in a JSON array", + " line One value per line", + " list Values delimited by \"|\"", + " markdown Markdown table format", + " quote Escape answers as for SQL", + " table ASCII-art table", + " tabs Tab-separated values", + " tcl TCL list elements", + ".nullvalue STRING Use STRING in place of NULL values", + ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE", + " If FILE begins with '|' then open as a pipe", + " --bom Put a UTF8 byte-order mark at the beginning", + " -e Send output to the system text editor", + " -x Send output as CSV to a spreadsheet (same as \".excel\")", +]; +COLLECT_HELP_TEXT[ +#ifdef SQLITE_DEBUG + ".oom ?--repeat M? ?N? Simulate an OOM error on the N-th allocation", +#endif +]; +COLLECT_HELP_TEXT[ + ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE", + " Options:", + " --append Use appendvfs to append database to the end of FILE", +#ifndef SQLITE_OMIT_DESERIALIZE + " --deserialize Load into memory using sqlite3_deserialize()", + " --hexdb Load the output of \"dbtotxt\" as an in-memory db", + " --maxsize N Maximum size for --hexdb or --deserialized database", +#endif + " --new Initialize FILE to an empty database", + " --nofollow Do not follow symbolic links", + " --readonly Open FILE readonly", + " --zip FILE is a ZIP archive", + ".output ?FILE? Send output to FILE or stdout if FILE is omitted", + " If FILE begins with '|' then open it as a pipe.", + " Options:", + " --bom Prefix output with a UTF8 byte-order mark", + " -e Send output to the system text editor", + " -x Send output as CSV to a spreadsheet", + ".parameter CMD ... Manage SQL parameter bindings", + " clear Erase all bindings", + " init Initialize the TEMP table that holds bindings", + " list List the current parameter bindings", + " set PARAMETER VALUE Given SQL parameter PARAMETER a value of VALUE", + " PARAMETER should start with one of: $ : @ ?", + " unset PARAMETER Remove PARAMETER from the binding table", + ".print STRING... Print literal STRING", +]; +COLLECT_HELP_TEXT[ +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + ".progress N Invoke progress handler after every N opcodes", + " --limit N Interrupt after N progress callbacks", + " --once Do no more than one progress interrupt", + " --quiet|-q No output except at interrupts", + " --reset Reset the count for each input and interrupt", +#endif +]; +COLLECT_HELP_TEXT[ + ".prompt MAIN CONTINUE Replace the standard prompts", + ".quit Exit this program", + ".read FILE Read input from FILE", +]; +COLLECT_HELP_TEXT[ +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) + ".recover Recover as much data as possible from corrupt db.", + " --freelist-corrupt Assume the freelist is corrupt", + " --recovery-db NAME Store recovery metadata in database file NAME", + " --lost-and-found TABLE Alternative name for the lost-and-found table", + " --no-rowids Do not attempt to recover rowid values", + " that are not also INTEGER PRIMARY KEYs", +#endif +]; +COLLECT_HELP_TEXT[ + ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE", + ".save FILE Write in-memory database into FILE", + ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off", + ".schema ?PATTERN? Show the CREATE statements matching PATTERN", + " Options:", + " --indent Try to pretty-print the schema", + " --nosys Omit objects whose names start with \"sqlite_\"", + ".selftest ?OPTIONS? Run tests defined in the SELFTEST table", + " Options:", + " --init Create a new SELFTEST table", + " -v Verbose output", + ".separator COL ?ROW? Change the column and row separators", +]; +COLLECT_HELP_TEXT[ +#if defined(SQLITE_ENABLE_SESSION) + ".session ?NAME? CMD ... Create or control sessions", + " Subcommands:", + " attach TABLE Attach TABLE", + " changeset FILE Write a changeset into FILE", + " close Close one session", + " enable ?BOOLEAN? Set or query the enable bit", + " filter GLOB... Reject tables matching GLOBs", + " indirect ?BOOLEAN? Mark or query the indirect status", + " isempty Query whether the session is empty", + " list List currently open session names", + " open DB NAME Open a new session on DB", + " patchset FILE Write a patchset into FILE", + " If ?NAME? is omitted, the first defined session is used.", +#endif +]; +COLLECT_HELP_TEXT[ + ".sha3sum ... Compute a SHA3 hash of database content", + " Options:", + " --schema Also hash the sqlite_schema table", + " --sha3-224 Use the sha3-224 algorithm", + " --sha3-256 Use the sha3-256 algorithm (default)", + " --sha3-384 Use the sha3-384 algorithm", + " --sha3-512 Use the sha3-512 algorithm", + " Any other argument is a LIKE pattern for tables to hash", +]; +COLLECT_HELP_TEXT[ +#ifndef SQLITE_NOHAVE_SYSTEM + ".shell CMD ARGS... Run CMD ARGS... in a system shell", +#endif +]; +COLLECT_HELP_TEXT[ + ".show Show the current values for various settings", + ".stats ?ARG? Show stats or turn stats on or off", + " off Turn off automatic stat display", + " on Turn on automatic stat display", + " stmt Show statement stats", + " vmstep Show the virtual machine step count only", +]; +COLLECT_HELP_TEXT[ +#ifndef SQLITE_NOHAVE_SYSTEM + ".system CMD ARGS... Run CMD ARGS... in a system shell", +#endif +]; +COLLECT_HELP_TEXT[ + ".tables ?TABLE? List names of tables matching LIKE pattern TABLE", + ".testcase NAME Begin redirecting output to 'testcase-out.txt'", + ".testctrl CMD ... Run various sqlite3_test_control() operations", + " Run \".testctrl\" with no arguments for details", + ".timeout MS Try opening locked tables for MS milliseconds", + ".timer on|off Turn SQL timer on or off", +]; +COLLECT_HELP_TEXT[ +#ifndef SQLITE_OMIT_TRACE + ".trace ?OPTIONS? Output each SQL statement as it is run", + " FILE Send output to FILE", + " stdout Send output to stdout", + " stderr Send output to stderr", + " off Disable tracing", + " --expanded Expand query parameters", +#ifdef SQLITE_ENABLE_NORMALIZE + " --normalized Normal the SQL statements", +#endif + " --plain Show SQL as it is input", + " --stmt Trace statement execution (SQLITE_TRACE_STMT)", + " --profile Profile statements (SQLITE_TRACE_PROFILE)", + " --row Trace each row (SQLITE_TRACE_ROW)", + " --close Trace connection close (SQLITE_TRACE_CLOSE)", +#endif /* SQLITE_OMIT_TRACE */ +]; +COLLECT_HELP_TEXT[ +#ifdef SQLITE_DEBUG + ".unmodule NAME ... Unregister virtual table modules", + " --allexcept Unregister everything except those named", +#endif +]; +COLLECT_HELP_TEXT[ + ".vfsinfo ?AUX? Information about the top-level VFS", + ".vfslist List all available VFSes", + ".vfsname ?AUX? Print the name of the VFS stack", + ".width NUM1 NUM2 ... Set minimum column widths for columnar output", + " Negative values right-justify", +]; + +/* +** 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[]) = { + EMIT_HELP_TEXT(); + 0 +}; + /* ** Show available command line options */ diff --git a/tool/mkshellc.tcl b/tool/mkshellc.tcl index 46c2a528fe..71ab09e302 100644 --- a/tool/mkshellc.tcl +++ b/tool/mkshellc.tcl @@ -11,7 +11,7 @@ # set topdir [file dir [file dir [file normal $argv0]]] set out stdout -fconfigure stdout -translation binary +fconfigure stdout -translation {auto lf} puts $out {/* DO NOT EDIT! ** This file is automatically generated by the script in the canonical ** SQLite source tree at tool/mkshellc.tcl. That script combines source @@ -30,20 +30,133 @@ puts $out {/* DO NOT EDIT! ** edit the src/shell.c.in" and/or some of the other files that are included ** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script. */} + set in [open $topdir/src/shell.c.in rb] + proc omit_redundant_typedefs {line} { +} + +set ::cmd_help [dict create] +set ::cmd_dispatch [dict create] +set ::iShuffleErrors 0 + +# Convert list of help text lines into a dict. +# Keys are the command names. Values are the help for the +# commands as a list of lines, with .* logically first. +# Any #if... #endif structures are maintained and do not +# interact with "logically first" .* lines, except that +# only one such line is seen within such a conditional. +# (The effect of this is to defeat sorting by command if +# help for multiple commands' is within one conditional.) +proc chunkify_help {htin} { + set rv [dict create] + set if_depth 0 + set cmd_seen "" + set chunk {} + foreach htx $htin { + if {[regexp {^\s*\"\.\w} $htx] && $cmd_seen ne "" && $if_depth == 0} { + # Flush accumulated chunk. + dict set rv $cmd_seen $chunk + set cmd_seen "" + set chunk {} + } + lappend chunk $htx + if {[regexp {^\s*#if} $htx]} { + incr if_depth + } elseif {[regexp {^\s*#endif} $htx]} { + incr if_depth -1 + } else { + if {[regexp {^\s*\"\.(\w+)} $htx all cmd] && $cmd_seen eq ""} { + set cmd_seen $cmd + } + } + } + if {$if_depth != 0} { + puts stderr "Help chunk bad #conditional:" + puts stderr [join $htin "\n"] + puts stderr "Swallowed [join $chunk \n]" + incr ::iShuffleErrors + } else { + if {$cmd_seen ne "" && [llength $chunk] > 0} { + # Flush accumulated chunk. + dict set rv $cmd_seen $chunk + } elseif {$cmd_seen ne "" || [llength $chunk] > 0} { + puts stderr "Orphaned help: '$cmd_seen' [join $chunk \n]" + incr ::iShuffleErrors + } + } + return $rv +} + +# Perform any input collection or deferred output emits. +# This function may consume additional lines via hFile. +# Return number of lines absorbed. A 0 return means the +# input line lx had no meaning to the shuffle processing, +# in which case it is emitted as-is. +proc do_shuffle {hFile lx ostrm} { + set iAte 0 + if {[regexp {^COLLECT_HELP_TEXT\[} $lx]} { + incr iAte + set help_frag {} + set lx [gets $hFile] + while {![eof $hFile] && ![regexp {^\s*\];} $lx]} { + lappend help_frag $lx + set lx [gets $hFile] + incr iAte + } + incr iAte + set ::cmd_help [dict merge $::cmd_help [chunkify_help $help_frag]] + } elseif {[regexp {^\s*EMIT_HELP_TEXT\(\)} $lx]} { + incr iAte + foreach htc [lsort [dict keys $::cmd_help]] { + puts $ostrm [join [dict get $::cmd_help $htc] "\n"] + } + } elseif {[regexp {^COLLECT_DISPATCH\(\s*(\w+)\s*\)\[} $lx ma cmd]} { + incr iAte + set disp_frag {} + set lx [gets $hFile] + while {![eof $hFile] && ![regexp {^\s*\];} $lx]} { + lappend disp_frag $lx + set lx [gets $hFile] + incr iAte + } + incr iAte + dict set ::cmd_dispatch $cmd $disp_frag + } elseif {[regexp {^\s*EMIT_DISPATCH\(\)} $lx]} { + incr iAte + foreach cmd [lsort [dict keys $::cmd_dispatch]] { + puts $ostrm [join [dict get $::cmd_dispatch $cmd] "\n"] + } + } else { + puts $ostrm $lx + } + return $iAte +} + +# Filter redundant typedefs and certain includes and qualifiers. +proc transform_line {line nesting} { global typedef_seen if {[regexp {^typedef .*;} $line]} { if {[info exists typedef_seen($line)]} { return "/* $line */" } set typedef_seen($line) 1 + return $line + } elseif {$nesting == 0} { + return $line + } + if {[regexp {^#include "sqlite} $line]} { + return "/* $line */" } - return $line + if {[regexp {^# *include "test_windirent.h"} $line]} { + return "/* $line */" + } + return [string map [list __declspec(dllexport) {}] $line] } + set iLine 0 while {1} { - set lx [omit_redundant_typedefs [gets $in]] + set lx [transform_line [gets $in] 0] if {[eof $in]} break; incr iLine if {[regexp {^INCLUDE } $lx]} { @@ -52,22 +165,20 @@ while {1} { # puts $out "#line 1 \"$cfile\"" set in2 [open $topdir/src/$cfile rb] while {![eof $in2]} { - set lx [omit_redundant_typedefs [gets $in2]] - if {[regexp {^#include "sqlite} $lx]} { - set lx "/* $lx */" - } - if {[regexp {^# *include "test_windirent.h"} $lx]} { - set lx "/* $lx */" - } - set lx [string map [list __declspec(dllexport) {}] $lx] - puts $out $lx + set lx [transform_line [gets $in2] 1] + do_shuffle $in2 $lx $out } close $in2 puts $out "/************************* End $cfile ********************/" # puts $out "#line [expr $iLine+1] \"shell.c.in\"" continue } - puts $out $lx + set iAte [do_shuffle $in $lx $out] + if {$iAte > 0} { + incr iLine [expr {$iAte - 1}] + } + } close $in close $out +exit $::iShuffleErrors