blob: 55a56520741de8de9d563206708f0a5260d3a4ee [file] [log] [blame]
drh75897232000-05-29 14:26:00 +00001/*
2** Copyright (c) 1999, 2000 D. Richard Hipp
3**
4** This program is free software; you can redistribute it and/or
5** modify it under the terms of the GNU General Public
6** License as published by the Free Software Foundation; either
7** version 2 of the License, or (at your option) any later version.
8**
9** This program is distributed in the hope that it will be useful,
10** but WITHOUT ANY WARRANTY; without even the implied warranty of
11** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12** General Public License for more details.
13**
14** You should have received a copy of the GNU General Public
15** License along with this library; if not, write to the
16** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17** Boston, MA 02111-1307, USA.
18**
19** Author contact information:
20** drh@hwaci.com
21** http://www.hwaci.com/drh/
22**
23*************************************************************************
24** This file contains code to implement the "sqlite" command line
25** utility for accessing SQLite databases.
26**
drh2dfbbca2000-07-28 14:32:48 +000027** $Id: shell.c,v 1.16 2000/07/28 14:32:49 drh Exp $
drh75897232000-05-29 14:26:00 +000028*/
29#include <stdlib.h>
30#include <string.h>
31#include <stdio.h>
32#include "sqlite.h"
33#include <unistd.h>
34#include <ctype.h>
35
36#if !defined(NO_READLINE)
drh8e7e7a22000-05-30 18:45:23 +000037# include <readline/readline.h>
38# include <readline/history.h>
39#else
40# define readline getline
41# define add_history(X)
drh75897232000-05-29 14:26:00 +000042#endif
43
44/*
drh8e7e7a22000-05-30 18:45:23 +000045** This routine reads a line of text from standard input, stores
46** the text in memory obtained from malloc() and returns a pointer
47** to the text. NULL is returned at end of file, or if malloc()
48** fails.
49**
50** The interface is like "readline" but no command-line editing
51** is done.
52*/
53static char *getline(char *zPrompt){
54 char *zLine;
55 int nLine;
drh8e7e7a22000-05-30 18:45:23 +000056 int n;
57 int eol;
58
59 if( zPrompt && *zPrompt ){
60 printf("%s",zPrompt);
61 fflush(stdout);
62 }
63 nLine = 100;
64 zLine = malloc( nLine );
65 if( zLine==0 ) return 0;
66 n = 0;
67 eol = 0;
68 while( !eol ){
69 if( n+100>nLine ){
70 nLine = nLine*2 + 100;
71 zLine = realloc(zLine, nLine);
72 if( zLine==0 ) return 0;
73 }
74 if( fgets(&zLine[n], nLine - n, stdin)==0 ){
75 if( n==0 ){
76 free(zLine);
77 return 0;
78 }
79 zLine[n] = 0;
80 eol = 1;
81 break;
82 }
83 while( zLine[n] ){ n++; }
84 if( n>0 && zLine[n-1]=='\n' ){
85 n--;
86 zLine[n] = 0;
87 eol = 1;
88 }
89 }
90 zLine = realloc( zLine, n+1 );
91 return zLine;
92}
93
94/*
95** Retrieve a single line of input text. "isatty" is true if text
96** is coming from a terminal. In that case, we issue a prompt and
97** attempt to use "readline" for command-line editing. If "isatty"
98** is false, use "getline" instead of "readline" and issue to prompt.
99**
100** zPrior is a string of prior text retrieved. If not the empty
101** string, then issue a continuation prompt.
102*/
103static char *one_input_line(const char *zPrior, int isatty){
104 char *zPrompt;
105 char *zResult;
106 if( !isatty ){
107 return getline(0);
108 }
109 if( zPrior && zPrior[0] ){
110 zPrompt = " ...> ";
111 }else{
112 zPrompt = "sqlite> ";
113 }
114 zResult = readline(zPrompt);
drh2dfbbca2000-07-28 14:32:48 +0000115 if( zResult ) add_history(zResult);
drh8e7e7a22000-05-30 18:45:23 +0000116 return zResult;
117}
118
119/*
drh75897232000-05-29 14:26:00 +0000120** An pointer to an instance of this structure is passed from
121** the main program to the callback. This is used to communicate
122** state and mode information.
123*/
124struct callback_data {
drh28bd4bc2000-06-15 15:57:22 +0000125 sqlite *db; /* The database */
126 int cnt; /* Number of records displayed so far */
127 FILE *out; /* Write results here */
128 int mode; /* An output mode setting */
129 int showHeader; /* True to show column names in List or Column mode */
130 int escape; /* Escape this character when in MODE_List */
131 char zDestTable[250]; /* Name of destination table when MODE_Insert */
132 char separator[20]; /* Separator character for MODE_List */
133 int colWidth[30]; /* Width of each column when in column mode */
drh75897232000-05-29 14:26:00 +0000134};
135
136/*
137** These are the allowed modes.
138*/
drh967e8b72000-06-21 13:59:10 +0000139#define MODE_Line 0 /* One column per line. Blank line between records */
drh75897232000-05-29 14:26:00 +0000140#define MODE_Column 1 /* One record per line in neat columns */
141#define MODE_List 2 /* One record per line with a separator */
drh1e5d0e92000-05-31 23:33:17 +0000142#define MODE_Html 3 /* Generate an XHTML table */
drh28bd4bc2000-06-15 15:57:22 +0000143#define MODE_Insert 4 /* Generate SQL "insert" statements */
drh75897232000-05-29 14:26:00 +0000144
145/*
146** Number of elements in an array
147*/
148#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
149
150/*
drh28bd4bc2000-06-15 15:57:22 +0000151** Return TRUE if the string supplied is a number of some kinds.
152*/
153static int is_numeric(const char *z){
154 int seen_digit = 0;
155 if( *z=='-' || *z=='+' ){
156 z++;
157 }
158 while( isdigit(*z) ){
159 seen_digit = 1;
160 z++;
161 }
162 if( seen_digit && *z=='.' ){
163 z++;
164 while( isdigit(*z) ){ z++; }
165 }
166 if( seen_digit && (*z=='e' || *z=='E')
167 && (isdigit(z[1]) || ((z[1]=='-' || z[1]=='+') && isdigit(z[2])))
168 ){
169 z+=2;
170 while( isdigit(*z) ){ z++; }
171 }
172 return seen_digit && *z==0;
173}
174
175/*
176** Output the given string as a quoted string using SQL quoting conventions.
177*/
178static void output_quoted_string(FILE *out, const char *z){
179 int i;
180 int nSingle = 0;
181 int nDouble = 0;
182 for(i=0; z[i]; i++){
183 if( z[i]=='\'' ) nSingle++;
184 else if( z[i]=='"' ) nDouble++;
185 }
186 if( nSingle==0 ){
187 fprintf(out,"'%s'",z);
188 }else if( nDouble==0 ){
189 fprintf(out,"\"%s\"",z);
190 }else{
191 fprintf(out,"'");
192 while( *z ){
193 for(i=0; z[i] && z[i]!='\''; i++){}
194 if( i==0 ){
195 fprintf(out,"''");
196 z++;
197 }else if( z[i]=='\'' ){
198 fprintf(out,"%.*s''",i,z);
199 z += i+1;
200 }else{
201 fprintf(out,"%s'",z);
202 break;
203 }
204 }
205 }
206}
207
208/*
drhc08a4f12000-06-15 16:49:48 +0000209** Output the given string with characters that are special to
210** HTML escaped.
211*/
212static void output_html_string(FILE *out, const char *z){
213 int i;
214 while( *z ){
215 for(i=0; z[i] && z[i]!='<' && z[i]!='&'; i++){}
216 if( i>0 ){
217 fprintf(out,"%.*s",i,z);
218 }
219 if( z[i]=='<' ){
220 fprintf(out,"&lt;");
221 }else if( z[i]=='&' ){
222 fprintf(out,"&amp;");
223 }else{
224 break;
225 }
226 z += i + 1;
227 }
228}
229
230/*
drh75897232000-05-29 14:26:00 +0000231** This is the callback routine that the SQLite library
232** invokes for each row of a query result.
233*/
234static int callback(void *pArg, int nArg, char **azArg, char **azCol){
235 int i;
236 struct callback_data *p = (struct callback_data*)pArg;
237 switch( p->mode ){
238 case MODE_Line: {
239 if( p->cnt++>0 ) fprintf(p->out,"\n");
240 for(i=0; i<nArg; i++){
drhc61053b2000-06-04 12:58:36 +0000241 fprintf(p->out,"%s = %s\n", azCol[i], azArg[i] ? azArg[i] : 0);
drh75897232000-05-29 14:26:00 +0000242 }
243 break;
244 }
245 case MODE_Column: {
246 if( p->cnt++==0 && p->showHeader ){
247 for(i=0; i<nArg; i++){
248 int w;
249 if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
250 w = p->colWidth[i];
251 }else{
252 w = 10;
253 }
254 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
255 }
256 for(i=0; i<nArg; i++){
257 int w;
258 if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
259 w = p->colWidth[i];
260 }else{
261 w = 10;
262 }
drh1e5d0e92000-05-31 23:33:17 +0000263 fprintf(p->out,"%-*.*s%s",w,w,"-------------------------------------"
264 "------------------------------------------------------------",
drh75897232000-05-29 14:26:00 +0000265 i==nArg-1 ? "\n": " ");
266 }
267 }
268 for(i=0; i<nArg; i++){
269 int w;
270 if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
271 w = p->colWidth[i];
272 }else{
273 w = 10;
274 }
drhc61053b2000-06-04 12:58:36 +0000275 fprintf(p->out,"%-*.*s%s",w,w,
276 azArg[i] ? azArg[i] : "", i==nArg-1 ? "\n": " ");
drh75897232000-05-29 14:26:00 +0000277 }
278 break;
279 }
280 case MODE_List: {
281 if( p->cnt++==0 && p->showHeader ){
282 for(i=0; i<nArg; i++){
283 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
284 }
285 }
286 for(i=0; i<nArg; i++){
drh4c653a02000-06-07 01:27:47 +0000287 char *z = azArg[i];
288 if( z==0 ) z = "";
289 while( *z ){
290 int j;
291 for(j=0; z[j] && z[j]!=p->escape && z[j]!='\\'; j++){}
292 if( j>0 ){
293 fprintf(p->out, "%.*s", j, z);
294 }
295 if( z[j] ){
296 fprintf(p->out, "\\%c", z[j]);
drh670f74f2000-06-07 02:04:22 +0000297 z++;
drh4c653a02000-06-07 01:27:47 +0000298 }
drh73755922000-06-07 01:33:42 +0000299 z += j;
drh4c653a02000-06-07 01:27:47 +0000300 }
301 fprintf(p->out, "%s", i==nArg-1 ? "\n" : p->separator);
drh75897232000-05-29 14:26:00 +0000302 }
303 break;
304 }
drh1e5d0e92000-05-31 23:33:17 +0000305 case MODE_Html: {
306 if( p->cnt++==0 && p->showHeader ){
307 fprintf(p->out,"<TR>");
308 for(i=0; i<nArg; i++){
309 fprintf(p->out,"<TH>%s</TH>",azCol[i]);
310 }
311 fprintf(p->out,"</TR>\n");
312 }
drh28bd4bc2000-06-15 15:57:22 +0000313 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +0000314 for(i=0; i<nArg; i++){
drhc08a4f12000-06-15 16:49:48 +0000315 fprintf(p->out,"<TD>");
316 output_html_string(p->out, azArg[i] ? azArg[i] : "");
317 fprintf(p->out,"</TD>\n");
drh1e5d0e92000-05-31 23:33:17 +0000318 }
drh28bd4bc2000-06-15 15:57:22 +0000319 fprintf(p->out,"</TD></TR>\n");
drh1e5d0e92000-05-31 23:33:17 +0000320 break;
321 }
drh28bd4bc2000-06-15 15:57:22 +0000322 case MODE_Insert: {
323 fprintf(p->out,"INSERT INTO '%s' VALUES(",p->zDestTable);
324 for(i=0; i<nArg; i++){
325 char *zSep = i>0 ? ",": "";
326 if( azArg[i]==0 ){
327 fprintf(p->out,"%sNULL",zSep);
328 }else if( is_numeric(azArg[i]) ){
329 fprintf(p->out,"%s%s",zSep, azArg[i]);
330 }else{
331 if( zSep[0] ) fprintf(p->out,"%s",zSep);
332 output_quoted_string(p->out, azArg[i]);
333 }
334 }
335 fprintf(p->out,");\n");
336 }
drh75897232000-05-29 14:26:00 +0000337 }
338 return 0;
339}
340
341/*
drh4c653a02000-06-07 01:27:47 +0000342** This is a different callback routine used for dumping the database.
343** Each row received by this callback consists of a table name,
344** the table type ("index" or "table") and SQL to create the table.
345** This routine should print text sufficient to recreate the table.
346*/
347static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
348 struct callback_data *pData = (struct callback_data *)pArg;
349 if( nArg!=3 ) return 1;
350 fprintf(pData->out, "%s;\n", azArg[2]);
351 if( strcmp(azArg[1],"table")==0 ){
352 struct callback_data d2;
353 char zSql[1000];
354 d2 = *pData;
355 d2.mode = MODE_List;
drh670f74f2000-06-07 02:04:22 +0000356 d2.escape = '\t';
drh4c653a02000-06-07 01:27:47 +0000357 strcpy(d2.separator,"\t");
358 fprintf(pData->out, "COPY '%s' FROM STDIN;\n", azArg[0]);
359 sprintf(zSql, "SELECT * FROM '%s'", azArg[0]);
360 sqlite_exec(pData->db, zSql, callback, &d2, 0);
361 fprintf(pData->out, "\\.\n");
362 }
drh73755922000-06-07 01:33:42 +0000363 fprintf(pData->out, "VACUUM '%s';\n", azArg[0]);
drh4c653a02000-06-07 01:27:47 +0000364 return 0;
365}
366
367/*
drh75897232000-05-29 14:26:00 +0000368** Text of a help message
369*/
370static char zHelp[] =
drh4c653a02000-06-07 01:27:47 +0000371 ".dump ?TABLE? ... Dump the database in an text format\n"
drh75897232000-05-29 14:26:00 +0000372 ".exit Exit this program\n"
373 ".explain Set output mode suitable for EXPLAIN\n"
374 ".header ON|OFF Turn display of headers on or off\n"
375 ".help Show this message\n"
376 ".indices TABLE Show names of all indices on TABLE\n"
drh1e5d0e92000-05-31 23:33:17 +0000377 ".mode MODE Set mode to one of \"line\", \"column\", "
378 "\"list\", or \"html\"\n"
drhc08a4f12000-06-15 16:49:48 +0000379 ".mode insert TABLE Generate SQL insert statements for TABLE\n"
drh75897232000-05-29 14:26:00 +0000380 ".output FILENAME Send output to FILENAME\n"
381 ".output stdout Send output to the screen\n"
382 ".schema ?TABLE? Show the CREATE statements\n"
383 ".separator STRING Change separator string for \"list\" mode\n"
384 ".tables List names all tables in the database\n"
drh2dfbbca2000-07-28 14:32:48 +0000385 ".timeout MS Try opening locked tables for MS milliseconds\n"
drh75897232000-05-29 14:26:00 +0000386 ".width NUM NUM ... Set column widths for \"column\" mode\n"
387;
388
389/*
390** If an input line begins with "." then invoke this routine to
391** process that line.
392*/
393static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
394 int i = 1;
395 int nArg = 0;
396 int n, c;
397 char *azArg[50];
398
399 /* Parse the input line into tokens.
400 */
401 while( zLine[i] && nArg<ArraySize(azArg) ){
402 while( isspace(zLine[i]) ){ i++; }
403 if( zLine[i]=='\'' || zLine[i]=='"' ){
404 int delim = zLine[i++];
405 azArg[nArg++] = &zLine[i];
406 while( zLine[i] && zLine[i]!=delim ){ i++; }
407 if( zLine[i]==delim ){
408 zLine[i++] = 0;
409 }
410 }else{
411 azArg[nArg++] = &zLine[i];
412 while( zLine[i] && !isspace(zLine[i]) ){ i++; }
413 if( zLine[i] ) zLine[i++] = 0;
414 }
415 }
416
417 /* Process the input line.
418 */
419 if( nArg==0 ) return;
420 n = strlen(azArg[0]);
421 c = azArg[0][0];
drh4c653a02000-06-07 01:27:47 +0000422
423 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
424 char *zErrMsg = 0;
425 char zSql[1000];
426 if( nArg==1 ){
427 sprintf(zSql, "SELECT name, type, sql FROM sqlite_master "
428 "ORDER BY tbl_name, type DESC, name");
429 sqlite_exec(db, zSql, dump_callback, p, &zErrMsg);
430 }else{
431 int i;
432 for(i=1; i<nArg && zErrMsg==0; i++){
433 sprintf(zSql, "SELECT name, type, sql FROM sqlite_master "
434 "WHERE tbl_name LIKE '%.800s'"
435 "ORDER BY type DESC, name", azArg[i]);
436 sqlite_exec(db, zSql, dump_callback, p, &zErrMsg);
437
438 }
439 }
440 if( zErrMsg ){
441 fprintf(stderr,"Error: %s\n", zErrMsg);
442 free(zErrMsg);
443 }
444 }else
drh75897232000-05-29 14:26:00 +0000445
446 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
447 exit(0);
448 }else
449
450 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
451 p->mode = MODE_Column;
452 p->showHeader = 1;
453 p->colWidth[0] = 4;
454 p->colWidth[1] = 12;
455 p->colWidth[2] = 5;
456 p->colWidth[3] = 5;
457 p->colWidth[4] = 40;
458 }else
459
460 if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
461 int j;
462 char *z = azArg[1];
463 int val = atoi(azArg[1]);
464 for(j=0; z[j]; j++){
465 if( isupper(z[j]) ) z[j] = tolower(z[j]);
466 }
467 if( strcmp(z,"on")==0 ){
468 val = 1;
469 }else if( strcmp(z,"yes")==0 ){
470 val = 1;
471 }
472 p->showHeader = val;
473 }else
474
475 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
476 fprintf(stderr,zHelp);
477 }else
478
479 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
480 struct callback_data data;
481 char *zErrMsg = 0;
482 char zSql[1000];
483 memcpy(&data, p, sizeof(data));
484 data.showHeader = 0;
485 data.mode = MODE_List;
486 sprintf(zSql, "SELECT name FROM sqlite_master "
drh4c653a02000-06-07 01:27:47 +0000487 "WHERE type='index' AND tbl_name LIKE '%.800s' "
drh305cea62000-05-29 17:44:25 +0000488 "ORDER BY name", azArg[1]);
drh75897232000-05-29 14:26:00 +0000489 sqlite_exec(db, zSql, callback, &data, &zErrMsg);
490 if( zErrMsg ){
491 fprintf(stderr,"Error: %s\n", zErrMsg);
492 free(zErrMsg);
493 }
494 }else
495
drh28bd4bc2000-06-15 15:57:22 +0000496 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
drh75897232000-05-29 14:26:00 +0000497 int n2 = strlen(azArg[1]);
498 if( strncmp(azArg[1],"line",n2)==0 ){
499 p->mode = MODE_Line;
500 }else if( strncmp(azArg[1],"column",n2)==0 ){
501 p->mode = MODE_Column;
502 }else if( strncmp(azArg[1],"list",n2)==0 ){
503 p->mode = MODE_List;
drh1e5d0e92000-05-31 23:33:17 +0000504 }else if( strncmp(azArg[1],"html",n2)==0 ){
505 p->mode = MODE_Html;
drh28bd4bc2000-06-15 15:57:22 +0000506 }else if( strncmp(azArg[1],"insert",n2)==0 ){
507 p->mode = MODE_Insert;
508 if( nArg>=3 ){
509 sprintf(p->zDestTable,"%.*s", (int)(sizeof(p->zDestTable)-1), azArg[2]);
510 }else{
511 sprintf(p->zDestTable,"table");
512 }
drh75897232000-05-29 14:26:00 +0000513 }
514 }else
515
516 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
517 if( p->out!=stdout ){
518 fclose(p->out);
519 }
520 if( strcmp(azArg[1],"stdout")==0 ){
521 p->out = stdout;
522 }else{
523 p->out = fopen(azArg[1], "w");
524 if( p->out==0 ){
525 fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
526 p->out = stdout;
527 }
528 }
529 }else
530
531 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
532 struct callback_data data;
533 char *zErrMsg = 0;
534 char zSql[1000];
535 memcpy(&data, p, sizeof(data));
536 data.showHeader = 0;
537 data.mode = MODE_List;
538 if( nArg>1 ){
drh59692542000-06-07 00:12:24 +0000539 sprintf(zSql, "SELECT sql FROM sqlite_master "
540 "WHERE tbl_name LIKE '%.800s'"
541 "ORDER BY type DESC, name",
drh75897232000-05-29 14:26:00 +0000542 azArg[1]);
543 }else{
544 sprintf(zSql, "SELECT sql FROM sqlite_master "
545 "ORDER BY tbl_name, type DESC, name");
546 }
547 sqlite_exec(db, zSql, callback, &data, &zErrMsg);
548 if( zErrMsg ){
549 fprintf(stderr,"Error: %s\n", zErrMsg);
550 free(zErrMsg);
551 }
552 }else
553
554 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
555 sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
556 }else
557
drh2dfbbca2000-07-28 14:32:48 +0000558 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
drh75897232000-05-29 14:26:00 +0000559 struct callback_data data;
560 char *zErrMsg = 0;
drh305cea62000-05-29 17:44:25 +0000561 static char zSql[] =
562 "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
drh75897232000-05-29 14:26:00 +0000563 memcpy(&data, p, sizeof(data));
564 data.showHeader = 0;
565 data.mode = MODE_List;
566 sqlite_exec(db, zSql, callback, &data, &zErrMsg);
567 if( zErrMsg ){
568 fprintf(stderr,"Error: %s\n", zErrMsg);
569 free(zErrMsg);
570 }
571 }else
572
drh2dfbbca2000-07-28 14:32:48 +0000573 if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
574 sqlite_busy_timeout(db, atoi(azArg[1]));
575 }else
576
drh75897232000-05-29 14:26:00 +0000577 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
578 int j;
579 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
580 p->colWidth[j-1] = atoi(azArg[j]);
581 }
582 }else
583
584 {
585 fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
586 azArg[0]);
587 }
588}
589
590int main(int argc, char **argv){
591 sqlite *db;
592 char *zErrMsg = 0;
drh1e5d0e92000-05-31 23:33:17 +0000593 char *argv0 = argv[0];
drh75897232000-05-29 14:26:00 +0000594 struct callback_data data;
595
drh1e5d0e92000-05-31 23:33:17 +0000596 memset(&data, 0, sizeof(data));
597 data.mode = MODE_List;
598 strcpy(data.separator,"|");
599 data.showHeader = 0;
600 while( argc>=2 && argv[1][0]=='-' ){
601 if( strcmp(argv[1],"-html")==0 ){
602 data.mode = MODE_Html;
603 argc--;
604 argv++;
605 }else if( strcmp(argv[1],"-list")==0 ){
606 data.mode = MODE_List;
607 argc--;
608 argv++;
609 }else if( strcmp(argv[1],"-line")==0 ){
610 data.mode = MODE_Line;
611 argc--;
612 argv++;
613 }else if( argc>=3 && strcmp(argv[0],"-separator")==0 ){
drhbed86902000-06-02 13:27:59 +0000614 sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]);
drh1e5d0e92000-05-31 23:33:17 +0000615 argc -= 2;
616 argv += 2;
617 }else if( strcmp(argv[1],"-header")==0 ){
618 data.showHeader = 1;
619 argc--;
620 argv++;
621 }else if( strcmp(argv[1],"-noheader")==0 ){
622 data.showHeader = 0;
623 argc--;
624 argv++;
625 }else{
626 fprintf(stderr,"%s: unknown option: %s\n", argv0, argv[1]);
627 return 1;
628 }
629 }
drh75897232000-05-29 14:26:00 +0000630 if( argc!=2 && argc!=3 ){
drh1e5d0e92000-05-31 23:33:17 +0000631 fprintf(stderr,"Usage: %s ?OPTIONS? FILENAME ?SQL?\n", argv0);
drh75897232000-05-29 14:26:00 +0000632 exit(1);
633 }
drh4c653a02000-06-07 01:27:47 +0000634 data.db = db = sqlite_open(argv[1], 0666, &zErrMsg);
drh75897232000-05-29 14:26:00 +0000635 if( db==0 ){
drhd1dedb82000-06-05 02:07:04 +0000636 if( zErrMsg ){
637 fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1], zErrMsg);
638 }else{
639 fprintf(stderr,"Unable to open database %s\n", argv[1]);
640 }
drh75897232000-05-29 14:26:00 +0000641 exit(1);
642 }
drh75897232000-05-29 14:26:00 +0000643 data.out = stdout;
644 if( argc==3 ){
drh75897232000-05-29 14:26:00 +0000645 if( sqlite_exec(db, argv[2], callback, &data, &zErrMsg)!=0 && zErrMsg!=0 ){
646 fprintf(stderr,"SQL error: %s\n", zErrMsg);
647 exit(1);
648 }
649 }else{
650 char *zLine;
651 char *zSql = 0;
652 int nSql = 0;
653 int istty = isatty(0);
drh75897232000-05-29 14:26:00 +0000654 if( istty ){
655 printf(
656 "Enter \".help\" for instructions\n"
657 );
658 }
drh8e7e7a22000-05-30 18:45:23 +0000659 while( (zLine = one_input_line(zSql, istty))!=0 ){
drh75897232000-05-29 14:26:00 +0000660 if( zLine && zLine[0]=='.' ){
661 do_meta_command(zLine, db, &data);
662 free(zLine);
663 continue;
664 }
665 if( zSql==0 ){
666 nSql = strlen(zLine);
667 zSql = malloc( nSql+1 );
668 strcpy(zSql, zLine);
669 }else{
670 int len = strlen(zLine);
671 zSql = realloc( zSql, nSql + len + 2 );
672 if( zSql==0 ){
drh1e5d0e92000-05-31 23:33:17 +0000673 fprintf(stderr,"%s: out of memory!\n", argv0);
drh75897232000-05-29 14:26:00 +0000674 exit(1);
675 }
676 strcpy(&zSql[nSql++], "\n");
677 strcpy(&zSql[nSql], zLine);
678 nSql += len;
679 }
680 free(zLine);
681 if( sqlite_complete(zSql) ){
682 data.cnt = 0;
683 if( sqlite_exec(db, zSql, callback, &data, &zErrMsg)!=0
684 && zErrMsg!=0 ){
685 printf("SQL error: %s\n", zErrMsg);
686 free(zErrMsg);
687 zErrMsg = 0;
688 }
689 free(zSql);
690 zSql = 0;
691 nSql = 0;
692 }
693 }
694 }
695 sqlite_close(db);
696 return 0;
697}