Fossil SCM
Experimental changes to TH1 to try to make it resistant to coding errors that could lead to XSS or SQL injection attacks.
Commit
b0b44924805848eca49b320d35251c074eee90c42c10f2fd7a352d4044a7fd0b
Parent
f1db9ead1d44290…
5 files changed
+87
-42
+53
-14
+68
-47
+51
-30
+16
-16
M
src/th.c
+87
-42
| --- src/th.c | ||
| +++ src/th.c | ||
| @@ -7,10 +7,16 @@ | ||
| 7 | 7 | #include "config.h" |
| 8 | 8 | #include "th.h" |
| 9 | 9 | #include <string.h> |
| 10 | 10 | #include <assert.h> |
| 11 | 11 | |
| 12 | +/* | |
| 13 | +** External routines | |
| 14 | +*/ | |
| 15 | +void fossil_panic(const char*,...); | |
| 16 | +void fossil_errorlog(const char*,...); | |
| 17 | + | |
| 12 | 18 | /* |
| 13 | 19 | ** Values used for element values in the tcl_platform array. |
| 14 | 20 | */ |
| 15 | 21 | |
| 16 | 22 | #if !defined(TH_ENGINE) |
| @@ -197,10 +203,11 @@ | ||
| 197 | 203 | */ |
| 198 | 204 | struct Buffer { |
| 199 | 205 | char *zBuf; |
| 200 | 206 | int nBuf; |
| 201 | 207 | int nBufAlloc; |
| 208 | + int bTaint; | |
| 202 | 209 | }; |
| 203 | 210 | typedef struct Buffer Buffer; |
| 204 | 211 | static void thBufferInit(Buffer *); |
| 205 | 212 | static void thBufferFree(Th_Interp *interp, Buffer *); |
| 206 | 213 | |
| @@ -209,10 +216,18 @@ | ||
| 209 | 216 | ** be NULL as long as the number of bytes to copy is zero. |
| 210 | 217 | */ |
| 211 | 218 | static void th_memcpy(void *dest, const void *src, size_t n){ |
| 212 | 219 | if( n>0 ) memcpy(dest,src,n); |
| 213 | 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 | +} | |
| 214 | 229 | |
| 215 | 230 | /* |
| 216 | 231 | ** Append nAdd bytes of content copied from zAdd to the end of buffer |
| 217 | 232 | ** pBuffer. If there is not enough space currently allocated, resize |
| 218 | 233 | ** the allocation to make space. |
| @@ -219,40 +234,46 @@ | ||
| 219 | 234 | */ |
| 220 | 235 | static void thBufferWriteResize( |
| 221 | 236 | Th_Interp *interp, |
| 222 | 237 | Buffer *pBuffer, |
| 223 | 238 | const char *zAdd, |
| 224 | - int nAdd | |
| 239 | + int nAddX | |
| 225 | 240 | ){ |
| 241 | + int nAdd = TH1_LEN(nAddX); | |
| 226 | 242 | int nNew = (pBuffer->nBuf+nAdd)*2+32; |
| 227 | 243 | #if defined(TH_MEMDEBUG) |
| 228 | 244 | char *zNew = (char *)Th_Malloc(interp, nNew); |
| 245 | + TH1_SIZECHECK(nNew); | |
| 229 | 246 | th_memcpy(zNew, pBuffer->zBuf, pBuffer->nBuf); |
| 230 | 247 | Th_Free(interp, pBuffer->zBuf); |
| 231 | 248 | pBuffer->zBuf = zNew; |
| 232 | 249 | #else |
| 233 | 250 | int nOld = pBuffer->nBufAlloc; |
| 251 | + TH1_SIZECHECK(nNew); | |
| 234 | 252 | pBuffer->zBuf = Th_Realloc(interp, pBuffer->zBuf, nNew); |
| 235 | 253 | memset(pBuffer->zBuf+nOld, 0, nNew-nOld); |
| 236 | 254 | #endif |
| 237 | 255 | pBuffer->nBufAlloc = nNew; |
| 238 | 256 | th_memcpy(&pBuffer->zBuf[pBuffer->nBuf], zAdd, nAdd); |
| 239 | 257 | pBuffer->nBuf += nAdd; |
| 258 | + TH1_XFER_TAINT(pBuffer->bTaint, nAddX); | |
| 240 | 259 | } |
| 241 | 260 | static void thBufferWriteFast( |
| 242 | 261 | Th_Interp *interp, |
| 243 | 262 | Buffer *pBuffer, |
| 244 | 263 | const char *zAdd, |
| 245 | - int nAdd | |
| 264 | + int nAddX | |
| 246 | 265 | ){ |
| 266 | + int nAdd = TH1_LEN(nAddX); | |
| 247 | 267 | if( pBuffer->nBuf+nAdd > pBuffer->nBufAlloc ){ |
| 248 | - thBufferWriteResize(interp, pBuffer, zAdd, nAdd); | |
| 268 | + thBufferWriteResize(interp, pBuffer, zAdd, nAddX); | |
| 249 | 269 | }else{ |
| 250 | 270 | if( pBuffer->zBuf ){ |
| 251 | 271 | memcpy(pBuffer->zBuf + pBuffer->nBuf, zAdd, nAdd); |
| 252 | 272 | } |
| 253 | 273 | pBuffer->nBuf += nAdd; |
| 274 | + TH1_XFER_TAINT(pBuffer->bTaint, nAddX); | |
| 254 | 275 | } |
| 255 | 276 | } |
| 256 | 277 | #define thBufferWrite(a,b,c,d) thBufferWriteFast(a,b,(const char *)c,d) |
| 257 | 278 | |
| 258 | 279 | /* |
| @@ -704,24 +725,25 @@ | ||
| 704 | 725 | int nWord |
| 705 | 726 | ){ |
| 706 | 727 | int rc = TH_OK; |
| 707 | 728 | Buffer output; |
| 708 | 729 | int i; |
| 730 | + int nn = TH1_LEN(nWord); | |
| 709 | 731 | |
| 710 | 732 | thBufferInit(&output); |
| 711 | 733 | |
| 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); | |
| 714 | 736 | }else{ |
| 715 | 737 | |
| 716 | 738 | /* 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]=='"') ){ | |
| 718 | 740 | zWord++; |
| 719 | - nWord -= 2; | |
| 741 | + nn -= 2; | |
| 720 | 742 | } |
| 721 | 743 | |
| 722 | - for(i=0; rc==TH_OK && i<nWord; i++){ | |
| 744 | + for(i=0; rc==TH_OK && i<nn; i++){ | |
| 723 | 745 | int nGet; |
| 724 | 746 | |
| 725 | 747 | int (*xGet)(Th_Interp *, const char*, int, int *) = 0; |
| 726 | 748 | int (*xSubst)(Th_Interp *, const char*, int) = 0; |
| 727 | 749 | |
| @@ -743,11 +765,11 @@ | ||
| 743 | 765 | thBufferAddChar(interp, &output, zWord[i]); |
| 744 | 766 | continue; /* Go to the next iteration of the for(...) loop */ |
| 745 | 767 | } |
| 746 | 768 | } |
| 747 | 769 | |
| 748 | - rc = xGet(interp, &zWord[i], nWord-i, &nGet); | |
| 770 | + rc = xGet(interp, &zWord[i], nn-i, &nGet); | |
| 749 | 771 | if( rc==TH_OK ){ |
| 750 | 772 | rc = xSubst(interp, &zWord[i], nGet); |
| 751 | 773 | } |
| 752 | 774 | if( rc==TH_OK ){ |
| 753 | 775 | const char *zRes; |
| @@ -826,11 +848,11 @@ | ||
| 826 | 848 | Buffer strbuf; |
| 827 | 849 | Buffer lenbuf; |
| 828 | 850 | int nCount = 0; |
| 829 | 851 | |
| 830 | 852 | const char *zInput = zList; |
| 831 | - int nInput = nList; | |
| 853 | + int nInput = TH1_LEN(nList); | |
| 832 | 854 | |
| 833 | 855 | thBufferInit(&strbuf); |
| 834 | 856 | thBufferInit(&lenbuf); |
| 835 | 857 | |
| 836 | 858 | while( nInput>0 ){ |
| @@ -886,10 +908,34 @@ | ||
| 886 | 908 | finish: |
| 887 | 909 | thBufferFree(interp, &strbuf); |
| 888 | 910 | thBufferFree(interp, &lenbuf); |
| 889 | 911 | return rc; |
| 890 | 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 | +} | |
| 891 | 937 | |
| 892 | 938 | /* |
| 893 | 939 | ** Evaluate the th1 script contained in the string (zProgram, nProgram) |
| 894 | 940 | ** in the current stack frame. |
| 895 | 941 | */ |
| @@ -896,10 +942,15 @@ | ||
| 896 | 942 | static int thEvalLocal(Th_Interp *interp, const char *zProgram, int nProgram){ |
| 897 | 943 | int rc = TH_OK; |
| 898 | 944 | const char *zInput = zProgram; |
| 899 | 945 | int nInput = nProgram; |
| 900 | 946 | |
| 947 | + if( TH1_TAINTED(nProgram) | |
| 948 | + && Th_ReportTaint(interp, "script", zProgram, nProgram) | |
| 949 | + ){ | |
| 950 | + return TH_ERROR; | |
| 951 | + } | |
| 901 | 952 | while( rc==TH_OK && nInput ){ |
| 902 | 953 | Th_HashEntry *pEntry; |
| 903 | 954 | int nSpace; |
| 904 | 955 | const char *zFirst; |
| 905 | 956 | |
| @@ -949,13 +1000,13 @@ | ||
| 949 | 1000 | if( rc!=TH_OK ) continue; |
| 950 | 1001 | |
| 951 | 1002 | if( argc>0 ){ |
| 952 | 1003 | |
| 953 | 1004 | /* 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); | |
| 955 | 1006 | 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])); | |
| 957 | 1008 | rc = TH_ERROR; |
| 958 | 1009 | } |
| 959 | 1010 | |
| 960 | 1011 | /* Call the command procedure. */ |
| 961 | 1012 | if( rc==TH_OK ){ |
| @@ -1095,10 +1146,12 @@ | ||
| 1095 | 1146 | int isGlobal = 0; |
| 1096 | 1147 | int i; |
| 1097 | 1148 | |
| 1098 | 1149 | if( nVarname<0 ){ |
| 1099 | 1150 | nVarname = th_strlen(zVarname); |
| 1151 | + }else{ | |
| 1152 | + nVarname = TH1_LEN(nVarname); | |
| 1100 | 1153 | } |
| 1101 | 1154 | nOuter = nVarname; |
| 1102 | 1155 | |
| 1103 | 1156 | /* If the variable name starts with "::", then do the lookup is in the |
| 1104 | 1157 | ** uppermost (global) frame. |
| @@ -1271,31 +1324,10 @@ | ||
| 1271 | 1324 | } |
| 1272 | 1325 | |
| 1273 | 1326 | return Th_SetResult(interp, pValue->zData, pValue->nData); |
| 1274 | 1327 | } |
| 1275 | 1328 | |
| 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 | 1329 | /* |
| 1298 | 1330 | ** Return true if variable (zVar, nVar) exists. |
| 1299 | 1331 | */ |
| 1300 | 1332 | int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1301 | 1333 | Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0); |
| @@ -1324,28 +1356,32 @@ | ||
| 1324 | 1356 | int nVar, |
| 1325 | 1357 | const char *zValue, |
| 1326 | 1358 | int nValue |
| 1327 | 1359 | ){ |
| 1328 | 1360 | Th_Variable *pValue; |
| 1361 | + int nn; | |
| 1329 | 1362 | |
| 1363 | + nVar = TH1_LEN(nVar); | |
| 1330 | 1364 | pValue = thFindValue(interp, zVar, nVar, 1, 0, 0, 0); |
| 1331 | 1365 | if( !pValue ){ |
| 1332 | 1366 | return TH_ERROR; |
| 1333 | 1367 | } |
| 1334 | 1368 | |
| 1335 | 1369 | if( nValue<0 ){ |
| 1336 | - nValue = th_strlen(zValue); | |
| 1370 | + nn = th_strlen(zValue); | |
| 1371 | + }else{ | |
| 1372 | + nn = TH1_LEN(nValue); | |
| 1337 | 1373 | } |
| 1338 | 1374 | if( pValue->zData ){ |
| 1339 | 1375 | Th_Free(interp, pValue->zData); |
| 1340 | 1376 | pValue->zData = 0; |
| 1341 | 1377 | } |
| 1342 | 1378 | |
| 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); | |
| 1347 | 1383 | pValue->nData = nValue; |
| 1348 | 1384 | |
| 1349 | 1385 | return TH_OK; |
| 1350 | 1386 | } |
| 1351 | 1387 | |
| @@ -1458,10 +1494,12 @@ | ||
| 1458 | 1494 | */ |
| 1459 | 1495 | char *th_strdup(Th_Interp *interp, const char *z, int n){ |
| 1460 | 1496 | char *zRes; |
| 1461 | 1497 | if( n<0 ){ |
| 1462 | 1498 | n = th_strlen(z); |
| 1499 | + }else{ | |
| 1500 | + n = TH1_LEN(n); | |
| 1463 | 1501 | } |
| 1464 | 1502 | zRes = Th_Malloc(interp, n+1); |
| 1465 | 1503 | th_memcpy(zRes, z, n); |
| 1466 | 1504 | zRes[n] = '\0'; |
| 1467 | 1505 | return zRes; |
| @@ -1519,13 +1557,14 @@ | ||
| 1519 | 1557 | n = th_strlen(z); |
| 1520 | 1558 | } |
| 1521 | 1559 | |
| 1522 | 1560 | if( z && n>0 ){ |
| 1523 | 1561 | 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'; | |
| 1527 | 1566 | pInterp->zResult = zResult; |
| 1528 | 1567 | pInterp->nResult = n; |
| 1529 | 1568 | } |
| 1530 | 1569 | |
| 1531 | 1570 | return TH_OK; |
| @@ -2456,10 +2495,12 @@ | ||
| 2456 | 2495 | int nToken = 0; |
| 2457 | 2496 | Expr **apToken = 0; |
| 2458 | 2497 | |
| 2459 | 2498 | if( nExpr<0 ){ |
| 2460 | 2499 | nExpr = th_strlen(zExpr); |
| 2500 | + }else{ | |
| 2501 | + nExpr = TH1_LEN(nExpr); | |
| 2461 | 2502 | } |
| 2462 | 2503 | |
| 2463 | 2504 | /* Parse the expression to a list of tokens. */ |
| 2464 | 2505 | rc = exprParse(interp, zExpr, nExpr, &apToken, &nToken); |
| 2465 | 2506 | |
| @@ -2567,10 +2608,12 @@ | ||
| 2567 | 2608 | Th_HashEntry *pRet; |
| 2568 | 2609 | Th_HashEntry **ppRet; |
| 2569 | 2610 | |
| 2570 | 2611 | if( nKey<0 ){ |
| 2571 | 2612 | nKey = th_strlen(zKey); |
| 2613 | + }else{ | |
| 2614 | + nKey = TH1_LEN(nKey); | |
| 2572 | 2615 | } |
| 2573 | 2616 | |
| 2574 | 2617 | for(i=0; i<nKey; i++){ |
| 2575 | 2618 | iKey = (iKey<<3) ^ iKey ^ zKey[i]; |
| 2576 | 2619 | } |
| @@ -2800,10 +2843,12 @@ | ||
| 2800 | 2843 | int base = 10; |
| 2801 | 2844 | int (*isdigit)(char) = th_isdigit; |
| 2802 | 2845 | |
| 2803 | 2846 | if( n<0 ){ |
| 2804 | 2847 | n = th_strlen(z); |
| 2848 | + }else{ | |
| 2849 | + n = TH1_LEN(n); | |
| 2805 | 2850 | } |
| 2806 | 2851 | |
| 2807 | 2852 | if( n>1 && (z[0]=='-' || z[0]=='+') ){ |
| 2808 | 2853 | i = 1; |
| 2809 | 2854 | } |
| @@ -2859,11 +2904,11 @@ | ||
| 2859 | 2904 | const char *z, |
| 2860 | 2905 | int n, |
| 2861 | 2906 | double *pfOut |
| 2862 | 2907 | ){ |
| 2863 | 2908 | 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)); | |
| 2865 | 2910 | return TH_ERROR; |
| 2866 | 2911 | } |
| 2867 | 2912 | |
| 2868 | 2913 | sqlite3AtoF((const char *)z, pfOut); |
| 2869 | 2914 | return TH_OK; |
| 2870 | 2915 |
| --- 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 |
M
src/th.h
+53
-14
| --- src/th.h | ||
| +++ src/th.h | ||
| @@ -1,10 +1,56 @@ | ||
| 1 | - | |
| 2 | 1 | /* This header file defines the external interface to the custom Scripting |
| 3 | 2 | ** Language (TH) interpreter. TH is very similar to Tcl but is not an |
| 4 | 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. | |
| 5 | 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); | |
| 6 | 52 | |
| 7 | 53 | /* |
| 8 | 54 | ** Before creating an interpreter, the application must allocate and |
| 9 | 55 | ** populate an instance of the following structure. It must remain valid |
| 10 | 56 | ** for the lifetime of the interpreter. |
| @@ -24,10 +70,16 @@ | ||
| 24 | 70 | ** Create and delete interpreters. |
| 25 | 71 | */ |
| 26 | 72 | Th_Interp * Th_CreateInterp(Th_Vtab *); |
| 27 | 73 | void Th_DeleteInterp(Th_Interp *); |
| 28 | 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 | + | |
| 29 | 81 | /* |
| 30 | 82 | ** Evaluate an TH program in the stack frame identified by parameter |
| 31 | 83 | ** iFrame, according to the following rules: |
| 32 | 84 | ** |
| 33 | 85 | ** * If iFrame is 0, this means the current frame. |
| @@ -56,23 +108,10 @@ | ||
| 56 | 108 | int Th_GetVar(Th_Interp *, const char *, int); |
| 57 | 109 | int Th_SetVar(Th_Interp *, const char *, int, const char *, int); |
| 58 | 110 | int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int); |
| 59 | 111 | int Th_UnsetVar(Th_Interp *, const char *, int); |
| 60 | 112 | |
| 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 | 113 | typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *); |
| 75 | 114 | |
| 76 | 115 | /* |
| 77 | 116 | ** Register new commands. |
| 78 | 117 | */ |
| 79 | 118 |
| --- 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 @@ | ||
| 39 | 39 | |
| 40 | 40 | rc = Th_Eval(interp, 0, argv[1], -1); |
| 41 | 41 | if( argc==3 ){ |
| 42 | 42 | int nResult; |
| 43 | 43 | 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); | |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | 47 | Th_SetResultInt(interp, rc); |
| 48 | 48 | return TH_OK; |
| 49 | 49 | } |
| @@ -215,15 +215,18 @@ | ||
| 215 | 215 | int *argl |
| 216 | 216 | ){ |
| 217 | 217 | char *zList = 0; |
| 218 | 218 | int nList = 0; |
| 219 | 219 | int i; |
| 220 | + int bTaint = 0; | |
| 220 | 221 | |
| 221 | 222 | for(i=1; i<argc; i++){ |
| 223 | + TH1_XFER_TAINT(bTaint,argl[i]); | |
| 222 | 224 | Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]); |
| 223 | 225 | } |
| 224 | 226 | |
| 227 | + TH1_XFER_TAINT(nList, bTaint); | |
| 225 | 228 | Th_SetResult(interp, zList, nList); |
| 226 | 229 | Th_Free(interp, zList); |
| 227 | 230 | |
| 228 | 231 | return TH_OK; |
| 229 | 232 | } |
| @@ -244,10 +247,11 @@ | ||
| 244 | 247 | int *argl |
| 245 | 248 | ){ |
| 246 | 249 | char *zList = 0; |
| 247 | 250 | int nList = 0; |
| 248 | 251 | int i, rc; |
| 252 | + int bTaint = 0; | |
| 249 | 253 | |
| 250 | 254 | if( argc<2 ){ |
| 251 | 255 | return Th_WrongNumArgs(interp, "lappend var ..."); |
| 252 | 256 | } |
| 253 | 257 | rc = Th_GetVar(interp, argv[1], argl[1]); |
| @@ -254,13 +258,15 @@ | ||
| 254 | 258 | if( rc==TH_OK ){ |
| 255 | 259 | zList = Th_TakeResult(interp, &nList); |
| 256 | 260 | } |
| 257 | 261 | |
| 258 | 262 | for(i=2; i<argc; i++){ |
| 263 | + TH1_XFER_TAINT(bTaint, argl[i]); | |
| 259 | 264 | Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]); |
| 260 | 265 | } |
| 261 | 266 | |
| 267 | + TH1_XFER_TAINT(nList, bTaint); | |
| 262 | 268 | Th_SetVar(interp, argv[1], argl[1], zList, nList); |
| 263 | 269 | Th_SetResult(interp, zList, nList); |
| 264 | 270 | Th_Free(interp, zList); |
| 265 | 271 | |
| 266 | 272 | return TH_OK; |
| @@ -561,20 +567,21 @@ | ||
| 561 | 567 | int nUsage = 0; /* Number of bytes at zUsage */ |
| 562 | 568 | |
| 563 | 569 | if( argc!=4 ){ |
| 564 | 570 | return Th_WrongNumArgs(interp, "proc name arglist code"); |
| 565 | 571 | } |
| 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) ){ | |
| 567 | 574 | return TH_ERROR; |
| 568 | 575 | } |
| 569 | 576 | |
| 570 | 577 | /* Allocate the new ProcDefn structure. */ |
| 571 | 578 | nByte = sizeof(ProcDefn) + /* ProcDefn structure */ |
| 572 | 579 | (sizeof(char *) + sizeof(int)) * nParam + /* azParam, anParam */ |
| 573 | 580 | (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 */ | |
| 576 | 583 | p = (ProcDefn *)Th_Malloc(interp, nByte); |
| 577 | 584 | |
| 578 | 585 | /* If the last parameter in the parameter list is "args", then set the |
| 579 | 586 | ** ProcDefn.hasArgs flag. The "args" parameter does not require an |
| 580 | 587 | ** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays. |
| @@ -590,12 +597,12 @@ | ||
| 590 | 597 | p->azParam = (char **)&p[1]; |
| 591 | 598 | p->anParam = (int *)&p->azParam[nParam]; |
| 592 | 599 | p->azDefault = (char **)&p->anParam[nParam]; |
| 593 | 600 | p->anDefault = (int *)&p->azDefault[nParam]; |
| 594 | 601 | 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]); | |
| 597 | 604 | zSpace = &p->zProgram[p->nProgram]; |
| 598 | 605 | |
| 599 | 606 | for(i=0; i<nParam; i++){ |
| 600 | 607 | char **az; |
| 601 | 608 | int *an; |
| @@ -672,11 +679,12 @@ | ||
| 672 | 679 | int *argl |
| 673 | 680 | ){ |
| 674 | 681 | if( argc!=3 ){ |
| 675 | 682 | return Th_WrongNumArgs(interp, "rename oldcmd newcmd"); |
| 676 | 683 | } |
| 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])); | |
| 678 | 686 | } |
| 679 | 687 | |
| 680 | 688 | /* |
| 681 | 689 | ** TH Syntax: |
| 682 | 690 | ** |
| @@ -746,13 +754,13 @@ | ||
| 746 | 754 | if( argc!=4 ){ |
| 747 | 755 | return Th_WrongNumArgs(interp, "string compare str1 str2"); |
| 748 | 756 | } |
| 749 | 757 | |
| 750 | 758 | zLeft = argv[2]; |
| 751 | - nLeft = argl[2]; | |
| 759 | + nLeft = TH1_LEN(argl[2]); | |
| 752 | 760 | zRight = argv[3]; |
| 753 | - nRight = argl[3]; | |
| 761 | + nRight = TH1_LEN(argl[3]); | |
| 754 | 762 | |
| 755 | 763 | for(i=0; iRes==0 && i<nLeft && i<nRight; i++){ |
| 756 | 764 | iRes = zLeft[i]-zRight[i]; |
| 757 | 765 | } |
| 758 | 766 | if( iRes==0 ){ |
| @@ -779,12 +787,12 @@ | ||
| 779 | 787 | |
| 780 | 788 | if( argc!=4 ){ |
| 781 | 789 | return Th_WrongNumArgs(interp, "string first needle haystack"); |
| 782 | 790 | } |
| 783 | 791 | |
| 784 | - nNeedle = argl[2]; | |
| 785 | - nHaystack = argl[3]; | |
| 792 | + nNeedle = TH1_LEN(argl[2]); | |
| 793 | + nHaystack = TH1_LEN(argl[3]); | |
| 786 | 794 | |
| 787 | 795 | if( nNeedle && nHaystack && nNeedle<=nHaystack ){ |
| 788 | 796 | const char *zNeedle = argv[2]; |
| 789 | 797 | const char *zHaystack = argv[3]; |
| 790 | 798 | int i; |
| @@ -812,19 +820,19 @@ | ||
| 812 | 820 | |
| 813 | 821 | if( argc!=4 ){ |
| 814 | 822 | return Th_WrongNumArgs(interp, "string index string index"); |
| 815 | 823 | } |
| 816 | 824 | |
| 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; | |
| 819 | 827 | }else if( Th_ToInt(interp, argv[3], argl[3], &iIndex) ){ |
| 820 | 828 | Th_ErrorMessage( |
| 821 | 829 | interp, "Expected \"end\" or integer, got:", argv[3], argl[3]); |
| 822 | 830 | return TH_ERROR; |
| 823 | 831 | } |
| 824 | 832 | |
| 825 | - if( iIndex>=0 && iIndex<argl[2] ){ | |
| 833 | + if( iIndex>=0 && iIndex<TH1_LEN(argl[2]) ){ | |
| 826 | 834 | return Th_SetResult(interp, &argv[2][iIndex], 1); |
| 827 | 835 | }else{ |
| 828 | 836 | return Th_SetResult(interp, 0, 0); |
| 829 | 837 | } |
| 830 | 838 | } |
| @@ -838,41 +846,44 @@ | ||
| 838 | 846 | Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl |
| 839 | 847 | ){ |
| 840 | 848 | if( argc!=4 ){ |
| 841 | 849 | return Th_WrongNumArgs(interp, "string is class string"); |
| 842 | 850 | } |
| 843 | - if( argl[2]==5 && 0==memcmp(argv[2], "alnum", 5) ){ | |
| 851 | + if( TH1_LEN(argl[2])==5 && 0==memcmp(argv[2], "alnum", 5) ){ | |
| 844 | 852 | int i; |
| 845 | 853 | int iRes = 1; |
| 846 | 854 | |
| 847 | - for(i=0; i<argl[3]; i++){ | |
| 855 | + for(i=0; i<TH1_LEN(argl[3]); i++){ | |
| 848 | 856 | if( !th_isalnum(argv[3][i]) ){ |
| 849 | 857 | iRes = 0; |
| 850 | 858 | } |
| 851 | 859 | } |
| 852 | 860 | |
| 853 | 861 | 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) ){ | |
| 855 | 863 | double fVal; |
| 856 | 864 | if( Th_ToDouble(interp, argv[3], argl[3], &fVal)==TH_OK ){ |
| 857 | 865 | return Th_SetResultInt(interp, 1); |
| 858 | 866 | } |
| 859 | 867 | 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) ){ | |
| 861 | 869 | int iVal; |
| 862 | 870 | if( Th_ToInt(interp, argv[3], argl[3], &iVal)==TH_OK ){ |
| 863 | 871 | return Th_SetResultInt(interp, 1); |
| 864 | 872 | } |
| 865 | 873 | 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) ){ | |
| 867 | 875 | if( Th_SplitList(interp, argv[3], argl[3], 0, 0, 0)==TH_OK ){ |
| 868 | 876 | return Th_SetResultInt(interp, 1); |
| 869 | 877 | } |
| 870 | 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])); | |
| 871 | 881 | }else{ |
| 872 | 882 | 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])); | |
| 874 | 885 | return TH_ERROR; |
| 875 | 886 | } |
| 876 | 887 | } |
| 877 | 888 | |
| 878 | 889 | /* |
| @@ -889,12 +900,12 @@ | ||
| 889 | 900 | |
| 890 | 901 | if( argc!=4 ){ |
| 891 | 902 | return Th_WrongNumArgs(interp, "string last needle haystack"); |
| 892 | 903 | } |
| 893 | 904 | |
| 894 | - nNeedle = argl[2]; | |
| 895 | - nHaystack = argl[3]; | |
| 905 | + nNeedle = TH1_LEN(argl[2]); | |
| 906 | + nHaystack = TH1_LEN(argl[3]); | |
| 896 | 907 | |
| 897 | 908 | if( nNeedle && nHaystack && nNeedle<=nHaystack ){ |
| 898 | 909 | const char *zNeedle = argv[2]; |
| 899 | 910 | const char *zHaystack = argv[3]; |
| 900 | 911 | int i; |
| @@ -919,11 +930,11 @@ | ||
| 919 | 930 | Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl |
| 920 | 931 | ){ |
| 921 | 932 | if( argc!=3 ){ |
| 922 | 933 | return Th_WrongNumArgs(interp, "string length string"); |
| 923 | 934 | } |
| 924 | - return Th_SetResultInt(interp, argl[2]); | |
| 935 | + return Th_SetResultInt(interp, TH1_LEN(argl[2])); | |
| 925 | 936 | } |
| 926 | 937 | |
| 927 | 938 | /* |
| 928 | 939 | ** TH Syntax: |
| 929 | 940 | ** |
| @@ -938,12 +949,12 @@ | ||
| 938 | 949 | char *zPat, *zStr; |
| 939 | 950 | int rc; |
| 940 | 951 | if( argc!=4 ){ |
| 941 | 952 | return Th_WrongNumArgs(interp, "string match pattern string"); |
| 942 | 953 | } |
| 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])); | |
| 945 | 956 | rc = sqlite3_strglob(zPat,zStr); |
| 946 | 957 | fossil_free(zPat); |
| 947 | 958 | fossil_free(zStr); |
| 948 | 959 | return Th_SetResultInt(interp, !rc); |
| 949 | 960 | } |
| @@ -961,23 +972,23 @@ | ||
| 961 | 972 | |
| 962 | 973 | if( argc!=5 ){ |
| 963 | 974 | return Th_WrongNumArgs(interp, "string range string first last"); |
| 964 | 975 | } |
| 965 | 976 | |
| 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]); | |
| 968 | 979 | }else if( Th_ToInt(interp, argv[4], argl[4], &iEnd) ){ |
| 969 | 980 | 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])); | |
| 971 | 982 | return TH_ERROR; |
| 972 | 983 | } |
| 973 | 984 | if( Th_ToInt(interp, argv[3], argl[3], &iStart) ){ |
| 974 | 985 | return TH_ERROR; |
| 975 | 986 | } |
| 976 | 987 | |
| 977 | 988 | 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; | |
| 979 | 990 | if( iStart>iEnd ) iEnd = iStart-1; |
| 980 | 991 | |
| 981 | 992 | return Th_SetResult(interp, &argv[2][iStart], iEnd-iStart+1); |
| 982 | 993 | } |
| 983 | 994 | |
| @@ -989,27 +1000,33 @@ | ||
| 989 | 1000 | static int string_repeat_command( |
| 990 | 1001 | Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl |
| 991 | 1002 | ){ |
| 992 | 1003 | int n; |
| 993 | 1004 | int i; |
| 994 | - int nByte; | |
| 1005 | + int sz; | |
| 1006 | + long long int nByte; | |
| 995 | 1007 | char *zByte; |
| 996 | 1008 | |
| 997 | 1009 | if( argc!=4 ){ |
| 998 | 1010 | return Th_WrongNumArgs(interp, "string repeat string n"); |
| 999 | 1011 | } |
| 1000 | 1012 | if( Th_ToInt(interp, argv[3], argl[3], &n) ){ |
| 1001 | 1013 | return TH_ERROR; |
| 1002 | 1014 | } |
| 1003 | 1015 | |
| 1004 | - nByte = argl[2] * n; | |
| 1016 | + nByte = n; | |
| 1017 | + sz = TH1_LEN(argl[2]); | |
| 1018 | + nByte *= sz; | |
| 1019 | + TH1_SIZECHECK(nByte+1); | |
| 1005 | 1020 | 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); | |
| 1008 | 1023 | } |
| 1009 | 1024 | |
| 1010 | - Th_SetResult(interp, zByte, nByte); | |
| 1025 | + n = nByte; | |
| 1026 | + TH1_XFER_TAINT(n, argl[2]); | |
| 1027 | + Th_SetResult(interp, zByte, n); | |
| 1011 | 1028 | Th_Free(interp, zByte); |
| 1012 | 1029 | return TH_OK; |
| 1013 | 1030 | } |
| 1014 | 1031 | |
| 1015 | 1032 | /* |
| @@ -1027,15 +1044,15 @@ | ||
| 1027 | 1044 | |
| 1028 | 1045 | if( argc!=3 ){ |
| 1029 | 1046 | return Th_WrongNumArgs(interp, "string trim string"); |
| 1030 | 1047 | } |
| 1031 | 1048 | 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' ){ | |
| 1034 | 1051 | while( n && th_isspace(z[0]) ){ z++; n--; } |
| 1035 | 1052 | } |
| 1036 | - if( argl[1]<5 || argv[1][4]=='r' ){ | |
| 1053 | + if( TH1_LEN(argl[1])<5 || argv[1][4]=='r' ){ | |
| 1037 | 1054 | while( n && th_isspace(z[n-1]) ){ n--; } |
| 1038 | 1055 | } |
| 1039 | 1056 | Th_SetResult(interp, z, n); |
| 1040 | 1057 | return TH_OK; |
| 1041 | 1058 | } |
| @@ -1051,11 +1068,11 @@ | ||
| 1051 | 1068 | int rc; |
| 1052 | 1069 | |
| 1053 | 1070 | if( argc!=3 ){ |
| 1054 | 1071 | return Th_WrongNumArgs(interp, "info exists var"); |
| 1055 | 1072 | } |
| 1056 | - rc = Th_ExistsVar(interp, argv[2], argl[2]); | |
| 1073 | + rc = Th_ExistsVar(interp, argv[2], TH1_LEN(argl[2])); | |
| 1057 | 1074 | Th_SetResultInt(interp, rc); |
| 1058 | 1075 | return TH_OK; |
| 1059 | 1076 | } |
| 1060 | 1077 | |
| 1061 | 1078 | /* |
| @@ -1117,11 +1134,11 @@ | ||
| 1117 | 1134 | int rc; |
| 1118 | 1135 | |
| 1119 | 1136 | if( argc!=3 ){ |
| 1120 | 1137 | return Th_WrongNumArgs(interp, "array exists var"); |
| 1121 | 1138 | } |
| 1122 | - rc = Th_ExistsArrayVar(interp, argv[2], argl[2]); | |
| 1139 | + rc = Th_ExistsArrayVar(interp, argv[2], TH1_LEN(argl[2])); | |
| 1123 | 1140 | Th_SetResultInt(interp, rc); |
| 1124 | 1141 | return TH_OK; |
| 1125 | 1142 | } |
| 1126 | 1143 | |
| 1127 | 1144 | /* |
| @@ -1137,11 +1154,11 @@ | ||
| 1137 | 1154 | int nElem = 0; |
| 1138 | 1155 | |
| 1139 | 1156 | if( argc!=3 ){ |
| 1140 | 1157 | return Th_WrongNumArgs(interp, "array names varname"); |
| 1141 | 1158 | } |
| 1142 | - rc = Th_ListAppendArray(interp, argv[2], argl[2], &zElem, &nElem); | |
| 1159 | + rc = Th_ListAppendArray(interp, argv[2], TH1_LEN(argl[2]), &zElem, &nElem); | |
| 1143 | 1160 | if( rc!=TH_OK ){ |
| 1144 | 1161 | return rc; |
| 1145 | 1162 | } |
| 1146 | 1163 | Th_SetResult(interp, zElem, nElem); |
| 1147 | 1164 | if( zElem ) Th_Free(interp, zElem); |
| @@ -1161,11 +1178,11 @@ | ||
| 1161 | 1178 | int *argl |
| 1162 | 1179 | ){ |
| 1163 | 1180 | if( argc!=2 ){ |
| 1164 | 1181 | return Th_WrongNumArgs(interp, "unset var"); |
| 1165 | 1182 | } |
| 1166 | - return Th_UnsetVar(interp, argv[1], argl[1]); | |
| 1183 | + return Th_UnsetVar(interp, argv[1], TH1_LEN(argl[1])); | |
| 1167 | 1184 | } |
| 1168 | 1185 | |
| 1169 | 1186 | int Th_CallSubCommand( |
| 1170 | 1187 | Th_Interp *interp, |
| 1171 | 1188 | void *ctx, |
| @@ -1176,19 +1193,22 @@ | ||
| 1176 | 1193 | ){ |
| 1177 | 1194 | if( argc>1 ){ |
| 1178 | 1195 | int i; |
| 1179 | 1196 | for(i=0; aSub[i].zName; i++){ |
| 1180 | 1197 | 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])) ){ | |
| 1182 | 1200 | return aSub[i].xProc(interp, ctx, argc, argv, argl); |
| 1183 | 1201 | } |
| 1184 | 1202 | } |
| 1185 | 1203 | } |
| 1186 | 1204 | 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])); | |
| 1188 | 1207 | }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])); | |
| 1190 | 1210 | } |
| 1191 | 1211 | return TH_ERROR; |
| 1192 | 1212 | } |
| 1193 | 1213 | |
| 1194 | 1214 | /* |
| @@ -1319,11 +1339,11 @@ | ||
| 1319 | 1339 | int iFrame = -1; |
| 1320 | 1340 | |
| 1321 | 1341 | if( argc!=2 && argc!=3 ){ |
| 1322 | 1342 | return Th_WrongNumArgs(interp, "uplevel ?level? script..."); |
| 1323 | 1343 | } |
| 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) ){ | |
| 1325 | 1345 | return TH_ERROR; |
| 1326 | 1346 | } |
| 1327 | 1347 | return Th_Eval(interp, iFrame, argv[argc-1], -1); |
| 1328 | 1348 | } |
| 1329 | 1349 | |
| @@ -1342,19 +1362,20 @@ | ||
| 1342 | 1362 | int iVar = 1; |
| 1343 | 1363 | int iFrame = -1; |
| 1344 | 1364 | int rc = TH_OK; |
| 1345 | 1365 | int i; |
| 1346 | 1366 | |
| 1347 | - if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){ | |
| 1367 | + if( TH_OK==thToFrame(0, argv[1], TH1_LEN(argl[1]), &iFrame) ){ | |
| 1348 | 1368 | iVar++; |
| 1349 | 1369 | } |
| 1350 | 1370 | if( argc==iVar || (argc-iVar)%2 ){ |
| 1351 | 1371 | return Th_WrongNumArgs(interp, |
| 1352 | 1372 | "upvar frame othervar myvar ?othervar myvar...?"); |
| 1353 | 1373 | } |
| 1354 | 1374 | 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])); | |
| 1356 | 1377 | } |
| 1357 | 1378 | return rc; |
| 1358 | 1379 | } |
| 1359 | 1380 | |
| 1360 | 1381 | /* |
| 1361 | 1382 |
| --- 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 @@ | ||
| 262 | 262 | ){ |
| 263 | 263 | char *zOut; |
| 264 | 264 | if( argc!=2 ){ |
| 265 | 265 | return Th_WrongNumArgs(interp, "httpize STRING"); |
| 266 | 266 | } |
| 267 | - zOut = httpize((char*)argv[1], argl[1]); | |
| 267 | + zOut = httpize((char*)argv[1], TH1_LEN(argl[1])); | |
| 268 | 268 | Th_SetResult(interp, zOut, -1); |
| 269 | 269 | free(zOut); |
| 270 | 270 | return TH_OK; |
| 271 | 271 | } |
| 272 | 272 | |
| @@ -291,11 +291,12 @@ | ||
| 291 | 291 | if( argc<2 || argc>3 ){ |
| 292 | 292 | return Th_WrongNumArgs(interp, "enable_output [LABEL] BOOLEAN"); |
| 293 | 293 | } |
| 294 | 294 | rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &enableOutput); |
| 295 | 295 | 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); | |
| 297 | 298 | } |
| 298 | 299 | return rc; |
| 299 | 300 | } |
| 300 | 301 | |
| 301 | 302 | /* |
| @@ -322,11 +323,11 @@ | ||
| 322 | 323 | buul = (TH_INIT_NO_ENCODE & g.th1Flags) ? 0 : 1; |
| 323 | 324 | Th_SetResultInt(g.interp, buul); |
| 324 | 325 | if(argc>1){ |
| 325 | 326 | if( g.thTrace ){ |
| 326 | 327 | Th_Trace("enable_htmlify {%.*s} -> %d<br>\n", |
| 327 | - argl[1],argv[1],buul); | |
| 328 | + TH1_LEN(argl[1]),argv[1],buul); | |
| 328 | 329 | } |
| 329 | 330 | rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &buul); |
| 330 | 331 | if(!rc){ |
| 331 | 332 | if(buul){ |
| 332 | 333 | g.th1Flags &= ~TH_INIT_NO_ENCODE; |
| @@ -387,13 +388,20 @@ | ||
| 387 | 388 | if(0==pOut && pThOut!=0){ |
| 388 | 389 | pOut = pThOut; |
| 389 | 390 | } |
| 390 | 391 | if(TH_INIT_NO_ENCODE & g.th1Flags){ |
| 391 | 392 | encode = 0; |
| 393 | + if( TH1_TAINTED(n) && Th_ReportTaint(0, "output string", z, n) ){ | |
| 394 | + return; | |
| 395 | + } | |
| 392 | 396 | } |
| 393 | 397 | 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 | + } | |
| 395 | 403 | if( encode ){ |
| 396 | 404 | z = htmlize(z, n); |
| 397 | 405 | n = strlen(z); |
| 398 | 406 | } |
| 399 | 407 | if(pOut!=0){ |
| @@ -558,10 +566,15 @@ | ||
| 558 | 566 | if( argc==3 ){ |
| 559 | 567 | if( Th_ToInt(interp, argv[2], argl[2], &withMethod) ){ |
| 560 | 568 | return TH_ERROR; |
| 561 | 569 | } |
| 562 | 570 | } |
| 571 | + if( TH1_TAINTED(argl[1]) | |
| 572 | + && Th_ReportTaint(interp,"redirect URL",argv[1],argl[1]) | |
| 573 | + ){ | |
| 574 | + return TH_ERROR; | |
| 575 | + } | |
| 563 | 576 | if( withMethod ){ |
| 564 | 577 | cgi_redirect_with_method(argv[1]); |
| 565 | 578 | }else{ |
| 566 | 579 | cgi_redirect(argv[1]); |
| 567 | 580 | } |
| @@ -660,11 +673,11 @@ | ||
| 660 | 673 | int nValue = 0; |
| 661 | 674 | if( argc!=2 ){ |
| 662 | 675 | return Th_WrongNumArgs(interp, "markdown STRING"); |
| 663 | 676 | } |
| 664 | 677 | blob_zero(&src); |
| 665 | - blob_init(&src, (char*)argv[1], argl[1]); | |
| 678 | + blob_init(&src, (char*)argv[1], TH1_LEN(argl[1])); | |
| 666 | 679 | blob_zero(&title); blob_zero(&body); |
| 667 | 680 | markdown_to_html(&src, &title, &body); |
| 668 | 681 | Th_ListAppend(interp, &zValue, &nValue, blob_str(&title), blob_size(&title)); |
| 669 | 682 | Th_ListAppend(interp, &zValue, &nValue, blob_str(&body), blob_size(&body)); |
| 670 | 683 | Th_SetResult(interp, zValue, nValue); |
| @@ -690,11 +703,11 @@ | ||
| 690 | 703 | if( argc!=2 ){ |
| 691 | 704 | return Th_WrongNumArgs(interp, "wiki STRING"); |
| 692 | 705 | } |
| 693 | 706 | if( enableOutput ){ |
| 694 | 707 | Blob src; |
| 695 | - blob_init(&src, (char*)argv[1], argl[1]); | |
| 708 | + blob_init(&src, (char*)argv[1], TH1_LEN(argl[1])); | |
| 696 | 709 | wiki_convert(&src, 0, flags); |
| 697 | 710 | blob_reset(&src); |
| 698 | 711 | } |
| 699 | 712 | return TH_OK; |
| 700 | 713 | } |
| @@ -735,11 +748,11 @@ | ||
| 735 | 748 | ){ |
| 736 | 749 | char *zOut; |
| 737 | 750 | if( argc!=2 ){ |
| 738 | 751 | return Th_WrongNumArgs(interp, "htmlize STRING"); |
| 739 | 752 | } |
| 740 | - zOut = htmlize((char*)argv[1], argl[1]); | |
| 753 | + zOut = htmlize((char*)argv[1], TH1_LEN(argl[1])); | |
| 741 | 754 | Th_SetResult(interp, zOut, -1); |
| 742 | 755 | free(zOut); |
| 743 | 756 | return TH_OK; |
| 744 | 757 | } |
| 745 | 758 | |
| @@ -757,11 +770,11 @@ | ||
| 757 | 770 | ){ |
| 758 | 771 | char *zOut; |
| 759 | 772 | if( argc!=2 ){ |
| 760 | 773 | return Th_WrongNumArgs(interp, "encode64 STRING"); |
| 761 | 774 | } |
| 762 | - zOut = encode64((char*)argv[1], argl[1]); | |
| 775 | + zOut = encode64((char*)argv[1], TH1_LEN(argl[1])); | |
| 763 | 776 | Th_SetResult(interp, zOut, -1); |
| 764 | 777 | free(zOut); |
| 765 | 778 | return TH_OK; |
| 766 | 779 | } |
| 767 | 780 | |
| @@ -778,11 +791,11 @@ | ||
| 778 | 791 | int argc, |
| 779 | 792 | const char **argv, |
| 780 | 793 | int *argl |
| 781 | 794 | ){ |
| 782 | 795 | 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 ){ | |
| 784 | 797 | zOut = db_text("??", "SELECT datetime('now',toLocal())"); |
| 785 | 798 | }else{ |
| 786 | 799 | zOut = db_text("??", "SELECT datetime('now')"); |
| 787 | 800 | } |
| 788 | 801 | Th_SetResult(interp, zOut, -1); |
| @@ -810,13 +823,13 @@ | ||
| 810 | 823 | if( argc<2 ){ |
| 811 | 824 | return Th_WrongNumArgs(interp, "hascap STRING ..."); |
| 812 | 825 | } |
| 813 | 826 | for(i=1; rc==1 && i<argc; i++){ |
| 814 | 827 | 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])); | |
| 816 | 829 | } |
| 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); | |
| 818 | 831 | } |
| 819 | 832 | if( g.thTrace ){ |
| 820 | 833 | Th_Trace("[%s %#h] => %d<br>\n", argv[0], nCapList, zCapList, rc); |
| 821 | 834 | Th_Free(interp, zCapList); |
| 822 | 835 | } |
| @@ -858,11 +871,11 @@ | ||
| 858 | 871 | int i; |
| 859 | 872 | |
| 860 | 873 | if( argc!=2 ){ |
| 861 | 874 | return Th_WrongNumArgs(interp, "capexpr EXPR"); |
| 862 | 875 | } |
| 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); | |
| 864 | 877 | if( rc ) return rc; |
| 865 | 878 | rc = 0; |
| 866 | 879 | for(i=0; i<nCap; i++){ |
| 867 | 880 | if( azCap[i][0]=='!' ){ |
| 868 | 881 | rc = !login_has_capability(azCap[i]+1, anCap[i]-1, 0); |
| @@ -921,11 +934,12 @@ | ||
| 921 | 934 | if( argc<2 ){ |
| 922 | 935 | return Th_WrongNumArgs(interp, "hascap STRING ..."); |
| 923 | 936 | } |
| 924 | 937 | for(i=1; i<argc && rc; i++){ |
| 925 | 938 | 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++){ | |
| 927 | 941 | switch( argv[i][j] ){ |
| 928 | 942 | case 'c': match |= searchCap & SRCH_CKIN; break; |
| 929 | 943 | case 'd': match |= searchCap & SRCH_DOC; break; |
| 930 | 944 | case 't': match |= searchCap & SRCH_TKT; break; |
| 931 | 945 | case 'w': match |= searchCap & SRCH_WIKI; break; |
| @@ -932,11 +946,11 @@ | ||
| 932 | 946 | } |
| 933 | 947 | } |
| 934 | 948 | if( !match ) rc = 0; |
| 935 | 949 | } |
| 936 | 950 | 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); | |
| 938 | 952 | } |
| 939 | 953 | Th_SetResultInt(interp, rc); |
| 940 | 954 | return TH_OK; |
| 941 | 955 | } |
| 942 | 956 | |
| @@ -1051,11 +1065,11 @@ | ||
| 1051 | 1065 | #endif |
| 1052 | 1066 | else if( 0 == fossil_strnicmp( zArg, "markdown\0", 9 ) ){ |
| 1053 | 1067 | rc = 1; |
| 1054 | 1068 | } |
| 1055 | 1069 | 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); | |
| 1057 | 1071 | } |
| 1058 | 1072 | Th_SetResultInt(interp, rc); |
| 1059 | 1073 | return TH_OK; |
| 1060 | 1074 | } |
| 1061 | 1075 | |
| @@ -1104,18 +1118,20 @@ | ||
| 1104 | 1118 | const char **argv, |
| 1105 | 1119 | int *argl |
| 1106 | 1120 | ){ |
| 1107 | 1121 | int rc = 0; |
| 1108 | 1122 | int i; |
| 1123 | + int nn; | |
| 1109 | 1124 | if( argc!=2 ){ |
| 1110 | 1125 | return Th_WrongNumArgs(interp, "anycap STRING"); |
| 1111 | 1126 | } |
| 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++){ | |
| 1113 | 1129 | rc = login_has_capability((char*)&argv[1][i],1,0); |
| 1114 | 1130 | } |
| 1115 | 1131 | 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); | |
| 1117 | 1133 | } |
| 1118 | 1134 | Th_SetResultInt(interp, rc); |
| 1119 | 1135 | return TH_OK; |
| 1120 | 1136 | } |
| 1121 | 1137 | |
| @@ -1149,12 +1165,12 @@ | ||
| 1149 | 1165 | int *aszElem; |
| 1150 | 1166 | char **azElem; |
| 1151 | 1167 | int i; |
| 1152 | 1168 | |
| 1153 | 1169 | 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])); | |
| 1156 | 1172 | zValue = Th_Fetch(blob_str(&name), &nValue); |
| 1157 | 1173 | zH = htmlize(blob_buffer(&name), blob_size(&name)); |
| 1158 | 1174 | z = mprintf("<select id=\"%s\" name=\"%s\" size=\"%d\">", zH, zH, height); |
| 1159 | 1175 | free(zH); |
| 1160 | 1176 | sendText(0,z, -1, 0); |
| @@ -1247,11 +1263,11 @@ | ||
| 1247 | 1263 | return Th_WrongNumArgs(interp, "linecount STRING MAX MIN"); |
| 1248 | 1264 | } |
| 1249 | 1265 | if( Th_ToInt(interp, argv[2], argl[2], &iMax) ) return TH_ERROR; |
| 1250 | 1266 | if( Th_ToInt(interp, argv[3], argl[3], &iMin) ) return TH_ERROR; |
| 1251 | 1267 | z = argv[1]; |
| 1252 | - size = argl[1]; | |
| 1268 | + size = TH1_LEN(argl[1]); | |
| 1253 | 1269 | for(n=1, i=0; i<size; i++){ |
| 1254 | 1270 | if( z[i]=='\n' ){ |
| 1255 | 1271 | n++; |
| 1256 | 1272 | if( n>=iMax ) break; |
| 1257 | 1273 | } |
| @@ -1407,11 +1423,12 @@ | ||
| 1407 | 1423 | return TH_OK; |
| 1408 | 1424 | }else if( fossil_strnicmp(argv[1], "vfs\0", 4)==0 ){ |
| 1409 | 1425 | Th_SetResult(interp, g.zVfsName ? g.zVfsName : zDefault, -1); |
| 1410 | 1426 | return TH_OK; |
| 1411 | 1427 | }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])); | |
| 1413 | 1430 | return TH_ERROR; |
| 1414 | 1431 | } |
| 1415 | 1432 | } |
| 1416 | 1433 | |
| 1417 | 1434 | /* |
| @@ -1939,15 +1956,19 @@ | ||
| 1939 | 1956 | Th_ErrorMessage(interp, "database is not open", 0, 0); |
| 1940 | 1957 | return TH_ERROR; |
| 1941 | 1958 | } |
| 1942 | 1959 | zSql = argv[1]; |
| 1943 | 1960 | nSql = argl[1]; |
| 1961 | + if( TH1_TAINTED(nSql) && Th_ReportTaint(interp,"query SQL",zSql,nSql) ){ | |
| 1962 | + return TH_ERROR; | |
| 1963 | + } | |
| 1964 | + | |
| 1944 | 1965 | while( res==TH_OK && nSql>0 ){ |
| 1945 | 1966 | zErr = 0; |
| 1946 | 1967 | report_restrict_sql(&zErr); |
| 1947 | 1968 | 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); | |
| 1949 | 1970 | g.dbIgnoreErrors--; |
| 1950 | 1971 | report_unrestrict_sql(); |
| 1951 | 1972 | if( rc!=0 || zErr!=0 ){ |
| 1952 | 1973 | if( noComplain ) return TH_OK; |
| 1953 | 1974 | Th_ErrorMessage(interp, "SQL error: ", |
| @@ -1974,16 +1995,16 @@ | ||
| 1974 | 1995 | for(i=0; i<nCol; i++){ |
| 1975 | 1996 | const char *zCol = sqlite3_column_name(pStmt, i); |
| 1976 | 1997 | int szCol = th_strlen(zCol); |
| 1977 | 1998 | const char *zVal = (const char*)sqlite3_column_text(pStmt, i); |
| 1978 | 1999 | 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)); | |
| 1980 | 2001 | } |
| 1981 | 2002 | 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]); | |
| 1983 | 2004 | } |
| 1984 | - res = Th_Eval(interp, 0, argv[2], argl[2]); | |
| 2005 | + res = Th_Eval(interp, 0, argv[2], TH1_LEN(argl[2])); | |
| 1985 | 2006 | if( g.thTrace ){ |
| 1986 | 2007 | int nTrRes; |
| 1987 | 2008 | char *zTrRes = (char*)Th_GetResult(g.interp, &nTrRes); |
| 1988 | 2009 | Th_Trace("[query_eval] => %h {%#h}<br>\n", |
| 1989 | 2010 | Th_ReturnCodeName(res, 0), nTrRes, zTrRes); |
| @@ -2038,11 +2059,11 @@ | ||
| 2038 | 2059 | Th_SetResult(interp, 0, 0); |
| 2039 | 2060 | rc = TH_OK; |
| 2040 | 2061 | } |
| 2041 | 2062 | if( g.thTrace ){ |
| 2042 | 2063 | Th_Trace("[setting %s%#h] => %d<br>\n", strict ? "strict " : "", |
| 2043 | - argl[nArg], argv[nArg], rc); | |
| 2064 | + TH1_LEN(argl[nArg]), argv[nArg], rc); | |
| 2044 | 2065 | } |
| 2045 | 2066 | return rc; |
| 2046 | 2067 | } |
| 2047 | 2068 | |
| 2048 | 2069 | /* |
| @@ -2121,11 +2142,11 @@ | ||
| 2121 | 2142 | return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS); |
| 2122 | 2143 | } |
| 2123 | 2144 | zErr = re_compile(&pRe, argv[nArg], noCase); |
| 2124 | 2145 | if( !zErr ){ |
| 2125 | 2146 | 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]))); | |
| 2127 | 2148 | rc = TH_OK; |
| 2128 | 2149 | }else{ |
| 2129 | 2150 | Th_SetResult(interp, zErr, -1); |
| 2130 | 2151 | rc = TH_ERROR; |
| 2131 | 2152 | } |
| @@ -2160,11 +2181,11 @@ | ||
| 2160 | 2181 | UrlData urlData; |
| 2161 | 2182 | |
| 2162 | 2183 | if( argc<2 || argc>5 ){ |
| 2163 | 2184 | return Th_WrongNumArgs(interp, HTTP_WRONGNUMARGS); |
| 2164 | 2185 | } |
| 2165 | - if( fossil_strnicmp(argv[nArg], "-asynchronous", argl[nArg])==0 ){ | |
| 2186 | + if( fossil_strnicmp(argv[nArg], "-asynchronous", TH1_LEN(argl[nArg]))==0 ){ | |
| 2166 | 2187 | fAsynchronous = 1; nArg++; |
| 2167 | 2188 | } |
| 2168 | 2189 | if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++; |
| 2169 | 2190 | if( nArg+1!=argc && nArg+2!=argc ){ |
| 2170 | 2191 | return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS); |
| @@ -2189,11 +2210,11 @@ | ||
| 2189 | 2210 | return TH_ERROR; |
| 2190 | 2211 | } |
| 2191 | 2212 | re_free(pRe); |
| 2192 | 2213 | blob_zero(&payload); |
| 2193 | 2214 | 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])); | |
| 2195 | 2216 | zType = "POST"; |
| 2196 | 2217 | }else{ |
| 2197 | 2218 | zType = "GET"; |
| 2198 | 2219 | } |
| 2199 | 2220 | if( fAsynchronous ){ |
| @@ -2268,11 +2289,11 @@ | ||
| 2268 | 2289 | if( argc!=2 ){ |
| 2269 | 2290 | return Th_WrongNumArgs(interp, "captureTh1 STRING"); |
| 2270 | 2291 | } |
| 2271 | 2292 | pOrig = Th_SetOutputBlob(&out); |
| 2272 | 2293 | zStr = argv[1]; |
| 2273 | - nStr = argl[1]; | |
| 2294 | + nStr = TH1_LEN(argl[1]); | |
| 2274 | 2295 | rc = Th_Eval(g.interp, 0, zStr, nStr); |
| 2275 | 2296 | Th_SetOutputBlob(pOrig); |
| 2276 | 2297 | if(0==rc){ |
| 2277 | 2298 | Th_SetResult(g.interp, blob_str(&out), blob_size(&out)); |
| 2278 | 2299 | } |
| 2279 | 2300 |
| --- 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 @@ | ||
| 41 | 41 | #define USE_ARGV_TO_OBJV() \ |
| 42 | 42 | int objc; \ |
| 43 | 43 | Tcl_Obj **objv; \ |
| 44 | 44 | int obji; |
| 45 | 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]); \ | |
| 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 | 52 | } |
| 53 | 53 | |
| 54 | 54 | #define FREE_ARGV_TO_OBJV() \ |
| 55 | 55 | for(obji=1; obji<argc; obji++){ \ |
| 56 | 56 | Tcl_DecrRefCount(objv[obji-1]); \ |
| @@ -449,11 +449,11 @@ | ||
| 449 | 449 | } |
| 450 | 450 | xNotifyProc = bIsPost ? tclContext->xPostEval : tclContext->xPreEval; |
| 451 | 451 | if( xNotifyProc ){ |
| 452 | 452 | rc = xNotifyProc(bIsPost ? |
| 453 | 453 | tclContext->pPostContext : tclContext->pPreContext, |
| 454 | - interp, ctx, argc, argv, argl, rc); | |
| 454 | + interp, ctx, argc, argv, TH1_LEN(argl), rc); | |
| 455 | 455 | } |
| 456 | 456 | return rc; |
| 457 | 457 | } |
| 458 | 458 | |
| 459 | 459 | /* |
| @@ -485,17 +485,17 @@ | ||
| 485 | 485 | tclInterp = GET_CTX_TCL_INTERP(ctx); |
| 486 | 486 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 487 | 487 | Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 488 | 488 | return TH_ERROR; |
| 489 | 489 | } |
| 490 | - rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc); | |
| 490 | + rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, TH1_LEN(argl), rc); | |
| 491 | 491 | if( rc!=TH_OK ){ |
| 492 | 492 | return rc; |
| 493 | 493 | } |
| 494 | 494 | Tcl_Preserve((ClientData)tclInterp); |
| 495 | 495 | if( argc==2 ){ |
| 496 | - objPtr = Tcl_NewStringObj(argv[1], argl[1]); | |
| 496 | + objPtr = Tcl_NewStringObj(argv[1], TH1_LEN(argl[1])); | |
| 497 | 497 | Tcl_IncrRefCount(objPtr); |
| 498 | 498 | rc = Tcl_EvalObjEx(tclInterp, objPtr, 0); |
| 499 | 499 | Tcl_DecrRefCount(objPtr); objPtr = 0; |
| 500 | 500 | }else{ |
| 501 | 501 | USE_ARGV_TO_OBJV(); |
| @@ -507,11 +507,11 @@ | ||
| 507 | 507 | FREE_ARGV_TO_OBJV(); |
| 508 | 508 | } |
| 509 | 509 | zResult = getTclResult(tclInterp, &nResult); |
| 510 | 510 | Th_SetResult(interp, zResult, nResult); |
| 511 | 511 | Tcl_Release((ClientData)tclInterp); |
| 512 | - rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, | |
| 512 | + rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, TH1_LEN(argl), | |
| 513 | 513 | getTh1ReturnCode(rc)); |
| 514 | 514 | return rc; |
| 515 | 515 | } |
| 516 | 516 | |
| 517 | 517 | /* |
| @@ -545,17 +545,17 @@ | ||
| 545 | 545 | tclInterp = GET_CTX_TCL_INTERP(ctx); |
| 546 | 546 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 547 | 547 | Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 548 | 548 | return TH_ERROR; |
| 549 | 549 | } |
| 550 | - rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc); | |
| 550 | + rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, TH1_LEN(argl), rc); | |
| 551 | 551 | if( rc!=TH_OK ){ |
| 552 | 552 | return rc; |
| 553 | 553 | } |
| 554 | 554 | Tcl_Preserve((ClientData)tclInterp); |
| 555 | 555 | if( argc==2 ){ |
| 556 | - objPtr = Tcl_NewStringObj(argv[1], argl[1]); | |
| 556 | + objPtr = Tcl_NewStringObj(argv[1], TH1_LEN(argl[1])); | |
| 557 | 557 | Tcl_IncrRefCount(objPtr); |
| 558 | 558 | rc = Tcl_ExprObj(tclInterp, objPtr, &resultObjPtr); |
| 559 | 559 | Tcl_DecrRefCount(objPtr); objPtr = 0; |
| 560 | 560 | }else{ |
| 561 | 561 | USE_ARGV_TO_OBJV(); |
| @@ -574,11 +574,11 @@ | ||
| 574 | 574 | Th_SetResult(interp, zResult, nResult); |
| 575 | 575 | if( rc==TCL_OK ){ |
| 576 | 576 | Tcl_DecrRefCount(resultObjPtr); resultObjPtr = 0; |
| 577 | 577 | } |
| 578 | 578 | Tcl_Release((ClientData)tclInterp); |
| 579 | - rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, | |
| 579 | + rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, TH1_LEN(argl), | |
| 580 | 580 | getTh1ReturnCode(rc)); |
| 581 | 581 | return rc; |
| 582 | 582 | } |
| 583 | 583 | |
| 584 | 584 | /* |
| @@ -610,20 +610,20 @@ | ||
| 610 | 610 | tclInterp = GET_CTX_TCL_INTERP(ctx); |
| 611 | 611 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 612 | 612 | Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 613 | 613 | return TH_ERROR; |
| 614 | 614 | } |
| 615 | - rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc); | |
| 615 | + rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, TH1_LEN(argl), rc); | |
| 616 | 616 | if( rc!=TH_OK ){ |
| 617 | 617 | return rc; |
| 618 | 618 | } |
| 619 | 619 | Tcl_Preserve((ClientData)tclInterp); |
| 620 | 620 | #if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV |
| 621 | 621 | if( GET_CTX_TCL_USEOBJPROC(ctx) ){ |
| 622 | 622 | Tcl_Command command; |
| 623 | 623 | 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])); | |
| 625 | 625 | Tcl_IncrRefCount(objPtr); |
| 626 | 626 | command = Tcl_GetCommandFromObj(tclInterp, objPtr); |
| 627 | 627 | if( !command || Tcl_GetCommandInfoFromToken(command, &cmdInfo)==0 ){ |
| 628 | 628 | Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]); |
| 629 | 629 | Tcl_DecrRefCount(objPtr); objPtr = 0; |
| @@ -649,11 +649,11 @@ | ||
| 649 | 649 | FREE_ARGV_TO_OBJV(); |
| 650 | 650 | } |
| 651 | 651 | zResult = getTclResult(tclInterp, &nResult); |
| 652 | 652 | Th_SetResult(interp, zResult, nResult); |
| 653 | 653 | Tcl_Release((ClientData)tclInterp); |
| 654 | - rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, | |
| 654 | + rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, TH1_LEN(argl), | |
| 655 | 655 | getTh1ReturnCode(rc)); |
| 656 | 656 | return rc; |
| 657 | 657 | } |
| 658 | 658 | |
| 659 | 659 | /* |
| 660 | 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], 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 |