Fossil SCM
Make sure the TH1 'info exists' sub-command preserves the existing interp error stack trace.
Commit
9765b03759ff95c506b6b5777c6849ba0591ec2d
Parent
ad2dd5680baf348…
2 files changed
+16
-9
+5
M
src/th.c
+16
-9
| --- src/th.c | ||
| +++ src/th.c | ||
| @@ -1060,11 +1060,12 @@ | ||
| 1060 | 1060 | static Th_Variable *thFindValue( |
| 1061 | 1061 | Th_Interp *interp, |
| 1062 | 1062 | const char *zVar, /* Pointer to variable name */ |
| 1063 | 1063 | int nVar, /* Number of bytes at nVar */ |
| 1064 | 1064 | int create, /* If true, create the variable if not found */ |
| 1065 | - int arrayok /* If true, an array is Ok. Otherwise array==error */ | |
| 1065 | + int arrayok, /* If true, an array is Ok. Otherwise array==error */ | |
| 1066 | + int noerror /* If false, set interpreter result to error message */ | |
| 1066 | 1067 | ){ |
| 1067 | 1068 | const char *zOuter; |
| 1068 | 1069 | int nOuter; |
| 1069 | 1070 | const char *zInner; |
| 1070 | 1071 | int nInner; |
| @@ -1093,11 +1094,13 @@ | ||
| 1093 | 1094 | pEntry->pData = (void *)pValue; |
| 1094 | 1095 | } |
| 1095 | 1096 | |
| 1096 | 1097 | if( zInner ){ |
| 1097 | 1098 | if( pValue->zData ){ |
| 1098 | - Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter); | |
| 1099 | + if( !noerror ){ | |
| 1100 | + Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter); | |
| 1101 | + } | |
| 1099 | 1102 | return 0; |
| 1100 | 1103 | } |
| 1101 | 1104 | if( !pValue->pHash ){ |
| 1102 | 1105 | if( !create ){ |
| 1103 | 1106 | goto no_such_var; |
| @@ -1115,19 +1118,23 @@ | ||
| 1115 | 1118 | pValue->nRef = 1; |
| 1116 | 1119 | pEntry->pData = (void *)pValue; |
| 1117 | 1120 | } |
| 1118 | 1121 | }else{ |
| 1119 | 1122 | if( pValue->pHash && !arrayok ){ |
| 1120 | - Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter); | |
| 1123 | + if( !noerror ){ | |
| 1124 | + Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter); | |
| 1125 | + } | |
| 1121 | 1126 | return 0; |
| 1122 | 1127 | } |
| 1123 | 1128 | } |
| 1124 | 1129 | |
| 1125 | 1130 | return pValue; |
| 1126 | 1131 | |
| 1127 | 1132 | no_such_var: |
| 1128 | - Th_ErrorMessage(interp, "no such variable:", zVar, nVar); | |
| 1133 | + if( !noerror ){ | |
| 1134 | + Th_ErrorMessage(interp, "no such variable:", zVar, nVar); | |
| 1135 | + } | |
| 1129 | 1136 | return 0; |
| 1130 | 1137 | } |
| 1131 | 1138 | |
| 1132 | 1139 | /* |
| 1133 | 1140 | ** String (zVar, nVar) must contain the name of a scalar variable or |
| @@ -1138,11 +1145,11 @@ | ||
| 1138 | 1145 | ** an error message in the interpreter result. |
| 1139 | 1146 | */ |
| 1140 | 1147 | int Th_GetVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1141 | 1148 | Th_Variable *pValue; |
| 1142 | 1149 | |
| 1143 | - pValue = thFindValue(interp, zVar, nVar, 0, 0); | |
| 1150 | + pValue = thFindValue(interp, zVar, nVar, 0, 0, 0); | |
| 1144 | 1151 | if( !pValue ){ |
| 1145 | 1152 | return TH_ERROR; |
| 1146 | 1153 | } |
| 1147 | 1154 | if( !pValue->zData ){ |
| 1148 | 1155 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); |
| @@ -1154,11 +1161,11 @@ | ||
| 1154 | 1161 | |
| 1155 | 1162 | /* |
| 1156 | 1163 | ** Return true if variable (zVar, nVar) exists. |
| 1157 | 1164 | */ |
| 1158 | 1165 | int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1159 | - Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 0); | |
| 1166 | + Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 0, 1); | |
| 1160 | 1167 | return pValue && pValue->zData; |
| 1161 | 1168 | } |
| 1162 | 1169 | |
| 1163 | 1170 | /* |
| 1164 | 1171 | ** String (zVar, nVar) must contain the name of a scalar variable or |
| @@ -1175,11 +1182,11 @@ | ||
| 1175 | 1182 | const char *zValue, |
| 1176 | 1183 | int nValue |
| 1177 | 1184 | ){ |
| 1178 | 1185 | Th_Variable *pValue; |
| 1179 | 1186 | |
| 1180 | - pValue = thFindValue(interp, zVar, nVar, 1, 0); | |
| 1187 | + pValue = thFindValue(interp, zVar, nVar, 1, 0, 0); | |
| 1181 | 1188 | if( !pValue ){ |
| 1182 | 1189 | return TH_ERROR; |
| 1183 | 1190 | } |
| 1184 | 1191 | |
| 1185 | 1192 | if( nValue<0 ){ |
| @@ -1218,11 +1225,11 @@ | ||
| 1218 | 1225 | if( !pFrame ){ |
| 1219 | 1226 | return TH_ERROR; |
| 1220 | 1227 | } |
| 1221 | 1228 | pSavedFrame = interp->pFrame; |
| 1222 | 1229 | interp->pFrame = pFrame; |
| 1223 | - pValue = thFindValue(interp, zLink, nLink, 1, 1); | |
| 1230 | + pValue = thFindValue(interp, zLink, nLink, 1, 1, 0); | |
| 1224 | 1231 | interp->pFrame = pSavedFrame; |
| 1225 | 1232 | |
| 1226 | 1233 | pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1); |
| 1227 | 1234 | if( pEntry->pData ){ |
| 1228 | 1235 | Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal); |
| @@ -1241,11 +1248,11 @@ | ||
| 1241 | 1248 | ** in the interpreter result and TH_ERROR is returned. |
| 1242 | 1249 | */ |
| 1243 | 1250 | int Th_UnsetVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1244 | 1251 | Th_Variable *pValue; |
| 1245 | 1252 | |
| 1246 | - pValue = thFindValue(interp, zVar, nVar, 0, 1); | |
| 1253 | + pValue = thFindValue(interp, zVar, nVar, 0, 1, 0); | |
| 1247 | 1254 | if( !pValue ){ |
| 1248 | 1255 | return TH_ERROR; |
| 1249 | 1256 | } |
| 1250 | 1257 | |
| 1251 | 1258 | Th_Free(interp, pValue->zData); |
| 1252 | 1259 |
| --- src/th.c | |
| +++ src/th.c | |
| @@ -1060,11 +1060,12 @@ | |
| 1060 | static Th_Variable *thFindValue( |
| 1061 | Th_Interp *interp, |
| 1062 | const char *zVar, /* Pointer to variable name */ |
| 1063 | int nVar, /* Number of bytes at nVar */ |
| 1064 | int create, /* If true, create the variable if not found */ |
| 1065 | int arrayok /* If true, an array is Ok. Otherwise array==error */ |
| 1066 | ){ |
| 1067 | const char *zOuter; |
| 1068 | int nOuter; |
| 1069 | const char *zInner; |
| 1070 | int nInner; |
| @@ -1093,11 +1094,13 @@ | |
| 1093 | pEntry->pData = (void *)pValue; |
| 1094 | } |
| 1095 | |
| 1096 | if( zInner ){ |
| 1097 | if( pValue->zData ){ |
| 1098 | Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter); |
| 1099 | return 0; |
| 1100 | } |
| 1101 | if( !pValue->pHash ){ |
| 1102 | if( !create ){ |
| 1103 | goto no_such_var; |
| @@ -1115,19 +1118,23 @@ | |
| 1115 | pValue->nRef = 1; |
| 1116 | pEntry->pData = (void *)pValue; |
| 1117 | } |
| 1118 | }else{ |
| 1119 | if( pValue->pHash && !arrayok ){ |
| 1120 | Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter); |
| 1121 | return 0; |
| 1122 | } |
| 1123 | } |
| 1124 | |
| 1125 | return pValue; |
| 1126 | |
| 1127 | no_such_var: |
| 1128 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); |
| 1129 | return 0; |
| 1130 | } |
| 1131 | |
| 1132 | /* |
| 1133 | ** String (zVar, nVar) must contain the name of a scalar variable or |
| @@ -1138,11 +1145,11 @@ | |
| 1138 | ** an error message in the interpreter result. |
| 1139 | */ |
| 1140 | int Th_GetVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1141 | Th_Variable *pValue; |
| 1142 | |
| 1143 | pValue = thFindValue(interp, zVar, nVar, 0, 0); |
| 1144 | if( !pValue ){ |
| 1145 | return TH_ERROR; |
| 1146 | } |
| 1147 | if( !pValue->zData ){ |
| 1148 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); |
| @@ -1154,11 +1161,11 @@ | |
| 1154 | |
| 1155 | /* |
| 1156 | ** Return true if variable (zVar, nVar) exists. |
| 1157 | */ |
| 1158 | int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1159 | Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 0); |
| 1160 | return pValue && pValue->zData; |
| 1161 | } |
| 1162 | |
| 1163 | /* |
| 1164 | ** String (zVar, nVar) must contain the name of a scalar variable or |
| @@ -1175,11 +1182,11 @@ | |
| 1175 | const char *zValue, |
| 1176 | int nValue |
| 1177 | ){ |
| 1178 | Th_Variable *pValue; |
| 1179 | |
| 1180 | pValue = thFindValue(interp, zVar, nVar, 1, 0); |
| 1181 | if( !pValue ){ |
| 1182 | return TH_ERROR; |
| 1183 | } |
| 1184 | |
| 1185 | if( nValue<0 ){ |
| @@ -1218,11 +1225,11 @@ | |
| 1218 | if( !pFrame ){ |
| 1219 | return TH_ERROR; |
| 1220 | } |
| 1221 | pSavedFrame = interp->pFrame; |
| 1222 | interp->pFrame = pFrame; |
| 1223 | pValue = thFindValue(interp, zLink, nLink, 1, 1); |
| 1224 | interp->pFrame = pSavedFrame; |
| 1225 | |
| 1226 | pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1); |
| 1227 | if( pEntry->pData ){ |
| 1228 | Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal); |
| @@ -1241,11 +1248,11 @@ | |
| 1241 | ** in the interpreter result and TH_ERROR is returned. |
| 1242 | */ |
| 1243 | int Th_UnsetVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1244 | Th_Variable *pValue; |
| 1245 | |
| 1246 | pValue = thFindValue(interp, zVar, nVar, 0, 1); |
| 1247 | if( !pValue ){ |
| 1248 | return TH_ERROR; |
| 1249 | } |
| 1250 | |
| 1251 | Th_Free(interp, pValue->zData); |
| 1252 |
| --- src/th.c | |
| +++ src/th.c | |
| @@ -1060,11 +1060,12 @@ | |
| 1060 | static Th_Variable *thFindValue( |
| 1061 | Th_Interp *interp, |
| 1062 | const char *zVar, /* Pointer to variable name */ |
| 1063 | int nVar, /* Number of bytes at nVar */ |
| 1064 | int create, /* If true, create the variable if not found */ |
| 1065 | int arrayok, /* If true, an array is Ok. Otherwise array==error */ |
| 1066 | int noerror /* If false, set interpreter result to error message */ |
| 1067 | ){ |
| 1068 | const char *zOuter; |
| 1069 | int nOuter; |
| 1070 | const char *zInner; |
| 1071 | int nInner; |
| @@ -1093,11 +1094,13 @@ | |
| 1094 | pEntry->pData = (void *)pValue; |
| 1095 | } |
| 1096 | |
| 1097 | if( zInner ){ |
| 1098 | if( pValue->zData ){ |
| 1099 | if( !noerror ){ |
| 1100 | Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter); |
| 1101 | } |
| 1102 | return 0; |
| 1103 | } |
| 1104 | if( !pValue->pHash ){ |
| 1105 | if( !create ){ |
| 1106 | goto no_such_var; |
| @@ -1115,19 +1118,23 @@ | |
| 1118 | pValue->nRef = 1; |
| 1119 | pEntry->pData = (void *)pValue; |
| 1120 | } |
| 1121 | }else{ |
| 1122 | if( pValue->pHash && !arrayok ){ |
| 1123 | if( !noerror ){ |
| 1124 | Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter); |
| 1125 | } |
| 1126 | return 0; |
| 1127 | } |
| 1128 | } |
| 1129 | |
| 1130 | return pValue; |
| 1131 | |
| 1132 | no_such_var: |
| 1133 | if( !noerror ){ |
| 1134 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); |
| 1135 | } |
| 1136 | return 0; |
| 1137 | } |
| 1138 | |
| 1139 | /* |
| 1140 | ** String (zVar, nVar) must contain the name of a scalar variable or |
| @@ -1138,11 +1145,11 @@ | |
| 1145 | ** an error message in the interpreter result. |
| 1146 | */ |
| 1147 | int Th_GetVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1148 | Th_Variable *pValue; |
| 1149 | |
| 1150 | pValue = thFindValue(interp, zVar, nVar, 0, 0, 0); |
| 1151 | if( !pValue ){ |
| 1152 | return TH_ERROR; |
| 1153 | } |
| 1154 | if( !pValue->zData ){ |
| 1155 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); |
| @@ -1154,11 +1161,11 @@ | |
| 1161 | |
| 1162 | /* |
| 1163 | ** Return true if variable (zVar, nVar) exists. |
| 1164 | */ |
| 1165 | int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1166 | Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 0, 1); |
| 1167 | return pValue && pValue->zData; |
| 1168 | } |
| 1169 | |
| 1170 | /* |
| 1171 | ** String (zVar, nVar) must contain the name of a scalar variable or |
| @@ -1175,11 +1182,11 @@ | |
| 1182 | const char *zValue, |
| 1183 | int nValue |
| 1184 | ){ |
| 1185 | Th_Variable *pValue; |
| 1186 | |
| 1187 | pValue = thFindValue(interp, zVar, nVar, 1, 0, 0); |
| 1188 | if( !pValue ){ |
| 1189 | return TH_ERROR; |
| 1190 | } |
| 1191 | |
| 1192 | if( nValue<0 ){ |
| @@ -1218,11 +1225,11 @@ | |
| 1225 | if( !pFrame ){ |
| 1226 | return TH_ERROR; |
| 1227 | } |
| 1228 | pSavedFrame = interp->pFrame; |
| 1229 | interp->pFrame = pFrame; |
| 1230 | pValue = thFindValue(interp, zLink, nLink, 1, 1, 0); |
| 1231 | interp->pFrame = pSavedFrame; |
| 1232 | |
| 1233 | pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1); |
| 1234 | if( pEntry->pData ){ |
| 1235 | Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal); |
| @@ -1241,11 +1248,11 @@ | |
| 1248 | ** in the interpreter result and TH_ERROR is returned. |
| 1249 | */ |
| 1250 | int Th_UnsetVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1251 | Th_Variable *pValue; |
| 1252 | |
| 1253 | pValue = thFindValue(interp, zVar, nVar, 0, 1, 0); |
| 1254 | if( !pValue ){ |
| 1255 | return TH_ERROR; |
| 1256 | } |
| 1257 | |
| 1258 | Th_Free(interp, pValue->zData); |
| 1259 |
+5
| --- test/th1.test | ||
| +++ test/th1.test | ||
| @@ -132,10 +132,15 @@ | ||
| 132 | 132 | |
| 133 | 133 | ############################################################################### |
| 134 | 134 | |
| 135 | 135 | fossil test-th-eval "set var 1; unset var; expr {\$var+0}" |
| 136 | 136 | test th1-info-exists-5 {$RESULT eq {TH_ERROR: no such variable: var}} |
| 137 | + | |
| 138 | +############################################################################### | |
| 139 | + | |
| 140 | +fossil test-th-eval "catch {bad}; info exists var; set th_stack_trace" | |
| 141 | +test th1-info-exists-6 {$RESULT eq {bad}} | |
| 137 | 142 | |
| 138 | 143 | ############################################################################### |
| 139 | 144 | |
| 140 | 145 | fossil test-th-eval "set var 1; unset var" |
| 141 | 146 | test th1-unset-1 {$RESULT eq {var}} |
| 142 | 147 |
| --- test/th1.test | |
| +++ test/th1.test | |
| @@ -132,10 +132,15 @@ | |
| 132 | |
| 133 | ############################################################################### |
| 134 | |
| 135 | fossil test-th-eval "set var 1; unset var; expr {\$var+0}" |
| 136 | test th1-info-exists-5 {$RESULT eq {TH_ERROR: no such variable: var}} |
| 137 | |
| 138 | ############################################################################### |
| 139 | |
| 140 | fossil test-th-eval "set var 1; unset var" |
| 141 | test th1-unset-1 {$RESULT eq {var}} |
| 142 |
| --- test/th1.test | |
| +++ test/th1.test | |
| @@ -132,10 +132,15 @@ | |
| 132 | |
| 133 | ############################################################################### |
| 134 | |
| 135 | fossil test-th-eval "set var 1; unset var; expr {\$var+0}" |
| 136 | test th1-info-exists-5 {$RESULT eq {TH_ERROR: no such variable: var}} |
| 137 | |
| 138 | ############################################################################### |
| 139 | |
| 140 | fossil test-th-eval "catch {bad}; info exists var; set th_stack_trace" |
| 141 | test th1-info-exists-6 {$RESULT eq {bad}} |
| 142 | |
| 143 | ############################################################################### |
| 144 | |
| 145 | fossil test-th-eval "set var 1; unset var" |
| 146 | test th1-unset-1 {$RESULT eq {var}} |
| 147 |