* Copyright 2008 Andrew Lunn <andrew@lunn.ch>
* Copyright 2008 Duane Ellis <openocd@duaneellis.com>
* Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ * Copyright 2008 Steve Bennett <steveb@workware.net.au>
*
* The FreeBSD license
*
#endif /* WIN32 */
#endif /* JIM_DYNLIB */
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
#ifdef __ECOS
#include <cyg/jimtcl/jim.h>
#else
if (brace) {
while (!stop) {
if (*pc->p == '}' || pc->len == 0) {
+ pc->tend = pc->p-1;
stop = 1;
if (pc->len == 0)
- continue;
+ break;
}
else if (*pc->p == '\n')
pc->linenr++;
pc->p++; pc->len--;
}
- if (pc->len == 0)
- pc->tend = pc->p-1;
- else
- pc->tend = pc->p-2;
} else {
+ /* Include leading colons */
+ while (*pc->p == ':') {
+ pc->p++;
+ pc->len--;
+ }
while (!stop) {
if (!((*pc->p >= 'a' && *pc->p <= 'z') ||
(*pc->p >= 'A' && *pc->p <= 'Z') ||
static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
{
- char *buf = Jim_Alloc(strObjPtr->length+1);
+ char *buf;
int i;
+ if (strObjPtr->typePtr != &stringObjType) {
+ SetStringFromAny(interp, strObjPtr);
+ }
+
+ buf = Jim_Alloc(strObjPtr->length+1);
memcpy(buf, strObjPtr->bytes, strObjPtr->length+1);
for (i = 0; i < strObjPtr->length; i++)
static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
{
- char *buf = Jim_Alloc(strObjPtr->length+1);
+ char *buf;
int i;
+ if (strObjPtr->typePtr != &stringObjType) {
+ SetStringFromAny(interp, strObjPtr);
+ }
+
+ buf = Jim_Alloc(strObjPtr->length+1);
memcpy(buf, strObjPtr->bytes, strObjPtr->length+1);
for (i = 0; i < strObjPtr->length; i++)
/* non-terminals */
case '0': /* zero pad */
zpad = 1;
- *fmt++; fmtLen--;
+ fmt++; fmtLen--;
goto next_fmt;
break;
case '+':
forceplus = 1;
- *fmt++; fmtLen--;
+ fmt++; fmtLen--;
goto next_fmt;
break;
case ' ': /* sign space */
spad = 1;
- *fmt++; fmtLen--;
+ fmt++; fmtLen--;
goto next_fmt;
break;
case '-':
ljust = 1;
- *fmt++; fmtLen--;
+ fmt++; fmtLen--;
goto next_fmt;
break;
case '#':
altfm = 1;
- *fmt++; fmtLen--;
+ fmt++; fmtLen--;
goto next_fmt;
-
+
case '.':
inprec = 1;
- *fmt++; fmtLen--;
+ fmt++; fmtLen--;
goto next_fmt;
break;
case '1':
goto next_fmt;
case '*':
/* suck up the next item as an integer */
- *fmt++; fmtLen--;
+ fmt++; fmtLen--;
objc--;
if( objc <= 0 ){
goto not_enough_args;
prec = 0;
}
} else {
- width = wideValue;
- if( width < 0 ){
- ljust = 1;
- width = -width;
- }
+ width = wideValue;
+ if( width < 0 ){
+ ljust = 1;
+ width = -width;
+ }
}
objv++;
goto next_fmt;
break;
case 'b':
case 'd':
+ case 'o':
case 'i':
case 'u':
case 'x':
initialLineNumber = objPtr->internalRep.sourceValue.lineNumber;
propagateSourceInfo = 1;
} else {
- script->fileName = Jim_StrDup("?");
+ script->fileName = Jim_StrDup("");
initialLineNumber = 1;
}
he = Jim_FindHashEntry(&interp->commands, cmdName);
if (he == NULL) { /* New command to create */
cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
- cmdPtr->cmdProc = cmdProc;
- cmdPtr->privData = privData;
- cmdPtr->delProc = delProc;
Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr);
} else {
Jim_InterpIncrProcEpoch(interp);
/* If it was a C coded command, call the delProc if any */
cmdPtr->delProc(interp, cmdPtr->privData);
}
- cmdPtr->cmdProc = cmdProc;
- cmdPtr->privData = privData;
}
+
+ /* Store the new details for this proc */
+ cmdPtr->delProc = delProc;
+ cmdPtr->cmdProc = cmdProc;
+ cmdPtr->privData = privData;
+
/* 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. */
/* Make sure it's not syntax glue to get/set dict. */
if (Jim_NameIsDictSugar(varName, len))
return JIM_DICT_SUGAR;
- /* Lookup this name into the variables hash table */
- he = Jim_FindHashEntry(&interp->framePtr->vars, varName);
- if (he == NULL) {
- /* Try with static vars. */
- if (interp->framePtr->staticVars == NULL)
- return JIM_ERR;
- if (!(he = Jim_FindHashEntry(interp->framePtr->staticVars, varName)))
+ if (varName[0] == ':' && varName[1] == ':') {
+ he = Jim_FindHashEntry(&interp->topFramePtr->vars, varName + 2);
+ if (he == NULL) {
return JIM_ERR;
+ }
+ }
+ else {
+ /* Lookup this name into the variables hash table */
+ he = Jim_FindHashEntry(&interp->framePtr->vars, varName);
+ if (he == NULL) {
+ /* Try with static vars. */
+ if (interp->framePtr->staticVars == NULL)
+ return JIM_ERR;
+ if (!(he = Jim_FindHashEntry(interp->framePtr->staticVars, varName)))
+ return JIM_ERR;
+ }
}
/* Free the old internal repr and set the new one. */
Jim_FreeIntRep(interp, objPtr);
Jim_IncrRefCount(valObjPtr);
var->linkFramePtr = NULL;
/* Insert the new variable */
- Jim_AddHashEntry(&interp->framePtr->vars, name, var);
+ if (name[0] == ':' && name[1] == ':') {
+ /* Into to the top evel frame */
+ Jim_AddHashEntry(&interp->topFramePtr->vars, name + 2, var);
+ }
+ else {
+ Jim_AddHashEntry(&interp->framePtr->vars, name, var);
+ }
/* Make the object int rep a variable */
Jim_FreeIntRep(interp, nameObjPtr);
nameObjPtr->typePtr = &variableObjType;
i->result = i->emptyObj;
i->stackTrace = Jim_NewListObj(i, NULL, 0);
i->unknown = Jim_NewStringObj(i, "unknown", -1);
+ i->unknown_called = 0;
Jim_IncrRefCount(i->emptyObj);
Jim_IncrRefCount(i->result);
Jim_IncrRefCount(i->stackTrace);
static void JimAppendStackTrace(Jim_Interp *interp, const char *procname,
const char *filename, int linenr)
{
+ /* No need to add this dummy entry to the stack trace */
+ if (strcmp(procname, "unknown") == 0) {
+ return;
+ }
+
if (Jim_IsShared(interp->stackTrace)) {
interp->stackTrace =
Jim_DuplicateObj(interp, interp->stackTrace);
case JIM_EXPROP_STRING:
break;
default:
- op = JimExprOperatorInfoByOpcode(expr->opcode[i]);
+ op = JimExprOperatorInfoByOpcode(expr->opcode[leftindex]);
if (op == NULL) {
Jim_Panic(interp,"Default reached in ExprMakeLazy()");
}
/* --- Double --- */
if (Jim_GetDouble(interp, A, &dA) != JIM_OK ||
Jim_GetDouble(interp, B, &dB) != JIM_OK) {
+
+ /* Hmmm! For compatibility, maybe convert != and == into ne and eq */
+ if (expr->opcode[i] == JIM_EXPROP_NUMNE) {
+ opcode = JIM_EXPROP_STRNE;
+ goto retry_as_string;
+ }
+ else if (expr->opcode[i] == JIM_EXPROP_NUMEQ) {
+ opcode = JIM_EXPROP_STREQ;
+ goto retry_as_string;
+ }
Jim_DecrRefCount(interp, A);
Jim_DecrRefCount(interp, B);
error = 1;
} else if (opcode == JIM_EXPROP_STREQ || opcode == JIM_EXPROP_STRNE) {
B = stack[--stacklen];
A = stack[--stacklen];
+retry_as_string:
sA = Jim_GetString(A, &Alen);
sB = Jim_GetString(B, &Blen);
- switch(expr->opcode[i]) {
+ switch(opcode) {
case JIM_EXPROP_STREQ:
if (Alen == Blen && memcmp(sA, sB, Alen) ==0)
wC = 1;
if (Jim_ListIndex(interp, libPathObjPtr, i,
&prefixObjPtr, JIM_NONE) != JIM_OK)
continue;
- prefix = Jim_GetString(prefixObjPtr, NULL);
- prefixlen = strlen(prefix);
+ prefix = Jim_GetString(prefixObjPtr, &prefixlen);
if (prefixlen+strlen(pathName)+1 >= JIM_PATH_LEN)
continue;
- if (prefixlen && prefix[prefixlen-1] == '/')
+ if (*pathName == '/') {
+ strcpy(buf, pathName);
+ }
+ else if (prefixlen && prefix[prefixlen-1] == '/')
sprintf(buf, "%s%s", prefix, pathName);
else
sprintf(buf, "%s/%s", prefix, pathName);
- printf("opening '%s'\n", buf);
fp = fopen(buf, "r");
if (fp == NULL)
continue;
fclose(fp);
handle = dlopen(buf, RTLD_LAZY);
- printf("got handle %p\n", handle);
}
if (handle == NULL) {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_HashEntry *he;
int requiredVer;
+ /* Start with an empty error string */
+ Jim_SetResultString(interp, "", 0);
+
if (JimPackageVersionToInt(interp, ver, &requiredVer, JIM_ERRMSG) != JIM_OK)
return NULL;
he = Jim_FindHashEntry(&interp->packages, name);
}
/* No way... return an error. */
if (flags & JIM_ERRMSG) {
- Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
- Jim_AppendStrings(interp, Jim_GetResult(interp),
+ int len;
+ Jim_GetString(Jim_GetResult(interp), &len);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), len ? "\n" : "",
"Can't find package '", name, "'", NULL);
}
return NULL;
}
/* Check if version matches. */
if (JimPackageMatchVersion(requiredVer, actualVer, flags) == 0) {
- Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp),
"Package '", name, "' already loaded, but with version ",
he->val, NULL);
Jim_Obj **v, *sv[JIM_EVAL_SARGV_LEN];
int retCode;
+ /* If JimUnknown() is recursively called (e.g. error in the unknown proc,
+ * done here
+ */
+ if (interp->unknown_called) {
+ return JIM_ERR;
+ }
+
/* If the [unknown] command does not exists returns
* just now */
if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
memcpy(v+1, argv, sizeof(Jim_Obj*)*argc);
v[0] = interp->unknown;
/* Call it */
+ interp->unknown_called++;
retCode = Jim_EvalObjVector(interp, argc+1, v);
+ interp->unknown_called--;
+
/* Clean up */
if (v != sv)
Jim_Free(v);
if (cmdPtr->cmdProc) {
interp->cmdPrivData = cmdPtr->privData;
retcode = cmdPtr->cmdProc(interp, objc, objv);
+ if (retcode == JIM_ERR_ADDSTACK) {
+ //JimAppendStackTrace(interp, "", script->fileName, token[i-argc*2].linenr);
+ retcode = JIM_ERR;
+ }
} else {
retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
- if (retcode == JIM_ERR) {
- JimAppendStackTrace(interp,
- Jim_GetString(objv[0], NULL), "?", 1);
- }
+ if (retcode == JIM_ERR) {
+ JimAppendStackTrace(interp,
+ Jim_GetString(objv[0], NULL), "", 1);
+ }
}
}
/* Decr refcount of arguments and return the retcode */
if (cmd->cmdProc) {
interp->cmdPrivData = cmd->privData;
retcode = cmd->cmdProc(interp, argc, argv);
+ if (retcode == JIM_ERR_ADDSTACK) {
+ JimAppendStackTrace(interp, "", script->fileName, token[i-argc*2].linenr);
+ retcode = JIM_ERR;
+ }
} else {
retcode = JimCallProcedure(interp, cmd, argc, argv);
if (retcode == JIM_ERR) {
retcode = JimUnknown(interp, argc, argv);
if (retcode == JIM_ERR) {
JimAppendStackTrace(interp,
- Jim_GetString(argv[0], NULL), script->fileName,
+ "", script->fileName,
token[i-argc*2].linenr);
}
}
{
int i, retcode;
Jim_CallFrame *callFramePtr;
+ int num_args;
/* Check arity */
if (argc < cmd->arityMin || (cmd->arityMax != -1 &&
Jim_IncrRefCount(cmd->bodyObjPtr);
interp->framePtr = callFramePtr;
interp->numLevels ++;
+
/* Set arguments */
- for (i = 0; i < cmd->arityMin-1; i++) {
- Jim_Obj *objPtr;
+ Jim_ListLength(interp, cmd->argListObjPtr, &num_args);
+
+ /* If last argument is 'args', don't set it here */
+ if (cmd->arityMax == -1) {
+ num_args--;
+ }
+
+ for (i = 0; i < num_args; i++) {
+ Jim_Obj *argObjPtr;
+ Jim_Obj *nameObjPtr;
+ Jim_Obj *valueObjPtr;
+
+ Jim_ListIndex(interp, cmd->argListObjPtr, i, &argObjPtr, JIM_NONE);
+ if (i + 1 >= cmd->arityMin) {
+ /* The name is the first element of the list */
+ Jim_ListIndex(interp, argObjPtr, 0, &nameObjPtr, JIM_NONE);
+ }
+ else {
+ /* The element arg is the name */
+ nameObjPtr = argObjPtr;
+ }
- Jim_ListIndex(interp, cmd->argListObjPtr, i, &objPtr, JIM_NONE);
- Jim_SetVariable(interp, objPtr, argv[i+1]);
+ if (i + 1 >= argc) {
+ /* No more values, so use default */
+ /* The value is the second element of the list */
+ Jim_ListIndex(interp, argObjPtr, 1, &valueObjPtr, JIM_NONE);
+ }
+ else {
+ valueObjPtr = argv[i+1];
+ }
+ Jim_SetVariable(interp, nameObjPtr, valueObjPtr);
}
+ /* Set optional arguments */
if (cmd->arityMax == -1) {
Jim_Obj *listObjPtr, *objPtr;
- listObjPtr = Jim_NewListObj(interp, argv+cmd->arityMin,
- argc-cmd->arityMin);
- Jim_ListIndex(interp, cmd->argListObjPtr, i, &objPtr, JIM_NONE);
+ i++;
+ listObjPtr = Jim_NewListObj(interp, argv+i, argc-i);
+ Jim_ListIndex(interp, cmd->argListObjPtr, num_args, &objPtr, JIM_NONE);
Jim_SetVariable(interp, objPtr, listObjPtr);
}
/* Eval the body */
}
Jim_ListLength(interp, argv[2], &argListLen);
arityMin = arityMax = argListLen+1;
+
if (argListLen) {
const char *str;
int len;
- Jim_Obj *lastArgPtr;
+ Jim_Obj *argPtr;
- Jim_ListIndex(interp, argv[2], argListLen-1, &lastArgPtr, JIM_NONE);
- str = Jim_GetString(lastArgPtr, &len);
+ /* Check for 'args' and adjust arityMin and arityMax if necessary */
+ Jim_ListIndex(interp, argv[2], argListLen-1, &argPtr, JIM_NONE);
+ str = Jim_GetString(argPtr, &len);
if (len == 4 && memcmp(str, "args", 4) == 0) {
arityMin--;
arityMax = -1;
}
+
+ /* Check for default arguments and reduce arityMin if necessary */
+ while (arityMin > 1) {
+ int len;
+ Jim_ListIndex(interp, argv[2], arityMin - 2, &argPtr, JIM_NONE);
+ Jim_ListLength(interp, argPtr, &len);
+ if (len != 2) {
+ /* No default argument */
+ break;
+ }
+ arityMin--;
+ }
}
if (argc == 4) {
return Jim_CreateProcedure(interp, Jim_GetString(argv[1], NULL),
int cmd, result = JIM_OK;
static const char *commands[] = {
"body", "commands", "exists", "globals", "level", "locals",
- "vars", "version", "complete", "args", NULL
+ "vars", "version", "complete", "args", "hostname", NULL
};
enum {INFO_BODY, INFO_COMMANDS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL,
- INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_COMPLETE, INFO_ARGS};
+ INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_COMPLETE, INFO_ARGS, INFO_HOSTNAME};
if (argc < 2) {
Jim_WrongNumArgs(interp, 1, argv, "command ?args ...?");
s = Jim_GetString(argv[2], &len);
Jim_SetResult(interp,
Jim_NewIntObj(interp, Jim_ScriptIsComplete(s, len, NULL)));
+ } else if (cmd == INFO_HOSTNAME) {
+ /* Redirect to os.hostname if it exists */
+ Jim_Obj *command = Jim_NewStringObj(interp, "os.gethostname", -1);
+ result = Jim_EvalObjVector(interp, 1, &command);
}
return result;
}
const char *key;
char *val;
+ if (argc == 1) {
+ extern char **environ;
+
+ int i;
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; environ[i]; i++) {
+ const char *equals = strchr(environ[i], '=');
+ if (equals) {
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, environ[i], equals - environ[i]));
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1));
+ }
+ }
+
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+ }
+
if (argc != 2) {
Jim_WrongNumArgs(interp, 1, argv, "varName");
return JIM_ERR;
return JIM_ERR;
}
retval = Jim_EvalFile(interp, Jim_GetString(argv[1], NULL));
+ if (retval == JIM_ERR) {
+ return JIM_ERR_ADDSTACK;
+ }
if (retval == JIM_RETURN)
return JIM_OK;
return retval;
argc == 4 ? Jim_GetString(argv[3], NULL) : "",
JIM_ERRMSG);
if (ver == NULL)
- return JIM_ERR;
+ return JIM_ERR_ADDSTACK;
Jim_SetResultString(interp, ver, -1);
} else if (option == OPT_PROVIDE) {
if (argc != 4) {
return JIM_OK;
}
-
-static void
-jim_get_s_us( jim_wide *s, jim_wide *us )
-{
-#if defined(WIN32)
- /*
- * Sorry - I do not have, or use Win32.
- * This concept is from
- *
- * Method is from:
- * http://www.openasthra.com/c-tidbits/gettimeofday-function-for-windows/
- *
- * I have no method to test/verify.
- * - Duane 6-sep-2008.
- * (once verified, please somebody remove this comment)
- */
-#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
- #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
-#else
- #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
-#endif
-
- FILETIME ft;
- unsigned __int64 tmpres;
- tmpres = 0;
- GetSystemTimeAsFileTime( &ft );
-
- tmpres |= ft.dwHighDateTime;
- tmpres <<= 32;
- tmpres |= ft.dwLowDateTime;
- /* convert to unix representation */
- tmpres /= 10;
- tmpres -= DELTA_EPOCH_IN_MICROSECS;
-
- *s = (tmpres / 1000000ULL);
- *us = (tmpres % 1000000ULL);
-
-#undef DELTA_EPOCH_IN_MICROSECS
-
-#else
- /* LINUX/CYGWIN */
- struct timeval tv;
- struct timezone tz;
- gettimeofday( &tv, &tz );
- *s = tv.tv_sec;
- *us = tv.tv_usec;
-#endif
-}
-
-
-/* [clock] */
-static int Jim_ClockCoreCommand( Jim_Interp *interp, int argc,
- Jim_Obj *const *argv)
-{
- /*
- * See: TCL man page for 'clock'
- * we do not impliment all features.
- */
- jim_wide r,s,us;
- int option;
- const char *options[] = {
- "clicks",
- "microseconds",
- "milliseconds",
- "seconds",
- NULL
- };
- enum { OPT_CLICKS, OPT_USEC, OPT_MSEC, OPT_SEC };
-
- if( argc < 2 ){
- Jim_WrongNumArgs( interp, 1, argv, "option ?arguments ...?");
- return JIM_ERR;
- }
-
- if( Jim_GetEnum(interp, argv[1], options, &option, "option",
- JIM_ERRMSG) != JIM_OK ){
- return JIM_ERR;
- }
-
- // platform independent get time.
- jim_get_s_us( &s, &us );
-
- r = 0;
- switch(option){
- case OPT_CLICKS:
- case OPT_USEC:
- /* clicks & usecs are the same */
- r = (s * 1000000) + us;
- break;
- case OPT_MSEC:
- r = (s * 1000) + (us / 1000);
- break;
- case OPT_SEC:
- r = s;
- break;
- }
-
- Jim_SetResult( interp, Jim_NewWideObj( interp, r ) );
- return JIM_OK;
-}
-
-
static struct {
const char *name;
Jim_CmdProc cmdProc;
{"rand", Jim_RandCoreCommand},
{"package", Jim_PackageCoreCommand},
{"tailcall", Jim_TailcallCoreCommand},
- {"clock", Jim_ClockCoreCommand},
{NULL, NULL},
};
{
int len, i;
- Jim_fprintf(interp, interp->cookie_stderr, "Runtime error, file \"%s\", line %d:" JIM_NL,
- interp->errorFileName, interp->errorLine);
- Jim_fprintf(interp,interp->cookie_stderr, " %s" JIM_NL,
+ if (*interp->errorFileName) {
+ Jim_fprintf(interp, interp->cookie_stderr, "Runtime error, file \"%s\", line %d:" JIM_NL " ",
+ interp->errorFileName, interp->errorLine);
+ }
+ Jim_fprintf(interp,interp->cookie_stderr, "%s" JIM_NL,
Jim_GetString(interp->result, NULL));
Jim_ListLength(interp, interp->stackTrace, &len);
for (i = len-3; i >= 0; i-= 3) {
Jim_ListIndex(interp, interp->stackTrace, i+2, &objPtr,
JIM_NONE);
line = Jim_GetString(objPtr, NULL);
- Jim_fprintf( interp, interp->cookie_stderr,
- "In procedure '%s' called at file \"%s\", line %s" JIM_NL,
- proc, file, line);
+ if (*proc) {
+ Jim_fprintf( interp, interp->cookie_stderr,
+ "in procedure '%s' ", proc);
+ }
+ if (*file) {
+ Jim_fprintf( interp, interp->cookie_stderr,
+ "called at file \"%s\", line %s",
+ file, line);
+ }
+ if (*file || *proc) {
+ Jim_fprintf( interp, interp->cookie_stderr, JIM_NL);
+ }
}
}
}
return (*(interp->cb_fgets))( s, size, cookie );
}
-
Jim_Nvp *
Jim_Nvp_name2value_simple( const Jim_Nvp *p, const char *name )
{
Jim_Obj *o;
o = NULL; // failure
- if( goi->argc > 0 ){
+ if( goi->argc ){
// success
o = goi->argv[0];
goi->argc -= 1;
{
va_list ap;
char *buf;
-
+
va_start(ap,fmt);
buf = jim_vasprintf( fmt, ap );
va_end(ap);
return Jim_GetString( debug_string_obj, NULL );
}
+
+
+
+/*
+ * Local Variables: ***
+ * c-basic-offset: 4 ***
+ * tab-width: 4 ***
+ * End: ***
+ */