Fossil SCM

Experimental changes to TH1 to try to make it resistant to coding errors that could lead to XSS or SQL injection attacks.

drh 2025-04-19 16:55 trunk
Commit b0b44924805848eca49b320d35251c074eee90c42c10f2fd7a352d4044a7fd0b
5 files changed +87 -42 +53 -14 +68 -47 +51 -30 +16 -16
+87 -42
--- src/th.c
+++ src/th.c
@@ -7,10 +7,16 @@
77
#include "config.h"
88
#include "th.h"
99
#include <string.h>
1010
#include <assert.h>
1111
12
+/*
13
+** External routines
14
+*/
15
+void fossil_panic(const char*,...);
16
+void fossil_errorlog(const char*,...);
17
+
1218
/*
1319
** Values used for element values in the tcl_platform array.
1420
*/
1521
1622
#if !defined(TH_ENGINE)
@@ -197,10 +203,11 @@
197203
*/
198204
struct Buffer {
199205
char *zBuf;
200206
int nBuf;
201207
int nBufAlloc;
208
+ int bTaint;
202209
};
203210
typedef struct Buffer Buffer;
204211
static void thBufferInit(Buffer *);
205212
static void thBufferFree(Th_Interp *interp, Buffer *);
206213
@@ -209,10 +216,18 @@
209216
** be NULL as long as the number of bytes to copy is zero.
210217
*/
211218
static void th_memcpy(void *dest, const void *src, size_t n){
212219
if( n>0 ) memcpy(dest,src,n);
213220
}
221
+
222
+/*
223
+** An oversized string has been encountered. Do not try to recover.
224
+** Panic the process.
225
+*/
226
+void Th_OversizeString(void){
227
+ fossil_panic("string too large. maximum size 286MB.");
228
+}
214229
215230
/*
216231
** Append nAdd bytes of content copied from zAdd to the end of buffer
217232
** pBuffer. If there is not enough space currently allocated, resize
218233
** the allocation to make space.
@@ -219,40 +234,46 @@
219234
*/
220235
static void thBufferWriteResize(
221236
Th_Interp *interp,
222237
Buffer *pBuffer,
223238
const char *zAdd,
224
- int nAdd
239
+ int nAddX
225240
){
241
+ int nAdd = TH1_LEN(nAddX);
226242
int nNew = (pBuffer->nBuf+nAdd)*2+32;
227243
#if defined(TH_MEMDEBUG)
228244
char *zNew = (char *)Th_Malloc(interp, nNew);
245
+ TH1_SIZECHECK(nNew);
229246
th_memcpy(zNew, pBuffer->zBuf, pBuffer->nBuf);
230247
Th_Free(interp, pBuffer->zBuf);
231248
pBuffer->zBuf = zNew;
232249
#else
233250
int nOld = pBuffer->nBufAlloc;
251
+ TH1_SIZECHECK(nNew);
234252
pBuffer->zBuf = Th_Realloc(interp, pBuffer->zBuf, nNew);
235253
memset(pBuffer->zBuf+nOld, 0, nNew-nOld);
236254
#endif
237255
pBuffer->nBufAlloc = nNew;
238256
th_memcpy(&pBuffer->zBuf[pBuffer->nBuf], zAdd, nAdd);
239257
pBuffer->nBuf += nAdd;
258
+ TH1_XFER_TAINT(pBuffer->bTaint, nAddX);
240259
}
241260
static void thBufferWriteFast(
242261
Th_Interp *interp,
243262
Buffer *pBuffer,
244263
const char *zAdd,
245
- int nAdd
264
+ int nAddX
246265
){
266
+ int nAdd = TH1_LEN(nAddX);
247267
if( pBuffer->nBuf+nAdd > pBuffer->nBufAlloc ){
248
- thBufferWriteResize(interp, pBuffer, zAdd, nAdd);
268
+ thBufferWriteResize(interp, pBuffer, zAdd, nAddX);
249269
}else{
250270
if( pBuffer->zBuf ){
251271
memcpy(pBuffer->zBuf + pBuffer->nBuf, zAdd, nAdd);
252272
}
253273
pBuffer->nBuf += nAdd;
274
+ TH1_XFER_TAINT(pBuffer->bTaint, nAddX);
254275
}
255276
}
256277
#define thBufferWrite(a,b,c,d) thBufferWriteFast(a,b,(const char *)c,d)
257278
258279
/*
@@ -704,24 +725,25 @@
704725
int nWord
705726
){
706727
int rc = TH_OK;
707728
Buffer output;
708729
int i;
730
+ int nn = TH1_LEN(nWord);
709731
710732
thBufferInit(&output);
711733
712
- if( nWord>1 && (zWord[0]=='{' && zWord[nWord-1]=='}') ){
713
- thBufferWrite(interp, &output, &zWord[1], nWord-2);
734
+ if( nn>1 && (zWord[0]=='{' && zWord[nn-1]=='}') ){
735
+ thBufferWrite(interp, &output, &zWord[1], nn-2);
714736
}else{
715737
716738
/* If the word is surrounded by double-quotes strip these away. */
717
- if( nWord>1 && (zWord[0]=='"' && zWord[nWord-1]=='"') ){
739
+ if( nn>1 && (zWord[0]=='"' && zWord[nn-1]=='"') ){
718740
zWord++;
719
- nWord -= 2;
741
+ nn -= 2;
720742
}
721743
722
- for(i=0; rc==TH_OK && i<nWord; i++){
744
+ for(i=0; rc==TH_OK && i<nn; i++){
723745
int nGet;
724746
725747
int (*xGet)(Th_Interp *, const char*, int, int *) = 0;
726748
int (*xSubst)(Th_Interp *, const char*, int) = 0;
727749
@@ -743,11 +765,11 @@
743765
thBufferAddChar(interp, &output, zWord[i]);
744766
continue; /* Go to the next iteration of the for(...) loop */
745767
}
746768
}
747769
748
- rc = xGet(interp, &zWord[i], nWord-i, &nGet);
770
+ rc = xGet(interp, &zWord[i], nn-i, &nGet);
749771
if( rc==TH_OK ){
750772
rc = xSubst(interp, &zWord[i], nGet);
751773
}
752774
if( rc==TH_OK ){
753775
const char *zRes;
@@ -826,11 +848,11 @@
826848
Buffer strbuf;
827849
Buffer lenbuf;
828850
int nCount = 0;
829851
830852
const char *zInput = zList;
831
- int nInput = nList;
853
+ int nInput = TH1_LEN(nList);
832854
833855
thBufferInit(&strbuf);
834856
thBufferInit(&lenbuf);
835857
836858
while( nInput>0 ){
@@ -886,10 +908,34 @@
886908
finish:
887909
thBufferFree(interp, &strbuf);
888910
thBufferFree(interp, &lenbuf);
889911
return rc;
890912
}
913
+
914
+/*
915
+** Report misuse of a tainted string.
916
+**
917
+** In the current implementation, this routine issues a warning to the
918
+** error log and returns 0, causing processing to continue. This is so
919
+** that the new taint detection will not disrupt legacy configurations.
920
+** However, if modified so that this routine returns non-zero, then it
921
+** will cause an error in the script.
922
+*/
923
+int Th_ReportTaint(
924
+ Th_Interp *interp, /* Report error here, if an error is reported */
925
+ const char *zWhere, /* Where the tainted string appears */
926
+ const char *zStr, /* The tainted string */
927
+ int nStr /* Length of the tainted string */
928
+){
929
+ nStr = TH1_LEN(nStr);
930
+ if( nStr>0 ){
931
+ fossil_errorlog("warning: tainted %s: \"%.s\"", zWhere, nStr, zStr);
932
+ }else{
933
+ fossil_errorlog("warning: tainted %s", zWhere);
934
+ }
935
+ return 0;
936
+}
891937
892938
/*
893939
** Evaluate the th1 script contained in the string (zProgram, nProgram)
894940
** in the current stack frame.
895941
*/
@@ -896,10 +942,15 @@
896942
static int thEvalLocal(Th_Interp *interp, const char *zProgram, int nProgram){
897943
int rc = TH_OK;
898944
const char *zInput = zProgram;
899945
int nInput = nProgram;
900946
947
+ if( TH1_TAINTED(nProgram)
948
+ && Th_ReportTaint(interp, "script", zProgram, nProgram)
949
+ ){
950
+ return TH_ERROR;
951
+ }
901952
while( rc==TH_OK && nInput ){
902953
Th_HashEntry *pEntry;
903954
int nSpace;
904955
const char *zFirst;
905956
@@ -949,13 +1000,13 @@
9491000
if( rc!=TH_OK ) continue;
9501001
9511002
if( argc>0 ){
9521003
9531004
/* Look up the command name in the command hash-table. */
954
- pEntry = Th_HashFind(interp, interp->paCmd, argv[0], argl[0], 0);
1005
+ pEntry = Th_HashFind(interp, interp->paCmd, argv[0], TH1_LEN(argl[0]),0);
9551006
if( !pEntry ){
956
- Th_ErrorMessage(interp, "no such command: ", argv[0], argl[0]);
1007
+ Th_ErrorMessage(interp, "no such command: ", argv[0], TH1_LEN(argl[0]));
9571008
rc = TH_ERROR;
9581009
}
9591010
9601011
/* Call the command procedure. */
9611012
if( rc==TH_OK ){
@@ -1095,10 +1146,12 @@
10951146
int isGlobal = 0;
10961147
int i;
10971148
10981149
if( nVarname<0 ){
10991150
nVarname = th_strlen(zVarname);
1151
+ }else{
1152
+ nVarname = TH1_LEN(nVarname);
11001153
}
11011154
nOuter = nVarname;
11021155
11031156
/* If the variable name starts with "::", then do the lookup is in the
11041157
** uppermost (global) frame.
@@ -1271,31 +1324,10 @@
12711324
}
12721325
12731326
return Th_SetResult(interp, pValue->zData, pValue->nData);
12741327
}
12751328
1276
-/*
1277
-** If interp has a variable with the given name, its value is returned
1278
-** and its length is returned via *nOut if nOut is not NULL. If
1279
-** interp has no such var then NULL is returned without setting any
1280
-** error state and *nOut, if not NULL, is set to -1. The returned value
1281
-** is owned by the interpreter and may be invalidated the next time
1282
-** the interpreter is modified.
1283
-*/
1284
-const char * Th_MaybeGetVar(Th_Interp *interp, const char *zVarName,
1285
- int *nOut){
1286
- Th_Variable *pValue;
1287
-
1288
- pValue = thFindValue(interp, zVarName, -1, 0, 0, 1, 0);
1289
- if( !pValue || !pValue->zData ){
1290
- if( nOut!=0 ) *nOut = -1;
1291
- return NULL;
1292
- }
1293
- if( nOut!=0 ) *nOut = pValue->nData;
1294
- return pValue->zData;
1295
-}
1296
-
12971329
/*
12981330
** Return true if variable (zVar, nVar) exists.
12991331
*/
13001332
int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
13011333
Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
@@ -1324,28 +1356,32 @@
13241356
int nVar,
13251357
const char *zValue,
13261358
int nValue
13271359
){
13281360
Th_Variable *pValue;
1361
+ int nn;
13291362
1363
+ nVar = TH1_LEN(nVar);
13301364
pValue = thFindValue(interp, zVar, nVar, 1, 0, 0, 0);
13311365
if( !pValue ){
13321366
return TH_ERROR;
13331367
}
13341368
13351369
if( nValue<0 ){
1336
- nValue = th_strlen(zValue);
1370
+ nn = th_strlen(zValue);
1371
+ }else{
1372
+ nn = TH1_LEN(nValue);
13371373
}
13381374
if( pValue->zData ){
13391375
Th_Free(interp, pValue->zData);
13401376
pValue->zData = 0;
13411377
}
13421378
1343
- assert(zValue || nValue==0);
1344
- pValue->zData = Th_Malloc(interp, nValue+1);
1345
- pValue->zData[nValue] = '\0';
1346
- th_memcpy(pValue->zData, zValue, nValue);
1379
+ assert(zValue || nn==0);
1380
+ pValue->zData = Th_Malloc(interp, nn+1);
1381
+ pValue->zData[nn] = '\0';
1382
+ th_memcpy(pValue->zData, zValue, nn);
13471383
pValue->nData = nValue;
13481384
13491385
return TH_OK;
13501386
}
13511387
@@ -1458,10 +1494,12 @@
14581494
*/
14591495
char *th_strdup(Th_Interp *interp, const char *z, int n){
14601496
char *zRes;
14611497
if( n<0 ){
14621498
n = th_strlen(z);
1499
+ }else{
1500
+ n = TH1_LEN(n);
14631501
}
14641502
zRes = Th_Malloc(interp, n+1);
14651503
th_memcpy(zRes, z, n);
14661504
zRes[n] = '\0';
14671505
return zRes;
@@ -1519,13 +1557,14 @@
15191557
n = th_strlen(z);
15201558
}
15211559
15221560
if( z && n>0 ){
15231561
char *zResult;
1524
- zResult = Th_Malloc(pInterp, n+1);
1525
- th_memcpy(zResult, z, n);
1526
- zResult[n] = '\0';
1562
+ int nn = TH1_LEN(n);
1563
+ zResult = Th_Malloc(pInterp, nn+1);
1564
+ th_memcpy(zResult, z, nn);
1565
+ zResult[nn] = '\0';
15271566
pInterp->zResult = zResult;
15281567
pInterp->nResult = n;
15291568
}
15301569
15311570
return TH_OK;
@@ -2456,10 +2495,12 @@
24562495
int nToken = 0;
24572496
Expr **apToken = 0;
24582497
24592498
if( nExpr<0 ){
24602499
nExpr = th_strlen(zExpr);
2500
+ }else{
2501
+ nExpr = TH1_LEN(nExpr);
24612502
}
24622503
24632504
/* Parse the expression to a list of tokens. */
24642505
rc = exprParse(interp, zExpr, nExpr, &apToken, &nToken);
24652506
@@ -2567,10 +2608,12 @@
25672608
Th_HashEntry *pRet;
25682609
Th_HashEntry **ppRet;
25692610
25702611
if( nKey<0 ){
25712612
nKey = th_strlen(zKey);
2613
+ }else{
2614
+ nKey = TH1_LEN(nKey);
25722615
}
25732616
25742617
for(i=0; i<nKey; i++){
25752618
iKey = (iKey<<3) ^ iKey ^ zKey[i];
25762619
}
@@ -2800,10 +2843,12 @@
28002843
int base = 10;
28012844
int (*isdigit)(char) = th_isdigit;
28022845
28032846
if( n<0 ){
28042847
n = th_strlen(z);
2848
+ }else{
2849
+ n = TH1_LEN(n);
28052850
}
28062851
28072852
if( n>1 && (z[0]=='-' || z[0]=='+') ){
28082853
i = 1;
28092854
}
@@ -2859,11 +2904,11 @@
28592904
const char *z,
28602905
int n,
28612906
double *pfOut
28622907
){
28632908
if( !sqlite3IsNumber((const char *)z, 0) ){
2864
- Th_ErrorMessage(interp, "expected number, got: \"", z, n);
2909
+ Th_ErrorMessage(interp, "expected number, got: \"", z, TH1_LEN(n));
28652910
return TH_ERROR;
28662911
}
28672912
28682913
sqlite3AtoF((const char *)z, pfOut);
28692914
return TH_OK;
28702915
--- src/th.c
+++ src/th.c
@@ -7,10 +7,16 @@
7 #include "config.h"
8 #include "th.h"
9 #include <string.h>
10 #include <assert.h>
11
 
 
 
 
 
 
12 /*
13 ** Values used for element values in the tcl_platform array.
14 */
15
16 #if !defined(TH_ENGINE)
@@ -197,10 +203,11 @@
197 */
198 struct Buffer {
199 char *zBuf;
200 int nBuf;
201 int nBufAlloc;
 
202 };
203 typedef struct Buffer Buffer;
204 static void thBufferInit(Buffer *);
205 static void thBufferFree(Th_Interp *interp, Buffer *);
206
@@ -209,10 +216,18 @@
209 ** be NULL as long as the number of bytes to copy is zero.
210 */
211 static void th_memcpy(void *dest, const void *src, size_t n){
212 if( n>0 ) memcpy(dest,src,n);
213 }
 
 
 
 
 
 
 
 
214
215 /*
216 ** Append nAdd bytes of content copied from zAdd to the end of buffer
217 ** pBuffer. If there is not enough space currently allocated, resize
218 ** the allocation to make space.
@@ -219,40 +234,46 @@
219 */
220 static void thBufferWriteResize(
221 Th_Interp *interp,
222 Buffer *pBuffer,
223 const char *zAdd,
224 int nAdd
225 ){
 
226 int nNew = (pBuffer->nBuf+nAdd)*2+32;
227 #if defined(TH_MEMDEBUG)
228 char *zNew = (char *)Th_Malloc(interp, nNew);
 
229 th_memcpy(zNew, pBuffer->zBuf, pBuffer->nBuf);
230 Th_Free(interp, pBuffer->zBuf);
231 pBuffer->zBuf = zNew;
232 #else
233 int nOld = pBuffer->nBufAlloc;
 
234 pBuffer->zBuf = Th_Realloc(interp, pBuffer->zBuf, nNew);
235 memset(pBuffer->zBuf+nOld, 0, nNew-nOld);
236 #endif
237 pBuffer->nBufAlloc = nNew;
238 th_memcpy(&pBuffer->zBuf[pBuffer->nBuf], zAdd, nAdd);
239 pBuffer->nBuf += nAdd;
 
240 }
241 static void thBufferWriteFast(
242 Th_Interp *interp,
243 Buffer *pBuffer,
244 const char *zAdd,
245 int nAdd
246 ){
 
247 if( pBuffer->nBuf+nAdd > pBuffer->nBufAlloc ){
248 thBufferWriteResize(interp, pBuffer, zAdd, nAdd);
249 }else{
250 if( pBuffer->zBuf ){
251 memcpy(pBuffer->zBuf + pBuffer->nBuf, zAdd, nAdd);
252 }
253 pBuffer->nBuf += nAdd;
 
254 }
255 }
256 #define thBufferWrite(a,b,c,d) thBufferWriteFast(a,b,(const char *)c,d)
257
258 /*
@@ -704,24 +725,25 @@
704 int nWord
705 ){
706 int rc = TH_OK;
707 Buffer output;
708 int i;
 
709
710 thBufferInit(&output);
711
712 if( nWord>1 && (zWord[0]=='{' && zWord[nWord-1]=='}') ){
713 thBufferWrite(interp, &output, &zWord[1], nWord-2);
714 }else{
715
716 /* If the word is surrounded by double-quotes strip these away. */
717 if( nWord>1 && (zWord[0]=='"' && zWord[nWord-1]=='"') ){
718 zWord++;
719 nWord -= 2;
720 }
721
722 for(i=0; rc==TH_OK && i<nWord; i++){
723 int nGet;
724
725 int (*xGet)(Th_Interp *, const char*, int, int *) = 0;
726 int (*xSubst)(Th_Interp *, const char*, int) = 0;
727
@@ -743,11 +765,11 @@
743 thBufferAddChar(interp, &output, zWord[i]);
744 continue; /* Go to the next iteration of the for(...) loop */
745 }
746 }
747
748 rc = xGet(interp, &zWord[i], nWord-i, &nGet);
749 if( rc==TH_OK ){
750 rc = xSubst(interp, &zWord[i], nGet);
751 }
752 if( rc==TH_OK ){
753 const char *zRes;
@@ -826,11 +848,11 @@
826 Buffer strbuf;
827 Buffer lenbuf;
828 int nCount = 0;
829
830 const char *zInput = zList;
831 int nInput = nList;
832
833 thBufferInit(&strbuf);
834 thBufferInit(&lenbuf);
835
836 while( nInput>0 ){
@@ -886,10 +908,34 @@
886 finish:
887 thBufferFree(interp, &strbuf);
888 thBufferFree(interp, &lenbuf);
889 return rc;
890 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
891
892 /*
893 ** Evaluate the th1 script contained in the string (zProgram, nProgram)
894 ** in the current stack frame.
895 */
@@ -896,10 +942,15 @@
896 static int thEvalLocal(Th_Interp *interp, const char *zProgram, int nProgram){
897 int rc = TH_OK;
898 const char *zInput = zProgram;
899 int nInput = nProgram;
900
 
 
 
 
 
901 while( rc==TH_OK && nInput ){
902 Th_HashEntry *pEntry;
903 int nSpace;
904 const char *zFirst;
905
@@ -949,13 +1000,13 @@
949 if( rc!=TH_OK ) continue;
950
951 if( argc>0 ){
952
953 /* Look up the command name in the command hash-table. */
954 pEntry = Th_HashFind(interp, interp->paCmd, argv[0], argl[0], 0);
955 if( !pEntry ){
956 Th_ErrorMessage(interp, "no such command: ", argv[0], argl[0]);
957 rc = TH_ERROR;
958 }
959
960 /* Call the command procedure. */
961 if( rc==TH_OK ){
@@ -1095,10 +1146,12 @@
1095 int isGlobal = 0;
1096 int i;
1097
1098 if( nVarname<0 ){
1099 nVarname = th_strlen(zVarname);
 
 
1100 }
1101 nOuter = nVarname;
1102
1103 /* If the variable name starts with "::", then do the lookup is in the
1104 ** uppermost (global) frame.
@@ -1271,31 +1324,10 @@
1271 }
1272
1273 return Th_SetResult(interp, pValue->zData, pValue->nData);
1274 }
1275
1276 /*
1277 ** If interp has a variable with the given name, its value is returned
1278 ** and its length is returned via *nOut if nOut is not NULL. If
1279 ** interp has no such var then NULL is returned without setting any
1280 ** error state and *nOut, if not NULL, is set to -1. The returned value
1281 ** is owned by the interpreter and may be invalidated the next time
1282 ** the interpreter is modified.
1283 */
1284 const char * Th_MaybeGetVar(Th_Interp *interp, const char *zVarName,
1285 int *nOut){
1286 Th_Variable *pValue;
1287
1288 pValue = thFindValue(interp, zVarName, -1, 0, 0, 1, 0);
1289 if( !pValue || !pValue->zData ){
1290 if( nOut!=0 ) *nOut = -1;
1291 return NULL;
1292 }
1293 if( nOut!=0 ) *nOut = pValue->nData;
1294 return pValue->zData;
1295 }
1296
1297 /*
1298 ** Return true if variable (zVar, nVar) exists.
1299 */
1300 int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
1301 Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
@@ -1324,28 +1356,32 @@
1324 int nVar,
1325 const char *zValue,
1326 int nValue
1327 ){
1328 Th_Variable *pValue;
 
1329
 
1330 pValue = thFindValue(interp, zVar, nVar, 1, 0, 0, 0);
1331 if( !pValue ){
1332 return TH_ERROR;
1333 }
1334
1335 if( nValue<0 ){
1336 nValue = th_strlen(zValue);
 
 
1337 }
1338 if( pValue->zData ){
1339 Th_Free(interp, pValue->zData);
1340 pValue->zData = 0;
1341 }
1342
1343 assert(zValue || nValue==0);
1344 pValue->zData = Th_Malloc(interp, nValue+1);
1345 pValue->zData[nValue] = '\0';
1346 th_memcpy(pValue->zData, zValue, nValue);
1347 pValue->nData = nValue;
1348
1349 return TH_OK;
1350 }
1351
@@ -1458,10 +1494,12 @@
1458 */
1459 char *th_strdup(Th_Interp *interp, const char *z, int n){
1460 char *zRes;
1461 if( n<0 ){
1462 n = th_strlen(z);
 
 
1463 }
1464 zRes = Th_Malloc(interp, n+1);
1465 th_memcpy(zRes, z, n);
1466 zRes[n] = '\0';
1467 return zRes;
@@ -1519,13 +1557,14 @@
1519 n = th_strlen(z);
1520 }
1521
1522 if( z && n>0 ){
1523 char *zResult;
1524 zResult = Th_Malloc(pInterp, n+1);
1525 th_memcpy(zResult, z, n);
1526 zResult[n] = '\0';
 
1527 pInterp->zResult = zResult;
1528 pInterp->nResult = n;
1529 }
1530
1531 return TH_OK;
@@ -2456,10 +2495,12 @@
2456 int nToken = 0;
2457 Expr **apToken = 0;
2458
2459 if( nExpr<0 ){
2460 nExpr = th_strlen(zExpr);
 
 
2461 }
2462
2463 /* Parse the expression to a list of tokens. */
2464 rc = exprParse(interp, zExpr, nExpr, &apToken, &nToken);
2465
@@ -2567,10 +2608,12 @@
2567 Th_HashEntry *pRet;
2568 Th_HashEntry **ppRet;
2569
2570 if( nKey<0 ){
2571 nKey = th_strlen(zKey);
 
 
2572 }
2573
2574 for(i=0; i<nKey; i++){
2575 iKey = (iKey<<3) ^ iKey ^ zKey[i];
2576 }
@@ -2800,10 +2843,12 @@
2800 int base = 10;
2801 int (*isdigit)(char) = th_isdigit;
2802
2803 if( n<0 ){
2804 n = th_strlen(z);
 
 
2805 }
2806
2807 if( n>1 && (z[0]=='-' || z[0]=='+') ){
2808 i = 1;
2809 }
@@ -2859,11 +2904,11 @@
2859 const char *z,
2860 int n,
2861 double *pfOut
2862 ){
2863 if( !sqlite3IsNumber((const char *)z, 0) ){
2864 Th_ErrorMessage(interp, "expected number, got: \"", z, n);
2865 return TH_ERROR;
2866 }
2867
2868 sqlite3AtoF((const char *)z, pfOut);
2869 return TH_OK;
2870
--- src/th.c
+++ src/th.c
@@ -7,10 +7,16 @@
7 #include "config.h"
8 #include "th.h"
9 #include <string.h>
10 #include <assert.h>
11
12 /*
13 ** External routines
14 */
15 void fossil_panic(const char*,...);
16 void fossil_errorlog(const char*,...);
17
18 /*
19 ** Values used for element values in the tcl_platform array.
20 */
21
22 #if !defined(TH_ENGINE)
@@ -197,10 +203,11 @@
203 */
204 struct Buffer {
205 char *zBuf;
206 int nBuf;
207 int nBufAlloc;
208 int bTaint;
209 };
210 typedef struct Buffer Buffer;
211 static void thBufferInit(Buffer *);
212 static void thBufferFree(Th_Interp *interp, Buffer *);
213
@@ -209,10 +216,18 @@
216 ** be NULL as long as the number of bytes to copy is zero.
217 */
218 static void th_memcpy(void *dest, const void *src, size_t n){
219 if( n>0 ) memcpy(dest,src,n);
220 }
221
222 /*
223 ** An oversized string has been encountered. Do not try to recover.
224 ** Panic the process.
225 */
226 void Th_OversizeString(void){
227 fossil_panic("string too large. maximum size 286MB.");
228 }
229
230 /*
231 ** Append nAdd bytes of content copied from zAdd to the end of buffer
232 ** pBuffer. If there is not enough space currently allocated, resize
233 ** the allocation to make space.
@@ -219,40 +234,46 @@
234 */
235 static void thBufferWriteResize(
236 Th_Interp *interp,
237 Buffer *pBuffer,
238 const char *zAdd,
239 int nAddX
240 ){
241 int nAdd = TH1_LEN(nAddX);
242 int nNew = (pBuffer->nBuf+nAdd)*2+32;
243 #if defined(TH_MEMDEBUG)
244 char *zNew = (char *)Th_Malloc(interp, nNew);
245 TH1_SIZECHECK(nNew);
246 th_memcpy(zNew, pBuffer->zBuf, pBuffer->nBuf);
247 Th_Free(interp, pBuffer->zBuf);
248 pBuffer->zBuf = zNew;
249 #else
250 int nOld = pBuffer->nBufAlloc;
251 TH1_SIZECHECK(nNew);
252 pBuffer->zBuf = Th_Realloc(interp, pBuffer->zBuf, nNew);
253 memset(pBuffer->zBuf+nOld, 0, nNew-nOld);
254 #endif
255 pBuffer->nBufAlloc = nNew;
256 th_memcpy(&pBuffer->zBuf[pBuffer->nBuf], zAdd, nAdd);
257 pBuffer->nBuf += nAdd;
258 TH1_XFER_TAINT(pBuffer->bTaint, nAddX);
259 }
260 static void thBufferWriteFast(
261 Th_Interp *interp,
262 Buffer *pBuffer,
263 const char *zAdd,
264 int nAddX
265 ){
266 int nAdd = TH1_LEN(nAddX);
267 if( pBuffer->nBuf+nAdd > pBuffer->nBufAlloc ){
268 thBufferWriteResize(interp, pBuffer, zAdd, nAddX);
269 }else{
270 if( pBuffer->zBuf ){
271 memcpy(pBuffer->zBuf + pBuffer->nBuf, zAdd, nAdd);
272 }
273 pBuffer->nBuf += nAdd;
274 TH1_XFER_TAINT(pBuffer->bTaint, nAddX);
275 }
276 }
277 #define thBufferWrite(a,b,c,d) thBufferWriteFast(a,b,(const char *)c,d)
278
279 /*
@@ -704,24 +725,25 @@
725 int nWord
726 ){
727 int rc = TH_OK;
728 Buffer output;
729 int i;
730 int nn = TH1_LEN(nWord);
731
732 thBufferInit(&output);
733
734 if( nn>1 && (zWord[0]=='{' && zWord[nn-1]=='}') ){
735 thBufferWrite(interp, &output, &zWord[1], nn-2);
736 }else{
737
738 /* If the word is surrounded by double-quotes strip these away. */
739 if( nn>1 && (zWord[0]=='"' && zWord[nn-1]=='"') ){
740 zWord++;
741 nn -= 2;
742 }
743
744 for(i=0; rc==TH_OK && i<nn; i++){
745 int nGet;
746
747 int (*xGet)(Th_Interp *, const char*, int, int *) = 0;
748 int (*xSubst)(Th_Interp *, const char*, int) = 0;
749
@@ -743,11 +765,11 @@
765 thBufferAddChar(interp, &output, zWord[i]);
766 continue; /* Go to the next iteration of the for(...) loop */
767 }
768 }
769
770 rc = xGet(interp, &zWord[i], nn-i, &nGet);
771 if( rc==TH_OK ){
772 rc = xSubst(interp, &zWord[i], nGet);
773 }
774 if( rc==TH_OK ){
775 const char *zRes;
@@ -826,11 +848,11 @@
848 Buffer strbuf;
849 Buffer lenbuf;
850 int nCount = 0;
851
852 const char *zInput = zList;
853 int nInput = TH1_LEN(nList);
854
855 thBufferInit(&strbuf);
856 thBufferInit(&lenbuf);
857
858 while( nInput>0 ){
@@ -886,10 +908,34 @@
908 finish:
909 thBufferFree(interp, &strbuf);
910 thBufferFree(interp, &lenbuf);
911 return rc;
912 }
913
914 /*
915 ** Report misuse of a tainted string.
916 **
917 ** In the current implementation, this routine issues a warning to the
918 ** error log and returns 0, causing processing to continue. This is so
919 ** that the new taint detection will not disrupt legacy configurations.
920 ** However, if modified so that this routine returns non-zero, then it
921 ** will cause an error in the script.
922 */
923 int Th_ReportTaint(
924 Th_Interp *interp, /* Report error here, if an error is reported */
925 const char *zWhere, /* Where the tainted string appears */
926 const char *zStr, /* The tainted string */
927 int nStr /* Length of the tainted string */
928 ){
929 nStr = TH1_LEN(nStr);
930 if( nStr>0 ){
931 fossil_errorlog("warning: tainted %s: \"%.s\"", zWhere, nStr, zStr);
932 }else{
933 fossil_errorlog("warning: tainted %s", zWhere);
934 }
935 return 0;
936 }
937
938 /*
939 ** Evaluate the th1 script contained in the string (zProgram, nProgram)
940 ** in the current stack frame.
941 */
@@ -896,10 +942,15 @@
942 static int thEvalLocal(Th_Interp *interp, const char *zProgram, int nProgram){
943 int rc = TH_OK;
944 const char *zInput = zProgram;
945 int nInput = nProgram;
946
947 if( TH1_TAINTED(nProgram)
948 && Th_ReportTaint(interp, "script", zProgram, nProgram)
949 ){
950 return TH_ERROR;
951 }
952 while( rc==TH_OK && nInput ){
953 Th_HashEntry *pEntry;
954 int nSpace;
955 const char *zFirst;
956
@@ -949,13 +1000,13 @@
1000 if( rc!=TH_OK ) continue;
1001
1002 if( argc>0 ){
1003
1004 /* Look up the command name in the command hash-table. */
1005 pEntry = Th_HashFind(interp, interp->paCmd, argv[0], TH1_LEN(argl[0]),0);
1006 if( !pEntry ){
1007 Th_ErrorMessage(interp, "no such command: ", argv[0], TH1_LEN(argl[0]));
1008 rc = TH_ERROR;
1009 }
1010
1011 /* Call the command procedure. */
1012 if( rc==TH_OK ){
@@ -1095,10 +1146,12 @@
1146 int isGlobal = 0;
1147 int i;
1148
1149 if( nVarname<0 ){
1150 nVarname = th_strlen(zVarname);
1151 }else{
1152 nVarname = TH1_LEN(nVarname);
1153 }
1154 nOuter = nVarname;
1155
1156 /* If the variable name starts with "::", then do the lookup is in the
1157 ** uppermost (global) frame.
@@ -1271,31 +1324,10 @@
1324 }
1325
1326 return Th_SetResult(interp, pValue->zData, pValue->nData);
1327 }
1328
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1329 /*
1330 ** Return true if variable (zVar, nVar) exists.
1331 */
1332 int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
1333 Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
@@ -1324,28 +1356,32 @@
1356 int nVar,
1357 const char *zValue,
1358 int nValue
1359 ){
1360 Th_Variable *pValue;
1361 int nn;
1362
1363 nVar = TH1_LEN(nVar);
1364 pValue = thFindValue(interp, zVar, nVar, 1, 0, 0, 0);
1365 if( !pValue ){
1366 return TH_ERROR;
1367 }
1368
1369 if( nValue<0 ){
1370 nn = th_strlen(zValue);
1371 }else{
1372 nn = TH1_LEN(nValue);
1373 }
1374 if( pValue->zData ){
1375 Th_Free(interp, pValue->zData);
1376 pValue->zData = 0;
1377 }
1378
1379 assert(zValue || nn==0);
1380 pValue->zData = Th_Malloc(interp, nn+1);
1381 pValue->zData[nn] = '\0';
1382 th_memcpy(pValue->zData, zValue, nn);
1383 pValue->nData = nValue;
1384
1385 return TH_OK;
1386 }
1387
@@ -1458,10 +1494,12 @@
1494 */
1495 char *th_strdup(Th_Interp *interp, const char *z, int n){
1496 char *zRes;
1497 if( n<0 ){
1498 n = th_strlen(z);
1499 }else{
1500 n = TH1_LEN(n);
1501 }
1502 zRes = Th_Malloc(interp, n+1);
1503 th_memcpy(zRes, z, n);
1504 zRes[n] = '\0';
1505 return zRes;
@@ -1519,13 +1557,14 @@
1557 n = th_strlen(z);
1558 }
1559
1560 if( z && n>0 ){
1561 char *zResult;
1562 int nn = TH1_LEN(n);
1563 zResult = Th_Malloc(pInterp, nn+1);
1564 th_memcpy(zResult, z, nn);
1565 zResult[nn] = '\0';
1566 pInterp->zResult = zResult;
1567 pInterp->nResult = n;
1568 }
1569
1570 return TH_OK;
@@ -2456,10 +2495,12 @@
2495 int nToken = 0;
2496 Expr **apToken = 0;
2497
2498 if( nExpr<0 ){
2499 nExpr = th_strlen(zExpr);
2500 }else{
2501 nExpr = TH1_LEN(nExpr);
2502 }
2503
2504 /* Parse the expression to a list of tokens. */
2505 rc = exprParse(interp, zExpr, nExpr, &apToken, &nToken);
2506
@@ -2567,10 +2608,12 @@
2608 Th_HashEntry *pRet;
2609 Th_HashEntry **ppRet;
2610
2611 if( nKey<0 ){
2612 nKey = th_strlen(zKey);
2613 }else{
2614 nKey = TH1_LEN(nKey);
2615 }
2616
2617 for(i=0; i<nKey; i++){
2618 iKey = (iKey<<3) ^ iKey ^ zKey[i];
2619 }
@@ -2800,10 +2843,12 @@
2843 int base = 10;
2844 int (*isdigit)(char) = th_isdigit;
2845
2846 if( n<0 ){
2847 n = th_strlen(z);
2848 }else{
2849 n = TH1_LEN(n);
2850 }
2851
2852 if( n>1 && (z[0]=='-' || z[0]=='+') ){
2853 i = 1;
2854 }
@@ -2859,11 +2904,11 @@
2904 const char *z,
2905 int n,
2906 double *pfOut
2907 ){
2908 if( !sqlite3IsNumber((const char *)z, 0) ){
2909 Th_ErrorMessage(interp, "expected number, got: \"", z, TH1_LEN(n));
2910 return TH_ERROR;
2911 }
2912
2913 sqlite3AtoF((const char *)z, pfOut);
2914 return TH_OK;
2915
+53 -14
--- src/th.h
+++ src/th.h
@@ -1,10 +1,56 @@
1
-
21
/* This header file defines the external interface to the custom Scripting
32
** Language (TH) interpreter. TH is very similar to Tcl but is not an
43
** exact clone.
4
+**
5
+** TH1 was original developed to run SQLite tests on SymbianOS. This version
6
+** of TH1 was repurposed as a scripted language for Fossil, and was heavily
7
+** modified for that purpose, beginning in early 2008.
8
+**
9
+** More recently, TH1 has been enhanced to distinguish between regular text
10
+** and "tainted" text. "Tainted" text is text that might have originated
11
+** from an outside source and hence might not be trustworthy. To prevent
12
+** cross-site scripting (XSS) and SQL-injections and similar attacks,
13
+** tainted text should not be used for the following purposes:
14
+**
15
+** * executed as TH1 script or expression.
16
+** * output as HTML or Javascript
17
+** * used as part of an SQL query
18
+**
19
+** Tainted text can be converted into a safe form using commands like
20
+** "htmlize". And some commands ("query" and "expr") know how to use
21
+** potentially tainted variable values directly, and thus can bypass
22
+** the restrictions above.
23
+**
24
+** Whether a string is clean or tainted is determined by its length integer.
25
+** TH1 limits strings to be no more than 0x0fffffff bytes bytes in length
26
+** (about 268MB - more than sufficient for the purposes of Fossil). The top
27
+** bit of the length integer is the sign bit, of course. The next three bits
28
+** are reserved. One of those, the 0x10000000 bit, marks tainted strings.
529
*/
30
+#define TH1_MX_STRLEN 0x0fffffff /* Maximum length of a TH1-C string */
31
+#define TH1_TAINT_BIT 0x10000000 /* The taint bit */
32
+#define TH1_SIGN 0x80000000
33
+
34
+/* Convert an integer into a string length. Negative values remain negative */
35
+#define TH1_LEN(X) ((TH1_SIGN|TH1_MX_STRLEN)&(X))
36
+
37
+/* Return true if the string is tainted */
38
+#define TH1_TAINTED(X) (((X)&TH1_TAINT_BIT)!=0)
39
+
40
+/* Remove taint from a string */
41
+#define TH1_RM_TAINT(X) ((X)&~TH1_TAINT_BIT)
42
+
43
+/* Add taint to a string */
44
+#define TH1_ADD_TAINT(X) ((X)|TH1_TAINT_BIT)
45
+
46
+/* If B is tainted, make A tainted too */
47
+#define TH1_XFER_TAINT(A,B) (A)|=(TH1_TAINT_BIT&(B))
48
+
49
+/* Check to see if a string is too big for TH1 */
50
+#define TH1_SIZECHECK(N) if((N)>TH1_MX_STRLEN){Th_OversizeString();}
51
+void Th_OversizeString(void);
652
753
/*
854
** Before creating an interpreter, the application must allocate and
955
** populate an instance of the following structure. It must remain valid
1056
** for the lifetime of the interpreter.
@@ -24,10 +70,16 @@
2470
** Create and delete interpreters.
2571
*/
2672
Th_Interp * Th_CreateInterp(Th_Vtab *);
2773
void Th_DeleteInterp(Th_Interp *);
2874
75
+/*
76
+** Report taint in the string zStr,nStr. That string represents "zTitle"
77
+** If non-zero is returned error out of the caller.
78
+*/
79
+int Th_ReportTaint(Th_Interp*,const char*,const char*zStr,int nStr);
80
+
2981
/*
3082
** Evaluate an TH program in the stack frame identified by parameter
3183
** iFrame, according to the following rules:
3284
**
3385
** * If iFrame is 0, this means the current frame.
@@ -56,23 +108,10 @@
56108
int Th_GetVar(Th_Interp *, const char *, int);
57109
int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
58110
int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
59111
int Th_UnsetVar(Th_Interp *, const char *, int);
60112
61
-/*
62
-** If interp has a variable with the given name, its value is returned
63
-** and its length is returned via *nOut if nOut is not NULL. If
64
-** interp has no such var then NULL is returned without setting any
65
-** error state and *nOut, if not NULL, is set to 0. The returned value
66
-** is owned by the interpreter and may be invalidated the next time
67
-** the interpreter is modified.
68
-**
69
-** zVarName must be NUL-terminated.
70
-*/
71
-const char * Th_MaybeGetVar(Th_Interp *interp, const char *zVarName,
72
- int *nOut);
73
-
74113
typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *);
75114
76115
/*
77116
** Register new commands.
78117
*/
79118
--- src/th.h
+++ src/th.h
@@ -1,10 +1,56 @@
1
2 /* This header file defines the external interface to the custom Scripting
3 ** Language (TH) interpreter. TH is very similar to Tcl but is not an
4 ** exact clone.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
7 /*
8 ** Before creating an interpreter, the application must allocate and
9 ** populate an instance of the following structure. It must remain valid
10 ** for the lifetime of the interpreter.
@@ -24,10 +70,16 @@
24 ** Create and delete interpreters.
25 */
26 Th_Interp * Th_CreateInterp(Th_Vtab *);
27 void Th_DeleteInterp(Th_Interp *);
28
 
 
 
 
 
 
29 /*
30 ** Evaluate an TH program in the stack frame identified by parameter
31 ** iFrame, according to the following rules:
32 **
33 ** * If iFrame is 0, this means the current frame.
@@ -56,23 +108,10 @@
56 int Th_GetVar(Th_Interp *, const char *, int);
57 int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
58 int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
59 int Th_UnsetVar(Th_Interp *, const char *, int);
60
61 /*
62 ** If interp has a variable with the given name, its value is returned
63 ** and its length is returned via *nOut if nOut is not NULL. If
64 ** interp has no such var then NULL is returned without setting any
65 ** error state and *nOut, if not NULL, is set to 0. The returned value
66 ** is owned by the interpreter and may be invalidated the next time
67 ** the interpreter is modified.
68 **
69 ** zVarName must be NUL-terminated.
70 */
71 const char * Th_MaybeGetVar(Th_Interp *interp, const char *zVarName,
72 int *nOut);
73
74 typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *);
75
76 /*
77 ** Register new commands.
78 */
79
--- src/th.h
+++ src/th.h
@@ -1,10 +1,56 @@
 
1 /* This header file defines the external interface to the custom Scripting
2 ** Language (TH) interpreter. TH is very similar to Tcl but is not an
3 ** exact clone.
4 **
5 ** TH1 was original developed to run SQLite tests on SymbianOS. This version
6 ** of TH1 was repurposed as a scripted language for Fossil, and was heavily
7 ** modified for that purpose, beginning in early 2008.
8 **
9 ** More recently, TH1 has been enhanced to distinguish between regular text
10 ** and "tainted" text. "Tainted" text is text that might have originated
11 ** from an outside source and hence might not be trustworthy. To prevent
12 ** cross-site scripting (XSS) and SQL-injections and similar attacks,
13 ** tainted text should not be used for the following purposes:
14 **
15 ** * executed as TH1 script or expression.
16 ** * output as HTML or Javascript
17 ** * used as part of an SQL query
18 **
19 ** Tainted text can be converted into a safe form using commands like
20 ** "htmlize". And some commands ("query" and "expr") know how to use
21 ** potentially tainted variable values directly, and thus can bypass
22 ** the restrictions above.
23 **
24 ** Whether a string is clean or tainted is determined by its length integer.
25 ** TH1 limits strings to be no more than 0x0fffffff bytes bytes in length
26 ** (about 268MB - more than sufficient for the purposes of Fossil). The top
27 ** bit of the length integer is the sign bit, of course. The next three bits
28 ** are reserved. One of those, the 0x10000000 bit, marks tainted strings.
29 */
30 #define TH1_MX_STRLEN 0x0fffffff /* Maximum length of a TH1-C string */
31 #define TH1_TAINT_BIT 0x10000000 /* The taint bit */
32 #define TH1_SIGN 0x80000000
33
34 /* Convert an integer into a string length. Negative values remain negative */
35 #define TH1_LEN(X) ((TH1_SIGN|TH1_MX_STRLEN)&(X))
36
37 /* Return true if the string is tainted */
38 #define TH1_TAINTED(X) (((X)&TH1_TAINT_BIT)!=0)
39
40 /* Remove taint from a string */
41 #define TH1_RM_TAINT(X) ((X)&~TH1_TAINT_BIT)
42
43 /* Add taint to a string */
44 #define TH1_ADD_TAINT(X) ((X)|TH1_TAINT_BIT)
45
46 /* If B is tainted, make A tainted too */
47 #define TH1_XFER_TAINT(A,B) (A)|=(TH1_TAINT_BIT&(B))
48
49 /* Check to see if a string is too big for TH1 */
50 #define TH1_SIZECHECK(N) if((N)>TH1_MX_STRLEN){Th_OversizeString();}
51 void Th_OversizeString(void);
52
53 /*
54 ** Before creating an interpreter, the application must allocate and
55 ** populate an instance of the following structure. It must remain valid
56 ** for the lifetime of the interpreter.
@@ -24,10 +70,16 @@
70 ** Create and delete interpreters.
71 */
72 Th_Interp * Th_CreateInterp(Th_Vtab *);
73 void Th_DeleteInterp(Th_Interp *);
74
75 /*
76 ** Report taint in the string zStr,nStr. That string represents "zTitle"
77 ** If non-zero is returned error out of the caller.
78 */
79 int Th_ReportTaint(Th_Interp*,const char*,const char*zStr,int nStr);
80
81 /*
82 ** Evaluate an TH program in the stack frame identified by parameter
83 ** iFrame, according to the following rules:
84 **
85 ** * If iFrame is 0, this means the current frame.
@@ -56,23 +108,10 @@
108 int Th_GetVar(Th_Interp *, const char *, int);
109 int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
110 int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
111 int Th_UnsetVar(Th_Interp *, const char *, int);
112
 
 
 
 
 
 
 
 
 
 
 
 
 
113 typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *);
114
115 /*
116 ** Register new commands.
117 */
118
+68 -47
--- src/th_lang.c
+++ src/th_lang.c
@@ -39,11 +39,11 @@
3939
4040
rc = Th_Eval(interp, 0, argv[1], -1);
4141
if( argc==3 ){
4242
int nResult;
4343
const char *zResult = Th_GetResult(interp, &nResult);
44
- Th_SetVar(interp, argv[2], argl[2], zResult, nResult);
44
+ Th_SetVar(interp, argv[2], TH1_LEN(argl[2]), zResult, nResult);
4545
}
4646
4747
Th_SetResultInt(interp, rc);
4848
return TH_OK;
4949
}
@@ -215,15 +215,18 @@
215215
int *argl
216216
){
217217
char *zList = 0;
218218
int nList = 0;
219219
int i;
220
+ int bTaint = 0;
220221
221222
for(i=1; i<argc; i++){
223
+ TH1_XFER_TAINT(bTaint,argl[i]);
222224
Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
223225
}
224226
227
+ TH1_XFER_TAINT(nList, bTaint);
225228
Th_SetResult(interp, zList, nList);
226229
Th_Free(interp, zList);
227230
228231
return TH_OK;
229232
}
@@ -244,10 +247,11 @@
244247
int *argl
245248
){
246249
char *zList = 0;
247250
int nList = 0;
248251
int i, rc;
252
+ int bTaint = 0;
249253
250254
if( argc<2 ){
251255
return Th_WrongNumArgs(interp, "lappend var ...");
252256
}
253257
rc = Th_GetVar(interp, argv[1], argl[1]);
@@ -254,13 +258,15 @@
254258
if( rc==TH_OK ){
255259
zList = Th_TakeResult(interp, &nList);
256260
}
257261
258262
for(i=2; i<argc; i++){
263
+ TH1_XFER_TAINT(bTaint, argl[i]);
259264
Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
260265
}
261266
267
+ TH1_XFER_TAINT(nList, bTaint);
262268
Th_SetVar(interp, argv[1], argl[1], zList, nList);
263269
Th_SetResult(interp, zList, nList);
264270
Th_Free(interp, zList);
265271
266272
return TH_OK;
@@ -561,20 +567,21 @@
561567
int nUsage = 0; /* Number of bytes at zUsage */
562568
563569
if( argc!=4 ){
564570
return Th_WrongNumArgs(interp, "proc name arglist code");
565571
}
566
- if( Th_SplitList(interp, argv[2], argl[2], &azParam, &anParam, &nParam) ){
572
+ if( Th_SplitList(interp, argv[2], TH1_LEN(argl[2]),
573
+ &azParam, &anParam, &nParam) ){
567574
return TH_ERROR;
568575
}
569576
570577
/* Allocate the new ProcDefn structure. */
571578
nByte = sizeof(ProcDefn) + /* ProcDefn structure */
572579
(sizeof(char *) + sizeof(int)) * nParam + /* azParam, anParam */
573580
(sizeof(char *) + sizeof(int)) * nParam + /* azDefault, anDefault */
574
- argl[3] + /* zProgram */
575
- argl[2]; /* Space for copies of parameter names and default values */
581
+ TH1_LEN(argl[3]) + /* zProgram */
582
+ TH1_LEN(argl[2]); /* Space for copies of param names and dflt values */
576583
p = (ProcDefn *)Th_Malloc(interp, nByte);
577584
578585
/* If the last parameter in the parameter list is "args", then set the
579586
** ProcDefn.hasArgs flag. The "args" parameter does not require an
580587
** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays.
@@ -590,12 +597,12 @@
590597
p->azParam = (char **)&p[1];
591598
p->anParam = (int *)&p->azParam[nParam];
592599
p->azDefault = (char **)&p->anParam[nParam];
593600
p->anDefault = (int *)&p->azDefault[nParam];
594601
p->zProgram = (char *)&p->anDefault[nParam];
595
- memcpy(p->zProgram, argv[3], argl[3]);
596
- p->nProgram = argl[3];
602
+ memcpy(p->zProgram, argv[3], TH1_LEN(argl[3]));
603
+ p->nProgram = TH1_LEN(argl[3]);
597604
zSpace = &p->zProgram[p->nProgram];
598605
599606
for(i=0; i<nParam; i++){
600607
char **az;
601608
int *an;
@@ -672,11 +679,12 @@
672679
int *argl
673680
){
674681
if( argc!=3 ){
675682
return Th_WrongNumArgs(interp, "rename oldcmd newcmd");
676683
}
677
- return Th_RenameCommand(interp, argv[1], argl[1], argv[2], argl[2]);
684
+ return Th_RenameCommand(interp, argv[1], TH1_LEN(argl[1]),
685
+ argv[2], TH1_LEN(argl[2]));
678686
}
679687
680688
/*
681689
** TH Syntax:
682690
**
@@ -746,13 +754,13 @@
746754
if( argc!=4 ){
747755
return Th_WrongNumArgs(interp, "string compare str1 str2");
748756
}
749757
750758
zLeft = argv[2];
751
- nLeft = argl[2];
759
+ nLeft = TH1_LEN(argl[2]);
752760
zRight = argv[3];
753
- nRight = argl[3];
761
+ nRight = TH1_LEN(argl[3]);
754762
755763
for(i=0; iRes==0 && i<nLeft && i<nRight; i++){
756764
iRes = zLeft[i]-zRight[i];
757765
}
758766
if( iRes==0 ){
@@ -779,12 +787,12 @@
779787
780788
if( argc!=4 ){
781789
return Th_WrongNumArgs(interp, "string first needle haystack");
782790
}
783791
784
- nNeedle = argl[2];
785
- nHaystack = argl[3];
792
+ nNeedle = TH1_LEN(argl[2]);
793
+ nHaystack = TH1_LEN(argl[3]);
786794
787795
if( nNeedle && nHaystack && nNeedle<=nHaystack ){
788796
const char *zNeedle = argv[2];
789797
const char *zHaystack = argv[3];
790798
int i;
@@ -812,19 +820,19 @@
812820
813821
if( argc!=4 ){
814822
return Th_WrongNumArgs(interp, "string index string index");
815823
}
816824
817
- if( argl[3]==3 && 0==memcmp("end", argv[3], 3) ){
818
- iIndex = argl[2]-1;
825
+ if( TH1_LEN(argl[3])==3 && 0==memcmp("end", argv[3], 3) ){
826
+ iIndex = TH1_LEN(argl[2])-1;
819827
}else if( Th_ToInt(interp, argv[3], argl[3], &iIndex) ){
820828
Th_ErrorMessage(
821829
interp, "Expected \"end\" or integer, got:", argv[3], argl[3]);
822830
return TH_ERROR;
823831
}
824832
825
- if( iIndex>=0 && iIndex<argl[2] ){
833
+ if( iIndex>=0 && iIndex<TH1_LEN(argl[2]) ){
826834
return Th_SetResult(interp, &argv[2][iIndex], 1);
827835
}else{
828836
return Th_SetResult(interp, 0, 0);
829837
}
830838
}
@@ -838,41 +846,44 @@
838846
Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
839847
){
840848
if( argc!=4 ){
841849
return Th_WrongNumArgs(interp, "string is class string");
842850
}
843
- if( argl[2]==5 && 0==memcmp(argv[2], "alnum", 5) ){
851
+ if( TH1_LEN(argl[2])==5 && 0==memcmp(argv[2], "alnum", 5) ){
844852
int i;
845853
int iRes = 1;
846854
847
- for(i=0; i<argl[3]; i++){
855
+ for(i=0; i<TH1_LEN(argl[3]); i++){
848856
if( !th_isalnum(argv[3][i]) ){
849857
iRes = 0;
850858
}
851859
}
852860
853861
return Th_SetResultInt(interp, iRes);
854
- }else if( argl[2]==6 && 0==memcmp(argv[2], "double", 6) ){
862
+ }else if( TH1_LEN(argl[2])==6 && 0==memcmp(argv[2], "double", 6) ){
855863
double fVal;
856864
if( Th_ToDouble(interp, argv[3], argl[3], &fVal)==TH_OK ){
857865
return Th_SetResultInt(interp, 1);
858866
}
859867
return Th_SetResultInt(interp, 0);
860
- }else if( argl[2]==7 && 0==memcmp(argv[2], "integer", 7) ){
868
+ }else if( TH1_LEN(argl[2])==7 && 0==memcmp(argv[2], "integer", 7) ){
861869
int iVal;
862870
if( Th_ToInt(interp, argv[3], argl[3], &iVal)==TH_OK ){
863871
return Th_SetResultInt(interp, 1);
864872
}
865873
return Th_SetResultInt(interp, 0);
866
- }else if( argl[2]==4 && 0==memcmp(argv[2], "list", 4) ){
874
+ }else if( TH1_LEN(argl[2])==4 && 0==memcmp(argv[2], "list", 4) ){
867875
if( Th_SplitList(interp, argv[3], argl[3], 0, 0, 0)==TH_OK ){
868876
return Th_SetResultInt(interp, 1);
869877
}
870878
return Th_SetResultInt(interp, 0);
879
+ }else if( TH1_LEN(argl[2])==7 && 0==memcmp(argv[2], "tainted", 7) ){
880
+ return Th_SetResultInt(interp, TH1_TAINTED(argl[3]));
871881
}else{
872882
Th_ErrorMessage(interp,
873
- "Expected alnum, double, integer, or list, got:", argv[2], argl[2]);
883
+ "Expected alnum, double, integer, list, or tainted, got:",
884
+ argv[2], TH1_LEN(argl[2]));
874885
return TH_ERROR;
875886
}
876887
}
877888
878889
/*
@@ -889,12 +900,12 @@
889900
890901
if( argc!=4 ){
891902
return Th_WrongNumArgs(interp, "string last needle haystack");
892903
}
893904
894
- nNeedle = argl[2];
895
- nHaystack = argl[3];
905
+ nNeedle = TH1_LEN(argl[2]);
906
+ nHaystack = TH1_LEN(argl[3]);
896907
897908
if( nNeedle && nHaystack && nNeedle<=nHaystack ){
898909
const char *zNeedle = argv[2];
899910
const char *zHaystack = argv[3];
900911
int i;
@@ -919,11 +930,11 @@
919930
Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
920931
){
921932
if( argc!=3 ){
922933
return Th_WrongNumArgs(interp, "string length string");
923934
}
924
- return Th_SetResultInt(interp, argl[2]);
935
+ return Th_SetResultInt(interp, TH1_LEN(argl[2]));
925936
}
926937
927938
/*
928939
** TH Syntax:
929940
**
@@ -938,12 +949,12 @@
938949
char *zPat, *zStr;
939950
int rc;
940951
if( argc!=4 ){
941952
return Th_WrongNumArgs(interp, "string match pattern string");
942953
}
943
- zPat = fossil_strndup(argv[2],argl[2]);
944
- zStr = fossil_strndup(argv[3],argl[3]);
954
+ zPat = fossil_strndup(argv[2],TH1_LEN(argl[2]));
955
+ zStr = fossil_strndup(argv[3],TH1_LEN(argl[3]));
945956
rc = sqlite3_strglob(zPat,zStr);
946957
fossil_free(zPat);
947958
fossil_free(zStr);
948959
return Th_SetResultInt(interp, !rc);
949960
}
@@ -961,23 +972,23 @@
961972
962973
if( argc!=5 ){
963974
return Th_WrongNumArgs(interp, "string range string first last");
964975
}
965976
966
- if( argl[4]==3 && 0==memcmp("end", argv[4], 3) ){
967
- iEnd = argl[2];
977
+ if( TH1_LEN(argl[4])==3 && 0==memcmp("end", argv[4], 3) ){
978
+ iEnd = TH1_LEN(argl[2]);
968979
}else if( Th_ToInt(interp, argv[4], argl[4], &iEnd) ){
969980
Th_ErrorMessage(
970
- interp, "Expected \"end\" or integer, got:", argv[4], argl[4]);
981
+ interp, "Expected \"end\" or integer, got:", argv[4], TH1_LEN(argl[4]));
971982
return TH_ERROR;
972983
}
973984
if( Th_ToInt(interp, argv[3], argl[3], &iStart) ){
974985
return TH_ERROR;
975986
}
976987
977988
if( iStart<0 ) iStart = 0;
978
- if( iEnd>=argl[2] ) iEnd = argl[2]-1;
989
+ if( iEnd>=TH1_LEN(argl[2]) ) iEnd = TH1_LEN(argl[2])-1;
979990
if( iStart>iEnd ) iEnd = iStart-1;
980991
981992
return Th_SetResult(interp, &argv[2][iStart], iEnd-iStart+1);
982993
}
983994
@@ -989,27 +1000,33 @@
9891000
static int string_repeat_command(
9901001
Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
9911002
){
9921003
int n;
9931004
int i;
994
- int nByte;
1005
+ int sz;
1006
+ long long int nByte;
9951007
char *zByte;
9961008
9971009
if( argc!=4 ){
9981010
return Th_WrongNumArgs(interp, "string repeat string n");
9991011
}
10001012
if( Th_ToInt(interp, argv[3], argl[3], &n) ){
10011013
return TH_ERROR;
10021014
}
10031015
1004
- nByte = argl[2] * n;
1016
+ nByte = n;
1017
+ sz = TH1_LEN(argl[2]);
1018
+ nByte *= sz;
1019
+ TH1_SIZECHECK(nByte+1);
10051020
zByte = Th_Malloc(interp, nByte+1);
1006
- for(i=0; i<nByte; i+=argl[2]){
1007
- memcpy(&zByte[i], argv[2], argl[2]);
1021
+ for(i=0; i<nByte; i+=sz){
1022
+ memcpy(&zByte[i], argv[2], sz);
10081023
}
10091024
1010
- Th_SetResult(interp, zByte, nByte);
1025
+ n = nByte;
1026
+ TH1_XFER_TAINT(n, argl[2]);
1027
+ Th_SetResult(interp, zByte, n);
10111028
Th_Free(interp, zByte);
10121029
return TH_OK;
10131030
}
10141031
10151032
/*
@@ -1027,15 +1044,15 @@
10271044
10281045
if( argc!=3 ){
10291046
return Th_WrongNumArgs(interp, "string trim string");
10301047
}
10311048
z = argv[2];
1032
- n = argl[2];
1033
- if( argl[1]<5 || argv[1][4]=='l' ){
1049
+ n = TH1_LEN(argl[2]);
1050
+ if( TH1_LEN(argl[1])<5 || argv[1][4]=='l' ){
10341051
while( n && th_isspace(z[0]) ){ z++; n--; }
10351052
}
1036
- if( argl[1]<5 || argv[1][4]=='r' ){
1053
+ if( TH1_LEN(argl[1])<5 || argv[1][4]=='r' ){
10371054
while( n && th_isspace(z[n-1]) ){ n--; }
10381055
}
10391056
Th_SetResult(interp, z, n);
10401057
return TH_OK;
10411058
}
@@ -1051,11 +1068,11 @@
10511068
int rc;
10521069
10531070
if( argc!=3 ){
10541071
return Th_WrongNumArgs(interp, "info exists var");
10551072
}
1056
- rc = Th_ExistsVar(interp, argv[2], argl[2]);
1073
+ rc = Th_ExistsVar(interp, argv[2], TH1_LEN(argl[2]));
10571074
Th_SetResultInt(interp, rc);
10581075
return TH_OK;
10591076
}
10601077
10611078
/*
@@ -1117,11 +1134,11 @@
11171134
int rc;
11181135
11191136
if( argc!=3 ){
11201137
return Th_WrongNumArgs(interp, "array exists var");
11211138
}
1122
- rc = Th_ExistsArrayVar(interp, argv[2], argl[2]);
1139
+ rc = Th_ExistsArrayVar(interp, argv[2], TH1_LEN(argl[2]));
11231140
Th_SetResultInt(interp, rc);
11241141
return TH_OK;
11251142
}
11261143
11271144
/*
@@ -1137,11 +1154,11 @@
11371154
int nElem = 0;
11381155
11391156
if( argc!=3 ){
11401157
return Th_WrongNumArgs(interp, "array names varname");
11411158
}
1142
- rc = Th_ListAppendArray(interp, argv[2], argl[2], &zElem, &nElem);
1159
+ rc = Th_ListAppendArray(interp, argv[2], TH1_LEN(argl[2]), &zElem, &nElem);
11431160
if( rc!=TH_OK ){
11441161
return rc;
11451162
}
11461163
Th_SetResult(interp, zElem, nElem);
11471164
if( zElem ) Th_Free(interp, zElem);
@@ -1161,11 +1178,11 @@
11611178
int *argl
11621179
){
11631180
if( argc!=2 ){
11641181
return Th_WrongNumArgs(interp, "unset var");
11651182
}
1166
- return Th_UnsetVar(interp, argv[1], argl[1]);
1183
+ return Th_UnsetVar(interp, argv[1], TH1_LEN(argl[1]));
11671184
}
11681185
11691186
int Th_CallSubCommand(
11701187
Th_Interp *interp,
11711188
void *ctx,
@@ -1176,19 +1193,22 @@
11761193
){
11771194
if( argc>1 ){
11781195
int i;
11791196
for(i=0; aSub[i].zName; i++){
11801197
const char *zName = aSub[i].zName;
1181
- if( th_strlen(zName)==argl[1] && 0==memcmp(zName, argv[1], argl[1]) ){
1198
+ if( th_strlen(zName)==TH1_LEN(argl[1])
1199
+ && 0==memcmp(zName, argv[1], TH1_LEN(argl[1])) ){
11821200
return aSub[i].xProc(interp, ctx, argc, argv, argl);
11831201
}
11841202
}
11851203
}
11861204
if(argc<2){
1187
- Th_ErrorMessage(interp, "Expected sub-command for", argv[0], argl[0]);
1205
+ Th_ErrorMessage(interp, "Expected sub-command for",
1206
+ argv[0], TH1_LEN(argl[0]));
11881207
}else{
1189
- Th_ErrorMessage(interp, "Expected sub-command, got:", argv[1], argl[1]);
1208
+ Th_ErrorMessage(interp, "Expected sub-command, got:",
1209
+ argv[1], TH1_LEN(argl[1]));
11901210
}
11911211
return TH_ERROR;
11921212
}
11931213
11941214
/*
@@ -1319,11 +1339,11 @@
13191339
int iFrame = -1;
13201340
13211341
if( argc!=2 && argc!=3 ){
13221342
return Th_WrongNumArgs(interp, "uplevel ?level? script...");
13231343
}
1324
- if( argc==3 && TH_OK!=thToFrame(interp, argv[1], argl[1], &iFrame) ){
1344
+ if( argc==3 && TH_OK!=thToFrame(interp, argv[1], TH1_LEN(argl[1]), &iFrame) ){
13251345
return TH_ERROR;
13261346
}
13271347
return Th_Eval(interp, iFrame, argv[argc-1], -1);
13281348
}
13291349
@@ -1342,19 +1362,20 @@
13421362
int iVar = 1;
13431363
int iFrame = -1;
13441364
int rc = TH_OK;
13451365
int i;
13461366
1347
- if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){
1367
+ if( TH_OK==thToFrame(0, argv[1], TH1_LEN(argl[1]), &iFrame) ){
13481368
iVar++;
13491369
}
13501370
if( argc==iVar || (argc-iVar)%2 ){
13511371
return Th_WrongNumArgs(interp,
13521372
"upvar frame othervar myvar ?othervar myvar...?");
13531373
}
13541374
for(i=iVar; rc==TH_OK && i<argc; i=i+2){
1355
- rc = Th_LinkVar(interp, argv[i+1], argl[i+1], iFrame, argv[i], argl[i]);
1375
+ rc = Th_LinkVar(interp, argv[i+1], TH1_LEN(argl[i+1]),
1376
+ iFrame, argv[i], TH1_LEN(argl[i]));
13561377
}
13571378
return rc;
13581379
}
13591380
13601381
/*
13611382
--- src/th_lang.c
+++ src/th_lang.c
@@ -39,11 +39,11 @@
39
40 rc = Th_Eval(interp, 0, argv[1], -1);
41 if( argc==3 ){
42 int nResult;
43 const char *zResult = Th_GetResult(interp, &nResult);
44 Th_SetVar(interp, argv[2], argl[2], zResult, nResult);
45 }
46
47 Th_SetResultInt(interp, rc);
48 return TH_OK;
49 }
@@ -215,15 +215,18 @@
215 int *argl
216 ){
217 char *zList = 0;
218 int nList = 0;
219 int i;
 
220
221 for(i=1; i<argc; i++){
 
222 Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
223 }
224
 
225 Th_SetResult(interp, zList, nList);
226 Th_Free(interp, zList);
227
228 return TH_OK;
229 }
@@ -244,10 +247,11 @@
244 int *argl
245 ){
246 char *zList = 0;
247 int nList = 0;
248 int i, rc;
 
249
250 if( argc<2 ){
251 return Th_WrongNumArgs(interp, "lappend var ...");
252 }
253 rc = Th_GetVar(interp, argv[1], argl[1]);
@@ -254,13 +258,15 @@
254 if( rc==TH_OK ){
255 zList = Th_TakeResult(interp, &nList);
256 }
257
258 for(i=2; i<argc; i++){
 
259 Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
260 }
261
 
262 Th_SetVar(interp, argv[1], argl[1], zList, nList);
263 Th_SetResult(interp, zList, nList);
264 Th_Free(interp, zList);
265
266 return TH_OK;
@@ -561,20 +567,21 @@
561 int nUsage = 0; /* Number of bytes at zUsage */
562
563 if( argc!=4 ){
564 return Th_WrongNumArgs(interp, "proc name arglist code");
565 }
566 if( Th_SplitList(interp, argv[2], argl[2], &azParam, &anParam, &nParam) ){
 
567 return TH_ERROR;
568 }
569
570 /* Allocate the new ProcDefn structure. */
571 nByte = sizeof(ProcDefn) + /* ProcDefn structure */
572 (sizeof(char *) + sizeof(int)) * nParam + /* azParam, anParam */
573 (sizeof(char *) + sizeof(int)) * nParam + /* azDefault, anDefault */
574 argl[3] + /* zProgram */
575 argl[2]; /* Space for copies of parameter names and default values */
576 p = (ProcDefn *)Th_Malloc(interp, nByte);
577
578 /* If the last parameter in the parameter list is "args", then set the
579 ** ProcDefn.hasArgs flag. The "args" parameter does not require an
580 ** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays.
@@ -590,12 +597,12 @@
590 p->azParam = (char **)&p[1];
591 p->anParam = (int *)&p->azParam[nParam];
592 p->azDefault = (char **)&p->anParam[nParam];
593 p->anDefault = (int *)&p->azDefault[nParam];
594 p->zProgram = (char *)&p->anDefault[nParam];
595 memcpy(p->zProgram, argv[3], argl[3]);
596 p->nProgram = argl[3];
597 zSpace = &p->zProgram[p->nProgram];
598
599 for(i=0; i<nParam; i++){
600 char **az;
601 int *an;
@@ -672,11 +679,12 @@
672 int *argl
673 ){
674 if( argc!=3 ){
675 return Th_WrongNumArgs(interp, "rename oldcmd newcmd");
676 }
677 return Th_RenameCommand(interp, argv[1], argl[1], argv[2], argl[2]);
 
678 }
679
680 /*
681 ** TH Syntax:
682 **
@@ -746,13 +754,13 @@
746 if( argc!=4 ){
747 return Th_WrongNumArgs(interp, "string compare str1 str2");
748 }
749
750 zLeft = argv[2];
751 nLeft = argl[2];
752 zRight = argv[3];
753 nRight = argl[3];
754
755 for(i=0; iRes==0 && i<nLeft && i<nRight; i++){
756 iRes = zLeft[i]-zRight[i];
757 }
758 if( iRes==0 ){
@@ -779,12 +787,12 @@
779
780 if( argc!=4 ){
781 return Th_WrongNumArgs(interp, "string first needle haystack");
782 }
783
784 nNeedle = argl[2];
785 nHaystack = argl[3];
786
787 if( nNeedle && nHaystack && nNeedle<=nHaystack ){
788 const char *zNeedle = argv[2];
789 const char *zHaystack = argv[3];
790 int i;
@@ -812,19 +820,19 @@
812
813 if( argc!=4 ){
814 return Th_WrongNumArgs(interp, "string index string index");
815 }
816
817 if( argl[3]==3 && 0==memcmp("end", argv[3], 3) ){
818 iIndex = argl[2]-1;
819 }else if( Th_ToInt(interp, argv[3], argl[3], &iIndex) ){
820 Th_ErrorMessage(
821 interp, "Expected \"end\" or integer, got:", argv[3], argl[3]);
822 return TH_ERROR;
823 }
824
825 if( iIndex>=0 && iIndex<argl[2] ){
826 return Th_SetResult(interp, &argv[2][iIndex], 1);
827 }else{
828 return Th_SetResult(interp, 0, 0);
829 }
830 }
@@ -838,41 +846,44 @@
838 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
839 ){
840 if( argc!=4 ){
841 return Th_WrongNumArgs(interp, "string is class string");
842 }
843 if( argl[2]==5 && 0==memcmp(argv[2], "alnum", 5) ){
844 int i;
845 int iRes = 1;
846
847 for(i=0; i<argl[3]; i++){
848 if( !th_isalnum(argv[3][i]) ){
849 iRes = 0;
850 }
851 }
852
853 return Th_SetResultInt(interp, iRes);
854 }else if( argl[2]==6 && 0==memcmp(argv[2], "double", 6) ){
855 double fVal;
856 if( Th_ToDouble(interp, argv[3], argl[3], &fVal)==TH_OK ){
857 return Th_SetResultInt(interp, 1);
858 }
859 return Th_SetResultInt(interp, 0);
860 }else if( argl[2]==7 && 0==memcmp(argv[2], "integer", 7) ){
861 int iVal;
862 if( Th_ToInt(interp, argv[3], argl[3], &iVal)==TH_OK ){
863 return Th_SetResultInt(interp, 1);
864 }
865 return Th_SetResultInt(interp, 0);
866 }else if( argl[2]==4 && 0==memcmp(argv[2], "list", 4) ){
867 if( Th_SplitList(interp, argv[3], argl[3], 0, 0, 0)==TH_OK ){
868 return Th_SetResultInt(interp, 1);
869 }
870 return Th_SetResultInt(interp, 0);
 
 
871 }else{
872 Th_ErrorMessage(interp,
873 "Expected alnum, double, integer, or list, got:", argv[2], argl[2]);
 
874 return TH_ERROR;
875 }
876 }
877
878 /*
@@ -889,12 +900,12 @@
889
890 if( argc!=4 ){
891 return Th_WrongNumArgs(interp, "string last needle haystack");
892 }
893
894 nNeedle = argl[2];
895 nHaystack = argl[3];
896
897 if( nNeedle && nHaystack && nNeedle<=nHaystack ){
898 const char *zNeedle = argv[2];
899 const char *zHaystack = argv[3];
900 int i;
@@ -919,11 +930,11 @@
919 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
920 ){
921 if( argc!=3 ){
922 return Th_WrongNumArgs(interp, "string length string");
923 }
924 return Th_SetResultInt(interp, argl[2]);
925 }
926
927 /*
928 ** TH Syntax:
929 **
@@ -938,12 +949,12 @@
938 char *zPat, *zStr;
939 int rc;
940 if( argc!=4 ){
941 return Th_WrongNumArgs(interp, "string match pattern string");
942 }
943 zPat = fossil_strndup(argv[2],argl[2]);
944 zStr = fossil_strndup(argv[3],argl[3]);
945 rc = sqlite3_strglob(zPat,zStr);
946 fossil_free(zPat);
947 fossil_free(zStr);
948 return Th_SetResultInt(interp, !rc);
949 }
@@ -961,23 +972,23 @@
961
962 if( argc!=5 ){
963 return Th_WrongNumArgs(interp, "string range string first last");
964 }
965
966 if( argl[4]==3 && 0==memcmp("end", argv[4], 3) ){
967 iEnd = argl[2];
968 }else if( Th_ToInt(interp, argv[4], argl[4], &iEnd) ){
969 Th_ErrorMessage(
970 interp, "Expected \"end\" or integer, got:", argv[4], argl[4]);
971 return TH_ERROR;
972 }
973 if( Th_ToInt(interp, argv[3], argl[3], &iStart) ){
974 return TH_ERROR;
975 }
976
977 if( iStart<0 ) iStart = 0;
978 if( iEnd>=argl[2] ) iEnd = argl[2]-1;
979 if( iStart>iEnd ) iEnd = iStart-1;
980
981 return Th_SetResult(interp, &argv[2][iStart], iEnd-iStart+1);
982 }
983
@@ -989,27 +1000,33 @@
989 static int string_repeat_command(
990 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
991 ){
992 int n;
993 int i;
994 int nByte;
 
995 char *zByte;
996
997 if( argc!=4 ){
998 return Th_WrongNumArgs(interp, "string repeat string n");
999 }
1000 if( Th_ToInt(interp, argv[3], argl[3], &n) ){
1001 return TH_ERROR;
1002 }
1003
1004 nByte = argl[2] * n;
 
 
 
1005 zByte = Th_Malloc(interp, nByte+1);
1006 for(i=0; i<nByte; i+=argl[2]){
1007 memcpy(&zByte[i], argv[2], argl[2]);
1008 }
1009
1010 Th_SetResult(interp, zByte, nByte);
 
 
1011 Th_Free(interp, zByte);
1012 return TH_OK;
1013 }
1014
1015 /*
@@ -1027,15 +1044,15 @@
1027
1028 if( argc!=3 ){
1029 return Th_WrongNumArgs(interp, "string trim string");
1030 }
1031 z = argv[2];
1032 n = argl[2];
1033 if( argl[1]<5 || argv[1][4]=='l' ){
1034 while( n && th_isspace(z[0]) ){ z++; n--; }
1035 }
1036 if( argl[1]<5 || argv[1][4]=='r' ){
1037 while( n && th_isspace(z[n-1]) ){ n--; }
1038 }
1039 Th_SetResult(interp, z, n);
1040 return TH_OK;
1041 }
@@ -1051,11 +1068,11 @@
1051 int rc;
1052
1053 if( argc!=3 ){
1054 return Th_WrongNumArgs(interp, "info exists var");
1055 }
1056 rc = Th_ExistsVar(interp, argv[2], argl[2]);
1057 Th_SetResultInt(interp, rc);
1058 return TH_OK;
1059 }
1060
1061 /*
@@ -1117,11 +1134,11 @@
1117 int rc;
1118
1119 if( argc!=3 ){
1120 return Th_WrongNumArgs(interp, "array exists var");
1121 }
1122 rc = Th_ExistsArrayVar(interp, argv[2], argl[2]);
1123 Th_SetResultInt(interp, rc);
1124 return TH_OK;
1125 }
1126
1127 /*
@@ -1137,11 +1154,11 @@
1137 int nElem = 0;
1138
1139 if( argc!=3 ){
1140 return Th_WrongNumArgs(interp, "array names varname");
1141 }
1142 rc = Th_ListAppendArray(interp, argv[2], argl[2], &zElem, &nElem);
1143 if( rc!=TH_OK ){
1144 return rc;
1145 }
1146 Th_SetResult(interp, zElem, nElem);
1147 if( zElem ) Th_Free(interp, zElem);
@@ -1161,11 +1178,11 @@
1161 int *argl
1162 ){
1163 if( argc!=2 ){
1164 return Th_WrongNumArgs(interp, "unset var");
1165 }
1166 return Th_UnsetVar(interp, argv[1], argl[1]);
1167 }
1168
1169 int Th_CallSubCommand(
1170 Th_Interp *interp,
1171 void *ctx,
@@ -1176,19 +1193,22 @@
1176 ){
1177 if( argc>1 ){
1178 int i;
1179 for(i=0; aSub[i].zName; i++){
1180 const char *zName = aSub[i].zName;
1181 if( th_strlen(zName)==argl[1] && 0==memcmp(zName, argv[1], argl[1]) ){
 
1182 return aSub[i].xProc(interp, ctx, argc, argv, argl);
1183 }
1184 }
1185 }
1186 if(argc<2){
1187 Th_ErrorMessage(interp, "Expected sub-command for", argv[0], argl[0]);
 
1188 }else{
1189 Th_ErrorMessage(interp, "Expected sub-command, got:", argv[1], argl[1]);
 
1190 }
1191 return TH_ERROR;
1192 }
1193
1194 /*
@@ -1319,11 +1339,11 @@
1319 int iFrame = -1;
1320
1321 if( argc!=2 && argc!=3 ){
1322 return Th_WrongNumArgs(interp, "uplevel ?level? script...");
1323 }
1324 if( argc==3 && TH_OK!=thToFrame(interp, argv[1], argl[1], &iFrame) ){
1325 return TH_ERROR;
1326 }
1327 return Th_Eval(interp, iFrame, argv[argc-1], -1);
1328 }
1329
@@ -1342,19 +1362,20 @@
1342 int iVar = 1;
1343 int iFrame = -1;
1344 int rc = TH_OK;
1345 int i;
1346
1347 if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){
1348 iVar++;
1349 }
1350 if( argc==iVar || (argc-iVar)%2 ){
1351 return Th_WrongNumArgs(interp,
1352 "upvar frame othervar myvar ?othervar myvar...?");
1353 }
1354 for(i=iVar; rc==TH_OK && i<argc; i=i+2){
1355 rc = Th_LinkVar(interp, argv[i+1], argl[i+1], iFrame, argv[i], argl[i]);
 
1356 }
1357 return rc;
1358 }
1359
1360 /*
1361
--- src/th_lang.c
+++ src/th_lang.c
@@ -39,11 +39,11 @@
39
40 rc = Th_Eval(interp, 0, argv[1], -1);
41 if( argc==3 ){
42 int nResult;
43 const char *zResult = Th_GetResult(interp, &nResult);
44 Th_SetVar(interp, argv[2], TH1_LEN(argl[2]), zResult, nResult);
45 }
46
47 Th_SetResultInt(interp, rc);
48 return TH_OK;
49 }
@@ -215,15 +215,18 @@
215 int *argl
216 ){
217 char *zList = 0;
218 int nList = 0;
219 int i;
220 int bTaint = 0;
221
222 for(i=1; i<argc; i++){
223 TH1_XFER_TAINT(bTaint,argl[i]);
224 Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
225 }
226
227 TH1_XFER_TAINT(nList, bTaint);
228 Th_SetResult(interp, zList, nList);
229 Th_Free(interp, zList);
230
231 return TH_OK;
232 }
@@ -244,10 +247,11 @@
247 int *argl
248 ){
249 char *zList = 0;
250 int nList = 0;
251 int i, rc;
252 int bTaint = 0;
253
254 if( argc<2 ){
255 return Th_WrongNumArgs(interp, "lappend var ...");
256 }
257 rc = Th_GetVar(interp, argv[1], argl[1]);
@@ -254,13 +258,15 @@
258 if( rc==TH_OK ){
259 zList = Th_TakeResult(interp, &nList);
260 }
261
262 for(i=2; i<argc; i++){
263 TH1_XFER_TAINT(bTaint, argl[i]);
264 Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
265 }
266
267 TH1_XFER_TAINT(nList, bTaint);
268 Th_SetVar(interp, argv[1], argl[1], zList, nList);
269 Th_SetResult(interp, zList, nList);
270 Th_Free(interp, zList);
271
272 return TH_OK;
@@ -561,20 +567,21 @@
567 int nUsage = 0; /* Number of bytes at zUsage */
568
569 if( argc!=4 ){
570 return Th_WrongNumArgs(interp, "proc name arglist code");
571 }
572 if( Th_SplitList(interp, argv[2], TH1_LEN(argl[2]),
573 &azParam, &anParam, &nParam) ){
574 return TH_ERROR;
575 }
576
577 /* Allocate the new ProcDefn structure. */
578 nByte = sizeof(ProcDefn) + /* ProcDefn structure */
579 (sizeof(char *) + sizeof(int)) * nParam + /* azParam, anParam */
580 (sizeof(char *) + sizeof(int)) * nParam + /* azDefault, anDefault */
581 TH1_LEN(argl[3]) + /* zProgram */
582 TH1_LEN(argl[2]); /* Space for copies of param names and dflt values */
583 p = (ProcDefn *)Th_Malloc(interp, nByte);
584
585 /* If the last parameter in the parameter list is "args", then set the
586 ** ProcDefn.hasArgs flag. The "args" parameter does not require an
587 ** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays.
@@ -590,12 +597,12 @@
597 p->azParam = (char **)&p[1];
598 p->anParam = (int *)&p->azParam[nParam];
599 p->azDefault = (char **)&p->anParam[nParam];
600 p->anDefault = (int *)&p->azDefault[nParam];
601 p->zProgram = (char *)&p->anDefault[nParam];
602 memcpy(p->zProgram, argv[3], TH1_LEN(argl[3]));
603 p->nProgram = TH1_LEN(argl[3]);
604 zSpace = &p->zProgram[p->nProgram];
605
606 for(i=0; i<nParam; i++){
607 char **az;
608 int *an;
@@ -672,11 +679,12 @@
679 int *argl
680 ){
681 if( argc!=3 ){
682 return Th_WrongNumArgs(interp, "rename oldcmd newcmd");
683 }
684 return Th_RenameCommand(interp, argv[1], TH1_LEN(argl[1]),
685 argv[2], TH1_LEN(argl[2]));
686 }
687
688 /*
689 ** TH Syntax:
690 **
@@ -746,13 +754,13 @@
754 if( argc!=4 ){
755 return Th_WrongNumArgs(interp, "string compare str1 str2");
756 }
757
758 zLeft = argv[2];
759 nLeft = TH1_LEN(argl[2]);
760 zRight = argv[3];
761 nRight = TH1_LEN(argl[3]);
762
763 for(i=0; iRes==0 && i<nLeft && i<nRight; i++){
764 iRes = zLeft[i]-zRight[i];
765 }
766 if( iRes==0 ){
@@ -779,12 +787,12 @@
787
788 if( argc!=4 ){
789 return Th_WrongNumArgs(interp, "string first needle haystack");
790 }
791
792 nNeedle = TH1_LEN(argl[2]);
793 nHaystack = TH1_LEN(argl[3]);
794
795 if( nNeedle && nHaystack && nNeedle<=nHaystack ){
796 const char *zNeedle = argv[2];
797 const char *zHaystack = argv[3];
798 int i;
@@ -812,19 +820,19 @@
820
821 if( argc!=4 ){
822 return Th_WrongNumArgs(interp, "string index string index");
823 }
824
825 if( TH1_LEN(argl[3])==3 && 0==memcmp("end", argv[3], 3) ){
826 iIndex = TH1_LEN(argl[2])-1;
827 }else if( Th_ToInt(interp, argv[3], argl[3], &iIndex) ){
828 Th_ErrorMessage(
829 interp, "Expected \"end\" or integer, got:", argv[3], argl[3]);
830 return TH_ERROR;
831 }
832
833 if( iIndex>=0 && iIndex<TH1_LEN(argl[2]) ){
834 return Th_SetResult(interp, &argv[2][iIndex], 1);
835 }else{
836 return Th_SetResult(interp, 0, 0);
837 }
838 }
@@ -838,41 +846,44 @@
846 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
847 ){
848 if( argc!=4 ){
849 return Th_WrongNumArgs(interp, "string is class string");
850 }
851 if( TH1_LEN(argl[2])==5 && 0==memcmp(argv[2], "alnum", 5) ){
852 int i;
853 int iRes = 1;
854
855 for(i=0; i<TH1_LEN(argl[3]); i++){
856 if( !th_isalnum(argv[3][i]) ){
857 iRes = 0;
858 }
859 }
860
861 return Th_SetResultInt(interp, iRes);
862 }else if( TH1_LEN(argl[2])==6 && 0==memcmp(argv[2], "double", 6) ){
863 double fVal;
864 if( Th_ToDouble(interp, argv[3], argl[3], &fVal)==TH_OK ){
865 return Th_SetResultInt(interp, 1);
866 }
867 return Th_SetResultInt(interp, 0);
868 }else if( TH1_LEN(argl[2])==7 && 0==memcmp(argv[2], "integer", 7) ){
869 int iVal;
870 if( Th_ToInt(interp, argv[3], argl[3], &iVal)==TH_OK ){
871 return Th_SetResultInt(interp, 1);
872 }
873 return Th_SetResultInt(interp, 0);
874 }else if( TH1_LEN(argl[2])==4 && 0==memcmp(argv[2], "list", 4) ){
875 if( Th_SplitList(interp, argv[3], argl[3], 0, 0, 0)==TH_OK ){
876 return Th_SetResultInt(interp, 1);
877 }
878 return Th_SetResultInt(interp, 0);
879 }else if( TH1_LEN(argl[2])==7 && 0==memcmp(argv[2], "tainted", 7) ){
880 return Th_SetResultInt(interp, TH1_TAINTED(argl[3]));
881 }else{
882 Th_ErrorMessage(interp,
883 "Expected alnum, double, integer, list, or tainted, got:",
884 argv[2], TH1_LEN(argl[2]));
885 return TH_ERROR;
886 }
887 }
888
889 /*
@@ -889,12 +900,12 @@
900
901 if( argc!=4 ){
902 return Th_WrongNumArgs(interp, "string last needle haystack");
903 }
904
905 nNeedle = TH1_LEN(argl[2]);
906 nHaystack = TH1_LEN(argl[3]);
907
908 if( nNeedle && nHaystack && nNeedle<=nHaystack ){
909 const char *zNeedle = argv[2];
910 const char *zHaystack = argv[3];
911 int i;
@@ -919,11 +930,11 @@
930 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
931 ){
932 if( argc!=3 ){
933 return Th_WrongNumArgs(interp, "string length string");
934 }
935 return Th_SetResultInt(interp, TH1_LEN(argl[2]));
936 }
937
938 /*
939 ** TH Syntax:
940 **
@@ -938,12 +949,12 @@
949 char *zPat, *zStr;
950 int rc;
951 if( argc!=4 ){
952 return Th_WrongNumArgs(interp, "string match pattern string");
953 }
954 zPat = fossil_strndup(argv[2],TH1_LEN(argl[2]));
955 zStr = fossil_strndup(argv[3],TH1_LEN(argl[3]));
956 rc = sqlite3_strglob(zPat,zStr);
957 fossil_free(zPat);
958 fossil_free(zStr);
959 return Th_SetResultInt(interp, !rc);
960 }
@@ -961,23 +972,23 @@
972
973 if( argc!=5 ){
974 return Th_WrongNumArgs(interp, "string range string first last");
975 }
976
977 if( TH1_LEN(argl[4])==3 && 0==memcmp("end", argv[4], 3) ){
978 iEnd = TH1_LEN(argl[2]);
979 }else if( Th_ToInt(interp, argv[4], argl[4], &iEnd) ){
980 Th_ErrorMessage(
981 interp, "Expected \"end\" or integer, got:", argv[4], TH1_LEN(argl[4]));
982 return TH_ERROR;
983 }
984 if( Th_ToInt(interp, argv[3], argl[3], &iStart) ){
985 return TH_ERROR;
986 }
987
988 if( iStart<0 ) iStart = 0;
989 if( iEnd>=TH1_LEN(argl[2]) ) iEnd = TH1_LEN(argl[2])-1;
990 if( iStart>iEnd ) iEnd = iStart-1;
991
992 return Th_SetResult(interp, &argv[2][iStart], iEnd-iStart+1);
993 }
994
@@ -989,27 +1000,33 @@
1000 static int string_repeat_command(
1001 Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
1002 ){
1003 int n;
1004 int i;
1005 int sz;
1006 long long int nByte;
1007 char *zByte;
1008
1009 if( argc!=4 ){
1010 return Th_WrongNumArgs(interp, "string repeat string n");
1011 }
1012 if( Th_ToInt(interp, argv[3], argl[3], &n) ){
1013 return TH_ERROR;
1014 }
1015
1016 nByte = n;
1017 sz = TH1_LEN(argl[2]);
1018 nByte *= sz;
1019 TH1_SIZECHECK(nByte+1);
1020 zByte = Th_Malloc(interp, nByte+1);
1021 for(i=0; i<nByte; i+=sz){
1022 memcpy(&zByte[i], argv[2], sz);
1023 }
1024
1025 n = nByte;
1026 TH1_XFER_TAINT(n, argl[2]);
1027 Th_SetResult(interp, zByte, n);
1028 Th_Free(interp, zByte);
1029 return TH_OK;
1030 }
1031
1032 /*
@@ -1027,15 +1044,15 @@
1044
1045 if( argc!=3 ){
1046 return Th_WrongNumArgs(interp, "string trim string");
1047 }
1048 z = argv[2];
1049 n = TH1_LEN(argl[2]);
1050 if( TH1_LEN(argl[1])<5 || argv[1][4]=='l' ){
1051 while( n && th_isspace(z[0]) ){ z++; n--; }
1052 }
1053 if( TH1_LEN(argl[1])<5 || argv[1][4]=='r' ){
1054 while( n && th_isspace(z[n-1]) ){ n--; }
1055 }
1056 Th_SetResult(interp, z, n);
1057 return TH_OK;
1058 }
@@ -1051,11 +1068,11 @@
1068 int rc;
1069
1070 if( argc!=3 ){
1071 return Th_WrongNumArgs(interp, "info exists var");
1072 }
1073 rc = Th_ExistsVar(interp, argv[2], TH1_LEN(argl[2]));
1074 Th_SetResultInt(interp, rc);
1075 return TH_OK;
1076 }
1077
1078 /*
@@ -1117,11 +1134,11 @@
1134 int rc;
1135
1136 if( argc!=3 ){
1137 return Th_WrongNumArgs(interp, "array exists var");
1138 }
1139 rc = Th_ExistsArrayVar(interp, argv[2], TH1_LEN(argl[2]));
1140 Th_SetResultInt(interp, rc);
1141 return TH_OK;
1142 }
1143
1144 /*
@@ -1137,11 +1154,11 @@
1154 int nElem = 0;
1155
1156 if( argc!=3 ){
1157 return Th_WrongNumArgs(interp, "array names varname");
1158 }
1159 rc = Th_ListAppendArray(interp, argv[2], TH1_LEN(argl[2]), &zElem, &nElem);
1160 if( rc!=TH_OK ){
1161 return rc;
1162 }
1163 Th_SetResult(interp, zElem, nElem);
1164 if( zElem ) Th_Free(interp, zElem);
@@ -1161,11 +1178,11 @@
1178 int *argl
1179 ){
1180 if( argc!=2 ){
1181 return Th_WrongNumArgs(interp, "unset var");
1182 }
1183 return Th_UnsetVar(interp, argv[1], TH1_LEN(argl[1]));
1184 }
1185
1186 int Th_CallSubCommand(
1187 Th_Interp *interp,
1188 void *ctx,
@@ -1176,19 +1193,22 @@
1193 ){
1194 if( argc>1 ){
1195 int i;
1196 for(i=0; aSub[i].zName; i++){
1197 const char *zName = aSub[i].zName;
1198 if( th_strlen(zName)==TH1_LEN(argl[1])
1199 && 0==memcmp(zName, argv[1], TH1_LEN(argl[1])) ){
1200 return aSub[i].xProc(interp, ctx, argc, argv, argl);
1201 }
1202 }
1203 }
1204 if(argc<2){
1205 Th_ErrorMessage(interp, "Expected sub-command for",
1206 argv[0], TH1_LEN(argl[0]));
1207 }else{
1208 Th_ErrorMessage(interp, "Expected sub-command, got:",
1209 argv[1], TH1_LEN(argl[1]));
1210 }
1211 return TH_ERROR;
1212 }
1213
1214 /*
@@ -1319,11 +1339,11 @@
1339 int iFrame = -1;
1340
1341 if( argc!=2 && argc!=3 ){
1342 return Th_WrongNumArgs(interp, "uplevel ?level? script...");
1343 }
1344 if( argc==3 && TH_OK!=thToFrame(interp, argv[1], TH1_LEN(argl[1]), &iFrame) ){
1345 return TH_ERROR;
1346 }
1347 return Th_Eval(interp, iFrame, argv[argc-1], -1);
1348 }
1349
@@ -1342,19 +1362,20 @@
1362 int iVar = 1;
1363 int iFrame = -1;
1364 int rc = TH_OK;
1365 int i;
1366
1367 if( TH_OK==thToFrame(0, argv[1], TH1_LEN(argl[1]), &iFrame) ){
1368 iVar++;
1369 }
1370 if( argc==iVar || (argc-iVar)%2 ){
1371 return Th_WrongNumArgs(interp,
1372 "upvar frame othervar myvar ?othervar myvar...?");
1373 }
1374 for(i=iVar; rc==TH_OK && i<argc; i=i+2){
1375 rc = Th_LinkVar(interp, argv[i+1], TH1_LEN(argl[i+1]),
1376 iFrame, argv[i], TH1_LEN(argl[i]));
1377 }
1378 return rc;
1379 }
1380
1381 /*
1382
+51 -30
--- src/th_main.c
+++ src/th_main.c
@@ -262,11 +262,11 @@
262262
){
263263
char *zOut;
264264
if( argc!=2 ){
265265
return Th_WrongNumArgs(interp, "httpize STRING");
266266
}
267
- zOut = httpize((char*)argv[1], argl[1]);
267
+ zOut = httpize((char*)argv[1], TH1_LEN(argl[1]));
268268
Th_SetResult(interp, zOut, -1);
269269
free(zOut);
270270
return TH_OK;
271271
}
272272
@@ -291,11 +291,12 @@
291291
if( argc<2 || argc>3 ){
292292
return Th_WrongNumArgs(interp, "enable_output [LABEL] BOOLEAN");
293293
}
294294
rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &enableOutput);
295295
if( g.thTrace ){
296
- Th_Trace("enable_output {%.*s} -> %d<br>\n", argl[1],argv[1],enableOutput);
296
+ Th_Trace("enable_output {%.*s} -> %d<br>\n",
297
+ TH1_LEN(argl[1]),argv[1],enableOutput);
297298
}
298299
return rc;
299300
}
300301
301302
/*
@@ -322,11 +323,11 @@
322323
buul = (TH_INIT_NO_ENCODE & g.th1Flags) ? 0 : 1;
323324
Th_SetResultInt(g.interp, buul);
324325
if(argc>1){
325326
if( g.thTrace ){
326327
Th_Trace("enable_htmlify {%.*s} -> %d<br>\n",
327
- argl[1],argv[1],buul);
328
+ TH1_LEN(argl[1]),argv[1],buul);
328329
}
329330
rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &buul);
330331
if(!rc){
331332
if(buul){
332333
g.th1Flags &= ~TH_INIT_NO_ENCODE;
@@ -387,13 +388,20 @@
387388
if(0==pOut && pThOut!=0){
388389
pOut = pThOut;
389390
}
390391
if(TH_INIT_NO_ENCODE & g.th1Flags){
391392
encode = 0;
393
+ if( TH1_TAINTED(n) && Th_ReportTaint(0, "output string", z, n) ){
394
+ return;
395
+ }
392396
}
393397
if( enableOutput && n ){
394
- if( n<0 ) n = strlen(z);
398
+ if( n<0 ){
399
+ n = strlen(z);
400
+ }else{
401
+ n = TH1_LEN(n);
402
+ }
395403
if( encode ){
396404
z = htmlize(z, n);
397405
n = strlen(z);
398406
}
399407
if(pOut!=0){
@@ -558,10 +566,15 @@
558566
if( argc==3 ){
559567
if( Th_ToInt(interp, argv[2], argl[2], &withMethod) ){
560568
return TH_ERROR;
561569
}
562570
}
571
+ if( TH1_TAINTED(argl[1])
572
+ && Th_ReportTaint(interp,"redirect URL",argv[1],argl[1])
573
+ ){
574
+ return TH_ERROR;
575
+ }
563576
if( withMethod ){
564577
cgi_redirect_with_method(argv[1]);
565578
}else{
566579
cgi_redirect(argv[1]);
567580
}
@@ -660,11 +673,11 @@
660673
int nValue = 0;
661674
if( argc!=2 ){
662675
return Th_WrongNumArgs(interp, "markdown STRING");
663676
}
664677
blob_zero(&src);
665
- blob_init(&src, (char*)argv[1], argl[1]);
678
+ blob_init(&src, (char*)argv[1], TH1_LEN(argl[1]));
666679
blob_zero(&title); blob_zero(&body);
667680
markdown_to_html(&src, &title, &body);
668681
Th_ListAppend(interp, &zValue, &nValue, blob_str(&title), blob_size(&title));
669682
Th_ListAppend(interp, &zValue, &nValue, blob_str(&body), blob_size(&body));
670683
Th_SetResult(interp, zValue, nValue);
@@ -690,11 +703,11 @@
690703
if( argc!=2 ){
691704
return Th_WrongNumArgs(interp, "wiki STRING");
692705
}
693706
if( enableOutput ){
694707
Blob src;
695
- blob_init(&src, (char*)argv[1], argl[1]);
708
+ blob_init(&src, (char*)argv[1], TH1_LEN(argl[1]));
696709
wiki_convert(&src, 0, flags);
697710
blob_reset(&src);
698711
}
699712
return TH_OK;
700713
}
@@ -735,11 +748,11 @@
735748
){
736749
char *zOut;
737750
if( argc!=2 ){
738751
return Th_WrongNumArgs(interp, "htmlize STRING");
739752
}
740
- zOut = htmlize((char*)argv[1], argl[1]);
753
+ zOut = htmlize((char*)argv[1], TH1_LEN(argl[1]));
741754
Th_SetResult(interp, zOut, -1);
742755
free(zOut);
743756
return TH_OK;
744757
}
745758
@@ -757,11 +770,11 @@
757770
){
758771
char *zOut;
759772
if( argc!=2 ){
760773
return Th_WrongNumArgs(interp, "encode64 STRING");
761774
}
762
- zOut = encode64((char*)argv[1], argl[1]);
775
+ zOut = encode64((char*)argv[1], TH1_LEN(argl[1]));
763776
Th_SetResult(interp, zOut, -1);
764777
free(zOut);
765778
return TH_OK;
766779
}
767780
@@ -778,11 +791,11 @@
778791
int argc,
779792
const char **argv,
780793
int *argl
781794
){
782795
char *zOut;
783
- if( argc>=2 && argl[1]==6 && memcmp(argv[1],"-local",6)==0 ){
796
+ if( argc>=2 && TH1_LEN(argl[1])==6 && memcmp(argv[1],"-local",6)==0 ){
784797
zOut = db_text("??", "SELECT datetime('now',toLocal())");
785798
}else{
786799
zOut = db_text("??", "SELECT datetime('now')");
787800
}
788801
Th_SetResult(interp, zOut, -1);
@@ -810,13 +823,13 @@
810823
if( argc<2 ){
811824
return Th_WrongNumArgs(interp, "hascap STRING ...");
812825
}
813826
for(i=1; rc==1 && i<argc; i++){
814827
if( g.thTrace ){
815
- Th_ListAppend(interp, &zCapList, &nCapList, argv[i], argl[i]);
828
+ Th_ListAppend(interp, &zCapList, &nCapList, argv[i], TH1_LEN(argl[i]));
816829
}
817
- rc = login_has_capability((char*)argv[i],argl[i],*(int*)p);
830
+ rc = login_has_capability((char*)argv[i],TH1_LEN(argl[i]),*(int*)p);
818831
}
819832
if( g.thTrace ){
820833
Th_Trace("[%s %#h] => %d<br>\n", argv[0], nCapList, zCapList, rc);
821834
Th_Free(interp, zCapList);
822835
}
@@ -858,11 +871,11 @@
858871
int i;
859872
860873
if( argc!=2 ){
861874
return Th_WrongNumArgs(interp, "capexpr EXPR");
862875
}
863
- rc = Th_SplitList(interp, argv[1], argl[1], &azCap, &anCap, &nCap);
876
+ rc = Th_SplitList(interp, argv[1], TH1_LEN(argl[1]), &azCap, &anCap, &nCap);
864877
if( rc ) return rc;
865878
rc = 0;
866879
for(i=0; i<nCap; i++){
867880
if( azCap[i][0]=='!' ){
868881
rc = !login_has_capability(azCap[i]+1, anCap[i]-1, 0);
@@ -921,11 +934,12 @@
921934
if( argc<2 ){
922935
return Th_WrongNumArgs(interp, "hascap STRING ...");
923936
}
924937
for(i=1; i<argc && rc; i++){
925938
int match = 0;
926
- for(j=0; j<argl[i]; j++){
939
+ int nn = TH1_LEN(argl[i]);
940
+ for(j=0; j<nn; j++){
927941
switch( argv[i][j] ){
928942
case 'c': match |= searchCap & SRCH_CKIN; break;
929943
case 'd': match |= searchCap & SRCH_DOC; break;
930944
case 't': match |= searchCap & SRCH_TKT; break;
931945
case 'w': match |= searchCap & SRCH_WIKI; break;
@@ -932,11 +946,11 @@
932946
}
933947
}
934948
if( !match ) rc = 0;
935949
}
936950
if( g.thTrace ){
937
- Th_Trace("[searchable %#h] => %d<br>\n", argl[1], argv[1], rc);
951
+ Th_Trace("[searchable %#h] => %d<br>\n", TH1_LEN(argl[1]), argv[1], rc);
938952
}
939953
Th_SetResultInt(interp, rc);
940954
return TH_OK;
941955
}
942956
@@ -1051,11 +1065,11 @@
10511065
#endif
10521066
else if( 0 == fossil_strnicmp( zArg, "markdown\0", 9 ) ){
10531067
rc = 1;
10541068
}
10551069
if( g.thTrace ){
1056
- Th_Trace("[hasfeature %#h] => %d<br>\n", argl[1], zArg, rc);
1070
+ Th_Trace("[hasfeature %#h] => %d<br>\n", TH1_LEN(argl[1]), zArg, rc);
10571071
}
10581072
Th_SetResultInt(interp, rc);
10591073
return TH_OK;
10601074
}
10611075
@@ -1104,18 +1118,20 @@
11041118
const char **argv,
11051119
int *argl
11061120
){
11071121
int rc = 0;
11081122
int i;
1123
+ int nn;
11091124
if( argc!=2 ){
11101125
return Th_WrongNumArgs(interp, "anycap STRING");
11111126
}
1112
- for(i=0; rc==0 && i<argl[1]; i++){
1127
+ nn = TH1_LEN(argl[1]);
1128
+ for(i=0; rc==0 && i<nn; i++){
11131129
rc = login_has_capability((char*)&argv[1][i],1,0);
11141130
}
11151131
if( g.thTrace ){
1116
- Th_Trace("[anycap %#h] => %d<br>\n", argl[1], argv[1], rc);
1132
+ Th_Trace("[anycap %#h] => %d<br>\n", TH1_LEN(argl[1]), argv[1], rc);
11171133
}
11181134
Th_SetResultInt(interp, rc);
11191135
return TH_OK;
11201136
}
11211137
@@ -1149,12 +1165,12 @@
11491165
int *aszElem;
11501166
char **azElem;
11511167
int i;
11521168
11531169
if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR;
1154
- Th_SplitList(interp, argv[2], argl[2], &azElem, &aszElem, &nElem);
1155
- blob_init(&name, (char*)argv[1], argl[1]);
1170
+ Th_SplitList(interp, argv[2], TH1_LEN(argl[2]), &azElem, &aszElem, &nElem);
1171
+ blob_init(&name, (char*)argv[1], TH1_LEN(argl[1]));
11561172
zValue = Th_Fetch(blob_str(&name), &nValue);
11571173
zH = htmlize(blob_buffer(&name), blob_size(&name));
11581174
z = mprintf("<select id=\"%s\" name=\"%s\" size=\"%d\">", zH, zH, height);
11591175
free(zH);
11601176
sendText(0,z, -1, 0);
@@ -1247,11 +1263,11 @@
12471263
return Th_WrongNumArgs(interp, "linecount STRING MAX MIN");
12481264
}
12491265
if( Th_ToInt(interp, argv[2], argl[2], &iMax) ) return TH_ERROR;
12501266
if( Th_ToInt(interp, argv[3], argl[3], &iMin) ) return TH_ERROR;
12511267
z = argv[1];
1252
- size = argl[1];
1268
+ size = TH1_LEN(argl[1]);
12531269
for(n=1, i=0; i<size; i++){
12541270
if( z[i]=='\n' ){
12551271
n++;
12561272
if( n>=iMax ) break;
12571273
}
@@ -1407,11 +1423,12 @@
14071423
return TH_OK;
14081424
}else if( fossil_strnicmp(argv[1], "vfs\0", 4)==0 ){
14091425
Th_SetResult(interp, g.zVfsName ? g.zVfsName : zDefault, -1);
14101426
return TH_OK;
14111427
}else{
1412
- Th_ErrorMessage(interp, "unsupported global state:", argv[1], argl[1]);
1428
+ Th_ErrorMessage(interp, "unsupported global state:",
1429
+ argv[1], TH1_LEN(argl[1]));
14131430
return TH_ERROR;
14141431
}
14151432
}
14161433
14171434
/*
@@ -1939,15 +1956,19 @@
19391956
Th_ErrorMessage(interp, "database is not open", 0, 0);
19401957
return TH_ERROR;
19411958
}
19421959
zSql = argv[1];
19431960
nSql = argl[1];
1961
+ if( TH1_TAINTED(nSql) && Th_ReportTaint(interp,"query SQL",zSql,nSql) ){
1962
+ return TH_ERROR;
1963
+ }
1964
+
19441965
while( res==TH_OK && nSql>0 ){
19451966
zErr = 0;
19461967
report_restrict_sql(&zErr);
19471968
g.dbIgnoreErrors++;
1948
- rc = sqlite3_prepare_v2(g.db, argv[1], argl[1], &pStmt, &zTail);
1969
+ rc = sqlite3_prepare_v2(g.db, argv[1], TH1_LEN(argl[1]), &pStmt, &zTail);
19491970
g.dbIgnoreErrors--;
19501971
report_unrestrict_sql();
19511972
if( rc!=0 || zErr!=0 ){
19521973
if( noComplain ) return TH_OK;
19531974
Th_ErrorMessage(interp, "SQL error: ",
@@ -1974,16 +1995,16 @@
19741995
for(i=0; i<nCol; i++){
19751996
const char *zCol = sqlite3_column_name(pStmt, i);
19761997
int szCol = th_strlen(zCol);
19771998
const char *zVal = (const char*)sqlite3_column_text(pStmt, i);
19781999
int szVal = sqlite3_column_bytes(pStmt, i);
1979
- Th_SetVar(interp, zCol, szCol, zVal, szVal);
2000
+ Th_SetVar(interp, zCol, szCol, zVal, TH1_ADD_TAINT(szVal));
19802001
}
19812002
if( g.thTrace ){
1982
- Th_Trace("query_eval {<pre>%#h</pre>}<br>\n", argl[2], argv[2]);
2003
+ Th_Trace("query_eval {<pre>%#h</pre>}<br>\n",TH1_LEN(argl[2]),argv[2]);
19832004
}
1984
- res = Th_Eval(interp, 0, argv[2], argl[2]);
2005
+ res = Th_Eval(interp, 0, argv[2], TH1_LEN(argl[2]));
19852006
if( g.thTrace ){
19862007
int nTrRes;
19872008
char *zTrRes = (char*)Th_GetResult(g.interp, &nTrRes);
19882009
Th_Trace("[query_eval] => %h {%#h}<br>\n",
19892010
Th_ReturnCodeName(res, 0), nTrRes, zTrRes);
@@ -2038,11 +2059,11 @@
20382059
Th_SetResult(interp, 0, 0);
20392060
rc = TH_OK;
20402061
}
20412062
if( g.thTrace ){
20422063
Th_Trace("[setting %s%#h] => %d<br>\n", strict ? "strict " : "",
2043
- argl[nArg], argv[nArg], rc);
2064
+ TH1_LEN(argl[nArg]), argv[nArg], rc);
20442065
}
20452066
return rc;
20462067
}
20472068
20482069
/*
@@ -2121,11 +2142,11 @@
21212142
return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS);
21222143
}
21232144
zErr = re_compile(&pRe, argv[nArg], noCase);
21242145
if( !zErr ){
21252146
Th_SetResultInt(interp, re_match(pRe,
2126
- (const unsigned char *)argv[nArg+1], argl[nArg+1]));
2147
+ (const unsigned char *)argv[nArg+1], TH1_LEN(argl[nArg+1])));
21272148
rc = TH_OK;
21282149
}else{
21292150
Th_SetResult(interp, zErr, -1);
21302151
rc = TH_ERROR;
21312152
}
@@ -2160,11 +2181,11 @@
21602181
UrlData urlData;
21612182
21622183
if( argc<2 || argc>5 ){
21632184
return Th_WrongNumArgs(interp, HTTP_WRONGNUMARGS);
21642185
}
2165
- if( fossil_strnicmp(argv[nArg], "-asynchronous", argl[nArg])==0 ){
2186
+ if( fossil_strnicmp(argv[nArg], "-asynchronous", TH1_LEN(argl[nArg]))==0 ){
21662187
fAsynchronous = 1; nArg++;
21672188
}
21682189
if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++;
21692190
if( nArg+1!=argc && nArg+2!=argc ){
21702191
return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS);
@@ -2189,11 +2210,11 @@
21892210
return TH_ERROR;
21902211
}
21912212
re_free(pRe);
21922213
blob_zero(&payload);
21932214
if( nArg+2==argc ){
2194
- blob_append(&payload, argv[nArg+1], argl[nArg+1]);
2215
+ blob_append(&payload, argv[nArg+1], TH1_LEN(argl[nArg+1]));
21952216
zType = "POST";
21962217
}else{
21972218
zType = "GET";
21982219
}
21992220
if( fAsynchronous ){
@@ -2268,11 +2289,11 @@
22682289
if( argc!=2 ){
22692290
return Th_WrongNumArgs(interp, "captureTh1 STRING");
22702291
}
22712292
pOrig = Th_SetOutputBlob(&out);
22722293
zStr = argv[1];
2273
- nStr = argl[1];
2294
+ nStr = TH1_LEN(argl[1]);
22742295
rc = Th_Eval(g.interp, 0, zStr, nStr);
22752296
Th_SetOutputBlob(pOrig);
22762297
if(0==rc){
22772298
Th_SetResult(g.interp, blob_str(&out), blob_size(&out));
22782299
}
22792300
--- src/th_main.c
+++ src/th_main.c
@@ -262,11 +262,11 @@
262 ){
263 char *zOut;
264 if( argc!=2 ){
265 return Th_WrongNumArgs(interp, "httpize STRING");
266 }
267 zOut = httpize((char*)argv[1], argl[1]);
268 Th_SetResult(interp, zOut, -1);
269 free(zOut);
270 return TH_OK;
271 }
272
@@ -291,11 +291,12 @@
291 if( argc<2 || argc>3 ){
292 return Th_WrongNumArgs(interp, "enable_output [LABEL] BOOLEAN");
293 }
294 rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &enableOutput);
295 if( g.thTrace ){
296 Th_Trace("enable_output {%.*s} -> %d<br>\n", argl[1],argv[1],enableOutput);
 
297 }
298 return rc;
299 }
300
301 /*
@@ -322,11 +323,11 @@
322 buul = (TH_INIT_NO_ENCODE & g.th1Flags) ? 0 : 1;
323 Th_SetResultInt(g.interp, buul);
324 if(argc>1){
325 if( g.thTrace ){
326 Th_Trace("enable_htmlify {%.*s} -> %d<br>\n",
327 argl[1],argv[1],buul);
328 }
329 rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &buul);
330 if(!rc){
331 if(buul){
332 g.th1Flags &= ~TH_INIT_NO_ENCODE;
@@ -387,13 +388,20 @@
387 if(0==pOut && pThOut!=0){
388 pOut = pThOut;
389 }
390 if(TH_INIT_NO_ENCODE & g.th1Flags){
391 encode = 0;
 
 
 
392 }
393 if( enableOutput && n ){
394 if( n<0 ) n = strlen(z);
 
 
 
 
395 if( encode ){
396 z = htmlize(z, n);
397 n = strlen(z);
398 }
399 if(pOut!=0){
@@ -558,10 +566,15 @@
558 if( argc==3 ){
559 if( Th_ToInt(interp, argv[2], argl[2], &withMethod) ){
560 return TH_ERROR;
561 }
562 }
 
 
 
 
 
563 if( withMethod ){
564 cgi_redirect_with_method(argv[1]);
565 }else{
566 cgi_redirect(argv[1]);
567 }
@@ -660,11 +673,11 @@
660 int nValue = 0;
661 if( argc!=2 ){
662 return Th_WrongNumArgs(interp, "markdown STRING");
663 }
664 blob_zero(&src);
665 blob_init(&src, (char*)argv[1], argl[1]);
666 blob_zero(&title); blob_zero(&body);
667 markdown_to_html(&src, &title, &body);
668 Th_ListAppend(interp, &zValue, &nValue, blob_str(&title), blob_size(&title));
669 Th_ListAppend(interp, &zValue, &nValue, blob_str(&body), blob_size(&body));
670 Th_SetResult(interp, zValue, nValue);
@@ -690,11 +703,11 @@
690 if( argc!=2 ){
691 return Th_WrongNumArgs(interp, "wiki STRING");
692 }
693 if( enableOutput ){
694 Blob src;
695 blob_init(&src, (char*)argv[1], argl[1]);
696 wiki_convert(&src, 0, flags);
697 blob_reset(&src);
698 }
699 return TH_OK;
700 }
@@ -735,11 +748,11 @@
735 ){
736 char *zOut;
737 if( argc!=2 ){
738 return Th_WrongNumArgs(interp, "htmlize STRING");
739 }
740 zOut = htmlize((char*)argv[1], argl[1]);
741 Th_SetResult(interp, zOut, -1);
742 free(zOut);
743 return TH_OK;
744 }
745
@@ -757,11 +770,11 @@
757 ){
758 char *zOut;
759 if( argc!=2 ){
760 return Th_WrongNumArgs(interp, "encode64 STRING");
761 }
762 zOut = encode64((char*)argv[1], argl[1]);
763 Th_SetResult(interp, zOut, -1);
764 free(zOut);
765 return TH_OK;
766 }
767
@@ -778,11 +791,11 @@
778 int argc,
779 const char **argv,
780 int *argl
781 ){
782 char *zOut;
783 if( argc>=2 && argl[1]==6 && memcmp(argv[1],"-local",6)==0 ){
784 zOut = db_text("??", "SELECT datetime('now',toLocal())");
785 }else{
786 zOut = db_text("??", "SELECT datetime('now')");
787 }
788 Th_SetResult(interp, zOut, -1);
@@ -810,13 +823,13 @@
810 if( argc<2 ){
811 return Th_WrongNumArgs(interp, "hascap STRING ...");
812 }
813 for(i=1; rc==1 && i<argc; i++){
814 if( g.thTrace ){
815 Th_ListAppend(interp, &zCapList, &nCapList, argv[i], argl[i]);
816 }
817 rc = login_has_capability((char*)argv[i],argl[i],*(int*)p);
818 }
819 if( g.thTrace ){
820 Th_Trace("[%s %#h] => %d<br>\n", argv[0], nCapList, zCapList, rc);
821 Th_Free(interp, zCapList);
822 }
@@ -858,11 +871,11 @@
858 int i;
859
860 if( argc!=2 ){
861 return Th_WrongNumArgs(interp, "capexpr EXPR");
862 }
863 rc = Th_SplitList(interp, argv[1], argl[1], &azCap, &anCap, &nCap);
864 if( rc ) return rc;
865 rc = 0;
866 for(i=0; i<nCap; i++){
867 if( azCap[i][0]=='!' ){
868 rc = !login_has_capability(azCap[i]+1, anCap[i]-1, 0);
@@ -921,11 +934,12 @@
921 if( argc<2 ){
922 return Th_WrongNumArgs(interp, "hascap STRING ...");
923 }
924 for(i=1; i<argc && rc; i++){
925 int match = 0;
926 for(j=0; j<argl[i]; j++){
 
927 switch( argv[i][j] ){
928 case 'c': match |= searchCap & SRCH_CKIN; break;
929 case 'd': match |= searchCap & SRCH_DOC; break;
930 case 't': match |= searchCap & SRCH_TKT; break;
931 case 'w': match |= searchCap & SRCH_WIKI; break;
@@ -932,11 +946,11 @@
932 }
933 }
934 if( !match ) rc = 0;
935 }
936 if( g.thTrace ){
937 Th_Trace("[searchable %#h] => %d<br>\n", argl[1], argv[1], rc);
938 }
939 Th_SetResultInt(interp, rc);
940 return TH_OK;
941 }
942
@@ -1051,11 +1065,11 @@
1051 #endif
1052 else if( 0 == fossil_strnicmp( zArg, "markdown\0", 9 ) ){
1053 rc = 1;
1054 }
1055 if( g.thTrace ){
1056 Th_Trace("[hasfeature %#h] => %d<br>\n", argl[1], zArg, rc);
1057 }
1058 Th_SetResultInt(interp, rc);
1059 return TH_OK;
1060 }
1061
@@ -1104,18 +1118,20 @@
1104 const char **argv,
1105 int *argl
1106 ){
1107 int rc = 0;
1108 int i;
 
1109 if( argc!=2 ){
1110 return Th_WrongNumArgs(interp, "anycap STRING");
1111 }
1112 for(i=0; rc==0 && i<argl[1]; i++){
 
1113 rc = login_has_capability((char*)&argv[1][i],1,0);
1114 }
1115 if( g.thTrace ){
1116 Th_Trace("[anycap %#h] => %d<br>\n", argl[1], argv[1], rc);
1117 }
1118 Th_SetResultInt(interp, rc);
1119 return TH_OK;
1120 }
1121
@@ -1149,12 +1165,12 @@
1149 int *aszElem;
1150 char **azElem;
1151 int i;
1152
1153 if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR;
1154 Th_SplitList(interp, argv[2], argl[2], &azElem, &aszElem, &nElem);
1155 blob_init(&name, (char*)argv[1], argl[1]);
1156 zValue = Th_Fetch(blob_str(&name), &nValue);
1157 zH = htmlize(blob_buffer(&name), blob_size(&name));
1158 z = mprintf("<select id=\"%s\" name=\"%s\" size=\"%d\">", zH, zH, height);
1159 free(zH);
1160 sendText(0,z, -1, 0);
@@ -1247,11 +1263,11 @@
1247 return Th_WrongNumArgs(interp, "linecount STRING MAX MIN");
1248 }
1249 if( Th_ToInt(interp, argv[2], argl[2], &iMax) ) return TH_ERROR;
1250 if( Th_ToInt(interp, argv[3], argl[3], &iMin) ) return TH_ERROR;
1251 z = argv[1];
1252 size = argl[1];
1253 for(n=1, i=0; i<size; i++){
1254 if( z[i]=='\n' ){
1255 n++;
1256 if( n>=iMax ) break;
1257 }
@@ -1407,11 +1423,12 @@
1407 return TH_OK;
1408 }else if( fossil_strnicmp(argv[1], "vfs\0", 4)==0 ){
1409 Th_SetResult(interp, g.zVfsName ? g.zVfsName : zDefault, -1);
1410 return TH_OK;
1411 }else{
1412 Th_ErrorMessage(interp, "unsupported global state:", argv[1], argl[1]);
 
1413 return TH_ERROR;
1414 }
1415 }
1416
1417 /*
@@ -1939,15 +1956,19 @@
1939 Th_ErrorMessage(interp, "database is not open", 0, 0);
1940 return TH_ERROR;
1941 }
1942 zSql = argv[1];
1943 nSql = argl[1];
 
 
 
 
1944 while( res==TH_OK && nSql>0 ){
1945 zErr = 0;
1946 report_restrict_sql(&zErr);
1947 g.dbIgnoreErrors++;
1948 rc = sqlite3_prepare_v2(g.db, argv[1], argl[1], &pStmt, &zTail);
1949 g.dbIgnoreErrors--;
1950 report_unrestrict_sql();
1951 if( rc!=0 || zErr!=0 ){
1952 if( noComplain ) return TH_OK;
1953 Th_ErrorMessage(interp, "SQL error: ",
@@ -1974,16 +1995,16 @@
1974 for(i=0; i<nCol; i++){
1975 const char *zCol = sqlite3_column_name(pStmt, i);
1976 int szCol = th_strlen(zCol);
1977 const char *zVal = (const char*)sqlite3_column_text(pStmt, i);
1978 int szVal = sqlite3_column_bytes(pStmt, i);
1979 Th_SetVar(interp, zCol, szCol, zVal, szVal);
1980 }
1981 if( g.thTrace ){
1982 Th_Trace("query_eval {<pre>%#h</pre>}<br>\n", argl[2], argv[2]);
1983 }
1984 res = Th_Eval(interp, 0, argv[2], argl[2]);
1985 if( g.thTrace ){
1986 int nTrRes;
1987 char *zTrRes = (char*)Th_GetResult(g.interp, &nTrRes);
1988 Th_Trace("[query_eval] => %h {%#h}<br>\n",
1989 Th_ReturnCodeName(res, 0), nTrRes, zTrRes);
@@ -2038,11 +2059,11 @@
2038 Th_SetResult(interp, 0, 0);
2039 rc = TH_OK;
2040 }
2041 if( g.thTrace ){
2042 Th_Trace("[setting %s%#h] => %d<br>\n", strict ? "strict " : "",
2043 argl[nArg], argv[nArg], rc);
2044 }
2045 return rc;
2046 }
2047
2048 /*
@@ -2121,11 +2142,11 @@
2121 return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS);
2122 }
2123 zErr = re_compile(&pRe, argv[nArg], noCase);
2124 if( !zErr ){
2125 Th_SetResultInt(interp, re_match(pRe,
2126 (const unsigned char *)argv[nArg+1], argl[nArg+1]));
2127 rc = TH_OK;
2128 }else{
2129 Th_SetResult(interp, zErr, -1);
2130 rc = TH_ERROR;
2131 }
@@ -2160,11 +2181,11 @@
2160 UrlData urlData;
2161
2162 if( argc<2 || argc>5 ){
2163 return Th_WrongNumArgs(interp, HTTP_WRONGNUMARGS);
2164 }
2165 if( fossil_strnicmp(argv[nArg], "-asynchronous", argl[nArg])==0 ){
2166 fAsynchronous = 1; nArg++;
2167 }
2168 if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++;
2169 if( nArg+1!=argc && nArg+2!=argc ){
2170 return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS);
@@ -2189,11 +2210,11 @@
2189 return TH_ERROR;
2190 }
2191 re_free(pRe);
2192 blob_zero(&payload);
2193 if( nArg+2==argc ){
2194 blob_append(&payload, argv[nArg+1], argl[nArg+1]);
2195 zType = "POST";
2196 }else{
2197 zType = "GET";
2198 }
2199 if( fAsynchronous ){
@@ -2268,11 +2289,11 @@
2268 if( argc!=2 ){
2269 return Th_WrongNumArgs(interp, "captureTh1 STRING");
2270 }
2271 pOrig = Th_SetOutputBlob(&out);
2272 zStr = argv[1];
2273 nStr = argl[1];
2274 rc = Th_Eval(g.interp, 0, zStr, nStr);
2275 Th_SetOutputBlob(pOrig);
2276 if(0==rc){
2277 Th_SetResult(g.interp, blob_str(&out), blob_size(&out));
2278 }
2279
--- src/th_main.c
+++ src/th_main.c
@@ -262,11 +262,11 @@
262 ){
263 char *zOut;
264 if( argc!=2 ){
265 return Th_WrongNumArgs(interp, "httpize STRING");
266 }
267 zOut = httpize((char*)argv[1], TH1_LEN(argl[1]));
268 Th_SetResult(interp, zOut, -1);
269 free(zOut);
270 return TH_OK;
271 }
272
@@ -291,11 +291,12 @@
291 if( argc<2 || argc>3 ){
292 return Th_WrongNumArgs(interp, "enable_output [LABEL] BOOLEAN");
293 }
294 rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &enableOutput);
295 if( g.thTrace ){
296 Th_Trace("enable_output {%.*s} -> %d<br>\n",
297 TH1_LEN(argl[1]),argv[1],enableOutput);
298 }
299 return rc;
300 }
301
302 /*
@@ -322,11 +323,11 @@
323 buul = (TH_INIT_NO_ENCODE & g.th1Flags) ? 0 : 1;
324 Th_SetResultInt(g.interp, buul);
325 if(argc>1){
326 if( g.thTrace ){
327 Th_Trace("enable_htmlify {%.*s} -> %d<br>\n",
328 TH1_LEN(argl[1]),argv[1],buul);
329 }
330 rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &buul);
331 if(!rc){
332 if(buul){
333 g.th1Flags &= ~TH_INIT_NO_ENCODE;
@@ -387,13 +388,20 @@
388 if(0==pOut && pThOut!=0){
389 pOut = pThOut;
390 }
391 if(TH_INIT_NO_ENCODE & g.th1Flags){
392 encode = 0;
393 if( TH1_TAINTED(n) && Th_ReportTaint(0, "output string", z, n) ){
394 return;
395 }
396 }
397 if( enableOutput && n ){
398 if( n<0 ){
399 n = strlen(z);
400 }else{
401 n = TH1_LEN(n);
402 }
403 if( encode ){
404 z = htmlize(z, n);
405 n = strlen(z);
406 }
407 if(pOut!=0){
@@ -558,10 +566,15 @@
566 if( argc==3 ){
567 if( Th_ToInt(interp, argv[2], argl[2], &withMethod) ){
568 return TH_ERROR;
569 }
570 }
571 if( TH1_TAINTED(argl[1])
572 && Th_ReportTaint(interp,"redirect URL",argv[1],argl[1])
573 ){
574 return TH_ERROR;
575 }
576 if( withMethod ){
577 cgi_redirect_with_method(argv[1]);
578 }else{
579 cgi_redirect(argv[1]);
580 }
@@ -660,11 +673,11 @@
673 int nValue = 0;
674 if( argc!=2 ){
675 return Th_WrongNumArgs(interp, "markdown STRING");
676 }
677 blob_zero(&src);
678 blob_init(&src, (char*)argv[1], TH1_LEN(argl[1]));
679 blob_zero(&title); blob_zero(&body);
680 markdown_to_html(&src, &title, &body);
681 Th_ListAppend(interp, &zValue, &nValue, blob_str(&title), blob_size(&title));
682 Th_ListAppend(interp, &zValue, &nValue, blob_str(&body), blob_size(&body));
683 Th_SetResult(interp, zValue, nValue);
@@ -690,11 +703,11 @@
703 if( argc!=2 ){
704 return Th_WrongNumArgs(interp, "wiki STRING");
705 }
706 if( enableOutput ){
707 Blob src;
708 blob_init(&src, (char*)argv[1], TH1_LEN(argl[1]));
709 wiki_convert(&src, 0, flags);
710 blob_reset(&src);
711 }
712 return TH_OK;
713 }
@@ -735,11 +748,11 @@
748 ){
749 char *zOut;
750 if( argc!=2 ){
751 return Th_WrongNumArgs(interp, "htmlize STRING");
752 }
753 zOut = htmlize((char*)argv[1], TH1_LEN(argl[1]));
754 Th_SetResult(interp, zOut, -1);
755 free(zOut);
756 return TH_OK;
757 }
758
@@ -757,11 +770,11 @@
770 ){
771 char *zOut;
772 if( argc!=2 ){
773 return Th_WrongNumArgs(interp, "encode64 STRING");
774 }
775 zOut = encode64((char*)argv[1], TH1_LEN(argl[1]));
776 Th_SetResult(interp, zOut, -1);
777 free(zOut);
778 return TH_OK;
779 }
780
@@ -778,11 +791,11 @@
791 int argc,
792 const char **argv,
793 int *argl
794 ){
795 char *zOut;
796 if( argc>=2 && TH1_LEN(argl[1])==6 && memcmp(argv[1],"-local",6)==0 ){
797 zOut = db_text("??", "SELECT datetime('now',toLocal())");
798 }else{
799 zOut = db_text("??", "SELECT datetime('now')");
800 }
801 Th_SetResult(interp, zOut, -1);
@@ -810,13 +823,13 @@
823 if( argc<2 ){
824 return Th_WrongNumArgs(interp, "hascap STRING ...");
825 }
826 for(i=1; rc==1 && i<argc; i++){
827 if( g.thTrace ){
828 Th_ListAppend(interp, &zCapList, &nCapList, argv[i], TH1_LEN(argl[i]));
829 }
830 rc = login_has_capability((char*)argv[i],TH1_LEN(argl[i]),*(int*)p);
831 }
832 if( g.thTrace ){
833 Th_Trace("[%s %#h] => %d<br>\n", argv[0], nCapList, zCapList, rc);
834 Th_Free(interp, zCapList);
835 }
@@ -858,11 +871,11 @@
871 int i;
872
873 if( argc!=2 ){
874 return Th_WrongNumArgs(interp, "capexpr EXPR");
875 }
876 rc = Th_SplitList(interp, argv[1], TH1_LEN(argl[1]), &azCap, &anCap, &nCap);
877 if( rc ) return rc;
878 rc = 0;
879 for(i=0; i<nCap; i++){
880 if( azCap[i][0]=='!' ){
881 rc = !login_has_capability(azCap[i]+1, anCap[i]-1, 0);
@@ -921,11 +934,12 @@
934 if( argc<2 ){
935 return Th_WrongNumArgs(interp, "hascap STRING ...");
936 }
937 for(i=1; i<argc && rc; i++){
938 int match = 0;
939 int nn = TH1_LEN(argl[i]);
940 for(j=0; j<nn; j++){
941 switch( argv[i][j] ){
942 case 'c': match |= searchCap & SRCH_CKIN; break;
943 case 'd': match |= searchCap & SRCH_DOC; break;
944 case 't': match |= searchCap & SRCH_TKT; break;
945 case 'w': match |= searchCap & SRCH_WIKI; break;
@@ -932,11 +946,11 @@
946 }
947 }
948 if( !match ) rc = 0;
949 }
950 if( g.thTrace ){
951 Th_Trace("[searchable %#h] => %d<br>\n", TH1_LEN(argl[1]), argv[1], rc);
952 }
953 Th_SetResultInt(interp, rc);
954 return TH_OK;
955 }
956
@@ -1051,11 +1065,11 @@
1065 #endif
1066 else if( 0 == fossil_strnicmp( zArg, "markdown\0", 9 ) ){
1067 rc = 1;
1068 }
1069 if( g.thTrace ){
1070 Th_Trace("[hasfeature %#h] => %d<br>\n", TH1_LEN(argl[1]), zArg, rc);
1071 }
1072 Th_SetResultInt(interp, rc);
1073 return TH_OK;
1074 }
1075
@@ -1104,18 +1118,20 @@
1118 const char **argv,
1119 int *argl
1120 ){
1121 int rc = 0;
1122 int i;
1123 int nn;
1124 if( argc!=2 ){
1125 return Th_WrongNumArgs(interp, "anycap STRING");
1126 }
1127 nn = TH1_LEN(argl[1]);
1128 for(i=0; rc==0 && i<nn; i++){
1129 rc = login_has_capability((char*)&argv[1][i],1,0);
1130 }
1131 if( g.thTrace ){
1132 Th_Trace("[anycap %#h] => %d<br>\n", TH1_LEN(argl[1]), argv[1], rc);
1133 }
1134 Th_SetResultInt(interp, rc);
1135 return TH_OK;
1136 }
1137
@@ -1149,12 +1165,12 @@
1165 int *aszElem;
1166 char **azElem;
1167 int i;
1168
1169 if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR;
1170 Th_SplitList(interp, argv[2], TH1_LEN(argl[2]), &azElem, &aszElem, &nElem);
1171 blob_init(&name, (char*)argv[1], TH1_LEN(argl[1]));
1172 zValue = Th_Fetch(blob_str(&name), &nValue);
1173 zH = htmlize(blob_buffer(&name), blob_size(&name));
1174 z = mprintf("<select id=\"%s\" name=\"%s\" size=\"%d\">", zH, zH, height);
1175 free(zH);
1176 sendText(0,z, -1, 0);
@@ -1247,11 +1263,11 @@
1263 return Th_WrongNumArgs(interp, "linecount STRING MAX MIN");
1264 }
1265 if( Th_ToInt(interp, argv[2], argl[2], &iMax) ) return TH_ERROR;
1266 if( Th_ToInt(interp, argv[3], argl[3], &iMin) ) return TH_ERROR;
1267 z = argv[1];
1268 size = TH1_LEN(argl[1]);
1269 for(n=1, i=0; i<size; i++){
1270 if( z[i]=='\n' ){
1271 n++;
1272 if( n>=iMax ) break;
1273 }
@@ -1407,11 +1423,12 @@
1423 return TH_OK;
1424 }else if( fossil_strnicmp(argv[1], "vfs\0", 4)==0 ){
1425 Th_SetResult(interp, g.zVfsName ? g.zVfsName : zDefault, -1);
1426 return TH_OK;
1427 }else{
1428 Th_ErrorMessage(interp, "unsupported global state:",
1429 argv[1], TH1_LEN(argl[1]));
1430 return TH_ERROR;
1431 }
1432 }
1433
1434 /*
@@ -1939,15 +1956,19 @@
1956 Th_ErrorMessage(interp, "database is not open", 0, 0);
1957 return TH_ERROR;
1958 }
1959 zSql = argv[1];
1960 nSql = argl[1];
1961 if( TH1_TAINTED(nSql) && Th_ReportTaint(interp,"query SQL",zSql,nSql) ){
1962 return TH_ERROR;
1963 }
1964
1965 while( res==TH_OK && nSql>0 ){
1966 zErr = 0;
1967 report_restrict_sql(&zErr);
1968 g.dbIgnoreErrors++;
1969 rc = sqlite3_prepare_v2(g.db, argv[1], TH1_LEN(argl[1]), &pStmt, &zTail);
1970 g.dbIgnoreErrors--;
1971 report_unrestrict_sql();
1972 if( rc!=0 || zErr!=0 ){
1973 if( noComplain ) return TH_OK;
1974 Th_ErrorMessage(interp, "SQL error: ",
@@ -1974,16 +1995,16 @@
1995 for(i=0; i<nCol; i++){
1996 const char *zCol = sqlite3_column_name(pStmt, i);
1997 int szCol = th_strlen(zCol);
1998 const char *zVal = (const char*)sqlite3_column_text(pStmt, i);
1999 int szVal = sqlite3_column_bytes(pStmt, i);
2000 Th_SetVar(interp, zCol, szCol, zVal, TH1_ADD_TAINT(szVal));
2001 }
2002 if( g.thTrace ){
2003 Th_Trace("query_eval {<pre>%#h</pre>}<br>\n",TH1_LEN(argl[2]),argv[2]);
2004 }
2005 res = Th_Eval(interp, 0, argv[2], TH1_LEN(argl[2]));
2006 if( g.thTrace ){
2007 int nTrRes;
2008 char *zTrRes = (char*)Th_GetResult(g.interp, &nTrRes);
2009 Th_Trace("[query_eval] => %h {%#h}<br>\n",
2010 Th_ReturnCodeName(res, 0), nTrRes, zTrRes);
@@ -2038,11 +2059,11 @@
2059 Th_SetResult(interp, 0, 0);
2060 rc = TH_OK;
2061 }
2062 if( g.thTrace ){
2063 Th_Trace("[setting %s%#h] => %d<br>\n", strict ? "strict " : "",
2064 TH1_LEN(argl[nArg]), argv[nArg], rc);
2065 }
2066 return rc;
2067 }
2068
2069 /*
@@ -2121,11 +2142,11 @@
2142 return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS);
2143 }
2144 zErr = re_compile(&pRe, argv[nArg], noCase);
2145 if( !zErr ){
2146 Th_SetResultInt(interp, re_match(pRe,
2147 (const unsigned char *)argv[nArg+1], TH1_LEN(argl[nArg+1])));
2148 rc = TH_OK;
2149 }else{
2150 Th_SetResult(interp, zErr, -1);
2151 rc = TH_ERROR;
2152 }
@@ -2160,11 +2181,11 @@
2181 UrlData urlData;
2182
2183 if( argc<2 || argc>5 ){
2184 return Th_WrongNumArgs(interp, HTTP_WRONGNUMARGS);
2185 }
2186 if( fossil_strnicmp(argv[nArg], "-asynchronous", TH1_LEN(argl[nArg]))==0 ){
2187 fAsynchronous = 1; nArg++;
2188 }
2189 if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++;
2190 if( nArg+1!=argc && nArg+2!=argc ){
2191 return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS);
@@ -2189,11 +2210,11 @@
2210 return TH_ERROR;
2211 }
2212 re_free(pRe);
2213 blob_zero(&payload);
2214 if( nArg+2==argc ){
2215 blob_append(&payload, argv[nArg+1], TH1_LEN(argl[nArg+1]));
2216 zType = "POST";
2217 }else{
2218 zType = "GET";
2219 }
2220 if( fAsynchronous ){
@@ -2268,11 +2289,11 @@
2289 if( argc!=2 ){
2290 return Th_WrongNumArgs(interp, "captureTh1 STRING");
2291 }
2292 pOrig = Th_SetOutputBlob(&out);
2293 zStr = argv[1];
2294 nStr = TH1_LEN(argl[1]);
2295 rc = Th_Eval(g.interp, 0, zStr, nStr);
2296 Th_SetOutputBlob(pOrig);
2297 if(0==rc){
2298 Th_SetResult(g.interp, blob_str(&out), blob_size(&out));
2299 }
2300
+16 -16
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -41,16 +41,16 @@
4141
#define USE_ARGV_TO_OBJV() \
4242
int objc; \
4343
Tcl_Obj **objv; \
4444
int obji;
4545
46
-#define COPY_ARGV_TO_OBJV() \
47
- objc = argc-1; \
48
- objv = (Tcl_Obj **)ckalloc((unsigned)(objc * sizeof(Tcl_Obj *))); \
49
- for(obji=1; obji<argc; obji++){ \
50
- objv[obji-1] = Tcl_NewStringObj(argv[obji], argl[obji]); \
51
- Tcl_IncrRefCount(objv[obji-1]); \
46
+#define COPY_ARGV_TO_OBJV() \
47
+ objc = argc-1; \
48
+ objv = (Tcl_Obj **)ckalloc((unsigned)(objc * sizeof(Tcl_Obj *))); \
49
+ for(obji=1; obji<argc; obji++){ \
50
+ objv[obji-1] = Tcl_NewStringObj(argv[obji], TH1_LEN(argl[obji])); \
51
+ Tcl_IncrRefCount(objv[obji-1]); \
5252
}
5353
5454
#define FREE_ARGV_TO_OBJV() \
5555
for(obji=1; obji<argc; obji++){ \
5656
Tcl_DecrRefCount(objv[obji-1]); \
@@ -449,11 +449,11 @@
449449
}
450450
xNotifyProc = bIsPost ? tclContext->xPostEval : tclContext->xPreEval;
451451
if( xNotifyProc ){
452452
rc = xNotifyProc(bIsPost ?
453453
tclContext->pPostContext : tclContext->pPreContext,
454
- interp, ctx, argc, argv, argl, rc);
454
+ interp, ctx, argc, argv, TH1_LEN(argl), rc);
455455
}
456456
return rc;
457457
}
458458
459459
/*
@@ -485,17 +485,17 @@
485485
tclInterp = GET_CTX_TCL_INTERP(ctx);
486486
if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
487487
Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
488488
return TH_ERROR;
489489
}
490
- rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc);
490
+ rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, TH1_LEN(argl), rc);
491491
if( rc!=TH_OK ){
492492
return rc;
493493
}
494494
Tcl_Preserve((ClientData)tclInterp);
495495
if( argc==2 ){
496
- objPtr = Tcl_NewStringObj(argv[1], argl[1]);
496
+ objPtr = Tcl_NewStringObj(argv[1], TH1_LEN(argl[1]));
497497
Tcl_IncrRefCount(objPtr);
498498
rc = Tcl_EvalObjEx(tclInterp, objPtr, 0);
499499
Tcl_DecrRefCount(objPtr); objPtr = 0;
500500
}else{
501501
USE_ARGV_TO_OBJV();
@@ -507,11 +507,11 @@
507507
FREE_ARGV_TO_OBJV();
508508
}
509509
zResult = getTclResult(tclInterp, &nResult);
510510
Th_SetResult(interp, zResult, nResult);
511511
Tcl_Release((ClientData)tclInterp);
512
- rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl,
512
+ rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, TH1_LEN(argl),
513513
getTh1ReturnCode(rc));
514514
return rc;
515515
}
516516
517517
/*
@@ -545,17 +545,17 @@
545545
tclInterp = GET_CTX_TCL_INTERP(ctx);
546546
if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
547547
Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
548548
return TH_ERROR;
549549
}
550
- rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc);
550
+ rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, TH1_LEN(argl), rc);
551551
if( rc!=TH_OK ){
552552
return rc;
553553
}
554554
Tcl_Preserve((ClientData)tclInterp);
555555
if( argc==2 ){
556
- objPtr = Tcl_NewStringObj(argv[1], argl[1]);
556
+ objPtr = Tcl_NewStringObj(argv[1], TH1_LEN(argl[1]));
557557
Tcl_IncrRefCount(objPtr);
558558
rc = Tcl_ExprObj(tclInterp, objPtr, &resultObjPtr);
559559
Tcl_DecrRefCount(objPtr); objPtr = 0;
560560
}else{
561561
USE_ARGV_TO_OBJV();
@@ -574,11 +574,11 @@
574574
Th_SetResult(interp, zResult, nResult);
575575
if( rc==TCL_OK ){
576576
Tcl_DecrRefCount(resultObjPtr); resultObjPtr = 0;
577577
}
578578
Tcl_Release((ClientData)tclInterp);
579
- rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl,
579
+ rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, TH1_LEN(argl),
580580
getTh1ReturnCode(rc));
581581
return rc;
582582
}
583583
584584
/*
@@ -610,20 +610,20 @@
610610
tclInterp = GET_CTX_TCL_INTERP(ctx);
611611
if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
612612
Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
613613
return TH_ERROR;
614614
}
615
- rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc);
615
+ rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, TH1_LEN(argl), rc);
616616
if( rc!=TH_OK ){
617617
return rc;
618618
}
619619
Tcl_Preserve((ClientData)tclInterp);
620620
#if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV
621621
if( GET_CTX_TCL_USEOBJPROC(ctx) ){
622622
Tcl_Command command;
623623
Tcl_CmdInfo cmdInfo;
624
- Tcl_Obj *objPtr = Tcl_NewStringObj(argv[1], argl[1]);
624
+ Tcl_Obj *objPtr = Tcl_NewStringObj(argv[1], TH1_LEN(argl[1]));
625625
Tcl_IncrRefCount(objPtr);
626626
command = Tcl_GetCommandFromObj(tclInterp, objPtr);
627627
if( !command || Tcl_GetCommandInfoFromToken(command, &cmdInfo)==0 ){
628628
Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]);
629629
Tcl_DecrRefCount(objPtr); objPtr = 0;
@@ -649,11 +649,11 @@
649649
FREE_ARGV_TO_OBJV();
650650
}
651651
zResult = getTclResult(tclInterp, &nResult);
652652
Th_SetResult(interp, zResult, nResult);
653653
Tcl_Release((ClientData)tclInterp);
654
- rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl,
654
+ rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, TH1_LEN(argl),
655655
getTh1ReturnCode(rc));
656656
return rc;
657657
}
658658
659659
/*
660660
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -41,16 +41,16 @@
41 #define USE_ARGV_TO_OBJV() \
42 int objc; \
43 Tcl_Obj **objv; \
44 int obji;
45
46 #define COPY_ARGV_TO_OBJV() \
47 objc = argc-1; \
48 objv = (Tcl_Obj **)ckalloc((unsigned)(objc * sizeof(Tcl_Obj *))); \
49 for(obji=1; obji<argc; obji++){ \
50 objv[obji-1] = Tcl_NewStringObj(argv[obji], argl[obji]); \
51 Tcl_IncrRefCount(objv[obji-1]); \
52 }
53
54 #define FREE_ARGV_TO_OBJV() \
55 for(obji=1; obji<argc; obji++){ \
56 Tcl_DecrRefCount(objv[obji-1]); \
@@ -449,11 +449,11 @@
449 }
450 xNotifyProc = bIsPost ? tclContext->xPostEval : tclContext->xPreEval;
451 if( xNotifyProc ){
452 rc = xNotifyProc(bIsPost ?
453 tclContext->pPostContext : tclContext->pPreContext,
454 interp, ctx, argc, argv, argl, rc);
455 }
456 return rc;
457 }
458
459 /*
@@ -485,17 +485,17 @@
485 tclInterp = GET_CTX_TCL_INTERP(ctx);
486 if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
487 Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
488 return TH_ERROR;
489 }
490 rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc);
491 if( rc!=TH_OK ){
492 return rc;
493 }
494 Tcl_Preserve((ClientData)tclInterp);
495 if( argc==2 ){
496 objPtr = Tcl_NewStringObj(argv[1], argl[1]);
497 Tcl_IncrRefCount(objPtr);
498 rc = Tcl_EvalObjEx(tclInterp, objPtr, 0);
499 Tcl_DecrRefCount(objPtr); objPtr = 0;
500 }else{
501 USE_ARGV_TO_OBJV();
@@ -507,11 +507,11 @@
507 FREE_ARGV_TO_OBJV();
508 }
509 zResult = getTclResult(tclInterp, &nResult);
510 Th_SetResult(interp, zResult, nResult);
511 Tcl_Release((ClientData)tclInterp);
512 rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl,
513 getTh1ReturnCode(rc));
514 return rc;
515 }
516
517 /*
@@ -545,17 +545,17 @@
545 tclInterp = GET_CTX_TCL_INTERP(ctx);
546 if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
547 Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
548 return TH_ERROR;
549 }
550 rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc);
551 if( rc!=TH_OK ){
552 return rc;
553 }
554 Tcl_Preserve((ClientData)tclInterp);
555 if( argc==2 ){
556 objPtr = Tcl_NewStringObj(argv[1], argl[1]);
557 Tcl_IncrRefCount(objPtr);
558 rc = Tcl_ExprObj(tclInterp, objPtr, &resultObjPtr);
559 Tcl_DecrRefCount(objPtr); objPtr = 0;
560 }else{
561 USE_ARGV_TO_OBJV();
@@ -574,11 +574,11 @@
574 Th_SetResult(interp, zResult, nResult);
575 if( rc==TCL_OK ){
576 Tcl_DecrRefCount(resultObjPtr); resultObjPtr = 0;
577 }
578 Tcl_Release((ClientData)tclInterp);
579 rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl,
580 getTh1ReturnCode(rc));
581 return rc;
582 }
583
584 /*
@@ -610,20 +610,20 @@
610 tclInterp = GET_CTX_TCL_INTERP(ctx);
611 if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
612 Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
613 return TH_ERROR;
614 }
615 rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc);
616 if( rc!=TH_OK ){
617 return rc;
618 }
619 Tcl_Preserve((ClientData)tclInterp);
620 #if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV
621 if( GET_CTX_TCL_USEOBJPROC(ctx) ){
622 Tcl_Command command;
623 Tcl_CmdInfo cmdInfo;
624 Tcl_Obj *objPtr = Tcl_NewStringObj(argv[1], argl[1]);
625 Tcl_IncrRefCount(objPtr);
626 command = Tcl_GetCommandFromObj(tclInterp, objPtr);
627 if( !command || Tcl_GetCommandInfoFromToken(command, &cmdInfo)==0 ){
628 Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]);
629 Tcl_DecrRefCount(objPtr); objPtr = 0;
@@ -649,11 +649,11 @@
649 FREE_ARGV_TO_OBJV();
650 }
651 zResult = getTclResult(tclInterp, &nResult);
652 Th_SetResult(interp, zResult, nResult);
653 Tcl_Release((ClientData)tclInterp);
654 rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl,
655 getTh1ReturnCode(rc));
656 return rc;
657 }
658
659 /*
660
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -41,16 +41,16 @@
41 #define USE_ARGV_TO_OBJV() \
42 int objc; \
43 Tcl_Obj **objv; \
44 int obji;
45
46 #define COPY_ARGV_TO_OBJV() \
47 objc = argc-1; \
48 objv = (Tcl_Obj **)ckalloc((unsigned)(objc * sizeof(Tcl_Obj *))); \
49 for(obji=1; obji<argc; obji++){ \
50 objv[obji-1] = Tcl_NewStringObj(argv[obji], TH1_LEN(argl[obji])); \
51 Tcl_IncrRefCount(objv[obji-1]); \
52 }
53
54 #define FREE_ARGV_TO_OBJV() \
55 for(obji=1; obji<argc; obji++){ \
56 Tcl_DecrRefCount(objv[obji-1]); \
@@ -449,11 +449,11 @@
449 }
450 xNotifyProc = bIsPost ? tclContext->xPostEval : tclContext->xPreEval;
451 if( xNotifyProc ){
452 rc = xNotifyProc(bIsPost ?
453 tclContext->pPostContext : tclContext->pPreContext,
454 interp, ctx, argc, argv, TH1_LEN(argl), rc);
455 }
456 return rc;
457 }
458
459 /*
@@ -485,17 +485,17 @@
485 tclInterp = GET_CTX_TCL_INTERP(ctx);
486 if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
487 Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
488 return TH_ERROR;
489 }
490 rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, TH1_LEN(argl), rc);
491 if( rc!=TH_OK ){
492 return rc;
493 }
494 Tcl_Preserve((ClientData)tclInterp);
495 if( argc==2 ){
496 objPtr = Tcl_NewStringObj(argv[1], TH1_LEN(argl[1]));
497 Tcl_IncrRefCount(objPtr);
498 rc = Tcl_EvalObjEx(tclInterp, objPtr, 0);
499 Tcl_DecrRefCount(objPtr); objPtr = 0;
500 }else{
501 USE_ARGV_TO_OBJV();
@@ -507,11 +507,11 @@
507 FREE_ARGV_TO_OBJV();
508 }
509 zResult = getTclResult(tclInterp, &nResult);
510 Th_SetResult(interp, zResult, nResult);
511 Tcl_Release((ClientData)tclInterp);
512 rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, TH1_LEN(argl),
513 getTh1ReturnCode(rc));
514 return rc;
515 }
516
517 /*
@@ -545,17 +545,17 @@
545 tclInterp = GET_CTX_TCL_INTERP(ctx);
546 if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
547 Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
548 return TH_ERROR;
549 }
550 rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, TH1_LEN(argl), rc);
551 if( rc!=TH_OK ){
552 return rc;
553 }
554 Tcl_Preserve((ClientData)tclInterp);
555 if( argc==2 ){
556 objPtr = Tcl_NewStringObj(argv[1], TH1_LEN(argl[1]));
557 Tcl_IncrRefCount(objPtr);
558 rc = Tcl_ExprObj(tclInterp, objPtr, &resultObjPtr);
559 Tcl_DecrRefCount(objPtr); objPtr = 0;
560 }else{
561 USE_ARGV_TO_OBJV();
@@ -574,11 +574,11 @@
574 Th_SetResult(interp, zResult, nResult);
575 if( rc==TCL_OK ){
576 Tcl_DecrRefCount(resultObjPtr); resultObjPtr = 0;
577 }
578 Tcl_Release((ClientData)tclInterp);
579 rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, TH1_LEN(argl),
580 getTh1ReturnCode(rc));
581 return rc;
582 }
583
584 /*
@@ -610,20 +610,20 @@
610 tclInterp = GET_CTX_TCL_INTERP(ctx);
611 if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
612 Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
613 return TH_ERROR;
614 }
615 rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, TH1_LEN(argl), rc);
616 if( rc!=TH_OK ){
617 return rc;
618 }
619 Tcl_Preserve((ClientData)tclInterp);
620 #if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV
621 if( GET_CTX_TCL_USEOBJPROC(ctx) ){
622 Tcl_Command command;
623 Tcl_CmdInfo cmdInfo;
624 Tcl_Obj *objPtr = Tcl_NewStringObj(argv[1], TH1_LEN(argl[1]));
625 Tcl_IncrRefCount(objPtr);
626 command = Tcl_GetCommandFromObj(tclInterp, objPtr);
627 if( !command || Tcl_GetCommandInfoFromToken(command, &cmdInfo)==0 ){
628 Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]);
629 Tcl_DecrRefCount(objPtr); objPtr = 0;
@@ -649,11 +649,11 @@
649 FREE_ARGV_TO_OBJV();
650 }
651 zResult = getTclResult(tclInterp, &nResult);
652 Th_SetResult(interp, zResult, nResult);
653 Tcl_Release((ClientData)tclInterp);
654 rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, TH1_LEN(argl),
655 getTh1ReturnCode(rc));
656 return rc;
657 }
658
659 /*
660

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button