aboutsummaryrefslogtreecommitdiff
path: root/jim.c
diff options
context:
space:
mode:
authorSteve Bennett <steveb@workware.net.au>2010-01-24 13:46:32 +1000
committerSteve Bennett <steveb@workware.net.au>2010-10-15 11:02:45 +1000
commitee6dbe0a8d66f8f17a5da82e8dad810d88e33bf6 (patch)
tree994b59d11b3199f697adaea8303ae8b5dc438397 /jim.c
parent541fe7c30691ace08847a35280d9cc8bc02e9a72 (diff)
downloadjimtcl-ee6dbe0a8d66f8f17a5da82e8dad810d88e33bf6.zip
jimtcl-ee6dbe0a8d66f8f17a5da82e8dad810d88e33bf6.tar.gz
jimtcl-ee6dbe0a8d66f8f17a5da82e8dad810d88e33bf6.tar.bz2
Allow catch to specify what is caught
*: Default to the same as Tcl. Not signal, eval, exit. *: Use 'catch -exit' to also catch exit. *: Also map for standard return codes: [info returncodes] *: Also Jim_ReturnCode() *: Add Jim_FindByName() for searching in a char* array *: Fix 'info nameofexectutable' if $::jim_argv0 is not set
Diffstat (limited to 'jim.c')
-rw-r--r--jim.c204
1 files changed, 149 insertions, 55 deletions
diff --git a/jim.c b/jim.c
index 8277bd3..09481f3 100644
--- a/jim.c
+++ b/jim.c
@@ -116,6 +116,7 @@ static int JimAddErrorToStack(Jim_Interp *interp, int retcode, const char *filen
static Jim_Obj *Jim_ExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype, const char *prefix, const char * const *tablePtr, const char *name);
static const Jim_HashTableType JimVariablesHashTableType;
@@ -6333,6 +6334,21 @@ int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
* Return Code Object.
* ---------------------------------------------------------------------------*/
+/* NOTE: These must be kept in the same order as JIM_OK, JIM_ERR, ... */
+static const char *jimReturnCodes[] = {
+ [JIM_OK] = "ok",
+ [JIM_ERR] = "error",
+ [JIM_RETURN] = "return",
+ [JIM_BREAK] = "break",
+ [JIM_CONTINUE] = "continue",
+ [JIM_SIGNAL] = "signal",
+ [JIM_EXIT] = "exit",
+ [JIM_EVAL] = "eval",
+ NULL
+};
+
+#define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
+
static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
static const Jim_ObjType returnCodeObjType = {
@@ -6343,19 +6359,28 @@ static const Jim_ObjType returnCodeObjType = {
JIM_TYPE_NONE,
};
+/* Converts a (standard) return code to a string. Returns "?" for
+ * non-standard return codes.
+ */
+const char *Jim_ReturnCode(int code)
+{
+ if (code < 0 || code >= jimReturnCodesSize) {
+ return "?";
+ }
+ else {
+ return jimReturnCodes[code];
+ }
+}
+
int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
{
int returnCode;
jim_wide wideValue;
- /* NOTE: These must be kept in the same order as JIM_OK, JIM_ERR, ... */
- static const char *options[] = {
- "ok", "error", "return", "break", "continue", "signal", "exit", "eval", NULL
- };
/* Try to convert into an integer */
if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
returnCode = (int) wideValue;
- else if (Jim_GetEnum(interp, objPtr, options, &returnCode, NULL, JIM_NONE) != JIM_OK) {
+ else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp),
"expected return code but got '", Jim_GetString(objPtr, NULL), "'",
@@ -11796,46 +11821,84 @@ static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc,
Jim_Obj *const *argv)
{
int exitCode = 0;
+ int i;
int sig = 0;
- if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-signal")) {
- sig++;
+ /* Which return codes are caught? These are the defaults */
+ jim_wide mask = (1 << JIM_OK | 1 << JIM_ERR | 1 << JIM_BREAK | 1 << JIM_CONTINUE | 1 << JIM_RETURN);
+
+ for (i = 1; i < argc - 2; i++) {
+ const char *arg = Jim_GetString(argv[i], NULL);
+ jim_wide option;
+ int add;
+
+ /* It's a pity we can't use Jim_GetEnum here :-( */
+ if (strncmp(arg, "-no", 3) == 0) {
+ arg += 3;
+ add = 0;
+ }
+ else if (*arg == '-') {
+ arg++;
+ add = 1;
+ }
+ else {
+ goto wrongargs;
+ }
+
+ if (Jim_StringToWide(arg, &option, 10) != JIM_OK) {
+ option = -1;
+ }
+ if (option < 0) {
+ option = Jim_FindByName(arg, jimReturnCodes, jimReturnCodesSize);
+ }
+ if (option < 0) {
+ goto wrongargs;
+ }
+
+ if (add) {
+ mask |= (1 << option);
+ }
+ else {
+ mask &= ~(1 << option);
+ }
}
- if (argc - sig != 2 && argc - sig != 3) {
- Jim_WrongNumArgs(interp, 1, argv, "?-signal? script ?varName?");
+ argc -= i;
+ if (argc != 1 && argc != 2) {
+wrongargs:
+ Jim_WrongNumArgs(interp, 1, argv, "?-?no?code ...? script ?varName?");
return JIM_ERR;
}
- argc -= sig;
- argv += sig;
+ argv += i;
+
+ if (mask & (1 << JIM_SIGNAL)) {
+ sig++;
+ }
interp->signal_level += sig;
- exitCode = Jim_EvalObj(interp, argv[1]);
+ exitCode = Jim_EvalObj(interp, argv[0]);
interp->signal_level -= sig;
- /* If we get TCL_SIGNAL without the -signal parameter,
- * just pass it through to be caught at a higher level
- */
- if (exitCode == JIM_SIGNAL && !sig) {
+ /* Catch or pass through? Only the first 64 codes can be passed through */
+ if (exitCode >= 0 && exitCode < sizeof(mask) && ((1 << exitCode) & mask) == 0) {
+ /* Not caught, pass it up */
return exitCode;
}
- if (sig) {
- if (exitCode == JIM_SIGNAL && interp->signal_level == 0) {
- /* Yes, catch the signal at this level */
- if (interp->signal_to_name) {
- Jim_SetResultString(interp, interp->signal_to_name(interp->signal), -1);
- }
- else {
- Jim_SetResultInt(interp, interp->signal);
- }
- interp->signal = 0;
+ if (sig && exitCode == JIM_SIGNAL && interp->signal_level == 0) {
+ /* Yes, catch the signal at this level */
+ if (interp->signal_to_name) {
+ Jim_SetResultString(interp, interp->signal_to_name(interp->signal), -1);
+ }
+ else {
+ Jim_SetResultInt(interp, interp->signal);
}
+ interp->signal = 0;
}
- if (argc == 3) {
- if (Jim_SetVariable(interp, argv[2], Jim_GetResult(interp))
+ if (argc == 2) {
+ if (Jim_SetVariable(interp, argv[1], Jim_GetResult(interp))
!= JIM_OK)
return JIM_ERR;
}
@@ -12073,11 +12136,12 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc,
static const char *commands[] = {
"body", "commands", "procs", "exists", "globals", "level", "locals",
"vars", "version", "patchlevel", "complete", "args", "hostname",
- "script", "source", "stacktrace", "nameofexecutable", NULL
+ "script", "source", "stacktrace", "nameofexecutable", "returncodes", NULL
};
enum {INFO_BODY, INFO_COMMANDS, INFO_PROCS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL,
INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_PATCHLEVEL, INFO_COMPLETE, INFO_ARGS,
- INFO_HOSTNAME, INFO_SCRIPT, INFO_SOURCE, INFO_STACKTRACE, INFO_NAMEOFEXECUTABLE};
+ INFO_HOSTNAME, INFO_SCRIPT, INFO_SOURCE, INFO_STACKTRACE, INFO_NAMEOFEXECUTABLE,
+ INFO_RETURNCODES };
if (argc < 2) {
Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?");
@@ -12211,6 +12275,18 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc,
/* Redirect to Tcl proc */
return Jim_Eval(interp, "info_nameofexecutable");
}
+ else if (cmd == INFO_RETURNCODES) {
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+ int i;
+
+ for (i = 0; jimReturnCodes[i]; i++) {
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewIntObj(interp, i));
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, jimReturnCodes[i], -1));
+ }
+
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+ }
return result;
}
@@ -12778,16 +12854,44 @@ void Jim_PrintErrorMessage(Jim_Interp *interp)
}
}
-int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype, const char *prefix, const char * const *tablePtr, const char *name)
+{
+ int count;
+ char **tablePtrSorted;
+ int i;
+
+ for (count = 0; tablePtr[count]; count++) {
+ }
+
+ if (name == NULL)
+ name = "option";
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp),
+ badtype, name, " \"", arg, "\": must be ",
+ NULL);
+ tablePtrSorted = Jim_Alloc(sizeof(char*)*count);
+ memcpy(tablePtrSorted, tablePtr, sizeof(char*)*count);
+ qsort(tablePtrSorted, count, sizeof(char*), qsortCompareStringPointers);
+ for (i = 0; i < count; i++) {
+ if (i+1 == count && count > 1)
+ Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
+ Jim_AppendStrings(interp, Jim_GetResult(interp),
+ prefix, tablePtrSorted[i], NULL);
+ if (i+1 != count)
+ Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
+ }
+ Jim_Free(tablePtrSorted);
+}
+
+int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
const char * const *tablePtr, int *indexPtr, const char *name, int flags)
{
const char *bad = "bad ";
const char * const *entryPtr = NULL;
- char **tablePtrSorted;
int i;
+ int match = -1;
int arglen;
const char *arg = Jim_GetString(objPtr, &arglen);
- int match = -1;
*indexPtr = -1;
@@ -12822,32 +12926,22 @@ int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
ambiguous:
if (flags & JIM_ERRMSG) {
- int count;
- for (count = 0; tablePtr[count]; count++) {
- }
-
- if (name == NULL)
- name = "option";
- Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
- Jim_AppendStrings(interp, Jim_GetResult(interp),
- bad, name, " \"", Jim_GetString(objPtr, NULL), "\": must be ",
- NULL);
- tablePtrSorted = Jim_Alloc(sizeof(char*)*count);
- memcpy(tablePtrSorted, tablePtr, sizeof(char*)*count);
- qsort(tablePtrSorted, count, sizeof(char*), qsortCompareStringPointers);
- for (i = 0; i < count; i++) {
- if (i+1 == count && count > 1)
- Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
- Jim_AppendString(interp, Jim_GetResult(interp),
- tablePtrSorted[i], -1);
- if (i+1 != count)
- Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
- }
- Jim_Free(tablePtrSorted);
+ JimSetFailedEnumResult(interp, arg, bad, "", tablePtr, name);
}
return JIM_ERR;
}
+int Jim_FindByName(const char *name, const char *array[], size_t len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ if (array[i] && strcmp(array[i], name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
int Jim_IsDict(Jim_Obj *objPtr)
{
return objPtr->typePtr == &dictObjType;