Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add support for saving the sqlite shell command-line history across sessions. (CVS 536) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
ca4abf3fe1f0e66802f9f98a20e0c8b8 |
User & Date: | drh 2002-04-19 12:34:06.000 |
Context
2002-04-20
| ||
14:24 | Fix for ticket #1: Implement the GLOB and LIKE operators as functions that can be overridden. This way, a developer can change the LIKE operator to be case sensitive, for example. (CVS 537) (check-in: 51572bf717 user: drh tags: trunk) | |
2002-04-19
| ||
12:34 | Add support for saving the sqlite shell command-line history across sessions. (CVS 536) (check-in: ca4abf3fe1 user: drh tags: trunk) | |
01:00 | Added rights release for Matthew O. Persico (CVS 535) (check-in: 6c32c07e82 user: persicom tags: trunk) | |
Changes
Changes to src/shell.c.
1 2 3 4 5 6 7 8 9 10 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** | < < < < | > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code to implement the "sqlite" command line ** utility for accessing SQLite databases. ** ** $Id: shell.c,v 1.55 2002/04/19 12:34:06 drh Exp $ */ #include <stdlib.h> #include <string.h> #include <stdio.h> #include "sqlite.h" #include <ctype.h> #if !defined(_WIN32) && !defined(WIN32) # include <signal.h> # include <pwd.h> # include <unistd.h> # include <sys/types.h> #endif #if defined(HAVE_READLINE) && HAVE_READLINE==1 # include <readline/readline.h> # include <readline/history.h> #else # define readline(p) getline(p,stdin) # define add_history(X) # define read_history(X) # define write_history(X) # define stifle_history(X) #endif /* ** The following is the open SQLite database. We make a pointer ** to this database a static variable so that it can be accessed ** by the SIGINT handler to interrupt database processing. */ static sqlite *db = 0; /* ** True if an interrupt (Control-C) has been received. */ static int seenInterrupt = 0; /* ** This is the name of our program. It is set in main(), used ** in a number of other places, mostly for error messages. */ static char *Argv0; /* |
︙ | ︙ | |||
269 270 271 272 273 274 275 276 277 278 279 280 281 282 | } } /* ** This routine runs when the user presses Ctrl-C */ static void interrupt_handler(int NotUsed){ if( db ) sqlite_interrupt(db); } /* ** This is the callback routine that the SQLite library ** invokes for each row of a query result. */ | > | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | } } /* ** This routine runs when the user presses Ctrl-C */ static void interrupt_handler(int NotUsed){ seenInterrupt = 1; if( db ) sqlite_interrupt(db); } /* ** This is the callback routine that the SQLite library ** invokes for each row of a query result. */ |
︙ | ︙ | |||
502 503 504 505 506 507 508 509 | /* Forward reference */ static void process_input(struct callback_data *p, FILE *in); /* ** If an input line begins with "." then invoke this routine to ** process that line. */ | > > | > | 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 | /* Forward reference */ static void process_input(struct callback_data *p, FILE *in); /* ** If an input line begins with "." then invoke this routine to ** process that line. ** ** Return 1 to exit and 0 to continue. */ static int do_meta_command(char *zLine, sqlite *db, struct callback_data *p){ int i = 1; int nArg = 0; int n, c; int rc = 0; char *azArg[50]; /* Parse the input line into tokens. */ while( zLine[i] && nArg<ArraySize(azArg) ){ while( isspace(zLine[i]) ){ i++; } if( zLine[i]=='\'' || zLine[i]=='"' ){ |
︙ | ︙ | |||
529 530 531 532 533 534 535 | while( zLine[i] && !isspace(zLine[i]) ){ i++; } if( zLine[i] ) zLine[i++] = 0; } } /* Process the input line. */ | | | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | while( zLine[i] && !isspace(zLine[i]) ){ i++; } if( zLine[i] ) zLine[i++] = 0; } } /* Process the input line. */ if( nArg==0 ) return rc; n = strlen(azArg[0]); c = azArg[0][0]; if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ char *zErrMsg = 0; fprintf(p->out, "BEGIN TRANSACTION;\n"); if( nArg==1 ){ sqlite_exec(db, |
︙ | ︙ | |||
577 578 579 580 581 582 583 | }else if( strcmp(z,"yes")==0 ){ val = 1; } p->echoOn = val; }else if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ | | < | 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 | }else if( strcmp(z,"yes")==0 ){ val = 1; } p->echoOn = val; }else if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ rc = 1; }else if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){ int j; char *z = nArg>=2 ? azArg[1] : "1"; int val = atoi(z); for(j=0; z[j]; j++){ |
︙ | ︙ | |||
817 818 819 820 821 822 823 | if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){ sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]); }else if( c=='s' && strncmp(azArg[0], "show", n)==0){ int i; fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off"); | | | > | 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 | if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){ sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]); }else if( c=='s' && strncmp(azArg[0], "show", n)==0){ int i; fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off"); fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off"); fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off"); fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]); fprintf(p->out,"%9.9s: %s\n","nullvalue", p->nullvalue); fprintf(p->out,"%9.9s: %s\n","output", strlen(p->outfile) ? p->outfile : "stdout"); fprintf(p->out,"%9.9s: %s\n","separator", p->separator); fprintf(p->out,"%9.9s: ","width"); for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) { fprintf(p->out,"%d ",p->colWidth[i]); } fprintf(p->out,"\n\n"); }else |
︙ | ︙ | |||
888 889 890 891 892 893 894 | int j; for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){ p->colWidth[j-1] = atoi(azArg[j]); } }else { | | | | > | > > > > > > > > > > > > | > | 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 | int j; for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){ p->colWidth[j-1] = atoi(azArg[j]); } }else { fprintf(stderr, "unknown command or invalid arguments: " " \"%s\". Enter \".help\" for help\n", azArg[0]); } return rc; } /* ** Read input from *in and process it. If *in==0 then input ** is interactive - the user is typing it it. Otherwise, input ** is coming from a file or device. A prompt is issued and history ** is saved only if input is interactive. An interrupt signal will ** cause this routine to exit immediately, unless input is interactive. */ static void process_input(struct callback_data *p, FILE *in){ char *zLine; char *zSql = 0; int nSql = 0; char *zErrMsg; while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){ if( seenInterrupt ){ if( in!=0 ) break; seenInterrupt = 0; } if( p->echoOn ) printf("%s\n", zLine); if( zLine && zLine[0]=='.' && nSql==0 ){ int rc = do_meta_command(zLine, db, p); free(zLine); if( rc ) break; continue; } if( zSql==0 ){ int i; for(i=0; zLine[i] && isspace(zLine[i]); i++){} if( zLine[i]!=0 ){ nSql = strlen(zLine); |
︙ | ︙ | |||
945 946 947 948 949 950 951 | } if( zSql ){ printf("Incomplete SQL: %s\n", zSql); free(zSql); } } | > > > > > > > > | > > > > > > > > > > | > > > > | > > > > > > > > > > > > > > > < < < < < < | < < < < < < < < < < < < < < < < < | < < < > | < < < < > > > | 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 | } if( zSql ){ printf("Incomplete SQL: %s\n", zSql); free(zSql); } } /* ** Return a pathname which is the user's home directory. A ** 0 return indicates an error of some kind. Space to hold the ** resulting string is obtained from malloc(). The calling ** function should free the result. */ static char *find_home_dir(void){ char *home_dir = NULL; #if !defined(_WIN32) && !defined(WIN32) struct passwd *pwent; uid_t uid = getuid(); while( (pwent=getpwent()) != NULL) { if(pwent->pw_uid == uid) { home_dir = pwent->pw_dir; break; } } #endif if (!home_dir) { home_dir = getenv("HOME"); if (!home_dir) { home_dir = getenv("HOMEPATH"); /* Windows? */ } } if( home_dir ){ char *z = malloc( strlen(home_dir)+1 ); if( z ) strcpy(z, home_dir); home_dir = z; } return home_dir; } /* ** Read input from the file given by sqliterc_override. Or if that ** parameter is NULL, take input from ~/.sqliterc */ static void process_sqliterc(struct callback_data *p, char *sqliterc_override){ char *home_dir = NULL; char *sqliterc = sqliterc_override; FILE *in = NULL; if (sqliterc == NULL) { home_dir = find_home_dir(); sqliterc = home_dir ? malloc(strlen(home_dir) + 15) : 0; if( sqliterc==0 ){ fprintf(stderr,"%s: out of memory!\n", Argv0); exit(1); } sprintf(sqliterc,"%s/.sqliterc",home_dir); free(home_dir); } in = fopen(sqliterc,"r"); if(in) { printf("Loading resources from %s\n",sqliterc); process_input(p,in); fclose(in); } return; } /* ** Initialize the state information in data */ void main_init(struct callback_data *data) { memset(data, 0, sizeof(*data)); data->mode = MODE_List; strcpy(data->separator,"|"); data->showHeader = 0; strcpy(mainPrompt,"sqlite> "); strcpy(continuePrompt," ...> "); |
︙ | ︙ | |||
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 | fprintf(stderr,"SQL error: %s\n", zErrMsg); exit(1); } } }else{ extern int isatty(); if( isatty(0) ){ printf( "SQLite version %s\n" "Enter \".help\" for instructions\n", sqlite_version ); process_input(&data, 0); }else{ process_input(&data, stdin); } } set_table_name(&data, 0); sqlite_close(db); return 0; } | > > > > > > > > > > > | 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 | fprintf(stderr,"SQL error: %s\n", zErrMsg); exit(1); } } }else{ extern int isatty(); if( isatty(0) ){ char *zHome; char *zHistory = 0; printf( "SQLite version %s\n" "Enter \".help\" for instructions\n", sqlite_version ); zHome = find_home_dir(); if( zHome && (zHistory = malloc(strlen(zHome)+20))!=0 ){ sprintf(zHistory,"%s/.sqlite_history", zHome); } if( zHistory ) read_history(zHistory); process_input(&data, 0); if( zHistory ){ stifle_history(100); write_history(zHistory); } }else{ process_input(&data, stdin); } } set_table_name(&data, 0); sqlite_close(db); return 0; } |