xref: /sqlite-3.40.0/src/tclsqlite.c (revision dcd997ea)
175897234Sdrh /*
2b19a2bc6Sdrh ** 2001 September 15
375897234Sdrh **
4b19a2bc6Sdrh ** The author disclaims copyright to this source code.  In place of
5b19a2bc6Sdrh ** a legal notice, here is a blessing:
675897234Sdrh **
7b19a2bc6Sdrh **    May you do good and not evil.
8b19a2bc6Sdrh **    May you find forgiveness for yourself and forgive others.
9b19a2bc6Sdrh **    May you share freely, never taking more than you give.
1075897234Sdrh **
1175897234Sdrh *************************************************************************
1275897234Sdrh ** A TCL Interface to SQLite
1375897234Sdrh **
14*dcd997eaSdrh ** $Id: tclsqlite.c,v 1.44 2003/01/31 17:21:50 drh Exp $
1575897234Sdrh */
166d31316cSdrh #ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */
176d31316cSdrh 
1806b2718aSdrh #include "sqliteInt.h"
1917a68934Sdrh #include "tcl.h"
2075897234Sdrh #include <stdlib.h>
2175897234Sdrh #include <string.h>
22ce927065Sdrh #include <assert.h>
2375897234Sdrh 
2475897234Sdrh /*
2598808babSdrh ** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we
2698808babSdrh ** have to do a translation when going between the two.  Set the
2798808babSdrh ** UTF_TRANSLATION_NEEDED macro to indicate that we need to do
2898808babSdrh ** this translation.
2998808babSdrh */
3098808babSdrh #if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8)
3198808babSdrh # define UTF_TRANSLATION_NEEDED 1
3298808babSdrh #endif
3398808babSdrh 
3498808babSdrh /*
35cabb0819Sdrh ** New SQL functions can be created as TCL scripts.  Each such function
36cabb0819Sdrh ** is described by an instance of the following structure.
37cabb0819Sdrh */
38cabb0819Sdrh typedef struct SqlFunc SqlFunc;
39cabb0819Sdrh struct SqlFunc {
40cabb0819Sdrh   Tcl_Interp *interp;   /* The TCL interpret to execute the function */
41cabb0819Sdrh   char *zScript;        /* The script to be run */
42cabb0819Sdrh   SqlFunc *pNext;       /* Next function on the list of them all */
43cabb0819Sdrh };
44cabb0819Sdrh 
45cabb0819Sdrh /*
46bec3f402Sdrh ** There is one instance of this structure for each SQLite database
47bec3f402Sdrh ** that has been opened by the SQLite TCL interface.
48bec3f402Sdrh */
49bec3f402Sdrh typedef struct SqliteDb SqliteDb;
50bec3f402Sdrh struct SqliteDb {
51bec3f402Sdrh   sqlite *db;           /* The "real" database structure */
52bec3f402Sdrh   Tcl_Interp *interp;   /* The interpreter used for this database */
536d31316cSdrh   char *zBusy;          /* The busy callback routine */
54cabb0819Sdrh   SqlFunc *pFunc;       /* List of SQL functions */
55*dcd997eaSdrh   int rc;               /* Return code of most recent sqlite_exec() */
56bec3f402Sdrh };
57bec3f402Sdrh 
58bec3f402Sdrh /*
5975897234Sdrh ** An instance of this structure passes information thru the sqlite
6075897234Sdrh ** logic from the original TCL command into the callback routine.
6175897234Sdrh */
6275897234Sdrh typedef struct CallbackData CallbackData;
6375897234Sdrh struct CallbackData {
6475897234Sdrh   Tcl_Interp *interp;       /* The TCL interpreter */
6575897234Sdrh   char *zArray;             /* The array into which data is written */
666d31316cSdrh   Tcl_Obj *pCode;           /* The code to execute for each row */
67ce927065Sdrh   int once;                 /* Set for first callback only */
68960e8c63Sdrh   int tcl_rc;               /* Return code from TCL script */
6998808babSdrh   int nColName;             /* Number of entries in the azColName[] array */
7098808babSdrh   char **azColName;         /* Column names translated to UTF-8 */
7198808babSdrh };
72297ecf14Sdrh 
736d4abfbeSdrh #ifdef UTF_TRANSLATION_NEEDED
74297ecf14Sdrh /*
7575897234Sdrh ** Called for each row of the result.
766d4abfbeSdrh **
776d4abfbeSdrh ** This version is used when TCL expects UTF-8 data but the database
786d4abfbeSdrh ** uses the ISO8859 format.  A translation must occur from ISO8859 into
796d4abfbeSdrh ** UTF-8.
8075897234Sdrh */
8175897234Sdrh static int DbEvalCallback(
8275897234Sdrh   void *clientData,      /* An instance of CallbackData */
8375897234Sdrh   int nCol,              /* Number of columns in the result */
8475897234Sdrh   char ** azCol,         /* Data for each column */
8575897234Sdrh   char ** azN            /* Name for each column */
8675897234Sdrh ){
8775897234Sdrh   CallbackData *cbData = (CallbackData*)clientData;
8875897234Sdrh   int i, rc;
89297ecf14Sdrh   Tcl_DString dCol;
906d4abfbeSdrh   Tcl_DStringInit(&dCol);
91ce927065Sdrh   if( cbData->azColName==0 ){
92ce927065Sdrh     assert( cbData->once );
93ce927065Sdrh     cbData->once = 0;
94ce927065Sdrh     if( cbData->zArray[0] ){
956d4abfbeSdrh       Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0);
96ce927065Sdrh     }
976d4abfbeSdrh     cbData->azColName = malloc( nCol*sizeof(char*) );
986d4abfbeSdrh     if( cbData->azColName==0 ){ return 1; }
996d4abfbeSdrh     cbData->nColName = nCol;
1006d4abfbeSdrh     for(i=0; i<nCol; i++){
1016d4abfbeSdrh       Tcl_ExternalToUtfDString(NULL, azN[i], -1, &dCol);
1026d4abfbeSdrh       cbData->azColName[i] = malloc( Tcl_DStringLength(&dCol) + 1 );
1036d4abfbeSdrh       if( cbData->azColName[i] ){
1046d4abfbeSdrh         strcpy(cbData->azColName[i], Tcl_DStringValue(&dCol));
105ce927065Sdrh       }else{
106ce927065Sdrh         return 1;
1076d4abfbeSdrh       }
108ce927065Sdrh       if( cbData->zArray[0] ){
109ce927065Sdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, "*",
110ce927065Sdrh              Tcl_DStringValue(&dCol), TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
111704027f1Sdrh         if( azN[nCol]!=0 ){
1125080aaa7Sdrh           Tcl_DString dType;
1135080aaa7Sdrh           Tcl_DStringInit(&dType);
114fa173a76Sdrh           Tcl_DStringAppend(&dType, "typeof:", -1);
115fa173a76Sdrh           Tcl_DStringAppend(&dType, Tcl_DStringValue(&dCol), -1);
116fa173a76Sdrh           Tcl_DStringFree(&dCol);
1175080aaa7Sdrh           Tcl_ExternalToUtfDString(NULL, azN[i+nCol], -1, &dCol);
118fa173a76Sdrh           Tcl_SetVar2(cbData->interp, cbData->zArray,
119fa173a76Sdrh                Tcl_DStringValue(&dType), Tcl_DStringValue(&dCol),
120fa173a76Sdrh                TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
121fa173a76Sdrh           Tcl_DStringFree(&dType);
1226d4abfbeSdrh         }
1235080aaa7Sdrh       }
124fa173a76Sdrh 
1256d4abfbeSdrh       Tcl_DStringFree(&dCol);
1266d4abfbeSdrh     }
1276d4abfbeSdrh   }
1286d4abfbeSdrh   if( azCol!=0 ){
1296d4abfbeSdrh     if( cbData->zArray[0] ){
1306d4abfbeSdrh       for(i=0; i<nCol; i++){
1316d4abfbeSdrh         char *z = azCol[i];
1326d4abfbeSdrh         if( z==0 ) z = "";
1336d4abfbeSdrh         Tcl_DStringInit(&dCol);
1346d4abfbeSdrh         Tcl_ExternalToUtfDString(NULL, z, -1, &dCol);
1356d4abfbeSdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, cbData->azColName[i],
1366d4abfbeSdrh               Tcl_DStringValue(&dCol), 0);
1376d4abfbeSdrh         Tcl_DStringFree(&dCol);
1386d4abfbeSdrh       }
1396d4abfbeSdrh     }else{
1406d4abfbeSdrh       for(i=0; i<nCol; i++){
1416d4abfbeSdrh         char *z = azCol[i];
1426d4abfbeSdrh         if( z==0 ) z = "";
1436d4abfbeSdrh         Tcl_DStringInit(&dCol);
1446d4abfbeSdrh         Tcl_ExternalToUtfDString(NULL, z, -1, &dCol);
1456d4abfbeSdrh         Tcl_SetVar(cbData->interp, cbData->azColName[i],
1466d4abfbeSdrh                    Tcl_DStringValue(&dCol), 0);
1476d4abfbeSdrh         Tcl_DStringFree(&dCol);
1486d4abfbeSdrh       }
1496d4abfbeSdrh     }
1506d4abfbeSdrh   }
1516d4abfbeSdrh   rc = Tcl_EvalObj(cbData->interp, cbData->pCode);
1526d4abfbeSdrh   if( rc==TCL_CONTINUE ) rc = TCL_OK;
1536d4abfbeSdrh   cbData->tcl_rc = rc;
1546d4abfbeSdrh   return rc!=TCL_OK;
1556d4abfbeSdrh }
1566d4abfbeSdrh #endif /* UTF_TRANSLATION_NEEDED */
1576d4abfbeSdrh 
1586d4abfbeSdrh #ifndef UTF_TRANSLATION_NEEDED
1596d4abfbeSdrh /*
1606d4abfbeSdrh ** Called for each row of the result.
1616d4abfbeSdrh **
1626d4abfbeSdrh ** This version is used when either of the following is true:
1636d4abfbeSdrh **
1646d4abfbeSdrh **    (1) This version of TCL uses UTF-8 and the data in the
1656d4abfbeSdrh **        SQLite database is already in the UTF-8 format.
1666d4abfbeSdrh **
1676d4abfbeSdrh **    (2) This version of TCL uses ISO8859 and the data in the
1686d4abfbeSdrh **        SQLite database is already in the ISO8859 format.
1696d4abfbeSdrh */
1706d4abfbeSdrh static int DbEvalCallback(
1716d4abfbeSdrh   void *clientData,      /* An instance of CallbackData */
1726d4abfbeSdrh   int nCol,              /* Number of columns in the result */
1736d4abfbeSdrh   char ** azCol,         /* Data for each column */
1746d4abfbeSdrh   char ** azN            /* Name for each column */
1756d4abfbeSdrh ){
1766d4abfbeSdrh   CallbackData *cbData = (CallbackData*)clientData;
1776d4abfbeSdrh   int i, rc;
1786a535340Sdrh   if( azCol==0 || (cbData->once && cbData->zArray[0]) ){
1799b0d0a8bSdrh     Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0);
18075897234Sdrh     for(i=0; i<nCol; i++){
18175897234Sdrh       Tcl_SetVar2(cbData->interp, cbData->zArray, "*", azN[i],
18275897234Sdrh          TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
1835080aaa7Sdrh       if( azN[nCol] ){
1845080aaa7Sdrh         char *z = sqlite_mprintf("typeof:%s", azN[i]);
1855080aaa7Sdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, z, azN[i+nCol],
186fa173a76Sdrh            TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
187fa173a76Sdrh         sqlite_freemem(z);
18875897234Sdrh       }
1895080aaa7Sdrh     }
1906a535340Sdrh     cbData->once = 0;
19175897234Sdrh   }
1926a535340Sdrh   if( azCol!=0 ){
1936a535340Sdrh     if( cbData->zArray[0] ){
19475897234Sdrh       for(i=0; i<nCol; i++){
195c61053b7Sdrh         char *z = azCol[i];
196c61053b7Sdrh         if( z==0 ) z = "";
197c61053b7Sdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], z, 0);
19875897234Sdrh       }
19975897234Sdrh     }else{
20075897234Sdrh       for(i=0; i<nCol; i++){
201c61053b7Sdrh         char *z = azCol[i];
202c61053b7Sdrh         if( z==0 ) z = "";
203c61053b7Sdrh         Tcl_SetVar(cbData->interp, azN[i], z, 0);
20475897234Sdrh       }
20575897234Sdrh     }
2066a535340Sdrh   }
2076d31316cSdrh   rc = Tcl_EvalObj(cbData->interp, cbData->pCode);
208960e8c63Sdrh   if( rc==TCL_CONTINUE ) rc = TCL_OK;
209960e8c63Sdrh   cbData->tcl_rc = rc;
210960e8c63Sdrh   return rc!=TCL_OK;
21175897234Sdrh }
2126d4abfbeSdrh #endif
21375897234Sdrh 
21475897234Sdrh /*
2156d31316cSdrh ** This is an alternative callback for database queries.  Instead
2166d31316cSdrh ** of invoking a TCL script to handle the result, this callback just
2176d31316cSdrh ** appends each column of the result to a list.  After the query
2186d31316cSdrh ** is complete, the list is returned.
2196d31316cSdrh */
2206d31316cSdrh static int DbEvalCallback2(
2216d31316cSdrh   void *clientData,      /* An instance of CallbackData */
2226d31316cSdrh   int nCol,              /* Number of columns in the result */
2236d31316cSdrh   char ** azCol,         /* Data for each column */
2246d31316cSdrh   char ** azN            /* Name for each column */
2256d31316cSdrh ){
2266d31316cSdrh   Tcl_Obj *pList = (Tcl_Obj*)clientData;
2276d31316cSdrh   int i;
2286a535340Sdrh   if( azCol==0 ) return 0;
2296d31316cSdrh   for(i=0; i<nCol; i++){
2306d31316cSdrh     Tcl_Obj *pElem;
2316d31316cSdrh     if( azCol[i] && *azCol[i] ){
232297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
233297ecf14Sdrh       Tcl_DString dCol;
234297ecf14Sdrh       Tcl_DStringInit(&dCol);
235297ecf14Sdrh       Tcl_ExternalToUtfDString(NULL, azCol[i], -1, &dCol);
236297ecf14Sdrh       pElem = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
237297ecf14Sdrh       Tcl_DStringFree(&dCol);
238297ecf14Sdrh #else
2396d31316cSdrh       pElem = Tcl_NewStringObj(azCol[i], -1);
240297ecf14Sdrh #endif
2416d31316cSdrh     }else{
2426d31316cSdrh       pElem = Tcl_NewObj();
2436d31316cSdrh     }
2446d31316cSdrh     Tcl_ListObjAppendElement(0, pList, pElem);
2456d31316cSdrh   }
2466d31316cSdrh   return 0;
2476d31316cSdrh }
2486d31316cSdrh 
2496d31316cSdrh /*
25075897234Sdrh ** Called when the command is deleted.
25175897234Sdrh */
25275897234Sdrh static void DbDeleteCmd(void *db){
253bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)db;
254bec3f402Sdrh   sqlite_close(pDb->db);
255cabb0819Sdrh   while( pDb->pFunc ){
256cabb0819Sdrh     SqlFunc *pFunc = pDb->pFunc;
257cabb0819Sdrh     pDb->pFunc = pFunc->pNext;
258cabb0819Sdrh     Tcl_Free((char*)pFunc);
259cabb0819Sdrh   }
260bec3f402Sdrh   if( pDb->zBusy ){
261bec3f402Sdrh     Tcl_Free(pDb->zBusy);
262bec3f402Sdrh   }
263bec3f402Sdrh   Tcl_Free((char*)pDb);
264bec3f402Sdrh }
265bec3f402Sdrh 
266bec3f402Sdrh /*
267bec3f402Sdrh ** This routine is called when a database file is locked while trying
268bec3f402Sdrh ** to execute SQL.
269bec3f402Sdrh */
270bec3f402Sdrh static int DbBusyHandler(void *cd, const char *zTable, int nTries){
271bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)cd;
272bec3f402Sdrh   int rc;
273bec3f402Sdrh   char zVal[30];
274bec3f402Sdrh   char *zCmd;
275bec3f402Sdrh   Tcl_DString cmd;
276bec3f402Sdrh 
277bec3f402Sdrh   Tcl_DStringInit(&cmd);
278bec3f402Sdrh   Tcl_DStringAppend(&cmd, pDb->zBusy, -1);
279bec3f402Sdrh   Tcl_DStringAppendElement(&cmd, zTable);
280bec3f402Sdrh   sprintf(zVal, " %d", nTries);
281bec3f402Sdrh   Tcl_DStringAppend(&cmd, zVal, -1);
282bec3f402Sdrh   zCmd = Tcl_DStringValue(&cmd);
283bec3f402Sdrh   rc = Tcl_Eval(pDb->interp, zCmd);
284bec3f402Sdrh   Tcl_DStringFree(&cmd);
285bec3f402Sdrh   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
286bec3f402Sdrh     return 0;
287bec3f402Sdrh   }
288bec3f402Sdrh   return 1;
28975897234Sdrh }
29075897234Sdrh 
29175897234Sdrh /*
292cabb0819Sdrh ** This routine is called to evaluate an SQL function implemented
293cabb0819Sdrh ** using TCL script.
294cabb0819Sdrh */
295cabb0819Sdrh static void tclSqlFunc(sqlite_func *context, int argc, const char **argv){
296cabb0819Sdrh   SqlFunc *p = sqlite_user_data(context);
297cabb0819Sdrh   Tcl_DString cmd;
298cabb0819Sdrh   int i;
299cabb0819Sdrh   int rc;
300cabb0819Sdrh 
301cabb0819Sdrh   Tcl_DStringInit(&cmd);
302cabb0819Sdrh   Tcl_DStringAppend(&cmd, p->zScript, -1);
303cabb0819Sdrh   for(i=0; i<argc; i++){
304cabb0819Sdrh     Tcl_DStringAppendElement(&cmd, argv[i] ? argv[i] : "");
305cabb0819Sdrh   }
306cabb0819Sdrh   rc = Tcl_Eval(p->interp, Tcl_DStringValue(&cmd));
307cabb0819Sdrh   if( rc ){
308cabb0819Sdrh     sqlite_set_result_error(context, Tcl_GetStringResult(p->interp), -1);
309cabb0819Sdrh   }else{
310cabb0819Sdrh     sqlite_set_result_string(context, Tcl_GetStringResult(p->interp), -1);
311cabb0819Sdrh   }
312cabb0819Sdrh }
313cabb0819Sdrh 
314cabb0819Sdrh /*
31575897234Sdrh ** The "sqlite" command below creates a new Tcl command for each
31675897234Sdrh ** connection it opens to an SQLite database.  This routine is invoked
31775897234Sdrh ** whenever one of those connection-specific commands is executed
31875897234Sdrh ** in Tcl.  For example, if you run Tcl code like this:
31975897234Sdrh **
32075897234Sdrh **       sqlite db1  "my_database"
32175897234Sdrh **       db1 close
32275897234Sdrh **
32375897234Sdrh ** The first command opens a connection to the "my_database" database
32475897234Sdrh ** and calls that connection "db1".  The second command causes this
32575897234Sdrh ** subroutine to be invoked.
32675897234Sdrh */
3276d31316cSdrh static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
328bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)cd;
3296d31316cSdrh   int choice;
3300de8c112Sdrh   static const char *DB_strs[] = {
331411995dcSdrh     "busy",               "changes",           "close",
332*dcd997eaSdrh     "complete",           "errorcode",         "eval",
333*dcd997eaSdrh     "function",           "last_insert_rowid", "open_aux_file",
334*dcd997eaSdrh     "timeout",            0
3356d31316cSdrh   };
336411995dcSdrh   enum DB_enum {
337411995dcSdrh     DB_BUSY,              DB_CHANGES,          DB_CLOSE,
338*dcd997eaSdrh     DB_COMPLETE,          DB_ERRORCODE,        DB_EVAL,
339*dcd997eaSdrh     DB_FUNCTION,          DB_LAST_INSERT_ROWID,DB_OPEN_AUX_FILE,
340*dcd997eaSdrh     DB_TIMEOUT,
3416d31316cSdrh   };
3426d31316cSdrh 
3436d31316cSdrh   if( objc<2 ){
3446d31316cSdrh     Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
34575897234Sdrh     return TCL_ERROR;
34675897234Sdrh   }
347411995dcSdrh   if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
3486d31316cSdrh     return TCL_ERROR;
3496d31316cSdrh   }
3506d31316cSdrh 
351411995dcSdrh   switch( (enum DB_enum)choice ){
35275897234Sdrh 
353bec3f402Sdrh   /*    $db busy ?CALLBACK?
354bec3f402Sdrh   **
355bec3f402Sdrh   ** Invoke the given callback if an SQL statement attempts to open
356bec3f402Sdrh   ** a locked database file.
357bec3f402Sdrh   */
3586d31316cSdrh   case DB_BUSY: {
3596d31316cSdrh     if( objc>3 ){
3606d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK");
361bec3f402Sdrh       return TCL_ERROR;
3626d31316cSdrh     }else if( objc==2 ){
363bec3f402Sdrh       if( pDb->zBusy ){
364bec3f402Sdrh         Tcl_AppendResult(interp, pDb->zBusy, 0);
365bec3f402Sdrh       }
366bec3f402Sdrh     }else{
3676d31316cSdrh       char *zBusy;
3686d31316cSdrh       int len;
369bec3f402Sdrh       if( pDb->zBusy ){
370bec3f402Sdrh         Tcl_Free(pDb->zBusy);
3716d31316cSdrh       }
3726d31316cSdrh       zBusy = Tcl_GetStringFromObj(objv[2], &len);
3736d31316cSdrh       if( zBusy && len>0 ){
3746d31316cSdrh         pDb->zBusy = Tcl_Alloc( len + 1 );
3756d31316cSdrh         strcpy(pDb->zBusy, zBusy);
3766d31316cSdrh       }else{
377bec3f402Sdrh         pDb->zBusy = 0;
378bec3f402Sdrh       }
379bec3f402Sdrh       if( pDb->zBusy ){
380bec3f402Sdrh         pDb->interp = interp;
381bec3f402Sdrh         sqlite_busy_handler(pDb->db, DbBusyHandler, pDb);
3826d31316cSdrh       }else{
3836d31316cSdrh         sqlite_busy_handler(pDb->db, 0, 0);
384bec3f402Sdrh       }
385bec3f402Sdrh     }
3866d31316cSdrh     break;
3876d31316cSdrh   }
388bec3f402Sdrh 
389c8d30ac1Sdrh   /*
390c8d30ac1Sdrh   **     $db changes
391c8d30ac1Sdrh   **
392c8d30ac1Sdrh   ** Return the number of rows that were modified, inserted, or deleted by
393c8d30ac1Sdrh   ** the most recent "eval".
394c8d30ac1Sdrh   */
395c8d30ac1Sdrh   case DB_CHANGES: {
396c8d30ac1Sdrh     Tcl_Obj *pResult;
397c8d30ac1Sdrh     int nChange;
398c8d30ac1Sdrh     if( objc!=2 ){
399c8d30ac1Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "");
400c8d30ac1Sdrh       return TCL_ERROR;
401c8d30ac1Sdrh     }
402c8d30ac1Sdrh     nChange = sqlite_changes(pDb->db);
403c8d30ac1Sdrh     pResult = Tcl_GetObjResult(interp);
404c8d30ac1Sdrh     Tcl_SetIntObj(pResult, nChange);
405c8d30ac1Sdrh     break;
406c8d30ac1Sdrh   }
407c8d30ac1Sdrh 
40875897234Sdrh   /*    $db close
40975897234Sdrh   **
41075897234Sdrh   ** Shutdown the database
41175897234Sdrh   */
4126d31316cSdrh   case DB_CLOSE: {
4136d31316cSdrh     Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
4146d31316cSdrh     break;
4156d31316cSdrh   }
41675897234Sdrh 
41775897234Sdrh   /*    $db complete SQL
41875897234Sdrh   **
41975897234Sdrh   ** Return TRUE if SQL is a complete SQL statement.  Return FALSE if
42075897234Sdrh   ** additional lines of input are needed.  This is similar to the
42175897234Sdrh   ** built-in "info complete" command of Tcl.
42275897234Sdrh   */
4236d31316cSdrh   case DB_COMPLETE: {
4246d31316cSdrh     Tcl_Obj *pResult;
4256d31316cSdrh     int isComplete;
4266d31316cSdrh     if( objc!=3 ){
4276d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL");
42875897234Sdrh       return TCL_ERROR;
42975897234Sdrh     }
4306d31316cSdrh     isComplete = sqlite_complete( Tcl_GetStringFromObj(objv[2], 0) );
4316d31316cSdrh     pResult = Tcl_GetObjResult(interp);
4326d31316cSdrh     Tcl_SetBooleanObj(pResult, isComplete);
4336d31316cSdrh     break;
4346d31316cSdrh   }
43575897234Sdrh 
43675897234Sdrh   /*
437*dcd997eaSdrh   **    $db errorcode
438*dcd997eaSdrh   **
439*dcd997eaSdrh   ** Return the numeric error code that was returned by the most recent
440*dcd997eaSdrh   ** call to sqlite_exec().
441*dcd997eaSdrh   */
442*dcd997eaSdrh   case DB_ERRORCODE: {
443*dcd997eaSdrh     Tcl_SetObjResult(interp, Tcl_NewIntObj(pDb->rc));
444*dcd997eaSdrh     break;
445*dcd997eaSdrh   }
446*dcd997eaSdrh 
447*dcd997eaSdrh   /*
44875897234Sdrh   **    $db eval $sql ?array {  ...code... }?
44975897234Sdrh   **
45075897234Sdrh   ** The SQL statement in $sql is evaluated.  For each row, the values are
451bec3f402Sdrh   ** placed in elements of the array named "array" and ...code... is executed.
45275897234Sdrh   ** If "array" and "code" are omitted, then no callback is every invoked.
45375897234Sdrh   ** If "array" is an empty string, then the values are placed in variables
45475897234Sdrh   ** that have the same name as the fields extracted by the query.
45575897234Sdrh   */
4566d31316cSdrh   case DB_EVAL: {
45775897234Sdrh     CallbackData cbData;
45875897234Sdrh     char *zErrMsg;
4596d31316cSdrh     char *zSql;
46075897234Sdrh     int rc;
461297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
462297ecf14Sdrh     Tcl_DString dSql;
4636d4abfbeSdrh     int i;
464297ecf14Sdrh #endif
46575897234Sdrh 
4666d31316cSdrh     if( objc!=5 && objc!=3 ){
4676d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME CODE?");
46875897234Sdrh       return TCL_ERROR;
46975897234Sdrh     }
470bec3f402Sdrh     pDb->interp = interp;
4716d31316cSdrh     zSql = Tcl_GetStringFromObj(objv[2], 0);
472297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
473297ecf14Sdrh     Tcl_DStringInit(&dSql);
474297ecf14Sdrh     Tcl_UtfToExternalDString(NULL, zSql, -1, &dSql);
475297ecf14Sdrh     zSql = Tcl_DStringValue(&dSql);
476297ecf14Sdrh #endif
4776d31316cSdrh     Tcl_IncrRefCount(objv[2]);
4786d31316cSdrh     if( objc==5 ){
47975897234Sdrh       cbData.interp = interp;
480dcc581ccSdrh       cbData.once = 1;
4816d31316cSdrh       cbData.zArray = Tcl_GetStringFromObj(objv[3], 0);
4826d31316cSdrh       cbData.pCode = objv[4];
483960e8c63Sdrh       cbData.tcl_rc = TCL_OK;
4846d4abfbeSdrh       cbData.nColName = 0;
4856d4abfbeSdrh       cbData.azColName = 0;
48675897234Sdrh       zErrMsg = 0;
4876d31316cSdrh       Tcl_IncrRefCount(objv[3]);
4886d31316cSdrh       Tcl_IncrRefCount(objv[4]);
4896d31316cSdrh       rc = sqlite_exec(pDb->db, zSql, DbEvalCallback, &cbData, &zErrMsg);
4906d31316cSdrh       Tcl_DecrRefCount(objv[4]);
4916d31316cSdrh       Tcl_DecrRefCount(objv[3]);
492960e8c63Sdrh       if( cbData.tcl_rc==TCL_BREAK ){ cbData.tcl_rc = TCL_OK; }
49375897234Sdrh     }else{
4946d31316cSdrh       Tcl_Obj *pList = Tcl_NewObj();
495960e8c63Sdrh       cbData.tcl_rc = TCL_OK;
4966d31316cSdrh       rc = sqlite_exec(pDb->db, zSql, DbEvalCallback2, pList, &zErrMsg);
4976d31316cSdrh       Tcl_SetObjResult(interp, pList);
49875897234Sdrh     }
499*dcd997eaSdrh     pDb->rc = rc;
500b798fa64Sdrh     if( rc==SQLITE_ABORT ){
501b798fa64Sdrh       if( zErrMsg ) free(zErrMsg);
502b798fa64Sdrh       rc = cbData.tcl_rc;
503b798fa64Sdrh     }else if( zErrMsg ){
50475897234Sdrh       Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
50575897234Sdrh       free(zErrMsg);
506960e8c63Sdrh       rc = TCL_ERROR;
507b798fa64Sdrh     }else if( rc!=SQLITE_OK ){
5086d4abfbeSdrh       Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
5096d4abfbeSdrh       rc = TCL_ERROR;
510960e8c63Sdrh     }else{
51175897234Sdrh     }
5126d31316cSdrh     Tcl_DecrRefCount(objv[2]);
513297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
514297ecf14Sdrh     Tcl_DStringFree(&dSql);
5156d4abfbeSdrh     if( objc==5 && cbData.azColName ){
5166d4abfbeSdrh       for(i=0; i<cbData.nColName; i++){
5176d4abfbeSdrh         if( cbData.azColName[i] ) free(cbData.azColName[i]);
5186d4abfbeSdrh       }
5196d4abfbeSdrh       free(cbData.azColName);
520ce927065Sdrh       cbData.azColName = 0;
5216d4abfbeSdrh     }
522297ecf14Sdrh #endif
52375897234Sdrh     return rc;
5246d31316cSdrh   }
525bec3f402Sdrh 
526bec3f402Sdrh   /*
527cabb0819Sdrh   **     $db function NAME SCRIPT
528cabb0819Sdrh   **
529cabb0819Sdrh   ** Create a new SQL function called NAME.  Whenever that function is
530cabb0819Sdrh   ** called, invoke SCRIPT to evaluate the function.
531cabb0819Sdrh   */
532cabb0819Sdrh   case DB_FUNCTION: {
533cabb0819Sdrh     SqlFunc *pFunc;
534cabb0819Sdrh     char *zName;
535cabb0819Sdrh     char *zScript;
536cabb0819Sdrh     int nScript;
537cabb0819Sdrh     if( objc!=4 ){
538cabb0819Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
539cabb0819Sdrh       return TCL_ERROR;
540cabb0819Sdrh     }
541cabb0819Sdrh     zName = Tcl_GetStringFromObj(objv[2], 0);
542cabb0819Sdrh     zScript = Tcl_GetStringFromObj(objv[3], &nScript);
543cabb0819Sdrh     pFunc = (SqlFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript + 1 );
544cabb0819Sdrh     if( pFunc==0 ) return TCL_ERROR;
545cabb0819Sdrh     pFunc->interp = interp;
546cabb0819Sdrh     pFunc->pNext = pDb->pFunc;
547cabb0819Sdrh     pFunc->zScript = (char*)&pFunc[1];
548cabb0819Sdrh     strcpy(pFunc->zScript, zScript);
549cabb0819Sdrh     sqlite_create_function(pDb->db, zName, -1, tclSqlFunc, pFunc);
550cabb0819Sdrh     sqlite_function_type(pDb->db, zName, SQLITE_NUMERIC);
551cabb0819Sdrh     break;
552cabb0819Sdrh   }
553cabb0819Sdrh 
554cabb0819Sdrh   /*
555af9ff33aSdrh   **     $db last_insert_rowid
556af9ff33aSdrh   **
557af9ff33aSdrh   ** Return an integer which is the ROWID for the most recent insert.
558af9ff33aSdrh   */
559af9ff33aSdrh   case DB_LAST_INSERT_ROWID: {
560af9ff33aSdrh     Tcl_Obj *pResult;
561af9ff33aSdrh     int rowid;
562af9ff33aSdrh     if( objc!=2 ){
563af9ff33aSdrh       Tcl_WrongNumArgs(interp, 2, objv, "");
564af9ff33aSdrh       return TCL_ERROR;
565af9ff33aSdrh     }
566af9ff33aSdrh     rowid = sqlite_last_insert_rowid(pDb->db);
567af9ff33aSdrh     pResult = Tcl_GetObjResult(interp);
568af9ff33aSdrh     Tcl_SetIntObj(pResult, rowid);
569af9ff33aSdrh     break;
570af9ff33aSdrh   }
571af9ff33aSdrh 
572af9ff33aSdrh   /*
573411995dcSdrh   **     $db open_aux_file  FILENAME
574411995dcSdrh   **
575411995dcSdrh   ** Begin using FILENAME as the database file used to store temporary
576411995dcSdrh   ** tables.
577411995dcSdrh   */
578411995dcSdrh   case DB_OPEN_AUX_FILE: {
579411995dcSdrh     const char *zFilename;
580411995dcSdrh     char *zErrMsg = 0;
581411995dcSdrh     int rc;
582411995dcSdrh     if( objc!=3 ){
583411995dcSdrh       Tcl_WrongNumArgs(interp, 2, objv, "FILENAME");
584411995dcSdrh       return TCL_ERROR;
585411995dcSdrh     }
586411995dcSdrh     zFilename = Tcl_GetStringFromObj(objv[2], 0);
587411995dcSdrh     rc = sqlite_open_aux_file(pDb->db, zFilename, &zErrMsg);
588*dcd997eaSdrh     pDb->rc = rc;
589411995dcSdrh     if( rc!=0 ){
590411995dcSdrh       if( zErrMsg ){
591411995dcSdrh         Tcl_AppendResult(interp, zErrMsg, 0);
592411995dcSdrh         free(zErrMsg);
593411995dcSdrh       }else{
594411995dcSdrh         Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
595411995dcSdrh       }
596411995dcSdrh       return TCL_ERROR;
597411995dcSdrh     }
598411995dcSdrh     break;
599411995dcSdrh   }
600411995dcSdrh 
601411995dcSdrh   /*
602bec3f402Sdrh   **     $db timeout MILLESECONDS
603bec3f402Sdrh   **
604bec3f402Sdrh   ** Delay for the number of milliseconds specified when a file is locked.
605bec3f402Sdrh   */
6066d31316cSdrh   case DB_TIMEOUT: {
607bec3f402Sdrh     int ms;
6086d31316cSdrh     if( objc!=3 ){
6096d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS");
610bec3f402Sdrh       return TCL_ERROR;
61175897234Sdrh     }
6126d31316cSdrh     if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR;
613bec3f402Sdrh     sqlite_busy_timeout(pDb->db, ms);
6146d31316cSdrh     break;
61575897234Sdrh   }
6166d31316cSdrh   } /* End of the SWITCH statement */
61775897234Sdrh   return TCL_OK;
61875897234Sdrh }
61975897234Sdrh 
62075897234Sdrh /*
62175897234Sdrh **   sqlite DBNAME FILENAME ?MODE?
62275897234Sdrh **
62375897234Sdrh ** This is the main Tcl command.  When the "sqlite" Tcl command is
62475897234Sdrh ** invoked, this routine runs to process that command.
62575897234Sdrh **
62675897234Sdrh ** The first argument, DBNAME, is an arbitrary name for a new
62775897234Sdrh ** database connection.  This command creates a new command named
62875897234Sdrh ** DBNAME that is used to control that connection.  The database
62975897234Sdrh ** connection is deleted when the DBNAME command is deleted.
63075897234Sdrh **
63175897234Sdrh ** The second argument is the name of the directory that contains
63275897234Sdrh ** the sqlite database that is to be accessed.
633fbc3eab8Sdrh **
634fbc3eab8Sdrh ** For testing purposes, we also support the following:
635fbc3eab8Sdrh **
636fbc3eab8Sdrh **  sqlite -encoding
637fbc3eab8Sdrh **
638fbc3eab8Sdrh **       Return the encoding used by LIKE and GLOB operators.  Choices
639fbc3eab8Sdrh **       are UTF-8 and iso8859.
640fbc3eab8Sdrh **
641647cb0e1Sdrh **  sqlite -version
642647cb0e1Sdrh **
643647cb0e1Sdrh **       Return the version number of the SQLite library.
644647cb0e1Sdrh **
645fbc3eab8Sdrh **  sqlite -tcl-uses-utf
646fbc3eab8Sdrh **
647fbc3eab8Sdrh **       Return "1" if compiled with a Tcl uses UTF-8.  Return "0" if
648fbc3eab8Sdrh **       not.  Used by tests to make sure the library was compiled
649fbc3eab8Sdrh **       correctly.
65075897234Sdrh */
65175897234Sdrh static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
65275897234Sdrh   int mode;
653bec3f402Sdrh   SqliteDb *p;
65475897234Sdrh   char *zErrMsg;
65506b2718aSdrh   char zBuf[80];
656fbc3eab8Sdrh   if( argc==2 ){
657fbc3eab8Sdrh     if( strcmp(argv[1],"-encoding")==0 ){
658fbc3eab8Sdrh       Tcl_AppendResult(interp,sqlite_encoding,0);
659fbc3eab8Sdrh       return TCL_OK;
660fbc3eab8Sdrh     }
661647cb0e1Sdrh     if( strcmp(argv[1],"-version")==0 ){
662647cb0e1Sdrh       Tcl_AppendResult(interp,sqlite_version,0);
663647cb0e1Sdrh       return TCL_OK;
664647cb0e1Sdrh     }
665fbc3eab8Sdrh     if( strcmp(argv[1],"-tcl-uses-utf")==0 ){
666fbc3eab8Sdrh #ifdef TCL_UTF_MAX
667fbc3eab8Sdrh       Tcl_AppendResult(interp,"1",0);
668fbc3eab8Sdrh #else
669fbc3eab8Sdrh       Tcl_AppendResult(interp,"0",0);
670fbc3eab8Sdrh #endif
671fbc3eab8Sdrh       return TCL_OK;
672fbc3eab8Sdrh     }
673fbc3eab8Sdrh   }
67475897234Sdrh   if( argc!=3 && argc!=4 ){
67575897234Sdrh     Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
67675897234Sdrh        " HANDLE FILENAME ?MODE?\"", 0);
67775897234Sdrh     return TCL_ERROR;
67875897234Sdrh   }
67975897234Sdrh   if( argc==3 ){
68058b9576bSdrh     mode = 0666;
68175897234Sdrh   }else if( Tcl_GetInt(interp, argv[3], &mode)!=TCL_OK ){
68275897234Sdrh     return TCL_ERROR;
68375897234Sdrh   }
68475897234Sdrh   zErrMsg = 0;
6854cdc9e84Sdrh   p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
68675897234Sdrh   if( p==0 ){
687bec3f402Sdrh     Tcl_SetResult(interp, "malloc failed", TCL_STATIC);
688bec3f402Sdrh     return TCL_ERROR;
689bec3f402Sdrh   }
690bec3f402Sdrh   memset(p, 0, sizeof(*p));
691bec3f402Sdrh   p->db = sqlite_open(argv[2], mode, &zErrMsg);
692bec3f402Sdrh   if( p->db==0 ){
69375897234Sdrh     Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
694bec3f402Sdrh     Tcl_Free((char*)p);
69575897234Sdrh     free(zErrMsg);
69675897234Sdrh     return TCL_ERROR;
69775897234Sdrh   }
6986d31316cSdrh   Tcl_CreateObjCommand(interp, argv[1], DbObjCmd, (char*)p, DbDeleteCmd);
699c22bd47dSdrh 
70006b2718aSdrh   /* The return value is the value of the sqlite* pointer
70106b2718aSdrh   */
70206b2718aSdrh   sprintf(zBuf, "%p", p->db);
7035e5377fbSdrh   if( strncmp(zBuf,"0x",2) ){
7045e5377fbSdrh     sprintf(zBuf, "0x%p", p->db);
7055e5377fbSdrh   }
70606b2718aSdrh   Tcl_AppendResult(interp, zBuf, 0);
70706b2718aSdrh 
708c22bd47dSdrh   /* If compiled with SQLITE_TEST turned on, then register the "md5sum"
70906b2718aSdrh   ** SQL function.
710c22bd47dSdrh   */
71128b4e489Sdrh #ifdef SQLITE_TEST
71228b4e489Sdrh   {
71328b4e489Sdrh     extern void Md5_Register(sqlite*);
71428b4e489Sdrh     Md5_Register(p->db);
71528b4e489Sdrh    }
71628b4e489Sdrh #endif
71775897234Sdrh   return TCL_OK;
71875897234Sdrh }
71975897234Sdrh 
72075897234Sdrh /*
72190ca9753Sdrh ** Provide a dummy Tcl_InitStubs if we are using this as a static
72290ca9753Sdrh ** library.
72390ca9753Sdrh */
72490ca9753Sdrh #ifndef USE_TCL_STUBS
72590ca9753Sdrh # undef  Tcl_InitStubs
72690ca9753Sdrh # define Tcl_InitStubs(a,b,c)
72790ca9753Sdrh #endif
72890ca9753Sdrh 
72990ca9753Sdrh /*
73075897234Sdrh ** Initialize this module.
73175897234Sdrh **
73275897234Sdrh ** This Tcl module contains only a single new Tcl command named "sqlite".
73375897234Sdrh ** (Hence there is no namespace.  There is no point in using a namespace
73475897234Sdrh ** if the extension only supplies one new name!)  The "sqlite" command is
73575897234Sdrh ** used to open a new SQLite database.  See the DbMain() routine above
73675897234Sdrh ** for additional information.
73775897234Sdrh */
73875897234Sdrh int Sqlite_Init(Tcl_Interp *interp){
73990ca9753Sdrh   Tcl_InitStubs(interp, "8.0", 0);
740c2eef3b3Sdrh   Tcl_CreateCommand(interp, "sqlite", (Tcl_CmdProc*)DbMain, 0, 0);
7416d4abfbeSdrh   Tcl_PkgProvide(interp, "sqlite", "2.0");
74290ca9753Sdrh   return TCL_OK;
74390ca9753Sdrh }
74490ca9753Sdrh int Tclsqlite_Init(Tcl_Interp *interp){
74590ca9753Sdrh   Tcl_InitStubs(interp, "8.0", 0);
746c2eef3b3Sdrh   Tcl_CreateCommand(interp, "sqlite", (Tcl_CmdProc*)DbMain, 0, 0);
7476d4abfbeSdrh   Tcl_PkgProvide(interp, "sqlite", "2.0");
74875897234Sdrh   return TCL_OK;
74975897234Sdrh }
75075897234Sdrh int Sqlite_SafeInit(Tcl_Interp *interp){
75175897234Sdrh   return TCL_OK;
75275897234Sdrh }
75390ca9753Sdrh int Tclsqlite_SafeInit(Tcl_Interp *interp){
75490ca9753Sdrh   return TCL_OK;
75590ca9753Sdrh }
75675897234Sdrh 
7573cebbde3Sdrh #if 0
75875897234Sdrh /*
75975897234Sdrh ** If compiled using mktclapp, this routine runs to initialize
76075897234Sdrh ** everything.
76175897234Sdrh */
76275897234Sdrh int Et_AppInit(Tcl_Interp *interp){
76375897234Sdrh   return Sqlite_Init(interp);
76475897234Sdrh }
7653cebbde3Sdrh #endif
766348784efSdrh 
767348784efSdrh /*
768348784efSdrh ** If the macro TCLSH is defined and is one, then put in code for the
769348784efSdrh ** "main" routine that will initialize Tcl.
770348784efSdrh */
771348784efSdrh #if defined(TCLSH) && TCLSH==1
772348784efSdrh static char zMainloop[] =
773348784efSdrh   "set line {}\n"
774348784efSdrh   "while {![eof stdin]} {\n"
775348784efSdrh     "if {$line!=\"\"} {\n"
776348784efSdrh       "puts -nonewline \"> \"\n"
777348784efSdrh     "} else {\n"
778348784efSdrh       "puts -nonewline \"% \"\n"
779348784efSdrh     "}\n"
780348784efSdrh     "flush stdout\n"
781348784efSdrh     "append line [gets stdin]\n"
782348784efSdrh     "if {[info complete $line]} {\n"
783348784efSdrh       "if {[catch {uplevel #0 $line} result]} {\n"
784348784efSdrh         "puts stderr \"Error: $result\"\n"
785348784efSdrh       "} elseif {$result!=\"\"} {\n"
786348784efSdrh         "puts $result\n"
787348784efSdrh       "}\n"
788348784efSdrh       "set line {}\n"
789348784efSdrh     "} else {\n"
790348784efSdrh       "append line \\n\n"
791348784efSdrh     "}\n"
792348784efSdrh   "}\n"
793348784efSdrh ;
794348784efSdrh 
795348784efSdrh #define TCLSH_MAIN main   /* Needed to fake out mktclapp */
796348784efSdrh int TCLSH_MAIN(int argc, char **argv){
797348784efSdrh   Tcl_Interp *interp;
798297ecf14Sdrh   Tcl_FindExecutable(argv[0]);
799348784efSdrh   interp = Tcl_CreateInterp();
800348784efSdrh   Sqlite_Init(interp);
801d9b0257aSdrh #ifdef SQLITE_TEST
802d1bf3512Sdrh   {
803d1bf3512Sdrh     extern int Sqlitetest1_Init(Tcl_Interp*);
8045c4d9703Sdrh     extern int Sqlitetest2_Init(Tcl_Interp*);
8055c4d9703Sdrh     extern int Sqlitetest3_Init(Tcl_Interp*);
806efc251daSdrh     extern int Md5_Init(Tcl_Interp*);
807d1bf3512Sdrh     Sqlitetest1_Init(interp);
8085c4d9703Sdrh     Sqlitetest2_Init(interp);
8095c4d9703Sdrh     Sqlitetest3_Init(interp);
810efc251daSdrh     Md5_Init(interp);
811d1bf3512Sdrh   }
812d1bf3512Sdrh #endif
813348784efSdrh   if( argc>=2 ){
814348784efSdrh     int i;
815348784efSdrh     Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
816348784efSdrh     Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
817348784efSdrh     for(i=2; i<argc; i++){
818348784efSdrh       Tcl_SetVar(interp, "argv", argv[i],
819348784efSdrh           TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
820348784efSdrh     }
821348784efSdrh     if( Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
8220de8c112Sdrh       const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
823c61053b7Sdrh       if( zInfo==0 ) zInfo = interp->result;
824c61053b7Sdrh       fprintf(stderr,"%s: %s\n", *argv, zInfo);
825348784efSdrh       return 1;
826348784efSdrh     }
827348784efSdrh   }else{
828348784efSdrh     Tcl_GlobalEval(interp, zMainloop);
829348784efSdrh   }
830348784efSdrh   return 0;
831348784efSdrh }
832348784efSdrh #endif /* TCLSH */
8336d31316cSdrh 
8346d31316cSdrh #endif /* !defined(NO_TCL) */
835