void Jsi_DString_SelfTest() { { Jsi_DString d1 = {}, d2 = {"Here is"}; Jsi_DSAppend(&d2 ," your score: ", NULL); Jsi_DSPrintf(&d2, " -> %d/%d", 99, 100); char *cp = Jsi_DSValue(&d2); puts(cp); // "Here is your score: -> 99/100" Jsi_DSAppend(&d1, cp, NULL); Jsi_DSFree(&d1); Jsi_DSFree(&d2); } { Jsi_DString d = {};; Jsi_DSPrintf(&d , "%0300d", 1); // Malloc Jsi_DSSetLength(&d, 0); Jsi_DSPrintf(&d , "%0300d", 1); // No-malloc Jsi_DSFree(&d); Jsi_DSPrintf(&d , "%0300d", 1); // Malloc Jsi_DSFree(&d); } { Jsi_DString d; Jsi_DSInit(&d); Jsi_DSAppend(&d , " some stuff: ", NULL); Jsi_DSFree(&d); } { JSI_DSTRING_VAR(dPtr,301); Jsi_DSPrintf(dPtr , "%0300d", 1); // No-malloc Jsi_DSSetLength(dPtr, 0); Jsi_DSPrintf(dPtr , "%0300d", 1); // No-malloc Jsi_DSFree(dPtr); Jsi_DSPrintf(dPtr , "%0400d", 1); // Malloc Jsi_DSFree(dPtr); } }
char * Jsi_DSSet(Jsi_DString *dsPtr, const char *str) { Jsi_DSSetLength(dsPtr, 0); if (str) Jsi_DSAppendLen(dsPtr, str, -1); return Jsi_DSValue(dsPtr); }
static void Jsi_RemoveTrailingNewline(Jsi_DString *dStr) { char *s = Jsi_DSValue(dStr); int len = strlen(s); if (len > 0 && s[len - 1] == '\n') { s[len-1] = 0; Jsi_DSSetLength(dStr, len-1); } }
/* * Returns the strdup of the string value and resets the DString in the same way as Jsi_DSFree. * This just avoids the user having to do an extra malloc/free when the DString was already malloced. * It is the responsibility of the caller to free the returned value. * RETURNS: previous string value malloced. */ char* Jsi_DSFreeDup(Jsi_DString *dsPtr) { char *cp; if (DSNotInit(dsPtr)) InitStr(dsPtr); if (dsPtr->staticSpace == dsPtr->str) { cp = Jsi_Strdup(dsPtr->str); Jsi_DSSetLength(dsPtr, 0); return cp; } cp = dsPtr->str; dsPtr->str = dsPtr->staticSpace; dsPtr->staticSpace[0] = 0; dsPtr->spaceAvl = dsPtr->staticSize; dsPtr->len = 0; dsPtr->str = NULL; return cp; }
/* * Format output and append to the end of dsPtr. * RETURNS: The string starting at the first appended character. */ char * Jsi_DSPrintf(Jsi_DString *dsPtr, const char *fmt, ...) { va_list argList; #ifndef JSI_PRINTF_BUFSIZ #define JSI_PRINTF_BUFSIZ BUFSIZ #endif char buf[JSI_PRINTF_BUFSIZ], *bPtr = buf; int n, bsiz = sizeof(buf), needAppend = 1; if (DSNotInit(dsPtr)) InitStr(dsPtr); int len = dsPtr->len; char *send = dsPtr->str + len; uint avail = (dsPtr->spaceAvl - len); if (avail >= sizeof(buf)) { /* Format directly into string. */ bPtr = dsPtr->str+len; bsiz = avail; needAppend = 0; } va_start(argList, fmt); n = vsnprintf(bPtr, bsiz, fmt, argList); if (n<0 || (n+len)>JSI_MAX_ALLOC_BUF) { LogError("vsnprintf error: rc=%d, len=%d", n, len); va_end(argList); return send; } if (n >= bsiz) { int m = len+n+1; if (Jsi_DSSetLength(dsPtr, m) < m) { va_start(argList, fmt); return send; } m = vsnprintf(dsPtr->str+len, len+1, fmt, argList); if (m != n) { LogError("len mismatch: %d != %d", m, n); va_end(argList); return send; } } else if (needAppend) { Jsi_DSAppendLen(dsPtr, buf, n); } va_end(argList); return send; }
/* * Append length bytes to the string. If length is less than 0, * the value of strlen is used. If required, the DString is realloced to * be large enough to contain bytes, plus an extra null byte that is added to the end. * RETURNS: The string starting at the first appended character. */ char *Jsi_DSAppendLen(Jsi_DString *dsPtr, const char *string, int length) { if (DSNotInit(dsPtr)) InitStr(dsPtr); int len = dsPtr->len; if (string) { if (length < 0) length = strlen(string); int nsiz = length + len+1; if (nsiz >= dsPtr->spaceAvl) { if (nsiz < dsPtr->spaceAvl*2) nsiz = dsPtr->spaceAvl*2; if (Jsi_DSSetLength(dsPtr, nsiz) < nsiz) return Jsi_DSValue(dsPtr); } char * dst = dsPtr->str + dsPtr->len; memcpy(dst, string, length); dst[length] = 0; dsPtr->len += length; } return dsPtr->str+len; }
/* Collect and execute code from stdin. The first byte of flags are passed to Jsi_ValueGetDString(). */ int Jsi_Interactive(Jsi_Interp* interp, int flags) { int rc = 0, done = 0, len, quote = (flags & 0xff), istty = 1; char *prompt = "# ", *buf; Jsi_DString dStr; Jsi_DSInit(&dStr); #ifndef __WIN32 istty = isatty(fileno(stdin)); #else istty = _isatty(_fileno(stdin)); #endif #ifdef HAVE_READLINE Jsi_DString dHist = {}; char *hist = NULL; if(interp->noreadline == 0 && !interp->parent) { hist = Jsi_NormalPath(interp, "~/.jsish_history", &dHist); if (hist) read_history(hist); } #endif interp->level++; while (done==0 && interp->exited==0) { buf = get_inputline(istty, prompt); if (buf) { Jsi_DSAppend(&dStr, buf, NULL); free(buf); } else { done = 1; } len = Jsi_DSLength(&dStr); if (done && len == 0) break; buf = Jsi_DSValue(&dStr); if (done == 0 && (!balanced(buf))) { prompt = "> "; if (len<5) break; continue; } prompt = "# "; while ((len = Jsi_Strlen(buf))>0 && (isspace(buf[len-1]))) buf[len-1] = 0; if (buf[0] == 0) continue; /* Convenience: add semicolon to "var" statements (required by parser). */ if (strncmp(buf,"var ", 4) == 0 && strchr(buf, '\n')==NULL && strchr(buf, ';')==NULL) strcat(buf, ";"); rc = Jsi_EvalString(interp, buf, JSI_EVAL_RETURN); if (interp->exited) break; if (rc == 0) { if (interp->ret.vt != JSI_VT_UNDEF || interp->noUndef==0) { Jsi_DString eStr = {}; fputs(Jsi_ValueGetDString(interp,&interp->ret, &eStr, quote), stdout); Jsi_DSFree(&eStr); fputs("\n", stdout); } } else if (!interp->exited) { fputs("ERROR\n", stderr); } Jsi_DSSetLength(&dStr, 0); len = 0; } interp->level--; #ifdef HAVE_READLINE if (hist) { stifle_history(100); write_history(hist); } Jsi_DSFree(&dHist); #endif Jsi_DSFree(&dStr); if (interp->exited && interp->level <= 0) { rc = interp->exitCode; Jsi_InterpDelete(interp); } return rc; }
/* Lookup a name, eg. "a[b].c a.b.c a[b][c] a.b[c] a["b"].c a[1].c */ Jsi_Value *Jsi_NameLookup(Jsi_Interp *interp, const char *name) { int cnt = 0, len, isq; char *nam = (char*)name, *cp, *cp2, *ocp, *kstr; Jsi_Value *v = NULL, tv = VALINIT, nv = VALINIT, key = VALINIT; Jsi_DString dStr = {}; cp2 = strchr(nam,'['); cp = strchr(nam, '.'); if (cp2 && (cp==0 || cp2<cp)) cp = cp2; if (!cp) return Jsi_VarLookup(interp, nam); Jsi_DSSetLength(&dStr, 0); Jsi_DSAppendLen(&dStr, nam, cp-nam); v = Jsi_VarLookup(interp, Jsi_DSValue(&dStr)); if (!v) goto bail; while (cnt++ < 1000) { ocp = cp; nam = cp+1; isq = 0; if (*cp == '[') { cp = FindEndB(cp+1); /* handle [] in strings. */ if (!cp) goto bail; len = cp-nam; cp++; if (len>=2 && ((nam[0] == '\"' && nam[len-1] == '\"') || (nam[0] == '\'' && nam[len-1] == '\''))) { nam += 1; len -= 2; isq = 1; } } else if (*cp == '.') { cp2 = strchr(nam,'['); cp = strchr(nam, '.'); if (cp2 && (cp==0 || cp2<cp)) cp = cp2; len = (cp ? cp-nam : strlen(nam)); } else { goto bail; } Jsi_DSSetLength(&dStr, 0); Jsi_DSAppendLen(&dStr, nam, len); kstr = Jsi_DSValue(&dStr); if (*ocp == '[' && isq == 0 && isdigit(kstr[0]) && Jsi_ValueIsArray(interp, v)) { int nn; if (Jsi_GetInt(interp, kstr, &nn, 0) != JSI_OK) goto bail; v = Jsi_ValueArrayIndex(interp, v, nn); if (!v) goto bail; } else if (*ocp == '[' && isq == 0) { Jsi_Value *kv = Jsi_VarLookup(interp, kstr); if (!kv) goto bail; jsi_ValueSubscriptLen(interp, v, kv, &nv, 1); goto keyon; } else { Jsi_ValueMakeStringKey(interp, &key, kstr); jsi_ValueSubscriptLen(interp, v, &key, &nv, 1); keyon: if (nv.vt == JSI_VT_UNDEF) goto bail; else { tv = nv; v = &tv; } } if (cp == 0 || *cp == 0) break; } //Jsi_ValueReset(interp, &ret); Jsi_DSFree(&dStr); if (v && v == &tv) { v = Jsi_ValueNew(interp); *v = tv; } return v; bail: Jsi_DSFree(&dStr); return NULL; }