]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add design doc for shell extensibility
authorlarrybr <larrybr@noemail.net>
Sat, 4 Dec 2021 18:40:51 +0000 (18:40 +0000)
committerlarrybr <larrybr@noemail.net>
Sat, 4 Dec 2021 18:40:51 +0000 (18:40 +0000)
FossilOrigin-Name: 96b8ffb05497b6c44f491fbb56d5ff6580b4fea112274f9f19faf24f79727460

doc/shell_extend.html [new file with mode: 0644]
manifest
manifest.uuid

diff --git a/doc/shell_extend.html b/doc/shell_extend.html
new file mode 100644 (file)
index 0000000..3f0eee1
--- /dev/null
@@ -0,0 +1,534 @@
+<!doctype html>
+<html>
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+    <title>CLI Shell Extensibility</title>
+  </head>
+  <body>
+<style>
+   body{counter-reset: section}
+   h2{counter-reset: h2counter; text-indent: 10px}
+   h3{counter-reset: h3counter; text-indent: 25px}
+   h4{counter-reset: h4counter; text-indent: 40px}
+
+   h2:before{
+     counter-increment: section;
+     content: counter(section) " ";
+   }
+   h3:before{
+     counter-increment: h2counter;
+     content: counter(section) "." counter(h2counter) " ";
+   }
+   h4:before{
+     counter-increment: h3counter;
+     content: counter(section) "." counter(h2counter) "." counter(h3counter) " ";
+   }
+   h5:before{
+     counter-increment: h4counter;
+     content: counter(section) "." counter(h2counter) "." counter(h3counter) "." counter(h4counter) " ";
+   }
+   </style>
+
+    <h1>CLI Shell Extensibility</h1>
+    <hr/>
+    <h2>Introduction</h2>
+    <p>The command line shell for SQLite can be customized
+      to modify or add certain kinds of features, without altering its source.
+      This document details this extensibility
+      and how such extension may be accomplished by shell users.
+    <p>Shell extensibility serves to reduce the tension between
+      keeping the shell simple with broadly useful features
+      and allowing the shell to become an ever-growing tool
+      meeting diverse needs for those not ready to satisfy them
+      with a custom program using the SQLite libary.
+      Extensions contributed by the SQLite developers or others
+      will become (or are) available for use in situations
+      that may not justify permanently adding the same features
+      to the core shell published by the SQLite project in binary form.
+      <h2>Extensible Features</h2>
+    <p>Only certain categories of features may be
+      added or modified via extension, namely:
+      
+      <h3>New or Revised Meta-Commands</h3>
+    <p>The "dot" commands implemented by the shell,
+      along with help text for them, may be augmented or overridden.
+      A meta-command effected with an extension may be used
+      in the same ways as one available in the core, non-extended shell.
+      
+      <h3>New or Revised Import Modes</h3>
+    <p>The ways in which data may be imported to a DB table
+      may be augmented or overriden. Once that is done, the .import
+      meta-command will either have a new option to specify a new
+      import handler or an existing .import option can be used for this.
+
+      <h3>New or Revised Query Result Handling</h3>
+    <p>The display formatting or other disposition of query results
+      may be augmented or overriden. Once that is done, the .mode
+      meta-command will either have a new option to specify a new
+      result handler or an existing .mode option can be used for this.
+
+      <h3>Generalized Import Modes and Query Result Handling</h3>
+    <p>New handlers added via extension are not restricted to
+      importing data from a file or result display formatting.
+      They may be considered more generally to be either
+      a data source or a data sink, producing or accepting
+      data row sets. The origin or destination of
+      the data is up to the handler, as may be affected
+      by arguments to the .import or most recent .mode command.
+
+      <h2>Extension Methods, Dynamic or Static</h2>
+    <p>Shell extension may be effected at different times
+      in different ways according to convenience and need.
+
+      <h3>Runtime Extension</h3>
+    <p>Extension at runtime (when the shell is running)
+      is effected via the .load command with a --shell flag.
+      In this way, a dynamically loaded library (DLL) is loaded with
+      provision made for its sqlite3_X_init() function to obtain
+      the shell extension API entry points and thereby
+      register with the shell core any
+      new meta-commands, or import or query result handlers
+      that it implements.
+
+      <h3>Build-Time Extension</h3>
+    <p>Extension when the shell is built is effected by specifying
+      certain option values to either the "make" invocation or
+      to a utility, (tool/mkshellc.tcl), which assembles and transforms
+      sources to produce the shell's unitary source file (shell.c).
+
+      <h3>Extension Source Code</h3>
+    <p>With certain coding conventions and methods followed,
+      the same source code can be used either
+      to produce most of a runtime shell extension DLL or to
+      be incorporated into shell.c as a built-in shell extension.
+      (See the extension code samples for details.)
+
+      <h3>Build-Time Diminuation</h3>
+    <p>Just as new meta-commands can be readily incorporated into
+      the shell when it is built, many of the core meta-commands
+      can be readily omitted from the shell build. This is done
+      with a variation of the option values that may be given
+      to "make" or to tool/mkshellc.tcl as the shell is built.
+      (See tool/mkshellc.tcl --help output for details.)
+      Such omission of meta-commands might be done when building
+      a customized shell which need not have the various meta-commands
+      which exist for the purpose of testing the SQLite library.
+
+      <h2>Interface</h2>
+    <p>The following details relate to src/shext_linkage.h, a header
+      in which declarations appear for objects and functions
+      that facilitate runtime interaction between the shell core
+      and shell extensions written in C/C++.
+      Comments in that header tersely summarize these explanations:
+
+      <h3>struct ShellStateX</h3>
+    <p>This struct consists of a public portion, which is available and
+      stable for use in shell/extension interactions, and a private
+      portion which may not be stable. Shell extension code used only for
+      build-time extension might use the private part, (to which it has
+      access because such code is compiled within the same translation unit
+      as the core shell code), but such usage generally precludes (or makes
+      hazardous) use of a runtime loadable extension built from the same code.
+
+      <h3>ExtensionId typedef and eid Member</h3>
+    <p>An object of this type serves to uniquely identify an extension
+      loaded at runtime so that it may be unloaded later. It must be
+      passed back to the shell (in the ShellExtensionLink eid member)
+      by the sqlite3_X_init() function if the extension DLL is ever
+      to be unloaded during that shell session.
+
+      <h3>extensionDtor member</h3>
+    <p>The function addressed by this member will be called prior to
+      the extension being unloaded (if the pointer is non-zero.)
+      This is an out parameter from the sqlite3_X_init() function.
+      It may perform any cleanup or deallocations necessitated by
+      successful initialization (and will never be called after
+      failed initialization.)
+
+      <h3>Notes Regarding Object Interfaces for C vs C++ Writers</h3>
+    <p>The objects registered with the shell core to provided extension
+      functionality may be implemented in C or C++ (or anything else
+      producing the same ABI.) In the below descriptions of their
+      interfaces, it should be understood that: C++ implementations
+      will not need to explicitly deal with anything like a WhatsitVtable
+      struct and will refer to the object pointer, passed implicitly,
+      as "this"; and C implementations will need to populate a static
+      WhatsitVtable and refer to the initial object pointer as "pThis".
+
+      <h3>MetaCommand typedef</h3>
+    <p>These objects represent an extension meta-command, including a
+      dispatch table for the public interface and any accompanying
+      data (which is opaque to the core shell.) Such objects are created
+      by extensions and passed to the core shell only by reference.
+      They are made known to the shell core via registerMetaCommand() calls.
+
+      <h3>MetaCommandVtable typedef</h3>
+    <p>These objects represent the dispatch table of a MetaCommand object.
+    <p>All methods are given the same leading (or lone) argument:<br>
+      (1) the address of the registered MetaCommand object.
+
+      <h4>destruct_free method</h4>
+    <p>This method is called prior to unloading a runtime extension
+      for any registered MetaCommand object, provided its dispatch
+      table entry is non-zero.
+      It should free resources allocated during the sqlite3_X_init() call.
+
+      <h4>name method</h4>
+    <p>This method returns the name of the meta-command (sans leading '.'.)
+      The returned pointer must remain valid throughout the lifetime of
+      the registered MetaCommand object.
+
+      <h4>help method</h4>
+    <p>This method returns help text for the meta-command. This text
+      should be formatted and aligned with the built-in meta-command
+      help text so that it can be displayed seamlessly.
+    <p>There is one additional argument:<br>
+      (2) an integer directing what help text to return, with
+      0 indicating primary, single-line help, or
+      1 indicating any more detailed help beyond the primary level.
+    <p>The return is either a C string or null pointer. The C string
+      will not be freed by the core shell, and must remain valid
+      during the lifetime of the MetaCommand object.
+
+      <h4>argsRange method</h4>
+    <p>This method returns a pair of unsigned integers indicating the range
+      of valid argument counts for the meta-command.
+    <p>The returned .minArgs value indicates the minimum number of
+      arguments required for a successful execute call.
+      The returned .maxArgs value indicates the maximum number of
+      arguments allowed for a successful execute call, with ~0
+      indicating no (practical) upper limit. The execute method will
+      never be called with an argument count not within this range.
+      (This significantly simplifies argument checking.)
+
+      <h4>execute method</h4>
+    <p>This method performs whatever work the meta-command is supposed
+      to do when invoked. It has 4 additional arguments:<br>
+      (2) present ShellStateX, passed by reference (an in/out parameter);<br>
+      (3) an error message pointer, passed by reference, set upon error but
+      otherwise not modified, to be freed by the shell core;<br>
+      (4) the number of invocation arguments;<br>
+      (5) an array of C strings constituting the invocation arguments;<br>
+    <p>The return is 0 for success, or anything else to indicate error.
+      The special value SHELL_INVALID_ARGS (aka SQLITE_MISUSE) should be
+      returned when argument checking shows an invalid call. This will
+      cause the command dispatcher to issue usage help (in interactive
+      shell sessions) without further fuss by the execute() method itself.
+      (And if an extension causes this error to be returned from the SQLite
+      library, which is a serious error by itself, it must either translate
+      it for return or trouble its users with a misleading error message
+      from the dispatcher.) If the output error message is set, it will
+      be issued in lieu of the standard error message for invalid calls.
+
+      <h3>FormatXfrInfo typedef</h3>
+    <p>An object of this type is passed between the shell core and its
+      import or query result handlers to convey or keep parameters and data
+      related to formatting or parsing data rows in an external form,
+      or to keep state associated with the progression of an import or result
+      handling operation from initiation to completion.
+    <p>The shell core .mode and .import implementations also use
+      an instance of this type to affect result output and import operations.
+      That instance resides in the ShellStateX so that extension meta-commands
+      can access it, possibly to change it. Meta-commands which alter this
+      instance for their own purposes (rather than for intended effect)
+      should take care to restore its value as the meta-command completes.
+
+      <h3>OutModeHandler typedef</h3>
+    <p>These objects represent an extension query result handler, including
+      a dispatch table for the public interface and any accompanying
+      data which is opaque to the core shell. Such objects are created
+      by extensions and passed to the core shell only by reference.
+      They are made known to the shell core via registerOutMode() calls.
+
+      <h3>OutModeHandlerVtable typedef</h3>
+    <p>These objects represent the dispatch table of an OutModeHandler object.
+      All methods in the dispatch table are given at
+      least this leading argument:<br>
+      (1) The OutModeHandler address registered via registerOutMode();<br>
+
+      <h4>destruct_free method</h4>
+    <p>This method is called prior to unloading a runtime extension
+      for any registered OutModeHandler object, provided its dispatch
+      table entry is non-zero.
+      It should free resources allocated during the sqlite3_X_init() call.
+
+      <h4>name method</h4>
+    <p>This method returns the name of the OutModeHandler, which users
+      specify to the .mode command (as the mode) to designate use of the
+      registered OutModeHandler for subsequent query results.
+      The returned pointer must remain valid throughout the lifetime of
+      the registered MetaCommand object.
+
+      <h4>help method</h4>
+    <p>This method returns help text for the OutModeHandler.
+    <p>There is one additional argument:<br>
+      (2) an integer directing what help text to return, with
+      0 indicating primary, single-line help, or
+      1 indicating any more detailed help beyond the primary level.
+      The primary help is included in the .mode command's own
+      detailed help text, so it should be aligned accordingly.
+      The detailed help is shown by the .mode command's --help option.
+    <p>The return is either a C string or null pointer. The C string
+      will not be freed by the core shell, and must remain valid
+      during the lifetime of the MetaCommand object.
+
+      <h4>Common arguments</h4>
+    <p>The following methods are given these 2 additional arguments:<br>
+      (2) A FormatXfrInfo object passed by reference; and<br>
+      (3) An error message pointer, passed by reference, to receive errors.<br>
+
+      <h4>openResultsOutStream method</h4>
+    <p>This method is called when a query output is setup,
+      (via the .mode command with the handler's name given as a --flag.)
+    <p>It is given 3 additional arguments:<br>
+      (4) the number of arguments in the said .mode command;<br>
+      (5) an array of C strings with the said argument values; and<br>
+      (6) the name given as a --flag which caused the handler to be used.
+    <p>When the extension handler is activated via a .mode command,
+      parsing that command and behaving accordingly is the responsibility
+      of this method alone. (The command is parsed and acted upon by the
+      default .mode implementation only when no OutModeHandler is used.)
+    <p>Once this method is called and succeeds, it is guaranteed that the
+      closeResultsOutStream method will be called.
+    <p>This method should return SQLITE_OK only upon success.
+      Any other return will abort remaining calls in the handling sequence.
+
+      <h4>prependResultsOut method</h4>
+    <p>This method is called when a query succeeds for which this handler
+      will be given the results. This is purely preparatory; zero or
+      more result rows may follow. It is up to this method to determine
+      if any results can even be had (by considering the return from
+      sqlite3_column_count()) and acting accordingly.
+    <p>It is given 1 additional argument:<br>
+      (4) the query prepared statement (pointer), not yet stepped.
+    <p>This method should return SQLITE_OK only upon success.
+      Any other return will abort the next 2 calls in the handling sequence.
+      (TBD: Such aborts without error should be supported for DDL and DML.)
+
+      <h4>rowResultsOut method</h4>
+    <p>This method is called when a query's prepared statement is stepped,
+      for each result row available.
+    <p>It is given 1 additional argument:<br>
+      (4) the query prepared statement (pointer), stepped with
+      a result row available. It is permitted for this method to
+      perform the remaining stepping, as indicated by the return.
+    <p>This method should return SQLITE_OK only upon success
+      without having completed stepping. If this method completes stepping,
+      (by making its own calls to sqlite3_step() until it returns SQLITE_DONE),
+      it must return SQLITE_DONE. Any other return will abort the next call
+      in the handling sequence.
+
+      <h4>appendResultsOut method</h4>
+    <p>This method is called when result set stepping has been completed.
+    <p>It is given  additional argument:<br>
+      (4) the query prepared statement (pointer), completely stepped.
+    <p>This method should return SQLITE_OK upon success, or may return
+      something else to indicate error with no effect upon succeeding calls.
+
+      <h4>closeResultsOutStream method</h4>
+    <p>This method is called when a new .mode command is invoked specifying
+      some output mode not using this OutModeHandler or when the extension
+      is about to be unloaded with this OutModeHandler selected for output.
+      It should free resources allocated or held as a result of the
+      previous openResultsOutStream call.
+
+      <h3>ImportHandler typedef</h3>
+    <p>These objects represent an extension data import handler, including
+      a dispatch table for the public interface and any accompanying
+      data which is opaque to the core shell. Such objects are created
+      by extensions and passed to the core shell only by reference.
+      They are made known to the shell core via registerImporter() calls.
+
+      <h3>ImportHandlerVtable typedef</h3>
+    <p>These objects represent the dispatch table of an ImportHandler object.
+      All methods in the dispatch table are given this 1 leading argument:<br>
+      (1) The ImportHandler address registered via registerImporter().
+
+      <h4>destruct_free method</h4>
+    <p>This method is called prior to unloading a runtime extension
+      for any registered OutModeHandler object, provided its dispatch
+      table entry is non-zero.
+      It should free resources allocated during the sqlite3_X_init() call.
+
+      <h4>name method</h4>
+    <p>This method returns the name of the importer, which is to
+      be passed with leading '--' (or '-') to the .import command
+      to specify use of the registered importer for that invocation.
+      The returned pointer must remain valid throughout the lifetime of
+      the registered MetaCommand object.
+
+      <h4>help method</h4>
+    <p>This method returns help text for the importer.
+    <p>There is one additional argument:<br>
+      (2) an integer directing what help text to return, with
+      0 indicating primary, single-line help, or
+      1 indicating any more detailed help beyond the primary level.
+      The primary help is included in the .import command's own
+      detailed help text, so it should be aligned accordingly.
+      The detailed help is shown by the .import command's --help option.
+    <p>The return is either a C string or null pointer. The C string
+      will not be freed by the core shell, and must remain valid
+      during the lifetime of the MetaCommand object.
+
+      <h4>Common arguments</h4>
+    <p>The following methods are given these 2 additional arguments:<br>
+      (2) A FormatXfrInfo object passed by reference; and<br>
+      (3) An error message pointer, passed by reference, to receive errors.
+
+      <h4>openDataInStream method</h4>
+    <p>This method is called when a .import command is invoked with
+      the '--' (or '-') prefixed name of the ImportHandler as an argument.
+    <p>These 3 additional arguments are passed:<br>
+      (4) the number of arguments to said .import command;<br>
+      (5) an array of C strings with the said argument values; and<br>
+      (6) the name of the ImportHandler (as its name method would return.)
+    <p>When the extension handler is activated via a .import command,
+      responsibility for parsing that command and behaving accordingly is
+      shared between the shell core .import implementation and this method.
+      The shell core normally takes the last argument as the name of a table
+      (to be created if necessary) which will receive the imported data.
+      (But see return values for exceptions to this treatment.)
+      The shell core also detects any --flag argument selecting a registered
+      ImportHandler (giving effect to the last one) and calls this and
+      following methods to perform the input part of the import operation.
+      This method may interpret any or all of the arguments as needed
+      and (supposedly) documented by the associated help(...) method returns.
+    <p>Once this method is called and succeeds, it is guaranteed that the
+      closeDataInStream method will be called.
+    <p>This method should return SQLITE_OK upon success where disposition
+      of the imported data (into a table named by the last argument) is
+      to be handled normally, by the shell core.
+      An alternative success return is SQLITE_DONE, indicating that
+      disposition of the imported data has been done by the ImportHandler.
+      In that case, the next 3 methods (*DataInput(...)) will not be called
+      and this method should have completed the whole import operation.
+      After a success return, closeDataInStream is guaranteed to be called.
+      Other returns will abort all remaining calls in the handling sequence.
+
+      <h4>prepareDataInput method</h4>
+    <p>This method prepares for the particular import operation commenced
+      with a .import invocation. It may take into account the shape of
+      the input data (and possibly its type) as discovered during the call.
+    <p>This 1 additional argument is passed:<br>
+      (4) a to-be-prepared statement (pointer), passed by reference.
+      This is an out parameter conveying a prepared statement created
+      by this method specifically for the single import operation.
+    <p>The prepared statement should, in some manner wholly determined
+      by the extension handler, incorporate compiled SQL (possibly with
+      as-yet unbound parameters) which will produce a result set.
+      (This may be no more than a query such as "SELECT @1 as one, ...",
+      or could be a SELECT from a temporary table used for buffering.)
+    <p>The return should be SQLITE_OK upon success, in which case the
+      following 2 methods will also be called. Any other return will
+      abort the {prepare,row,finish}DataInput() call sequence. In that
+      case, no prepared statement should be returned either.
+
+      <h4>rowDataInput method</h4>
+    <p>This method is called to collect imported data, making it available
+      through the prepared statement passed as the last argument with as
+      many steps as are needed to get SQLITE_DONE from sqlite3_step().
+      It will be called repeatedly until its return indicates no more data.
+    <p>It is given 1 additional argument:<br>
+      (4) the prepared statement (pointer) returned by prepareDataInput().<br>
+      This prepared statement can have values bound to it or be reset as
+      necessary to return some or more data. However, it must remain the
+      same sqlite3_statement instance returned by prepareDataInput().
+    <p>It is given 1 additional argument:<br>
+      (4) the prepared statement (pointer) returned by prepareDataInput().
+    <p>The return should be SQLITE_DONE when no more data is available,
+      or SQLITE_ROW to indicate that more data is or might be available.
+      Any other return (including SQLITE_OK) indicates a condition which
+      will abort the data collection phase of the import operation. Any
+      of those 3 returns is treated as success by the shell core.
+
+      <h4>finishDataInput method</h4>
+    <p>This method is called to complete the data input phase of the
+      import operation commenced by prepareDataInput().
+    <p>It is given 1 additional argument:<br>
+      (4) the prepared statement (pointer) returned by prepareDataInput().<br>
+      This prepared statement should be finalized by this method. Other
+      cleanup or import closing related to the transfer may also be performed.
+
+      <h4>closeDataInStream method</h4>
+    <p>This method is called as a .import command which specified this
+      ImportHandler completes.
+      It should free resources allocated or held as a result of the
+      previous openDataInStream call.
+
+      <h3>ShellExtensionLink typedef</h3>
+    <p>An object of this type is passed (somewhat indirectly) to the
+      sqlite3_X_init(...) function which is called when a runtime
+      extension is loaded via a .load command with a --shell flag.
+      It is used to establish linkage between the loaded extension
+      and a shell core API exposed specifically for extensibility.
+    <p>At present, the extension API is limited to registration of
+      meta-commands, query result handlers, and import handlers
+      implemented by extensions. This API may be extended in future
+      versions of the core shell, in a backwards-compatible manner.
+      (See the pExtra sentinel, whose offset may increase.)
+
+      <h4>Establishing Shell/Extension Linkage</h4>
+    <p>The 1st or 2nd parameter passed to the sqlite3_X_init() function
+      as an extension is dynamically loaded is used to obtain a pointer
+      to the ShellExtensionLink object (provided that .load was
+      invoked with the --shell flag.) To verify that the correct
+      object type was passed and reference it if so, the extension's
+      sqlite3_X_init() function can use one of these two means:
+    <p>The least code-intensive means is implemented by a macro,
+      EXTENSION_LINKAGE_PTR(pzem), parameter of which is the char**
+      passed as the 2nd sqlite3_X_init() argument. This is reliable
+      except in the case of a maliciously written shell core (which
+      portends worse problems than the undefined behavior which
+      could arise from invoking .load from such a shell.)
+    <p>A more code-intensive means, (which is no safer in the
+      case of a maliciously written shell core), is to use
+      a C macro, DEFINE_SHDB_TO_SHEXT_API(function_name),
+      in the extension source to define a function named per
+      the macro argument. Then that function may be called with its
+      lone argument being the sqlite3 * (db) pointer passed as the
+      1st argument to sqlite3_X_init().
+    <p>Either means will return (or yield) either a null pointer
+      or a verified ShellExtensionLink pointer. In the former
+      case, sqlite3_X_init() may return SHELL_INVALID_ARGS to induce
+      the emission of help on using the .load command. (Said help
+      will mention the need to use the --shell flag for extensions.)
+      In the latter case, the obtained pointer may be called to
+      register the extension's feature implementor(s) as described.
+
+      <h2>Development Aspects of Extensibility and Its Evolution</h2>
+
+    <p>There is critical tension between competing uses of the ShellState
+      object which is kept and used by the core shell for state which
+      must persist between meta-command invocations. For unhindered
+      implementation and feature expansion flexibility, the structure
+      of the ShellState data should be unconstrained across versions
+      of the shell. However, unless extension meta-commands and data
+      transferers are to act entirely independently of built-in meta-commands,
+      (excepting interaction through the above-described extension methods),
+      some portion of the ShellState data needs to be shared in a stable
+      manner between extensions and the core shell code.
+    <p>With respect to interface stability concerns, it is nearly immaterial
+      whether the sharing occurs through exposed data structures
+      or an extension API devised to convey similar data. (Only data layout
+      and possible change notification are at stake in that choice.)
+    <p>For simplicity, and because it can work in a way consistent with how
+      built-in shell features are implemented now, the chosen sharing method
+      is to simply directly expose a subset of the ShellState data. That
+      subset will be extremely limited to minimize hinderance of what has
+      previously been unfettered change to that data structure/meaning.
+      It will initially be: the present output stream, as affected by
+      .output and .once commands; the currently open user DB (if any);
+      the dedicated shell DB; and the data related to formatting
+      and transfer of data in external forms. This data resides in the
+      ShellState object as a FormatXfrInfo struct.
+    <p>As shell extensibility evolves, additional data items may need
+      to be moved into the publicly exposed portion of ShellState, either
+      directly (via exposed data members) or by means of some additional
+      extension APIs defined in the ShellExtensionLink object (which has
+      been defined to accommodate growth of its function pointer list in
+      a backwards-compatible manner.)
+
+  </body>
+</html>
+
index 31155c25d038b20717b5e28cce2aaa2bd99591cc..4771a2bff73861016a217d8b13102f3c434b2b79 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Extension\sinterface\stweaks\sin\ssupport\sof\splanned\susage
-D 2021-12-03T19:27:06.906
+C Add\sdesign\sdoc\sfor\sshell\sextensibility
+D 2021-12-04T18:40:51.887
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -40,6 +40,7 @@ F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
 F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
 F doc/lemon.html efc0cd2345d66905505d98f862e1c571512def0ceb5b016cb658fd4918eb76a3
 F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
+F doc/shell_extend.html b369e9dc53b7d07e2fc8e4acdf3183784826c522a0111960026f6058081c1a98
 F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
 F doc/vdbesort-memory.md 4da2639c14cd24a31e0af694b1a8dd37eaf277aff3867e9a8cc14046bc49df56
 F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
@@ -1934,7 +1935,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P eab1e1af5b51eb267e9bceaf6412d2be12b8f3deb435631e55291211099720ff
-R d47b4cfbdf90e9b5dfc09603b7ee76a8
+P ce2a91438a3403f55cddc6c5e26db292bf6dd10e805f55416063a63986d28740
+R e58755c0a075efc772ebe9b493832561
 U larrybr
-Z 1371e2d598bc40c6fc66804e5df68b0c
+Z 7adbcc5b389a42b1ea01dd812dbf6613
index 668dba7b61a697ed39ada1fb24103e60b6ff9b5f..1bb52128621bd2accdc52111a39436fa6eaf08d7 100644 (file)
@@ -1 +1 @@
-ce2a91438a3403f55cddc6c5e26db292bf6dd10e805f55416063a63986d28740
\ No newline at end of file
+96b8ffb05497b6c44f491fbb56d5ff6580b4fea112274f9f19faf24f79727460
\ No newline at end of file