diff packages/net/athttpd/current/src/jim.c @ 2326:bd648d8929f6

* cdl/httpd.cdl: Improve CDL dependencies. * doc/athttpd.sgml: Updated to describe lasted changes and corrected minor typos. * src/http.c: Check for "Content-Type" header. This is needed if we want to support parsing form variables in POST requests. * src/jim.c: Updated with latest release from Jim CVS. * src/cgi.c: streamlined cyg_httpd_exec_cgi_tcl(), now uses the 'source' command of tcl to execute a tcl script. * src/forms.c: Modified cyg_handle_method_POST so that the variables in the payload are scanned only if the request has a Content-Type of 'application/x-www-form-urlencoded' * src/jim-aio.c: Added to package. Now tcl has IO functions to access a file system. * include/httpd.h: Added a new mode, CYG_HTTPD_MODE_FORM_DATA which is set when a POST request has a Content-Type of 'application/x-www-form-urlencoded' * cdl/httpd.cdl: add CYGOPT_NET_ATHTTPD_CLOSE_CHUNKED_CONNECTIONS. Default is set to CLOSE, so it is backward compatible with previous versions of the browser. * src/socket.c: cyg_httpd_process_request() uses a loop to collect at least one full frame (til a header terminator is found), cyg_httpd_start_chunked() only close if configured to do so. * src/httpd.c: Overhaul of cyg_httpd_send_error to avoid the use of inbuffer as temporary storage (conflicts with pipelined frames), removed the option to send a page after calling a C language handler * include/httpd.h: Added a new mode, CYG_HTTPD_MODE_NO_CACHE 2006-10-12 Lars Povlsen <lpovlsen@vitesse.com> and Anthony Tonizzo <atonizzo@gmail.com> * cdl/httpd.cdl: add CYGNUM_ATHTTPD_SERVER_MAX_POST to limit POST'ed data * include/http.h: Added header_end, post_data fields to httpstate, Added "302 Found" for POST handler redirect (CYG_HTTPD_STATUS_MOVED_TEMPORARILY) * src/forms.c: Fixed variable decoding, fixed large POST processing * src/http.c: Fixed some debug ouptuts, cleanup after POST processing, overhaul of the pipelined requests code which can now handle multiple requests per frame. * src/socket.c: Removed assert for socket write failure, Accumulating receiving of requests (Browsers (Firefox) may pass partial headers in separate fragments). Fixed some diagnostics output.
author jlarmour
date Mon, 27 Nov 2006 15:41:55 +0000
parents b5670f3c40f2
children
line wrap: on
line diff
--- a/packages/net/athttpd/current/src/jim.c
+++ b/packages/net/athttpd/current/src/jim.c
@@ -2,7 +2,7 @@
  * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
  * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
  *
- * $Id: jim.c,v 1.163 2005/09/19 15:47:15 antirez Exp $
+ * $Id: jim.c,v 1.170 2006/11/06 21:48:57 antirez Exp $
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,11 +20,11 @@
  * limitations under the License.
  */
 
-#include <pkgconf/athttpd.h>
-
 #define __JIM_CORE__
 #define JIM_OPTIMIZATION /* comment to avoid optimizations and reduce size */
 
+#include <pkgconf/athttpd.h>
+
 #ifndef JIM_ANSIC
 #define JIM_DYNLIB      /* Dynamic library support for UNIX and WIN32 */
 #endif /* JIM_ANSIC */
@@ -450,14 +450,19 @@ static jim_wide JimPowWide(jim_wide b, j
 /* -----------------------------------------------------------------------------
  * Special functions
  * ---------------------------------------------------------------------------*/
-void Jim_Panic(const char *fmt, ...)
+
+/* Note that 'interp' may be NULL if not available in the
+ * context of the panic. It's only useful to get the error
+ * file descriptor, it will default to stderr otherwise. */
+void Jim_Panic(Jim_Interp *interp, const char *fmt, ...)
 {
     va_list ap;
+    FILE *fp = interp ? interp->stderr : stderr;
 
     va_start(ap, fmt);
-    fprintf(stderr, "\nJIM INTERPRETER PANIC: ");
-    vfprintf(stderr, fmt, ap);
-    fprintf(stderr, "\n\n");
+    fprintf(fp, JIM_NL "JIM INTERPRETER PANIC: ");
+    vfprintf(fp, fmt, ap);
+    fprintf(fp, JIM_NL JIM_NL);
     va_end(ap);
 #ifdef HAVE_BACKTRACE
     {
@@ -468,9 +473,9 @@ void Jim_Panic(const char *fmt, ...)
         size = backtrace(array, 40);
         strings = backtrace_symbols(array, size);
         for (i = 0; i < size; i++)
-            printf("[backtrace] %s\n", strings[i]);
-        printf("[backtrace] Include the above lines and the output\n");
-        printf("[backtrace] of 'nm <executable>' in the bug report.\n");
+            fprintf(fp,"[backtrace] %s" JIM_NL, strings[i]);
+        fprintf(fp,"[backtrace] Include the above lines and the output" JIM_NL);
+        fprintf(fp,"[backtrace] of 'nm <executable>' in the bug report." JIM_NL);
     }
 #endif
     abort();
@@ -493,7 +498,7 @@ void *Jim_Alloc(int size)
 {
     void *p = malloc(size);
     if (p == NULL)
-        Jim_Panic("Out of memory");
+        Jim_Panic(NULL,"Out of memory");
     return p;
 }
 
@@ -505,7 +510,7 @@ void *Jim_Realloc(void *ptr, int size)
 {
     void *p = realloc(ptr, size);
     if (p == NULL)
-        Jim_Panic("Out of memory");
+        Jim_Panic(NULL,"Out of memory");
     return p;
 }
 
@@ -1406,7 +1411,7 @@ int JimParseComment(struct JimParserCtx 
 /* xdigitval and odigitval are helper functions for JimParserGetToken() */
 static int xdigitval(int c)
 {
-    if (c >= '0' && c <= '7') return c-'0';
+    if (c >= '0' && c <= '9') return c-'0';
     if (c >= 'a' && c <= 'f') return c-'a'+10;
     if (c >= 'A' && c <= 'F') return c-'A'+10;
     return -1;
@@ -1748,7 +1753,7 @@ void Jim_FreeObj(Jim_Interp *interp, Jim
 {
     /* Check if the object was already freed, panic. */
     if (objPtr->refCount != 0)  {
-        Jim_Panic("!!!Object %p freed with bad refcount %d", objPtr,
+        Jim_Panic(interp,"!!!Object %p freed with bad refcount %d", objPtr,
                 objPtr->refCount);
     }
     /* Free the internal representation */
@@ -1835,7 +1840,7 @@ const char *Jim_GetString(Jim_Obj *objPt
     if (objPtr->bytes == NULL) {
         /* Invalid string repr. Generate it. */
         if (objPtr->typePtr->updateStringProc == NULL) {
-            Jim_Panic("UpdataStringProc called against '%s' type.",
+            Jim_Panic(NULL,"UpdataStringProc called against '%s' type.",
                 objPtr->typePtr->name);
         }
         objPtr->typePtr->updateStringProc(objPtr);
@@ -1883,8 +1888,7 @@ void DupStringInternalRep(Jim_Interp *in
 int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
 {
     /* Get a fresh string representation. */
-//    (void*) Jim_GetString(objPtr, NULL);
-    Jim_GetString(objPtr, NULL);
+    (void) Jim_GetString(objPtr, NULL);
     /* Free any other internal representation. */
     Jim_FreeIntRep(interp, objPtr);
     /* Set it as string, i.e. just set the maxLength field. */
@@ -1966,7 +1970,7 @@ void Jim_AppendString(Jim_Interp *interp
         int len)
 {
     if (Jim_IsShared(objPtr))
-        Jim_Panic("Jim_AppendString called with shared object");
+        Jim_Panic(interp,"Jim_AppendString called with shared object");
     if (objPtr->typePtr != &stringObjType)
         SetStringFromAny(interp, objPtr);
     StringAppendString(objPtr, str, len);
@@ -2330,9 +2334,9 @@ static void JimSetSourceInfo(Jim_Interp 
         const char *fileName, int lineNumber)
 {
     if (Jim_IsShared(objPtr))
-        Jim_Panic("JimSetSourceInfo called with shared object");
+        Jim_Panic(interp,"JimSetSourceInfo called with shared object");
     if (objPtr->typePtr != NULL)
-        Jim_Panic("JimSetSourceInfo called with typePtr != NULL");
+        Jim_Panic(interp,"JimSetSourceInfo called with typePtr != NULL");
     objPtr->internalRep.sourceValue.fileName =
         Jim_GetSharedString(interp, fileName);
     objPtr->internalRep.sourceValue.lineNumber = lineNumber;
@@ -2698,7 +2702,8 @@ int SetScriptFromAny(Jim_Interp *interp,
                 if (token[end].type == JIM_TT_STR &&
                     token[end+1].type != JIM_TT_SEP &&
                     token[end+1].type != JIM_TT_EOL &&
-                    !strcmp(token[end].objPtr->bytes, "expand"))
+                    (!strcmp(token[end].objPtr->bytes, "expand") ||
+                     !strcmp(token[end].objPtr->bytes, "*")))
                     expand++;
             }
             if (token[end].type == JIM_TT_SEP)
@@ -2727,7 +2732,8 @@ int SetScriptFromAny(Jim_Interp *interp,
                 tokens = 0;
                 continue;
             } else if (tokens == 0 && token[i].type == JIM_TT_STR &&
-                   !strcmp(token[i].objPtr->bytes, "expand"))
+                   (!strcmp(token[i].objPtr->bytes, "expand") ||
+                    !strcmp(token[i].objPtr->bytes, "*")))
             {
                 expand++;
             }
@@ -2921,11 +2927,18 @@ int Jim_CreateProcedure(Jim_Interp *inte
     }
 
     /* Add the new command */
-    Jim_DeleteHashEntry(&interp->commands, cmdName); /* it may already exist */
+
+    /* it may already exist, so we try to delete the old one */
+    if (Jim_DeleteHashEntry(&interp->commands, cmdName) != JIM_ERR) {
+        /* There was an old procedure with the same name, this requires
+         * a 'proc epoch' update. */
+        Jim_InterpIncrProcEpoch(interp);
+    }
+    /* If a procedure with the same name didn't existed there is no need
+     * to increment the 'proc epoch' because creation of a new procedure
+     * can never affect existing cached commands. We don't do
+     * negative caching. */
     Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr);
-    /* There is no need to increment the 'proc epoch' because
-     * creation of a new procedure can never affect existing
-     * cached commands. We don't do negative caching. */
     return JIM_OK;
 
 err:
@@ -3525,10 +3538,6 @@ Jim_Obj *Jim_ExpandDictSugar(Jim_Interp 
     if (Jim_DictKey(interp, dictObjPtr, substKeyObjPtr, &resObjPtr, JIM_ERRMSG)
             != JIM_OK) {
         resObjPtr = NULL;
-        Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
-        Jim_AppendStrings(interp, Jim_GetResult(interp),
-                "Variable '", Jim_GetString(varObjPtr, NULL),
-                "' does not contain a valid dictionary", NULL);
         goto err;
     }
 err:
@@ -3885,7 +3894,8 @@ int Jim_Collect(Jim_Interp *interp)
                 Jim_AddHashEntry(&marks,
                     &objPtr->internalRep.refValue.id, NULL);
 #ifdef JIM_DEBUG_GC
-                printf("MARK (reference): %d refcount: %d\n", 
+                fprintf(interp->stdout,
+                    "MARK (reference): %d refcount: %d" JIM_NL, 
                     (int) objPtr->internalRep.refValue.id,
                     objPtr->refCount);
 #endif
@@ -3923,7 +3933,7 @@ int Jim_Collect(Jim_Interp *interp)
                  * was found. Mark it. */
                 Jim_AddHashEntry(&marks, &id, NULL);
 #ifdef JIM_DEBUG_GC
-                printf("MARK: %d\n", (int)id);
+                fprintf(interp->stdout,"MARK: %d" JIM_NL, (int)id);
 #endif
                 p += JIM_REFERENCE_SPACE;
             }
@@ -3943,7 +3953,7 @@ int Jim_Collect(Jim_Interp *interp)
          * this reference. */
         if (Jim_FindHashEntry(&marks, refId) == NULL) {
 #ifdef JIM_DEBUG_GC
-            printf("COLLECTING %d\n", (int)*refId);
+            fprintf(interp->stdout,"COLLECTING %d" JIM_NL, (int)*refId);
 #endif
             collected++;
             /* Drop the reference, but call the
@@ -4020,6 +4030,7 @@ Jim_Interp *Jim_CreateInterp(void)
     i->numLevels = 0;
     i->maxNestingDepth = JIM_MAX_NESTING_DEPTH;
     i->returnCode = JIM_OK;
+    i->exitCode = 0;
     i->procEpoch = 0;
     i->callFrameEpoch = 0;
     i->liveList = i->freeList = NULL;
@@ -4030,6 +4041,9 @@ Jim_Interp *Jim_CreateInterp(void)
     i->freeFramesList = NULL;
     i->prngState = NULL;
     i->evalRetcodeLevel = -1;
+    i->stdin = stdin;
+    i->stdout = stdout;
+    i->stderr = stderr;
 
     /* Note that we can create objects only after the
      * interpreter liveList and freeList pointers are
@@ -4098,24 +4112,24 @@ void Jim_FreeInterp(Jim_Interp *i)
     if (i->liveList != NULL) {
         Jim_Obj *objPtr = i->liveList;
     
-        printf("\n-------------------------------------\n");
-        printf("Objects still in the free list:\n");
+        fprintf(i->stdout,JIM_NL "-------------------------------------" JIM_NL);
+        fprintf(i->stdout,"Objects still in the free list:" JIM_NL);
         while(objPtr) {
             const char *type = objPtr->typePtr ?
                 objPtr->typePtr->name : "";
-            printf("%p \"%-10s\": '%.20s' (refCount: %d)\n",
+            fprintf(i->stdout,"%p \"%-10s\": '%.20s' (refCount: %d)" JIM_NL,
                     objPtr, type,
                     objPtr->bytes ? objPtr->bytes
                     : "(null)", objPtr->refCount);
             if (objPtr->typePtr == &sourceObjType) {
-                printf("FILE %s LINE %d\n",
+                fprintf(i->stdout, "FILE %s LINE %d" JIM_NL,
                 objPtr->internalRep.sourceValue.fileName,
                 objPtr->internalRep.sourceValue.lineNumber);
             }
             objPtr = objPtr->nextObjPtr;
         }
-        printf("-------------------------------------\n\n");
-        Jim_Panic("Live list non empty freeing the interpreter! Leak?");
+        fprintf(stdout, "-------------------------------------" JIM_NL JIM_NL);
+        Jim_Panic(i,"Live list non empty freeing the interpreter! Leak?");
     }
     /* Free all the freed objects. */
     objPtr = i->freeList;
@@ -4296,6 +4310,28 @@ int Jim_DeleteAssocData(Jim_Interp *inte
     return Jim_DeleteHashEntry(&interp->assocData, key);
 }
 
+int Jim_GetExitCode(Jim_Interp *interp) {
+    return interp->exitCode;
+}
+
+FILE *Jim_SetStdin(Jim_Interp *interp, FILE *fp)
+{
+    if (fp != NULL) interp->stdin = fp;
+    return interp->stdin;
+}
+
+FILE *Jim_SetStdout(Jim_Interp *interp, FILE *fp)
+{
+    if (fp != NULL) interp->stdout = fp;
+    return interp->stdout;
+}
+
+FILE *Jim_SetStderr(Jim_Interp *interp, FILE *fp)
+{
+    if (fp != NULL) interp->stderr = fp;
+    return interp->stderr;
+}
+
 /* -----------------------------------------------------------------------------
  * Shared strings.
  * Every interpreter has an hash table where to put shared dynamically
@@ -4335,7 +4371,7 @@ void Jim_ReleaseSharedString(Jim_Interp 
     Jim_HashEntry *he = Jim_FindHashEntry(&interp->sharedStrings, str);
 
     if (he == NULL)
-        Jim_Panic("Jim_ReleaseSharedString called with "
+        Jim_Panic(interp,"Jim_ReleaseSharedString called with "
               "unknown shared string '%s'", str);
     refCount = (long) he->val;
     refCount--;
@@ -4438,7 +4474,7 @@ int Jim_GetLong(Jim_Interp *interp, Jim_
 void Jim_SetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide wideValue)
 {
     if (Jim_IsShared(objPtr))
-        Jim_Panic("Jim_SetWide called with shared object");
+        Jim_Panic(interp,"Jim_SetWide called with shared object");
     if (objPtr->typePtr != &intObjType) {
         Jim_FreeIntRep(interp, objPtr);
         objPtr->typePtr = &intObjType;
@@ -4518,7 +4554,7 @@ int Jim_GetDouble(Jim_Interp *interp, Ji
 void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double doubleValue)
 {
     if (Jim_IsShared(objPtr))
-        Jim_Panic("Jim_SetDouble called with shared object");
+        Jim_Panic(interp,"Jim_SetDouble called with shared object");
     if (objPtr->typePtr != &doubleObjType) {
         Jim_FreeIntRep(interp, objPtr);
         objPtr->typePtr = &doubleObjType;
@@ -4870,7 +4906,7 @@ static void ListSortElements(Jim_Interp 
     int len;
 
     if (Jim_IsShared(listObjPtr))
-        Jim_Panic("Jim_ListSortElements called with shared object");
+        Jim_Panic(interp,"Jim_ListSortElements called with shared object");
     if (listObjPtr->typePtr != &listObjType)
         SetListFromAny(interp, listObjPtr);
 
@@ -4883,7 +4919,7 @@ static void ListSortElements(Jim_Interp 
         case JIM_LSORT_NOCASE_DECR: fn = ListSortStringNoCaseDecr;  break;
         default:
             fn = NULL; /* avoid warning */
-            Jim_Panic("ListSort called with invalid sort type");
+            Jim_Panic(interp,"ListSort called with invalid sort type");
     }
     qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *)fn);
     Jim_InvalidateStringRep(listObjPtr);
@@ -4973,7 +5009,7 @@ void ListAppendList(Jim_Obj *listPtr, Ji
 void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr)
 {
     if (Jim_IsShared(listPtr))
-        Jim_Panic("Jim_ListAppendElement called with shared object");
+        Jim_Panic(interp,"Jim_ListAppendElement called with shared object");
     if (listPtr->typePtr != &listObjType)
         SetListFromAny(interp, listPtr);
     Jim_InvalidateStringRep(listPtr);
@@ -4983,7 +5019,7 @@ void Jim_ListAppendElement(Jim_Interp *i
 void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr)
 {
     if (Jim_IsShared(listPtr))
-        Jim_Panic("Jim_ListAppendList called with shared object");
+        Jim_Panic(interp,"Jim_ListAppendList called with shared object");
     if (listPtr->typePtr != &listObjType)
         SetListFromAny(interp, listPtr);
     Jim_InvalidateStringRep(listPtr);
@@ -5001,7 +5037,7 @@ void Jim_ListInsertElements(Jim_Interp *
         int objc, Jim_Obj *const *objVec)
 {
     if (Jim_IsShared(listPtr))
-        Jim_Panic("Jim_ListInsertElement called with shared object");
+        Jim_Panic(interp,"Jim_ListInsertElement called with shared object");
     if (listPtr->typePtr != &listObjType)
         SetListFromAny(interp, listPtr);
     if (index >= 0 && index > listPtr->internalRep.listValue.len)
@@ -5435,7 +5471,7 @@ int Jim_DictAddElement(Jim_Interp *inter
         Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
 {
     if (Jim_IsShared(objPtr))
-        Jim_Panic("Jim_DictAddElement called with shared object");
+        Jim_Panic(interp,"Jim_DictAddElement called with shared object");
     if (objPtr->typePtr != &dictObjType) {
         if (SetDictFromAny(interp, objPtr) != JIM_OK)
             return JIM_ERR;
@@ -5451,7 +5487,7 @@ Jim_Obj *Jim_NewDictObj(Jim_Interp *inte
     int i;
 
     if (len % 2)
-        Jim_Panic("Jim_NewDicObj() 'len' argument must be even");
+        Jim_Panic(interp,"Jim_NewDicObj() 'len' argument must be even");
 
     objPtr = Jim_NewObj(interp);
     objPtr->typePtr = &dictObjType;
@@ -5704,6 +5740,8 @@ int SetReturnCodeFromAny(Jim_Interp *int
         returnCode = JIM_CONTINUE;
     else if (!JimStringCompare(str, strLen, "eval", 4, JIM_NOCASE))
         returnCode = JIM_EVAL;
+    else if (!JimStringCompare(str, strLen, "exit", 4, JIM_NOCASE))
+        returnCode = JIM_EXIT;
     else {
         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
         Jim_AppendStrings(interp, Jim_GetResult(interp),
@@ -5922,7 +5960,10 @@ int JimParseExprNumber(struct JimParserC
     if (*pc->p == '-') {
         pc->p++; pc->len--;
     }
-    while (isdigit((int)*pc->p) || (allowdot && *pc->p == '.')) {
+    while (isdigit((int)*pc->p) || (allowdot && *pc->p == '.') ||
+           (pc->p-pc->tstart == 1 && *pc->tstart == '0' &&
+              (*pc->p == 'x' || *pc->p == 'X')))
+    {
         if (*pc->p == '.')
             allowdot = 0;
         pc->p++; pc->len--;
@@ -6112,7 +6153,7 @@ static int ExprCheckCorrectness(ExprByte
             stacklen--;
             break;
         default:
-            Jim_Panic("Default opcode reached ExprCheckCorrectness");
+            Jim_Panic(NULL,"Default opcode reached ExprCheckCorrectness");
             break;
         }
     }
@@ -6195,7 +6236,7 @@ static void ExprMakeLazy(Jim_Interp *int
             default:
                 op = JimExprOperatorInfoByOpcode(expr->opcode[i]);
                 if (op == NULL) {
-                    Jim_Panic("Default reached in ExprMakeLazy()");
+                    Jim_Panic(interp,"Default reached in ExprMakeLazy()");
                 }
                 arity += op->arity;
                 break;
@@ -6337,7 +6378,7 @@ int SetExprFromAny(Jim_Interp *interp, s
             Jim_Free(token);
             break;
         default:
-            Jim_Panic("Default reached in SetExprFromAny()");
+            Jim_Panic(interp,"Default reached in SetExprFromAny()");
             break;
         }
     }
@@ -6722,7 +6763,7 @@ trydouble_unary:
             Jim_IncrRefCount(stack[stacklen]);
             stacklen++;
         } else {
-            Jim_Panic("Unknown opcode in Jim_EvalExpression");
+            Jim_Panic(interp,"Unknown opcode in Jim_EvalExpression");
         }
     }
 err:
@@ -8001,7 +8042,7 @@ int Jim_InterpolateTokens(Jim_Interp *in
             intv[i] = Jim_GetResult(interp);
             break;
         default:
-            Jim_Panic(
+            Jim_Panic(interp,
               "default token type reached "
               "in Jim_InterpolateTokens().");
             break;
@@ -8178,7 +8219,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_
                     argv[j] = Jim_GetResult(interp);
                     break;
                 default:
-                    Jim_Panic(
+                    Jim_Panic(interp,
                       "default token type reached "
                       "in Jim_EvalObj().");
                     break;
@@ -8411,7 +8452,7 @@ int Jim_EvalObjBackground(Jim_Interp *in
         Jim_IncrRefCount(objv[1]);
         if (Jim_EvalObjVector(interp, 2, objv) != JIM_OK) {
             /* Report the error to stderr. */
-            fprintf(stderr, "Background error:\n");
+            fprintf(interp->stderr, "Background error:" JIM_NL);
             Jim_PrintErrorMessage(interp);
         }
         Jim_DecrRefCount(interp, objv[0]);
@@ -8650,7 +8691,7 @@ int Jim_SubstObj(Jim_Interp *interp, Jim
             Jim_AppendObj(interp, resObjPtr, interp->result);
             break;
         default:
-            Jim_Panic(
+            Jim_Panic(interp,
               "default token type (%d) reached "
               "in Jim_SubstObj().", token[i].type);
             break;
@@ -8743,6 +8784,10 @@ void JimRegisterCoreApi(Jim_Interp *inte
   JIM_REGISTER_API(GetFinalizer);
   JIM_REGISTER_API(CreateInterp);
   JIM_REGISTER_API(FreeInterp);
+  JIM_REGISTER_API(GetExitCode);
+  JIM_REGISTER_API(SetStdin);
+  JIM_REGISTER_API(SetStdout);
+  JIM_REGISTER_API(SetStderr);
   JIM_REGISTER_API(CreateCommand);
   JIM_REGISTER_API(CreateProcedure);
   JIM_REGISTER_API(DeleteCommand);
@@ -8940,8 +8985,8 @@ static int Jim_PutsCoreCommand(Jim_Inter
         }
     }
     str = Jim_GetString(argv[1], &len);
-    fwrite(str, 1, len, stdout);
-    if (!nonewline) printf("\n");
+    fwrite(str, 1, len, interp->stdout);
+    if (!nonewline) fprintf(interp->stdout, JIM_NL);
     return JIM_OK;
 }
 
@@ -8987,9 +9032,12 @@ static int Jim_SubDivHelper(Jim_Interp *
     double doubleValue, doubleRes = 0;
     int i = 2;
 
-    /* The arity = 2 case is different. For [- x] returns -x,
-     * while [/ x] returns 1/x. */
-    if (argc == 2) {
+    if (argc < 2) {
+        Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?");
+        return JIM_ERR;
+    } else if (argc == 2) {
+        /* The arity = 2 case is different. For [- x] returns -x,
+         * while [/ x] returns 1/x. */
         if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) {
             if (Jim_GetDouble(interp, argv[1], &doubleValue) !=
                     JIM_OK)
@@ -9218,7 +9266,8 @@ static int Jim_WhileCoreCommand(Jim_Inte
             }
             break;
         default:
-            Jim_Panic("Unexpected default reached in Jim_WhileCoreCommand()");
+            Jim_Panic(interp,
+                "Unexpected default reached in Jim_WhileCoreCommand()");
             break;
         }
 
@@ -10793,8 +10842,8 @@ static int Jim_ExitCoreCommand(Jim_Inter
         if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK)
             return JIM_ERR;
     }
-    exit(exitCode);
-    return JIM_OK; /* unreached */
+    interp->exitCode = exitCode;
+    return JIM_EXIT;
 }
 
 /* [catch] */
@@ -11669,9 +11718,10 @@ void Jim_PrintErrorMessage(Jim_Interp *i
 {
     int len, i;
 
-    fprintf(stderr, "Runtime error, file \"%s\", line %d:\n",
+    fprintf(interp->stderr, "Runtime error, file \"%s\", line %d:" JIM_NL,
             interp->errorFileName, interp->errorLine);
-    fprintf(stderr, "    %s\n", Jim_GetString(interp->result, NULL));
+    fprintf(interp->stderr, "    %s" JIM_NL,
+            Jim_GetString(interp->result, NULL));
     Jim_ListLength(interp, interp->stackTrace, &len);
     for (i = 0; i < len; i+= 3) {
         Jim_Obj *objPtr;
@@ -11685,7 +11735,8 @@ void Jim_PrintErrorMessage(Jim_Interp *i
         Jim_ListIndex(interp, interp->stackTrace, i+2, &objPtr,
                 JIM_NONE);
         line = Jim_GetString(objPtr, NULL);
-        fprintf(stderr, "In procedure '%s' called at file \"%s\", line %s\n",
+        fprintf(interp->stderr,
+                "In procedure '%s' called at file \"%s\", line %s" JIM_NL,
                 proc, file, line);
     }
 }
@@ -11695,27 +11746,29 @@ int Jim_InteractivePrompt(Jim_Interp *in
     int retcode = JIM_OK;
     Jim_Obj *scriptObjPtr;
 
-    printf("Welcome to Jim version %d.%d, "
-           "Copyright (c) 2005 Salvatore Sanfilippo\n",
+    fprintf(interp->stdout, "Welcome to Jim version %d.%d, "
+           "Copyright (c) 2005 Salvatore Sanfilippo" JIM_NL,
            JIM_VERSION / 100, JIM_VERSION % 100);
-    printf("CVS ID: $Id: jim.c,v 1.1 2006/07/18 16:37:24 jlarmour Exp $\n");
+    fprintf(interp->stdout,
+            "CVS ID: $Id: jim.c,v 1.170 2006/11/06 21:48:57 antirez Exp $"
+            JIM_NL);
     Jim_SetVariableStrWithStr(interp, "jim_interactive", "1");
     while (1) {
         char buf[1024];
         const char *result;
         const char *retcodestr[] = {
-            "ok", "error", "return", "break", "continue", "eval"
+            "ok", "error", "return", "break", "continue", "eval", "exit"
         };
         int reslen;
 
         if (retcode != 0) {
-            if (retcode >= 2 && retcode <= 5)
-                printf("[%s] . ", retcodestr[retcode]);
+            if (retcode >= 2 && retcode <= 6)
+                fprintf(interp->stdout, "[%s] . ", retcodestr[retcode]);
             else
-                printf("[%d] . ", retcode);
+                fprintf(interp->stdout, "[%d] . ", retcode);
         } else
-            printf(". ");
-        fflush(stdout);
+            fprintf(interp->stdout, ". ");
+        fflush(interp->stdout);
         scriptObjPtr = Jim_NewStringObj(interp, "", 0);
         Jim_IncrRefCount(scriptObjPtr);
         while(1) {
@@ -11723,7 +11776,7 @@ int Jim_InteractivePrompt(Jim_Interp *in
             char state;
             int len;
 
-            if (fgets(buf, 1024, stdin) == NULL) {
+            if (fgets(buf, 1024, interp->stdin) == NULL) {
                 Jim_DecrRefCount(interp, scriptObjPtr);
                 goto out;
             }
@@ -11731,7 +11784,7 @@ int Jim_InteractivePrompt(Jim_Interp *in
             str = Jim_GetString(scriptObjPtr, &len);
             if (Jim_ScriptIsComplete(str, len, &state))
                 break;
-            printf("%c> ", state);
+            fprintf(interp->stdout, "%c> ", state);
             fflush(stdout);
         }
         retcode = Jim_EvalObj(interp, scriptObjPtr);
@@ -11739,10 +11792,12 @@ int Jim_InteractivePrompt(Jim_Interp *in
         result = Jim_GetString(Jim_GetResult(interp), &reslen);
         if (retcode == JIM_ERR) {
             Jim_PrintErrorMessage(interp);
+        } else if (retcode == JIM_EXIT) {
+            exit(Jim_GetExitCode(interp));
         } else {
             if (reslen) {
-                fwrite(result, 1, reslen, stdout);
-                printf("\n");
+                fwrite(result, 1, reslen, interp->stdout);
+                fprintf(interp->stdout, JIM_NL);
             }
         }
     }