/ Check-in [1cd1d600a3]
DEMO | DOWNLOAD | DEPLOY | SEARCH
Login

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

Overview
Comment:Release "2.5.22". To exec add "chdir" option.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:1cd1d600a3cd869140851150106b8ecad1aacc3b
User & Date: pmacdona 2018-10-17 01:36:00
Context
2018-10-18
23:00
Release "2.5.23". Fix new RegExp arg 2 bug. Expand module -m to support templates. Fix File.chmod bug. Add SqliteUI -dump option. check-in: 81b5253abf user: pmacdona tags: trunk
2018-10-17
01:36
Release "2.5.22". To exec add "chdir" option. check-in: 1cd1d600a3 user: pmacdona tags: trunk
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
Changes

Changes to lib/Jsi_SqliteUI/Jsi_SqliteUI.jsi.

47
48
49
50
51
52
53
54
55

56
57
58
59
60
61


62
63
64
65
66
67
68
69
            "CREATE TABLE IF NOT EXISTS dbfiles (file);" +
            "CREATE TABLE IF NOT EXISTS saved_queries (query NOT NULL, dbID NOT NULL);" +
            "CREATE UNIQUE INDEX IF NOT EXISTS savedq_idx ON saved_queries(query, dbID);"
    };
    
    parseOpts(self, options, conf);

    function DumpSql(files) {
        var rv = 'PRAGMA foreign_keys=OFF;\nBEGIN TRANSACTION;\n';

        for (var fn of files) {
            var re = '', db = new Sqlite(fn);
            for (var i of db.query("SELECT name, type, sql FROM sqlite_master WHERE sql NOT NULL")) {
                if (i.name.match(/^sqlite_/)) continue;
                switch (i.type) {
                    case 'table':


                        rv += i.sql + ';\n' + db.query('SELECT * FROM '+i.name, {mode:'insert', table:i.name});
                        break;
                    case 'index': case 'trigger': case 'view':
                        re += i.sql+';\n';
                }
            }
            rv += re;
        }







|

>






>
>
|







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
            "CREATE TABLE IF NOT EXISTS dbfiles (file);" +
            "CREATE TABLE IF NOT EXISTS saved_queries (query NOT NULL, dbID NOT NULL);" +
            "CREATE UNIQUE INDEX IF NOT EXISTS savedq_idx ON saved_queries(query, dbID);"
    };
    
    parseOpts(self, options, conf);

    function DumpSql(files:string|array, skipTbls:array=void) {
        var rv = 'PRAGMA foreign_keys=OFF;\nBEGIN TRANSACTION;\n';
        if (typeof files === 'string') files = [files];
        for (var fn of files) {
            var re = '', db = new Sqlite(fn);
            for (var i of db.query("SELECT name, type, sql FROM sqlite_master WHERE sql NOT NULL")) {
                if (i.name.match(/^sqlite_/)) continue;
                switch (i.type) {
                    case 'table':
                        rv += i.sql + ';\n';
                        if (skipTbls && skipTbls.indexOf(i.name)>=0) continue;
                        rv += db.query('SELECT * FROM '+i.name, {mode:'insert', table:i.name});
                        break;
                    case 'index': case 'trigger': case 'view':
                        re += i.sql+';\n';
                }
            }
            rv += re;
        }

Changes to src/jsi.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.....
18481
18482
18483
18484
18485
18486
18487
18488
18489
18490
18491
18492
18493
18494
18495
.....
19104
19105
19106
19107
19108
19109
19110
19111
19112
19113
19114
19115
19116
19117
19118
.....
19119
19120
19121
19122
19123
19124
19125

19126
19127
19128
19129
19130
19131
19132
19133
19134
.....
19148
19149
19150
19151
19152
19153
19154
19155
19156
19157


19158
19159
19160
19161
19162
19163
19164
.....
19185
19186
19187
19188
19189
19190
19191
19192
19193
19194
19195
19196
19197
19198
19199
.....
19446
19447
19448
19449
19450
19451
19452
19453
19454
19455
19456
19457
19458
19459
19460
.....
29403
29404
29405
29406
29407
29408
29409
29410
29411
29412
29413
29414
29415
29416
29417
.....
33428
33429
33430
33431
33432
33433
33434

33435
33436
33437
33438
33439
33440
33441
33442
33443
33444
33445

33446
33447
33448
33449
33450
33451
33452
.....
33482
33483
33484
33485
33486
33487
33488

33489
33490
33491
33492
33493
33494
33495
.....
33509
33510
33511
33512
33513
33514
33515














33516
33517
33518
33519
33520
33521
33522
.....
33579
33580
33581
33582
33583
33584
33585







33586
33587
33588
33589
33590
33591
33592
.....
48449
48450
48451
48452
48453
48454
48455
48456
48457
48458
48459
48460
48461
48462
48463
48464
48465
48466
48467
48468
48469
48470
48471
48472
48473
48474
48475
48476
48477
.....
48482
48483
48484
48485
48486
48487
48488
48489
48490
48491
48492
48493
48494
48495
48496
.....
54766
54767
54768
54769
54770
54771
54772
54773
54774
54775
54776
54777
54778
54779
54780
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   5
#define JSI_VERSION_RELEASE 20

#define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))

#ifndef JSI_EXTERN
#define JSI_EXTERN extern
#endif

................................................................................
    JSI_OPT(STRKEY, jsi_LogOptions, timeFmt, .help="A format string to use with strftime" ),
    JSI_OPT(USEROBJ,jsi_LogOptions, chan,    .help="Channel to send output to", .flags=0, .custom=0, .data=(void*)"Channel" ),
    JSI_OPT_END(jsi_LogOptions, .help="Interp options for logging")
};
static Jsi_OptionSpec InterpSubOptions[] = {
    JSI_OPT(STRKEY,jsi_SubOptions, blacklist,   .help="Comma separated modules to disable loading for", jsi_IIOF ),
    JSI_OPT(BOOL,  jsi_SubOptions, compat,      .help="Ignore unknown options via JSI_OPTS_IGNORE_EXTRA in option parser" ),
    JSI_OPT(INT,   jsi_SubOptions, dblPrec,     .help="Format precision of double (-1): 0=max, -1=max-1, ..", jsi_IIOF),
    JSI_OPT(BOOL,  jsi_SubOptions, istty,       .help="Indicates interp is in interactive mode", jsi_IIRO),
    JSI_OPT(BOOL,  jsi_SubOptions, logColNums,  .help="Display column numbers in error messages"),
    JSI_OPT(BOOL,  jsi_SubOptions, logAllowDups,.help="Log should not filter out duplicate messages"),
    JSI_OPT(BOOL,  jsi_SubOptions, mutexUnlock, .help="Unlock own mutex when evaling in other interps (true)", jsi_IIOF),
    JSI_OPT(BOOL,  jsi_SubOptions, noproto,     .help="Disable support of the OOP symbols:  __proto__, prototype, constructor, etc"),
    JSI_OPT(BOOL,  jsi_SubOptions, noReadline,  .help="In interactive mode disable use of readline" ),
    JSI_OPT(BOOL,  jsi_SubOptions, outUndef,     .help="In interactive mode output result values that are undefined"),
................................................................................
        if (interp->opts.no_interactive)
            return interp;
        rc = Jsi_Interactive(interp, JSI_OUTPUT_QUOTE|JSI_OUTPUT_NEWLINES);
    } else {
        if (argc == 2 && !Jsi_Strcmp(argv[1], "-h" )) {
            puts("usage: jsish -h/--help | -v/--version | -d/--debug | -D/--debugui | -u/--unittest | -U/-UU\n\t"
            "| -s/--safe | -Z/--zip | -S/--sqliteui | -w/--wget | -W/--websrv | -H/--htmli | -J/--jsi\n\t"
            "| -C/--cssi | -c/--cdata | -M/--module | -m/--make | -e/--eval | -t/--tracecall\n\t"
            "| -a/--archive | -T/--typecheck OPT | -IOPT VAL | FILE arg arg ...\nUse --help for long help.");
            return jsi_DoExit(interp, 1);
        }
        if (argc == 2 && !Jsi_Strcmp(argv[1], "--help")) {
            puts("jsish arguments:\n"
              "  -a/--archive FILE\tMount an archive (zip, sqlar or fossil repo) and run module.\n"
              "  -c/--cdata FILE\tGenerate .c or JSON output from a .jsc description.\n"
................................................................................
              "  -C/--cssi FILE\tPreprocess embedded CSS in .css file.\n"
              "  -d/--debug FILE\tRun console debugger on script.\n"
              "  -D/--debugui FILE\tRun web-gui debugger on script.\n"
              "  -e/--eval STRING\tEvaluate a javascript string and exit.\n"
              "  -h/--help\t\tPrint help in short or long form.\n"
              "  -H/--htmli FILE\tPreprocess embedded jsi in .htmli file.\n"
              "  -J/--jsi FILE\t\tPreprocess a .jsi file to typecheck in standard javascript.\n"

              "  -m/--make FILE\tPreprocess script as a Jsi Makefile.\n"
              "  -M/--module NAME\tInvoke module using runModule(NAME) (eg. from the /zvfs directory).\n"
              "  -s/--safe FILE\tRun script in safe sub-interp.\n"
              "  -S/--sqliteui DBFILE\tRun Sqlite web-gui.\n"
              "  -t/--tracecall\tTrace all function calls.\n"
              "  -T/--typecheck OPT\tEnable typechecking.\n"
              "  -u/--unittest FILE\tRun unit-tests on a script file, or a dir containing .js/.jsi files.\n"
              "  -U/-UU SCRIPT\t\tShow output from unit-test mode, omitting pass/fail compare.\n"
              "  -v/--version\t\tPrint short/long version info and exit.\n"
................................................................................
            printf("%u.%u.%u %.4" JSI_NUMGFMT " %s", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE, Jsi_Version(), str);
            return jsi_DoExit(interp, 1);
        }
        if (argc == 2 && !Jsi_Strcmp(argv[1], "-v" )) {
            printf("%u.%u.%u\n", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE);
            return jsi_DoExit(interp, 1);
        }
        if (argc > 2 && (Jsi_Strcmp(argv[1], "--module")==0 || Jsi_Strcmp(argv[1], "-M" )==0)) {
            Jsi_DString dStr = {};
            Jsi_DSAppend(&dStr, "runModule(\"", argv[2], "\",console.args.slice(1));", NULL);


            rc = Jsi_EvalString(interp, Jsi_DSValue(&dStr), JSI_EVAL_NOSKIPBANG);
            Jsi_DSFree(&dStr);
        }
        else if (argc == 3 && (Jsi_Strcmp(argv[1], "--eval")==0 || Jsi_Strcmp(argv[1], "-e" )==0))
            rc = Jsi_EvalString(interp, argv[2], JSI_EVAL_NOSKIPBANG);

        else if (interp->selfZvfs && argc > 1 && (Jsi_Strcmp(argv[1], "--debug")==0 || Jsi_Strcmp(argv[1], "-d" )==0)) {
................................................................................
            rc = Jsi_EvalString(interp, "runModule('Jsi_Csspp');", JSI_EVAL_ISMAIN);
        else if (interp->selfZvfs && argc > 1 && (Jsi_Strcmp(argv[1], "--jsi")==0 || Jsi_Strcmp(argv[1], "-J" )==0))
            rc = Jsi_EvalString(interp, "runModule('Jsi_Jspp');", JSI_EVAL_ISMAIN);
        else if (interp->selfZvfs && argc > 1 && (Jsi_Strcmp(argv[1], "--htmli")==0 || Jsi_Strcmp(argv[1], "-H" )==0))
            rc = Jsi_EvalString(interp, "runModule('Jsi_Htmlpp');", JSI_EVAL_ISMAIN);
        else if (interp->selfZvfs && argc > 1 && (Jsi_Strcmp(argv[1], "--unittest")==0 || Jsi_Strcmp(argv[1], "-u" )==0))
            rc = Jsi_EvalString(interp, "exit(runModule('Jsi_UnitTest'));", JSI_EVAL_ISMAIN);
        else if (interp->selfZvfs && argc > 1 && (Jsi_Strcmp(argv[1], "--make")==0 || Jsi_Strcmp(argv[1], "-m" )==0))
            rc = Jsi_EvalString(interp, "exit(runModule('Jsi_Make'));", JSI_EVAL_ISMAIN);
        else {
            int iocnt;
            for (iocnt = 1; (iocnt+1)<argc; iocnt+=2) {
                if (Jsi_Strcmp(argv[iocnt], "-t") == 0 || Jsi_Strcmp(argv[iocnt], "--tracecall") == 0) {iocnt--; continue; }
                if (Jsi_Strcmp(argv[iocnt], "-T") == 0 || Jsi_Strcmp(argv[iocnt], "--typecheck") == 0) {continue; }
                if (Jsi_Strcmp(argv[iocnt], "-U") == 0) {iocnt--; continue; }
................................................................................
            Jsi_LogError("exceeded max subinterp depth");
            return NULL;
        }
    }
    interp->maxDepth = JSI_MAX_EVAL_DEPTH;
    interp->maxIncDepth = JSI_MAX_INCLUDE_DEPTH;
    interp->typeWarnMax = 50;
    interp->subOpts.dblPrec = -1;

    int iocnt;
    if (iopts) {
        iopts->interp = interp;
        interp->opts = *iopts;
    }
    interp->logOpts.file = 1;
................................................................................
    {_JSI_OPNM(TIME_W),  .cName="time_w",   .size=sizeof(time_w),     .fmt=PRId64, .xfmt="#" PRIx64,   .sfmt=SCNd64, .help="A time value in milliseconds stored as a 64 bit integer" },
    {_JSI_OPNM(TIME_D),  .cName="time_d",   .size=sizeof(time_d),     .fmt="g",    .xfmt="#" "g",      .sfmt="g", .help="A time value in milliseconds stored as a double" },
    {_JSI_OPNM(TIME_T),  .cName="time_t",   .size=sizeof(time_t),     .fmt="ld",   .xfmt="#lx",  .sfmt="ld", .help="A time value stored in a unix time_t" },
    {_JSI_OPNM(SIZE_T),  .cName="size_t",   .size=sizeof(size_t),     .fmt="zd",   .xfmt="#zx",  .sfmt="z", .help="Size unsigned" },
    {_JSI_OPNM(SSIZE_T), .cName="ssize_t",  .size=sizeof(ssize_t),    .fmt="zu",   .xfmt="#zx",  .sfmt="zu", .help="Size integer" },
    {_JSI_OPNM(INTPTR_T),.cName="intptr_t", .size=sizeof(intptr_t),   .fmt="d",    .xfmt="#x",   .sfmt="d", .help="Integer large enough to store pointer" },
    {_JSI_OPNM(UINTPTR_T),.cName="uintptr_t",.size=sizeof(uintptr_t), .fmt="u",    .xfmt="#x",   .sfmt="u", .help="Unsigned large enough to store pointer" },
    {_JSI_OPNM(NUMBER),   .cName="Jsi_Number",.size=sizeof(Jsi_Number),.fmt=JSI_NUMGFMT, .xfmt="#" JSI_NUMGFMT,   .sfmt=JSI_NUMGFMT, .help="Double or long double" },
    {_JSI_OPNM(INT),     .cName="int",      .size=sizeof(int),        .fmt="d",    .xfmt="#x",   .sfmt="d", .help="Integer" },
    {_JSI_OPNM(UINT),    .cName="uint",     .size=sizeof(uint),       .fmt="u",    .xfmt="#x",   .sfmt="u", .help="Unsigned" },
    {_JSI_OPNM(LONG),    .cName="long",     .size=sizeof(long),       .fmt="ld",   .xfmt="#lx",  .sfmt="ld", .help="Long" },
    {_JSI_OPNM(ULONG),   .cName="ulong",    .size=sizeof(ulong),      .fmt="lu",   .xfmt="#lx",  .sfmt="lu", .help="Unsigned long" },
    {_JSI_OPNM(SHORT),   .cName="short",    .size=sizeof(short),      .fmt="hd",   .xfmt="#hx",  .sfmt="hd", .help="Short" },
    {_JSI_OPNM(USHORT),  .cName="ushort",   .size=sizeof(ushort),     .fmt="hu",   .xfmt="#hx",  .sfmt="hu", .help="Unsigned short" },
    {_JSI_OPNM(STRING),  .cName="Jsi_Value*",.size=sizeof(Jsi_Value*),.fmt="s",    .xfmt="s", .sfmt=0, .help="A string Value"},
................................................................................
    Jsi_ValueMakeNumber(interp, ret, pid);
    return JSI_OK;
#endif
}

typedef struct {
    Jsi_Value* inputStr;

    bool bg;
    bool noError;
    bool trim;
    bool retCode;
    bool retAll;
    bool retval;
    bool noRedir;
} ExecOpts;

static Jsi_OptionSpec ExecOptions[] = {
    JSI_OPT(BOOL,   ExecOpts, bg,       .help="Run command in background using system() and return OS code" ),

    JSI_OPT(STRING, ExecOpts, inputStr, .help="Use string as input and return OS code" ),
    JSI_OPT(BOOL,   ExecOpts, noError,  .help="Suppress all OS errors" ),
    JSI_OPT(BOOL,   ExecOpts, noRedir,  .help="Disable redirect and shell escapes in command" ),
    JSI_OPT(BOOL,   ExecOpts, trim,     .help="Trim trailing whitespace from output" ),
    JSI_OPT(BOOL,   ExecOpts, retAll,   .help="Return the OS return code and data as an object" ),
    JSI_OPT(BOOL,   ExecOpts, retCode,  .help="Return only the OS return code" ),
    JSI_OPT_END(ExecOpts, .help="Exec options")
................................................................................
        }
        if (no)
            return Jsi_LogError("no exec in safe mode");
    }
    Jsi_RC rc = JSI_OK;
    Jsi_Value *opt = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_DString dStr = {};

    ExecOpts edata = {};
    edata.retval = 1;
    
    if (opt != NULL) {
        if (opt->vt == JSI_VT_OBJECT && opt->d.obj->ot == JSI_OT_OBJECT) {
            hasopts = 1;
            if (Jsi_OptionsProcess(interp, ExecOptions, &edata, opt, 0) < 0) {
................................................................................
            if (*cp2 != '>' && *cp2 != '<' &&*cp2 != '|' &&*cp2 != ';' && *cp2 != '&' && *cp2 != '$' && *cp2 != '`' && *cp2 != '=')
                cp2++;
            else 
                return Jsi_LogError("restricted exec at char '%c' in string: %s", *cp2, cp);
        }
    }
    int isbg = 0, ec = 0;














    if (edata.bg || (isbg=((sLen>1 && cp[sLen-1] == '&')))) {
        if (edata.inputStr) {
            rc = Jsi_LogError("inputStr can not used with bg");
            goto done;
        }
        if (!isbg) {
            Jsi_DSAppend(&dStr, cp, " &", NULL);
................................................................................
    } else if (edata.retval)
        Jsi_ValueFromDS(interp, &dStr, ret);
    else {
        Jsi_DSFree(&dStr);
        Jsi_ValueMakeNumber(interp, ret, (Jsi_Number)exitCode);
    }
done:







    if (hasopts)
        Jsi_OptionsFree(interp, ExecOptions, &edata, 0);
    return rc;
}

static Jsi_RC SysExecCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
................................................................................
    
    case _JSI_EF_INSERT: {
        Jsi_DString vStr = {};    
        while( JSI_OK==(rc = dbEvalStep(&sEval)) ) {
            int i;
            int nCol;
            const char *tbl = (opts.table ? opts.table : "table");
            if (cnt)
                Jsi_DSAppend(dStr, "\n", NULL);
            Jsi_DSAppend(dStr, "INSERT INTO ", tbl, " VALUES(", NULL);
            dbEvalRowInfo(&sEval, &nCol, &apColName, &apColType);
            for(i=0; i<nCol; i++) {
                Jsi_Number dv;
                const char *azArg;
                Jsi_DSSetLength(&vStr, 0);
                dbEvalSetColumn(&sEval, i, &vStr);
                sqlite3_stmt *pStmt = sEval.pPreStmt->pStmt;
                int ptype = sqlite3_column_type(pStmt, i);
                
                azArg = Jsi_DSValue(&vStr);
                const char *zSep = i>0 ? ",": "";
                if( (azArg[i]==0) || (apColType && apColType[i]==SQLITE_NULL) ) {
                  Jsi_DSAppend(dStr, zSep, "NULL", NULL);
                }else if( ptype ==SQLITE_TEXT ) {
                  if( zSep[0] ) Jsi_DSAppend(dStr,zSep, NULL);
                  dbOutputQuotedString(dStr, azArg);
                }else if (ptype==SQLITE_INTEGER || ptype ==SQLITE_FLOAT) {
                  Jsi_DSAppend(dStr, zSep, azArg, NULL);
                }else if (ptype ==SQLITE_BLOB) {
................................................................................
                }else if( Jsi_GetDouble(interp, azArg, &dv) == JSI_OK ){
                  Jsi_DSAppend(dStr, zSep, azArg, NULL);
                }else{
                  if( zSep[0] ) Jsi_DSAppend(dStr,zSep, NULL);
                  dbOutputQuotedString(dStr, azArg);
                }
            }
            Jsi_DSAppend(dStr, ");", NULL);
            cnt++;
            if (opts.limit && cnt>=opts.limit) break;
        }
        Jsi_DSFree(&vStr);
    }

    case _JSI_EF_TABS:
................................................................................
                    mdbEvalSetColumn(&sEval, i, &vStr);
                    
                    MysqlPrep *prep = sEval.prep;
                    Jsi_OptionId ptype = prep->fieldResult[i].jsiTypeMap;
                    
                    azArg = Jsi_DSValue(&vStr);
                    const char *zSep = i>0 ? ",": "";
                    if (azArg[i]==0) {
                      Jsi_DSAppend(dStr, zSep, "NULL", NULL);
                    } else if( ptype ==JSI_OPTION_STRING) {
                      if( zSep[0] ) Jsi_DSAppend(dStr,zSep, NULL);
                      mdbOutputQuotedString(dStr, azArg);
                    } else if (ptype==JSI_OPTION_BOOL || ptype ==JSI_OPTION_DOUBLE) {
                      Jsi_DSAppend(dStr, zSep, azArg, NULL);
                    } else if( Jsi_GetDouble(interp, azArg, &dv) == JSI_OK ) {






|







 







|







 







|







 







>
|
<







 







|

|
>
>







 







|







 







|







 







|







 







>











>







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>







 







<
<
|











|







 







|







 







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
.....
18481
18482
18483
18484
18485
18486
18487
18488
18489
18490
18491
18492
18493
18494
18495
.....
19104
19105
19106
19107
19108
19109
19110
19111
19112
19113
19114
19115
19116
19117
19118
.....
19119
19120
19121
19122
19123
19124
19125
19126
19127

19128
19129
19130
19131
19132
19133
19134
.....
19148
19149
19150
19151
19152
19153
19154
19155
19156
19157
19158
19159
19160
19161
19162
19163
19164
19165
19166
.....
19187
19188
19189
19190
19191
19192
19193
19194
19195
19196
19197
19198
19199
19200
19201
.....
19448
19449
19450
19451
19452
19453
19454
19455
19456
19457
19458
19459
19460
19461
19462
.....
29405
29406
29407
29408
29409
29410
29411
29412
29413
29414
29415
29416
29417
29418
29419
.....
33430
33431
33432
33433
33434
33435
33436
33437
33438
33439
33440
33441
33442
33443
33444
33445
33446
33447
33448
33449
33450
33451
33452
33453
33454
33455
33456
.....
33486
33487
33488
33489
33490
33491
33492
33493
33494
33495
33496
33497
33498
33499
33500
.....
33514
33515
33516
33517
33518
33519
33520
33521
33522
33523
33524
33525
33526
33527
33528
33529
33530
33531
33532
33533
33534
33535
33536
33537
33538
33539
33540
33541
.....
33598
33599
33600
33601
33602
33603
33604
33605
33606
33607
33608
33609
33610
33611
33612
33613
33614
33615
33616
33617
33618
.....
48475
48476
48477
48478
48479
48480
48481


48482
48483
48484
48485
48486
48487
48488
48489
48490
48491
48492
48493
48494
48495
48496
48497
48498
48499
48500
48501
.....
48506
48507
48508
48509
48510
48511
48512
48513
48514
48515
48516
48517
48518
48519
48520
.....
54790
54791
54792
54793
54794
54795
54796
54797
54798
54799
54800
54801
54802
54803
54804
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   5
#define JSI_VERSION_RELEASE 22

#define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))

#ifndef JSI_EXTERN
#define JSI_EXTERN extern
#endif

................................................................................
    JSI_OPT(STRKEY, jsi_LogOptions, timeFmt, .help="A format string to use with strftime" ),
    JSI_OPT(USEROBJ,jsi_LogOptions, chan,    .help="Channel to send output to", .flags=0, .custom=0, .data=(void*)"Channel" ),
    JSI_OPT_END(jsi_LogOptions, .help="Interp options for logging")
};
static Jsi_OptionSpec InterpSubOptions[] = {
    JSI_OPT(STRKEY,jsi_SubOptions, blacklist,   .help="Comma separated modules to disable loading for", jsi_IIOF ),
    JSI_OPT(BOOL,  jsi_SubOptions, compat,      .help="Ignore unknown options via JSI_OPTS_IGNORE_EXTRA in option parser" ),
    JSI_OPT(INT,   jsi_SubOptions, dblPrec,     .help="Format precision of double where 0=max, -1=max-1, ... (max-1)", jsi_IIOF),
    JSI_OPT(BOOL,  jsi_SubOptions, istty,       .help="Indicates interp is in interactive mode", jsi_IIRO),
    JSI_OPT(BOOL,  jsi_SubOptions, logColNums,  .help="Display column numbers in error messages"),
    JSI_OPT(BOOL,  jsi_SubOptions, logAllowDups,.help="Log should not filter out duplicate messages"),
    JSI_OPT(BOOL,  jsi_SubOptions, mutexUnlock, .help="Unlock own mutex when evaling in other interps (true)", jsi_IIOF),
    JSI_OPT(BOOL,  jsi_SubOptions, noproto,     .help="Disable support of the OOP symbols:  __proto__, prototype, constructor, etc"),
    JSI_OPT(BOOL,  jsi_SubOptions, noReadline,  .help="In interactive mode disable use of readline" ),
    JSI_OPT(BOOL,  jsi_SubOptions, outUndef,     .help="In interactive mode output result values that are undefined"),
................................................................................
        if (interp->opts.no_interactive)
            return interp;
        rc = Jsi_Interactive(interp, JSI_OUTPUT_QUOTE|JSI_OUTPUT_NEWLINES);
    } else {
        if (argc == 2 && !Jsi_Strcmp(argv[1], "-h" )) {
            puts("usage: jsish -h/--help | -v/--version | -d/--debug | -D/--debugui | -u/--unittest | -U/-UU\n\t"
            "| -s/--safe | -Z/--zip | -S/--sqliteui | -w/--wget | -W/--websrv | -H/--htmli | -J/--jsi\n\t"
            "| -C/--cssi | -c/--cdata | -m/--module | -M/--make | -e/--eval | -t/--tracecall\n\t"
            "| -a/--archive | -T/--typecheck OPT | -IOPT VAL | FILE arg arg ...\nUse --help for long help.");
            return jsi_DoExit(interp, 1);
        }
        if (argc == 2 && !Jsi_Strcmp(argv[1], "--help")) {
            puts("jsish arguments:\n"
              "  -a/--archive FILE\tMount an archive (zip, sqlar or fossil repo) and run module.\n"
              "  -c/--cdata FILE\tGenerate .c or JSON output from a .jsc description.\n"
................................................................................
              "  -C/--cssi FILE\tPreprocess embedded CSS in .css file.\n"
              "  -d/--debug FILE\tRun console debugger on script.\n"
              "  -D/--debugui FILE\tRun web-gui debugger on script.\n"
              "  -e/--eval STRING\tEvaluate a javascript string and exit.\n"
              "  -h/--help\t\tPrint help in short or long form.\n"
              "  -H/--htmli FILE\tPreprocess embedded jsi in .htmli file.\n"
              "  -J/--jsi FILE\t\tPreprocess a .jsi file to typecheck in standard javascript.\n"
              "  -m/--module FILE\tSource file and invoke runModule.\n"
              "  -M/--make FILE\tPreprocess script as a Jsi Makefile.\n"

              "  -s/--safe FILE\tRun script in safe sub-interp.\n"
              "  -S/--sqliteui DBFILE\tRun Sqlite web-gui.\n"
              "  -t/--tracecall\tTrace all function calls.\n"
              "  -T/--typecheck OPT\tEnable typechecking.\n"
              "  -u/--unittest FILE\tRun unit-tests on a script file, or a dir containing .js/.jsi files.\n"
              "  -U/-UU SCRIPT\t\tShow output from unit-test mode, omitting pass/fail compare.\n"
              "  -v/--version\t\tPrint short/long version info and exit.\n"
................................................................................
            printf("%u.%u.%u %.4" JSI_NUMGFMT " %s", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE, Jsi_Version(), str);
            return jsi_DoExit(interp, 1);
        }
        if (argc == 2 && !Jsi_Strcmp(argv[1], "-v" )) {
            printf("%u.%u.%u\n", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE);
            return jsi_DoExit(interp, 1);
        }
        if (argc > 2 && (Jsi_Strcmp(argv[1], "--module")==0 || Jsi_Strcmp(argv[1], "-m" )==0)) {
            Jsi_DString dStr = {};
            const char* cpe = Jsi_Strrchr(argv[2], '.');
            int len = (cpe?cpe-argv[2]:Jsi_Strlen(argv[2]));
            Jsi_DSPrintf(&dStr, "source(\"%s\"); puts(runModule(\"%.*s\",console.args.slice(1)));", argv[2], len, argv[2]);
            rc = Jsi_EvalString(interp, Jsi_DSValue(&dStr), JSI_EVAL_NOSKIPBANG);
            Jsi_DSFree(&dStr);
        }
        else if (argc == 3 && (Jsi_Strcmp(argv[1], "--eval")==0 || Jsi_Strcmp(argv[1], "-e" )==0))
            rc = Jsi_EvalString(interp, argv[2], JSI_EVAL_NOSKIPBANG);

        else if (interp->selfZvfs && argc > 1 && (Jsi_Strcmp(argv[1], "--debug")==0 || Jsi_Strcmp(argv[1], "-d" )==0)) {
................................................................................
            rc = Jsi_EvalString(interp, "runModule('Jsi_Csspp');", JSI_EVAL_ISMAIN);
        else if (interp->selfZvfs && argc > 1 && (Jsi_Strcmp(argv[1], "--jsi")==0 || Jsi_Strcmp(argv[1], "-J" )==0))
            rc = Jsi_EvalString(interp, "runModule('Jsi_Jspp');", JSI_EVAL_ISMAIN);
        else if (interp->selfZvfs && argc > 1 && (Jsi_Strcmp(argv[1], "--htmli")==0 || Jsi_Strcmp(argv[1], "-H" )==0))
            rc = Jsi_EvalString(interp, "runModule('Jsi_Htmlpp');", JSI_EVAL_ISMAIN);
        else if (interp->selfZvfs && argc > 1 && (Jsi_Strcmp(argv[1], "--unittest")==0 || Jsi_Strcmp(argv[1], "-u" )==0))
            rc = Jsi_EvalString(interp, "exit(runModule('Jsi_UnitTest'));", JSI_EVAL_ISMAIN);
        else if (interp->selfZvfs && argc > 1 && (Jsi_Strcmp(argv[1], "--make")==0 || Jsi_Strcmp(argv[1], "-M" )==0))
            rc = Jsi_EvalString(interp, "exit(runModule('Jsi_Make'));", JSI_EVAL_ISMAIN);
        else {
            int iocnt;
            for (iocnt = 1; (iocnt+1)<argc; iocnt+=2) {
                if (Jsi_Strcmp(argv[iocnt], "-t") == 0 || Jsi_Strcmp(argv[iocnt], "--tracecall") == 0) {iocnt--; continue; }
                if (Jsi_Strcmp(argv[iocnt], "-T") == 0 || Jsi_Strcmp(argv[iocnt], "--typecheck") == 0) {continue; }
                if (Jsi_Strcmp(argv[iocnt], "-U") == 0) {iocnt--; continue; }
................................................................................
            Jsi_LogError("exceeded max subinterp depth");
            return NULL;
        }
    }
    interp->maxDepth = JSI_MAX_EVAL_DEPTH;
    interp->maxIncDepth = JSI_MAX_INCLUDE_DEPTH;
    interp->typeWarnMax = 50;
    interp->subOpts.dblPrec = DBL_DECIMAL_DIG-1;

    int iocnt;
    if (iopts) {
        iopts->interp = interp;
        interp->opts = *iopts;
    }
    interp->logOpts.file = 1;
................................................................................
    {_JSI_OPNM(TIME_W),  .cName="time_w",   .size=sizeof(time_w),     .fmt=PRId64, .xfmt="#" PRIx64,   .sfmt=SCNd64, .help="A time value in milliseconds stored as a 64 bit integer" },
    {_JSI_OPNM(TIME_D),  .cName="time_d",   .size=sizeof(time_d),     .fmt="g",    .xfmt="#" "g",      .sfmt="g", .help="A time value in milliseconds stored as a double" },
    {_JSI_OPNM(TIME_T),  .cName="time_t",   .size=sizeof(time_t),     .fmt="ld",   .xfmt="#lx",  .sfmt="ld", .help="A time value stored in a unix time_t" },
    {_JSI_OPNM(SIZE_T),  .cName="size_t",   .size=sizeof(size_t),     .fmt="zd",   .xfmt="#zx",  .sfmt="z", .help="Size unsigned" },
    {_JSI_OPNM(SSIZE_T), .cName="ssize_t",  .size=sizeof(ssize_t),    .fmt="zu",   .xfmt="#zx",  .sfmt="zu", .help="Size integer" },
    {_JSI_OPNM(INTPTR_T),.cName="intptr_t", .size=sizeof(intptr_t),   .fmt="d",    .xfmt="#x",   .sfmt="d", .help="Integer large enough to store pointer" },
    {_JSI_OPNM(UINTPTR_T),.cName="uintptr_t",.size=sizeof(uintptr_t), .fmt="u",    .xfmt="#x",   .sfmt="u", .help="Unsigned large enough to store pointer" },
    {_JSI_OPNM(NUMBER),  .cName="Jsi_Number",.size=sizeof(Jsi_Number),.fmt=JSI_NUMGFMT,.xfmt="#" JSI_NUMGFMT,.sfmt=JSI_NUMGFMT, .help="Double or long double" },
    {_JSI_OPNM(INT),     .cName="int",      .size=sizeof(int),        .fmt="d",    .xfmt="#x",   .sfmt="d", .help="Integer" },
    {_JSI_OPNM(UINT),    .cName="uint",     .size=sizeof(uint),       .fmt="u",    .xfmt="#x",   .sfmt="u", .help="Unsigned" },
    {_JSI_OPNM(LONG),    .cName="long",     .size=sizeof(long),       .fmt="ld",   .xfmt="#lx",  .sfmt="ld", .help="Long" },
    {_JSI_OPNM(ULONG),   .cName="ulong",    .size=sizeof(ulong),      .fmt="lu",   .xfmt="#lx",  .sfmt="lu", .help="Unsigned long" },
    {_JSI_OPNM(SHORT),   .cName="short",    .size=sizeof(short),      .fmt="hd",   .xfmt="#hx",  .sfmt="hd", .help="Short" },
    {_JSI_OPNM(USHORT),  .cName="ushort",   .size=sizeof(ushort),     .fmt="hu",   .xfmt="#hx",  .sfmt="hu", .help="Unsigned short" },
    {_JSI_OPNM(STRING),  .cName="Jsi_Value*",.size=sizeof(Jsi_Value*),.fmt="s",    .xfmt="s", .sfmt=0, .help="A string Value"},
................................................................................
    Jsi_ValueMakeNumber(interp, ret, pid);
    return JSI_OK;
#endif
}

typedef struct {
    Jsi_Value* inputStr;
    Jsi_Value* chdir;
    bool bg;
    bool noError;
    bool trim;
    bool retCode;
    bool retAll;
    bool retval;
    bool noRedir;
} ExecOpts;

static Jsi_OptionSpec ExecOptions[] = {
    JSI_OPT(BOOL,   ExecOpts, bg,       .help="Run command in background using system() and return OS code" ),
    JSI_OPT(STRING, ExecOpts, chdir,    .help="Change to directory" ),
    JSI_OPT(STRING, ExecOpts, inputStr, .help="Use string as input and return OS code" ),
    JSI_OPT(BOOL,   ExecOpts, noError,  .help="Suppress all OS errors" ),
    JSI_OPT(BOOL,   ExecOpts, noRedir,  .help="Disable redirect and shell escapes in command" ),
    JSI_OPT(BOOL,   ExecOpts, trim,     .help="Trim trailing whitespace from output" ),
    JSI_OPT(BOOL,   ExecOpts, retAll,   .help="Return the OS return code and data as an object" ),
    JSI_OPT(BOOL,   ExecOpts, retCode,  .help="Return only the OS return code" ),
    JSI_OPT_END(ExecOpts, .help="Exec options")
................................................................................
        }
        if (no)
            return Jsi_LogError("no exec in safe mode");
    }
    Jsi_RC rc = JSI_OK;
    Jsi_Value *opt = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_DString dStr = {};
    Jsi_DString cStr = {};
    ExecOpts edata = {};
    edata.retval = 1;
    
    if (opt != NULL) {
        if (opt->vt == JSI_VT_OBJECT && opt->d.obj->ot == JSI_OT_OBJECT) {
            hasopts = 1;
            if (Jsi_OptionsProcess(interp, ExecOptions, &edata, opt, 0) < 0) {
................................................................................
            if (*cp2 != '>' && *cp2 != '<' &&*cp2 != '|' &&*cp2 != ';' && *cp2 != '&' && *cp2 != '$' && *cp2 != '`' && *cp2 != '=')
                cp2++;
            else 
                return Jsi_LogError("restricted exec at char '%c' in string: %s", *cp2, cp);
        }
    }
    int isbg = 0, ec = 0;
    const char *ocd = NULL, *cd = (edata.chdir ? Jsi_ValueString(interp, edata.chdir, NULL) : NULL);
    if (cd && interp->isSafe) {
        cd = NULL;
        rc = Jsi_LogError("no chdir in safe mode");
        goto done;        
    }
    if (cd) {
        ocd = Jsi_GetCwd(interp, &cStr);
        if (!Jsi_FSNative(interp, edata.chdir) || Jsi_Chdir(interp, edata.chdir)<0) {
            cd = NULL;
            rc = Jsi_LogError("chdir failed");
            goto done;        
        }
    }
    if (edata.bg || (isbg=((sLen>1 && cp[sLen-1] == '&')))) {
        if (edata.inputStr) {
            rc = Jsi_LogError("inputStr can not used with bg");
            goto done;
        }
        if (!isbg) {
            Jsi_DSAppend(&dStr, cp, " &", NULL);
................................................................................
    } else if (edata.retval)
        Jsi_ValueFromDS(interp, &dStr, ret);
    else {
        Jsi_DSFree(&dStr);
        Jsi_ValueMakeNumber(interp, ret, (Jsi_Number)exitCode);
    }
done:
    if (cd && ocd) {
        Jsi_Value *oc = Jsi_ValueNewStringDup(interp, ocd);
        Jsi_IncrRefCount(interp, oc);
        Jsi_Chdir(interp, oc);
        Jsi_DecrRefCount(interp, oc);
    }
    Jsi_DSFree(&cStr);
    if (hasopts)
        Jsi_OptionsFree(interp, ExecOptions, &edata, 0);
    return rc;
}

static Jsi_RC SysExecCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
................................................................................
    
    case _JSI_EF_INSERT: {
        Jsi_DString vStr = {};    
        while( JSI_OK==(rc = dbEvalStep(&sEval)) ) {
            int i;
            int nCol;
            const char *tbl = (opts.table ? opts.table : "table");


            Jsi_DSAppend(dStr, "INSERT INTO \"", tbl, "\" VALUES(", NULL);
            dbEvalRowInfo(&sEval, &nCol, &apColName, &apColType);
            for(i=0; i<nCol; i++) {
                Jsi_Number dv;
                const char *azArg;
                Jsi_DSSetLength(&vStr, 0);
                dbEvalSetColumn(&sEval, i, &vStr);
                sqlite3_stmt *pStmt = sEval.pPreStmt->pStmt;
                int ptype = sqlite3_column_type(pStmt, i);
                
                azArg = Jsi_DSValue(&vStr);
                const char *zSep = i>0 ? ",": "";
                if(apColType && apColType[i]==SQLITE_NULL) {
                  Jsi_DSAppend(dStr, zSep, "NULL", NULL);
                }else if( ptype ==SQLITE_TEXT ) {
                  if( zSep[0] ) Jsi_DSAppend(dStr,zSep, NULL);
                  dbOutputQuotedString(dStr, azArg);
                }else if (ptype==SQLITE_INTEGER || ptype ==SQLITE_FLOAT) {
                  Jsi_DSAppend(dStr, zSep, azArg, NULL);
                }else if (ptype ==SQLITE_BLOB) {
................................................................................
                }else if( Jsi_GetDouble(interp, azArg, &dv) == JSI_OK ){
                  Jsi_DSAppend(dStr, zSep, azArg, NULL);
                }else{
                  if( zSep[0] ) Jsi_DSAppend(dStr,zSep, NULL);
                  dbOutputQuotedString(dStr, azArg);
                }
            }
            Jsi_DSAppend(dStr, ");\n", NULL);
            cnt++;
            if (opts.limit && cnt>=opts.limit) break;
        }
        Jsi_DSFree(&vStr);
    }

    case _JSI_EF_TABS:
................................................................................
                    mdbEvalSetColumn(&sEval, i, &vStr);
                    
                    MysqlPrep *prep = sEval.prep;
                    Jsi_OptionId ptype = prep->fieldResult[i].jsiTypeMap;
                    
                    azArg = Jsi_DSValue(&vStr);
                    const char *zSep = i>0 ? ",": "";
                    if (azArg[i]==0 && ptype != JSI_OPTION_STRING) {
                      Jsi_DSAppend(dStr, zSep, "NULL", NULL);
                    } else if( ptype ==JSI_OPTION_STRING) {
                      if( zSep[0] ) Jsi_DSAppend(dStr,zSep, NULL);
                      mdbOutputQuotedString(dStr, azArg);
                    } else if (ptype==JSI_OPTION_BOOL || ptype ==JSI_OPTION_DOUBLE) {
                      Jsi_DSAppend(dStr, zSep, azArg, NULL);
                    } else if( Jsi_GetDouble(interp, azArg, &dv) == JSI_OK ) {

Changes to src/jsi.h.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   5
#define JSI_VERSION_RELEASE 21

#define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))

#ifndef JSI_EXTERN
#define JSI_EXTERN extern
#endif







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   5
#define JSI_VERSION_RELEASE 22

#define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))

#ifndef JSI_EXTERN
#define JSI_EXTERN extern
#endif

Changes to src/jsiCmds.c.

1169
1170
1171
1172
1173
1174
1175

1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186

1187
1188
1189
1190
1191
1192
1193
....
1223
1224
1225
1226
1227
1228
1229

1230
1231
1232
1233
1234
1235
1236
....
1250
1251
1252
1253
1254
1255
1256














1257
1258
1259
1260
1261
1262
1263
....
1320
1321
1322
1323
1324
1325
1326







1327
1328
1329
1330
1331
1332
1333
    Jsi_ValueMakeNumber(interp, ret, pid);
    return JSI_OK;
#endif
}

typedef struct {
    Jsi_Value* inputStr;

    bool bg;
    bool noError;
    bool trim;
    bool retCode;
    bool retAll;
    bool retval;
    bool noRedir;
} ExecOpts;

static Jsi_OptionSpec ExecOptions[] = {
    JSI_OPT(BOOL,   ExecOpts, bg,       .help="Run command in background using system() and return OS code" ),

    JSI_OPT(STRING, ExecOpts, inputStr, .help="Use string as input and return OS code" ),
    JSI_OPT(BOOL,   ExecOpts, noError,  .help="Suppress all OS errors" ),
    JSI_OPT(BOOL,   ExecOpts, noRedir,  .help="Disable redirect and shell escapes in command" ),
    JSI_OPT(BOOL,   ExecOpts, trim,     .help="Trim trailing whitespace from output" ),
    JSI_OPT(BOOL,   ExecOpts, retAll,   .help="Return the OS return code and data as an object" ),
    JSI_OPT(BOOL,   ExecOpts, retCode,  .help="Return only the OS return code" ),
    JSI_OPT_END(ExecOpts, .help="Exec options")
................................................................................
        }
        if (no)
            return Jsi_LogError("no exec in safe mode");
    }
    Jsi_RC rc = JSI_OK;
    Jsi_Value *opt = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_DString dStr = {};

    ExecOpts edata = {};
    edata.retval = 1;
    
    if (opt != NULL) {
        if (opt->vt == JSI_VT_OBJECT && opt->d.obj->ot == JSI_OT_OBJECT) {
            hasopts = 1;
            if (Jsi_OptionsProcess(interp, ExecOptions, &edata, opt, 0) < 0) {
................................................................................
            if (*cp2 != '>' && *cp2 != '<' &&*cp2 != '|' &&*cp2 != ';' && *cp2 != '&' && *cp2 != '$' && *cp2 != '`' && *cp2 != '=')
                cp2++;
            else 
                return Jsi_LogError("restricted exec at char '%c' in string: %s", *cp2, cp);
        }
    }
    int isbg = 0, ec = 0;














    if (edata.bg || (isbg=((sLen>1 && cp[sLen-1] == '&')))) {
        if (edata.inputStr) {
            rc = Jsi_LogError("inputStr can not used with bg");
            goto done;
        }
        if (!isbg) {
            Jsi_DSAppend(&dStr, cp, " &", NULL);
................................................................................
    } else if (edata.retval)
        Jsi_ValueFromDS(interp, &dStr, ret);
    else {
        Jsi_DSFree(&dStr);
        Jsi_ValueMakeNumber(interp, ret, (Jsi_Number)exitCode);
    }
done:







    if (hasopts)
        Jsi_OptionsFree(interp, ExecOptions, &edata, 0);
    return rc;
}

static Jsi_RC SysExecCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)







>











>







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>







1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
....
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
....
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
....
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
    Jsi_ValueMakeNumber(interp, ret, pid);
    return JSI_OK;
#endif
}

typedef struct {
    Jsi_Value* inputStr;
    Jsi_Value* chdir;
    bool bg;
    bool noError;
    bool trim;
    bool retCode;
    bool retAll;
    bool retval;
    bool noRedir;
} ExecOpts;

static Jsi_OptionSpec ExecOptions[] = {
    JSI_OPT(BOOL,   ExecOpts, bg,       .help="Run command in background using system() and return OS code" ),
    JSI_OPT(STRING, ExecOpts, chdir,    .help="Change to directory" ),
    JSI_OPT(STRING, ExecOpts, inputStr, .help="Use string as input and return OS code" ),
    JSI_OPT(BOOL,   ExecOpts, noError,  .help="Suppress all OS errors" ),
    JSI_OPT(BOOL,   ExecOpts, noRedir,  .help="Disable redirect and shell escapes in command" ),
    JSI_OPT(BOOL,   ExecOpts, trim,     .help="Trim trailing whitespace from output" ),
    JSI_OPT(BOOL,   ExecOpts, retAll,   .help="Return the OS return code and data as an object" ),
    JSI_OPT(BOOL,   ExecOpts, retCode,  .help="Return only the OS return code" ),
    JSI_OPT_END(ExecOpts, .help="Exec options")
................................................................................
        }
        if (no)
            return Jsi_LogError("no exec in safe mode");
    }
    Jsi_RC rc = JSI_OK;
    Jsi_Value *opt = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_DString dStr = {};
    Jsi_DString cStr = {};
    ExecOpts edata = {};
    edata.retval = 1;
    
    if (opt != NULL) {
        if (opt->vt == JSI_VT_OBJECT && opt->d.obj->ot == JSI_OT_OBJECT) {
            hasopts = 1;
            if (Jsi_OptionsProcess(interp, ExecOptions, &edata, opt, 0) < 0) {
................................................................................
            if (*cp2 != '>' && *cp2 != '<' &&*cp2 != '|' &&*cp2 != ';' && *cp2 != '&' && *cp2 != '$' && *cp2 != '`' && *cp2 != '=')
                cp2++;
            else 
                return Jsi_LogError("restricted exec at char '%c' in string: %s", *cp2, cp);
        }
    }
    int isbg = 0, ec = 0;
    const char *ocd = NULL, *cd = (edata.chdir ? Jsi_ValueString(interp, edata.chdir, NULL) : NULL);
    if (cd && interp->isSafe) {
        cd = NULL;
        rc = Jsi_LogError("no chdir in safe mode");
        goto done;        
    }
    if (cd) {
        ocd = Jsi_GetCwd(interp, &cStr);
        if (!Jsi_FSNative(interp, edata.chdir) || Jsi_Chdir(interp, edata.chdir)<0) {
            cd = NULL;
            rc = Jsi_LogError("chdir failed");
            goto done;        
        }
    }
    if (edata.bg || (isbg=((sLen>1 && cp[sLen-1] == '&')))) {
        if (edata.inputStr) {
            rc = Jsi_LogError("inputStr can not used with bg");
            goto done;
        }
        if (!isbg) {
            Jsi_DSAppend(&dStr, cp, " &", NULL);
................................................................................
    } else if (edata.retval)
        Jsi_ValueFromDS(interp, &dStr, ret);
    else {
        Jsi_DSFree(&dStr);
        Jsi_ValueMakeNumber(interp, ret, (Jsi_Number)exitCode);
    }
done:
    if (cd && ocd) {
        Jsi_Value *oc = Jsi_ValueNewStringDup(interp, ocd);
        Jsi_IncrRefCount(interp, oc);
        Jsi_Chdir(interp, oc);
        Jsi_DecrRefCount(interp, oc);
    }
    Jsi_DSFree(&cStr);
    if (hasopts)
        Jsi_OptionsFree(interp, ExecOptions, &edata, 0);
    return rc;
}

static Jsi_RC SysExecCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)

Changes to src/jsiMySql.c.

1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
                    mdbEvalSetColumn(&sEval, i, &vStr);
                    
                    MysqlPrep *prep = sEval.prep;
                    Jsi_OptionId ptype = prep->fieldResult[i].jsiTypeMap;
                    
                    azArg = Jsi_DSValue(&vStr);
                    const char *zSep = i>0 ? ",": "";
                    if (azArg[i]==0) {
                      Jsi_DSAppend(dStr, zSep, "NULL", NULL);
                    } else if( ptype ==JSI_OPTION_STRING) {
                      if( zSep[0] ) Jsi_DSAppend(dStr,zSep, NULL);
                      mdbOutputQuotedString(dStr, azArg);
                    } else if (ptype==JSI_OPTION_BOOL || ptype ==JSI_OPTION_DOUBLE) {
                      Jsi_DSAppend(dStr, zSep, azArg, NULL);
                    } else if( Jsi_GetDouble(interp, azArg, &dv) == JSI_OK ) {







|







1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
                    mdbEvalSetColumn(&sEval, i, &vStr);
                    
                    MysqlPrep *prep = sEval.prep;
                    Jsi_OptionId ptype = prep->fieldResult[i].jsiTypeMap;
                    
                    azArg = Jsi_DSValue(&vStr);
                    const char *zSep = i>0 ? ",": "";
                    if (azArg[i]==0 && ptype != JSI_OPTION_STRING) {
                      Jsi_DSAppend(dStr, zSep, "NULL", NULL);
                    } else if( ptype ==JSI_OPTION_STRING) {
                      if( zSep[0] ) Jsi_DSAppend(dStr,zSep, NULL);
                      mdbOutputQuotedString(dStr, azArg);
                    } else if (ptype==JSI_OPTION_BOOL || ptype ==JSI_OPTION_DOUBLE) {
                      Jsi_DSAppend(dStr, zSep, azArg, NULL);
                    } else if( Jsi_GetDouble(interp, azArg, &dv) == JSI_OK ) {

Changes to tests/sqlite.jsi.

147
148
149
150
151
152
153
154
155
156

157
158
159
160
161
162
163
164
165
166
167
95	2
91	3
db.query('select * from foo;',{mode:'line'}) ==>     a = 99    b = 1
    a = 95
    b = 2
    a = 91
    b = 3
db.query('select * from foo;',{mode:'insert'}) ==> INSERT INTO table VALUES(99,NULL);
INSERT INTO table VALUES(95,NULL);
INSERT INTO table VALUES(91,NULL);

binds = [91,3] ==> [ 91, 3 ]
db.query('insert into foo values(?,?);', {varName:'binds'}) ==> []
db.query('insert into foo values(?,?);', {values:binds}) ==> []
db.query('insert into foo values(?,?);', {values:[91,3]}) ==> []
db.func('bar',function(n) { return n+'.000'; }) ==> undefined
db.onecolumn('select bar(a) from foo where b == 2;') ==> TRACING: select bar(a) from foo where b == 2;
95.000
db.conf({onTrace:null}) ==> undefined
=!EXPECTEND!=
*/








|
|
|
>











147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
95	2
91	3
db.query('select * from foo;',{mode:'line'}) ==>     a = 99    b = 1
    a = 95
    b = 2
    a = 91
    b = 3
db.query('select * from foo;',{mode:'insert'}) ==> INSERT INTO "table" VALUES(99,1);
INSERT INTO "table" VALUES(95,2);
INSERT INTO "table" VALUES(91,3);

binds = [91,3] ==> [ 91, 3 ]
db.query('insert into foo values(?,?);', {varName:'binds'}) ==> []
db.query('insert into foo values(?,?);', {values:binds}) ==> []
db.query('insert into foo values(?,?);', {values:[91,3]}) ==> []
db.func('bar',function(n) { return n+'.000'; }) ==> undefined
db.onecolumn('select bar(a) from foo where b == 2;') ==> TRACING: select bar(a) from foo where b == 2;
95.000
db.conf({onTrace:null}) ==> undefined
=!EXPECTEND!=
*/

Changes to tools/protos.jsi.

1
2
3
4
5
6
7
8
//JSI Command Prototypes: version 2.5.20
throw("NOT EXECUTABLE: USE FILE IN GEANY EDITOR FOR CMD LINE COMPLETION + GOTO TAG");

var Array = function(cmd,args) {};
Array.prototype.concat = function(...):array {};
Array.prototype.every = function(callback:function):any {};
Array.prototype.fill = function(value:any, start:number=0, end:number=-1):array {};
Array.prototype.filter = function(callback:function, this:object=void):array {};
|







1
2
3
4
5
6
7
8
//JSI Command Prototypes: version 2.5.22
throw("NOT EXECUTABLE: USE FILE IN GEANY EDITOR FOR CMD LINE COMPLETION + GOTO TAG");

var Array = function(cmd,args) {};
Array.prototype.concat = function(...):array {};
Array.prototype.every = function(callback:function):any {};
Array.prototype.fill = function(value:any, start:number=0, end:number=-1):array {};
Array.prototype.filter = function(callback:function, this:object=void):array {};

Changes to www/reference.wiki.

702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
....
1350
1351
1352
1353
1354
1355
1356

1357
1358
1359
1360
1361
1362
1363

<a name="subOptsOptions"></a>
<h2>Options for "subOpts"</h2>
<table border="1" class="optstbl table">
<tr><th>Option</th> <th>Type</th> <th>Description</th><th>Flags</th></tr>
<tr><td>blacklist</td><td><i>STRKEY</i></td><td>Comma separated modules to disable loading for.</td><td><i>initOnly</i></td></tr>
<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>
<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>
<tr><td>istty</td><td><i>BOOL</i></td><td>Indicates interp is in interactive mode.</td><td><i>readOnly</i></td></tr>
<tr><td>logColNums</td><td><i>BOOL</i></td><td>Display column numbers in error messages.</td><td><i></i></td></tr>
<tr><td>logAllowDups</td><td><i>BOOL</i></td><td>Log should not filter out duplicate messages.</td><td><i></i></td></tr>
<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>
<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>
<tr><td>noReadline</td><td><i>BOOL</i></td><td>In interactive mode disable use of readline.</td><td><i></i></td></tr>
<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>
................................................................................

<a name="System.execOptions"></a>
<a name="System.confOptions"></a>
<h2>Options for "System.exec"</h2>
<table border="1" class="optstbl table">
<tr><th>Option</th> <th>Type</th> <th>Description</th><th>Flags</th></tr>
<tr><td>bg</td><td><i>BOOL</i></td><td>Run command in background using system() and return OS code.</td><td><i></i></td></tr>

<tr><td>inputStr</td><td><i>STRING</i></td><td>Use string as input and return OS code.</td><td><i></i></td></tr>
<tr><td>noError</td><td><i>BOOL</i></td><td>Suppress all OS errors.</td><td><i></i></td></tr>
<tr><td>noRedir</td><td><i>BOOL</i></td><td>Disable redirect and shell escapes in command.</td><td><i></i></td></tr>
<tr><td>trim</td><td><i>BOOL</i></td><td>Trim trailing whitespace from output.</td><td><i></i></td></tr>
<tr><td>retAll</td><td><i>BOOL</i></td><td>Return the OS return code and data as an object.</td><td><i></i></td></tr>
<tr><td>retCode</td><td><i>BOOL</i></td><td>Return only the OS return code.</td><td><i></i></td></tr>
</table>







|







 







>







702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
....
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364

<a name="subOptsOptions"></a>
<h2>Options for "subOpts"</h2>
<table border="1" class="optstbl table">
<tr><th>Option</th> <th>Type</th> <th>Description</th><th>Flags</th></tr>
<tr><td>blacklist</td><td><i>STRKEY</i></td><td>Comma separated modules to disable loading for.</td><td><i>initOnly</i></td></tr>
<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>
<tr><td>dblPrec</td><td><i>INT</i></td><td>Format precision of double where 0=max, -1=max-1, ... (max-1).</td><td><i>initOnly</i></td></tr>
<tr><td>istty</td><td><i>BOOL</i></td><td>Indicates interp is in interactive mode.</td><td><i>readOnly</i></td></tr>
<tr><td>logColNums</td><td><i>BOOL</i></td><td>Display column numbers in error messages.</td><td><i></i></td></tr>
<tr><td>logAllowDups</td><td><i>BOOL</i></td><td>Log should not filter out duplicate messages.</td><td><i></i></td></tr>
<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>
<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>
<tr><td>noReadline</td><td><i>BOOL</i></td><td>In interactive mode disable use of readline.</td><td><i></i></td></tr>
<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>
................................................................................

<a name="System.execOptions"></a>
<a name="System.confOptions"></a>
<h2>Options for "System.exec"</h2>
<table border="1" class="optstbl table">
<tr><th>Option</th> <th>Type</th> <th>Description</th><th>Flags</th></tr>
<tr><td>bg</td><td><i>BOOL</i></td><td>Run command in background using system() and return OS code.</td><td><i></i></td></tr>
<tr><td>chdir</td><td><i>STRING</i></td><td>Change to directory.</td><td><i></i></td></tr>
<tr><td>inputStr</td><td><i>STRING</i></td><td>Use string as input and return OS code.</td><td><i></i></td></tr>
<tr><td>noError</td><td><i>BOOL</i></td><td>Suppress all OS errors.</td><td><i></i></td></tr>
<tr><td>noRedir</td><td><i>BOOL</i></td><td>Disable redirect and shell escapes in command.</td><td><i></i></td></tr>
<tr><td>trim</td><td><i>BOOL</i></td><td>Trim trailing whitespace from output.</td><td><i></i></td></tr>
<tr><td>retAll</td><td><i>BOOL</i></td><td>Return the OS return code and data as an object.</td><td><i></i></td></tr>
<tr><td>retCode</td><td><i>BOOL</i></td><td>Return only the OS return code.</td><td><i></i></td></tr>
</table>