/ Check-in [229a87b69c]
DEMO | DOWNLOAD | DEPLOY | SEARCH
Login

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

Overview
Comment:Add validate command. Docs
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:229a87b69c2695f130055ac8c622df5a36bb4966
User & Date: pmacdona 2019-12-03 16:42:49
Context
2019-12-03
16:43
Doc check-in: 7da18f30d9 user: pmacdona tags: trunk
16:42
Add validate command. Docs check-in: 229a87b69c user: pmacdona tags: trunk
2019-12-02
02:02
Sqlite: set dbname on open. Htmlpp: change echo to output. check-in: 64a6b822fd user: pmacdona tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to js-demos/vfsfossil.jsi.

1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/local/bin/jsish --U %s
// Note: if was a real unit test it would fail as info changes in fossil, but we show output below anyways.


var target = '../../jsi.fossil';
File.size(target);

var mnt, mnt2, mnt3, mnt4, mnt5, fn, fp, stat, x;
;mnt=Vfs.mount('fossil', target);
x = File.read(mnt+'/lib/SqliteUI/html/sqlite.jsi');
;File.glob(mnt+'/lib/*');

;fn = mnt+'/README.md';
;File.read(fn);
;File.size(fn);
;File.mtime(fn);
;stat=File.lstat(fn);
;format('%#o', stat.mode);
;File.readable(fn);
................................................................................

;Vfs.list();
;Vfs.type();
;Vfs.type('fossil');
;Vfs.unmount(mnt);

mnt4 = Vfs.mount('fossil', target, {version:'Release 2.4'});
;File.size(mnt4+'/jsi.h');

;mnt5=Vfs.vmount({type:'fossil', file:target, mount:'/zvfs'});
;File.glob(mnt5+'/lib/*');
/*
=!EXPECTSTART!=
mnt=Vfs.mount('fossil', target) ==>  /vfs1
File.glob(mnt+'/jsi/*') ==>  [ "/vfs1/jsi/js-demos", "/vfs1/jsi/jsiZvfs.c", "/vfs1/jsi/tests", "/vfs1/jsi/jsiCData.c", "/vfs1/jsi/miniz", "/vfs1/jsi/jsiInterp.c", "/vfs1/jsi/jsiSqlite.c", "/vfs1/jsi/jsiValue.c", "/vfs1/jsi/websocket", "/vfs1/jsi/jsiInt.h", "/vfs1/jsi/BUILD", "/vfs1/jsi/jsiNumber.c", "/vfs1/jsi/jsiOne.c", "/vfs1/jsi/jsiFormat.c", "/vfs1/jsi/jsiBool.c", "/vfs1/jsi/parser.y", "/vfs1/jsi/jsiVfs.c", "/vfs1/jsi/jsiJSON.c", "/vfs1/jsi/README", "/vfs1/jsi/jsiTree.c", "/vfs1/jsi/jsiCode.c", "/vfs1/jsi/Makefile", "/vfs1/jsi/jsiParser.y", "/vfs1/jsi/jsiWebSocket.c", "/vfs1/jsi/jsiRegexp.c", "/vfs1/jsi/sqlite", "/vfs1/jsi/win", "/vfs1/jsi/jsiLoad.c", "/vfs1/jsi/jsiString.c", "/vfs1/jsi/zipdir", "/vfs1/jsi/jsiLexer.c", "/vfs1/jsi/linenoise.c", "/vfs1/jsi/jsiUserObj.c", "/vfs1/jsi/jsiHash.c", "/vfs1/jsi/regex", "/vfs1/jsi/linenoise.h", "/vfs1/jsi/jsiChar.c", "/vfs1/jsi/jsiCmds.c", "/vfs1/jsi/jsiSignal.c", "/vfs1/jsi/jsiSocket.c", "/vfs1/jsi/jsiObj.c", "/vfs1/jsi/COPYING", "/vfs1/jsi/jsiMySql.c", "/vfs1/jsi/TODO", "/vfs1/jsi/jsiCrypto.c", "/vfs1/jsi/jsiMath.c", "/vfs1/jsi/jsiUtils.c", "/vfs1/jsi/jsmn.c", "/vfs1/jsi/configure", "/vfs1/jsi/jsiEval.c", "/vfs1/jsi/jsiDString.c", "/vfs1/jsi/jsiArray.c", "/vfs1/jsi/c-demos", "/vfs1/jsi/Configs", "/vfs1/jsi/jsiUtf8.c", "/vfs1/jsi/jsiPstate.c", "/vfs1/jsi/jsiStubs.c", "/vfs1/jsi/jsiOptions.c", "/vfs1/jsi/jsiStubs.h", "/vfs1/jsi/jsiFileCmds.c", "/vfs1/jsi/lib", "/vfs1/jsi/jsiMarkdown.c", "/vfs1/jsi/CMakeLists.txt", "/vfs1/jsi/jsiFunc.c", "/vfs1/jsi/jsiProto.c", "/vfs1/jsi/www", "/vfs1/jsi/jsiFilesys.c", "/vfs1/jsi/main.c", "/vfs1/jsi/jsi.c", "/vfs1/jsi/jsi.h", "/vfs1/jsi/tools" ]




|




<

>







 







|







1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
17
18
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/local/bin/jsish --U %s
// Note: if was a real unit test it would fail as info changes in fossil, but we show output below anyways.


var target = '../jsi.fossil';
File.size(target);

var mnt, mnt2, mnt3, mnt4, mnt5, fn, fp, stat, x;
;mnt=Vfs.mount('fossil', target);

;File.glob(mnt+'/lib/*');
x = File.read(mnt+'/lib/SqliteUI/html/sqlite.jsi');
;fn = mnt+'/README.md';
;File.read(fn);
;File.size(fn);
;File.mtime(fn);
;stat=File.lstat(fn);
;format('%#o', stat.mode);
;File.readable(fn);
................................................................................

;Vfs.list();
;Vfs.type();
;Vfs.type('fossil');
;Vfs.unmount(mnt);

mnt4 = Vfs.mount('fossil', target, {version:'Release 2.4'});
;File.size(mnt4+'/src/jsi.h');

;mnt5=Vfs.vmount({type:'fossil', file:target, mount:'/zvfs'});
;File.glob(mnt5+'/lib/*');
/*
=!EXPECTSTART!=
mnt=Vfs.mount('fossil', target) ==>  /vfs1
File.glob(mnt+'/jsi/*') ==>  [ "/vfs1/jsi/js-demos", "/vfs1/jsi/jsiZvfs.c", "/vfs1/jsi/tests", "/vfs1/jsi/jsiCData.c", "/vfs1/jsi/miniz", "/vfs1/jsi/jsiInterp.c", "/vfs1/jsi/jsiSqlite.c", "/vfs1/jsi/jsiValue.c", "/vfs1/jsi/websocket", "/vfs1/jsi/jsiInt.h", "/vfs1/jsi/BUILD", "/vfs1/jsi/jsiNumber.c", "/vfs1/jsi/jsiOne.c", "/vfs1/jsi/jsiFormat.c", "/vfs1/jsi/jsiBool.c", "/vfs1/jsi/parser.y", "/vfs1/jsi/jsiVfs.c", "/vfs1/jsi/jsiJSON.c", "/vfs1/jsi/README", "/vfs1/jsi/jsiTree.c", "/vfs1/jsi/jsiCode.c", "/vfs1/jsi/Makefile", "/vfs1/jsi/jsiParser.y", "/vfs1/jsi/jsiWebSocket.c", "/vfs1/jsi/jsiRegexp.c", "/vfs1/jsi/sqlite", "/vfs1/jsi/win", "/vfs1/jsi/jsiLoad.c", "/vfs1/jsi/jsiString.c", "/vfs1/jsi/zipdir", "/vfs1/jsi/jsiLexer.c", "/vfs1/jsi/linenoise.c", "/vfs1/jsi/jsiUserObj.c", "/vfs1/jsi/jsiHash.c", "/vfs1/jsi/regex", "/vfs1/jsi/linenoise.h", "/vfs1/jsi/jsiChar.c", "/vfs1/jsi/jsiCmds.c", "/vfs1/jsi/jsiSignal.c", "/vfs1/jsi/jsiSocket.c", "/vfs1/jsi/jsiObj.c", "/vfs1/jsi/COPYING", "/vfs1/jsi/jsiMySql.c", "/vfs1/jsi/TODO", "/vfs1/jsi/jsiCrypto.c", "/vfs1/jsi/jsiMath.c", "/vfs1/jsi/jsiUtils.c", "/vfs1/jsi/jsmn.c", "/vfs1/jsi/configure", "/vfs1/jsi/jsiEval.c", "/vfs1/jsi/jsiDString.c", "/vfs1/jsi/jsiArray.c", "/vfs1/jsi/c-demos", "/vfs1/jsi/Configs", "/vfs1/jsi/jsiUtf8.c", "/vfs1/jsi/jsiPstate.c", "/vfs1/jsi/jsiStubs.c", "/vfs1/jsi/jsiOptions.c", "/vfs1/jsi/jsiStubs.h", "/vfs1/jsi/jsiFileCmds.c", "/vfs1/jsi/lib", "/vfs1/jsi/jsiMarkdown.c", "/vfs1/jsi/CMakeLists.txt", "/vfs1/jsi/jsiFunc.c", "/vfs1/jsi/jsiProto.c", "/vfs1/jsi/www", "/vfs1/jsi/jsiFilesys.c", "/vfs1/jsi/main.c", "/vfs1/jsi/jsi.c", "/vfs1/jsi/jsi.h", "/vfs1/jsi/tools" ]

Changes to lib/SqliteUI/SqliteUI.jsi.

509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
...
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
    function WsOpen(ws:userobj, id:number)
    {
        var hdrs = self.ws.header(id);
        LogDebug('OPEN:', hdrs.keys(), "\n", hdrs);
        LogTrace('HDRS:', self.ws.header(id,'get '));
    }
        
    function WsRecv(ws:userobj, id:number, data:any)
    {
        var buf, buf0, buf1, buf2;
        LogDebug("SERVER GOT: "+ id +": "+data);
        if (self.debugging)
            debugger;
        var dat = JSON.parse(data);
        LogDebug("JSON: "+dat.toString());
................................................................................
            case 'dbBackup':    return dbBackup(id,dat.data);
            case 'dbRestore':   return dbRestore(id,dat.data);
            case 'dbRead':      return dbRead(id,dat.data);
            case 'dbAdd':       return dbAdd(id,dat.data);
            case 'fileBrowse':  return fileBrowse(id,dat.data);
            case 'exit':        DoExit(); break;
                
            default: LogDebug("unknown webmsg: "+dat.cmd); break;
        }
    }

    function cleanup() {
        LogDebug("Done!");
        if (self.optdbfile)
            delete self.optdb;







|







 







|







509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
...
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
    function WsOpen(ws:userobj, id:number)
    {
        var hdrs = self.ws.header(id);
        LogDebug('OPEN:', hdrs.keys(), "\n", hdrs);
        LogTrace('HDRS:', self.ws.header(id,'get '));
    }
        
    function WsRecv(ws:userobj, id:number, data:string)
    {
        var buf, buf0, buf1, buf2;
        LogDebug("SERVER GOT: "+ id +": "+data);
        if (self.debugging)
            debugger;
        var dat = JSON.parse(data);
        LogDebug("JSON: "+dat.toString());
................................................................................
            case 'dbBackup':    return dbBackup(id,dat.data);
            case 'dbRestore':   return dbRestore(id,dat.data);
            case 'dbRead':      return dbRead(id,dat.data);
            case 'dbAdd':       return dbAdd(id,dat.data);
            case 'fileBrowse':  return fileBrowse(id,dat.data);
            case 'exit':        DoExit(); break;
                
            default: LogWarn("unknown webmsg: "+data); break;
        }
    }

    function cleanup() {
        LogDebug("Done!");
        if (self.optdbfile)
            delete self.optdb;

Changes to lib/web/jsi.js.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
587
588
589
590
591
592
593








































594
595
596
597
598
599
600
...
604
605
606
607
608
609
610
611
612
613









614

615
616
617
618
619
620
621
622
623
624
625
626
// jsi.js:  Typed function arguments. https://jsish.org/jsig
// Implements  builtin typechecking (sans return types) in Jsi.

(function () {
"use strict";

if (window) {
    var LogDebug = function(){},
    LogTrace = function(){},
    LogTest = function(){},
    LogWarn = console.warn.bind(console),
    LogError = console.error.bind(console);
}

var config = {
    mode:'error', 
    disabled:false,
    insert:false,
    inline:false,
    onload:null
};
................................................................................
        return obj;
    },

    websock:function(prot) { // Create websocket connection.
        var url = document.URL.replace(/^http/,'ws').split('#')[0];
        return new WebSocket(url, (prot?prot:'ws'));
    },








































    
    _main: function(f) { // Startup.
        if (jsi.state.srcCnt>0) {
            LogDebug("waiting for src");
            setTimeout("$jsi._main()", 1000);
            return;
        }
................................................................................
    
        if (jsi.config.onload)
            jsi.config.onload();
    }

};

if (window) {
    window['$jsi'] = jsi;
    window['$jsig']= jsi.$jsig;









    

    if (typeof window['puts'] === 'undefined')
        window['puts'] = console.log.bind(console);    
    if (typeof window['$'] === 'undefined')
        window['$'] = $jsi.$;
    
    if (document.readyState !== 'loading')
        jsi._main();
    else
        document.addEventListener("DOMContentLoaded", function () {jsi._main();}, false); 
}

}());






<
<
<
<
<
<
<
<







 







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







 







<
|
|
>
>
>
>
>
>
>
>
>
|
>
|
|
|
|
|
|
|
|
|
|
<

1
2
3
4
5
6








7
8
9
10
11
12
13
...
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
...
636
637
638
639
640
641
642

643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665

666
// jsi.js:  Typed function arguments. https://jsish.org/jsig
// Implements  builtin typechecking (sans return types) in Jsi.

(function () {
"use strict";









var config = {
    mode:'error', 
    disabled:false,
    insert:false,
    inline:false,
    onload:null
};
................................................................................
        return obj;
    },

    websock:function(prot) { // Create websocket connection.
        var url = document.URL.replace(/^http/,'ws').split('#')[0];
        return new WebSocket(url, (prot?prot:'ws'));
    },
    
    $validate:function(msg, match) { //msg:object, match:string|array=void
        function typeGet(msg) {
            var tt = typeof(msg);
            if (tt !== 'object')
                return tt;
            var pat = '{', pre = '';
            for (var i in msg) {
                pat += pre + i + ':' + typeof(msg[i]);
                pre = ',';
            }
            pat += '}';
            return pat;
        }
        
        function mismatch(msg) {
            throw(msg);
        }
        var len = 1, i, pat = typeGet(msg);
        if (!match)
            return pat;
        if (typeof(match) === 'string') {
            if (pat !== match)
                mismatch('mismatch '+pat+' != '+match);
        } else {
            //assert(typeof(match) === 'array');
            len = match.length;
            if ((len%2)===1)
                throw('array len must be odd');
            var mat = match[0];
            if (pat !== match[0])
                mismatch('mismatch '+pat+' != '+mat);
            for (i=1; i<len; i+2) {
                mat = match[i+1];
                pat = typeGet(msg[match[i]]);
                if (pat !== mat)
                    mismatch('mismatch '+pat+' != '+mat);
            }
        }
    },
    
    _main: function(f) { // Startup.
        if (jsi.state.srcCnt>0) {
            LogDebug("waiting for src");
            setTimeout("$jsi._main()", 1000);
            return;
        }
................................................................................
    
        if (jsi.config.onload)
            jsi.config.onload();
    }

};


window['$jsi'] = jsi;
window['$jsig'] = jsi.$jsig;
window['$validate'] = jsi.$validate;
window.LogDebug = function(){};
window.LogTrace = function(){};
window.LogTest = function(){};
window.LogDebug = console.error.bind(console,'DEBUG: ');
window.LogTrace = console.warn.bind(console,'TRACE: ');
window.LogTest = console.error.bind(console,'TEST: ');
window.LogWarn = console.warn.bind(console,'WARN: ');
window.LogError = console.error.bind(console,'ERROR: ');


if (typeof window['puts'] === 'undefined')
    window['puts'] = console.log.bind(console);    
if (typeof window['$'] === 'undefined')
    window['$'] = $jsi.$;

if (document.readyState !== 'loading')
    jsi._main();
else
    document.addEventListener("DOMContentLoaded", function () {jsi._main();}, false); 


}());

Changes to md/Home.md.

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<polygon points="56,40 44,34.4 44,45.6 " style="stroke:none" transform="rotate(270,48,40 )"></polygon>
<g transform="translate(0,0)"><text text-anchor="middle" x="24" y="20">B</text><text text-anchor="middle" x="32" y="20">r</text><text text-anchor="middle" x="40" y="20">o</text><text text-anchor="middle" x="48" y="20">w</text><text text-anchor="middle" x="56" y="20">s</text><text text-anchor="middle" x="64" y="20">e</text><text text-anchor="middle" x="72" y="20">r</text><text text-anchor="middle" x="128" y="68">D</text><text text-anchor="middle" x="136" y="68">a</text><text text-anchor="middle" x="144" y="68">t</text><text text-anchor="middle" x="152" y="68">a</text><text text-anchor="middle" x="160" y="68">b</text><text text-anchor="middle" x="168" y="68">a</text><text text-anchor="middle" x="176" y="68">s</text><text text-anchor="middle" x="184" y="68">e</text><text text-anchor="middle" x="32" y="116">J</text><text text-anchor="middle" x="40" y="116">s</text><text text-anchor="middle" x="48" y="116">i</text><text text-anchor="middle" x="56" y="116">s</text><text text-anchor="middle" x="64" y="116">h</text><text text-anchor="middle" x="136" y="116">S</text><text text-anchor="middle" x="144" y="116">c</text><text text-anchor="middle" x="152" y="116">r</text><text text-anchor="middle" x="160" y="116">i</text><text text-anchor="middle" x="168" y="116">p</text><text text-anchor="middle" x="176" y="116">t</text><text text-anchor="middle" x="144" y="132">F</text><text text-anchor="middle" x="152" y="132">i</text><text text-anchor="middle" x="160" y="132">l</text><text text-anchor="middle" x="168" y="132">e</text><text text-anchor="middle" x="32" y="148">Z</text><text text-anchor="middle" x="40" y="148">V</text><text text-anchor="middle" x="48" y="148">F</text><text text-anchor="middle" x="56" y="148">S</text></g></g></svg>

</td>

<td>
<a href="https://jsish.org">
<img src="../www/site/logojsi_dark2.png" style="vertical-align:middle" class="spinimg"></a>
<span style="border-bottom:1px solid"> Javascript interpreter + embedded Web-server</span>
<ul>
<li><a href="Types.md">Typed function-parameters</a>.</li>
<li><a href="Builtins.md#Zvfs">Zvfs integrated scripts</a> for extended functionality.</li>
<li><a href="Download.md#Embedding">Embed in <b>C</b> programs</a> using only <b>#include</b>.</li>
<li>WebSockets, Sqlite and other common prerequisites built-in.</li>
</ul>







|







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<polygon points="56,40 44,34.4 44,45.6 " style="stroke:none" transform="rotate(270,48,40 )"></polygon>
<g transform="translate(0,0)"><text text-anchor="middle" x="24" y="20">B</text><text text-anchor="middle" x="32" y="20">r</text><text text-anchor="middle" x="40" y="20">o</text><text text-anchor="middle" x="48" y="20">w</text><text text-anchor="middle" x="56" y="20">s</text><text text-anchor="middle" x="64" y="20">e</text><text text-anchor="middle" x="72" y="20">r</text><text text-anchor="middle" x="128" y="68">D</text><text text-anchor="middle" x="136" y="68">a</text><text text-anchor="middle" x="144" y="68">t</text><text text-anchor="middle" x="152" y="68">a</text><text text-anchor="middle" x="160" y="68">b</text><text text-anchor="middle" x="168" y="68">a</text><text text-anchor="middle" x="176" y="68">s</text><text text-anchor="middle" x="184" y="68">e</text><text text-anchor="middle" x="32" y="116">J</text><text text-anchor="middle" x="40" y="116">s</text><text text-anchor="middle" x="48" y="116">i</text><text text-anchor="middle" x="56" y="116">s</text><text text-anchor="middle" x="64" y="116">h</text><text text-anchor="middle" x="136" y="116">S</text><text text-anchor="middle" x="144" y="116">c</text><text text-anchor="middle" x="152" y="116">r</text><text text-anchor="middle" x="160" y="116">i</text><text text-anchor="middle" x="168" y="116">p</text><text text-anchor="middle" x="176" y="116">t</text><text text-anchor="middle" x="144" y="132">F</text><text text-anchor="middle" x="152" y="132">i</text><text text-anchor="middle" x="160" y="132">l</text><text text-anchor="middle" x="168" y="132">e</text><text text-anchor="middle" x="32" y="148">Z</text><text text-anchor="middle" x="40" y="148">V</text><text text-anchor="middle" x="48" y="148">F</text><text text-anchor="middle" x="56" y="148">S</text></g></g></svg>

</td>

<td>
<a href="https://jsish.org">
<img src="../www/site/logojsi.png" style="vertical-align:middle" class="spinimg"></a>
<span style="border-bottom:1px solid"> Javascript interpreter + embedded Web-server</span>
<ul>
<li><a href="Types.md">Typed function-parameters</a>.</li>
<li><a href="Builtins.md#Zvfs">Zvfs integrated scripts</a> for extended functionality.</li>
<li><a href="Download.md#Embedding">Embed in <b>C</b> programs</a> using only <b>#include</b>.</li>
<li>WebSockets, Sqlite and other common prerequisites built-in.</li>
</ul>

Changes to src/jsiCmds.c.

1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805

1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
....
2049
2050
2051
2052
2053
2054
2055
2056




2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067





2068
2069
2070
2071
2072
2073
2074
....
3696
3697
3698
3699
3700
3701
3702

























































































3703
3704
3705
3706
3707
3708
3709
....
4640
4641
4642
4643
4644
4645
4646

4647
4648
4649
4650
4651
4652
4653
            rv = Jsi_LogError("%s", msg);
    }
    Jsi_ValueMakeUndef(interp, ret);
    return rv;
}

typedef struct {
    bool utc, secs;
    const char *fmt;
} DateOpts;

static Jsi_OptionSpec DateOptions[] = {
    JSI_OPT(BOOL,   DateOpts, secs, .help="Time is seconds (out for parse, in for format)" ),
    JSI_OPT(STRKEY, DateOpts, fmt, .help="Format string for time" ),

    JSI_OPT(BOOL,   DateOpts, utc, .help="Time is utc (in for parse, out for format)" ),
    JSI_OPT_END(DateOpts, .help="Date options")
};

static const char *timeFmts[] = {
    "%Y-%m-%d %H:%M:%S",
    "%Y-%m-%dT%H:%M:%S",
    "%Y-%m-%d %H:%M:%S",
    "%Y-%m-%d %H:%M",
    "%Y-%m-%dT%H:%M",
    "%Y-%m-%d",
    "%H:%M:%S",
    "%H:%M",
    "%c",
    NULL
................................................................................
    Jsi_Number num;
    int isOpt = 0;
    Jsi_RC rc = JSI_OK;
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    
    if (val==NULL || Jsi_ValueIsNull(interp, val)) {
        num = 1000.0 * (Jsi_Number)time(NULL);




   /* } else if ((cp=Jsi_ValueString(interp, val, NULL))) {*/
        /* Handle below */
    } else if (Jsi_GetDoubleFromValue(interp, val, &num) != JSI_OK)
        return JSI_ERROR;
        
    if (opt != NULL && opt->vt != JSI_VT_NULL && !(fmt = Jsi_ValueString(interp, opt, NULL))) {
        if (Jsi_OptionsProcess(interp, DateOptions, &opts, opt, 0) < 0) {
            return JSI_ERROR;
        }
        isOpt = 1;
        fmt = opts.fmt;





    }
    const char *errMsg = "time format error";
/*    if (cp) {
        if (isdigit(*cp))
            rc = Jsi_GetDouble(interp, cp, &num);
        else {
            if (Jsi_Strcmp(cp,"now")==0) {
................................................................................
            return JSI_OK;
        }
    }
bail:
    Jsi_ValueMakeNull(interp, ret);
    return JSI_OK;
}


























































































static Jsi_RC SysTimesCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_RC rc = JSI_OK;
    int i, n=1, argc = Jsi_ValueGetLength(interp, args);
    Jsi_Value *func = Jsi_ValueArrayIndex(interp, args, 0);
................................................................................
    { "times",      SysTimesCmd,     1,  2, "callback:function|boolean, count:number=1", .help="Call function count times and return execution time in microseconds", .retType=(uint)JSI_TT_NUMBER },
#ifndef JSI_OMIT_LOAD
    { "unload",     jsi_LoadUnloadCmd, 1, 1,  "shlib:string", .help="Unload a shared executable and invoke its _Done call", .retType=(uint)JSI_TT_VOID },
#endif
#ifndef JSI_OMIT_EVENT
    { "update",     SysUpdateCmd,    0,  1, "options:number|object=void", .help="Service all events, eg. setInterval/setTimeout", .retType=(uint)JSI_TT_NUMBER, .flags=0, .info=FN_update, .opts=jsiUpdateOptions },
#endif

    { NULL, 0,0,0,0, .help="Builtin system commands. All methods are exported as global" }
};

Jsi_RC jsi_InitCmds(Jsi_Interp *interp, int release)
{
    if (release) return JSI_OK;
    interp->console = Jsi_CommandCreateSpecs(interp, "console", consoleCmds, NULL, 0);







|






>







<







 







|
>
>
>
>











>
>
>
>
>







 







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







 







>







1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813

1814
1815
1816
1817
1818
1819
1820
....
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
....
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
....
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
            rv = Jsi_LogError("%s", msg);
    }
    Jsi_ValueMakeUndef(interp, ret);
    return rv;
}

typedef struct {
    bool utc, secs, iso;
    const char *fmt;
} DateOpts;

static Jsi_OptionSpec DateOptions[] = {
    JSI_OPT(BOOL,   DateOpts, secs, .help="Time is seconds (out for parse, in for format)" ),
    JSI_OPT(STRKEY, DateOpts, fmt, .help="Format string for time" ),
    JSI_OPT(BOOL,   DateOpts, iso, .help="ISO fmt plus milliseconds ie: %FT%T.%f" ),
    JSI_OPT(BOOL,   DateOpts, utc, .help="Time is utc (in for parse, out for format)" ),
    JSI_OPT_END(DateOpts, .help="Date options")
};

static const char *timeFmts[] = {
    "%Y-%m-%d %H:%M:%S",
    "%Y-%m-%dT%H:%M:%S",

    "%Y-%m-%d %H:%M",
    "%Y-%m-%dT%H:%M",
    "%Y-%m-%d",
    "%H:%M:%S",
    "%H:%M",
    "%c",
    NULL
................................................................................
    Jsi_Number num;
    int isOpt = 0;
    Jsi_RC rc = JSI_OK;
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    
    if (val==NULL || Jsi_ValueIsNull(interp, val)) {
        //num = 1000.0 * (Jsi_Number)time(NULL);
        struct timeval tv;
        gettimeofday(&tv, NULL);
        num = tv.tv_sec*1000LL + ((Jsi_Wide)tv.tv_usec)/1000LL;

   /* } else if ((cp=Jsi_ValueString(interp, val, NULL))) {*/
        /* Handle below */
    } else if (Jsi_GetDoubleFromValue(interp, val, &num) != JSI_OK)
        return JSI_ERROR;
        
    if (opt != NULL && opt->vt != JSI_VT_NULL && !(fmt = Jsi_ValueString(interp, opt, NULL))) {
        if (Jsi_OptionsProcess(interp, DateOptions, &opts, opt, 0) < 0) {
            return JSI_ERROR;
        }
        isOpt = 1;
        fmt = opts.fmt;
        if (opts.iso) {
            if (fmt)
                return Jsi_LogError("Do not use both iso and fmt");
            fmt = "%FT%T.%f";
        }
    }
    const char *errMsg = "time format error";
/*    if (cp) {
        if (isdigit(*cp))
            rc = Jsi_GetDouble(interp, cp, &num);
        else {
            if (Jsi_Strcmp(cp,"now")==0) {
................................................................................
            return JSI_OK;
        }
    }
bail:
    Jsi_ValueMakeNull(interp, ret);
    return JSI_OK;
}

static void jsi_sysTypeGet(Jsi_Interp *interp, Jsi_Value *arg, Jsi_DString *dStr) {
    Jsi_DSFree(dStr);
    if (!Jsi_ValueIsObjType(interp, arg, JSI_OT_OBJECT)) {
        Jsi_DSAppend(dStr, jsi_ValueTypeName(interp, arg), NULL);
        return;
    }
    uint i;
    const char *pre = "";
    Jsi_DSAppend(dStr, "{", NULL);
    Jsi_IterObj *io = jsi_IterObjNew(interp, NULL);
    jsi_IterGetKeys(interp, arg, io, 0);
    for (i=0; i<io->count; i++) {
        Jsi_Value *targ = Jsi_ValueObjLookup(interp, arg, io->keys[i], true);
        Jsi_DSAppend(dStr, pre, io->keys[i], ":", jsi_ValueTypeName(interp, targ), NULL);
        pre = ",";
    }
    Jsi_DSAppend(dStr, "}", NULL);
    jsi_IterObjFree(io);
}

static Jsi_RC SysValidateCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    bool ok = 1;
    Jsi_Value *arg1 = Jsi_ValueArrayIndex(interp, args, 0);
    if (!arg1 || !Jsi_ValueIsObjType(interp, arg1, JSI_OT_OBJECT))
        return Jsi_LogError("arg 1: exected object");
    Jsi_Value *targ, *argn, *arg2 = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    if (!arg2) {
        jsi_sysTypeGet(interp, arg1, &dStr);
        Jsi_ValueMakeStringDup(interp, ret, Jsi_DSValue(&dStr));
        Jsi_DSFree(&dStr);
        return JSI_OK;
    }
    Jsi_RC rc = JSI_OK;
    int argc = 0, i;
    jsi_sysTypeGet(interp, arg1, &dStr);
    char *sp = Jsi_ValueString(interp, arg2, NULL), *cp = Jsi_DSValue(&dStr);
    if (sp) {
        if (Jsi_Strcmp(cp, sp)) {
mismatch:
            ok = 0;
            rc = Jsi_LogType("mismatch: '%s' != '%s'", cp, sp);
        }
        goto done;
    }
    if (!Jsi_ValueIsArray(interp, arg2))
        return Jsi_LogError("arg 2: exected string|array");
    argc = Jsi_ValueGetLength(interp, arg2);
    if ((argc%2) != 1) {
        rc = Jsi_LogError("array length must be odd");
        goto done;
    }
    argn = Jsi_ValueArrayIndex(interp, arg2, 0);
    sp = Jsi_ValueString(interp, argn, NULL);
    if (!sp)
        goto badstr;
    for (i=1; i<argc; i+=2) {
        argn = Jsi_ValueArrayIndex(interp, arg2, i);
        sp = Jsi_ValueString(interp, argn, NULL);
        if (!sp)
            goto badstr;
        targ = Jsi_ValueObjLookup(interp, arg1, sp, true);
        if (!targ) {
            rc = Jsi_LogType("object lookup failed: %s", sp);
            goto done;
        }
        argn = Jsi_ValueArrayIndex(interp, arg2, i+1);
        sp = Jsi_ValueString(interp, argn, NULL);
        if (!sp)
            goto badstr;
        jsi_sysTypeGet(interp, targ, &dStr);
        cp = Jsi_DSValue(&dStr);
        if (Jsi_Strcmp(cp, sp))
            goto mismatch;
    }
done:
    Jsi_DSFree(&dStr);
    Jsi_ValueMakeBool(interp, ret, ok);
    return rc;
    
badstr:
    Jsi_DSFree(&dStr);
    return Jsi_LogError("array elements must be a string");

}

static Jsi_RC SysTimesCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_RC rc = JSI_OK;
    int i, n=1, argc = Jsi_ValueGetLength(interp, args);
    Jsi_Value *func = Jsi_ValueArrayIndex(interp, args, 0);
................................................................................
    { "times",      SysTimesCmd,     1,  2, "callback:function|boolean, count:number=1", .help="Call function count times and return execution time in microseconds", .retType=(uint)JSI_TT_NUMBER },
#ifndef JSI_OMIT_LOAD
    { "unload",     jsi_LoadUnloadCmd, 1, 1,  "shlib:string", .help="Unload a shared executable and invoke its _Done call", .retType=(uint)JSI_TT_VOID },
#endif
#ifndef JSI_OMIT_EVENT
    { "update",     SysUpdateCmd,    0,  1, "options:number|object=void", .help="Service all events, eg. setInterval/setTimeout", .retType=(uint)JSI_TT_NUMBER, .flags=0, .info=FN_update, .opts=jsiUpdateOptions },
#endif
    { "validate",   SysValidateCmd,  1,  2, "msg:object, match:string|array=void", .help="Verify/generate object field name/type match", .retType=(uint)JSI_TT_BOOLEAN|JSI_TT_STRING  },
    { NULL, 0,0,0,0, .help="Builtin system commands. All methods are exported as global" }
};

Jsi_RC jsi_InitCmds(Jsi_Interp *interp, int release)
{
    if (release) return JSI_OK;
    interp->console = Jsi_CommandCreateSpecs(interp, "console", consoleCmds, NULL, 0);

Changes to src/jsiInt.h.

1501
1502
1503
1504
1505
1506
1507

1508
1509
1510
1511
1512
1513
1514
extern Jsi_RC jsi_FuncArgsToString(Jsi_Interp *interp, Jsi_Func *f, Jsi_DString *dStr, int flags);
extern Jsi_Value *jsi_LoadFunction(Jsi_Interp *interp, const char *str, Jsi_Value *tret);
extern Jsi_RC jsi_SysExecCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr, bool restricted);

extern Jsi_IterObj *jsi_IterObjNew(Jsi_Interp *interp, Jsi_IterProc *iterProc);
extern void jsi_IterObjFree(Jsi_IterObj *iobj);

extern Jsi_FuncObj *jsi_FuncObjNew(Jsi_Interp *interp, Jsi_Func *func);
extern void jsi_FuncObjFree(Jsi_FuncObj *fobj);
extern Jsi_RC jsi_ArglistFree(Jsi_Interp *interp, Jsi_HashEntry *hPtr, void *ptr);
extern void jsi_FuncFree(Jsi_Interp *interp, Jsi_Func *func);
extern void jsi_ToHexStr(const uchar *indata, int dlen, char *out);
extern bool jsi_StrIsBalanced(char *str);








>







1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
extern Jsi_RC jsi_FuncArgsToString(Jsi_Interp *interp, Jsi_Func *f, Jsi_DString *dStr, int flags);
extern Jsi_Value *jsi_LoadFunction(Jsi_Interp *interp, const char *str, Jsi_Value *tret);
extern Jsi_RC jsi_SysExecCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr, bool restricted);

extern Jsi_IterObj *jsi_IterObjNew(Jsi_Interp *interp, Jsi_IterProc *iterProc);
extern void jsi_IterObjFree(Jsi_IterObj *iobj);
extern void jsi_IterGetKeys(Jsi_Interp *interp, Jsi_Value *target, Jsi_IterObj *iterobj, int depth);
extern Jsi_FuncObj *jsi_FuncObjNew(Jsi_Interp *interp, Jsi_Func *func);
extern void jsi_FuncObjFree(Jsi_FuncObj *fobj);
extern Jsi_RC jsi_ArglistFree(Jsi_Interp *interp, Jsi_HashEntry *hPtr, void *ptr);
extern void jsi_FuncFree(Jsi_Interp *interp, Jsi_Func *func);
extern void jsi_ToHexStr(const uchar *indata, int dlen, char *out);
extern bool jsi_StrIsBalanced(char *str);

Changes to src/jsiSqlite.c.

3590
3591
3592
3593
3594
3595
3596

3597
3598
3599
3600
3601
3602
3603
....
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
    Jsi_Value *arg = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_DString dStr = {};
    int ismem = 0;
    Jsi_Obj *fobj;
    Jsi_Value *toacc;
    const char *vf;
    int aflag;

    
    if (vFile==NULL || Jsi_ValueIsNull(interp, vFile) ||
        ((vf = Jsi_ValueString(interp, vFile, NULL)) && !Jsi_Strcmp(vf,":memory:"))) {
        zFile = ":memory:";
        ismem = 1;
    } else {
        zFile = Jsi_ValueNormalPath(interp, vFile, &dStr);
................................................................................
    db->stmtHash = Jsi_HashNew(interp, JSI_KEYS_STRING, NULL);
    db->fobj = fobj;
    //dbSys->cnt = Jsi_UserObjCreate(interp, sqliteobject.name /*dbSys*/, fobj, db);
    db->interp = interp;
    db->optPtr = &db->queryOpts;
    db->stmtCache = Jsi_ListNew((Jsi_Interp*)db, 0, dbStmtFreeProc);
    rc = JSI_OK;
    const char *dbname = Jsi_DSValue(&db->name);
    if (dbname[0])
        sqlite3_db_config(db->db, SQLITE_DBCONFIG_MAINDBNAME, dbname);
    Jsi_JSONParseFmt(interp, &db->version, "{libVer:\"%s\", hdrVer:\"%s\", hdrNum:%d, hdrSrcId:\"%s\", pkgVer:%d}",
        (char *)sqlite3_libversion(), SQLITE_VERSION, SQLITE_VERSION_NUMBER, SQLITE_SOURCE_ID, jsi_DbPkgVersion); 
    dbSetupCallbacks(db, NULL);
    
bail:







>







 







|







3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
....
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
    Jsi_Value *arg = Jsi_ValueArrayIndex(interp, args, 1);
    Jsi_DString dStr = {};
    int ismem = 0;
    Jsi_Obj *fobj;
    Jsi_Value *toacc;
    const char *vf;
    int aflag;
    const char *dbname = NULL;
    
    if (vFile==NULL || Jsi_ValueIsNull(interp, vFile) ||
        ((vf = Jsi_ValueString(interp, vFile, NULL)) && !Jsi_Strcmp(vf,":memory:"))) {
        zFile = ":memory:";
        ismem = 1;
    } else {
        zFile = Jsi_ValueNormalPath(interp, vFile, &dStr);
................................................................................
    db->stmtHash = Jsi_HashNew(interp, JSI_KEYS_STRING, NULL);
    db->fobj = fobj;
    //dbSys->cnt = Jsi_UserObjCreate(interp, sqliteobject.name /*dbSys*/, fobj, db);
    db->interp = interp;
    db->optPtr = &db->queryOpts;
    db->stmtCache = Jsi_ListNew((Jsi_Interp*)db, 0, dbStmtFreeProc);
    rc = JSI_OK;
    dbname = Jsi_DSValue(&db->name);
    if (dbname[0])
        sqlite3_db_config(db->db, SQLITE_DBCONFIG_MAINDBNAME, dbname);
    Jsi_JSONParseFmt(interp, &db->version, "{libVer:\"%s\", hdrVer:\"%s\", hdrNum:%d, hdrSrcId:\"%s\", pkgVer:%d}",
        (char *)sqlite3_libversion(), SQLITE_VERSION, SQLITE_VERSION_NUMBER, SQLITE_SOURCE_ID, jsi_DbPkgVersion); 
    dbSetupCallbacks(db, NULL);
    
bail:

Changes to src/jsiValue.c.

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
....
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
....
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
....
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
....
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
#include "jsiInt.h"
#endif

#define bits_set(who, mask)     ((who) |= (mask))
#define bits_unset(who, mask)   ((who) &= (~(mask)))
#define bits_get(who, mask)     ((who) & (mask))

static void IterGetKeys(Jsi_Interp *interp, Jsi_Value *target, Jsi_IterObj *iterobj, int depth);

#if  JSI__MEMDEBUG
void jsi_VALCHK(Jsi_Value *val) {
    SIGASSERTV(val,VALUE);
    assert(val->vt <= JSI_VT__MAX);
    if (val->vt == JSI_VT_OBJECT)
        OBJCHK(val->d.obj);
}
................................................................................

        if (target->vt == JSI_VT_OBJECT && to->arr) {
            io->isArrayList = 1;
            io->count = to->arrCnt;
        } else {
            if (isof &&interp->strict)
                Jsi_LogWarn("non-array in 'for...of'");
            IterGetKeys(interp, target, io, 0);
        }
    }
    io->obj = to;
    io->isof = isof;
    Jsi_Obj *r = Jsi_ObjNew(interp);
    r->ot = JSI_OT_ITER;
    r->d.iobj = io;
................................................................................
                n++;
            }
        }
        r->arrCnt = n;
        return JSI_OK;
    }
    io = jsi_IterObjNew(interp, NULL);
    IterGetKeys(interp, target, io, 0);
    if (Jsi_ObjArraySizer(interp, r, io->count) <= 0) {
        Jsi_LogError("too long");
        Jsi_ValueMakeUndef(interp, &ret);
        return JSI_ERROR;
    }
    for (i=0; i<io->count; i++) {
        r->arr[i] = (io->keys[i] ? Jsi_ValueNewStringKey(interp, io->keys[i]) : NULL);
................................................................................
    Jsi_IterObj *io = (Jsi_IterObj *)data;
    if (!hPtr->f.bits.dontenum) {
        IterObjInsert(io, hPtr);
    }
    return JSI_OK;
}

static void IterGetKeys(Jsi_Interp *interp, Jsi_Value *target, Jsi_IterObj *iterobj, int depth)
{
    if (!target) return;
    if (target->vt != JSI_VT_OBJECT) {
        if (interp->strict)
            Jsi_LogWarn("operand is not a object");
        return;
    }
................................................................................
            cs++;
        }
        return;
    }
    iterobj->depth = depth;
    Jsi_TreeWalk(target->d.obj->tree, IterGetKeysCallback, iterobj, 0);
    if (target->d.obj->__proto__ && target != target->d.obj->__proto__)
        IterGetKeys(interp, target->d.obj->__proto__, iterobj, depth+1);
    iterobj->depth = depth;
}

Jsi_Value* Jsi_ValueMakeDStringObject(Jsi_Interp *interp, Jsi_Value **vPtr, Jsi_DString *dsPtr)  {
    Jsi_Value *v = (vPtr?*vPtr:NULL);
    Jsi_Obj *obj;
    if (!v)







<
<







 







|







 







|







 







|







 







|







3
4
5
6
7
8
9


10
11
12
13
14
15
16
....
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
....
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
....
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
....
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
#include "jsiInt.h"
#endif

#define bits_set(who, mask)     ((who) |= (mask))
#define bits_unset(who, mask)   ((who) &= (~(mask)))
#define bits_get(who, mask)     ((who) & (mask))



#if  JSI__MEMDEBUG
void jsi_VALCHK(Jsi_Value *val) {
    SIGASSERTV(val,VALUE);
    assert(val->vt <= JSI_VT__MAX);
    if (val->vt == JSI_VT_OBJECT)
        OBJCHK(val->d.obj);
}
................................................................................

        if (target->vt == JSI_VT_OBJECT && to->arr) {
            io->isArrayList = 1;
            io->count = to->arrCnt;
        } else {
            if (isof &&interp->strict)
                Jsi_LogWarn("non-array in 'for...of'");
            jsi_IterGetKeys(interp, target, io, 0);
        }
    }
    io->obj = to;
    io->isof = isof;
    Jsi_Obj *r = Jsi_ObjNew(interp);
    r->ot = JSI_OT_ITER;
    r->d.iobj = io;
................................................................................
                n++;
            }
        }
        r->arrCnt = n;
        return JSI_OK;
    }
    io = jsi_IterObjNew(interp, NULL);
    jsi_IterGetKeys(interp, target, io, 0);
    if (Jsi_ObjArraySizer(interp, r, io->count) <= 0) {
        Jsi_LogError("too long");
        Jsi_ValueMakeUndef(interp, &ret);
        return JSI_ERROR;
    }
    for (i=0; i<io->count; i++) {
        r->arr[i] = (io->keys[i] ? Jsi_ValueNewStringKey(interp, io->keys[i]) : NULL);
................................................................................
    Jsi_IterObj *io = (Jsi_IterObj *)data;
    if (!hPtr->f.bits.dontenum) {
        IterObjInsert(io, hPtr);
    }
    return JSI_OK;
}

void jsi_IterGetKeys(Jsi_Interp *interp, Jsi_Value *target, Jsi_IterObj *iterobj, int depth)
{
    if (!target) return;
    if (target->vt != JSI_VT_OBJECT) {
        if (interp->strict)
            Jsi_LogWarn("operand is not a object");
        return;
    }
................................................................................
            cs++;
        }
        return;
    }
    iterobj->depth = depth;
    Jsi_TreeWalk(target->d.obj->tree, IterGetKeysCallback, iterobj, 0);
    if (target->d.obj->__proto__ && target != target->d.obj->__proto__)
        jsi_IterGetKeys(interp, target->d.obj->__proto__, iterobj, depth+1);
    iterobj->depth = depth;
}

Jsi_Value* Jsi_ValueMakeDStringObject(Jsi_Interp *interp, Jsi_Value **vPtr, Jsi_DString *dsPtr)  {
    Jsi_Value *v = (vPtr?*vPtr:NULL);
    Jsi_Obj *obj;
    if (!v)