-C Store\sthe\sprompts\sas\spart\sof\sthe\sShellState\sobject,\snot\sas\sglobal\svariables.
-D 2026-04-09T22:14:58.383
+C A\sprototype\sof\scode\sthat\sshows\show\sto\sexpand\sbackslash\sescapes\sin\sthe\nCLI\sprompt.
+D 2026-04-09T23:37:48.087
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c ffe199f025a0dd74670d2a77232bdea364a4d7b36f32c64a6572d39ba6a11576
-F src/shell.c.in 41b2b8ed58a2b34ca1b3027ab73fa5f21fa5a359025ec4d803fff43e5053c85e
+F src/shell.c.in 35f99690f368ef171713cbccd89efef382944e4b85396bdb78e6995636e278b3
F src/sqlite.h.in e2915e4a86d5e0783afb5cb72411df38d987c7f3c5aa2d5441b8e74d30b649d8
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P ab08b7a8ef518f96a549a41fe8ff11776abe5e83153c5f8d5d58694ecc476389
-R 94a7119792f4c428d79e21c5509da5f9
+P 39f6c5a8a7d91e03f89b13496e333b9500977a2cbcc0c27ba14dfb87dc81e678
+R d2a4bc02232fb4db2f52e0b9d98461ba
U drh
-Z 849f1289eaea61587540a79ea11d0c87
+Z f5b6fe9da177b5e89ebf6c4cb7c9f5ea
# Remove this line to create a well-formed Fossil manifest.
return zLine;
}
+/*
+** Expand escapes in the given input prompt string. Return the
+** expanded prompt in memory obtained from sqlite3_malloc(). The
+** caller is responsible for freeing the memory.
+*/
+static char *expand_prompt(
+ ShellState *p, /* The current shell state */
+ const char *zPrior, /* Prior input lines not yet processed */
+ const char *zPrompt /* Prompt string to be expanded */
+){
+ sqlite3_str *pOut = sqlite3_str_new(0);
+ int i;
+ char c;
+ for(i=0; zPrompt[i]; i++){
+ if( zPrompt[i]!='\\' ) continue;
+ if( i>0 ){
+ sqlite3_str_append(pOut, zPrompt, i);
+ zPrompt += i;
+ i = 0;
+ }
+ /* At this point zPrompt[0] is a \ character and all prior
+ ** characters have already been loaded into pOut. Process the
+ ** escape sequence that zPrompt points to. */
+ c = zPrompt[1];
+ if( c==0 ){
+ /* \ at the end of a line is silently ignored */
+ break;
+ }
+ if( c=='\\' ){
+ /* \\ maps into a single \ */
+ zPrompt++;
+ continue;
+ }
+ if( c>='0' && c<='7' ){
+ /* \nnn becomes a single byte given by octal nnn */
+ int v = c - '0';
+ while( i<=2 && zPrompt[i+1]>='0' && zPrompt[i+1]<='7' ){
+ v = v*8 + zPrompt[++i] - '0';
+ }
+ sqlite3_str_appendchar(pOut, 1, v);
+ zPrompt += i+1;
+ i = -1;
+ continue;
+ }
+ if( c=='x' ){
+ /* \x becomes "*" if in a transaction and nothing if not */
+ if( p->db && !sqlite3_get_autocommit(p->db) ){
+ sqlite3_str_append(pOut, "*", 1);
+ }
+ zPrompt += 2;
+ i = -1;
+ continue;
+ }
+ if( c=='f' || c=='F' || c=='~' ){
+ /* \f becomes the tail of the database filename */
+ /* \F becomes the full pathname */
+ /* \~ becomes the full pathname relative to $HOME */
+ sqlite3_filename pFN = p->db ? sqlite3_db_filename(p->db,0) : 0;
+ const char *zFN;
+ if( pFN && (zFN = sqlite3_filename_database(pFN))!=0 ){
+ if( c=='f' ){
+ const char *zTail = strrchr(zFN,'/');
+ if( zTail && zTail[1] ) zFN = &zTail[1];
+ }else if( c=='~' ){
+ const char *zHOME = getenv("HOME");
+ size_t nHOME = zHOME ? strlen(zHOME) : 0;
+ if( nHOME<strlen(zFN) && memcmp(zHOME,zFN,nHOME)==0 ){
+ sqlite3_str_append(pOut,"~",1);
+ zFN += nHOME;
+ }
+ }
+ sqlite3_str_appendall(pOut, zFN);
+ }
+ zPrompt += 2;
+ i = -1;
+ continue;
+ }
+
+ /* No match to a known escape. Generate an error. */
+ sqlite3_str_appendf(pOut,"UNKNOWN(\"\\%c\")",c);
+ zPrompt += 2;
+ i = -1;
+ }
+ if( i>0 ){
+ sqlite3_str_append(pOut, zPrompt, i);
+ }
+ return sqlite3_str_finish(pOut);
+}
+
/*
** Retrieve a single line of input text.
**
** If in==0 then read from standard input and prompt before each line.
-** If isContinuation is true, then a continuation prompt is appropriate.
-** If isContinuation is zero, then the main prompt should be used.
+** If bContinue is true, then a continuation prompt is appropriate.
+** If bContinue is zero, then the main prompt should be used.
**
** If zPrior is not NULL then it is a buffer from a prior call to this
** routine that can be reused.
** zPrior argument for reuse.
*/
#ifndef SQLITE_SHELL_FIDDLE
-static char *one_input_line(ShellState *p, char *zPrior, int isContinuation){
- char *zPrompt;
+static char *one_input_line(ShellState *p, char *zPrior, int bContinue){
char *zResult;
FILE *in = p->in;
if( in!=0 ){
zResult = local_getline(zPrior, in);
}else{
- zPrompt = isContinuation ? p->contPrompt : p->mainPrompt;
+ const char *zBase = bContinue ? p->contPrompt : p->mainPrompt;
+ char *zPrompt = expand_prompt(p, zPrior, zBase);
+ shell_check_oom(zPrompt);
#if SHELL_USE_LOCAL_GETLINE
sputz(stdout, zPrompt);
fflush(stdout);
}
if( zResult && *zResult ) shell_add_history(zResult);
#endif
+ sqlite3_free(zPrompt);
}
return zResult;
}
** impl because we need the global shellState and cannot access it from that
** function without moving lots of code around (creating a larger/messier diff).
*/
-static char *one_input_line(ShellState *p, char *zPrior, int isContinuation){
+static char *one_input_line(ShellState *p, char *zPrior, int bContinue){
/* Parse the next line from shellState.wasm.zInput. */
const char *zBegin = shellState.wasm.zPos;
const char *z = zBegin;
FILE *in = p->in;
UNUSED_PARAMETER(in);
- UNUSED_PARAMETER(isContinuation);
+ UNUSED_PARAMETER(bContinue);
if(!z || !*z){
return 0;
}