| ︙ | | | ︙ | |
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
static int thHexdigit(char c);
static int thEndOfLine(const char *, int);
static int thPushFrame(Th_Interp*, Th_Frame*);
static void thPopFrame(Th_Interp*);
static void thFreeVariable(Th_HashEntry*, void*);
static void thFreeCommand(Th_HashEntry*, void*);
/*
** The following are used by both the expression and language parsers.
** Given that the start of the input string (z, n) is a language
** construct of the relevant type (a command enclosed in [], an escape
** sequence etc.), these functions determine the number of bytes
** of the input consumed by the construct. For example:
|
|
|
|
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
static int thHexdigit(char c);
static int thEndOfLine(const char *, int);
static int thPushFrame(Th_Interp*, Th_Frame*);
static void thPopFrame(Th_Interp*);
static int thFreeVariable(Th_HashEntry*, void*);
static int thFreeCommand(Th_HashEntry*, void*);
/*
** The following are used by both the expression and language parsers.
** Given that the start of the input string (z, n) is a language
** construct of the relevant type (a command enclosed in [], an escape
** sequence etc.), these functions determine the number of bytes
** of the input consumed by the construct. For example:
|
| ︙ | | | ︙ | |
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
|
/*
** Argument pEntry points to an entry in a stack frame hash table
** (Th_Frame.paVar). Decrement the reference count of the Th_Variable
** structure that the entry points to. Free the Th_Variable if its
** reference count reaches 0.
**
** Argument pContext is a pointer to the interpreter structure.
*/
static void thFreeVariable(Th_HashEntry *pEntry, void *pContext){
Th_Variable *pValue = (Th_Variable *)pEntry->pData;
pValue->nRef--;
assert( pValue->nRef>=0 );
if( pValue->nRef==0 ){
Th_Interp *interp = (Th_Interp *)pContext;
Th_Free(interp, pValue->zData);
if( pValue->pHash ){
Th_HashIterate(interp, pValue->pHash, thFreeVariable, pContext);
Th_HashDelete(interp, pValue->pHash);
}
Th_Free(interp, pValue);
}
}
/*
** Argument pEntry points to an entry in the command hash table
** (Th_Interp.paCmd). Delete the Th_Command structure that the
** entry points to.
**
** Argument pContext is a pointer to the interpreter structure.
*/
static void thFreeCommand(Th_HashEntry *pEntry, void *pContext){
Th_Command *pCommand = (Th_Command *)pEntry->pData;
if( pCommand->xDel ){
pCommand->xDel((Th_Interp *)pContext, pCommand->pContext);
}
Th_Free((Th_Interp *)pContext, pEntry->pData);
pEntry->pData = 0;
}
/*
** Push a new frame onto the stack.
*/
static int thPushFrame(Th_Interp *interp, Th_Frame *pFrame){
pFrame->paVar = Th_HashNew(interp);
|
>
>
|
>
>
>
>
>
|
>
|
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
|
/*
** Argument pEntry points to an entry in a stack frame hash table
** (Th_Frame.paVar). Decrement the reference count of the Th_Variable
** structure that the entry points to. Free the Th_Variable if its
** reference count reaches 0.
**
** Argument pContext is a pointer to the interpreter structure.
**
** Returns non-zero if the Th_Variable was actually freed.
*/
static int thFreeVariable(Th_HashEntry *pEntry, void *pContext){
Th_Variable *pValue = (Th_Variable *)pEntry->pData;
pValue->nRef--;
assert( pValue->nRef>=0 );
if( pValue->nRef==0 ){
Th_Interp *interp = (Th_Interp *)pContext;
Th_Free(interp, pValue->zData);
if( pValue->pHash ){
Th_HashIterate(interp, pValue->pHash, thFreeVariable, pContext);
Th_HashDelete(interp, pValue->pHash);
}
Th_Free(interp, pValue);
pEntry->pData = 0;
return 1;
}
return 0;
}
/*
** Argument pEntry points to an entry in the command hash table
** (Th_Interp.paCmd). Delete the Th_Command structure that the
** entry points to.
**
** Argument pContext is a pointer to the interpreter structure.
**
** Always returns non-zero.
*/
static int thFreeCommand(Th_HashEntry *pEntry, void *pContext){
Th_Command *pCommand = (Th_Command *)pEntry->pData;
if( pCommand->xDel ){
pCommand->xDel((Th_Interp *)pContext, pCommand->pContext);
}
Th_Free((Th_Interp *)pContext, pEntry->pData);
pEntry->pData = 0;
return 1;
}
/*
** Push a new frame onto the stack.
*/
static int thPushFrame(Th_Interp *interp, Th_Frame *pFrame){
pFrame->paVar = Th_HashNew(interp);
|
| ︙ | | | ︙ | |
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
|
** it is created. Otherwise, an error is left in the interpreter result
** and NULL returned.
**
** If the arrayok argument is false and the named variable is an array,
** an error is left in the interpreter result and NULL returned. If
** arrayok is true an array name is Ok.
*/
static Th_Variable *thFindValue(
Th_Interp *interp,
const char *zVar, /* Pointer to variable name */
int nVar, /* Number of bytes at nVar */
int create, /* If true, create the variable if not found */
int arrayok, /* If true, an array is Ok. Otherwise array==error */
int noerror /* If false, set interpreter result to error message */
){
const char *zOuter;
int nOuter;
const char *zInner;
int nInner;
int isGlobal;
Th_HashEntry *pEntry;
Th_Frame *pFrame = interp->pFrame;
Th_Variable *pValue;
thAnalyseVarname(zVar, nVar, &zOuter, &nOuter, &zInner, &nInner, &isGlobal);
if( isGlobal ){
while( pFrame->pCaller ) pFrame = pFrame->pCaller;
}
pEntry = Th_HashFind(interp, pFrame->paVar, zOuter, nOuter, create);
assert(pEntry || create<=0);
if( !pEntry ){
goto no_such_var;
}
pValue = (Th_Variable *)pEntry->pData;
if( !pValue ){
assert(create);
|
>
>
>
>
>
>
>
>
|
|
|
|
|
>
>
>
>
>
>
>
>
|
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
|
** it is created. Otherwise, an error is left in the interpreter result
** and NULL returned.
**
** If the arrayok argument is false and the named variable is an array,
** an error is left in the interpreter result and NULL returned. If
** arrayok is true an array name is Ok.
*/
struct Find {
Th_HashEntry *pValueEntry;
Th_HashEntry *pElemEntry;
const char *zElem;
int nElem;
};
typedef struct Find Find;
static Th_Variable *thFindValue(
Th_Interp *interp,
const char *zVar, /* Pointer to variable name */
int nVar, /* Number of bytes at nVar */
int create, /* If true, create the variable if not found */
int arrayok, /* If true, an array is Ok. Otherwise array==error */
int noerror, /* If false, set interpreter result to error */
Find *pFind /* If non-zero, place output here */
){
const char *zOuter;
int nOuter;
const char *zInner;
int nInner;
int isGlobal;
Th_HashEntry *pEntry;
Th_Frame *pFrame = interp->pFrame;
Th_Variable *pValue;
thAnalyseVarname(zVar, nVar, &zOuter, &nOuter, &zInner, &nInner, &isGlobal);
if( pFind ){
pFind->zElem = zInner;
pFind->nElem = nInner;
}
if( isGlobal ){
while( pFrame->pCaller ) pFrame = pFrame->pCaller;
}
pEntry = Th_HashFind(interp, pFrame->paVar, zOuter, nOuter, create);
assert(pEntry || create<=0);
if( pFind ){
pFind->pValueEntry = pEntry;
}
if( !pEntry ){
goto no_such_var;
}
pValue = (Th_Variable *)pEntry->pData;
if( !pValue ){
assert(create);
|
| ︙ | | | ︙ | |
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
|
if( !pValue->pHash ){
if( !create ){
goto no_such_var;
}
pValue->pHash = Th_HashNew(interp);
}
pEntry = Th_HashFind(interp, pValue->pHash, zInner, nInner, create);
if( !pEntry ){
goto no_such_var;
}
pValue = (Th_Variable *)pEntry->pData;
if( !pValue ){
assert(create);
pValue = Th_Malloc(interp, sizeof(Th_Variable));
|
>
>
>
>
|
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
|
if( !pValue->pHash ){
if( !create ){
goto no_such_var;
}
pValue->pHash = Th_HashNew(interp);
}
pEntry = Th_HashFind(interp, pValue->pHash, zInner, nInner, create);
assert(pEntry || create<=0);
if( pFind ){
pFind->pElemEntry = pEntry;
}
if( !pEntry ){
goto no_such_var;
}
pValue = (Th_Variable *)pEntry->pData;
if( !pValue ){
assert(create);
pValue = Th_Malloc(interp, sizeof(Th_Variable));
|
| ︙ | | | ︙ | |
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
|
**
** If the named variable does not exist, return TH_ERROR and leave
** an error message in the interpreter result.
*/
int Th_GetVar(Th_Interp *interp, const char *zVar, int nVar){
Th_Variable *pValue;
pValue = thFindValue(interp, zVar, nVar, 0, 0, 0);
if( !pValue ){
return TH_ERROR;
}
if( !pValue->zData ){
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
return TH_ERROR;
}
return Th_SetResult(interp, pValue->zData, pValue->nData);
}
/*
** Return true if variable (zVar, nVar) exists.
*/
int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 0, 1);
return pValue && pValue->zData;
}
/*
** String (zVar, nVar) must contain the name of a scalar variable or
** array member. If the variable does not exist it is created. The
** variable is set to the value supplied in string (zValue, nValue).
**
** If (zVar, nVar) refers to an existing array, TH_ERROR is returned
** and an error message left in the interpreter result.
*/
int Th_SetVar(
Th_Interp *interp,
const char *zVar,
int nVar,
const char *zValue,
int nValue
){
Th_Variable *pValue;
pValue = thFindValue(interp, zVar, nVar, 1, 0, 0);
if( !pValue ){
return TH_ERROR;
}
if( nValue<0 ){
nValue = th_strlen(zValue);
}
|
|
|
|
|
|
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
|
**
** If the named variable does not exist, return TH_ERROR and leave
** an error message in the interpreter result.
*/
int Th_GetVar(Th_Interp *interp, const char *zVar, int nVar){
Th_Variable *pValue;
pValue = thFindValue(interp, zVar, nVar, 0, 0, 0, 0);
if( !pValue ){
return TH_ERROR;
}
if( !pValue->zData ){
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
return TH_ERROR;
}
return Th_SetResult(interp, pValue->zData, pValue->nData);
}
/*
** Return true if variable (zVar, nVar) exists.
*/
int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
return pValue && (pValue->zData || pValue->pHash);
}
/*
** String (zVar, nVar) must contain the name of a scalar variable or
** array member. If the variable does not exist it is created. The
** variable is set to the value supplied in string (zValue, nValue).
**
** If (zVar, nVar) refers to an existing array, TH_ERROR is returned
** and an error message left in the interpreter result.
*/
int Th_SetVar(
Th_Interp *interp,
const char *zVar,
int nVar,
const char *zValue,
int nValue
){
Th_Variable *pValue;
pValue = thFindValue(interp, zVar, nVar, 1, 0, 0, 0);
if( !pValue ){
return TH_ERROR;
}
if( nValue<0 ){
nValue = th_strlen(zValue);
}
|
| ︙ | | | ︙ | |
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
|
pFrame = getFrame(interp, iFrame);
if( !pFrame ){
return TH_ERROR;
}
pSavedFrame = interp->pFrame;
interp->pFrame = pFrame;
pValue = thFindValue(interp, zLink, nLink, 1, 1, 0);
interp->pFrame = pSavedFrame;
pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1);
if( pEntry->pData ){
Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal);
return TH_ERROR;
}
pEntry->pData = (void *)pValue;
pValue->nRef++;
return TH_OK;
}
/*
** Input string (zVar, nVar) must contain the name of a scalar variable,
** an array, or an array member. If the identified variable exists, it
** is deleted and TH_OK returned. Otherwise, an error message is left
** in the interpreter result and TH_ERROR is returned.
*/
int Th_UnsetVar(Th_Interp *interp, const char *zVar, int nVar){
Th_Variable *pValue;
pValue = thFindValue(interp, zVar, nVar, 0, 1, 0);
if( !pValue ){
return TH_ERROR;
}
if( pValue->zData ){
Th_Free(interp, pValue->zData);
pValue->zData = 0;
}
if( pValue->pHash ){
Th_HashIterate(interp, pValue->pHash, thFreeVariable, (void *)interp);
Th_HashDelete(interp, pValue->pHash);
pValue->pHash = 0;
}
thFindValue(interp, zVar, nVar, -1, 1, 1); /* Finally, delete from frame */
return TH_OK;
}
/*
** Return an allocated buffer containing a copy of string (z, n). The
** caller is responsible for eventually calling Th_Free() to free
** the returned buffer.
*/
|
|
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
>
|
>
|
|
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
|
pFrame = getFrame(interp, iFrame);
if( !pFrame ){
return TH_ERROR;
}
pSavedFrame = interp->pFrame;
interp->pFrame = pFrame;
pValue = thFindValue(interp, zLink, nLink, 1, 1, 0, 0);
interp->pFrame = pSavedFrame;
pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1);
if( pEntry->pData ){
Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal);
return TH_ERROR;
}
pEntry->pData = (void *)pValue;
pValue->nRef++;
return TH_OK;
}
/*
** Input string (zVar, nVar) must contain the name of a scalar variable,
** an array, or an array member. If the identified variable exists, it
** is deleted and TH_OK returned. Otherwise, an error message is left
** in the interpreter result and TH_ERROR is returned.
*/
int Th_UnsetVar(Th_Interp *interp, const char *zVar, int nVar){
Find find;
Th_Variable *pValue;
Th_HashEntry *pEntry;
int rc = TH_ERROR;
memset(&find, 0, sizeof(Find));
pValue = thFindValue(interp, zVar, nVar, 0, 1, 0, &find);
if( !pValue ){
return rc;
}
if( pValue->zData || pValue->pHash ){
rc = TH_OK;
}else {
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
}
/*
** The variable may be shared by more than one frame; therefore, make sure
** it is actually freed prior to freeing the parent structure. The values
** for the variable must be freed now so the variable appears undefined in
** all frames. The hash entry in the current frame must also be deleted
** now; otherwise, if the current stack frame is later popped, it will try
** to delete a variable which has already been freed.
*/
if( find.zElem ){
pEntry = find.pElemEntry;
}else{
pEntry = find.pValueEntry;
}
assert( pEntry );
assert( pValue );
if( thFreeVariable(pEntry, (void *)interp) ){
if( find.zElem ){
Th_Variable *pValue2 = find.pValueEntry->pData;
Th_HashFind(interp, pValue2->pHash, find.zElem, find.nElem, -1);
}else{
Th_Free(interp, pEntry->pData);
pEntry->pData = 0;
}
}else{
if( pValue->zData ){
Th_Free(interp, pValue->zData);
pValue->zData = 0;
}
if( pValue->pHash ){
Th_HashIterate(interp, pValue->pHash, thFreeVariable, (void *)interp);
Th_HashDelete(interp, pValue->pHash);
pValue->pHash = 0;
}
}
if( !find.zElem ){
thFindValue(interp, zVar, nVar, -1, 1, 1, 0);
}
return rc;
}
/*
** Return an allocated buffer containing a copy of string (z, n). The
** caller is responsible for eventually calling Th_Free() to free
** the returned buffer.
*/
|
| ︙ | | | ︙ | |
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
|
return p;
}
/*
** Iterate through all values currently stored in the hash table. Invoke
** the callback function xCallback for each entry. The second argument
** passed to xCallback is a copy of the fourth argument passed to this
** function.
*/
void Th_HashIterate(
Th_Interp *interp,
Th_Hash *pHash,
void (*xCallback)(Th_HashEntry *pEntry, void *pContext),
void *pContext
){
int i;
for(i=0; i<TH_HASHSIZE; i++){
Th_HashEntry *pEntry;
Th_HashEntry *pNext;
for(pEntry=pHash->a[i]; pEntry; pEntry=pNext){
pNext = pEntry->pNext;
xCallback(pEntry, pContext);
}
}
}
/*
** Helper function for Th_HashDelete().
*/
static void xFreeHashEntry(Th_HashEntry *pEntry, void *pContext){
Th_Free((Th_Interp *)pContext, (void *)pEntry);
}
/*
** Free a hash-table previously allocated by Th_HashNew().
*/
void Th_HashDelete(Th_Interp *interp, Th_Hash *pHash){
if( pHash ){
|
|
>
|
|
|
>
|
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
|
return p;
}
/*
** Iterate through all values currently stored in the hash table. Invoke
** the callback function xCallback for each entry. The second argument
** passed to xCallback is a copy of the fourth argument passed to this
** function. The return value from the callback function xCallback is
** ignored.
*/
void Th_HashIterate(
Th_Interp *interp,
Th_Hash *pHash,
int (*xCallback)(Th_HashEntry *pEntry, void *pContext),
void *pContext
){
int i;
for(i=0; i<TH_HASHSIZE; i++){
Th_HashEntry *pEntry;
Th_HashEntry *pNext;
for(pEntry=pHash->a[i]; pEntry; pEntry=pNext){
pNext = pEntry->pNext;
xCallback(pEntry, pContext);
}
}
}
/*
** Helper function for Th_HashDelete(). Always returns non-zero.
*/
static int xFreeHashEntry(Th_HashEntry *pEntry, void *pContext){
Th_Free((Th_Interp *)pContext, (void *)pEntry);
return 1;
}
/*
** Free a hash-table previously allocated by Th_HashNew().
*/
void Th_HashDelete(Th_Interp *interp, Th_Hash *pHash){
if( pHash ){
|
| ︙ | | | ︙ | |