/ Check-in [973645aa81]
DEMO | DOWNLOAD | DEPLOY | SEARCH
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Release "2.5.20". Fix issue [a86dc1c04b]: Heap use after free in Jsi_ObjFree. Increase floating point precision to max-1 (default) and make it changable.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:973645aa8124d94cd72fd5ee745b766f0b7a917c
User & Date: pmacdona 2018-10-11 17:31:06
References
2018-10-11
17:35 Closed ticket [a86dc1c04b]: Heap use after free in Jsi_ObjFree plus 6 other changes artifact: 6a7afb043c user: pcmacdon
Context
2018-10-15
22:48
Release "2.5.21". Fix Sqlite select "insert" mode for query. Swap -m and -M. Make --module source file then invoke runModule(). check-in: e82becfd14 user: pmacdona tags: trunk
2018-10-11
17:31
Release "2.5.20". Fix issue [a86dc1c04b]: Heap use after free in Jsi_ObjFree. Increase floating point precision to max-1 (default) and make it changable. check-in: 973645aa81 user: pmacdona tags: trunk
02:26
Fix VFS bug check-in: ebcd5f87dd user: pmacdona tags: trunk
Changes

Changes to src/jsi.c.

     1      1   /* jsi.h : External API header file for Jsi. */
     2      2   #ifndef __JSI_H__
     3      3   #define __JSI_H__
     4      4   
     5      5   #define JSI_VERSION_MAJOR   2
     6      6   #define JSI_VERSION_MINOR   5
     7         -#define JSI_VERSION_RELEASE 19
            7  +#define JSI_VERSION_RELEASE 20
     8      8   
     9      9   #define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))
    10     10   
    11     11   #ifndef JSI_EXTERN
    12     12   #define JSI_EXTERN extern
    13     13   #endif
    14     14   
................................................................................
   568    568   JSI_EXTERN int Jsi_UserObjNew    (Jsi_Interp *interp, Jsi_UserObjReg* reg, Jsi_Obj *obj, void *data); /*STUB = 180*/
   569    569   JSI_EXTERN void* Jsi_UserObjGetData(Jsi_Interp *interp, Jsi_Value* value, Jsi_Func *funcPtr); /*STUB = 181*/
   570    570   /* -- */
   571    571   
   572    572   
   573    573   /* --UTILITY-- */
   574    574   #define JSI_NOTUSED(n) (void)n /* Eliminate annoying compiler warning. */
   575         -JSI_EXTERN char* Jsi_NumberToString(Jsi_Number d, char *buf, int bsiz); /*STUB = 182*/
          575  +JSI_EXTERN char* Jsi_NumberToString(Jsi_Interp *interp, Jsi_Number d, char *buf, int bsiz); /*STUB = 182*/
   576    576   JSI_EXTERN Jsi_Number Jsi_Version(void); /*STUB = 183*/
   577    577   JSI_EXTERN Jsi_Value* Jsi_ReturnValue(Jsi_Interp *interp); /*STUB = 184*/
   578    578   JSI_EXTERN Jsi_RC Jsi_Mount( Jsi_Interp *interp, Jsi_Value *archive, Jsi_Value *mount, Jsi_Value **ret); /*STUB = 185*/
   579    579   JSI_EXTERN Jsi_Value* Jsi_Executable(Jsi_Interp *interp); /*STUB = 186*/
   580    580   JSI_EXTERN Jsi_Regex* Jsi_RegExpNew(Jsi_Interp *interp, const char *regtxt, int flag); /*STUB = 187*/
   581    581   JSI_EXTERN void Jsi_RegExpFree(Jsi_Regex* re); /*STUB = 188*/
   582    582   JSI_EXTERN Jsi_RC Jsi_RegExpMatch( Jsi_Interp *interp,  Jsi_Value *pattern, const char *str, int *rc, Jsi_DString *dStr); /*STUB = 189*/
................................................................................
   637    637   JSI_EXTERN bool Jsi_NumberIsInteger(Jsi_Number n);  /*STUB = 238*/
   638    638   JSI_EXTERN bool Jsi_NumberIsNaN(Jsi_Number a);  /*STUB = 239*/
   639    639   JSI_EXTERN bool Jsi_NumberIsNormal(Jsi_Number a);  /*STUB = 240*/
   640    640   JSI_EXTERN bool Jsi_NumberIsSubnormal(Jsi_Number a);  /*STUB = 241*/
   641    641   JSI_EXTERN bool Jsi_NumberIsWide(Jsi_Number n);  /*STUB = 242*/
   642    642   JSI_EXTERN Jsi_Number Jsi_NumberInfinity(int i);  /*STUB = 243*/
   643    643   JSI_EXTERN Jsi_Number Jsi_NumberNaN(void);  /*STUB = 244*/
   644         -JSI_EXTERN void Jsi_NumberDtoA(Jsi_Number value, char* buf, int bsiz, int prec);  /*STUB = 245*/
          644  +JSI_EXTERN void Jsi_NumberDtoA(Jsi_Interp *interp, Jsi_Number value, char* buf, int bsiz, int prec);  /*STUB = 245*/
   645    645   JSI_EXTERN void Jsi_NumberItoA10(Jsi_Wide value, char* buf, int bsiz);  /*STUB = 246*/
   646    646   JSI_EXTERN void Jsi_NumberUtoA10(Jsi_UWide, char* buf, int bsiz);  /*STUB = 247*/
   647    647   
   648    648   /* -- */
   649    649   
   650    650   #define JSI_WORDKEY_CAST (void*)(uintptr_t)
   651    651   
................................................................................
 12436  12436   #include <string.h>
 12437  12437   #include <stdarg.h>
 12438  12438   #include <unistd.h>
 12439  12439   #include <ctype.h>
 12440  12440   #include <assert.h>
 12441  12441   #include <inttypes.h>
 12442  12442   #include <limits.h>
        12443  +#include <float.h>
 12443  12444   
 12444  12445   #ifdef __WIN32 /* TODO: support windows signal??? */
 12445  12446   #define JSI__MINIZ 1
 12446  12447   #define JSI_OMIT_SIGNAL
 12447  12448   #endif
 12448  12449   
 12449  12450   #ifndef JSI_AMALGAMATION
................................................................................
 12787  12788   } jsi_JmpPopInfo;
 12788  12789   
 12789  12790   #define RES_CONTINUE    1
 12790  12791   #define RES_BREAK       2
 12791  12792   typedef struct YYLTYPE jsi_Pline;
 12792  12793   
 12793  12794   //void jsi_codes_print(Jsi_OpCodes *ops);
 12794         -void jsi_code_decode(jsi_OpCode *op, int currentip, char *buf, int bsiz);
        12795  +void jsi_code_decode(Jsi_Interp *interp, jsi_OpCode *op, int currentip, char *buf, int bsiz);
 12795  12796   const char* jsi_opcode_string(uint opCode);
 12796  12797   
 12797  12798   #ifdef JSI_MEM_DEBUG
 12798  12799   typedef struct 
 12799  12800   {
 12800  12801       const char *fname;
 12801  12802       int line;
................................................................................
 13328  13329       bool outUndef;
 13329  13330       bool strictFiles;
 13330  13331       bool logAllowDups;
 13331  13332       bool logColNums;
 13332  13333       bool privKeys;
 13333  13334       bool compat;
 13334  13335       bool mutexUnlock;
        13336  +    int dblPrec;
 13335  13337       const char *blacklist;
 13336  13338   } jsi_SubOptions;
 13337  13339   
 13338  13340   extern Jsi_OptionSpec jsi_InterpLogOptions[];
 13339  13341   
 13340  13342   typedef enum {
 13341  13343           jsi_TL_TRY,
................................................................................
 14403  14405   const char* jsi_opcode_string(uint opCode)
 14404  14406   {
 14405  14407       if (opCode >= (sizeof(jsi_op_names)/sizeof(jsi_op_names[0])))
 14406  14408           return "NULL";
 14407  14409       return jsi_op_names[opCode];
 14408  14410   }
 14409  14411   
 14410         -void jsi_code_decode(jsi_OpCode *op, int currentip, char *buf, int bsiz)
        14412  +void jsi_code_decode(Jsi_Interp *interp, jsi_OpCode *op, int currentip, char *buf, int bsiz)
 14411  14413   {
 14412  14414       if (_JSICASTINT(op->op) < 0 || op->op >= OP_LASTOP) {
 14413  14415           snprintf(buf, bsiz, "Bad opcode[%d] at %d", op->op, currentip);
 14414  14416       }
 14415  14417       char nbuf[100];
 14416  14418       snprintf(nbuf, sizeof(nbuf), "%d#%d", currentip, op->Line);
 14417  14419       snprintf(buf, bsiz, "%-8s %s ", nbuf, jsi_op_names[op->op]);
................................................................................
 14422  14424       if (op->op == OP_PUSHBOO || op->op == OP_FCALL || op->op == OP_EVAL ||
 14423  14425           op->op == OP_POP || op->op == OP_ASSIGN ||
 14424  14426           op->op == OP_RET || op->op == OP_NEWFCALL ||
 14425  14427           op->op == OP_DELETE || op->op == OP_CHTHIS ||
 14426  14428           op->op == OP_OBJECT || op->op == OP_ARRAY ||
 14427  14429           op->op == OP_SHF ||
 14428  14430           op->op == OP_INC || op->op == OP_DEC) snprintf(bp, bsiz, "%" PRId64, (Jsi_Wide)(uintptr_t)op->data);
 14429         -    else if (op->op == OP_PUSHNUM) snprintf(bp, bsiz, "%" JSI_NUMGFMT "", *((Jsi_Number *)op->data));
        14431  +    else if (op->op == OP_PUSHNUM) Jsi_NumberDtoA(interp, *((Jsi_Number *)op->data), bp, bsiz, 0);
 14430  14432       else if (op->op == OP_PUSHSTR || op->op == OP_LOCAL ||
 14431  14433                op->op == OP_SCATCH) snprintf(bp, bsiz, "\"%s\"", op->data ? (char*)op->data:"(NoCatch)");
 14432  14434       else if (op->op == OP_PUSHVAR) snprintf(bp, bsiz, "var: \"%s\"", ((jsi_FastVar *)op->data)->varname);
 14433  14435       else if (op->op == OP_PUSHFUN) snprintf(bp, bsiz, "func: 0x%" PRIx64, (Jsi_Wide)(uintptr_t)op->data);
 14434  14436       else if (op->op == OP_JTRUE || op->op == OP_JFALSE ||
 14435  14437                op->op == OP_JTRUE_NP || op->op == OP_JFALSE_NP ||
 14436  14438                op->op == OP_JMP) snprintf(bp, bsiz, "{%" PRIu64 "}\t#%" PRIu64 "", (Jsi_Wide)(uintptr_t)op->data, (Jsi_Wide)((uintptr_t)currentip + (uintptr_t)op->data));
................................................................................
 14452  14454           return;
 14453  14455       while (i < ops->code_len) {
 14454  14456           if (ops->codes[i].op == OP_PUSHVAR)
 14455  14457               ops->codes[i].local = 1;
 14456  14458           i++;
 14457  14459       }
 14458  14460   }
 14459         -
 14460         -/*
 14461         -void jsi_codes_print(Jsi_OpCodes *ops)
 14462         -{
 14463         -    int i = 0;
 14464         -    jsi_OpCode *opcodes = ops->codes;
 14465         -    int opcodesi = ops->code_len;
 14466         -    
 14467         -    fprintf(stderr, "opcodes count = %d\n", opcodesi);
 14468         -    
 14469         -    while(i < opcodesi) {
 14470         -        jsi_code_decode(&opcodes[i], i);
 14471         -        i++;
 14472         -    }
 14473         -}*/
 14474         -
 14475         -
 14476  14461   
 14477  14462   static jsi_ForinVar *forinvar_new(jsi_Pstate *pstate, const char *varname, Jsi_OpCodes *local, Jsi_OpCodes *lval)
 14478  14463   {
 14479  14464       jsi_ForinVar *r = (jsi_ForinVar*)Jsi_Calloc(1,sizeof(*r));
 14480  14465       r->sig = JSI_SIG_FORINVAR;
 14481  14466       r->varname = varname;
 14482  14467       r->local = local;
................................................................................
 16565  16550       if (otype != JSI_OT_ARRAY)
 16566  16551           return (v->d.obj->ot == otype);
 16567  16552       if (v->d.obj->ot != JSI_OT_OBJECT || !v->d.obj->isarrlist)
 16568  16553           return 0;
 16569  16554       return 1;
 16570  16555   }
 16571  16556   
 16572         -char* Jsi_NumberToString(Jsi_Number d, char *buf, int bsiz)
        16557  +char* Jsi_NumberToString(Jsi_Interp *interp, Jsi_Number d, char *buf, int bsiz)
 16573  16558   {
 16574  16559        if (Jsi_NumberIsInteger(d)) {
 16575  16560           Jsi_NumberItoA10((Jsi_Wide)d, buf, bsiz);
 16576  16561       } else if (Jsi_NumberIsNormal(d)) {
 16577         -        Jsi_NumberDtoA(d, buf, bsiz, 10);
        16562  +        Jsi_NumberDtoA(interp, d, buf, bsiz, 0);
 16578  16563       } else if (Jsi_NumberIsNaN(d)) {
 16579  16564           Jsi_Strcpy(buf, "NaN");
 16580  16565       } else {
 16581  16566           int s = Jsi_NumberIsInfinity(d);
 16582  16567           if (s > 0) Jsi_Strcpy(buf,  "Infinity");
 16583  16568           else if (s < 0) Jsi_Strcpy(buf, "-Infinity");
 16584  16569           else {
................................................................................
 16616  16601               d = v->d.num;
 16617  16602   fmtnum:
 16618  16603               if (Jsi_NumberIsInteger(d)) {
 16619  16604                   Jsi_NumberItoA10((Jsi_Wide)d, unibuf, sizeof(unibuf));
 16620  16605                   kflag = 0;
 16621  16606                   ntxt = unibuf;
 16622  16607               } else if (Jsi_NumberIsNormal(d)) {
 16623         -                Jsi_NumberDtoA(d, unibuf, sizeof(unibuf), 10);
        16608  +                Jsi_NumberDtoA(interp, d, unibuf, sizeof(unibuf), 0);
 16624  16609                   kflag = 0;
 16625  16610                   ntxt = unibuf;
 16626  16611               } else if (Jsi_NumberIsNaN(v->d.num)) {
 16627  16612                   ntxt = "NaN";
 16628  16613               } else {
 16629  16614                   int s = Jsi_NumberIsInfinity(d);
 16630  16615                   if (s > 0) ntxt = "Infinity";
................................................................................
 18496  18481       JSI_OPT(STRKEY, jsi_LogOptions, timeFmt, .help="A format string to use with strftime" ),
 18497  18482       JSI_OPT(USEROBJ,jsi_LogOptions, chan,    .help="Channel to send output to", .flags=0, .custom=0, .data=(void*)"Channel" ),
 18498  18483       JSI_OPT_END(jsi_LogOptions, .help="Interp options for logging")
 18499  18484   };
 18500  18485   static Jsi_OptionSpec InterpSubOptions[] = {
 18501  18486       JSI_OPT(STRKEY,jsi_SubOptions, blacklist,   .help="Comma separated modules to disable loading for", jsi_IIOF ),
 18502  18487       JSI_OPT(BOOL,  jsi_SubOptions, compat,      .help="Ignore unknown options via JSI_OPTS_IGNORE_EXTRA in option parser" ),
        18488  +    JSI_OPT(INT,   jsi_SubOptions, dblPrec,     .help="Format precision of double (-1): 0=max, -1=max-1, ..", jsi_IIOF),
 18503  18489       JSI_OPT(BOOL,  jsi_SubOptions, istty,       .help="Indicates interp is in interactive mode", jsi_IIRO),
 18504  18490       JSI_OPT(BOOL,  jsi_SubOptions, logColNums,  .help="Display column numbers in error messages"),
 18505  18491       JSI_OPT(BOOL,  jsi_SubOptions, logAllowDups,.help="Log should not filter out duplicate messages"),
 18506  18492       JSI_OPT(BOOL,  jsi_SubOptions, mutexUnlock, .help="Unlock own mutex when evaling in other interps (true)", jsi_IIOF),
 18507  18493       JSI_OPT(BOOL,  jsi_SubOptions, noproto,     .help="Disable support of the OOP symbols:  __proto__, prototype, constructor, etc"),
 18508  18494       JSI_OPT(BOOL,  jsi_SubOptions, noReadline,  .help="In interactive mode disable use of readline" ),
 18509  18495       JSI_OPT(BOOL,  jsi_SubOptions, outUndef,     .help="In interactive mode output result values that are undefined"),
................................................................................
 19155  19141               return jsi_DoExit(interp, 1);
 19156  19142           }
 19157  19143           if (argc == 2 && !Jsi_Strcmp(argv[1], "--version")) {
 19158  19144               char str[200] = "\n";
 19159  19145               Jsi_Channel chan = Jsi_Open(interp, Jsi_ValueNewStringKey(interp, "/zvfs/lib/sourceid.txt"), "r");
 19160  19146               if (chan)
 19161  19147                   Jsi_Read(interp, chan, str, sizeof(str));
 19162         -            printf("%u.%u.%u %" JSI_NUMGFMT " %s", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE, Jsi_Version(), str);
        19148  +            printf("%u.%u.%u %.4" JSI_NUMGFMT " %s", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE, Jsi_Version(), str);
 19163  19149               return jsi_DoExit(interp, 1);
 19164  19150           }
 19165  19151           if (argc == 2 && !Jsi_Strcmp(argv[1], "-v" )) {
 19166  19152               printf("%u.%u.%u\n", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE);
 19167  19153               return jsi_DoExit(interp, 1);
 19168  19154           }
 19169  19155           if (argc > 2 && (Jsi_Strcmp(argv[1], "--module")==0 || Jsi_Strcmp(argv[1], "-M" )==0)) {
................................................................................
 19460  19446               Jsi_LogError("exceeded max subinterp depth");
 19461  19447               return NULL;
 19462  19448           }
 19463  19449       }
 19464  19450       interp->maxDepth = JSI_MAX_EVAL_DEPTH;
 19465  19451       interp->maxIncDepth = JSI_MAX_INCLUDE_DEPTH;
 19466  19452       interp->typeWarnMax = 50;
        19453  +    interp->subOpts.dblPrec = -1;
 19467  19454   
 19468  19455       int iocnt;
 19469  19456       if (iopts) {
 19470  19457           iopts->interp = interp;
 19471  19458           interp->opts = *iopts;
 19472  19459       }
 19473  19460       interp->logOpts.file = 1;
................................................................................
 20012  19999                   refSum += vp->refCnt;
 20013  20000                   if (vdLev>1) {
 20014  20001                       char ebuf[JSI_BUFSIZ], ebuf2[JSI_MAX_NUMBER_STRING];
 20015  20002                       ebuf[0] = 0;
 20016  20003                       if (vp->vt==JSI_VT_OBJECT)
 20017  20004                           snprintf(ebuf, sizeof(ebuf), " {obj=%p, otype=%s}", vp->d.obj, Jsi_ObjTypeStr(interp, vp->d.obj));
 20018  20005                       else if (vp->vt==JSI_VT_NUMBER)
 20019         -                        snprintf(ebuf, sizeof(ebuf), " {num=%s}", Jsi_NumberToString(vp->d.num, ebuf2, sizeof(ebuf2)));
        20006  +                        snprintf(ebuf, sizeof(ebuf), " {num=%s}", Jsi_NumberToString(interp, vp->d.num, ebuf2, sizeof(ebuf2)));
 20020  20007                       else if (vp->vt==JSI_VT_BOOL)
 20021  20008                           snprintf(ebuf, sizeof(ebuf), " {bool=%s}", vp->d.val?"true":"false");
 20022  20009                       else if (vp->vt==JSI_VT_STRING) {
 20023  20010                           const char *sbuf = ((vp->d.s.str && Jsi_Strlen(vp->d.s.str)>40)?"...":"");
 20024  20011                           snprintf(ebuf, sizeof(ebuf), " {string=\"%.40s%s\"}", (vp->d.s.str?vp->d.s.str:""), sbuf);
 20025  20012                       }
 20026  20013                       const char *pfx = "";
................................................................................
 20053  20040                       ebuf[0] = 0;
 20054  20041                       if (vp->ot==JSI_OT_OBJECT) {
 20055  20042                           if (vp->isarrlist)
 20056  20043                               snprintf(ebuf, sizeof(ebuf), "tree#%d, array#%d", (vp->tree?vp->tree->numEntries:0), vp->arrCnt);
 20057  20044                           else
 20058  20045                               snprintf(ebuf, sizeof(ebuf), "tree#%d", (vp->tree?vp->tree->numEntries:0));
 20059  20046                       } else if (vp->ot==JSI_OT_NUMBER)
 20060         -                        snprintf(ebuf, sizeof(ebuf), "num=%s", Jsi_NumberToString(vp->d.num, ebuf2, sizeof(ebuf2)));
        20047  +                        snprintf(ebuf, sizeof(ebuf), "num=%s", Jsi_NumberToString(interp, vp->d.num, ebuf2, sizeof(ebuf2)));
 20061  20048                       else if (vp->ot==JSI_OT_BOOL)
 20062  20049                           snprintf(ebuf, sizeof(ebuf), "bool=%s", vp->d.val?"true":"false");
 20063  20050                       else if (vp->ot==JSI_OT_STRING) {
 20064  20051                           const char *sbuf = ((vp->d.s.str && Jsi_Strlen(vp->d.s.str)>40)?"...":"");
 20065  20052                           snprintf(ebuf, sizeof(ebuf), "string=\"%.40s%s\"", (vp->d.s.str?vp->d.s.str:""), sbuf);
 20066  20053                       }
 20067  20054                       fprintf(stderr, "[*%p,#%d,%s,%d:%s%s%s]:%s @%s:%d in %s() {%s}\n",
................................................................................
 21772  21759       Jsi_DSAppend(dStr, ":", NULL);
 21773  21760       ow->depth++;
 21774  21761       Jsi_RC rc = jsiValueGetString(tree->opts.interp, v, dStr, ow);
 21775  21762       ow->depth--;
 21776  21763       return rc;
 21777  21764   }
 21778  21765   
 21779         -#include <float.h>
 21780         -
 21781  21766   /* Format value into dStr.  Toplevel caller does init/free. */
 21782  21767   static Jsi_RC jsiValueGetString(Jsi_Interp *interp, Jsi_Value* v, Jsi_DString *dStr, objwalker *owPtr)
 21783  21768   {
 21784  21769       char buf[100], *str;
 21785  21770       Jsi_DString eStr;
 21786  21771       Jsi_DSInit(&eStr);
 21787  21772       if (interp->maxDepth>0 && owPtr->depth > interp->maxDepth)
................................................................................
 21810  21795               } else if (Jsi_NumberIsInteger(num)) {
 21811  21796                   Jsi_NumberItoA10((Jsi_Wide)num, buf, sizeof(buf));
 21812  21797                   Jsi_DSAppend(dStr, buf, NULL);
 21813  21798               } else if (Jsi_NumberIsWide(num)) {
 21814  21799                   snprintf(buf, sizeof(buf), "%" PRId64, (Jsi_Wide)num);
 21815  21800                   Jsi_DSAppend(dStr, buf, NULL);
 21816  21801               } else if (Jsi_NumberIsNormal(num) || Jsi_NumberIsSubnormal(num)) {
 21817         -                Jsi_NumberDtoA(num, buf, sizeof(buf), -1);
        21802  +                Jsi_NumberDtoA(interp, num, buf, sizeof(buf), 0);
 21818  21803                   Jsi_DSAppend(dStr, buf, NULL);
 21819  21804               } else if (Jsi_NumberIsNaN(num)) {
 21820  21805                   Jsi_DSAppend(dStr, "NaN", NULL);
 21821  21806               } else {
 21822  21807                   int s = Jsi_NumberIsInfinity(num);
 21823  21808                   if (s > 0) Jsi_DSAppend(dStr, "+Infinity", NULL);
 21824  21809                   else if (s < 0) Jsi_DSAppend(dStr, "-Infinity", NULL);
................................................................................
 22298  22283       if (hist) {
 22299  22284           jsi_sh_stifle_history(100);
 22300  22285           jsi_sh_write_history(hist);
 22301  22286       }
 22302  22287       Jsi_DSFree(&dHist);
 22303  22288   #endif
 22304  22289       Jsi_DSFree(&dStr);
        22290  +    if (interp->retValue) {
        22291  +        Jsi_DecrRefCount(interp, interp->retValue);
        22292  +        interp->retValue = NULL;
        22293  +    }
 22305  22294       if (interp->exited && interp->level <= 0)
 22306  22295       {
 22307  22296           rc = JSI_EXIT;
 22308  22297           Jsi_InterpDelete(interp);
 22309  22298       }
 22310  22299       jsi_interactiveInterp = NULL;
 22311  22300       return rc;
................................................................................
 26958  26947       if (!release)
 26959  26948           interp->Boolean_prototype = Jsi_CommandCreateSpecs(interp, "Boolean", booleanCmds, NULL, JSI_CMDSPEC_ISOBJ);
 26960  26949       return JSI_OK;
 26961  26950   }
 26962  26951   #endif
 26963  26952   
 26964  26953   #include <math.h>
 26965         -#include <float.h>
 26966         -#include <stdio.h>
 26967  26954   #ifndef JSI_AMALGAMATION
 26968  26955   #include "jsiInt.h"
 26969  26956   #endif
 26970  26957   
 26971  26958   bool Jsi_NumberIsSubnormal(Jsi_Number a) { return fpclassify(a) == FP_SUBNORMAL; }
 26972  26959   
 26973  26960   bool Jsi_NumberIsNormal(Jsi_Number a) { return (fpclassify(a) == FP_ZERO || isnormal(a)); }
................................................................................
 27020  27007   
 27021  27008   bool Jsi_NumberIsFinite(Jsi_Number value)
 27022  27009   {
 27023  27010       Jsi_Number r = INFINITY;
 27024  27011       return (Jsi_NumberIsNaN(value)==0 && value != r && r != -value);
 27025  27012   }
 27026  27013   
 27027         -void Jsi_NumberDtoA(Jsi_Number value, char* buf, int bsiz, int prec)
        27014  +void Jsi_NumberDtoA(Jsi_Interp *interp, Jsi_Number value, char* buf, int bsiz, int prec)
 27028  27015   {
 27029         -    if (prec<0)
 27030         -        prec = DBL_DECIMAL_DIG;
        27016  +    int dp = interp->subOpts.dblPrec, dm = DBL_DECIMAL_DIG;
        27017  +    if (prec==0)
        27018  +        prec = (dp<=0?dm+dp:dp);
        27019  +    else if (prec<0)
        27020  +            prec = dm+prec;
        27021  +    if (prec<=0)
        27022  +        prec = dm-1;
 27031  27023       if (Jsi_NumberIsNaN(value))
 27032  27024           Jsi_Strcpy(buf,"NaN");
 27033  27025       else
 27034  27026           snprintf(buf, bsiz, "%.*" JSI_NUMGFMT, prec, value);
 27035  27027   }
 27036  27028   
 27037  27029   bool Jsi_NumberIsEqual(Jsi_Number n1, Jsi_Number n2)
................................................................................
 33041  33033   Jsi_RC jsi_GetVerFromVal(Jsi_Interp *interp, Jsi_Value *val, Jsi_Number *nPtr, bool isProvide)
 33042  33034   {
 33043  33035       Jsi_Number n = *nPtr;
 33044  33036       if (!val)
 33045  33037           return Jsi_LogError("missing version");
 33046  33038       if (Jsi_ValueIsNumber(interp, val)) {
 33047  33039           if (Jsi_GetDoubleFromValue(interp, val, &n) != JSI_OK || Jsi_NumberIsNaN(n) || (isProvide?n<=0.0:n<0.0) || n>=100.0)
 33048         -            return Jsi_LogError("bad version: %" JSI_NUMGFMT, n);
        33040  +            return Jsi_LogError("bad version: %.4" JSI_NUMGFMT, n);
 33049  33041           *nPtr = n;
 33050  33042           return JSI_OK;
 33051  33043       }
 33052  33044       const char *vstr = Jsi_ValueString(interp, val, NULL), *vs = vstr;
 33053  33045       if (!vstr)
 33054  33046           return Jsi_LogError("bad version");
 33055  33047       uint v[3] = {};
................................................................................
 33137  33129       Jsi_Number ver = Jsi_PkgRequire(interp, name, n);
 33138  33130       interp->isMain = isMain;
 33139  33131       if (ver < 0)
 33140  33132           return JSI_ERROR;
 33141  33133       Jsi_RC rc = JSI_OK;
 33142  33134       if (argc>1) {
 33143  33135           if (ver < n) 
 33144         -            rc = Jsi_LogType("package '%s' downlevel: %" JSI_NUMGFMT " < %" JSI_NUMGFMT, name, ver, n);
        33136  +            rc = Jsi_LogType("package '%s' downlevel: %.4" JSI_NUMGFMT " < %.4" JSI_NUMGFMT, name, ver, n);
 33145  33137           if (rc != JSI_OK)
 33146  33138               return rc;
 33147  33139           return jsi_PkgDumpInfo(interp, name, ret);
 33148  33140       }
 33149  33141       Jsi_ValueMakeNumber(interp, ret, ver);
 33150  33142       return rc;
 33151  33143   }
................................................................................
 47417  47409   #else
 47418  47410           snprintf(nbuf, sizeof(nbuf), "%lld", v);
 47419  47411   #endif
 47420  47412           Jsi_DSAppend(dStr, nbuf, NULL);
 47421  47413           return;
 47422  47414       }
 47423  47415       case SQLITE_FLOAT: {
 47424         -        Jsi_NumberToString(sqlite3_column_double(pStmt, iCol), nbuf, sizeof(nbuf));
        47416  +        Jsi_NumberToString(interp, sqlite3_column_double(pStmt, iCol), nbuf, sizeof(nbuf));
 47425  47417           Jsi_DSAppend(dStr, nbuf, NULL);
 47426  47418           return;
 47427  47419       }
 47428  47420       case SQLITE_NULL: {
 47429  47421           Jsi_DSAppend(dStr, "null", NULL);
 47430  47422           return;
 47431  47423       }
................................................................................
 47433  47425       const char *str = (char*)sqlite3_column_text(pStmt, iCol );
 47434  47426       if (!str)
 47435  47427           str = p->jdb->optPtr->nullvalue;
 47436  47428       Jsi_JSONQuote(interp, str?str:"", -1, dStr);
 47437  47429   }
 47438  47430   
 47439  47431   static void dbEvalSetColumn(DbEvalContext *p, int iCol, Jsi_DString *dStr) {
        47432  +    Jsi_Interp *interp = p->jdb->interp;
 47440  47433       char nbuf[200];
 47441  47434   
 47442  47435       sqlite3_stmt *pStmt = p->pPreStmt->pStmt;
 47443  47436   
 47444  47437       switch( sqlite3_column_type(pStmt, iCol) ) {
 47445  47438       case SQLITE_BLOB: {
 47446  47439           int bytes = sqlite3_column_bytes(pStmt, iCol);
................................................................................
 47458  47451   #else
 47459  47452           snprintf(nbuf, sizeof(nbuf), "%lld", v);
 47460  47453   #endif
 47461  47454           Jsi_DSAppend(dStr, nbuf, NULL);
 47462  47455           return;
 47463  47456       }
 47464  47457       case SQLITE_FLOAT: {
 47465         -        Jsi_NumberToString(sqlite3_column_double(pStmt, iCol), nbuf, sizeof(nbuf));
        47458  +        Jsi_NumberToString(interp, sqlite3_column_double(pStmt, iCol), nbuf, sizeof(nbuf));
 47466  47459           Jsi_DSAppend(dStr, nbuf, NULL);
 47467  47460           return;
 47468  47461       }
 47469  47462       case SQLITE_NULL: {
 47470  47463           return;
 47471  47464       }
 47472  47465       }
................................................................................
 54101  54094           }
 54102  54095           case JSI_OPTION_INT64: {
 54103  54096               snprintf(nbuf, sizeof(nbuf), "%lld", field->buffer.vlonglong);
 54104  54097               Jsi_DSAppend(dStr, nbuf, NULL);
 54105  54098               return;
 54106  54099           }
 54107  54100           case JSI_OPTION_DOUBLE: {
 54108         -            Jsi_NumberToString(field->buffer.vdouble, nbuf, sizeof(nbuf));
        54101  +            Jsi_NumberToString(interp, field->buffer.vdouble, nbuf, sizeof(nbuf));
 54109  54102               Jsi_DSAppend(dStr, nbuf, NULL);
 54110  54103               return;
 54111  54104           }
 54112  54105           //case JSI_OPTION_TIME_T:
 54113  54106           case JSI_OPTION_TIME_D:
 54114  54107           case JSI_OPTION_TIME_W: {
 54115  54108               Jsi_Number jtime = mdbMyTimeToJS(&field->buffer.timestamp);
 54116         -            Jsi_NumberToString(jtime, nbuf, sizeof(nbuf));
        54109  +            Jsi_NumberToString(interp, jtime, nbuf, sizeof(nbuf));
 54117  54110               Jsi_DSAppend(dStr, nbuf, NULL);
 54118  54111               return;
 54119  54112           }
 54120  54113           case JSI_OPTION_STRING:
 54121  54114               zBlob = field->buffer.vstring;
 54122  54115           default:
 54123  54116           {
................................................................................
 54163  54156               Jsi_DSAppend(dStr, nbuf, NULL);
 54164  54157               return;
 54165  54158           }
 54166  54159           //case JSI_OPTION_TIME_T:
 54167  54160           case JSI_OPTION_TIME_D:
 54168  54161           case JSI_OPTION_TIME_W: {
 54169  54162               Jsi_Number jtime = mdbMyTimeToJS(&field->buffer.timestamp);
 54170         -            Jsi_NumberToString(jtime, nbuf, sizeof(nbuf));
        54163  +            Jsi_NumberToString(interp, jtime, nbuf, sizeof(nbuf));
 54171  54164               Jsi_DSAppend(dStr, nbuf, NULL);
 54172  54165               return;
 54173  54166           }
 54174  54167           case JSI_OPTION_DOUBLE: {
 54175         -            Jsi_NumberToString(field->buffer.vdouble, nbuf, sizeof(nbuf));
        54168  +            Jsi_NumberToString(interp, field->buffer.vdouble, nbuf, sizeof(nbuf));
 54176  54169               Jsi_DSAppend(dStr, nbuf, NULL);
 54177  54170               return;
 54178  54171           }
 54179  54172           default:
 54180  54173               Jsi_LogWarn("unknown type: %d", field->jsiTypeMap);
 54181  54174       
 54182  54175       }
................................................................................
 63326  63319   }
 63327  63320   
 63328  63321   static void DumpInstr(Jsi_Interp *interp, jsi_Pstate *ps, Jsi_Value *_this,
 63329  63322       jsi_TryList *trylist, jsi_OpCode *ip, Jsi_OpCodes *opcodes)
 63330  63323   {
 63331  63324       int i;
 63332  63325       char buf[200];
 63333         -    jsi_code_decode(ip, ip - opcodes->codes, buf, sizeof(buf));
        63326  +    jsi_code_decode(interp, ip, ip - opcodes->codes, buf, sizeof(buf));
 63334  63327       Jsi_Printf(interp, jsi_Stderr, "%p: %-30.200s : THIS=%s, STACK=[", ip, buf, vprint(_this));
 63335  63328       for (i = 0; i < interp->framePtr->Sp; ++i) {
 63336  63329           Jsi_Printf(interp, jsi_Stderr, "%s%s", (i>0?", ":""), vprint(_jsi_STACKIDX(i)));
 63337  63330       }
 63338  63331       Jsi_Printf(interp, jsi_Stderr, "]");
 63339  63332       if (ip->fname) {
 63340  63333           const char *fn = ip->fname,  *cp = Jsi_Strrchr(fn, '/');

Changes to src/jsi.h.

     1      1   /* jsi.h : External API header file for Jsi. */
     2      2   #ifndef __JSI_H__
     3      3   #define __JSI_H__
     4      4   
     5      5   #define JSI_VERSION_MAJOR   2
     6      6   #define JSI_VERSION_MINOR   5
     7         -#define JSI_VERSION_RELEASE 19
            7  +#define JSI_VERSION_RELEASE 20
     8      8   
     9      9   #define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))
    10     10   
    11     11   #ifndef JSI_EXTERN
    12     12   #define JSI_EXTERN extern
    13     13   #endif
    14     14   
................................................................................
   568    568   JSI_EXTERN int Jsi_UserObjNew    (Jsi_Interp *interp, Jsi_UserObjReg* reg, Jsi_Obj *obj, void *data); /*STUB = 180*/
   569    569   JSI_EXTERN void* Jsi_UserObjGetData(Jsi_Interp *interp, Jsi_Value* value, Jsi_Func *funcPtr); /*STUB = 181*/
   570    570   /* -- */
   571    571   
   572    572   
   573    573   /* --UTILITY-- */
   574    574   #define JSI_NOTUSED(n) (void)n /* Eliminate annoying compiler warning. */
   575         -JSI_EXTERN char* Jsi_NumberToString(Jsi_Number d, char *buf, int bsiz); /*STUB = 182*/
          575  +JSI_EXTERN char* Jsi_NumberToString(Jsi_Interp *interp, Jsi_Number d, char *buf, int bsiz); /*STUB = 182*/
   576    576   JSI_EXTERN Jsi_Number Jsi_Version(void); /*STUB = 183*/
   577    577   JSI_EXTERN Jsi_Value* Jsi_ReturnValue(Jsi_Interp *interp); /*STUB = 184*/
   578    578   JSI_EXTERN Jsi_RC Jsi_Mount( Jsi_Interp *interp, Jsi_Value *archive, Jsi_Value *mount, Jsi_Value **ret); /*STUB = 185*/
   579    579   JSI_EXTERN Jsi_Value* Jsi_Executable(Jsi_Interp *interp); /*STUB = 186*/
   580    580   JSI_EXTERN Jsi_Regex* Jsi_RegExpNew(Jsi_Interp *interp, const char *regtxt, int flag); /*STUB = 187*/
   581    581   JSI_EXTERN void Jsi_RegExpFree(Jsi_Regex* re); /*STUB = 188*/
   582    582   JSI_EXTERN Jsi_RC Jsi_RegExpMatch( Jsi_Interp *interp,  Jsi_Value *pattern, const char *str, int *rc, Jsi_DString *dStr); /*STUB = 189*/
................................................................................
   637    637   JSI_EXTERN bool Jsi_NumberIsInteger(Jsi_Number n);  /*STUB = 238*/
   638    638   JSI_EXTERN bool Jsi_NumberIsNaN(Jsi_Number a);  /*STUB = 239*/
   639    639   JSI_EXTERN bool Jsi_NumberIsNormal(Jsi_Number a);  /*STUB = 240*/
   640    640   JSI_EXTERN bool Jsi_NumberIsSubnormal(Jsi_Number a);  /*STUB = 241*/
   641    641   JSI_EXTERN bool Jsi_NumberIsWide(Jsi_Number n);  /*STUB = 242*/
   642    642   JSI_EXTERN Jsi_Number Jsi_NumberInfinity(int i);  /*STUB = 243*/
   643    643   JSI_EXTERN Jsi_Number Jsi_NumberNaN(void);  /*STUB = 244*/
   644         -JSI_EXTERN void Jsi_NumberDtoA(Jsi_Number value, char* buf, int bsiz, int prec);  /*STUB = 245*/
          644  +JSI_EXTERN void Jsi_NumberDtoA(Jsi_Interp *interp, Jsi_Number value, char* buf, int bsiz, int prec);  /*STUB = 245*/
   645    645   JSI_EXTERN void Jsi_NumberItoA10(Jsi_Wide value, char* buf, int bsiz);  /*STUB = 246*/
   646    646   JSI_EXTERN void Jsi_NumberUtoA10(Jsi_UWide, char* buf, int bsiz);  /*STUB = 247*/
   647    647   
   648    648   /* -- */
   649    649   
   650    650   #define JSI_WORDKEY_CAST (void*)(uintptr_t)
   651    651   

Changes to src/jsiCmds.c.

   774    774   Jsi_RC jsi_GetVerFromVal(Jsi_Interp *interp, Jsi_Value *val, Jsi_Number *nPtr, bool isProvide)
   775    775   {
   776    776       Jsi_Number n = *nPtr;
   777    777       if (!val)
   778    778           return Jsi_LogError("missing version");
   779    779       if (Jsi_ValueIsNumber(interp, val)) {
   780    780           if (Jsi_GetDoubleFromValue(interp, val, &n) != JSI_OK || Jsi_NumberIsNaN(n) || (isProvide?n<=0.0:n<0.0) || n>=100.0)
   781         -            return Jsi_LogError("bad version: %" JSI_NUMGFMT, n);
          781  +            return Jsi_LogError("bad version: %.4" JSI_NUMGFMT, n);
   782    782           *nPtr = n;
   783    783           return JSI_OK;
   784    784       }
   785    785       const char *vstr = Jsi_ValueString(interp, val, NULL), *vs = vstr;
   786    786       if (!vstr)
   787    787           return Jsi_LogError("bad version");
   788    788       uint v[3] = {};
................................................................................
   870    870       Jsi_Number ver = Jsi_PkgRequire(interp, name, n);
   871    871       interp->isMain = isMain;
   872    872       if (ver < 0)
   873    873           return JSI_ERROR;
   874    874       Jsi_RC rc = JSI_OK;
   875    875       if (argc>1) {
   876    876           if (ver < n) 
   877         -            rc = Jsi_LogType("package '%s' downlevel: %" JSI_NUMGFMT " < %" JSI_NUMGFMT, name, ver, n);
          877  +            rc = Jsi_LogType("package '%s' downlevel: %.4" JSI_NUMGFMT " < %.4" JSI_NUMGFMT, name, ver, n);
   878    878           if (rc != JSI_OK)
   879    879               return rc;
   880    880           return jsi_PkgDumpInfo(interp, name, ret);
   881    881       }
   882    882       Jsi_ValueMakeNumber(interp, ret, ver);
   883    883       return rc;
   884    884   }

Changes to src/jsiCode.c.

   422    422   const char* jsi_opcode_string(uint opCode)
   423    423   {
   424    424       if (opCode >= (sizeof(jsi_op_names)/sizeof(jsi_op_names[0])))
   425    425           return "NULL";
   426    426       return jsi_op_names[opCode];
   427    427   }
   428    428   
   429         -void jsi_code_decode(jsi_OpCode *op, int currentip, char *buf, int bsiz)
          429  +void jsi_code_decode(Jsi_Interp *interp, jsi_OpCode *op, int currentip, char *buf, int bsiz)
   430    430   {
   431    431       if (_JSICASTINT(op->op) < 0 || op->op >= OP_LASTOP) {
   432    432           snprintf(buf, bsiz, "Bad opcode[%d] at %d", op->op, currentip);
   433    433       }
   434    434       char nbuf[100];
   435    435       snprintf(nbuf, sizeof(nbuf), "%d#%d", currentip, op->Line);
   436    436       snprintf(buf, bsiz, "%-8s %s ", nbuf, jsi_op_names[op->op]);
................................................................................
   441    441       if (op->op == OP_PUSHBOO || op->op == OP_FCALL || op->op == OP_EVAL ||
   442    442           op->op == OP_POP || op->op == OP_ASSIGN ||
   443    443           op->op == OP_RET || op->op == OP_NEWFCALL ||
   444    444           op->op == OP_DELETE || op->op == OP_CHTHIS ||
   445    445           op->op == OP_OBJECT || op->op == OP_ARRAY ||
   446    446           op->op == OP_SHF ||
   447    447           op->op == OP_INC || op->op == OP_DEC) snprintf(bp, bsiz, "%" PRId64, (Jsi_Wide)(uintptr_t)op->data);
   448         -    else if (op->op == OP_PUSHNUM) snprintf(bp, bsiz, "%" JSI_NUMGFMT "", *((Jsi_Number *)op->data));
          448  +    else if (op->op == OP_PUSHNUM) Jsi_NumberDtoA(interp, *((Jsi_Number *)op->data), bp, bsiz, 0);
   449    449       else if (op->op == OP_PUSHSTR || op->op == OP_LOCAL ||
   450    450                op->op == OP_SCATCH) snprintf(bp, bsiz, "\"%s\"", op->data ? (char*)op->data:"(NoCatch)");
   451    451       else if (op->op == OP_PUSHVAR) snprintf(bp, bsiz, "var: \"%s\"", ((jsi_FastVar *)op->data)->varname);
   452    452       else if (op->op == OP_PUSHFUN) snprintf(bp, bsiz, "func: 0x%" PRIx64, (Jsi_Wide)(uintptr_t)op->data);
   453    453       else if (op->op == OP_JTRUE || op->op == OP_JFALSE ||
   454    454                op->op == OP_JTRUE_NP || op->op == OP_JFALSE_NP ||
   455    455                op->op == OP_JMP) snprintf(bp, bsiz, "{%" PRIu64 "}\t#%" PRIu64 "", (Jsi_Wide)(uintptr_t)op->data, (Jsi_Wide)((uintptr_t)currentip + (uintptr_t)op->data));
................................................................................
   471    471           return;
   472    472       while (i < ops->code_len) {
   473    473           if (ops->codes[i].op == OP_PUSHVAR)
   474    474               ops->codes[i].local = 1;
   475    475           i++;
   476    476       }
   477    477   }
   478         -
   479         -/*
   480         -void jsi_codes_print(Jsi_OpCodes *ops)
   481         -{
   482         -    int i = 0;
   483         -    jsi_OpCode *opcodes = ops->codes;
   484         -    int opcodesi = ops->code_len;
   485         -    
   486         -    fprintf(stderr, "opcodes count = %d\n", opcodesi);
   487         -    
   488         -    while(i < opcodesi) {
   489         -        jsi_code_decode(&opcodes[i], i);
   490         -        i++;
   491         -    }
   492         -}*/
   493         -
   494         -
   495    478   
   496    479   static jsi_ForinVar *forinvar_new(jsi_Pstate *pstate, const char *varname, Jsi_OpCodes *local, Jsi_OpCodes *lval)
   497    480   {
   498    481       jsi_ForinVar *r = (jsi_ForinVar*)Jsi_Calloc(1,sizeof(*r));
   499    482       r->sig = JSI_SIG_FORINVAR;
   500    483       r->varname = varname;
   501    484       r->local = local;

Changes to src/jsiEval.c.

   407    407   }
   408    408   
   409    409   static void DumpInstr(Jsi_Interp *interp, jsi_Pstate *ps, Jsi_Value *_this,
   410    410       jsi_TryList *trylist, jsi_OpCode *ip, Jsi_OpCodes *opcodes)
   411    411   {
   412    412       int i;
   413    413       char buf[200];
   414         -    jsi_code_decode(ip, ip - opcodes->codes, buf, sizeof(buf));
          414  +    jsi_code_decode(interp, ip, ip - opcodes->codes, buf, sizeof(buf));
   415    415       Jsi_Printf(interp, jsi_Stderr, "%p: %-30.200s : THIS=%s, STACK=[", ip, buf, vprint(_this));
   416    416       for (i = 0; i < interp->framePtr->Sp; ++i) {
   417    417           Jsi_Printf(interp, jsi_Stderr, "%s%s", (i>0?", ":""), vprint(_jsi_STACKIDX(i)));
   418    418       }
   419    419       Jsi_Printf(interp, jsi_Stderr, "]");
   420    420       if (ip->fname) {
   421    421           const char *fn = ip->fname,  *cp = Jsi_Strrchr(fn, '/');

Changes to src/jsiInt.h.

   115    115   #include <string.h>
   116    116   #include <stdarg.h>
   117    117   #include <unistd.h>
   118    118   #include <ctype.h>
   119    119   #include <assert.h>
   120    120   #include <inttypes.h>
   121    121   #include <limits.h>
          122  +#include <float.h>
   122    123   
   123    124   #ifdef __WIN32 /* TODO: support windows signal??? */
   124    125   #define JSI__MINIZ 1
   125    126   #define JSI_OMIT_SIGNAL
   126    127   #endif
   127    128   
   128    129   #ifndef JSI_AMALGAMATION
................................................................................
   466    467   } jsi_JmpPopInfo;
   467    468   
   468    469   #define RES_CONTINUE    1
   469    470   #define RES_BREAK       2
   470    471   typedef struct YYLTYPE jsi_Pline;
   471    472   
   472    473   //void jsi_codes_print(Jsi_OpCodes *ops);
   473         -void jsi_code_decode(jsi_OpCode *op, int currentip, char *buf, int bsiz);
          474  +void jsi_code_decode(Jsi_Interp *interp, jsi_OpCode *op, int currentip, char *buf, int bsiz);
   474    475   const char* jsi_opcode_string(uint opCode);
   475    476   
   476    477   #ifdef JSI_MEM_DEBUG
   477    478   typedef struct 
   478    479   {
   479    480       const char *fname;
   480    481       int line;
................................................................................
  1007   1008       bool outUndef;
  1008   1009       bool strictFiles;
  1009   1010       bool logAllowDups;
  1010   1011       bool logColNums;
  1011   1012       bool privKeys;
  1012   1013       bool compat;
  1013   1014       bool mutexUnlock;
         1015  +    int dblPrec;
  1014   1016       const char *blacklist;
  1015   1017   } jsi_SubOptions;
  1016   1018   
  1017   1019   extern Jsi_OptionSpec jsi_InterpLogOptions[];
  1018   1020   
  1019   1021   typedef enum {
  1020   1022           jsi_TL_TRY,

Changes to src/jsiInterp.c.

    52     52       JSI_OPT(STRKEY, jsi_LogOptions, timeFmt, .help="A format string to use with strftime" ),
    53     53       JSI_OPT(USEROBJ,jsi_LogOptions, chan,    .help="Channel to send output to", .flags=0, .custom=0, .data=(void*)"Channel" ),
    54     54       JSI_OPT_END(jsi_LogOptions, .help="Interp options for logging")
    55     55   };
    56     56   static Jsi_OptionSpec InterpSubOptions[] = {
    57     57       JSI_OPT(STRKEY,jsi_SubOptions, blacklist,   .help="Comma separated modules to disable loading for", jsi_IIOF ),
    58     58       JSI_OPT(BOOL,  jsi_SubOptions, compat,      .help="Ignore unknown options via JSI_OPTS_IGNORE_EXTRA in option parser" ),
           59  +    JSI_OPT(INT,   jsi_SubOptions, dblPrec,     .help="Format precision of double (-1): 0=max, -1=max-1, ..", jsi_IIOF),
    59     60       JSI_OPT(BOOL,  jsi_SubOptions, istty,       .help="Indicates interp is in interactive mode", jsi_IIRO),
    60     61       JSI_OPT(BOOL,  jsi_SubOptions, logColNums,  .help="Display column numbers in error messages"),
    61     62       JSI_OPT(BOOL,  jsi_SubOptions, logAllowDups,.help="Log should not filter out duplicate messages"),
    62     63       JSI_OPT(BOOL,  jsi_SubOptions, mutexUnlock, .help="Unlock own mutex when evaling in other interps (true)", jsi_IIOF),
    63     64       JSI_OPT(BOOL,  jsi_SubOptions, noproto,     .help="Disable support of the OOP symbols:  __proto__, prototype, constructor, etc"),
    64     65       JSI_OPT(BOOL,  jsi_SubOptions, noReadline,  .help="In interactive mode disable use of readline" ),
    65     66       JSI_OPT(BOOL,  jsi_SubOptions, outUndef,     .help="In interactive mode output result values that are undefined"),
................................................................................
   711    712               return jsi_DoExit(interp, 1);
   712    713           }
   713    714           if (argc == 2 && !Jsi_Strcmp(argv[1], "--version")) {
   714    715               char str[200] = "\n";
   715    716               Jsi_Channel chan = Jsi_Open(interp, Jsi_ValueNewStringKey(interp, "/zvfs/lib/sourceid.txt"), "r");
   716    717               if (chan)
   717    718                   Jsi_Read(interp, chan, str, sizeof(str));
   718         -            printf("%u.%u.%u %" JSI_NUMGFMT " %s", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE, Jsi_Version(), str);
          719  +            printf("%u.%u.%u %.4" JSI_NUMGFMT " %s", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE, Jsi_Version(), str);
   719    720               return jsi_DoExit(interp, 1);
   720    721           }
   721    722           if (argc == 2 && !Jsi_Strcmp(argv[1], "-v" )) {
   722    723               printf("%u.%u.%u\n", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE);
   723    724               return jsi_DoExit(interp, 1);
   724    725           }
   725    726           if (argc > 2 && (Jsi_Strcmp(argv[1], "--module")==0 || Jsi_Strcmp(argv[1], "-M" )==0)) {
................................................................................
  1016   1017               Jsi_LogError("exceeded max subinterp depth");
  1017   1018               return NULL;
  1018   1019           }
  1019   1020       }
  1020   1021       interp->maxDepth = JSI_MAX_EVAL_DEPTH;
  1021   1022       interp->maxIncDepth = JSI_MAX_INCLUDE_DEPTH;
  1022   1023       interp->typeWarnMax = 50;
         1024  +    interp->subOpts.dblPrec = -1;
  1023   1025   
  1024   1026       int iocnt;
  1025   1027       if (iopts) {
  1026   1028           iopts->interp = interp;
  1027   1029           interp->opts = *iopts;
  1028   1030       }
  1029   1031       interp->logOpts.file = 1;
................................................................................
  1568   1570                   refSum += vp->refCnt;
  1569   1571                   if (vdLev>1) {
  1570   1572                       char ebuf[JSI_BUFSIZ], ebuf2[JSI_MAX_NUMBER_STRING];
  1571   1573                       ebuf[0] = 0;
  1572   1574                       if (vp->vt==JSI_VT_OBJECT)
  1573   1575                           snprintf(ebuf, sizeof(ebuf), " {obj=%p, otype=%s}", vp->d.obj, Jsi_ObjTypeStr(interp, vp->d.obj));
  1574   1576                       else if (vp->vt==JSI_VT_NUMBER)
  1575         -                        snprintf(ebuf, sizeof(ebuf), " {num=%s}", Jsi_NumberToString(vp->d.num, ebuf2, sizeof(ebuf2)));
         1577  +                        snprintf(ebuf, sizeof(ebuf), " {num=%s}", Jsi_NumberToString(interp, vp->d.num, ebuf2, sizeof(ebuf2)));
  1576   1578                       else if (vp->vt==JSI_VT_BOOL)
  1577   1579                           snprintf(ebuf, sizeof(ebuf), " {bool=%s}", vp->d.val?"true":"false");
  1578   1580                       else if (vp->vt==JSI_VT_STRING) {
  1579   1581                           const char *sbuf = ((vp->d.s.str && Jsi_Strlen(vp->d.s.str)>40)?"...":"");
  1580   1582                           snprintf(ebuf, sizeof(ebuf), " {string=\"%.40s%s\"}", (vp->d.s.str?vp->d.s.str:""), sbuf);
  1581   1583                       }
  1582   1584                       const char *pfx = "";
................................................................................
  1609   1611                       ebuf[0] = 0;
  1610   1612                       if (vp->ot==JSI_OT_OBJECT) {
  1611   1613                           if (vp->isarrlist)
  1612   1614                               snprintf(ebuf, sizeof(ebuf), "tree#%d, array#%d", (vp->tree?vp->tree->numEntries:0), vp->arrCnt);
  1613   1615                           else
  1614   1616                               snprintf(ebuf, sizeof(ebuf), "tree#%d", (vp->tree?vp->tree->numEntries:0));
  1615   1617                       } else if (vp->ot==JSI_OT_NUMBER)
  1616         -                        snprintf(ebuf, sizeof(ebuf), "num=%s", Jsi_NumberToString(vp->d.num, ebuf2, sizeof(ebuf2)));
         1618  +                        snprintf(ebuf, sizeof(ebuf), "num=%s", Jsi_NumberToString(interp, vp->d.num, ebuf2, sizeof(ebuf2)));
  1617   1619                       else if (vp->ot==JSI_OT_BOOL)
  1618   1620                           snprintf(ebuf, sizeof(ebuf), "bool=%s", vp->d.val?"true":"false");
  1619   1621                       else if (vp->ot==JSI_OT_STRING) {
  1620   1622                           const char *sbuf = ((vp->d.s.str && Jsi_Strlen(vp->d.s.str)>40)?"...":"");
  1621   1623                           snprintf(ebuf, sizeof(ebuf), "string=\"%.40s%s\"", (vp->d.s.str?vp->d.s.str:""), sbuf);
  1622   1624                       }
  1623   1625                       fprintf(stderr, "[*%p,#%d,%s,%d:%s%s%s]:%s @%s:%d in %s() {%s}\n",

Changes to src/jsiMySql.c.

  1170   1170           }
  1171   1171           case JSI_OPTION_INT64: {
  1172   1172               snprintf(nbuf, sizeof(nbuf), "%lld", field->buffer.vlonglong);
  1173   1173               Jsi_DSAppend(dStr, nbuf, NULL);
  1174   1174               return;
  1175   1175           }
  1176   1176           case JSI_OPTION_DOUBLE: {
  1177         -            Jsi_NumberToString(field->buffer.vdouble, nbuf, sizeof(nbuf));
         1177  +            Jsi_NumberToString(interp, field->buffer.vdouble, nbuf, sizeof(nbuf));
  1178   1178               Jsi_DSAppend(dStr, nbuf, NULL);
  1179   1179               return;
  1180   1180           }
  1181   1181           //case JSI_OPTION_TIME_T:
  1182   1182           case JSI_OPTION_TIME_D:
  1183   1183           case JSI_OPTION_TIME_W: {
  1184   1184               Jsi_Number jtime = mdbMyTimeToJS(&field->buffer.timestamp);
  1185         -            Jsi_NumberToString(jtime, nbuf, sizeof(nbuf));
         1185  +            Jsi_NumberToString(interp, jtime, nbuf, sizeof(nbuf));
  1186   1186               Jsi_DSAppend(dStr, nbuf, NULL);
  1187   1187               return;
  1188   1188           }
  1189   1189           case JSI_OPTION_STRING:
  1190   1190               zBlob = field->buffer.vstring;
  1191   1191           default:
  1192   1192           {
................................................................................
  1232   1232               Jsi_DSAppend(dStr, nbuf, NULL);
  1233   1233               return;
  1234   1234           }
  1235   1235           //case JSI_OPTION_TIME_T:
  1236   1236           case JSI_OPTION_TIME_D:
  1237   1237           case JSI_OPTION_TIME_W: {
  1238   1238               Jsi_Number jtime = mdbMyTimeToJS(&field->buffer.timestamp);
  1239         -            Jsi_NumberToString(jtime, nbuf, sizeof(nbuf));
         1239  +            Jsi_NumberToString(interp, jtime, nbuf, sizeof(nbuf));
  1240   1240               Jsi_DSAppend(dStr, nbuf, NULL);
  1241   1241               return;
  1242   1242           }
  1243   1243           case JSI_OPTION_DOUBLE: {
  1244         -            Jsi_NumberToString(field->buffer.vdouble, nbuf, sizeof(nbuf));
         1244  +            Jsi_NumberToString(interp, field->buffer.vdouble, nbuf, sizeof(nbuf));
  1245   1245               Jsi_DSAppend(dStr, nbuf, NULL);
  1246   1246               return;
  1247   1247           }
  1248   1248           default:
  1249   1249               Jsi_LogWarn("unknown type: %d", field->jsiTypeMap);
  1250   1250       
  1251   1251       }

Changes to src/jsiNumber.c.

     1      1   #include <math.h>
     2         -#include <float.h>
     3         -#include <stdio.h>
     4      2   #ifndef JSI_AMALGAMATION
     5      3   #include "jsiInt.h"
     6      4   #endif
     7      5   
     8      6   bool Jsi_NumberIsSubnormal(Jsi_Number a) { return fpclassify(a) == FP_SUBNORMAL; }
     9      7   
    10      8   bool Jsi_NumberIsNormal(Jsi_Number a) { return (fpclassify(a) == FP_ZERO || isnormal(a)); }
................................................................................
    57     55   
    58     56   bool Jsi_NumberIsFinite(Jsi_Number value)
    59     57   {
    60     58       Jsi_Number r = INFINITY;
    61     59       return (Jsi_NumberIsNaN(value)==0 && value != r && r != -value);
    62     60   }
    63     61   
    64         -void Jsi_NumberDtoA(Jsi_Number value, char* buf, int bsiz, int prec)
           62  +void Jsi_NumberDtoA(Jsi_Interp *interp, Jsi_Number value, char* buf, int bsiz, int prec)
    65     63   {
    66         -    if (prec<0)
    67         -        prec = DBL_DECIMAL_DIG;
           64  +    int dp = interp->subOpts.dblPrec, dm = DBL_DECIMAL_DIG;
           65  +    if (prec==0)
           66  +        prec = (dp<=0?dm+dp:dp);
           67  +    else if (prec<0)
           68  +            prec = dm+prec;
           69  +    if (prec<=0)
           70  +        prec = dm-1;
    68     71       if (Jsi_NumberIsNaN(value))
    69     72           Jsi_Strcpy(buf,"NaN");
    70     73       else
    71     74           snprintf(buf, bsiz, "%.*" JSI_NUMGFMT, prec, value);
    72     75   }
    73     76   
    74     77   bool Jsi_NumberIsEqual(Jsi_Number n1, Jsi_Number n2)

Changes to src/jsiSqlite.c.

  1727   1727   #else
  1728   1728           snprintf(nbuf, sizeof(nbuf), "%lld", v);
  1729   1729   #endif
  1730   1730           Jsi_DSAppend(dStr, nbuf, NULL);
  1731   1731           return;
  1732   1732       }
  1733   1733       case SQLITE_FLOAT: {
  1734         -        Jsi_NumberToString(sqlite3_column_double(pStmt, iCol), nbuf, sizeof(nbuf));
         1734  +        Jsi_NumberToString(interp, sqlite3_column_double(pStmt, iCol), nbuf, sizeof(nbuf));
  1735   1735           Jsi_DSAppend(dStr, nbuf, NULL);
  1736   1736           return;
  1737   1737       }
  1738   1738       case SQLITE_NULL: {
  1739   1739           Jsi_DSAppend(dStr, "null", NULL);
  1740   1740           return;
  1741   1741       }
................................................................................
  1743   1743       const char *str = (char*)sqlite3_column_text(pStmt, iCol );
  1744   1744       if (!str)
  1745   1745           str = p->jdb->optPtr->nullvalue;
  1746   1746       Jsi_JSONQuote(interp, str?str:"", -1, dStr);
  1747   1747   }
  1748   1748   
  1749   1749   static void dbEvalSetColumn(DbEvalContext *p, int iCol, Jsi_DString *dStr) {
         1750  +    Jsi_Interp *interp = p->jdb->interp;
  1750   1751       char nbuf[200];
  1751   1752   
  1752   1753       sqlite3_stmt *pStmt = p->pPreStmt->pStmt;
  1753   1754   
  1754   1755       switch( sqlite3_column_type(pStmt, iCol) ) {
  1755   1756       case SQLITE_BLOB: {
  1756   1757           int bytes = sqlite3_column_bytes(pStmt, iCol);
................................................................................
  1768   1769   #else
  1769   1770           snprintf(nbuf, sizeof(nbuf), "%lld", v);
  1770   1771   #endif
  1771   1772           Jsi_DSAppend(dStr, nbuf, NULL);
  1772   1773           return;
  1773   1774       }
  1774   1775       case SQLITE_FLOAT: {
  1775         -        Jsi_NumberToString(sqlite3_column_double(pStmt, iCol), nbuf, sizeof(nbuf));
         1776  +        Jsi_NumberToString(interp, sqlite3_column_double(pStmt, iCol), nbuf, sizeof(nbuf));
  1776   1777           Jsi_DSAppend(dStr, nbuf, NULL);
  1777   1778           return;
  1778   1779       }
  1779   1780       case SQLITE_NULL: {
  1780   1781           return;
  1781   1782       }
  1782   1783       }

Changes to src/jsiStubs.h.

     1      1   #ifndef __JSI_STUBS_H__
     2      2   #define __JSI_STUBS_H__
     3      3   #include "jsi.h"
     4      4   
     5         -#define JSI_STUBS_MD5 "cdb9ad7386a9d0519e79e25db2f53698"
            5  +#define JSI_STUBS_MD5 "bd4e55a8383c3598c0344241217a1d53"
     6      6   
     7      7   #undef JSI_EXTENSION_INI
     8      8   #define JSI_EXTENSION_INI Jsi_Stubs *jsiStubsPtr = NULL;
     9      9   
    10     10   #ifdef JSI__MUSL
    11     11   #define JSI_STUBS_BLDFLAGS 1
    12     12   #else
................................................................................
   203    203       Jsi_Value*(*_Jsi_ValueDupJSON)(Jsi_Interp *interp, Jsi_Value *val);
   204    204       void(*_Jsi_ValueMove)(Jsi_Interp *interp, Jsi_Value *to, Jsi_Value *from);
   205    205       bool (*_Jsi_ValueIsEqual)(Jsi_Interp *interp, Jsi_Value *v1, Jsi_Value* v2);
   206    206       Jsi_Hash*(*_Jsi_UserObjRegister)(Jsi_Interp *interp, Jsi_UserObjReg *reg);
   207    207       Jsi_RC(*_Jsi_UserObjUnregister)(Jsi_Interp *interp, Jsi_UserObjReg *reg);
   208    208       int(*_Jsi_UserObjNew)(Jsi_Interp *interp, Jsi_UserObjReg* reg, Jsi_Obj *obj, void *data);
   209    209       void*(*_Jsi_UserObjGetData)(Jsi_Interp *interp, Jsi_Value* value, Jsi_Func *funcPtr);
   210         -    char*(*_Jsi_NumberToString)(Jsi_Number d, char *buf, int bsiz);
          210  +    char*(*_Jsi_NumberToString)(Jsi_Interp *interp, Jsi_Number d, char *buf, int bsiz);
   211    211       Jsi_Number(*_Jsi_Version)(void);
   212    212       Jsi_Value*(*_Jsi_ReturnValue)(Jsi_Interp *interp);
   213    213       Jsi_RC(*_Jsi_Mount)( Jsi_Interp *interp, Jsi_Value *archive, Jsi_Value *mount, Jsi_Value **ret);
   214    214       Jsi_Value*(*_Jsi_Executable)(Jsi_Interp *interp);
   215    215       Jsi_Regex*(*_Jsi_RegExpNew)(Jsi_Interp *interp, const char *regtxt, int flag);
   216    216       void(*_Jsi_RegExpFree)(Jsi_Regex* re);
   217    217       Jsi_RC(*_Jsi_RegExpMatch)( Jsi_Interp *interp,  Jsi_Value *pattern, const char *str, int *rc, Jsi_DString *dStr);
................................................................................
   266    266       bool(*_Jsi_NumberIsInteger)(Jsi_Number n);
   267    267       bool(*_Jsi_NumberIsNaN)(Jsi_Number a);
   268    268       bool(*_Jsi_NumberIsNormal)(Jsi_Number a);
   269    269       bool(*_Jsi_NumberIsSubnormal)(Jsi_Number a);
   270    270       bool(*_Jsi_NumberIsWide)(Jsi_Number n);
   271    271       Jsi_Number(*_Jsi_NumberInfinity)(int i);
   272    272       Jsi_Number(*_Jsi_NumberNaN)(void);
   273         -    void(*_Jsi_NumberDtoA)(Jsi_Number value, char* buf, int bsiz, int prec);
          273  +    void(*_Jsi_NumberDtoA)(Jsi_Interp *interp, Jsi_Number value, char* buf, int bsiz, int prec);
   274    274       void(*_Jsi_NumberItoA10)(Jsi_Wide value, char* buf, int bsiz);
   275    275       void(*_Jsi_NumberUtoA10)(Jsi_UWide, char* buf, int bsiz);
   276    276       Jsi_Hash*(*_Jsi_HashNew)(Jsi_Interp *interp, uint keyType, Jsi_HashDeleteProc *freeProc);
   277    277       Jsi_RC(*_Jsi_HashConf)(Jsi_Hash *hashPtr, Jsi_MapOpts *opts, bool set);
   278    278       void(*_Jsi_HashDelete)(Jsi_Hash *hashPtr);
   279    279       void(*_Jsi_HashClear)(Jsi_Hash *hashPtr);
   280    280       Jsi_HashEntry*(*_Jsi_HashSet)(Jsi_Hash *hashPtr, const void *key, void *value);
................................................................................
  1029   1029   #define Jsi_ValueDupJSON(n0,n1) JSISTUBCALL(jsiStubsPtr, _Jsi_ValueDupJSON(n0,n1))
  1030   1030   #define Jsi_ValueMove(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_ValueMove(n0,n1,n2))
  1031   1031   #define Jsi_ValueIsEqual(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_ValueIsEqual(n0,n1,n2))
  1032   1032   #define Jsi_UserObjRegister(n0,n1) JSISTUBCALL(jsiStubsPtr, _Jsi_UserObjRegister(n0,n1))
  1033   1033   #define Jsi_UserObjUnregister(n0,n1) JSISTUBCALL(jsiStubsPtr, _Jsi_UserObjUnregister(n0,n1))
  1034   1034   #define Jsi_UserObjNew(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_UserObjNew(n0,n1,n2,n3))
  1035   1035   #define Jsi_UserObjGetData(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_UserObjGetData(n0,n1,n2))
  1036         -#define Jsi_NumberToString(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberToString(n0,n1,n2))
         1036  +#define Jsi_NumberToString(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberToString(n0,n1,n2,n3))
  1037   1037   #define Jsi_Version(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_Version(n0))
  1038   1038   #define Jsi_ReturnValue(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_ReturnValue(n0))
  1039   1039   #define Jsi_Mount(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_Mount(n0,n1,n2,n3))
  1040   1040   #define Jsi_Executable(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_Executable(n0))
  1041   1041   #define Jsi_RegExpNew(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpNew(n0,n1,n2))
  1042   1042   #define Jsi_RegExpFree(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpFree(n0))
  1043   1043   #define Jsi_RegExpMatch(n0,n1,n2,n3,n4) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpMatch(n0,n1,n2,n3,n4))
................................................................................
  1092   1092   #define Jsi_NumberIsInteger(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberIsInteger(n0))
  1093   1093   #define Jsi_NumberIsNaN(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberIsNaN(n0))
  1094   1094   #define Jsi_NumberIsNormal(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberIsNormal(n0))
  1095   1095   #define Jsi_NumberIsSubnormal(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberIsSubnormal(n0))
  1096   1096   #define Jsi_NumberIsWide(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberIsWide(n0))
  1097   1097   #define Jsi_NumberInfinity(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberInfinity(n0))
  1098   1098   #define Jsi_NumberNaN(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberNaN(n0))
  1099         -#define Jsi_NumberDtoA(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberDtoA(n0,n1,n2,n3))
         1099  +#define Jsi_NumberDtoA(n0,n1,n2,n3,n4) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberDtoA(n0,n1,n2,n3,n4))
  1100   1100   #define Jsi_NumberItoA10(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberItoA10(n0,n1,n2))
  1101   1101   #define Jsi_NumberUtoA10(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_NumberUtoA10(n0,n1,n2))
  1102   1102   #define Jsi_HashNew(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_HashNew(n0,n1,n2))
  1103   1103   #define Jsi_HashConf(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_HashConf(n0,n1,n2))
  1104   1104   #define Jsi_HashDelete(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_HashDelete(n0))
  1105   1105   #define Jsi_HashClear(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_HashClear(n0))
  1106   1106   #define Jsi_HashSet(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_HashSet(n0,n1,n2))

Changes to src/jsiUtils.c.

   496    496       Jsi_DSAppend(dStr, ":", NULL);
   497    497       ow->depth++;
   498    498       Jsi_RC rc = jsiValueGetString(tree->opts.interp, v, dStr, ow);
   499    499       ow->depth--;
   500    500       return rc;
   501    501   }
   502    502   
   503         -#include <float.h>
   504         -
   505    503   /* Format value into dStr.  Toplevel caller does init/free. */
   506    504   static Jsi_RC jsiValueGetString(Jsi_Interp *interp, Jsi_Value* v, Jsi_DString *dStr, objwalker *owPtr)
   507    505   {
   508    506       char buf[100], *str;
   509    507       Jsi_DString eStr;
   510    508       Jsi_DSInit(&eStr);
   511    509       if (interp->maxDepth>0 && owPtr->depth > interp->maxDepth)
................................................................................
   534    532               } else if (Jsi_NumberIsInteger(num)) {
   535    533                   Jsi_NumberItoA10((Jsi_Wide)num, buf, sizeof(buf));
   536    534                   Jsi_DSAppend(dStr, buf, NULL);
   537    535               } else if (Jsi_NumberIsWide(num)) {
   538    536                   snprintf(buf, sizeof(buf), "%" PRId64, (Jsi_Wide)num);
   539    537                   Jsi_DSAppend(dStr, buf, NULL);
   540    538               } else if (Jsi_NumberIsNormal(num) || Jsi_NumberIsSubnormal(num)) {
   541         -                Jsi_NumberDtoA(num, buf, sizeof(buf), -1);
          539  +                Jsi_NumberDtoA(interp, num, buf, sizeof(buf), 0);
   542    540                   Jsi_DSAppend(dStr, buf, NULL);
   543    541               } else if (Jsi_NumberIsNaN(num)) {
   544    542                   Jsi_DSAppend(dStr, "NaN", NULL);
   545    543               } else {
   546    544                   int s = Jsi_NumberIsInfinity(num);
   547    545                   if (s > 0) Jsi_DSAppend(dStr, "+Infinity", NULL);
   548    546                   else if (s < 0) Jsi_DSAppend(dStr, "-Infinity", NULL);
................................................................................
  1022   1020       if (hist) {
  1023   1021           jsi_sh_stifle_history(100);
  1024   1022           jsi_sh_write_history(hist);
  1025   1023       }
  1026   1024       Jsi_DSFree(&dHist);
  1027   1025   #endif
  1028   1026       Jsi_DSFree(&dStr);
         1027  +    if (interp->retValue) {
         1028  +        Jsi_DecrRefCount(interp, interp->retValue);
         1029  +        interp->retValue = NULL;
         1030  +    }
  1029   1031       if (interp->exited && interp->level <= 0)
  1030   1032       {
  1031   1033           rc = JSI_EXIT;
  1032   1034           Jsi_InterpDelete(interp);
  1033   1035       }
  1034   1036       jsi_interactiveInterp = NULL;
  1035   1037       return rc;

Changes to src/jsiValue.c.

   454    454       if (otype != JSI_OT_ARRAY)
   455    455           return (v->d.obj->ot == otype);
   456    456       if (v->d.obj->ot != JSI_OT_OBJECT || !v->d.obj->isarrlist)
   457    457           return 0;
   458    458       return 1;
   459    459   }
   460    460   
   461         -char* Jsi_NumberToString(Jsi_Number d, char *buf, int bsiz)
          461  +char* Jsi_NumberToString(Jsi_Interp *interp, Jsi_Number d, char *buf, int bsiz)
   462    462   {
   463    463        if (Jsi_NumberIsInteger(d)) {
   464    464           Jsi_NumberItoA10((Jsi_Wide)d, buf, bsiz);
   465    465       } else if (Jsi_NumberIsNormal(d)) {
   466         -        Jsi_NumberDtoA(d, buf, bsiz, 10);
          466  +        Jsi_NumberDtoA(interp, d, buf, bsiz, 0);
   467    467       } else if (Jsi_NumberIsNaN(d)) {
   468    468           Jsi_Strcpy(buf, "NaN");
   469    469       } else {
   470    470           int s = Jsi_NumberIsInfinity(d);
   471    471           if (s > 0) Jsi_Strcpy(buf,  "Infinity");
   472    472           else if (s < 0) Jsi_Strcpy(buf, "-Infinity");
   473    473           else {
................................................................................
   505    505               d = v->d.num;
   506    506   fmtnum:
   507    507               if (Jsi_NumberIsInteger(d)) {
   508    508                   Jsi_NumberItoA10((Jsi_Wide)d, unibuf, sizeof(unibuf));
   509    509                   kflag = 0;
   510    510                   ntxt = unibuf;
   511    511               } else if (Jsi_NumberIsNormal(d)) {
   512         -                Jsi_NumberDtoA(d, unibuf, sizeof(unibuf), 10);
          512  +                Jsi_NumberDtoA(interp, d, unibuf, sizeof(unibuf), 0);
   513    513                   kflag = 0;
   514    514                   ntxt = unibuf;
   515    515               } else if (Jsi_NumberIsNaN(v->d.num)) {
   516    516                   ntxt = "NaN";
   517    517               } else {
   518    518                   int s = Jsi_NumberIsInfinity(d);
   519    519                   if (s > 0) ntxt = "Infinity";

Changes to tests/math.jsi.

    46     46   Number.toPrecision(9.1234,2) ==> 9.1
    47     47   Number.toExponential(9.1234,2) ==> 9.12e+00
    48     48   Number.toFixed(9.1234,2) ==> 9.12
    49     49   j = new Number(9.1234) ==> 9.1234
    50     50   j.toPrecision(2) ==> 9.1
    51     51   j.toExponential(2) ==> 9.12e+00
    52     52   j.toFixed(2) ==> 9.12
    53         -Math.tan(9) ==> -0.452316
           53  +Math.tan(9) ==> -0.4523156594418098
    54     54   Number.toPrecision(k,2) ==> -0.4
    55     55   Number.toPrecision(Math.tan(9),2) ==> -0.4
    56     56   Number.toExponential(k,2) ==> -4.52e-01
    57     57   Number.toFixed(k,2) ==> -0.45
    58     58   Math.abs(-1) ==> 1
    59     59   Math.acos(1) ==> 0
    60         -Math.asin(1) ==> 1.5708
    61         -Math.atan(1) ==> 0.785398
    62         -Math.atan2(0.4,5) ==> 0.07983
    63         -Math.cos(1) ==> 0.540302
    64         -Math.sin(1) ==> 0.841471
    65         -Math.exp(2) ==> 7.38906
           60  +Math.asin(1) ==> 1.570796326794897
           61  +Math.atan(1) ==> 0.7853981633974483
           62  +Math.atan2(0.4,5) ==> 0.07982998571223732
           63  +Math.cos(1) ==> 0.5403023058681398
           64  +Math.sin(1) ==> 0.8414709848078965
           65  +Math.exp(2) ==> 7.38905609893065
    66     66   Math.ceil(5.33) ==> 6
    67     67   Math.floor(5.33) ==> 5
    68         -Math.log(5.33) ==> 1.67335
           68  +Math.log(5.33) ==> 1.673351238177753
    69     69   Math.max(1,2,3) ==> 3
    70     70   Math.min(1,2,3) ==> 1
    71     71   Math.pow(2,3) ==> 8
    72     72   Math.round(5.33) ==> 5
    73         -Math.sqrt(5.33) ==> 2.30868
           73  +Math.sqrt(5.33) ==> 2.308679276123039
    74     74   1/0 ==> +Infinity
    75     75   -1/0 ==> -Infinity
    76     76   x = Math.pow(2,6) ==> 64
    77     77   x.toString(16) ==> 40
    78     78   x.toString(10) ==> 64
    79     79   x.toString(8) ==> 100
    80     80   x.toString(2) ==> 64
    81     81   =!EXPECTEND!=
    82     82   */

Changes to tests/time.jsi.

    48     48   t = strptime(s, {utc:true, fmt:'%Y-%m-%d %H:%M:%S'}) ==> 0
    49     49   t = strptime('1970-01-01 10:00:00', {utc:true}) ==> 36000000
    50     50   s = strftime(t, {utc:true}) ==> 1970-01-01 10:00:00
    51     51   '
    52     52   ===Use of seconds vs ms==='
    53     53   t = strptime('2010-01-01 10:00:00.123', {utc:true}) ==> 1262340000123
    54     54   s = strftime(t, {utc:true}) ==> 2010-01-01 10:00:00
    55         -t/1000 ==> 1.26234e+09
           55  +t/1000 ==> 1262340000.123
    56     56   Math.floor(t/1000) ==> 1262340000
    57     57   '
    58     58   ===Coerce to seconds==='
    59     59   t = strptime('2010-01-01 10:00:00.123', {utc:true, secs:true}) ==> 1262340000
    60     60   s = strftime(t, {utc:true, secs:true}) ==> 2010-01-01 10:00:00
    61     61   '
    62     62   ===Now and future dates==='
    63     63   strptime('1970-01-01 10:00:00')-ofs ==> 36000000
    64     64   strftime(ofs) ==> 1970-01-01 00:00:00
    65     65   n=strptime('2020-03-04 12:34:56.123')-ofs ==> 1583325296123
    66     66   strftime(n, {utc:true, fmt:'%Y-%m-%d %H:%M:%S.%f'}) ==> 2020-03-04 12:34:56.123
    67     67   =!EXPECTEND!=
    68     68   */

Changes to tools/protos.jsi.

     1         -//JSI Command Prototypes: version 2.5.19
            1  +//JSI Command Prototypes: version 2.5.20
     2      2   throw("NOT EXECUTABLE: USE FILE IN GEANY EDITOR FOR CMD LINE COMPLETION + GOTO TAG");
     3      3   
     4      4   var Array = function(cmd,args) {};
     5      5   Array.prototype.concat = function(...):array {};
     6      6   Array.prototype.every = function(callback:function):any {};
     7      7   Array.prototype.fill = function(value:any, start:number=0, end:number=-1):array {};
     8      8   Array.prototype.filter = function(callback:function, this:object=void):array {};

Changes to www/reference.wiki.

   702    702   
   703    703   <a name="subOptsOptions"></a>
   704    704   <h2>Options for "subOpts"</h2>
   705    705   <table border="1" class="optstbl table">
   706    706   <tr><th>Option</th> <th>Type</th> <th>Description</th><th>Flags</th></tr>
   707    707   <tr><td>blacklist</td><td><i>STRKEY</i></td><td>Comma separated modules to disable loading for.</td><td><i>initOnly</i></td></tr>
   708    708   <tr><td>compat</td><td><i>BOOL</i></td><td>Ignore unknown options via JSI_OPTS_IGNORE_EXTRA in option parser.</td><td><i></i></td></tr>
          709  +<tr><td>dblPrec</td><td><i>INT</i></td><td>Format precision of double (-1): 0=max, -1=max-1, ...</td><td><i>initOnly</i></td></tr>
   709    710   <tr><td>istty</td><td><i>BOOL</i></td><td>Indicates interp is in interactive mode.</td><td><i>readOnly</i></td></tr>
   710    711   <tr><td>logColNums</td><td><i>BOOL</i></td><td>Display column numbers in error messages.</td><td><i></i></td></tr>
   711    712   <tr><td>logAllowDups</td><td><i>BOOL</i></td><td>Log should not filter out duplicate messages.</td><td><i></i></td></tr>
   712    713   <tr><td>mutexUnlock</td><td><i>BOOL</i></td><td>Unlock own mutex when evaling in other interps (true).</td><td><i>initOnly</i></td></tr>
   713    714   <tr><td>noproto</td><td><i>BOOL</i></td><td>Disable support of the OOP symbols:  __proto__, prototype, constructor, etc.</td><td><i></i></td></tr>
   714    715   <tr><td>noReadline</td><td><i>BOOL</i></td><td>In interactive mode disable use of readline.</td><td><i></i></td></tr>
   715    716   <tr><td>outUndef</td><td><i>BOOL</i></td><td>In interactive mode output result values that are undefined.</td><td><i></i></td></tr>