/ Check-in [5128793be7]
DEMO | DOWNLOAD | DEPLOY | SEARCH
Login

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

Overview
Comment:Release "2.8.34" UTF null fixes. Introduce jsig.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:5128793be74325beef35774ea4abbdb529c97b9b
User & Date: pmacdona 2019-06-01 03:41:43
Context
2019-06-01
14:17
More jsiweb -> jsig changes. check-in: 8c1c2dd67c user: pmacdona tags: trunk
03:41
Release "2.8.34" UTF null fixes. Introduce jsig. check-in: 5128793be7 user: pmacdona tags: trunk
2019-05-31
14:37
Fix str add with embedded null. check-in: 593072fb9a user: pmacdona tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to js-demos/wspage.html.

1

2
3
4
5
6
7
8
<!-- USAGE: "jsish -W wsdemo.html" -->

<html>
<body onload='DoInit()' >
Minimal web page using websockets
<p />

<input id="myinput" size=30></input>
<!-- <img src="/jsitechno2.png"> -->

>







1
2
3
4
5
6
7
8
9
<!-- USAGE: "jsish -W wsdemo.html" -->
<!DOCTYPE html>
<html>
<body onload='DoInit()' >
Minimal web page using websockets
<p />

<input id="myinput" size=30></input>
<!-- <img src="/jsitechno2.png"> -->

Changes to lib/Jsi_DebugUI/html/debugui.jsi.

251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
        rr += "<button onclick='scrollToLine("+r[1]+")'>"+r[0]+ '</button>';
    }
    rr += '<br>';
    id.innerHTML = rr;
}

// Toggle sub-display and change +/- suffix.
function TogglePanel(cmd:string, parent:object|undefined) {
    var id = $$('#'+cmd);
    var och = '-', nch = '+';
    var isvis = (id.style.display !== 'none');
    if  (isvis) {
        id.style.display = 'none';
    } else {
        nch = '-'; och = '+';







|







251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
        rr += "<button onclick='scrollToLine("+r[1]+")'>"+r[0]+ '</button>';
    }
    rr += '<br>';
    id.innerHTML = rr;
}

// Toggle sub-display and change +/- suffix.
function TogglePanel(cmd:string, parent:object|null) {
    var id = $$('#'+cmd);
    var och = '-', nch = '+';
    var isvis = (id.style.display !== 'none');
    if  (isvis) {
        id.style.display = 'none';
    } else {
        nch = '-'; och = '+';

Changes to lib/Jsi_DebugUI/html/main.htmli.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html style="height: 100%">
  <head>
    <meta charset=utf-8 />
    <title>DebugUI</title>
    <link rel="icon" href="data:;base64,iVBORw0KGgo=">

    <script src="/jsi/web/jsiweb.js"></script>
    <script src="/jsi/web/bind.js"></script>
<? 
    // Load .jsi and .cssi for preprocessing inline.
    include(['debugui.jsi', 'debugui.cssi']);
?>
  </head>
  <body id="body" onload="onload()" style="display: flex; height: 97%; flex-direction: column; margin:3px">







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html style="height: 100%">
  <head>
    <meta charset=utf-8 />
    <title>DebugUI</title>
    <link rel="icon" href="data:;base64,iVBORw0KGgo=">

    <script src="/jsi/web/jsig.js"></script>
    <script src="/jsi/web/bind.js"></script>
<? 
    // Load .jsi and .cssi for preprocessing inline.
    include(['debugui.jsi', 'debugui.cssi']);
?>
  </head>
  <body id="body" onload="onload()" style="display: flex; height: 97%; flex-direction: column; margin:3px">

Changes to lib/Jsi_Jspp.jsi.

17
18
19
20
21
22
23

24
25
26
27
28
29
30
..
32
33
34
35
36
37
38

39
40
41
42
43
44
45
46
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
73
74
75
76
..
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107


108
109
110
111
112
113
114
115
116

117
118
119
120
121
122
123
124

125
126
127
128
129
130
131
...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

function Jsi_Jspp(files:array|string=null, conf:object=undefined):string|object
{
    var options = { // A JS preprocessor to convert "typed" functions out to web-browser compatible form
        checkRet    :false,     // Check return code by creating wrapper functions
        disable     :false,     // Preprocess to vanilla JS. WARNING: use of default values may break things.
        listFuncs   :false,     // Echo function list.

        noCheck     :false      // Disable argument type checking.
    };
    var self = {
        funcLst:[],         // List of functions
        funcIdx:0,          // Func idx.
        curFile:'',         // Current file being processed.
        tail:''             // Basename of file.
................................................................................
 
    parseOpts(self, options, conf);

    self.typeNameStr = "number string boolean array function object regexp any userobj void null undefined";
    self.typeNameList = self.typeNameStr.split(' ');
    
    function typeValidate(typ) {

        var tlst = typ.split('|');
        var i = -1;
        for (i = 0; i<tlst.length; i++)
            if (self.typeNameList.indexOf(tlst[i]) < 0)
                throw "type unknown '"+tlst[i]+'" not one of: '+self.typeNameStr;
        return tlst;
    }
  
    function reMethod(str:string) {
        var reg = /^function\s*([a-zA-Z0-9_]*)\s*\(([^)]*)\)(:[\|a-z]+|)\s*\{$/;
        var vals = reg.exec(str);
        if (!vals)
            throw "invalid method: "+str;
        //puts(vals);
        var fnam = vals[1];
        if (fnam !== '' && fnam[0] !== '_')
            self.funcLst.push(fnam);
        var someDef = str.indexOf('=')>=0;
        if (str.indexOf(':')<0 && !someDef) // Skip functions with no types or defaults
            return str;
        var res = 'function '+fnam+'(';
    
        var astr = vals[2].trim();




        var cres = '/* Fn('+astr+') */ ';
        var acall = [];
        if (astr !== '') {
            var alst = astr.split(',');
            var minargs = alst.length, maxargs = minargs;
            var last = alst.length-1;
            if (!someDef)
                cres += 'Jsi.CheckFunc("'+fnam+'",'+minargs+','+maxargs+', arguments.length';
            for (var i = 0; i<=last; i++) {
                var aval = alst[i].trim();
                if (aval === '...') {
                    if (i != last)
                        throw "expected ... to be at end";
                    maxargs = -1;
                    continue;
................................................................................
                if (i)
                    res += ', ';
                var afnam = avals[1];
                if (afnam === '' || avals.length<3)
                    afnam = aval;
                res += afnam;
                acall.push(afnam);
                var defval, atyp = '';
                if (avals.length>2)
                    atyp = avals[2].substr(1);
                if (atyp !== '')
                    typeValidate(atyp);
                if (!someDef) {
                    cres += ', "'+afnam+'",'+afnam+',"'+atyp+'"';
                } else {
    

                    var hasDef = (avals[3] && avals[3] !== '');
                    if (hasDef)
                        cres += '  '+afnam+'=';
                    cres += 'Jsi.ArgCheck('+(i+1)+',"'+fnam+'","'+afnam+'",'+afnam+',"'+atyp+'"';
                    if (hasDef) { // Default value
                        if (avals[3] === '=void') {
                            defval = 'undefined';
                        } else {
                            defval = avals[3].substr(1);


                        }
                        cres += ','+ defval;
                        if (minargs===alst.length)
                            minargs = i;
                    }
                    else if (minargs!==alst.length)
                        throw "non-default value follows default: "+aval+' in: '+str;
                    cres += ');';
                }

            }
            if (someDef)
                cres += '  Jsi.ArgCount("'+fnam+'",'+minargs+','+maxargs+',arguments.length); ';
            else
                cres += ');';
        }
        res += ') { ';
        var rettyp = vals[3].substr(1);

        if (fnam !== '' && rettyp !== '' && rettyp !== 'any' && self.checkRet) {
            typeValidate(rettyp);
            var wfn = '__Jsi_WrapRet_'+self.tail+'_'+fnam+'_'+ ++self.funcIdx;
            cres += '  var __ret = '+wfn+'('+acall.join(',')+');\n';
            cres += '  Jsi.RetCheck("'+fnam+'",'+' __ret,"'+rettyp+'");\n  return __ret;\n}\n';
            cres += 'function '+wfn+'('+acall.join(', ')+') {';
        }
................................................................................
        }
        if (self.listFuncs) {
            rc = '';
            var n = 0;
            for (i of self.funcLst.sort())
                rc += i + ':' + i + (++n === self.funcLst.length ? '' : ',') + '\n';
        }
        return rc;
    }
    if (files)
        return parse(files);

    self.parse = parse;
    return self;
}

provide(Jsi_Jspp, 1);

if (isMain()) 
    runModule(Jsi_Jspp);








>







 







>









|







|
|




>
>
>
>
|





|
<







 







|


<
|
<
<
<
|
>

<
<
<

|

|

>
>
|
<





<

>

|
|
<
<

|
<
>







 







|













17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
..
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
73
74

75
76
77
78
79
80
81
..
88
89
90
91
92
93
94
95
96
97

98



99
100
101



102
103
104
105
106
107
108
109

110
111
112
113
114

115
116
117
118
119


120
121

122
123
124
125
126
127
128
129
...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165

function Jsi_Jspp(files:array|string=null, conf:object=undefined):string|object
{
    var options = { // A JS preprocessor to convert "typed" functions out to web-browser compatible form
        checkRet    :false,     // Check return code by creating wrapper functions
        disable     :false,     // Preprocess to vanilla JS. WARNING: use of default values may break things.
        listFuncs   :false,     // Echo function list.
        inline      :false,     // Inline signature parse.
        noCheck     :false      // Disable argument type checking.
    };
    var self = {
        funcLst:[],         // List of functions
        funcIdx:0,          // Func idx.
        curFile:'',         // Current file being processed.
        tail:''             // Basename of file.
................................................................................
 
    parseOpts(self, options, conf);

    self.typeNameStr = "number string boolean array function object regexp any userobj void null undefined";
    self.typeNameList = self.typeNameStr.split(' ');
    
    function typeValidate(typ) {
        if (typ === '') return [];
        var tlst = typ.split('|');
        var i = -1;
        for (i = 0; i<tlst.length; i++)
            if (self.typeNameList.indexOf(tlst[i]) < 0)
                throw "type unknown '"+tlst[i]+'" not one of: '+self.typeNameStr;
        return tlst;
    }
  
    function reMethod(str:string) {
        var reg = /^function\s*([a-zA-Z0-9_]*)\s*\(([^)]*)\)(:[\|a-z]+|)(\s*)\{$/;
        var vals = reg.exec(str);
        if (!vals)
            throw "invalid method: "+str;
        //puts(vals);
        var fnam = vals[1];
        if (fnam !== '' && fnam[0] !== '_')
            self.funcLst.push(fnam);
        var someDflt = str.indexOf('=')>=0;
        if (str.indexOf(':')<0 && !someDflt) // Skip functions with no types or defaults
            return str;
        var res = 'function '+fnam+'(';
    
        var astr = vals[2].trim();
        var rettyp = vals[3].substr(1);
        var cres = '', ncres = '';
        if (!self.inline)
            cres += '$jsig("'+fnam+'('+astr+')'+vals[3]+'", arguments ); ';
        //res += '/* Fn('+astr+') */ ';
        var acall = [];
        if (astr !== '') {
            var alst = astr.split(',');
            var minargs = alst.length, maxargs = minargs;
            var last = alst.length-1;
            var acres = [];

            for (var i = 0; i<=last; i++) {
                var aval = alst[i].trim();
                if (aval === '...') {
                    if (i != last)
                        throw "expected ... to be at end";
                    maxargs = -1;
                    continue;
................................................................................
                if (i)
                    res += ', ';
                var afnam = avals[1];
                if (afnam === '' || avals.length<3)
                    afnam = aval;
                res += afnam;
                acall.push(afnam);
                var defval = 'undefined', atyp = '';
                if (avals.length>2)
                    atyp = avals[2].substr(1);

                atyp = typeValidate(atyp);



 
                if (someDflt) {
                    var hasDef = (avals[3] && avals[3] !== '');



                    if (hasDef) { // Default value
                        if (avals[3] === '=void') 
                            defval = 'undefined';
                        else
                            defval = avals[3].substr(1);
                        if (hasDef)
                            ncres += ' if (arguments.length<='+i+') '+afnam+'='+defval+';';
                            

                        if (minargs===alst.length)
                            minargs = i;
                    }
                    else if (minargs!==alst.length)
                        throw "non-default value follows default: "+aval+' in: '+str;

                }
                acres.push('{name:"'+afnam+'", type:'+JSON.stringify(atyp)+', def:'+defval+'}');
            }
            if (self.inline)
                cres += '  $jsig({name:"'+fnam+'",astr:"'+astr+'",args:['+acres.join(',')+'],min:'+minargs+',max:'+maxargs+',rettyp:"'+rettyp+'"}, arguments); ';


        }
        cres += ncres;

        res += ')'+vals[4]+' { ';
        if (fnam !== '' && rettyp !== '' && rettyp !== 'any' && self.checkRet) {
            typeValidate(rettyp);
            var wfn = '__Jsi_WrapRet_'+self.tail+'_'+fnam+'_'+ ++self.funcIdx;
            cres += '  var __ret = '+wfn+'('+acall.join(',')+');\n';
            cres += '  Jsi.RetCheck("'+fnam+'",'+' __ret,"'+rettyp+'");\n  return __ret;\n}\n';
            cres += 'function '+wfn+'('+acall.join(', ')+') {';
        }
................................................................................
        }
        if (self.listFuncs) {
            rc = '';
            var n = 0;
            for (i of self.funcLst.sort())
                rc += i + ':' + i + (++n === self.funcLst.length ? '' : ',') + '\n';
        }
        return rc + '\n<!--JSIG GEN-->';
    }
    if (files)
        return parse(files);

    self.parse = parse;
    return self;
}

provide(Jsi_Jspp, 1);

if (isMain()) 
    runModule(Jsi_Jspp);

Changes to lib/Jsi_SqliteUI/html/main.htmli.

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

<head>
<title>SqliteUI</title>
<!--
<script src='sqlite.js'></script> 
<link rel="stylesheet" type="text/css" href="sqlite.css">
-->
<script src='/SqliteUI/jsi/web/jsiweb.js'></script> 
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<? 
// Load .jsi and .cssi for preprocessing.
include(['sqlite.jsi', 'sqlite.cssi'], true);
?>
</head>








|







3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

<head>
<title>SqliteUI</title>
<!--
<script src='sqlite.js'></script> 
<link rel="stylesheet" type="text/css" href="sqlite.css">
-->
<script src='/SqliteUI/jsi/web/jsig.js'></script> 
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<? 
// Load .jsi and .cssi for preprocessing.
include(['sqlite.jsi', 'sqlite.cssi'], true);
?>
</head>

Changes to lib/web/jsig.js.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

18
19
20
21

22
23

24
25
26
27
28
29
30
31
32
33


34
35
36
37
38
39
40
41
42
43
44
45
46
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

73
74
75
76
77
78
79
80
81
82
83
84
85
86
..
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121




122

123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193

194
195
196
197
198
199
200
...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
// JS signatures: type-check function call arguments.
// Emulates the typechecking builtin to Jsi, minus return types.  See https://jsish.org

(function () {
"use strict";

var doc = document,
    win = window,
    typeNameStr="number string boolean array function object regexp any userobj void null",
    typeNameLst= typeNameStr.split(' '),
    sigs = {},
    srcList = [],
    srcCnt = 0,
    onloadFunc = null,
    funcLst = [],
    ENDSTR = '<!--JSIG GEN-->',
    config = {

        alert:false,
        debug:true,
        enable:true,
        fatal :false,

        inline:true
    }

;

// Code to handle function parameter types and default values.
function Jsi() {
}

Jsi.prototype = {
    
    errorCmd: function(msg) {
        // Set breakpoint here to intercept function type warnings.


        console.log(msg);
        if (config.alert) alert(msg);
        if (config.debug) debugger;
        if (config.fatal) throw(msg);
    },
    
    parseError: function(msg) {
        errorCmd('PARSERR: '+msg+' ==> '+jsi.curSig);
        return [];
    },
    
    conf: function(vals) { // Configure options.
        for (var i in vals) {
            if (typeof config[i] == 'undefined')
                errorCmd("Option "+i+" not one of: "+Object.keys(config).join(', '));
            else
                config[i] = vals[i];
        }
    },

    ArgCheck: function(o, aind, val) { // Check arg type and return value or default.
        var af = o.args[aind],
            typ = af.typ, def = af.def;
        if (val===undefined) {
            if (def === undefined)
                return val;
            val = def;
        }
        if (typ && typ.length) {
            jsi.ArgCheckType(o, aind, val);
        }
        return val;
    },

    ArgCheckType: function(o, aind, val) {
        var typ, nam;
        if (aind>=0) {
            var af = o.args[aind];
            typ = af.typ,

            nam = af.name;
        } else {
            typ = o.rettyp;
            nam = 'return';
        }
        var tlst = typ, vtyp = typeof(val), fnam = o.name;
        var pre = 'In "'+fnam+'()" ' + (aind<0?"return value":"");
        for (var i = 0; i<tlst.length; i++) {
            switch (tlst[i]) {
                case "number":  if (vtyp === 'number') return; break;
                case "string":  if (vtyp === 'string') return; break;
                case "boolean": if (vtyp === 'boolean') return; break;
                case "function":if (vtyp === 'function') return; break;
                case "array":   if (vtyp === 'object' && val && val.constructor === Array) return; break;
................................................................................
                case "regexp":  if (vtyp === 'object' && val && val.constructor === RegExp) return; break;
                case "object":  if (vtyp === 'object' && val && val.constructor !== Array) return; break;
                case "any":     return; break;
                case "userobj": if (vtyp === 'object') return; break;
                case "undefined": case "void": if (val === undefined) return; break;
                case "null": if (val === null) return; break;
                default:
                    jsi.errorCmd(pre+" type unknown '"+tlst[i]+'" not one of: '+typeNameStr);
                    return 0;
            }
        }
        jsi.errorCmd(pre+' type mismatch for "'+nam+'" expected "'+typ.join('|')+'" but got "'+vtyp+'" => '+val);
    },
    
    Chk: function(sig, args) { // Check function arguments
        if (!config.enable)
            return;
        var o = sig;
        if (typeof sig === 'string') {
            o = sigs[sig];
            if (!o)
                o = sigs[sig] = jsi.SigParse(sig);        
        }
        if (typeof o !== 'object' || typeof args !== 'object')
            return jsi.errorCmd('bad sig or arguments:'+o);
        
        var len = o.args.length;
        var pre = 'In "'+o.name+'()" ';
        if (o.max>=0 && len>o.max)
            jsi.errorCmd('In "'+o.name+'()" '+"extra arguments: expected "+o.max+" got "+len);
        if (len<o.min)
            jsi.errorCmd('In "'+o.name+'()" '+"missing arguments: expected "+o.min+" got "+len);
        for (var aind = 0; aind<len; aind++) {
            var af = o.args[aind];
            jsi.ArgCheck(o, aind, args[aind]);




        }

    },

    typeValidate: function (typ) {
        if (typ === '') return null;
        var tlst = typ.split('|');
        var i = -1;
        for (i = 0; i<tlst.length; i++)
            if (typeNameLst.indexOf(tlst[i]) < 0) {
                jsi.parseError("type unknown '"+tlst[i]+'" not one of: '+typeNameStr);
                return null;
            }
        if (tlst.length===1 && tlst[0] === 'any')
            return [];
        return tlst;
    },

    SigParse: function(sig) { // Parse string signature and return info.
        jsi.curSig = sig;
        var reg = /^([a-zA-Z0-9_]*)\s*\(([^)]*)\)(:[\|a-z]+|)(\s*)$/;
        var vals = reg.exec(sig);
................................................................................
                if (afnam === '' || avals.length<3)
                    afnam = aval;
                sargs += afnam;
                var defval=undefined, atyp = '';
                if (avals.length>2)
                    atyp = avals[2].substr(1);
                var tlst = jsi.typeValidate(atyp);
                   
                var hasDef = (avals[3] && avals[3] !== '');
                if (hasDef) { // Default value
                    if (avals[3] !== '=void')
                        defval = avals[3].substr(1);
                    if (minargs===alst.length)
                        minargs = i;
                }
                else if (minargs!==alst.length)
                    return jsi.parseError("non-default value follows default: "+aval+' in: '+str);
            }
            acall.push({name:afnam, typ:tlst, def:defval});

        }
        res.astr = astr;
        res.min = minargs;
        res.max = maxargs;
        res.args = acall;
        res.sargs = sargs;
        var rettyp = vals[3].substr(1);
................................................................................
            else
                rc = top.getElementsByTagName(sel);
        }
        return rc;
    },
    
    query1: function(sel, top) {
        var rc = jsi.query1(sel, top);
        if (rc && rc.length)
            return rc[0];
        puts('LOOKUP FAILURE: '+sel+' '+top);
        return null;
    },
    onload: function(f) {
        onloadFunc = f;
................................................................................
        if (onloadFunc)
            onloadFunc();
    }

};

var jsi = new Jsi();
win['Jsi'] = win['$jsi'] = jsi;
win['$jsig']= jsi.Chk;

if (typeof win['$'] === 'undefined')
    win['$'] = jsi.query;

if (typeof win['$$'] === 'undefined')
    win['$$'] = jsi.query1;

|







|








>

|
<

>

|
>










>
>
|



|
<

|






|




|
<
<
<
<
<
<
<
<
<
<
<
<
<
<

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







 







|
|


|

|
|









|

|


|
|
|
|
<
|
>
>
>
>

>












|







 







<









<
|
>







 







|







 







|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

43
44
45
46
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
162
163
164
165
166
167
168

169
170
171
172
173
174
175
176
177

178
179
180
181
182
183
184
185
186
...
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
...
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
// JS signatures: type-checking for arguments of a function call.
// Emulates the typechecking builtin to Jsi, minus return types.  See https://jsish.org

(function () {
"use strict";

var doc = document,
    win = window,
    typeNameStr="number string boolean array function object regexp any userobj void null undefined",
    typeNameLst= typeNameStr.split(' '),
    sigs = {},
    srcList = [],
    srcCnt = 0,
    onloadFunc = null,
    funcLst = [],
    ENDSTR = '<!--JSIG GEN-->',
    config = {
        enable:true,
        alert:false,
        debug:false,

        fatal :false,
        traceback:false,
        inline:true
    },
    isChrome = (window.chrome && window.navigator.vendor === "Google Inc.")
;

// Code to handle function parameter types and default values.
function Jsi() {
}

Jsi.prototype = {
    
    errorCmd: function(msg) {
        // Set breakpoint here to intercept function type warnings.
        console.error(msg);
        if (config.traceback)
            console.trace();
        if (config.alert) alert(msg);
        if (config.debug) debugger;
        if (config.fatal) throw(msg);
    },    

    parseError: function(msg) {
        jsi.errorCmd('PARSERR: '+msg+' ==> '+jsi.curSig);
        return [];
    },
    
    conf: function(vals) { // Configure options.
        for (var i in vals) {
            if (typeof config[i] == 'undefined')
                jsi.errorCmd("Option "+i+" not one of: "+Object.keys(config).join(', '));
            else
                config[i] = vals[i];
        }
    },
    














    ArgCheckType: function(o, aind, val) {


        var af = o.args[aind];
        var tlst = af.typ;
        if (!tlst) return;
        var nam = af.name;




        var vtyp = typeof(val);

        for (var i = 0; i<tlst.length; i++) {
            switch (tlst[i]) {
                case "number":  if (vtyp === 'number') return; break;
                case "string":  if (vtyp === 'string') return; break;
                case "boolean": if (vtyp === 'boolean') return; break;
                case "function":if (vtyp === 'function') return; break;
                case "array":   if (vtyp === 'object' && val && val.constructor === Array) return; break;
................................................................................
                case "regexp":  if (vtyp === 'object' && val && val.constructor === RegExp) return; break;
                case "object":  if (vtyp === 'object' && val && val.constructor !== Array) return; break;
                case "any":     return; break;
                case "userobj": if (vtyp === 'object') return; break;
                case "undefined": case "void": if (val === undefined) return; break;
                case "null": if (val === null) return; break;
                default:
                    puts("type '"+tlst[i]+'" is unknown: not one of: '+typeNameStr);
                    return;
            }
        }
        return 'type mismatch for arg '+(i+1)+' "'+nam+'" expected "'+tlst.join('|')+'" got "'+vtyp+'" '+val;
    },

    $jsig: function(sig, args) { // Check function arguments
        if (!config.enable)
            return;
        var o = sig;
        if (typeof sig === 'string') {
            o = sigs[sig];
            if (!o)
                o = sigs[sig] = jsi.SigParse(sig);        
        }
        if (typeof o !== 'object' || typeof args !== 'object')
            throw('bad sig or arguments:'+sig+args);
        
        var len = o.args.length, msg;
        var pre = 'In "'+o.name+'()" ';
        if (o.max>=0 && len>o.max)
            msg = "extra arguments: expected "+o.max+" got "+len;
        else if (len<o.min)
            msg = "missing arguments: expected "+o.min+" got "+len;
        for (var aind = 0; aind<args.length && !msg; aind++)

            msg = jsi.ArgCheckType(o, aind, args[aind]);
        if (msg) {
            msg+=': calling '+o.name+'('+o.astr+')'+o.retval;
            //msg+=': calling '+o.name+'('+Array.prototype.slice.call(args).join(',')+'), sig ==> FN('+o.astr+')'+o.retval;
            jsi.errorCmd(msg);
        }
        return msg;
    },

    typeValidate: function (typ) {
        if (typ === '') return null;
        var tlst = typ.split('|');
        var i = -1;
        for (i = 0; i<tlst.length; i++)
            if (typeNameLst.indexOf(tlst[i]) < 0) {
                jsi.parseError("type unknown '"+tlst[i]+'" not one of: '+typeNameStr);
                return null;
            }
        if (tlst.length===1 && tlst[0] === 'any')
            return null;
        return tlst;
    },

    SigParse: function(sig) { // Parse string signature and return info.
        jsi.curSig = sig;
        var reg = /^([a-zA-Z0-9_]*)\s*\(([^)]*)\)(:[\|a-z]+|)(\s*)$/;
        var vals = reg.exec(sig);
................................................................................
                if (afnam === '' || avals.length<3)
                    afnam = aval;
                sargs += afnam;
                var defval=undefined, atyp = '';
                if (avals.length>2)
                    atyp = avals[2].substr(1);
                var tlst = jsi.typeValidate(atyp);

                var hasDef = (avals[3] && avals[3] !== '');
                if (hasDef) { // Default value
                    if (avals[3] !== '=void')
                        defval = avals[3].substr(1);
                    if (minargs===alst.length)
                        minargs = i;
                }
                else if (minargs!==alst.length)
                    return jsi.parseError("non-default value follows default: "+aval+' in: '+str);

                acall.push({name:afnam, typ:tlst, def:defval});
            }
        }
        res.astr = astr;
        res.min = minargs;
        res.max = maxargs;
        res.args = acall;
        res.sargs = sargs;
        var rettyp = vals[3].substr(1);
................................................................................
            else
                rc = top.getElementsByTagName(sel);
        }
        return rc;
    },
    
    query1: function(sel, top) {
        var rc = jsi.query(sel, top);
        if (rc && rc.length)
            return rc[0];
        puts('LOOKUP FAILURE: '+sel+' '+top);
        return null;
    },
    onload: function(f) {
        onloadFunc = f;
................................................................................
        if (onloadFunc)
            onloadFunc();
    }

};

var jsi = new Jsi();
win['$jsi'] = jsi;
win['$jsig']= jsi.$jsig;

if (typeof win['$'] === 'undefined')
    win['$'] = jsi.query;

if (typeof win['$$'] === 'undefined')
    win['$$'] = jsi.query1;

Changes to md/Reference.md.

1620
1621
1622
1623
1624
1625
1626

1627
1628
1629
1630
1631
1632
1633
....
1649
1650
1651
1652
1653
1654
1655

1656
1657
1658
1659
1660
1661
1662
<tr><td>debug</td><td><i>INT</i></td><td>Set debug level. Setting this to 512 will turn on max libwebsocket log levels.</td><td><i></i></td></tr>
<tr><td>echo</td><td><i>BOOL</i></td><td>LogInfo outputs all websock Send/Recv messages.</td><td><i></i></td></tr>
<tr><td>formParams</td><td><i>STRKEY</i></td><td>Comma seperated list of upload form param names ('text,send,file,upload').</td><td><i>readOnly</i></td></tr>
<tr><td>extArgs</td><td><i>OBJ</i></td><td>Arguments for extension handlers.</td><td><i>initOnly</i></td></tr>
<tr><td>extHandlers</td><td><i>BOOL</i></td><td>Enable builtin handlers for these extensions: .htmli, .cssi, .jsi, and .md.</td><td><i>initOnly</i></td></tr>
<tr><td>getRegexp</td><td><i>REGEXP</i></td><td>Call onGet() only if Url matches pattern.</td><td><i></i></td></tr>
<tr><td>headers</td><td><i>ARRAY</i></td><td>List of name/value output header pairs.</td><td><i>initOnly</i></td></tr>

<tr><td>interface</td><td><i>STRING</i></td><td>Interface for server to listen on, eg. 'eth0' or 'lo'.</td><td><i>initOnly</i></td></tr>
<tr><td>local</td><td><i>BOOL</i></td><td>Limit connections to localhost addresses on the 127 network.</td><td><i></i></td></tr>
<tr><td>localhostName</td><td><i>STRKEY</i></td><td>Client name used by localhost connections ('localhost').</td><td><i></i></td></tr>
<tr><td>maxConnects</td><td><i>INT</i></td><td>In server mode, max number of client connections accepted.</td><td><i></i></td></tr>
<tr><td>maxDownload</td><td><i>INT</i></td><td>Max size of file download.</td><td><i></i></td></tr>
<tr><td>maxUpload</td><td><i>INT</i></td><td>Max size of file upload will accept.</td><td><i></i></td></tr>
<tr><td>mimeTypes</td><td><i>OBJ</i></td><td>Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'}).</td><td><i>initOnly</i></td></tr>
................................................................................
<tr><td>post</td><td><i>STRING</i></td><td>Post string to serve.</td><td><i>initOnly</i></td></tr>
<tr><td>protocol</td><td><i>STRKEY</i></td><td>Name of protocol (ws/wss).</td><td><i></i></td></tr>
<tr><td>realm</td><td><i>STRKEY</i></td><td>Realm for basic auth (jsish).</td><td><i></i></td></tr>
<tr><td>recvBufMax</td><td><i>INT</i></td><td>Size limit of a websocket message.</td><td><i>initOnly</i></td></tr>
<tr><td>recvBufTimeout</td><td><i>INT</i></td><td>Timeout for recv of a websock msg.</td><td><i>initOnly</i></td></tr>
<tr><td>redirMax</td><td><i>BOOL</i></td><td>Temporarily disable redirects when see more than this in 10 minutes.</td><td><i></i></td></tr>
<tr><td>rootdir</td><td><i>STRING</i></td><td>Directory to serve html from (".").</td><td><i></i></td></tr>

<tr><td>stats</td><td><i><a href='#statsOptions'>options</a></i></td><td>Statistical data.</td><td><i>readOnly</i></td></tr>
<tr><td>startTime</td><td><i>TIME_T</i></td><td>Time of websocket start.</td><td><i>readOnly</i></td></tr>
<tr><td>includeFile</td><td><i>STRKEY</i></td><td>Default file when no extension given (include.shtml).</td><td><i></i></td></tr>
<tr><td>urlPrefix</td><td><i>STRKEY</i></td><td>Prefix in url to strip from path; for reverse proxy.</td><td><i></i></td></tr>
<tr><td>urlRedirect</td><td><i>STRKEY</i></td><td>Redirect when no url or / is given. Must match urlPrefix, if given.</td><td><i></i></td></tr>
<tr><td>use_ssl</td><td><i>BOOL</i></td><td>Use https (for client).</td><td><i>initOnly</i></td></tr>
<tr><td>useridPass</td><td><i>STRKEY</i></td><td>The USERID:PASSWORD to use for basic authentication.</td><td><i></i></td></tr>







>







 







>







1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
....
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
<tr><td>debug</td><td><i>INT</i></td><td>Set debug level. Setting this to 512 will turn on max libwebsocket log levels.</td><td><i></i></td></tr>
<tr><td>echo</td><td><i>BOOL</i></td><td>LogInfo outputs all websock Send/Recv messages.</td><td><i></i></td></tr>
<tr><td>formParams</td><td><i>STRKEY</i></td><td>Comma seperated list of upload form param names ('text,send,file,upload').</td><td><i>readOnly</i></td></tr>
<tr><td>extArgs</td><td><i>OBJ</i></td><td>Arguments for extension handlers.</td><td><i>initOnly</i></td></tr>
<tr><td>extHandlers</td><td><i>BOOL</i></td><td>Enable builtin handlers for these extensions: .htmli, .cssi, .jsi, and .md.</td><td><i>initOnly</i></td></tr>
<tr><td>getRegexp</td><td><i>REGEXP</i></td><td>Call onGet() only if Url matches pattern.</td><td><i></i></td></tr>
<tr><td>headers</td><td><i>ARRAY</i></td><td>List of name/value output header pairs.</td><td><i>initOnly</i></td></tr>
<tr><td>jsiFnPattern</td><td><i>STRKEY</i></td><td>A glob-match pattern for files to which is appended 'window.jsiWebSocket=true;' (jsi*.js).</td><td><i>readOnly</i></td></tr>
<tr><td>interface</td><td><i>STRING</i></td><td>Interface for server to listen on, eg. 'eth0' or 'lo'.</td><td><i>initOnly</i></td></tr>
<tr><td>local</td><td><i>BOOL</i></td><td>Limit connections to localhost addresses on the 127 network.</td><td><i></i></td></tr>
<tr><td>localhostName</td><td><i>STRKEY</i></td><td>Client name used by localhost connections ('localhost').</td><td><i></i></td></tr>
<tr><td>maxConnects</td><td><i>INT</i></td><td>In server mode, max number of client connections accepted.</td><td><i></i></td></tr>
<tr><td>maxDownload</td><td><i>INT</i></td><td>Max size of file download.</td><td><i></i></td></tr>
<tr><td>maxUpload</td><td><i>INT</i></td><td>Max size of file upload will accept.</td><td><i></i></td></tr>
<tr><td>mimeTypes</td><td><i>OBJ</i></td><td>Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'}).</td><td><i>initOnly</i></td></tr>
................................................................................
<tr><td>post</td><td><i>STRING</i></td><td>Post string to serve.</td><td><i>initOnly</i></td></tr>
<tr><td>protocol</td><td><i>STRKEY</i></td><td>Name of protocol (ws/wss).</td><td><i></i></td></tr>
<tr><td>realm</td><td><i>STRKEY</i></td><td>Realm for basic auth (jsish).</td><td><i></i></td></tr>
<tr><td>recvBufMax</td><td><i>INT</i></td><td>Size limit of a websocket message.</td><td><i>initOnly</i></td></tr>
<tr><td>recvBufTimeout</td><td><i>INT</i></td><td>Timeout for recv of a websock msg.</td><td><i>initOnly</i></td></tr>
<tr><td>redirMax</td><td><i>BOOL</i></td><td>Temporarily disable redirects when see more than this in 10 minutes.</td><td><i></i></td></tr>
<tr><td>rootdir</td><td><i>STRING</i></td><td>Directory to serve html from (".").</td><td><i></i></td></tr>
<tr><td>server</td><td><i>STRKEY</i></td><td>String to send out int the header SERVER (jsiWebSocket).</td><td><i></i></td></tr>
<tr><td>stats</td><td><i><a href='#statsOptions'>options</a></i></td><td>Statistical data.</td><td><i>readOnly</i></td></tr>
<tr><td>startTime</td><td><i>TIME_T</i></td><td>Time of websocket start.</td><td><i>readOnly</i></td></tr>
<tr><td>includeFile</td><td><i>STRKEY</i></td><td>Default file when no extension given (include.shtml).</td><td><i></i></td></tr>
<tr><td>urlPrefix</td><td><i>STRKEY</i></td><td>Prefix in url to strip from path; for reverse proxy.</td><td><i></i></td></tr>
<tr><td>urlRedirect</td><td><i>STRKEY</i></td><td>Redirect when no url or / is given. Must match urlPrefix, if given.</td><td><i></i></td></tr>
<tr><td>use_ssl</td><td><i>BOOL</i></td><td>Use https (for client).</td><td><i>initOnly</i></td></tr>
<tr><td>useridPass</td><td><i>STRKEY</i></td><td>The USERID:PASSWORD to use for basic authentication.</td><td><i></i></td></tr>

Changes to src/jsi.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
....
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
....
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
....
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
....
7652
7653
7654
7655
7656
7657
7658




7659
7660
7661
7662
7663
7664
7665
....
8944
8945
8946
8947
8948
8949
8950
8951
8952
8953
8954
8955
8956
8957
8958
....
8968
8969
8970
8971
8972
8973
8974
8975
8976
8977
8978
8979
8980
8981
8982
.....
19506
19507
19508
19509
19510
19511
19512
19513
19514
19515
19516
19517
19518
19519
19520
19521
19522
19523
19524
19525
19526
19527
19528
19529
19530
19531
19532
19533
19534
.....
19555
19556
19557
19558
19559
19560
19561
19562
19563

19564
19565
19566
19567
19568
19569
19570
.....
19578
19579
19580
19581
19582
19583
19584
19585
19586
19587
19588
19589
19590
19591
19592
19593
19594
.....
19612
19613
19614
19615
19616
19617
19618
19619
19620
19621
19622
19623
19624
19625
19626
.....
27574
27575
27576
27577
27578
27579
27580
27581
27582



27583
27584


27585
27586
27587
27588
27589
27590
27591
27592
27593

27594
27595
27596
27597
27598

27599
27600
27601
27602
27603
27604
27605
.....
27791
27792
27793
27794
27795
27796
27797
27798
27799
27800
27801
27802
27803
27804
27805
.....
27807
27808
27809
27810
27811
27812
27813
27814
27815
27816
27817
27818
27819
27820
27821
.....
27889
27890
27891
27892
27893
27894
27895
27896
27897
27898
27899
27900

27901
27902
27903
27904


27905
27906
27907
27908
27909
27910
27911
27912
27913
27914
27915
27916

27917
27918
27919
27920
27921
27922
27923
27924
.....
27933
27934
27935
27936
27937
27938
27939
27940
27941
27942
27943

27944
27945
27946

27947
27948
27949
27950
27951
27952
27953
27954
27955
27956
27957
27958
27959
27960

27961
27962
27963
27964
27965
27966
27967
27968
.....
28035
28036
28037
28038
28039
28040
28041
28042
28043
28044
28045
28046
28047
28048
28049
.....
28296
28297
28298
28299
28300
28301
28302
28303
28304
28305
28306
28307
28308
28309
28310
.....
28380
28381
28382
28383
28384
28385
28386
28387
28388
28389
28390
28391
28392
28393
28394
.....
28444
28445
28446
28447
28448
28449
28450
28451
28452
28453
28454
28455
28456
28457
28458
.....
28544
28545
28546
28547
28548
28549
28550
28551
28552
28553
28554
28555
28556
28557
28558
28559
28560
.....
28562
28563
28564
28565
28566
28567
28568
28569



28570



28571
28572
28573
28574
28575
28576
28577
.....
28612
28613
28614
28615
28616
28617
28618
28619
28620
28621
28622
28623
28624
28625
28626
.....
35282
35283
35284
35285
35286
35287
35288
35289
35290
35291
35292
35293
35294
35295
35296
.....
35298
35299
35300
35301
35302
35303
35304

35305
35306
35307
35308
35309
35310
35311
.....
35314
35315
35316
35317
35318
35319
35320
35321
35322

35323
35324
35325
35326
35327
35328
35329
.....
38027
38028
38029
38030
38031
38032
38033
38034
38035
38036
38037
38038
38039
38040
38041
.....
38066
38067
38068
38069
38070
38071
38072
38073
38074
38075
38076
38077
38078
38079
38080
.....
39522
39523
39524
39525
39526
39527
39528


39529
39530
39531
39532
39533


39534
39535
39536
39537
39538
39539
39540
.....
39544
39545
39546
39547
39548
39549
39550
39551


39552
39553
39554
39555
39556
39557
39558
.....
39609
39610
39611
39612
39613
39614
39615
39616
39617
39618
39619
39620
39621
39622
39623
.....
52763
52764
52765
52766
52767
52768
52769
52770
52771
52772
52773
52774
52775
52776
52777
52778
.....
52925
52926
52927
52928
52929
52930
52931

52932
52933
52934
52935
52936
52937
52938
.....
52954
52955
52956
52957
52958
52959
52960

52961
52962
52963
52964
52965
52966
52967
.....
53126
53127
53128
53129
53130
53131
53132


53133
53134
53135
53136
53137
53138
53139
53140
.....
53414
53415
53416
53417
53418
53419
53420
















53421
53422
53423
53424
53425
53426
53427
.....
53442
53443
53444
53445
53446
53447
53448

53449
53450
53451
53452
53453
53454
53455
.....
53544
53545
53546
53547
53548
53549
53550
53551
53552
53553
53554
53555
53556
53557
53558
.....
53677
53678
53679
53680
53681
53682
53683
53684

53685
53686
53687
53688
53689
53690
53691
.....
53925
53926
53927
53928
53929
53930
53931

53932
53933
53934
53935
53936
53937


53938
53939
53940
53941
53942
53943
53944
53945
53946
53947
53948
53949
53950
53951



53952
53953
53954
53955
53956
53957
53958
.....
55234
55235
55236
55237
55238
55239
55240

55241
55242
55243
55244
55245
55246
55247
.....
58828
58829
58830
58831
58832
58833
58834
58835
58836
58837
58838
58839
58840
58841
58842
.....
69762
69763
69764
69765
69766
69767
69768
69769
69770
69771
69772
69773
69774
69775
69776
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   8
#define JSI_VERSION_RELEASE 33

#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_EXTERN Jsi_Number Jsi_Version(void); /*STUB = 183*/
JSI_EXTERN Jsi_Value* Jsi_ReturnValue(Jsi_Interp *interp); /*STUB = 184*/
JSI_EXTERN Jsi_RC Jsi_Mount( Jsi_Interp *interp, Jsi_Value *archive, Jsi_Value *mount, Jsi_Value **ret); /*STUB = 185*/
JSI_EXTERN Jsi_Value* Jsi_Executable(Jsi_Interp *interp); /*STUB = 186*/
JSI_EXTERN Jsi_Regex* Jsi_RegExpNew(Jsi_Interp *interp, const char *regtxt, int flag); /*STUB = 187*/
JSI_EXTERN void Jsi_RegExpFree(Jsi_Regex* re); /*STUB = 188*/
JSI_EXTERN Jsi_RC Jsi_RegExpMatch( Jsi_Interp *interp,  Jsi_Value *pattern, const char *str, int *rc, Jsi_DString *dStr); /*STUB = 189*/
JSI_EXTERN Jsi_RC Jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, Jsi_Value *ret); /*STUB = 190*/
JSI_EXTERN bool Jsi_GlobMatch(const char *pattern, const char *string, int nocase); /*STUB = 191*/
JSI_EXTERN char* Jsi_FileRealpath(Jsi_Interp *interp, Jsi_Value *path, char *newpath); /*STUB = 192*/
JSI_EXTERN char* Jsi_FileRealpathStr(Jsi_Interp *interp, const char *path, char *newpath); /*STUB = 193*/
JSI_EXTERN char* Jsi_NormalPath(Jsi_Interp *interp, const char *path, Jsi_DString *dStr); /*STUB = 194*/
JSI_EXTERN char* Jsi_ValueNormalPath(Jsi_Interp *interp, Jsi_Value *path, Jsi_DString *dStr); /*STUB = 195*/
JSI_EXTERN Jsi_RC Jsi_PathNormalize(Jsi_Interp *interp, Jsi_Value **pathPtr); /*STUB = 410*/
JSI_EXTERN Jsi_RC Jsi_JSONParse(Jsi_Interp *interp, const char *js, Jsi_Value **ret, int flags); /*STUB = 196*/
................................................................................
#ifndef __JSI_STUBS_H__
#define __JSI_STUBS_H__
#ifndef JSI_AMALGAMATION
#include "jsi.h"
#endif


#define JSI_STUBS_MD5 "f10cf428d26d56bf41a31286e1cbc9c2"

#undef JSI_EXTENSION_INI
#define JSI_EXTENSION_INI Jsi_Stubs *jsiStubsPtr = NULL;

#ifdef JSI__MUSL
#define JSI_STUBS_BLDFLAGS 1
#else
................................................................................
    Jsi_Number(*_Jsi_Version)(void);
    Jsi_Value*(*_Jsi_ReturnValue)(Jsi_Interp *interp);
    Jsi_RC(*_Jsi_Mount)( Jsi_Interp *interp, Jsi_Value *archive, Jsi_Value *mount, Jsi_Value **ret);
    Jsi_Value*(*_Jsi_Executable)(Jsi_Interp *interp);
    Jsi_Regex*(*_Jsi_RegExpNew)(Jsi_Interp *interp, const char *regtxt, int flag);
    void(*_Jsi_RegExpFree)(Jsi_Regex* re);
    Jsi_RC(*_Jsi_RegExpMatch)( Jsi_Interp *interp,  Jsi_Value *pattern, const char *str, int *rc, Jsi_DString *dStr);
    Jsi_RC(*_Jsi_RegExpMatches)(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, Jsi_Value *ret);
    bool(*_Jsi_GlobMatch)(const char *pattern, const char *string, int nocase);
    char*(*_Jsi_FileRealpath)(Jsi_Interp *interp, Jsi_Value *path, char *newpath);
    char*(*_Jsi_FileRealpathStr)(Jsi_Interp *interp, const char *path, char *newpath);
    char*(*_Jsi_NormalPath)(Jsi_Interp *interp, const char *path, Jsi_DString *dStr);
    char*(*_Jsi_ValueNormalPath)(Jsi_Interp *interp, Jsi_Value *path, Jsi_DString *dStr);
    Jsi_RC(*_Jsi_JSONParse)(Jsi_Interp *interp, const char *js, Jsi_Value **ret, int flags);
    Jsi_RC(*_Jsi_JSONParseFmt)(Jsi_Interp *interp, Jsi_Value **ret, const char *fmt, ...);
................................................................................
#define Jsi_Version(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_Version(n0))
#define Jsi_ReturnValue(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_ReturnValue(n0))
#define Jsi_Mount(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_Mount(n0,n1,n2,n3))
#define Jsi_Executable(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_Executable(n0))
#define Jsi_RegExpNew(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpNew(n0,n1,n2))
#define Jsi_RegExpFree(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpFree(n0))
#define Jsi_RegExpMatch(n0,n1,n2,n3,n4) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpMatch(n0,n1,n2,n3,n4))
#define Jsi_RegExpMatches(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpMatches(n0,n1,n2,n3))
#define Jsi_GlobMatch(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_GlobMatch(n0,n1,n2))
#define Jsi_FileRealpath(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_FileRealpath(n0,n1,n2))
#define Jsi_FileRealpathStr(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_FileRealpathStr(n0,n1,n2))
#define Jsi_NormalPath(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_NormalPath(n0,n1,n2))
#define Jsi_ValueNormalPath(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_ValueNormalPath(n0,n1,n2))
#define Jsi_JSONParse(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_JSONParse(n0,n1,n2,n3))
#define Jsi_JSONParseFmt(n0,n1,n2,...) JSISTUBCALL(jsiStubsPtr, _Jsi_JSONParseFmt(n0,n1,n2,##__VA_ARGS__))
................................................................................

#ifdef __FreeBSD__
#define _JSICASTINT(s) (int)(s)
#else
#define _JSICASTINT(s) (s)
#endif





#if 0
#ifndef uint
typedef unsigned int uint;
#endif
#ifndef uchar
typedef unsigned char uchar;
#endif
................................................................................
#define _JSI_MEMCLEAR(ptr) memset(ptr, 0, sizeof(*ptr)) /* To aid debugging memory.*/
#endif
#endif

#define MAX_SUBREGEX    256
#define JSI__LONG_LONG
#define UCHAR(s) (unsigned char)(s)
extern char* jsi_SubstrDup(const char *a, int start, int len);
extern int jsi_typeGet(Jsi_Interp *interp , const char *tname);
extern const char *jsi_typeName(Jsi_Interp *interp, int typ, Jsi_DString *dStr);
extern Jsi_RC jsi_ArgTypeCheck(Jsi_Interp *interp, int typ, Jsi_Value *arg, const char *p1, const char *p2, int index, Jsi_Func *func, bool isdefault);
extern void jsi_FuncCallCheck(jsi_Pstate *p, jsi_Pline *line, int argc, bool isNew, const char *name, const char *namePre, Jsi_OpCodes *argCodes);
extern Jsi_RC jsi_RunFuncCallCheck(Jsi_Interp *interp, Jsi_Func *func, int argc, const char *name, jsi_Pline *line, Jsi_OpCodes *argCodes, bool isParse);
extern Jsi_RC jsi_FunctionSubCall(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Value *tocall, int discard);
extern Jsi_ScopeStrs *jsi_ArgsOptAdd(jsi_Pstate *pstate, Jsi_ScopeStrs *a);
................................................................................
extern int jsi_GetDefaultType(const char *cp);
extern Jsi_RC jsi_ParseTypeCheckStr(Jsi_Interp *interp, const char *str);
extern Jsi_Interp *jsi_DoExit(Jsi_Interp *interp, int rc);
extern Jsi_RC jsi_CDataDataSetCmdSub(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Func *funcPtr, int flags);
extern Jsi_RC jsi_AliasInvoke(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Func *funcPtr);
extern Jsi_Number jsi_VersionNormalize(Jsi_Number ver, char *obuf, size_t osiz);
extern const char* jsi_FuncGetCode(Jsi_Interp *interp, Jsi_Func *func, int *lenPtr);
extern Jsi_RC jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, Jsi_Value *ret, int *ofs, bool match);

extern Jsi_RC Jsi_CleanValue(Jsi_Interp *interp, Jsi_Interp *tointerp, Jsi_Value *val, Jsi_Value **ret); //TODO: EXPORT

extern char jsi_toHexChar(char code);
extern char jsi_fromHexChar(char ch);
extern bool jsi_IsAlnumStr(const char *cp);
extern char *jsi_TrimStr(char *str);
................................................................................
    }
    
    return JSI_OK;
}



Jsi_RC jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, Jsi_Value *ret, int *ofs, bool match)
{
    Jsi_Regex *re;
    int regexec_flags = 0;
    Jsi_Value *seq = pattern;

    if (seq == NULL || seq->vt != JSI_VT_OBJECT || seq->d.obj->ot != JSI_OT_REGEXP) {
        Jsi_ValueMakeNull(interp, &ret);
        return JSI_OK;
    }
    re = seq->d.obj->d.robj;
    regex_t *reg = &re->reg;
    
    regmatch_t pos[MAX_SUBREGEX] = {};
    int num_matches = 0, r, n = Jsi_Strlen(str);
    int isglob = (re->eflags&JSI_REG_GLOB);
    Jsi_Obj *obj;
    
    do {
        r = regexec(reg, str, MAX_SUBREGEX, pos, regexec_flags);

        if (r >= REG_BADPAT) {
................................................................................
        int i;
        for (i = 0; i < MAX_SUBREGEX; ++i) {
            if (pos[i].rm_so <= 0 && pos[i].rm_eo <= 0)
                break;
            if (i && pos[i].rm_so == pos[i-1].rm_so && pos[i].rm_eo == pos[i-1].rm_eo)
                continue;
    
            Jsi_Value *val = Jsi_ValueMakeString(interp, NULL, 
                jsi_SubstrDup(str, pos[i].rm_so, pos[i].rm_eo - pos[i].rm_so));

            if (ofs)
                *ofs = pos[i].rm_eo;
            Jsi_ValueInsertArray(interp, ret, num_matches, val, 0);
            num_matches++;
            if ( match && isglob)
                break;
        }
................................................................................

        regexec_flags |= REG_NOTBOL;
    } while (n && pos[0].rm_eo>0);
    
    return JSI_OK;
}

Jsi_RC Jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, Jsi_Value *ret)
{
    return jsi_RegExpMatches(interp, pattern, str, ret, NULL, 0);
}


#define FN_regexec JSI_INFO("\
Perform regexp match checking.  Returns the array of matches.\
With the global flag g, sets lastIndex and returns next match.")
static Jsi_RC RegexpExecCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
................................................................................
        l = Jsi_ValueObjLookup(interp, v, "lastIndex", 0);
        if (l && Jsi_ValueGetNumber(interp, l, &lv) != JSI_OK) 
            return Jsi_LogError("lastIndex not a number");
        if (l)
            re->lastIndex = (int)lv;
    }
    int ofs = 0;
    Jsi_RC rc = jsi_RegExpMatches(interp, v, re->lastIndex<slen?str+re->lastIndex:"", *ret, isglob?&ofs:NULL, 0);
    if (isglob) {
        if (rc != JSI_OK)
            return rc;
        re->lastIndex += ofs;
        if (Jsi_ValueIsNull(interp, *ret))
            re->lastIndex = 0;
        lv = (Jsi_Number)re->lastIndex;
................................................................................
        len = Jsi_Strlen(str);
    char *cp = (char*)Jsi_Malloc(len+1);
    memcpy(cp, str, len);
    cp[len] = 0;
    return cp;
}

char *jsi_SubstrDup(const char *a, int start, int len)
{



    if (len == 0) return Jsi_Strdup("");
    


    int lenofa = Jsi_Strlen(a);
    while (start < 0) start += lenofa;
    if (start >= lenofa) return Jsi_Strdup("");
    
    int maxcpy = lenofa - start;
    
    if (len > 0) {
        maxcpy = maxcpy < len ? maxcpy : len;
    }

    
    char *r = (char*)Jsi_Malloc(maxcpy + 2);

    Jsi_Strncpy(r, a + start, maxcpy + 1);
    r[maxcpy + 1] = 0;

    return r;
}


char* Jsi_Strrchr(const char *str, int c)
{
    return strrchr((char*)str, c);
................................................................................
    }

static Jsi_RC StringConstructor(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    if (Jsi_FunctionIsConstructor(funcPtr)) {
        const char *nv = "";
        int len = 0;
        if (Jsi_ValueGetLength(interp, args) > 0) {
            Jsi_Value *v = Jsi_ValueArrayIndex(interp, args, 0);
            if (v) {
                
                nv = Jsi_ValueToString(interp, v, &len);
            }
        }
................................................................................
            if (_this->d.obj->d.s.str)
                if (!_this->d.obj->isstrkey)
                    Jsi_Free(_this->d.obj->d.s.str);
            _this->d.obj->isstrkey = 0;
            _this->d.obj->d.s.str = Jsi_StrdupLen(nv, len);
            _this->d.obj->d.s.len = len;
        } else
            Jsi_ValueMakeStringDup(interp, &_this, nv);
        Jsi_ValueDup2(interp, ret, _this);
        return JSI_OK;
    }
    if (Jsi_ValueGetLength(interp, args) > 0) {
        Jsi_Value *v = Jsi_ValueArrayIndex(interp, args, 0);
        if (v) {
            Jsi_ValueDup2(interp, ret, v);
................................................................................
    ChkString(_this, funcPtr, v, &sLen, &bLen);

    Jsi_Value *start = Jsi_ValueArrayIndex(interp, args, skip);
    Jsi_Value *len = Jsi_ValueArrayIndex(interp, args, skip+1);
    
    Jsi_Number nstart, nlen;
    if (!start || Jsi_GetNumberFromValue(interp,start, &nstart) != JSI_OK) {
        Jsi_ValueMakeStringDup(interp, ret, v);
        return JSI_OK;
    }
    int istart = (int)nstart;
    Jsi_DString dStr;

    Jsi_DSInit(&dStr);
    if (!len || Jsi_GetNumberFromValue(interp,len, &nlen) != JSI_OK) {
        if (sLen == bLen)
            Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(v, istart, -1));


        else {
            Jsi_UtfSubstr(v, istart, -1, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
        return JSI_OK;
    }
    int ilen = (int)nlen;
    if (ilen <= 0) {
        Jsi_ValueMakeStringDup(interp, ret, "");
    } else {
        if (sLen == bLen)
            Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(v, istart, ilen));

        else {
            Jsi_UtfSubstr(v, istart, ilen, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
    }
    return JSI_OK;
}

................................................................................
    Jsi_Value *end = Jsi_ValueArrayIndex(interp, args, skip+1);
    
    Jsi_Number nstart, nend;
    if (!start || Jsi_GetNumberFromValue(interp,start, &nstart) != JSI_OK) {
        Jsi_ValueMakeStringDup(interp, ret, v);
        return JSI_OK;
    }
    int istart = (int)nstart;
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    

    if (!end || Jsi_GetNumberFromValue(interp,end, &nend) != JSI_OK) {
        if (sLen == bLen)
            Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(v, istart, -1));

        else {
            Jsi_UtfSubstr(v, istart, -1, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
        return JSI_OK;
    }
    int iend = (int)nend;
    if (iend>sLen)
        iend = sLen;
    if (iend < istart) {
        Jsi_ValueMakeStringDup(interp, ret, "");
    } else {
        if (sLen == bLen)
            Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(v, istart, iend-istart+1));

        else {
            Jsi_UtfSubstr(v, istart, iend-istart+1, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
    }
    return JSI_OK;
}

................................................................................
    if (Jsi_ValueIsString(interp, seq)) {
        char *cp = Jsi_ValueString(interp, seq, NULL);

        if (jsi_RegExpValueNew(interp, cp, seq) != JSI_OK)
            return JSI_ERROR;
    }
    /* TODO: differentiate from re.exec() */
    return jsi_RegExpMatches(interp, seq, v, *ret, NULL, 1);
}

static Jsi_RC StringFromCharCodeCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    if (!(_this->vt == JSI_VT_OBJECT && _this->d.obj->ot == JSI_OT_FUNCTION &&
       _this->d.obj->__proto__ == interp->String_prototype->d.obj->__proto__ ))
................................................................................
            Jsi_LogError("String get failure");
            Jsi_DSFree(&dStr);
            return JSI_ERROR;
        }
        Jsi_DSAppend(&dStr, vstr, NULL);
    }

    Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
    return JSI_OK;
    
}

static Jsi_RC StringSliceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
................................................................................
                j += slen;
            }
        }
        if (i>=obj->arrCnt)
            Jsi_DSAppendLen(&dStr, p, 1);
    }

    Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
    return JSI_OK;
}
    
#define FN_strreplace JSI_INFO("\
If the replace argument is a function, it is called with match,p1,p2,...,offset,string.  \
If called function is known to have 1 argument, it is called with just the match.")
static Jsi_RC StringReplaceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
................................................................................
                    Jsi_DSFree(&dStr);
                    Jsi_DecrRefCount(interp, inStr);
                    return JSI_ERROR;
                }
                Jsi_DecrRefCount(interp, inStr);
            }
            Jsi_DSAppend(&dStr, ce+Jsi_Strlen(cp), NULL);
            Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
        }
        return JSI_OK;
    }
    if (seq == NULL || seq->vt != JSI_VT_OBJECT || seq->d.obj->ot != JSI_OT_REGEXP) {
        Jsi_ValueMakeNull(interp, ret);
        return JSI_OK;
    }
................................................................................
            }
    
        } else {
            Jsi_DString sStr;
            Jsi_DSInit(&sStr); 
            if (pmatch[0].rm_so <= 0 && pmatch[0].rm_eo <= 0)
                break;
    
            Jsi_Value *inStr = Jsi_ValueMakeString(interp, NULL, 
                jsi_SubstrDup(p, pmatch[0].rm_so, pmatch[0].rm_eo - pmatch[0].rm_so));
            Jsi_DSFree(&sStr);
            Jsi_IncrRefCount(interp, inStr);
            if (maxArgs==1) {
                Jsi_RC rc = Jsi_FunctionInvokeString(interp, repVal, inStr, &dStr);
                if (Jsi_InterpGone(interp))
                    return JSI_ERROR;
                if (rc != JSI_OK) {
................................................................................
                    Jsi_DecrRefCount(interp, inStr);
                    return JSI_ERROR;
                }
            } else {
                Jsi_Value *vpargs, *items[MAX_SUBREGEX] = {}, *ret;
                int i;
                items[0] = inStr;
                for (i=1; i<=(int)re->reg.re_nsub && i<(MAX_SUBREGEX-3); i++)



                    items[i] = (pmatch[i].rm_so<0?interp->NullValue:Jsi_ValueMakeString(interp, NULL, jsi_SubstrDup(p, pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so)));



                items[i++] = Jsi_ValueMakeNumber(interp, NULL, eoffset+pmatch[0].rm_so);
                items[i++] = strVal;
                vpargs = Jsi_ValueMakeObject(interp, NULL, Jsi_ObjNewArray(interp, items, i, 0));
                Jsi_IncrRefCount(interp, vpargs);
                ret = Jsi_ValueNew1(interp);
                rc = Jsi_FunctionInvoke(interp, repVal, vpargs, &ret, NULL);
                if (Jsi_InterpGone(interp))
................................................................................
    } while (n);

    /*
     * Copy the portion of the string after the last match to the
     * result variable.
     */
    Jsi_DSAppend(&dStr, p, NULL);
    Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
    return rc;

}

static Jsi_RC StringSearchCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
................................................................................
  }
  *pbuf = '\0';
  return buf;
}

/* Returns a url-decoded version of str */
/* IMPORTANT: be sure to free() the returned string after use */
static char *url_decode(char *str) {
  char *pstr = str, *buf = (char*)Jsi_Malloc(Jsi_Strlen(str) + 1), *pbuf = buf;
  while (*pstr) {
    if (*pstr == '%') {
      if (pstr[1] && pstr[2]) {
        *pbuf++ = jsi_fromHexChar(pstr[1]) << 4 | jsi_fromHexChar(pstr[2]);
        pstr += 2;
      }
................................................................................
      *pbuf++ = ' ';
    } else {
      *pbuf++ = *pstr;
    }
    pstr++;
  }
  *pbuf = '\0';

  return buf;
}

static Jsi_RC EncodeURICmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    char *cp, *str = Jsi_ValueArrayIndexToStr(interp, args, 0, NULL);
................................................................................
    return JSI_OK;
}

static Jsi_RC DecodeURICmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    char *cp, *str = Jsi_ValueArrayIndexToStr(interp, args, 0, NULL);
    cp = url_decode(str);
    Jsi_ValueMakeString(interp, ret, cp);

    return JSI_OK;
}

static Jsi_RC SysSleepCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_Number dtim = 1;
................................................................................
}

static Jsi_RC B64Decode(Jsi_Interp *interp, char *inbuffer, int ilen, Jsi_Value **ret)
{
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    B64DecodeDStr(inbuffer, ilen, &dStr);
    Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
    return JSI_OK;
}

static Jsi_RC
B64EncodeDStr(const char *ib, int ilen, Jsi_DString *dStr)
{
    int i=0, pos=0;
................................................................................

static Jsi_RC
B64Encode(Jsi_Interp *interp, char *ib, int ilen, Jsi_Value **ret)
{
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    B64EncodeDStr(ib, ilen, &dStr);
    Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
    return JSI_OK;
}

Jsi_RC Jsi_Base64(const char *str, int len, Jsi_DString *dStr, bool decode)
{
    if (len<0)
        len = Jsi_Strlen(str);
................................................................................
        Jsi_ValueMakeStringKey(interp, ret, ".");
    }
    else if (p == path) {
        Jsi_ValueMakeStringKey(interp, ret, "/");
    }
#if defined(__MINGW32__) || defined(_MSC_VER)
    else if (p[-1] == ':') {


        Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(path, 0, p-path+1));
    }
#endif
    else {
        Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(path, 0, p-path));


    }
    return JSI_OK;
}

static Jsi_RC FileRootnameCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
................................................................................
    const char *lastSlash = Jsi_Strrchr(path, '/');
    const char *p = Jsi_Strrchr(path, '.');

    if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
        Jsi_ValueMakeStringDup(interp, ret, path);
    }
    else {
        Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(path,0, p-path));


    }
    return JSI_OK;
}
static Jsi_RC FileExtensionCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    const char *path = Jsi_ValueString(interp, Jsi_ValueArrayIndex(interp, args, 0), NULL);
................................................................................
    char *newname;
    if (*path2 == '/' || *path2 == '~')
        newname = Jsi_FileRealpath(interp, p2, NULL);
    else {
        Jsi_DString dStr = {};
        Jsi_DSAppend(&dStr, path1, "/", path2, NULL);
        Jsi_Value *tpPtr = Jsi_ValueNew1(interp);
        Jsi_ValueMakeString(interp, &tpPtr, Jsi_DSFreeDup(&dStr));
        newname = Jsi_FileRealpath(interp, tpPtr, NULL);
        Jsi_DecrRefCount(interp, tpPtr);
    }
    if (newname ==  NULL)
        return JSI_ERROR;
    Jsi_ValueMakeString(interp, ret, (char*)newname);
    return JSI_OK;
................................................................................
    int bufferPwr2;
    jsi_wsStatData stats;
    char *iface;
    const char* urlPrefix, *urlRedirect;
    const char *localhostName;
    const char *clientName;
    const char *clientIP;
    const char *useridPass;
    const char *realm, *includeFile;
    struct lws_context *instCtx;
    Jsi_Value *getRegexp, *post;
    unsigned int oldus;
    int opts;
    int hasOpts;
    int debug;
    int maxConnects;
................................................................................
    JSI_OPT(BOOL,   jsi_wsCmdObj, echo,       .help="LogInfo outputs all websock Send/Recv messages"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, formParams, .help="Comma seperated list of upload form param names ('text,send,file,upload')", jsi_IIRO),
    JSI_OPT(OBJ,    jsi_wsCmdObj, extArgs,    .help="Arguments for extension handlers", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, extHandlers,.help="Enable builtin handlers for these extensions: .htmli, .cssi, .jsi, and .md", jsi_IIOF),
    JSI_OPT(REGEXP, jsi_wsCmdObj, getRegexp,  .help="Call onGet() only if Url matches pattern"),
//    JSI_OPT(CUSTOM, jsi_wsCmdObj, handlersPkg,.help="Handlers use package() to upgrade string to function object"),
    JSI_OPT(ARRAY,  jsi_wsCmdObj, headers,    .help="List of name/value output header pairs", jsi_IIOF),

    JSI_OPT(STRING, jsi_wsCmdObj, interface,  .help="Interface for server to listen on, eg. 'eth0' or 'lo'", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, local,      .help="Limit connections to localhost addresses on the 127 network"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, localhostName,.help="Client name used by localhost connections ('localhost')"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxConnects,.help="In server mode, max number of client connections accepted"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxDownload,.help="Max size of file download"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxUpload,  .help="Max size of file upload will accept"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, mimeTypes,  .help="Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'})", jsi_IIOF),
................................................................................
    JSI_OPT(STRING, jsi_wsCmdObj, post,       .help="Post string to serve", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, protocol,   .help="Name of protocol (ws/wss)"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, realm,      .help="Realm for basic auth (jsish)", ),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufMax, .help="Size limit of a websocket message", jsi_IIOF),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufTimeout,.help="Timeout for recv of a websock msg", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, redirMax,   .help="Temporarily disable redirects when see more than this in 10 minutes"),
    JSI_OPT(STRING, jsi_wsCmdObj, rootdir,    .help="Directory to serve html from (\".\")"),

    JSI_OPT(CUSTOM, jsi_wsCmdObj, stats,      .help="Statistical data", jsi_IIRO, .custom=Jsi_Opt_SwitchSuboption, .data=WPSStats),
    JSI_OPT(TIME_T, jsi_wsCmdObj, startTime,  .help="Time of websocket start", jsi_IIRO),
    JSI_OPT(STRKEY, jsi_wsCmdObj, includeFile, .help="Default file when no extension given (include.shtml)"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlPrefix,  .help="Prefix in url to strip from path; for reverse proxy"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlRedirect,.help="Redirect when no url or / is given. Must match urlPrefix, if given"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, use_ssl,    .help="Use https (for client)", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, useridPass, .help="The USERID:PASSWORD to use for basic authentication"),
................................................................................
    int code, const char *extra, const char *mime, Jsi_DString *jStr)
{
    uchar ubuf[JSI_BUFSIZ], *p=ubuf, *end = &ubuf[sizeof(ubuf)-1];
    if (!mime) mime = "text/html";
    if (code<=0) code = 200;
    if (lws_add_http_header_status(wsi, code, &p, end))
        return -1;


    if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER, (uchar*)"libwebsockets", 13, &p, end))
        return -1;
    if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (uchar *)mime, Jsi_Strlen(mime), &p, end))
        return -1;
    if (lws_add_http_header_content_length(wsi, strLen, &p, end))
        return -1;
    *p = 0;
    Jsi_DSAppend(jStr, (char*)ubuf, extra, NULL);
................................................................................
            if (n>0)
                Jsi_DSAppendLen(hStr, (char*)buffer, n);
            p = buffer;
        }
    }
    return true;
}

















// Read native file only if inside rootdir
static Jsi_RC jsi_wsFileRead(Jsi_Interp *interp, Jsi_Value *name, Jsi_DString *dStr, jsi_wsCmdObj *cmdPtr) {
    Jsi_StatBuf sb;
    Jsi_RC rc = JSI_ERROR;
    int n = Jsi_Stat(interp, name, &sb);
    if (!n && sb.st_size>0) {
................................................................................
    int lvl) {
    Jsi_Value *fval;
    Jsi_RC rc = JSI_OK;
    char *cp, *cp2, *ce, pref[] = "<!--#include file=\"", suffix[] = "\"-->",
        pref2[] = "<!--#include virtual=\"";
    int flen, plen, plen1 = sizeof(pref)-1,  plen2 = sizeof(pref2)-1, slen = sizeof(suffix)-1;
    Jsi_DString tStr = {};

    const char *cs = "<!-- Markdeep: --><style class=\"fallback\">body{visibility:hidden;}</style>\n"
                "<script>window.markdeepOptions={tocStyle:\"medium\"}</script>\n"
                "<!--#include file=\"$inc\"-->\n"
                "<script src=\"markdeep.min.js\"></script>\n"
                "<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility='visible')</script>";
    char *fs, *fname = Jsi_ValueString(interp, fn, &flen), *fend = fname;
    char fbuf[PATH_MAX];
................................................................................
    time_t now = time(NULL);
    char buf[JSI_BUFSIZ];
    int rc = 0, essi = 0;
    buf[0] = 0;
    uchar *p = buffer, *end = &buffer[sizeof(buffer)-1];
    int n;
    Jsi_Value* fname = NULL;
    bool isMdi = 0;

    /* if a legal POST URL, let it continue and accept data */
    if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
        return 0;
    if (!pss)
        pss = jsi_wsgetPss(cmdPtr, wsi, user, 1, 1);

................................................................................
            }
        }
    }

    snprintf(buf, sizeof(buf), "%s/%s", cmdPtr->curRoot, inPtr);
    if (cmdPtr->debug>1)
        fprintf(stderr, "FILE: %s in %s | %s\n", buf, cmdPtr->curRoot, Jsi_ValueString(interp, cmdPtr->rootdir, NULL));
    char extBuf[100];

    bool isgzip = 0;
    if (!ext || !ext[1])
        mime = "text/html";
    else {
        const char *eext = ext+1;
        uint elen = Jsi_Strlen(ext);
        if (elen>3 && elen<(sizeof(extBuf)-10) && !Jsi_Strcmp(ext+elen-3,".gz")) {
................................................................................
            goto bail;
    }
    if (cmdPtr->headers && !jsi_wsAddHeader(interp, cmdPtr, wsi, cmdPtr->headers, &hStr))
        goto bail;

    if (pss->headers && !jsi_wsAddHeader(interp, cmdPtr, wsi, pss->headers, &hStr))
        goto bail;


    n = Jsi_DSLength(&hStr);

    if (native && !isMdi) {
        Jsi_DecrRefCount(interp, fname);



        int hrc = lws_serve_http_file(wsi, buf, mime, Jsi_DSValue(&hStr), Jsi_DSLength(&hStr));
        if (hrc<0) {
            if (cmdPtr->noWarn==0)
                fprintf(stderr, "can not serve file (%d): %s\n", hrc, buf);
            goto bail;
        } else if (hrc > 0 && lws_http_transaction_completed(wsi))
            goto bail;
    } else {
        // Need to read data for non-native files.
        Jsi_DString dStr = {}, fStr = {};
        if (isMdi)
            rc = jsi_wsTemplateFill(interp, cmdPtr, fname, &fStr, (essi?1:0));
        else
            rc = jsi_wsFileRead(interp, fname, &fStr, cmdPtr);



        if (rc != JSI_OK) {
            Jsi_DSFree(&fStr);
            goto nofile;
        }
        int hrc = jsi_wsServeHeader(pss, wsi, (int)Jsi_DSLength(&fStr), 200, Jsi_DSValue(&hStr), mime, &dStr);
        if (hrc>=0) {
            Jsi_DSAppendLen(&dStr, Jsi_DSValue(&fStr), Jsi_DSLength(&fStr));
................................................................................
    cmdPtr->ietf_version = -1;
    cmdPtr->bufferPwr2 = 0;
    cmdPtr->ws_gid = -1;
    cmdPtr->ws_uid = -1;
    cmdPtr->startTime = time(NULL);
    cmdPtr->hasOpts = 1;
    cmdPtr->includeFile = "include.shtml";

    if ((arg != NULL && !Jsi_ValueIsNull(interp,arg))
        && Jsi_OptionsProcess(interp, WSOptions, cmdPtr, arg, 0) < 0) {
bail:
        jsi_wswebsocketObjFree(interp, cmdPtr);
        return JSI_ERROR;
    }
    Jsi_PathNormalize(interp, &cmdPtr->rootdir);
................................................................................
    Jsi_StructSpec *sf = jsi_csStructFields(interp, arg1);

    if (!sf)
        return Jsi_LogError("unkown struct: %s", arg1);;

    Jsi_DString dStr = {};
    Jsi_OptionsData(interp, (Jsi_OptionSpec*)sf, &dStr, 1);
    Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
    Jsi_DSFree(&dStr);
    return JSI_OK;
}

/* Scanning function */
static Jsi_RC jsi_csValueToFieldType(Jsi_Interp *interp, Jsi_OptionSpec* spec, Jsi_Value *inValue, const char *inStr, void *record, Jsi_Wide flags)
{
................................................................................
                    Assert(l1>=0 && l1<=JSI_MAX_ALLOC_BUF);
                    Assert(l2>=0 && l2<=JSI_MAX_ALLOC_BUF);
                    str = (char*)Jsi_Malloc(l1+l2+1);
                    memcpy(str, s2, l2);
                    memcpy(str+l2, s1, l1);
                    str[l1+l2] = 0;
                    jsiClearStack(interp,2);
                    Jsi_ValueMakeString(interp, &v2, str);
                } else {
                    Jsi_ValueToNumber(interp, v1);
                    Jsi_ValueToNumber(interp, v2);
                    rc = _jsi_StrictChk2(v1, v2);
                    Jsi_Number n = v1->d.num + v2->d.num;
                    jsiClearStack(interp,2);
                    Jsi_ValueMakeNumber(interp, &v2, n);






|







 







|







 







|







 







|







 







|







 







>
>
>
>







 







|







 







|







 







|













|







 







|
|
>







 







|

|







 







|







 







|

>
>
>
|
|
>
>
|
|
|

|




>





>







 







|







 







|







 







|


|

>


|
<
>
>
|









|
|
>
|







 







|


<
>

|
|
>
|











|
|
>
|







 







|







 







|







 







|







 







|







 







|
|
|







 







|
>
>
>
|
>
>
>







 







|







 







|







 







>







 







|
|
>







 







|







 







|







 







>
>
|



|
>
>







 







|
>
>







 







|







 







|
|







 







>







 







>







 







>
>
|







 







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







 







>







 







|







 







|
>







 







>



|


>
>












|

>
>
>







 







>







 







|







 







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
....
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
....
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
....
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
....
7652
7653
7654
7655
7656
7657
7658
7659
7660
7661
7662
7663
7664
7665
7666
7667
7668
7669
....
8948
8949
8950
8951
8952
8953
8954
8955
8956
8957
8958
8959
8960
8961
8962
....
8972
8973
8974
8975
8976
8977
8978
8979
8980
8981
8982
8983
8984
8985
8986
.....
19510
19511
19512
19513
19514
19515
19516
19517
19518
19519
19520
19521
19522
19523
19524
19525
19526
19527
19528
19529
19530
19531
19532
19533
19534
19535
19536
19537
19538
.....
19559
19560
19561
19562
19563
19564
19565
19566
19567
19568
19569
19570
19571
19572
19573
19574
19575
.....
19583
19584
19585
19586
19587
19588
19589
19590
19591
19592
19593
19594
19595
19596
19597
19598
19599
.....
19617
19618
19619
19620
19621
19622
19623
19624
19625
19626
19627
19628
19629
19630
19631
.....
27579
27580
27581
27582
27583
27584
27585
27586
27587
27588
27589
27590
27591
27592
27593
27594
27595
27596
27597
27598
27599
27600
27601
27602
27603
27604
27605
27606
27607
27608
27609
27610
27611
27612
27613
27614
27615
27616
27617
.....
27803
27804
27805
27806
27807
27808
27809
27810
27811
27812
27813
27814
27815
27816
27817
.....
27819
27820
27821
27822
27823
27824
27825
27826
27827
27828
27829
27830
27831
27832
27833
.....
27901
27902
27903
27904
27905
27906
27907
27908
27909
27910
27911
27912
27913
27914
27915
27916

27917
27918
27919
27920
27921
27922
27923
27924
27925
27926
27927
27928
27929
27930
27931
27932
27933
27934
27935
27936
27937
27938
27939
.....
27948
27949
27950
27951
27952
27953
27954
27955
27956
27957

27958
27959
27960
27961
27962
27963
27964
27965
27966
27967
27968
27969
27970
27971
27972
27973
27974
27975
27976
27977
27978
27979
27980
27981
27982
27983
27984
27985
.....
28052
28053
28054
28055
28056
28057
28058
28059
28060
28061
28062
28063
28064
28065
28066
.....
28313
28314
28315
28316
28317
28318
28319
28320
28321
28322
28323
28324
28325
28326
28327
.....
28397
28398
28399
28400
28401
28402
28403
28404
28405
28406
28407
28408
28409
28410
28411
.....
28461
28462
28463
28464
28465
28466
28467
28468
28469
28470
28471
28472
28473
28474
28475
.....
28561
28562
28563
28564
28565
28566
28567
28568
28569
28570
28571
28572
28573
28574
28575
28576
28577
.....
28579
28580
28581
28582
28583
28584
28585
28586
28587
28588
28589
28590
28591
28592
28593
28594
28595
28596
28597
28598
28599
28600
.....
28635
28636
28637
28638
28639
28640
28641
28642
28643
28644
28645
28646
28647
28648
28649
.....
35305
35306
35307
35308
35309
35310
35311
35312
35313
35314
35315
35316
35317
35318
35319
.....
35321
35322
35323
35324
35325
35326
35327
35328
35329
35330
35331
35332
35333
35334
35335
.....
35338
35339
35340
35341
35342
35343
35344
35345
35346
35347
35348
35349
35350
35351
35352
35353
35354
.....
38052
38053
38054
38055
38056
38057
38058
38059
38060
38061
38062
38063
38064
38065
38066
.....
38091
38092
38093
38094
38095
38096
38097
38098
38099
38100
38101
38102
38103
38104
38105
.....
39547
39548
39549
39550
39551
39552
39553
39554
39555
39556
39557
39558
39559
39560
39561
39562
39563
39564
39565
39566
39567
39568
39569
.....
39573
39574
39575
39576
39577
39578
39579
39580
39581
39582
39583
39584
39585
39586
39587
39588
39589
.....
39640
39641
39642
39643
39644
39645
39646
39647
39648
39649
39650
39651
39652
39653
39654
.....
52794
52795
52796
52797
52798
52799
52800
52801
52802
52803
52804
52805
52806
52807
52808
52809
.....
52956
52957
52958
52959
52960
52961
52962
52963
52964
52965
52966
52967
52968
52969
52970
.....
52986
52987
52988
52989
52990
52991
52992
52993
52994
52995
52996
52997
52998
52999
53000
.....
53159
53160
53161
53162
53163
53164
53165
53166
53167
53168
53169
53170
53171
53172
53173
53174
53175
.....
53449
53450
53451
53452
53453
53454
53455
53456
53457
53458
53459
53460
53461
53462
53463
53464
53465
53466
53467
53468
53469
53470
53471
53472
53473
53474
53475
53476
53477
53478
.....
53493
53494
53495
53496
53497
53498
53499
53500
53501
53502
53503
53504
53505
53506
53507
.....
53596
53597
53598
53599
53600
53601
53602
53603
53604
53605
53606
53607
53608
53609
53610
.....
53729
53730
53731
53732
53733
53734
53735
53736
53737
53738
53739
53740
53741
53742
53743
53744
.....
53978
53979
53980
53981
53982
53983
53984
53985
53986
53987
53988
53989
53990
53991
53992
53993
53994
53995
53996
53997
53998
53999
54000
54001
54002
54003
54004
54005
54006
54007
54008
54009
54010
54011
54012
54013
54014
54015
54016
54017
.....
55293
55294
55295
55296
55297
55298
55299
55300
55301
55302
55303
55304
55305
55306
55307
.....
58888
58889
58890
58891
58892
58893
58894
58895
58896
58897
58898
58899
58900
58901
58902
.....
69822
69823
69824
69825
69826
69827
69828
69829
69830
69831
69832
69833
69834
69835
69836
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   8
#define JSI_VERSION_RELEASE 34

#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_EXTERN Jsi_Number Jsi_Version(void); /*STUB = 183*/
JSI_EXTERN Jsi_Value* Jsi_ReturnValue(Jsi_Interp *interp); /*STUB = 184*/
JSI_EXTERN Jsi_RC Jsi_Mount( Jsi_Interp *interp, Jsi_Value *archive, Jsi_Value *mount, Jsi_Value **ret); /*STUB = 185*/
JSI_EXTERN Jsi_Value* Jsi_Executable(Jsi_Interp *interp); /*STUB = 186*/
JSI_EXTERN Jsi_Regex* Jsi_RegExpNew(Jsi_Interp *interp, const char *regtxt, int flag); /*STUB = 187*/
JSI_EXTERN void Jsi_RegExpFree(Jsi_Regex* re); /*STUB = 188*/
JSI_EXTERN Jsi_RC Jsi_RegExpMatch( Jsi_Interp *interp,  Jsi_Value *pattern, const char *str, int *rc, Jsi_DString *dStr); /*STUB = 189*/
JSI_EXTERN Jsi_RC Jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, int slen, Jsi_Value *ret); /*STUB = 190*/
JSI_EXTERN bool Jsi_GlobMatch(const char *pattern, const char *string, int nocase); /*STUB = 191*/
JSI_EXTERN char* Jsi_FileRealpath(Jsi_Interp *interp, Jsi_Value *path, char *newpath); /*STUB = 192*/
JSI_EXTERN char* Jsi_FileRealpathStr(Jsi_Interp *interp, const char *path, char *newpath); /*STUB = 193*/
JSI_EXTERN char* Jsi_NormalPath(Jsi_Interp *interp, const char *path, Jsi_DString *dStr); /*STUB = 194*/
JSI_EXTERN char* Jsi_ValueNormalPath(Jsi_Interp *interp, Jsi_Value *path, Jsi_DString *dStr); /*STUB = 195*/
JSI_EXTERN Jsi_RC Jsi_PathNormalize(Jsi_Interp *interp, Jsi_Value **pathPtr); /*STUB = 410*/
JSI_EXTERN Jsi_RC Jsi_JSONParse(Jsi_Interp *interp, const char *js, Jsi_Value **ret, int flags); /*STUB = 196*/
................................................................................
#ifndef __JSI_STUBS_H__
#define __JSI_STUBS_H__
#ifndef JSI_AMALGAMATION
#include "jsi.h"
#endif


#define JSI_STUBS_MD5 "84f582f050ca4afde696dea1f107497f"

#undef JSI_EXTENSION_INI
#define JSI_EXTENSION_INI Jsi_Stubs *jsiStubsPtr = NULL;

#ifdef JSI__MUSL
#define JSI_STUBS_BLDFLAGS 1
#else
................................................................................
    Jsi_Number(*_Jsi_Version)(void);
    Jsi_Value*(*_Jsi_ReturnValue)(Jsi_Interp *interp);
    Jsi_RC(*_Jsi_Mount)( Jsi_Interp *interp, Jsi_Value *archive, Jsi_Value *mount, Jsi_Value **ret);
    Jsi_Value*(*_Jsi_Executable)(Jsi_Interp *interp);
    Jsi_Regex*(*_Jsi_RegExpNew)(Jsi_Interp *interp, const char *regtxt, int flag);
    void(*_Jsi_RegExpFree)(Jsi_Regex* re);
    Jsi_RC(*_Jsi_RegExpMatch)( Jsi_Interp *interp,  Jsi_Value *pattern, const char *str, int *rc, Jsi_DString *dStr);
    Jsi_RC(*_Jsi_RegExpMatches)(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, int slen, Jsi_Value *ret);
    bool(*_Jsi_GlobMatch)(const char *pattern, const char *string, int nocase);
    char*(*_Jsi_FileRealpath)(Jsi_Interp *interp, Jsi_Value *path, char *newpath);
    char*(*_Jsi_FileRealpathStr)(Jsi_Interp *interp, const char *path, char *newpath);
    char*(*_Jsi_NormalPath)(Jsi_Interp *interp, const char *path, Jsi_DString *dStr);
    char*(*_Jsi_ValueNormalPath)(Jsi_Interp *interp, Jsi_Value *path, Jsi_DString *dStr);
    Jsi_RC(*_Jsi_JSONParse)(Jsi_Interp *interp, const char *js, Jsi_Value **ret, int flags);
    Jsi_RC(*_Jsi_JSONParseFmt)(Jsi_Interp *interp, Jsi_Value **ret, const char *fmt, ...);
................................................................................
#define Jsi_Version(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_Version(n0))
#define Jsi_ReturnValue(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_ReturnValue(n0))
#define Jsi_Mount(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_Mount(n0,n1,n2,n3))
#define Jsi_Executable(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_Executable(n0))
#define Jsi_RegExpNew(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpNew(n0,n1,n2))
#define Jsi_RegExpFree(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpFree(n0))
#define Jsi_RegExpMatch(n0,n1,n2,n3,n4) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpMatch(n0,n1,n2,n3,n4))
#define Jsi_RegExpMatches(n0,n1,n2,n3,n4) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpMatches(n0,n1,n2,n3,n4))
#define Jsi_GlobMatch(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_GlobMatch(n0,n1,n2))
#define Jsi_FileRealpath(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_FileRealpath(n0,n1,n2))
#define Jsi_FileRealpathStr(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_FileRealpathStr(n0,n1,n2))
#define Jsi_NormalPath(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_NormalPath(n0,n1,n2))
#define Jsi_ValueNormalPath(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_ValueNormalPath(n0,n1,n2))
#define Jsi_JSONParse(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_JSONParse(n0,n1,n2,n3))
#define Jsi_JSONParseFmt(n0,n1,n2,...) JSISTUBCALL(jsiStubsPtr, _Jsi_JSONParseFmt(n0,n1,n2,##__VA_ARGS__))
................................................................................

#ifdef __FreeBSD__
#define _JSICASTINT(s) (int)(s)
#else
#define _JSICASTINT(s) (s)
#endif

#ifndef __DBL_DECIMAL_DIG__
#define __DBL_DECIMAL_DIG__ 17
#endif

#if 0
#ifndef uint
typedef unsigned int uint;
#endif
#ifndef uchar
typedef unsigned char uchar;
#endif
................................................................................
#define _JSI_MEMCLEAR(ptr) memset(ptr, 0, sizeof(*ptr)) /* To aid debugging memory.*/
#endif
#endif

#define MAX_SUBREGEX    256
#define JSI__LONG_LONG
#define UCHAR(s) (unsigned char)(s)
extern char* jsi_SubstrDup(const char *a, int alen, int start, int len, int *olen);
extern int jsi_typeGet(Jsi_Interp *interp , const char *tname);
extern const char *jsi_typeName(Jsi_Interp *interp, int typ, Jsi_DString *dStr);
extern Jsi_RC jsi_ArgTypeCheck(Jsi_Interp *interp, int typ, Jsi_Value *arg, const char *p1, const char *p2, int index, Jsi_Func *func, bool isdefault);
extern void jsi_FuncCallCheck(jsi_Pstate *p, jsi_Pline *line, int argc, bool isNew, const char *name, const char *namePre, Jsi_OpCodes *argCodes);
extern Jsi_RC jsi_RunFuncCallCheck(Jsi_Interp *interp, Jsi_Func *func, int argc, const char *name, jsi_Pline *line, Jsi_OpCodes *argCodes, bool isParse);
extern Jsi_RC jsi_FunctionSubCall(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Value *tocall, int discard);
extern Jsi_ScopeStrs *jsi_ArgsOptAdd(jsi_Pstate *pstate, Jsi_ScopeStrs *a);
................................................................................
extern int jsi_GetDefaultType(const char *cp);
extern Jsi_RC jsi_ParseTypeCheckStr(Jsi_Interp *interp, const char *str);
extern Jsi_Interp *jsi_DoExit(Jsi_Interp *interp, int rc);
extern Jsi_RC jsi_CDataDataSetCmdSub(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Func *funcPtr, int flags);
extern Jsi_RC jsi_AliasInvoke(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Func *funcPtr);
extern Jsi_Number jsi_VersionNormalize(Jsi_Number ver, char *obuf, size_t osiz);
extern const char* jsi_FuncGetCode(Jsi_Interp *interp, Jsi_Func *func, int *lenPtr);
extern Jsi_RC jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, int slen, Jsi_Value *ret, int *ofs, bool match);

extern Jsi_RC Jsi_CleanValue(Jsi_Interp *interp, Jsi_Interp *tointerp, Jsi_Value *val, Jsi_Value **ret); //TODO: EXPORT

extern char jsi_toHexChar(char code);
extern char jsi_fromHexChar(char ch);
extern bool jsi_IsAlnumStr(const char *cp);
extern char *jsi_TrimStr(char *str);
................................................................................
    }
    
    return JSI_OK;
}



Jsi_RC jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, int n, Jsi_Value *ret, int *ofs, bool match)
{
    Jsi_Regex *re;
    int regexec_flags = 0;
    Jsi_Value *seq = pattern;

    if (seq == NULL || seq->vt != JSI_VT_OBJECT || seq->d.obj->ot != JSI_OT_REGEXP) {
        Jsi_ValueMakeNull(interp, &ret);
        return JSI_OK;
    }
    re = seq->d.obj->d.robj;
    regex_t *reg = &re->reg;
    
    regmatch_t pos[MAX_SUBREGEX] = {};
    int num_matches = 0, r;
    int isglob = (re->eflags&JSI_REG_GLOB);
    Jsi_Obj *obj;
    
    do {
        r = regexec(reg, str, MAX_SUBREGEX, pos, regexec_flags);

        if (r >= REG_BADPAT) {
................................................................................
        int i;
        for (i = 0; i < MAX_SUBREGEX; ++i) {
            if (pos[i].rm_so <= 0 && pos[i].rm_eo <= 0)
                break;
            if (i && pos[i].rm_so == pos[i-1].rm_so && pos[i].rm_eo == pos[i-1].rm_eo)
                continue;
    
            int olen = -1;
            char *ostr = jsi_SubstrDup(str, -1, pos[i].rm_so, pos[i].rm_eo - pos[i].rm_so, &olen);
            Jsi_Value *val = Jsi_ValueMakeBlob(interp, NULL, (uchar*)ostr, olen);
            if (ofs)
                *ofs = pos[i].rm_eo;
            Jsi_ValueInsertArray(interp, ret, num_matches, val, 0);
            num_matches++;
            if ( match && isglob)
                break;
        }
................................................................................

        regexec_flags |= REG_NOTBOL;
    } while (n && pos[0].rm_eo>0);
    
    return JSI_OK;
}

Jsi_RC Jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, int slen, Jsi_Value *ret)
{
    return jsi_RegExpMatches(interp, pattern, str, slen, ret, NULL, 0);
}


#define FN_regexec JSI_INFO("\
Perform regexp match checking.  Returns the array of matches.\
With the global flag g, sets lastIndex and returns next match.")
static Jsi_RC RegexpExecCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
................................................................................
        l = Jsi_ValueObjLookup(interp, v, "lastIndex", 0);
        if (l && Jsi_ValueGetNumber(interp, l, &lv) != JSI_OK) 
            return Jsi_LogError("lastIndex not a number");
        if (l)
            re->lastIndex = (int)lv;
    }
    int ofs = 0;
    Jsi_RC rc = jsi_RegExpMatches(interp, v, re->lastIndex<slen?str+re->lastIndex:"", -1, *ret, isglob?&ofs:NULL, 0);
    if (isglob) {
        if (rc != JSI_OK)
            return rc;
        re->lastIndex += ofs;
        if (Jsi_ValueIsNull(interp, *ret))
            re->lastIndex = 0;
        lv = (Jsi_Number)re->lastIndex;
................................................................................
        len = Jsi_Strlen(str);
    char *cp = (char*)Jsi_Malloc(len+1);
    memcpy(cp, str, len);
    cp[len] = 0;
    return cp;
}

char *jsi_SubstrDup(const char *a, int alen, int start, int len, int *olen)
{
    if (len == 0) {
empty:
        *olen = 0;
        return Jsi_Strdup("");
    }
    
    if (alen<0)
        alen = Jsi_Strlen(a);
    while (start < 0) start += alen;
    if (start >= alen) goto empty;
    
    int maxcpy = alen - start;
    
    if (len > 0) {
        maxcpy = maxcpy < len ? maxcpy : len;
    }
    if (maxcpy<=0) goto empty;
    
    char *r = (char*)Jsi_Malloc(maxcpy + 2);

    Jsi_Strncpy(r, a + start, maxcpy + 1);
    r[maxcpy + 1] = 0;
    *olen = maxcpy;
    return r;
}


char* Jsi_Strrchr(const char *str, int c)
{
    return strrchr((char*)str, c);
................................................................................
    }

static Jsi_RC StringConstructor(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    if (Jsi_FunctionIsConstructor(funcPtr)) {
        const char *nv = "";
        int len = -1;
        if (Jsi_ValueGetLength(interp, args) > 0) {
            Jsi_Value *v = Jsi_ValueArrayIndex(interp, args, 0);
            if (v) {
                
                nv = Jsi_ValueToString(interp, v, &len);
            }
        }
................................................................................
            if (_this->d.obj->d.s.str)
                if (!_this->d.obj->isstrkey)
                    Jsi_Free(_this->d.obj->d.s.str);
            _this->d.obj->isstrkey = 0;
            _this->d.obj->d.s.str = Jsi_StrdupLen(nv, len);
            _this->d.obj->d.s.len = len;
        } else
            jsi_ValueMakeBlobDup(interp, &_this, (uchar*)nv, len);
        Jsi_ValueDup2(interp, ret, _this);
        return JSI_OK;
    }
    if (Jsi_ValueGetLength(interp, args) > 0) {
        Jsi_Value *v = Jsi_ValueArrayIndex(interp, args, 0);
        if (v) {
            Jsi_ValueDup2(interp, ret, v);
................................................................................
    ChkString(_this, funcPtr, v, &sLen, &bLen);

    Jsi_Value *start = Jsi_ValueArrayIndex(interp, args, skip);
    Jsi_Value *len = Jsi_ValueArrayIndex(interp, args, skip+1);
    
    Jsi_Number nstart, nlen;
    if (!start || Jsi_GetNumberFromValue(interp,start, &nstart) != JSI_OK) {
        jsi_ValueMakeBlobDup(interp, ret, (uchar*)v, bLen);
        return JSI_OK;
    }
    int istart = (int)nstart, olen = -1;
    Jsi_DString dStr;
    char *ostr;
    Jsi_DSInit(&dStr);
    if (!len || Jsi_GetNumberFromValue(interp,len, &nlen) != JSI_OK) {
        if (sLen == bLen) {

            ostr = jsi_SubstrDup(v, bLen, istart, -1, &olen);
            Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
        } else {
            Jsi_UtfSubstr(v, istart, -1, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
        return JSI_OK;
    }
    int ilen = (int)nlen;
    if (ilen <= 0) {
        Jsi_ValueMakeStringDup(interp, ret, "");
    } else {
        if (sLen == bLen) {
            ostr = jsi_SubstrDup(v, bLen, istart, ilen, &olen);
            Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
        } else {
            Jsi_UtfSubstr(v, istart, ilen, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
    }
    return JSI_OK;
}

................................................................................
    Jsi_Value *end = Jsi_ValueArrayIndex(interp, args, skip+1);
    
    Jsi_Number nstart, nend;
    if (!start || Jsi_GetNumberFromValue(interp,start, &nstart) != JSI_OK) {
        Jsi_ValueMakeStringDup(interp, ret, v);
        return JSI_OK;
    }
    int istart = (int)nstart, olen = -1;
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);

    char *ostr;
    if (!end || Jsi_GetNumberFromValue(interp,end, &nend) != JSI_OK) {
        if (sLen == bLen) {
            ostr = jsi_SubstrDup(v, bLen, istart, -1, &olen);
            Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
        } else {
            Jsi_UtfSubstr(v, istart, -1, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
        return JSI_OK;
    }
    int iend = (int)nend;
    if (iend>sLen)
        iend = sLen;
    if (iend < istart) {
        Jsi_ValueMakeStringDup(interp, ret, "");
    } else {
        if (sLen == bLen) {
            ostr = jsi_SubstrDup(v, bLen, istart, iend-istart+1, &olen);
            Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
        } else {
            Jsi_UtfSubstr(v, istart, iend-istart+1, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
    }
    return JSI_OK;
}

................................................................................
    if (Jsi_ValueIsString(interp, seq)) {
        char *cp = Jsi_ValueString(interp, seq, NULL);

        if (jsi_RegExpValueNew(interp, cp, seq) != JSI_OK)
            return JSI_ERROR;
    }
    /* TODO: differentiate from re.exec() */
    return jsi_RegExpMatches(interp, seq, v, bLen, *ret, NULL, 1);
}

static Jsi_RC StringFromCharCodeCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    if (!(_this->vt == JSI_VT_OBJECT && _this->d.obj->ot == JSI_OT_FUNCTION &&
       _this->d.obj->__proto__ == interp->String_prototype->d.obj->__proto__ ))
................................................................................
            Jsi_LogError("String get failure");
            Jsi_DSFree(&dStr);
            return JSI_ERROR;
        }
        Jsi_DSAppend(&dStr, vstr, NULL);
    }

    Jsi_ValueFromDS(interp, &dStr, ret);
    return JSI_OK;
    
}

static Jsi_RC StringSliceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
................................................................................
                j += slen;
            }
        }
        if (i>=obj->arrCnt)
            Jsi_DSAppendLen(&dStr, p, 1);
    }

    Jsi_ValueFromDS(interp, &dStr, ret);
    return JSI_OK;
}
    
#define FN_strreplace JSI_INFO("\
If the replace argument is a function, it is called with match,p1,p2,...,offset,string.  \
If called function is known to have 1 argument, it is called with just the match.")
static Jsi_RC StringReplaceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
................................................................................
                    Jsi_DSFree(&dStr);
                    Jsi_DecrRefCount(interp, inStr);
                    return JSI_ERROR;
                }
                Jsi_DecrRefCount(interp, inStr);
            }
            Jsi_DSAppend(&dStr, ce+Jsi_Strlen(cp), NULL);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
        return JSI_OK;
    }
    if (seq == NULL || seq->vt != JSI_VT_OBJECT || seq->d.obj->ot != JSI_OT_REGEXP) {
        Jsi_ValueMakeNull(interp, ret);
        return JSI_OK;
    }
................................................................................
            }
    
        } else {
            Jsi_DString sStr;
            Jsi_DSInit(&sStr); 
            if (pmatch[0].rm_so <= 0 && pmatch[0].rm_eo <= 0)
                break;
            int olen = -1;
            char *ostr = jsi_SubstrDup(p, -1, pmatch[0].rm_so, pmatch[0].rm_eo - pmatch[0].rm_so, &olen);
            Jsi_Value *inStr = Jsi_ValueMakeBlob(interp, NULL, (uchar*)ostr, olen);
            Jsi_DSFree(&sStr);
            Jsi_IncrRefCount(interp, inStr);
            if (maxArgs==1) {
                Jsi_RC rc = Jsi_FunctionInvokeString(interp, repVal, inStr, &dStr);
                if (Jsi_InterpGone(interp))
                    return JSI_ERROR;
                if (rc != JSI_OK) {
................................................................................
                    Jsi_DecrRefCount(interp, inStr);
                    return JSI_ERROR;
                }
            } else {
                Jsi_Value *vpargs, *items[MAX_SUBREGEX] = {}, *ret;
                int i;
                items[0] = inStr;
                for (i=1; i<=(int)re->reg.re_nsub && i<(MAX_SUBREGEX-3); i++) {
                    if (pmatch[i].rm_so<0)
                        items[i] = interp->NullValue;
                    else {
                        ostr = jsi_SubstrDup(p, -1, pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so, &olen);
                        items[i] = Jsi_ValueMakeBlob(interp, NULL, (uchar*)ostr, olen);
                    }
                }
                items[i++] = Jsi_ValueMakeNumber(interp, NULL, eoffset+pmatch[0].rm_so);
                items[i++] = strVal;
                vpargs = Jsi_ValueMakeObject(interp, NULL, Jsi_ObjNewArray(interp, items, i, 0));
                Jsi_IncrRefCount(interp, vpargs);
                ret = Jsi_ValueNew1(interp);
                rc = Jsi_FunctionInvoke(interp, repVal, vpargs, &ret, NULL);
                if (Jsi_InterpGone(interp))
................................................................................
    } while (n);

    /*
     * Copy the portion of the string after the last match to the
     * result variable.
     */
    Jsi_DSAppend(&dStr, p, NULL);
    Jsi_ValueFromDS(interp, &dStr, ret);
    return rc;

}

static Jsi_RC StringSearchCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
................................................................................
  }
  *pbuf = '\0';
  return buf;
}

/* Returns a url-decoded version of str */
/* IMPORTANT: be sure to free() the returned string after use */
static char *url_decode(char *str, int *len) {
  char *pstr = str, *buf = (char*)Jsi_Malloc(Jsi_Strlen(str) + 1), *pbuf = buf;
  while (*pstr) {
    if (*pstr == '%') {
      if (pstr[1] && pstr[2]) {
        *pbuf++ = jsi_fromHexChar(pstr[1]) << 4 | jsi_fromHexChar(pstr[2]);
        pstr += 2;
      }
................................................................................
      *pbuf++ = ' ';
    } else {
      *pbuf++ = *pstr;
    }
    pstr++;
  }
  *pbuf = '\0';
  *len = (pbuf-buf);
  return buf;
}

static Jsi_RC EncodeURICmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    char *cp, *str = Jsi_ValueArrayIndexToStr(interp, args, 0, NULL);
................................................................................
    return JSI_OK;
}

static Jsi_RC DecodeURICmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    char *cp, *str = Jsi_ValueArrayIndexToStr(interp, args, 0, NULL);
    int len;
    cp = url_decode(str, &len);
    Jsi_ValueMakeBlob(interp, ret, (uchar*)cp, len);
    return JSI_OK;
}

static Jsi_RC SysSleepCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_Number dtim = 1;
................................................................................
}

static Jsi_RC B64Decode(Jsi_Interp *interp, char *inbuffer, int ilen, Jsi_Value **ret)
{
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    B64DecodeDStr(inbuffer, ilen, &dStr);
    Jsi_ValueFromDS(interp, &dStr, ret);
    return JSI_OK;
}

static Jsi_RC
B64EncodeDStr(const char *ib, int ilen, Jsi_DString *dStr)
{
    int i=0, pos=0;
................................................................................

static Jsi_RC
B64Encode(Jsi_Interp *interp, char *ib, int ilen, Jsi_Value **ret)
{
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    B64EncodeDStr(ib, ilen, &dStr);
    Jsi_ValueFromDS(interp, &dStr, ret);
    return JSI_OK;
}

Jsi_RC Jsi_Base64(const char *str, int len, Jsi_DString *dStr, bool decode)
{
    if (len<0)
        len = Jsi_Strlen(str);
................................................................................
        Jsi_ValueMakeStringKey(interp, ret, ".");
    }
    else if (p == path) {
        Jsi_ValueMakeStringKey(interp, ret, "/");
    }
#if defined(__MINGW32__) || defined(_MSC_VER)
    else if (p[-1] == ':') {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path+1, &olen);
        Jsi_ValueMakeString(interp, ret, (uchar*)ostr, olen);
    }
#endif
    else {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path, &olen);
        Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
    }
    return JSI_OK;
}

static Jsi_RC FileRootnameCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
................................................................................
    const char *lastSlash = Jsi_Strrchr(path, '/');
    const char *p = Jsi_Strrchr(path, '.');

    if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
        Jsi_ValueMakeStringDup(interp, ret, path);
    }
    else {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path, &olen);
        Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
    }
    return JSI_OK;
}
static Jsi_RC FileExtensionCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    const char *path = Jsi_ValueString(interp, Jsi_ValueArrayIndex(interp, args, 0), NULL);
................................................................................
    char *newname;
    if (*path2 == '/' || *path2 == '~')
        newname = Jsi_FileRealpath(interp, p2, NULL);
    else {
        Jsi_DString dStr = {};
        Jsi_DSAppend(&dStr, path1, "/", path2, NULL);
        Jsi_Value *tpPtr = Jsi_ValueNew1(interp);
        Jsi_ValueFromDS(interp, &dStr, &tpPtr);
        newname = Jsi_FileRealpath(interp, tpPtr, NULL);
        Jsi_DecrRefCount(interp, tpPtr);
    }
    if (newname ==  NULL)
        return JSI_ERROR;
    Jsi_ValueMakeString(interp, ret, (char*)newname);
    return JSI_OK;
................................................................................
    int bufferPwr2;
    jsi_wsStatData stats;
    char *iface;
    const char* urlPrefix, *urlRedirect;
    const char *localhostName;
    const char *clientName;
    const char *clientIP;
    const char *useridPass, *server;
    const char *realm, *includeFile, *jsiFnPattern;
    struct lws_context *instCtx;
    Jsi_Value *getRegexp, *post;
    unsigned int oldus;
    int opts;
    int hasOpts;
    int debug;
    int maxConnects;
................................................................................
    JSI_OPT(BOOL,   jsi_wsCmdObj, echo,       .help="LogInfo outputs all websock Send/Recv messages"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, formParams, .help="Comma seperated list of upload form param names ('text,send,file,upload')", jsi_IIRO),
    JSI_OPT(OBJ,    jsi_wsCmdObj, extArgs,    .help="Arguments for extension handlers", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, extHandlers,.help="Enable builtin handlers for these extensions: .htmli, .cssi, .jsi, and .md", jsi_IIOF),
    JSI_OPT(REGEXP, jsi_wsCmdObj, getRegexp,  .help="Call onGet() only if Url matches pattern"),
//    JSI_OPT(CUSTOM, jsi_wsCmdObj, handlersPkg,.help="Handlers use package() to upgrade string to function object"),
    JSI_OPT(ARRAY,  jsi_wsCmdObj, headers,    .help="List of name/value output header pairs", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, jsiFnPattern,.help="A glob-match pattern for files to which is appended 'window.jsiWebSocket=true;' (jsi*.js)", jsi_IIRO),
    JSI_OPT(STRING, jsi_wsCmdObj, interface,  .help="Interface for server to listen on, eg. 'eth0' or 'lo'", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, local,      .help="Limit connections to localhost addresses on the 127 network"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, localhostName,.help="Client name used by localhost connections ('localhost')"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxConnects,.help="In server mode, max number of client connections accepted"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxDownload,.help="Max size of file download"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxUpload,  .help="Max size of file upload will accept"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, mimeTypes,  .help="Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'})", jsi_IIOF),
................................................................................
    JSI_OPT(STRING, jsi_wsCmdObj, post,       .help="Post string to serve", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, protocol,   .help="Name of protocol (ws/wss)"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, realm,      .help="Realm for basic auth (jsish)", ),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufMax, .help="Size limit of a websocket message", jsi_IIOF),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufTimeout,.help="Timeout for recv of a websock msg", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, redirMax,   .help="Temporarily disable redirects when see more than this in 10 minutes"),
    JSI_OPT(STRING, jsi_wsCmdObj, rootdir,    .help="Directory to serve html from (\".\")"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, server,     .help="String to send out int the header SERVER (jsiWebSocket)"),
    JSI_OPT(CUSTOM, jsi_wsCmdObj, stats,      .help="Statistical data", jsi_IIRO, .custom=Jsi_Opt_SwitchSuboption, .data=WPSStats),
    JSI_OPT(TIME_T, jsi_wsCmdObj, startTime,  .help="Time of websocket start", jsi_IIRO),
    JSI_OPT(STRKEY, jsi_wsCmdObj, includeFile, .help="Default file when no extension given (include.shtml)"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlPrefix,  .help="Prefix in url to strip from path; for reverse proxy"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlRedirect,.help="Redirect when no url or / is given. Must match urlPrefix, if given"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, use_ssl,    .help="Use https (for client)", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, useridPass, .help="The USERID:PASSWORD to use for basic authentication"),
................................................................................
    int code, const char *extra, const char *mime, Jsi_DString *jStr)
{
    uchar ubuf[JSI_BUFSIZ], *p=ubuf, *end = &ubuf[sizeof(ubuf)-1];
    if (!mime) mime = "text/html";
    if (code<=0) code = 200;
    if (lws_add_http_header_status(wsi, code, &p, end))
        return -1;
    const char *srv = pss->cmdPtr->server;
    if (!srv) srv = "jsiWebSocket";
    if (srv[0] && lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER, (uchar*)srv, Jsi_Strlen(srv), &p, end))
        return -1;
    if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (uchar *)mime, Jsi_Strlen(mime), &p, end))
        return -1;
    if (lws_add_http_header_content_length(wsi, strLen, &p, end))
        return -1;
    *p = 0;
    Jsi_DSAppend(jStr, (char*)ubuf, extra, NULL);
................................................................................
            if (n>0)
                Jsi_DSAppendLen(hStr, (char*)buffer, n);
            p = buffer;
        }
    }
    return true;
}

static bool jsi_wsAddStdHeader(Jsi_Interp *interp, jsi_wsCmdObj *cmdPtr, struct lws *wsi,    Jsi_DString *hStr) {
    uchar buffer[JSI_BUFSIZ];
    uchar *p = (unsigned char *)buffer, *end = p + sizeof(buffer);
    const char *srv = cmdPtr->server;
    if (!srv) srv = "jsiWebSocket";
    int n = 0;
    if (srv[0] && lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER, (uchar*)srv, Jsi_Strlen(srv), &p, end))
        return false;
    n = p - buffer;
    if (n>0) {
        Jsi_DSAppendLen(hStr, (char*)buffer, n);
        p = buffer;
    }
    return true;
}

// Read native file only if inside rootdir
static Jsi_RC jsi_wsFileRead(Jsi_Interp *interp, Jsi_Value *name, Jsi_DString *dStr, jsi_wsCmdObj *cmdPtr) {
    Jsi_StatBuf sb;
    Jsi_RC rc = JSI_ERROR;
    int n = Jsi_Stat(interp, name, &sb);
    if (!n && sb.st_size>0) {
................................................................................
    int lvl) {
    Jsi_Value *fval;
    Jsi_RC rc = JSI_OK;
    char *cp, *cp2, *ce, pref[] = "<!--#include file=\"", suffix[] = "\"-->",
        pref2[] = "<!--#include virtual=\"";
    int flen, plen, plen1 = sizeof(pref)-1,  plen2 = sizeof(pref2)-1, slen = sizeof(suffix)-1;
    Jsi_DString tStr = {};
    // Fallback script.
    const char *cs = "<!-- Markdeep: --><style class=\"fallback\">body{visibility:hidden;}</style>\n"
                "<script>window.markdeepOptions={tocStyle:\"medium\"}</script>\n"
                "<!--#include file=\"$inc\"-->\n"
                "<script src=\"markdeep.min.js\"></script>\n"
                "<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility='visible')</script>";
    char *fs, *fname = Jsi_ValueString(interp, fn, &flen), *fend = fname;
    char fbuf[PATH_MAX];
................................................................................
    time_t now = time(NULL);
    char buf[JSI_BUFSIZ];
    int rc = 0, essi = 0;
    buf[0] = 0;
    uchar *p = buffer, *end = &buffer[sizeof(buffer)-1];
    int n;
    Jsi_Value* fname = NULL;
    bool isMdi = 0, isJsiWeb = 0;

    /* if a legal POST URL, let it continue and accept data */
    if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
        return 0;
    if (!pss)
        pss = jsi_wsgetPss(cmdPtr, wsi, user, 1, 1);

................................................................................
            }
        }
    }

    snprintf(buf, sizeof(buf), "%s/%s", cmdPtr->curRoot, inPtr);
    if (cmdPtr->debug>1)
        fprintf(stderr, "FILE: %s in %s | %s\n", buf, cmdPtr->curRoot, Jsi_ValueString(interp, cmdPtr->rootdir, NULL));
    char extBuf[100], *cpde = Jsi_Strrchr(buf, '/');
    isJsiWeb = (cpde && cmdPtr->jsiFnPattern && Jsi_GlobMatch(cmdPtr->jsiFnPattern, cpde+1, 0));
    bool isgzip = 0;
    if (!ext || !ext[1])
        mime = "text/html";
    else {
        const char *eext = ext+1;
        uint elen = Jsi_Strlen(ext);
        if (elen>3 && elen<(sizeof(extBuf)-10) && !Jsi_Strcmp(ext+elen-3,".gz")) {
................................................................................
            goto bail;
    }
    if (cmdPtr->headers && !jsi_wsAddHeader(interp, cmdPtr, wsi, cmdPtr->headers, &hStr))
        goto bail;

    if (pss->headers && !jsi_wsAddHeader(interp, cmdPtr, wsi, pss->headers, &hStr))
        goto bail;
    

    n = Jsi_DSLength(&hStr);

    if (native && !isMdi && !isJsiWeb) {
        Jsi_DecrRefCount(interp, fname);

        if (!jsi_wsAddStdHeader(interp, cmdPtr, wsi, &hStr))
            goto bail;
        int hrc = lws_serve_http_file(wsi, buf, mime, Jsi_DSValue(&hStr), Jsi_DSLength(&hStr));
        if (hrc<0) {
            if (cmdPtr->noWarn==0)
                fprintf(stderr, "can not serve file (%d): %s\n", hrc, buf);
            goto bail;
        } else if (hrc > 0 && lws_http_transaction_completed(wsi))
            goto bail;
    } else {
        // Need to read data for non-native files.
        Jsi_DString dStr = {}, fStr = {};
        if (isMdi)
            rc = jsi_wsTemplateFill(interp, cmdPtr, fname, &fStr, (essi?1:0));
        else {
            rc = jsi_wsFileRead(interp, fname, &fStr, cmdPtr);
            if (isJsiWeb)
                Jsi_DSAppend(&fStr, "\nwindow.jsiWebSocket=true;", NULL);
        }
        if (rc != JSI_OK) {
            Jsi_DSFree(&fStr);
            goto nofile;
        }
        int hrc = jsi_wsServeHeader(pss, wsi, (int)Jsi_DSLength(&fStr), 200, Jsi_DSValue(&hStr), mime, &dStr);
        if (hrc>=0) {
            Jsi_DSAppendLen(&dStr, Jsi_DSValue(&fStr), Jsi_DSLength(&fStr));
................................................................................
    cmdPtr->ietf_version = -1;
    cmdPtr->bufferPwr2 = 0;
    cmdPtr->ws_gid = -1;
    cmdPtr->ws_uid = -1;
    cmdPtr->startTime = time(NULL);
    cmdPtr->hasOpts = 1;
    cmdPtr->includeFile = "include.shtml";
    cmdPtr->jsiFnPattern = "jsi*js";
    if ((arg != NULL && !Jsi_ValueIsNull(interp,arg))
        && Jsi_OptionsProcess(interp, WSOptions, cmdPtr, arg, 0) < 0) {
bail:
        jsi_wswebsocketObjFree(interp, cmdPtr);
        return JSI_ERROR;
    }
    Jsi_PathNormalize(interp, &cmdPtr->rootdir);
................................................................................
    Jsi_StructSpec *sf = jsi_csStructFields(interp, arg1);

    if (!sf)
        return Jsi_LogError("unkown struct: %s", arg1);;

    Jsi_DString dStr = {};
    Jsi_OptionsData(interp, (Jsi_OptionSpec*)sf, &dStr, 1);
    Jsi_ValueFromDS(interp, &dStr, ret);
    Jsi_DSFree(&dStr);
    return JSI_OK;
}

/* Scanning function */
static Jsi_RC jsi_csValueToFieldType(Jsi_Interp *interp, Jsi_OptionSpec* spec, Jsi_Value *inValue, const char *inStr, void *record, Jsi_Wide flags)
{
................................................................................
                    Assert(l1>=0 && l1<=JSI_MAX_ALLOC_BUF);
                    Assert(l2>=0 && l2<=JSI_MAX_ALLOC_BUF);
                    str = (char*)Jsi_Malloc(l1+l2+1);
                    memcpy(str, s2, l2);
                    memcpy(str+l2, s1, l1);
                    str[l1+l2] = 0;
                    jsiClearStack(interp,2);
                    Jsi_ValueMakeBlob(interp, &v2, (uchar*)str, l1+l2);
                } else {
                    Jsi_ValueToNumber(interp, v1);
                    Jsi_ValueToNumber(interp, v2);
                    rc = _jsi_StrictChk2(v1, v2);
                    Jsi_Number n = v1->d.num + v2->d.num;
                    jsiClearStack(interp,2);
                    Jsi_ValueMakeNumber(interp, &v2, n);

Changes to src/jsi.h.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   8
#define JSI_VERSION_RELEASE 33

#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_EXTERN Jsi_Number Jsi_Version(void); /*STUB = 183*/
JSI_EXTERN Jsi_Value* Jsi_ReturnValue(Jsi_Interp *interp); /*STUB = 184*/
JSI_EXTERN Jsi_RC Jsi_Mount( Jsi_Interp *interp, Jsi_Value *archive, Jsi_Value *mount, Jsi_Value **ret); /*STUB = 185*/
JSI_EXTERN Jsi_Value* Jsi_Executable(Jsi_Interp *interp); /*STUB = 186*/
JSI_EXTERN Jsi_Regex* Jsi_RegExpNew(Jsi_Interp *interp, const char *regtxt, int flag); /*STUB = 187*/
JSI_EXTERN void Jsi_RegExpFree(Jsi_Regex* re); /*STUB = 188*/
JSI_EXTERN Jsi_RC Jsi_RegExpMatch( Jsi_Interp *interp,  Jsi_Value *pattern, const char *str, int *rc, Jsi_DString *dStr); /*STUB = 189*/
JSI_EXTERN Jsi_RC Jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, Jsi_Value *ret); /*STUB = 190*/
JSI_EXTERN bool Jsi_GlobMatch(const char *pattern, const char *string, int nocase); /*STUB = 191*/
JSI_EXTERN char* Jsi_FileRealpath(Jsi_Interp *interp, Jsi_Value *path, char *newpath); /*STUB = 192*/
JSI_EXTERN char* Jsi_FileRealpathStr(Jsi_Interp *interp, const char *path, char *newpath); /*STUB = 193*/
JSI_EXTERN char* Jsi_NormalPath(Jsi_Interp *interp, const char *path, Jsi_DString *dStr); /*STUB = 194*/
JSI_EXTERN char* Jsi_ValueNormalPath(Jsi_Interp *interp, Jsi_Value *path, Jsi_DString *dStr); /*STUB = 195*/
JSI_EXTERN Jsi_RC Jsi_PathNormalize(Jsi_Interp *interp, Jsi_Value **pathPtr); /*STUB = 410*/
JSI_EXTERN Jsi_RC Jsi_JSONParse(Jsi_Interp *interp, const char *js, Jsi_Value **ret, int flags); /*STUB = 196*/






|







 







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   8
#define JSI_VERSION_RELEASE 34

#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_EXTERN Jsi_Number Jsi_Version(void); /*STUB = 183*/
JSI_EXTERN Jsi_Value* Jsi_ReturnValue(Jsi_Interp *interp); /*STUB = 184*/
JSI_EXTERN Jsi_RC Jsi_Mount( Jsi_Interp *interp, Jsi_Value *archive, Jsi_Value *mount, Jsi_Value **ret); /*STUB = 185*/
JSI_EXTERN Jsi_Value* Jsi_Executable(Jsi_Interp *interp); /*STUB = 186*/
JSI_EXTERN Jsi_Regex* Jsi_RegExpNew(Jsi_Interp *interp, const char *regtxt, int flag); /*STUB = 187*/
JSI_EXTERN void Jsi_RegExpFree(Jsi_Regex* re); /*STUB = 188*/
JSI_EXTERN Jsi_RC Jsi_RegExpMatch( Jsi_Interp *interp,  Jsi_Value *pattern, const char *str, int *rc, Jsi_DString *dStr); /*STUB = 189*/
JSI_EXTERN Jsi_RC Jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, int slen, Jsi_Value *ret); /*STUB = 190*/
JSI_EXTERN bool Jsi_GlobMatch(const char *pattern, const char *string, int nocase); /*STUB = 191*/
JSI_EXTERN char* Jsi_FileRealpath(Jsi_Interp *interp, Jsi_Value *path, char *newpath); /*STUB = 192*/
JSI_EXTERN char* Jsi_FileRealpathStr(Jsi_Interp *interp, const char *path, char *newpath); /*STUB = 193*/
JSI_EXTERN char* Jsi_NormalPath(Jsi_Interp *interp, const char *path, Jsi_DString *dStr); /*STUB = 194*/
JSI_EXTERN char* Jsi_ValueNormalPath(Jsi_Interp *interp, Jsi_Value *path, Jsi_DString *dStr); /*STUB = 195*/
JSI_EXTERN Jsi_RC Jsi_PathNormalize(Jsi_Interp *interp, Jsi_Value **pathPtr); /*STUB = 410*/
JSI_EXTERN Jsi_RC Jsi_JSONParse(Jsi_Interp *interp, const char *js, Jsi_Value **ret, int flags); /*STUB = 196*/

Changes to src/jsiCData.c.

902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
    Jsi_StructSpec *sf = jsi_csStructFields(interp, arg1);

    if (!sf)
        return Jsi_LogError("unkown struct: %s", arg1);;

    Jsi_DString dStr = {};
    Jsi_OptionsData(interp, (Jsi_OptionSpec*)sf, &dStr, 1);
    Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
    Jsi_DSFree(&dStr);
    return JSI_OK;
}

/* Scanning function */
static Jsi_RC jsi_csValueToFieldType(Jsi_Interp *interp, Jsi_OptionSpec* spec, Jsi_Value *inValue, const char *inStr, void *record, Jsi_Wide flags)
{







|







902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
    Jsi_StructSpec *sf = jsi_csStructFields(interp, arg1);

    if (!sf)
        return Jsi_LogError("unkown struct: %s", arg1);;

    Jsi_DString dStr = {};
    Jsi_OptionsData(interp, (Jsi_OptionSpec*)sf, &dStr, 1);
    Jsi_ValueFromDS(interp, &dStr, ret);
    Jsi_DSFree(&dStr);
    return JSI_OK;
}

/* Scanning function */
static Jsi_RC jsi_csValueToFieldType(Jsi_Interp *interp, Jsi_OptionSpec* spec, Jsi_Value *inValue, const char *inStr, void *record, Jsi_Wide flags)
{

Changes to src/jsiChar.c.

72
73
74
75
76
77
78
79
80



81
82


83
84
85
86
87
88
89
90
91

92
93
94
95
96

97
98
99
100
101
102
103
        len = Jsi_Strlen(str);
    char *cp = (char*)Jsi_Malloc(len+1);
    memcpy(cp, str, len);
    cp[len] = 0;
    return cp;
}

char *jsi_SubstrDup(const char *a, int start, int len)
{



    if (len == 0) return Jsi_Strdup("");
    


    int lenofa = Jsi_Strlen(a);
    while (start < 0) start += lenofa;
    if (start >= lenofa) return Jsi_Strdup("");
    
    int maxcpy = lenofa - start;
    
    if (len > 0) {
        maxcpy = maxcpy < len ? maxcpy : len;
    }

    
    char *r = (char*)Jsi_Malloc(maxcpy + 2);

    Jsi_Strncpy(r, a + start, maxcpy + 1);
    r[maxcpy + 1] = 0;

    return r;
}


char* Jsi_Strrchr(const char *str, int c)
{
    return strrchr((char*)str, c);







|

>
>
>
|
|
>
>
|
|
|

|




>





>







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
        len = Jsi_Strlen(str);
    char *cp = (char*)Jsi_Malloc(len+1);
    memcpy(cp, str, len);
    cp[len] = 0;
    return cp;
}

char *jsi_SubstrDup(const char *a, int alen, int start, int len, int *olen)
{
    if (len == 0) {
empty:
        *olen = 0;
        return Jsi_Strdup("");
    }
    
    if (alen<0)
        alen = Jsi_Strlen(a);
    while (start < 0) start += alen;
    if (start >= alen) goto empty;
    
    int maxcpy = alen - start;
    
    if (len > 0) {
        maxcpy = maxcpy < len ? maxcpy : len;
    }
    if (maxcpy<=0) goto empty;
    
    char *r = (char*)Jsi_Malloc(maxcpy + 2);

    Jsi_Strncpy(r, a + start, maxcpy + 1);
    r[maxcpy + 1] = 0;
    *olen = maxcpy;
    return r;
}


char* Jsi_Strrchr(const char *str, int c)
{
    return strrchr((char*)str, c);

Changes to src/jsiCmds.c.

1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
....
1122
1123
1124
1125
1126
1127
1128

1129
1130
1131
1132
1133
1134
1135
....
1138
1139
1140
1141
1142
1143
1144
1145
1146

1147
1148
1149
1150
1151
1152
1153
....
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
....
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
  }
  *pbuf = '\0';
  return buf;
}

/* Returns a url-decoded version of str */
/* IMPORTANT: be sure to free() the returned string after use */
static char *url_decode(char *str) {
  char *pstr = str, *buf = (char*)Jsi_Malloc(Jsi_Strlen(str) + 1), *pbuf = buf;
  while (*pstr) {
    if (*pstr == '%') {
      if (pstr[1] && pstr[2]) {
        *pbuf++ = jsi_fromHexChar(pstr[1]) << 4 | jsi_fromHexChar(pstr[2]);
        pstr += 2;
      }
................................................................................
      *pbuf++ = ' ';
    } else {
      *pbuf++ = *pstr;
    }
    pstr++;
  }
  *pbuf = '\0';

  return buf;
}

static Jsi_RC EncodeURICmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    char *cp, *str = Jsi_ValueArrayIndexToStr(interp, args, 0, NULL);
................................................................................
    return JSI_OK;
}

static Jsi_RC DecodeURICmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    char *cp, *str = Jsi_ValueArrayIndexToStr(interp, args, 0, NULL);
    cp = url_decode(str);
    Jsi_ValueMakeString(interp, ret, cp);

    return JSI_OK;
}

static Jsi_RC SysSleepCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_Number dtim = 1;
................................................................................
}

static Jsi_RC B64Decode(Jsi_Interp *interp, char *inbuffer, int ilen, Jsi_Value **ret)
{
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    B64DecodeDStr(inbuffer, ilen, &dStr);
    Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
    return JSI_OK;
}

static Jsi_RC
B64EncodeDStr(const char *ib, int ilen, Jsi_DString *dStr)
{
    int i=0, pos=0;
................................................................................

static Jsi_RC
B64Encode(Jsi_Interp *interp, char *ib, int ilen, Jsi_Value **ret)
{
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    B64EncodeDStr(ib, ilen, &dStr);
    Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
    return JSI_OK;
}

Jsi_RC Jsi_Base64(const char *str, int len, Jsi_DString *dStr, bool decode)
{
    if (len<0)
        len = Jsi_Strlen(str);







|







 







>







 







|
|
>







 







|







 







|







1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
....
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
....
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
....
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
....
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
  }
  *pbuf = '\0';
  return buf;
}

/* Returns a url-decoded version of str */
/* IMPORTANT: be sure to free() the returned string after use */
static char *url_decode(char *str, int *len) {
  char *pstr = str, *buf = (char*)Jsi_Malloc(Jsi_Strlen(str) + 1), *pbuf = buf;
  while (*pstr) {
    if (*pstr == '%') {
      if (pstr[1] && pstr[2]) {
        *pbuf++ = jsi_fromHexChar(pstr[1]) << 4 | jsi_fromHexChar(pstr[2]);
        pstr += 2;
      }
................................................................................
      *pbuf++ = ' ';
    } else {
      *pbuf++ = *pstr;
    }
    pstr++;
  }
  *pbuf = '\0';
  *len = (pbuf-buf);
  return buf;
}

static Jsi_RC EncodeURICmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    char *cp, *str = Jsi_ValueArrayIndexToStr(interp, args, 0, NULL);
................................................................................
    return JSI_OK;
}

static Jsi_RC DecodeURICmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    char *cp, *str = Jsi_ValueArrayIndexToStr(interp, args, 0, NULL);
    int len;
    cp = url_decode(str, &len);
    Jsi_ValueMakeBlob(interp, ret, (uchar*)cp, len);
    return JSI_OK;
}

static Jsi_RC SysSleepCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_Number dtim = 1;
................................................................................
}

static Jsi_RC B64Decode(Jsi_Interp *interp, char *inbuffer, int ilen, Jsi_Value **ret)
{
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    B64DecodeDStr(inbuffer, ilen, &dStr);
    Jsi_ValueFromDS(interp, &dStr, ret);
    return JSI_OK;
}

static Jsi_RC
B64EncodeDStr(const char *ib, int ilen, Jsi_DString *dStr)
{
    int i=0, pos=0;
................................................................................

static Jsi_RC
B64Encode(Jsi_Interp *interp, char *ib, int ilen, Jsi_Value **ret)
{
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    B64EncodeDStr(ib, ilen, &dStr);
    Jsi_ValueFromDS(interp, &dStr, ret);
    return JSI_OK;
}

Jsi_RC Jsi_Base64(const char *str, int len, Jsi_DString *dStr, bool decode)
{
    if (len<0)
        len = Jsi_Strlen(str);

Changes to src/jsiFileCmds.c.

687
688
689
690
691
692
693


694
695
696
697
698


699
700
701
702
703
704
705
...
709
710
711
712
713
714
715
716


717
718
719
720
721
722
723
...
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
        Jsi_ValueMakeStringKey(interp, ret, ".");
    }
    else if (p == path) {
        Jsi_ValueMakeStringKey(interp, ret, "/");
    }
#if defined(__MINGW32__) || defined(_MSC_VER)
    else if (p[-1] == ':') {


        Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(path, 0, p-path+1));
    }
#endif
    else {
        Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(path, 0, p-path));


    }
    return JSI_OK;
}

static Jsi_RC FileRootnameCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
................................................................................
    const char *lastSlash = Jsi_Strrchr(path, '/');
    const char *p = Jsi_Strrchr(path, '.');

    if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
        Jsi_ValueMakeStringDup(interp, ret, path);
    }
    else {
        Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(path,0, p-path));


    }
    return JSI_OK;
}
static Jsi_RC FileExtensionCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    const char *path = Jsi_ValueString(interp, Jsi_ValueArrayIndex(interp, args, 0), NULL);
................................................................................
    char *newname;
    if (*path2 == '/' || *path2 == '~')
        newname = Jsi_FileRealpath(interp, p2, NULL);
    else {
        Jsi_DString dStr = {};
        Jsi_DSAppend(&dStr, path1, "/", path2, NULL);
        Jsi_Value *tpPtr = Jsi_ValueNew1(interp);
        Jsi_ValueMakeString(interp, &tpPtr, Jsi_DSFreeDup(&dStr));
        newname = Jsi_FileRealpath(interp, tpPtr, NULL);
        Jsi_DecrRefCount(interp, tpPtr);
    }
    if (newname ==  NULL)
        return JSI_ERROR;
    Jsi_ValueMakeString(interp, ret, (char*)newname);
    return JSI_OK;







>
>
|



|
>
>







 







|
>
>







 







|







687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
...
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
...
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
        Jsi_ValueMakeStringKey(interp, ret, ".");
    }
    else if (p == path) {
        Jsi_ValueMakeStringKey(interp, ret, "/");
    }
#if defined(__MINGW32__) || defined(_MSC_VER)
    else if (p[-1] == ':') {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path+1, &olen);
        Jsi_ValueMakeString(interp, ret, (uchar*)ostr, olen);
    }
#endif
    else {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path, &olen);
        Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
    }
    return JSI_OK;
}

static Jsi_RC FileRootnameCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
................................................................................
    const char *lastSlash = Jsi_Strrchr(path, '/');
    const char *p = Jsi_Strrchr(path, '.');

    if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
        Jsi_ValueMakeStringDup(interp, ret, path);
    }
    else {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path, &olen);
        Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
    }
    return JSI_OK;
}
static Jsi_RC FileExtensionCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    const char *path = Jsi_ValueString(interp, Jsi_ValueArrayIndex(interp, args, 0), NULL);
................................................................................
    char *newname;
    if (*path2 == '/' || *path2 == '~')
        newname = Jsi_FileRealpath(interp, p2, NULL);
    else {
        Jsi_DString dStr = {};
        Jsi_DSAppend(&dStr, path1, "/", path2, NULL);
        Jsi_Value *tpPtr = Jsi_ValueNew1(interp);
        Jsi_ValueFromDS(interp, &dStr, &tpPtr);
        newname = Jsi_FileRealpath(interp, tpPtr, NULL);
        Jsi_DecrRefCount(interp, tpPtr);
    }
    if (newname ==  NULL)
        return JSI_ERROR;
    Jsi_ValueMakeString(interp, ret, (char*)newname);
    return JSI_OK;

Changes to src/jsiInt.h.

221
222
223
224
225
226
227




228
229
230
231
232
233
234
....
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
....
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551

#ifdef __FreeBSD__
#define _JSICASTINT(s) (int)(s)
#else
#define _JSICASTINT(s) (s)
#endif





#if 0
#ifndef uint
typedef unsigned int uint;
#endif
#ifndef uchar
typedef unsigned char uchar;
#endif
................................................................................
#define _JSI_MEMCLEAR(ptr) memset(ptr, 0, sizeof(*ptr)) /* To aid debugging memory.*/
#endif
#endif

#define MAX_SUBREGEX    256
#define JSI__LONG_LONG
#define UCHAR(s) (unsigned char)(s)
extern char* jsi_SubstrDup(const char *a, int start, int len);
extern int jsi_typeGet(Jsi_Interp *interp , const char *tname);
extern const char *jsi_typeName(Jsi_Interp *interp, int typ, Jsi_DString *dStr);
extern Jsi_RC jsi_ArgTypeCheck(Jsi_Interp *interp, int typ, Jsi_Value *arg, const char *p1, const char *p2, int index, Jsi_Func *func, bool isdefault);
extern void jsi_FuncCallCheck(jsi_Pstate *p, jsi_Pline *line, int argc, bool isNew, const char *name, const char *namePre, Jsi_OpCodes *argCodes);
extern Jsi_RC jsi_RunFuncCallCheck(Jsi_Interp *interp, Jsi_Func *func, int argc, const char *name, jsi_Pline *line, Jsi_OpCodes *argCodes, bool isParse);
extern Jsi_RC jsi_FunctionSubCall(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Value *tocall, int discard);
extern Jsi_ScopeStrs *jsi_ArgsOptAdd(jsi_Pstate *pstate, Jsi_ScopeStrs *a);
................................................................................
extern int jsi_GetDefaultType(const char *cp);
extern Jsi_RC jsi_ParseTypeCheckStr(Jsi_Interp *interp, const char *str);
extern Jsi_Interp *jsi_DoExit(Jsi_Interp *interp, int rc);
extern Jsi_RC jsi_CDataDataSetCmdSub(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Func *funcPtr, int flags);
extern Jsi_RC jsi_AliasInvoke(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Func *funcPtr);
extern Jsi_Number jsi_VersionNormalize(Jsi_Number ver, char *obuf, size_t osiz);
extern const char* jsi_FuncGetCode(Jsi_Interp *interp, Jsi_Func *func, int *lenPtr);
extern Jsi_RC jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, Jsi_Value *ret, int *ofs, bool match);

extern Jsi_RC Jsi_CleanValue(Jsi_Interp *interp, Jsi_Interp *tointerp, Jsi_Value *val, Jsi_Value **ret); //TODO: EXPORT

extern char jsi_toHexChar(char code);
extern char jsi_fromHexChar(char ch);
extern bool jsi_IsAlnumStr(const char *cp);
extern char *jsi_TrimStr(char *str);







>
>
>
>







 







|







 







|







221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
....
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
....
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555

#ifdef __FreeBSD__
#define _JSICASTINT(s) (int)(s)
#else
#define _JSICASTINT(s) (s)
#endif

#ifndef __DBL_DECIMAL_DIG__
#define __DBL_DECIMAL_DIG__ 17
#endif

#if 0
#ifndef uint
typedef unsigned int uint;
#endif
#ifndef uchar
typedef unsigned char uchar;
#endif
................................................................................
#define _JSI_MEMCLEAR(ptr) memset(ptr, 0, sizeof(*ptr)) /* To aid debugging memory.*/
#endif
#endif

#define MAX_SUBREGEX    256
#define JSI__LONG_LONG
#define UCHAR(s) (unsigned char)(s)
extern char* jsi_SubstrDup(const char *a, int alen, int start, int len, int *olen);
extern int jsi_typeGet(Jsi_Interp *interp , const char *tname);
extern const char *jsi_typeName(Jsi_Interp *interp, int typ, Jsi_DString *dStr);
extern Jsi_RC jsi_ArgTypeCheck(Jsi_Interp *interp, int typ, Jsi_Value *arg, const char *p1, const char *p2, int index, Jsi_Func *func, bool isdefault);
extern void jsi_FuncCallCheck(jsi_Pstate *p, jsi_Pline *line, int argc, bool isNew, const char *name, const char *namePre, Jsi_OpCodes *argCodes);
extern Jsi_RC jsi_RunFuncCallCheck(Jsi_Interp *interp, Jsi_Func *func, int argc, const char *name, jsi_Pline *line, Jsi_OpCodes *argCodes, bool isParse);
extern Jsi_RC jsi_FunctionSubCall(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Value *tocall, int discard);
extern Jsi_ScopeStrs *jsi_ArgsOptAdd(jsi_Pstate *pstate, Jsi_ScopeStrs *a);
................................................................................
extern int jsi_GetDefaultType(const char *cp);
extern Jsi_RC jsi_ParseTypeCheckStr(Jsi_Interp *interp, const char *str);
extern Jsi_Interp *jsi_DoExit(Jsi_Interp *interp, int rc);
extern Jsi_RC jsi_CDataDataSetCmdSub(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Func *funcPtr, int flags);
extern Jsi_RC jsi_AliasInvoke(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Func *funcPtr);
extern Jsi_Number jsi_VersionNormalize(Jsi_Number ver, char *obuf, size_t osiz);
extern const char* jsi_FuncGetCode(Jsi_Interp *interp, Jsi_Func *func, int *lenPtr);
extern Jsi_RC jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, int slen, Jsi_Value *ret, int *ofs, bool match);

extern Jsi_RC Jsi_CleanValue(Jsi_Interp *interp, Jsi_Interp *tointerp, Jsi_Value *val, Jsi_Value **ret); //TODO: EXPORT

extern char jsi_toHexChar(char code);
extern char jsi_fromHexChar(char ch);
extern bool jsi_IsAlnumStr(const char *cp);
extern char *jsi_TrimStr(char *str);

Changes to src/jsiRegexp.c.

174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
...
223
224
225
226
227
228
229
230
231

232
233
234
235
236
237
238
...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
...
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
    }
    
    return JSI_OK;
}



Jsi_RC jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, Jsi_Value *ret, int *ofs, bool match)
{
    Jsi_Regex *re;
    int regexec_flags = 0;
    Jsi_Value *seq = pattern;

    if (seq == NULL || seq->vt != JSI_VT_OBJECT || seq->d.obj->ot != JSI_OT_REGEXP) {
        Jsi_ValueMakeNull(interp, &ret);
        return JSI_OK;
    }
    re = seq->d.obj->d.robj;
    regex_t *reg = &re->reg;
    
    regmatch_t pos[MAX_SUBREGEX] = {};
    int num_matches = 0, r, n = Jsi_Strlen(str);
    int isglob = (re->eflags&JSI_REG_GLOB);
    Jsi_Obj *obj;
    
    do {
        r = regexec(reg, str, MAX_SUBREGEX, pos, regexec_flags);

        if (r >= REG_BADPAT) {
................................................................................
        int i;
        for (i = 0; i < MAX_SUBREGEX; ++i) {
            if (pos[i].rm_so <= 0 && pos[i].rm_eo <= 0)
                break;
            if (i && pos[i].rm_so == pos[i-1].rm_so && pos[i].rm_eo == pos[i-1].rm_eo)
                continue;
    
            Jsi_Value *val = Jsi_ValueMakeString(interp, NULL, 
                jsi_SubstrDup(str, pos[i].rm_so, pos[i].rm_eo - pos[i].rm_so));

            if (ofs)
                *ofs = pos[i].rm_eo;
            Jsi_ValueInsertArray(interp, ret, num_matches, val, 0);
            num_matches++;
            if ( match && isglob)
                break;
        }
................................................................................

        regexec_flags |= REG_NOTBOL;
    } while (n && pos[0].rm_eo>0);
    
    return JSI_OK;
}

Jsi_RC Jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, Jsi_Value *ret)
{
    return jsi_RegExpMatches(interp, pattern, str, ret, NULL, 0);
}


#define FN_regexec JSI_INFO("\
Perform regexp match checking.  Returns the array of matches.\
With the global flag g, sets lastIndex and returns next match.")
static Jsi_RC RegexpExecCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
................................................................................
        l = Jsi_ValueObjLookup(interp, v, "lastIndex", 0);
        if (l && Jsi_ValueGetNumber(interp, l, &lv) != JSI_OK) 
            return Jsi_LogError("lastIndex not a number");
        if (l)
            re->lastIndex = (int)lv;
    }
    int ofs = 0;
    Jsi_RC rc = jsi_RegExpMatches(interp, v, re->lastIndex<slen?str+re->lastIndex:"", *ret, isglob?&ofs:NULL, 0);
    if (isglob) {
        if (rc != JSI_OK)
            return rc;
        re->lastIndex += ofs;
        if (Jsi_ValueIsNull(interp, *ret))
            re->lastIndex = 0;
        lv = (Jsi_Number)re->lastIndex;







|













|







 







|
|
>







 







|

|







 







|







174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
...
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
    }
    
    return JSI_OK;
}



Jsi_RC jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, int n, Jsi_Value *ret, int *ofs, bool match)
{
    Jsi_Regex *re;
    int regexec_flags = 0;
    Jsi_Value *seq = pattern;

    if (seq == NULL || seq->vt != JSI_VT_OBJECT || seq->d.obj->ot != JSI_OT_REGEXP) {
        Jsi_ValueMakeNull(interp, &ret);
        return JSI_OK;
    }
    re = seq->d.obj->d.robj;
    regex_t *reg = &re->reg;
    
    regmatch_t pos[MAX_SUBREGEX] = {};
    int num_matches = 0, r;
    int isglob = (re->eflags&JSI_REG_GLOB);
    Jsi_Obj *obj;
    
    do {
        r = regexec(reg, str, MAX_SUBREGEX, pos, regexec_flags);

        if (r >= REG_BADPAT) {
................................................................................
        int i;
        for (i = 0; i < MAX_SUBREGEX; ++i) {
            if (pos[i].rm_so <= 0 && pos[i].rm_eo <= 0)
                break;
            if (i && pos[i].rm_so == pos[i-1].rm_so && pos[i].rm_eo == pos[i-1].rm_eo)
                continue;
    
            int olen = -1;
            char *ostr = jsi_SubstrDup(str, -1, pos[i].rm_so, pos[i].rm_eo - pos[i].rm_so, &olen);
            Jsi_Value *val = Jsi_ValueMakeBlob(interp, NULL, (uchar*)ostr, olen);
            if (ofs)
                *ofs = pos[i].rm_eo;
            Jsi_ValueInsertArray(interp, ret, num_matches, val, 0);
            num_matches++;
            if ( match && isglob)
                break;
        }
................................................................................

        regexec_flags |= REG_NOTBOL;
    } while (n && pos[0].rm_eo>0);
    
    return JSI_OK;
}

Jsi_RC Jsi_RegExpMatches(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, int slen, Jsi_Value *ret)
{
    return jsi_RegExpMatches(interp, pattern, str, slen, ret, NULL, 0);
}


#define FN_regexec JSI_INFO("\
Perform regexp match checking.  Returns the array of matches.\
With the global flag g, sets lastIndex and returns next match.")
static Jsi_RC RegexpExecCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
................................................................................
        l = Jsi_ValueObjLookup(interp, v, "lastIndex", 0);
        if (l && Jsi_ValueGetNumber(interp, l, &lv) != JSI_OK) 
            return Jsi_LogError("lastIndex not a number");
        if (l)
            re->lastIndex = (int)lv;
    }
    int ofs = 0;
    Jsi_RC rc = jsi_RegExpMatches(interp, v, re->lastIndex<slen?str+re->lastIndex:"", -1, *ret, isglob?&ofs:NULL, 0);
    if (isglob) {
        if (rc != JSI_OK)
            return rc;
        re->lastIndex += ofs;
        if (Jsi_ValueIsNull(interp, *ret))
            re->lastIndex = 0;
        lv = (Jsi_Number)re->lastIndex;

Changes to src/jsiString.c.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
..
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
...
113
114
115
116
117
118
119
120
121
122
123
124

125
126
127
128


129
130
131
132
133
134
135
136
137
138
139
140

141
142
143
144
145
146
147
148
...
157
158
159
160
161
162
163
164
165
166
167

168
169
170

171
172
173
174
175
176
177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192
...
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
...
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
...
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
...
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
...
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
...
786
787
788
789
790
791
792
793



794



795
796
797
798
799
800
801
...
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
    }

static Jsi_RC StringConstructor(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    if (Jsi_FunctionIsConstructor(funcPtr)) {
        const char *nv = "";
        int len = 0;
        if (Jsi_ValueGetLength(interp, args) > 0) {
            Jsi_Value *v = Jsi_ValueArrayIndex(interp, args, 0);
            if (v) {
                
                nv = Jsi_ValueToString(interp, v, &len);
            }
        }
................................................................................
            if (_this->d.obj->d.s.str)
                if (!_this->d.obj->isstrkey)
                    Jsi_Free(_this->d.obj->d.s.str);
            _this->d.obj->isstrkey = 0;
            _this->d.obj->d.s.str = Jsi_StrdupLen(nv, len);
            _this->d.obj->d.s.len = len;
        } else
            Jsi_ValueMakeStringDup(interp, &_this, nv);
        Jsi_ValueDup2(interp, ret, _this);
        return JSI_OK;
    }
    if (Jsi_ValueGetLength(interp, args) > 0) {
        Jsi_Value *v = Jsi_ValueArrayIndex(interp, args, 0);
        if (v) {
            Jsi_ValueDup2(interp, ret, v);
................................................................................
    ChkString(_this, funcPtr, v, &sLen, &bLen);

    Jsi_Value *start = Jsi_ValueArrayIndex(interp, args, skip);
    Jsi_Value *len = Jsi_ValueArrayIndex(interp, args, skip+1);
    
    Jsi_Number nstart, nlen;
    if (!start || Jsi_GetNumberFromValue(interp,start, &nstart) != JSI_OK) {
        Jsi_ValueMakeStringDup(interp, ret, v);
        return JSI_OK;
    }
    int istart = (int)nstart;
    Jsi_DString dStr;

    Jsi_DSInit(&dStr);
    if (!len || Jsi_GetNumberFromValue(interp,len, &nlen) != JSI_OK) {
        if (sLen == bLen)
            Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(v, istart, -1));


        else {
            Jsi_UtfSubstr(v, istart, -1, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
        return JSI_OK;
    }
    int ilen = (int)nlen;
    if (ilen <= 0) {
        Jsi_ValueMakeStringDup(interp, ret, "");
    } else {
        if (sLen == bLen)
            Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(v, istart, ilen));

        else {
            Jsi_UtfSubstr(v, istart, ilen, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
    }
    return JSI_OK;
}

................................................................................
    Jsi_Value *end = Jsi_ValueArrayIndex(interp, args, skip+1);
    
    Jsi_Number nstart, nend;
    if (!start || Jsi_GetNumberFromValue(interp,start, &nstart) != JSI_OK) {
        Jsi_ValueMakeStringDup(interp, ret, v);
        return JSI_OK;
    }
    int istart = (int)nstart;
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);
    

    if (!end || Jsi_GetNumberFromValue(interp,end, &nend) != JSI_OK) {
        if (sLen == bLen)
            Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(v, istart, -1));

        else {
            Jsi_UtfSubstr(v, istart, -1, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
        return JSI_OK;
    }
    int iend = (int)nend;
    if (iend>sLen)
        iend = sLen;
    if (iend < istart) {
        Jsi_ValueMakeStringDup(interp, ret, "");
    } else {
        if (sLen == bLen)
            Jsi_ValueMakeString(interp, ret, jsi_SubstrDup(v, istart, iend-istart+1));

        else {
            Jsi_UtfSubstr(v, istart, iend-istart+1, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
    }
    return JSI_OK;
}

................................................................................
    if (Jsi_ValueIsString(interp, seq)) {
        char *cp = Jsi_ValueString(interp, seq, NULL);

        if (jsi_RegExpValueNew(interp, cp, seq) != JSI_OK)
            return JSI_ERROR;
    }
    /* TODO: differentiate from re.exec() */
    return jsi_RegExpMatches(interp, seq, v, *ret, NULL, 1);
}

static Jsi_RC StringFromCharCodeCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    if (!(_this->vt == JSI_VT_OBJECT && _this->d.obj->ot == JSI_OT_FUNCTION &&
       _this->d.obj->__proto__ == interp->String_prototype->d.obj->__proto__ ))
................................................................................
            Jsi_LogError("String get failure");
            Jsi_DSFree(&dStr);
            return JSI_ERROR;
        }
        Jsi_DSAppend(&dStr, vstr, NULL);
    }

    Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
    return JSI_OK;
    
}

static Jsi_RC StringSliceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
................................................................................
                j += slen;
            }
        }
        if (i>=obj->arrCnt)
            Jsi_DSAppendLen(&dStr, p, 1);
    }

    Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
    return JSI_OK;
}
    
#define FN_strreplace JSI_INFO("\
If the replace argument is a function, it is called with match,p1,p2,...,offset,string.  \
If called function is known to have 1 argument, it is called with just the match.")
static Jsi_RC StringReplaceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
................................................................................
                    Jsi_DSFree(&dStr);
                    Jsi_DecrRefCount(interp, inStr);
                    return JSI_ERROR;
                }
                Jsi_DecrRefCount(interp, inStr);
            }
            Jsi_DSAppend(&dStr, ce+Jsi_Strlen(cp), NULL);
            Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
        }
        return JSI_OK;
    }
    if (seq == NULL || seq->vt != JSI_VT_OBJECT || seq->d.obj->ot != JSI_OT_REGEXP) {
        Jsi_ValueMakeNull(interp, ret);
        return JSI_OK;
    }
................................................................................
            }
    
        } else {
            Jsi_DString sStr;
            Jsi_DSInit(&sStr); 
            if (pmatch[0].rm_so <= 0 && pmatch[0].rm_eo <= 0)
                break;
    
            Jsi_Value *inStr = Jsi_ValueMakeString(interp, NULL, 
                jsi_SubstrDup(p, pmatch[0].rm_so, pmatch[0].rm_eo - pmatch[0].rm_so));
            Jsi_DSFree(&sStr);
            Jsi_IncrRefCount(interp, inStr);
            if (maxArgs==1) {
                Jsi_RC rc = Jsi_FunctionInvokeString(interp, repVal, inStr, &dStr);
                if (Jsi_InterpGone(interp))
                    return JSI_ERROR;
                if (rc != JSI_OK) {
................................................................................
                    Jsi_DecrRefCount(interp, inStr);
                    return JSI_ERROR;
                }
            } else {
                Jsi_Value *vpargs, *items[MAX_SUBREGEX] = {}, *ret;
                int i;
                items[0] = inStr;
                for (i=1; i<=(int)re->reg.re_nsub && i<(MAX_SUBREGEX-3); i++)



                    items[i] = (pmatch[i].rm_so<0?interp->NullValue:Jsi_ValueMakeString(interp, NULL, jsi_SubstrDup(p, pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so)));



                items[i++] = Jsi_ValueMakeNumber(interp, NULL, eoffset+pmatch[0].rm_so);
                items[i++] = strVal;
                vpargs = Jsi_ValueMakeObject(interp, NULL, Jsi_ObjNewArray(interp, items, i, 0));
                Jsi_IncrRefCount(interp, vpargs);
                ret = Jsi_ValueNew1(interp);
                rc = Jsi_FunctionInvoke(interp, repVal, vpargs, &ret, NULL);
                if (Jsi_InterpGone(interp))
................................................................................
    } while (n);

    /*
     * Copy the portion of the string after the last match to the
     * result variable.
     */
    Jsi_DSAppend(&dStr, p, NULL);
    Jsi_ValueMakeString(interp, ret, Jsi_DSFreeDup(&dStr));
    return rc;

}

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







|







 







|







 







|


|

>


|
<
>
>
|









|
|
>
|







 







|


<
>

|
|
>
|











|
|
>
|







 







|







 







|







 







|







 







|







 







|
|
|







 







|
>
>
>
|
>
>
>







 







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
..
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
...
160
161
162
163
164
165
166
167
168
169

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
...
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
...
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
...
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
...
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
...
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
...
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
    }

static Jsi_RC StringConstructor(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    if (Jsi_FunctionIsConstructor(funcPtr)) {
        const char *nv = "";
        int len = -1;
        if (Jsi_ValueGetLength(interp, args) > 0) {
            Jsi_Value *v = Jsi_ValueArrayIndex(interp, args, 0);
            if (v) {
                
                nv = Jsi_ValueToString(interp, v, &len);
            }
        }
................................................................................
            if (_this->d.obj->d.s.str)
                if (!_this->d.obj->isstrkey)
                    Jsi_Free(_this->d.obj->d.s.str);
            _this->d.obj->isstrkey = 0;
            _this->d.obj->d.s.str = Jsi_StrdupLen(nv, len);
            _this->d.obj->d.s.len = len;
        } else
            jsi_ValueMakeBlobDup(interp, &_this, (uchar*)nv, len);
        Jsi_ValueDup2(interp, ret, _this);
        return JSI_OK;
    }
    if (Jsi_ValueGetLength(interp, args) > 0) {
        Jsi_Value *v = Jsi_ValueArrayIndex(interp, args, 0);
        if (v) {
            Jsi_ValueDup2(interp, ret, v);
................................................................................
    ChkString(_this, funcPtr, v, &sLen, &bLen);

    Jsi_Value *start = Jsi_ValueArrayIndex(interp, args, skip);
    Jsi_Value *len = Jsi_ValueArrayIndex(interp, args, skip+1);
    
    Jsi_Number nstart, nlen;
    if (!start || Jsi_GetNumberFromValue(interp,start, &nstart) != JSI_OK) {
        jsi_ValueMakeBlobDup(interp, ret, (uchar*)v, bLen);
        return JSI_OK;
    }
    int istart = (int)nstart, olen = -1;
    Jsi_DString dStr;
    char *ostr;
    Jsi_DSInit(&dStr);
    if (!len || Jsi_GetNumberFromValue(interp,len, &nlen) != JSI_OK) {
        if (sLen == bLen) {

            ostr = jsi_SubstrDup(v, bLen, istart, -1, &olen);
            Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
        } else {
            Jsi_UtfSubstr(v, istart, -1, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
        return JSI_OK;
    }
    int ilen = (int)nlen;
    if (ilen <= 0) {
        Jsi_ValueMakeStringDup(interp, ret, "");
    } else {
        if (sLen == bLen) {
            ostr = jsi_SubstrDup(v, bLen, istart, ilen, &olen);
            Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
        } else {
            Jsi_UtfSubstr(v, istart, ilen, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
    }
    return JSI_OK;
}

................................................................................
    Jsi_Value *end = Jsi_ValueArrayIndex(interp, args, skip+1);
    
    Jsi_Number nstart, nend;
    if (!start || Jsi_GetNumberFromValue(interp,start, &nstart) != JSI_OK) {
        Jsi_ValueMakeStringDup(interp, ret, v);
        return JSI_OK;
    }
    int istart = (int)nstart, olen = -1;
    Jsi_DString dStr;
    Jsi_DSInit(&dStr);

    char *ostr;
    if (!end || Jsi_GetNumberFromValue(interp,end, &nend) != JSI_OK) {
        if (sLen == bLen) {
            ostr = jsi_SubstrDup(v, bLen, istart, -1, &olen);
            Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
        } else {
            Jsi_UtfSubstr(v, istart, -1, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
        return JSI_OK;
    }
    int iend = (int)nend;
    if (iend>sLen)
        iend = sLen;
    if (iend < istart) {
        Jsi_ValueMakeStringDup(interp, ret, "");
    } else {
        if (sLen == bLen) {
            ostr = jsi_SubstrDup(v, bLen, istart, iend-istart+1, &olen);
            Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
        } else {
            Jsi_UtfSubstr(v, istart, iend-istart+1, &dStr);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
    }
    return JSI_OK;
}

................................................................................
    if (Jsi_ValueIsString(interp, seq)) {
        char *cp = Jsi_ValueString(interp, seq, NULL);

        if (jsi_RegExpValueNew(interp, cp, seq) != JSI_OK)
            return JSI_ERROR;
    }
    /* TODO: differentiate from re.exec() */
    return jsi_RegExpMatches(interp, seq, v, bLen, *ret, NULL, 1);
}

static Jsi_RC StringFromCharCodeCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    if (!(_this->vt == JSI_VT_OBJECT && _this->d.obj->ot == JSI_OT_FUNCTION &&
       _this->d.obj->__proto__ == interp->String_prototype->d.obj->__proto__ ))
................................................................................
            Jsi_LogError("String get failure");
            Jsi_DSFree(&dStr);
            return JSI_ERROR;
        }
        Jsi_DSAppend(&dStr, vstr, NULL);
    }

    Jsi_ValueFromDS(interp, &dStr, ret);
    return JSI_OK;
    
}

static Jsi_RC StringSliceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
................................................................................
                j += slen;
            }
        }
        if (i>=obj->arrCnt)
            Jsi_DSAppendLen(&dStr, p, 1);
    }

    Jsi_ValueFromDS(interp, &dStr, ret);
    return JSI_OK;
}
    
#define FN_strreplace JSI_INFO("\
If the replace argument is a function, it is called with match,p1,p2,...,offset,string.  \
If called function is known to have 1 argument, it is called with just the match.")
static Jsi_RC StringReplaceCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
................................................................................
                    Jsi_DSFree(&dStr);
                    Jsi_DecrRefCount(interp, inStr);
                    return JSI_ERROR;
                }
                Jsi_DecrRefCount(interp, inStr);
            }
            Jsi_DSAppend(&dStr, ce+Jsi_Strlen(cp), NULL);
            Jsi_ValueFromDS(interp, &dStr, ret);
        }
        return JSI_OK;
    }
    if (seq == NULL || seq->vt != JSI_VT_OBJECT || seq->d.obj->ot != JSI_OT_REGEXP) {
        Jsi_ValueMakeNull(interp, ret);
        return JSI_OK;
    }
................................................................................
            }
    
        } else {
            Jsi_DString sStr;
            Jsi_DSInit(&sStr); 
            if (pmatch[0].rm_so <= 0 && pmatch[0].rm_eo <= 0)
                break;
            int olen = -1;
            char *ostr = jsi_SubstrDup(p, -1, pmatch[0].rm_so, pmatch[0].rm_eo - pmatch[0].rm_so, &olen);
            Jsi_Value *inStr = Jsi_ValueMakeBlob(interp, NULL, (uchar*)ostr, olen);
            Jsi_DSFree(&sStr);
            Jsi_IncrRefCount(interp, inStr);
            if (maxArgs==1) {
                Jsi_RC rc = Jsi_FunctionInvokeString(interp, repVal, inStr, &dStr);
                if (Jsi_InterpGone(interp))
                    return JSI_ERROR;
                if (rc != JSI_OK) {
................................................................................
                    Jsi_DecrRefCount(interp, inStr);
                    return JSI_ERROR;
                }
            } else {
                Jsi_Value *vpargs, *items[MAX_SUBREGEX] = {}, *ret;
                int i;
                items[0] = inStr;
                for (i=1; i<=(int)re->reg.re_nsub && i<(MAX_SUBREGEX-3); i++) {
                    if (pmatch[i].rm_so<0)
                        items[i] = interp->NullValue;
                    else {
                        ostr = jsi_SubstrDup(p, -1, pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so, &olen);
                        items[i] = Jsi_ValueMakeBlob(interp, NULL, (uchar*)ostr, olen);
                    }
                }
                items[i++] = Jsi_ValueMakeNumber(interp, NULL, eoffset+pmatch[0].rm_so);
                items[i++] = strVal;
                vpargs = Jsi_ValueMakeObject(interp, NULL, Jsi_ObjNewArray(interp, items, i, 0));
                Jsi_IncrRefCount(interp, vpargs);
                ret = Jsi_ValueNew1(interp);
                rc = Jsi_FunctionInvoke(interp, repVal, vpargs, &ret, NULL);
                if (Jsi_InterpGone(interp))
................................................................................
    } while (n);

    /*
     * Copy the portion of the string after the last match to the
     * result variable.
     */
    Jsi_DSAppend(&dStr, p, NULL);
    Jsi_ValueFromDS(interp, &dStr, ret);
    return rc;

}

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

Changes to src/jsiStubs.h.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
....
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
#ifndef __JSI_STUBS_H__
#define __JSI_STUBS_H__
#ifndef JSI_AMALGAMATION
#include "jsi.h"
#endif


#define JSI_STUBS_MD5 "f10cf428d26d56bf41a31286e1cbc9c2"

#undef JSI_EXTENSION_INI
#define JSI_EXTENSION_INI Jsi_Stubs *jsiStubsPtr = NULL;

#ifdef JSI__MUSL
#define JSI_STUBS_BLDFLAGS 1
#else
................................................................................
    Jsi_Number(*_Jsi_Version)(void);
    Jsi_Value*(*_Jsi_ReturnValue)(Jsi_Interp *interp);
    Jsi_RC(*_Jsi_Mount)( Jsi_Interp *interp, Jsi_Value *archive, Jsi_Value *mount, Jsi_Value **ret);
    Jsi_Value*(*_Jsi_Executable)(Jsi_Interp *interp);
    Jsi_Regex*(*_Jsi_RegExpNew)(Jsi_Interp *interp, const char *regtxt, int flag);
    void(*_Jsi_RegExpFree)(Jsi_Regex* re);
    Jsi_RC(*_Jsi_RegExpMatch)( Jsi_Interp *interp,  Jsi_Value *pattern, const char *str, int *rc, Jsi_DString *dStr);
    Jsi_RC(*_Jsi_RegExpMatches)(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, Jsi_Value *ret);
    bool(*_Jsi_GlobMatch)(const char *pattern, const char *string, int nocase);
    char*(*_Jsi_FileRealpath)(Jsi_Interp *interp, Jsi_Value *path, char *newpath);
    char*(*_Jsi_FileRealpathStr)(Jsi_Interp *interp, const char *path, char *newpath);
    char*(*_Jsi_NormalPath)(Jsi_Interp *interp, const char *path, Jsi_DString *dStr);
    char*(*_Jsi_ValueNormalPath)(Jsi_Interp *interp, Jsi_Value *path, Jsi_DString *dStr);
    Jsi_RC(*_Jsi_JSONParse)(Jsi_Interp *interp, const char *js, Jsi_Value **ret, int flags);
    Jsi_RC(*_Jsi_JSONParseFmt)(Jsi_Interp *interp, Jsi_Value **ret, const char *fmt, ...);
................................................................................
#define Jsi_Version(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_Version(n0))
#define Jsi_ReturnValue(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_ReturnValue(n0))
#define Jsi_Mount(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_Mount(n0,n1,n2,n3))
#define Jsi_Executable(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_Executable(n0))
#define Jsi_RegExpNew(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpNew(n0,n1,n2))
#define Jsi_RegExpFree(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpFree(n0))
#define Jsi_RegExpMatch(n0,n1,n2,n3,n4) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpMatch(n0,n1,n2,n3,n4))
#define Jsi_RegExpMatches(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpMatches(n0,n1,n2,n3))
#define Jsi_GlobMatch(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_GlobMatch(n0,n1,n2))
#define Jsi_FileRealpath(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_FileRealpath(n0,n1,n2))
#define Jsi_FileRealpathStr(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_FileRealpathStr(n0,n1,n2))
#define Jsi_NormalPath(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_NormalPath(n0,n1,n2))
#define Jsi_ValueNormalPath(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_ValueNormalPath(n0,n1,n2))
#define Jsi_JSONParse(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_JSONParse(n0,n1,n2,n3))
#define Jsi_JSONParseFmt(n0,n1,n2,...) JSISTUBCALL(jsiStubsPtr, _Jsi_JSONParseFmt(n0,n1,n2,##__VA_ARGS__))







|







 







|







 







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
....
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
#ifndef __JSI_STUBS_H__
#define __JSI_STUBS_H__
#ifndef JSI_AMALGAMATION
#include "jsi.h"
#endif


#define JSI_STUBS_MD5 "84f582f050ca4afde696dea1f107497f"

#undef JSI_EXTENSION_INI
#define JSI_EXTENSION_INI Jsi_Stubs *jsiStubsPtr = NULL;

#ifdef JSI__MUSL
#define JSI_STUBS_BLDFLAGS 1
#else
................................................................................
    Jsi_Number(*_Jsi_Version)(void);
    Jsi_Value*(*_Jsi_ReturnValue)(Jsi_Interp *interp);
    Jsi_RC(*_Jsi_Mount)( Jsi_Interp *interp, Jsi_Value *archive, Jsi_Value *mount, Jsi_Value **ret);
    Jsi_Value*(*_Jsi_Executable)(Jsi_Interp *interp);
    Jsi_Regex*(*_Jsi_RegExpNew)(Jsi_Interp *interp, const char *regtxt, int flag);
    void(*_Jsi_RegExpFree)(Jsi_Regex* re);
    Jsi_RC(*_Jsi_RegExpMatch)( Jsi_Interp *interp,  Jsi_Value *pattern, const char *str, int *rc, Jsi_DString *dStr);
    Jsi_RC(*_Jsi_RegExpMatches)(Jsi_Interp *interp, Jsi_Value *pattern, const char *str, int slen, Jsi_Value *ret);
    bool(*_Jsi_GlobMatch)(const char *pattern, const char *string, int nocase);
    char*(*_Jsi_FileRealpath)(Jsi_Interp *interp, Jsi_Value *path, char *newpath);
    char*(*_Jsi_FileRealpathStr)(Jsi_Interp *interp, const char *path, char *newpath);
    char*(*_Jsi_NormalPath)(Jsi_Interp *interp, const char *path, Jsi_DString *dStr);
    char*(*_Jsi_ValueNormalPath)(Jsi_Interp *interp, Jsi_Value *path, Jsi_DString *dStr);
    Jsi_RC(*_Jsi_JSONParse)(Jsi_Interp *interp, const char *js, Jsi_Value **ret, int flags);
    Jsi_RC(*_Jsi_JSONParseFmt)(Jsi_Interp *interp, Jsi_Value **ret, const char *fmt, ...);
................................................................................
#define Jsi_Version(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_Version(n0))
#define Jsi_ReturnValue(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_ReturnValue(n0))
#define Jsi_Mount(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_Mount(n0,n1,n2,n3))
#define Jsi_Executable(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_Executable(n0))
#define Jsi_RegExpNew(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpNew(n0,n1,n2))
#define Jsi_RegExpFree(n0) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpFree(n0))
#define Jsi_RegExpMatch(n0,n1,n2,n3,n4) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpMatch(n0,n1,n2,n3,n4))
#define Jsi_RegExpMatches(n0,n1,n2,n3,n4) JSISTUBCALL(jsiStubsPtr, _Jsi_RegExpMatches(n0,n1,n2,n3,n4))
#define Jsi_GlobMatch(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_GlobMatch(n0,n1,n2))
#define Jsi_FileRealpath(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_FileRealpath(n0,n1,n2))
#define Jsi_FileRealpathStr(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_FileRealpathStr(n0,n1,n2))
#define Jsi_NormalPath(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_NormalPath(n0,n1,n2))
#define Jsi_ValueNormalPath(n0,n1,n2) JSISTUBCALL(jsiStubsPtr, _Jsi_ValueNormalPath(n0,n1,n2))
#define Jsi_JSONParse(n0,n1,n2,n3) JSISTUBCALL(jsiStubsPtr, _Jsi_JSONParse(n0,n1,n2,n3))
#define Jsi_JSONParseFmt(n0,n1,n2,...) JSISTUBCALL(jsiStubsPtr, _Jsi_JSONParseFmt(n0,n1,n2,##__VA_ARGS__))

Changes to src/jsiWebSocket.c.

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
...
294
295
296
297
298
299
300

301
302
303
304
305
306
307
...
323
324
325
326
327
328
329

330
331
332
333
334
335
336
...
495
496
497
498
499
500
501


502
503
504
505
506
507
508
509
...
783
784
785
786
787
788
789
















790
791
792
793
794
795
796
...
811
812
813
814
815
816
817

818
819
820
821
822
823
824
...
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
....
1046
1047
1048
1049
1050
1051
1052
1053

1054
1055
1056
1057
1058
1059
1060
....
1294
1295
1296
1297
1298
1299
1300

1301
1302
1303
1304
1305
1306


1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320



1321
1322
1323
1324
1325
1326
1327
....
2603
2604
2605
2606
2607
2608
2609

2610
2611
2612
2613
2614
2615
2616
    int bufferPwr2;
    jsi_wsStatData stats;
    char *iface;
    const char* urlPrefix, *urlRedirect;
    const char *localhostName;
    const char *clientName;
    const char *clientIP;
    const char *useridPass;
    const char *realm, *includeFile;
    struct lws_context *instCtx;
    Jsi_Value *getRegexp, *post;
    unsigned int oldus;
    int opts;
    int hasOpts;
    int debug;
    int maxConnects;
................................................................................
    JSI_OPT(BOOL,   jsi_wsCmdObj, echo,       .help="LogInfo outputs all websock Send/Recv messages"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, formParams, .help="Comma seperated list of upload form param names ('text,send,file,upload')", jsi_IIRO),
    JSI_OPT(OBJ,    jsi_wsCmdObj, extArgs,    .help="Arguments for extension handlers", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, extHandlers,.help="Enable builtin handlers for these extensions: .htmli, .cssi, .jsi, and .md", jsi_IIOF),
    JSI_OPT(REGEXP, jsi_wsCmdObj, getRegexp,  .help="Call onGet() only if Url matches pattern"),
//    JSI_OPT(CUSTOM, jsi_wsCmdObj, handlersPkg,.help="Handlers use package() to upgrade string to function object"),
    JSI_OPT(ARRAY,  jsi_wsCmdObj, headers,    .help="List of name/value output header pairs", jsi_IIOF),

    JSI_OPT(STRING, jsi_wsCmdObj, interface,  .help="Interface for server to listen on, eg. 'eth0' or 'lo'", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, local,      .help="Limit connections to localhost addresses on the 127 network"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, localhostName,.help="Client name used by localhost connections ('localhost')"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxConnects,.help="In server mode, max number of client connections accepted"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxDownload,.help="Max size of file download"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxUpload,  .help="Max size of file upload will accept"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, mimeTypes,  .help="Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'})", jsi_IIOF),
................................................................................
    JSI_OPT(STRING, jsi_wsCmdObj, post,       .help="Post string to serve", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, protocol,   .help="Name of protocol (ws/wss)"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, realm,      .help="Realm for basic auth (jsish)", ),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufMax, .help="Size limit of a websocket message", jsi_IIOF),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufTimeout,.help="Timeout for recv of a websock msg", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, redirMax,   .help="Temporarily disable redirects when see more than this in 10 minutes"),
    JSI_OPT(STRING, jsi_wsCmdObj, rootdir,    .help="Directory to serve html from (\".\")"),

    JSI_OPT(CUSTOM, jsi_wsCmdObj, stats,      .help="Statistical data", jsi_IIRO, .custom=Jsi_Opt_SwitchSuboption, .data=WPSStats),
    JSI_OPT(TIME_T, jsi_wsCmdObj, startTime,  .help="Time of websocket start", jsi_IIRO),
    JSI_OPT(STRKEY, jsi_wsCmdObj, includeFile, .help="Default file when no extension given (include.shtml)"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlPrefix,  .help="Prefix in url to strip from path; for reverse proxy"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlRedirect,.help="Redirect when no url or / is given. Must match urlPrefix, if given"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, use_ssl,    .help="Use https (for client)", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, useridPass, .help="The USERID:PASSWORD to use for basic authentication"),
................................................................................
    int code, const char *extra, const char *mime, Jsi_DString *jStr)
{
    uchar ubuf[JSI_BUFSIZ], *p=ubuf, *end = &ubuf[sizeof(ubuf)-1];
    if (!mime) mime = "text/html";
    if (code<=0) code = 200;
    if (lws_add_http_header_status(wsi, code, &p, end))
        return -1;


    if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER, (uchar*)"libwebsockets", 13, &p, end))
        return -1;
    if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (uchar *)mime, Jsi_Strlen(mime), &p, end))
        return -1;
    if (lws_add_http_header_content_length(wsi, strLen, &p, end))
        return -1;
    *p = 0;
    Jsi_DSAppend(jStr, (char*)ubuf, extra, NULL);
................................................................................
            if (n>0)
                Jsi_DSAppendLen(hStr, (char*)buffer, n);
            p = buffer;
        }
    }
    return true;
}

















// Read native file only if inside rootdir
static Jsi_RC jsi_wsFileRead(Jsi_Interp *interp, Jsi_Value *name, Jsi_DString *dStr, jsi_wsCmdObj *cmdPtr) {
    Jsi_StatBuf sb;
    Jsi_RC rc = JSI_ERROR;
    int n = Jsi_Stat(interp, name, &sb);
    if (!n && sb.st_size>0) {
................................................................................
    int lvl) {
    Jsi_Value *fval;
    Jsi_RC rc = JSI_OK;
    char *cp, *cp2, *ce, pref[] = "<!--#include file=\"", suffix[] = "\"-->",
        pref2[] = "<!--#include virtual=\"";
    int flen, plen, plen1 = sizeof(pref)-1,  plen2 = sizeof(pref2)-1, slen = sizeof(suffix)-1;
    Jsi_DString tStr = {};

    const char *cs = "<!-- Markdeep: --><style class=\"fallback\">body{visibility:hidden;}</style>\n"
                "<script>window.markdeepOptions={tocStyle:\"medium\"}</script>\n"
                "<!--#include file=\"$inc\"-->\n"
                "<script src=\"markdeep.min.js\"></script>\n"
                "<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility='visible')</script>";
    char *fs, *fname = Jsi_ValueString(interp, fn, &flen), *fend = fname;
    char fbuf[PATH_MAX];
................................................................................
    time_t now = time(NULL);
    char buf[JSI_BUFSIZ];
    int rc = 0, essi = 0;
    buf[0] = 0;
    uchar *p = buffer, *end = &buffer[sizeof(buffer)-1];
    int n;
    Jsi_Value* fname = NULL;
    bool isMdi = 0;

    /* if a legal POST URL, let it continue and accept data */
    if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
        return 0;
    if (!pss)
        pss = jsi_wsgetPss(cmdPtr, wsi, user, 1, 1);

................................................................................
            }
        }
    }

    snprintf(buf, sizeof(buf), "%s/%s", cmdPtr->curRoot, inPtr);
    if (cmdPtr->debug>1)
        fprintf(stderr, "FILE: %s in %s | %s\n", buf, cmdPtr->curRoot, Jsi_ValueString(interp, cmdPtr->rootdir, NULL));
    char extBuf[100];

    bool isgzip = 0;
    if (!ext || !ext[1])
        mime = "text/html";
    else {
        const char *eext = ext+1;
        uint elen = Jsi_Strlen(ext);
        if (elen>3 && elen<(sizeof(extBuf)-10) && !Jsi_Strcmp(ext+elen-3,".gz")) {
................................................................................
            goto bail;
    }
    if (cmdPtr->headers && !jsi_wsAddHeader(interp, cmdPtr, wsi, cmdPtr->headers, &hStr))
        goto bail;

    if (pss->headers && !jsi_wsAddHeader(interp, cmdPtr, wsi, pss->headers, &hStr))
        goto bail;


    n = Jsi_DSLength(&hStr);

    if (native && !isMdi) {
        Jsi_DecrRefCount(interp, fname);



        int hrc = lws_serve_http_file(wsi, buf, mime, Jsi_DSValue(&hStr), Jsi_DSLength(&hStr));
        if (hrc<0) {
            if (cmdPtr->noWarn==0)
                fprintf(stderr, "can not serve file (%d): %s\n", hrc, buf);
            goto bail;
        } else if (hrc > 0 && lws_http_transaction_completed(wsi))
            goto bail;
    } else {
        // Need to read data for non-native files.
        Jsi_DString dStr = {}, fStr = {};
        if (isMdi)
            rc = jsi_wsTemplateFill(interp, cmdPtr, fname, &fStr, (essi?1:0));
        else
            rc = jsi_wsFileRead(interp, fname, &fStr, cmdPtr);



        if (rc != JSI_OK) {
            Jsi_DSFree(&fStr);
            goto nofile;
        }
        int hrc = jsi_wsServeHeader(pss, wsi, (int)Jsi_DSLength(&fStr), 200, Jsi_DSValue(&hStr), mime, &dStr);
        if (hrc>=0) {
            Jsi_DSAppendLen(&dStr, Jsi_DSValue(&fStr), Jsi_DSLength(&fStr));
................................................................................
    cmdPtr->ietf_version = -1;
    cmdPtr->bufferPwr2 = 0;
    cmdPtr->ws_gid = -1;
    cmdPtr->ws_uid = -1;
    cmdPtr->startTime = time(NULL);
    cmdPtr->hasOpts = 1;
    cmdPtr->includeFile = "include.shtml";

    if ((arg != NULL && !Jsi_ValueIsNull(interp,arg))
        && Jsi_OptionsProcess(interp, WSOptions, cmdPtr, arg, 0) < 0) {
bail:
        jsi_wswebsocketObjFree(interp, cmdPtr);
        return JSI_ERROR;
    }
    Jsi_PathNormalize(interp, &cmdPtr->rootdir);







|
|







 







>







 







>







 







>
>
|







 







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







 







>







 







|







 







|
>







 







>



|


>
>












|

>
>
>







 







>







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
...
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
...
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
...
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
...
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
....
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
....
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
....
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
    int bufferPwr2;
    jsi_wsStatData stats;
    char *iface;
    const char* urlPrefix, *urlRedirect;
    const char *localhostName;
    const char *clientName;
    const char *clientIP;
    const char *useridPass, *server;
    const char *realm, *includeFile, *jsiFnPattern;
    struct lws_context *instCtx;
    Jsi_Value *getRegexp, *post;
    unsigned int oldus;
    int opts;
    int hasOpts;
    int debug;
    int maxConnects;
................................................................................
    JSI_OPT(BOOL,   jsi_wsCmdObj, echo,       .help="LogInfo outputs all websock Send/Recv messages"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, formParams, .help="Comma seperated list of upload form param names ('text,send,file,upload')", jsi_IIRO),
    JSI_OPT(OBJ,    jsi_wsCmdObj, extArgs,    .help="Arguments for extension handlers", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, extHandlers,.help="Enable builtin handlers for these extensions: .htmli, .cssi, .jsi, and .md", jsi_IIOF),
    JSI_OPT(REGEXP, jsi_wsCmdObj, getRegexp,  .help="Call onGet() only if Url matches pattern"),
//    JSI_OPT(CUSTOM, jsi_wsCmdObj, handlersPkg,.help="Handlers use package() to upgrade string to function object"),
    JSI_OPT(ARRAY,  jsi_wsCmdObj, headers,    .help="List of name/value output header pairs", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, jsiFnPattern,.help="A glob-match pattern for files to which is appended 'window.jsiWebSocket=true;' (jsi*.js)", jsi_IIRO),
    JSI_OPT(STRING, jsi_wsCmdObj, interface,  .help="Interface for server to listen on, eg. 'eth0' or 'lo'", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, local,      .help="Limit connections to localhost addresses on the 127 network"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, localhostName,.help="Client name used by localhost connections ('localhost')"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxConnects,.help="In server mode, max number of client connections accepted"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxDownload,.help="Max size of file download"),
    JSI_OPT(INT,    jsi_wsCmdObj, maxUpload,  .help="Max size of file upload will accept"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, mimeTypes,  .help="Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'})", jsi_IIOF),
................................................................................
    JSI_OPT(STRING, jsi_wsCmdObj, post,       .help="Post string to serve", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, protocol,   .help="Name of protocol (ws/wss)"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, realm,      .help="Realm for basic auth (jsish)", ),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufMax, .help="Size limit of a websocket message", jsi_IIOF),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufTimeout,.help="Timeout for recv of a websock msg", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, redirMax,   .help="Temporarily disable redirects when see more than this in 10 minutes"),
    JSI_OPT(STRING, jsi_wsCmdObj, rootdir,    .help="Directory to serve html from (\".\")"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, server,     .help="String to send out int the header SERVER (jsiWebSocket)"),
    JSI_OPT(CUSTOM, jsi_wsCmdObj, stats,      .help="Statistical data", jsi_IIRO, .custom=Jsi_Opt_SwitchSuboption, .data=WPSStats),
    JSI_OPT(TIME_T, jsi_wsCmdObj, startTime,  .help="Time of websocket start", jsi_IIRO),
    JSI_OPT(STRKEY, jsi_wsCmdObj, includeFile, .help="Default file when no extension given (include.shtml)"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlPrefix,  .help="Prefix in url to strip from path; for reverse proxy"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, urlRedirect,.help="Redirect when no url or / is given. Must match urlPrefix, if given"),
    JSI_OPT(BOOL,   jsi_wsCmdObj, use_ssl,    .help="Use https (for client)", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, useridPass, .help="The USERID:PASSWORD to use for basic authentication"),
................................................................................
    int code, const char *extra, const char *mime, Jsi_DString *jStr)
{
    uchar ubuf[JSI_BUFSIZ], *p=ubuf, *end = &ubuf[sizeof(ubuf)-1];
    if (!mime) mime = "text/html";
    if (code<=0) code = 200;
    if (lws_add_http_header_status(wsi, code, &p, end))
        return -1;
    const char *srv = pss->cmdPtr->server;
    if (!srv) srv = "jsiWebSocket";
    if (srv[0] && lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER, (uchar*)srv, Jsi_Strlen(srv), &p, end))
        return -1;
    if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (uchar *)mime, Jsi_Strlen(mime), &p, end))
        return -1;
    if (lws_add_http_header_content_length(wsi, strLen, &p, end))
        return -1;
    *p = 0;
    Jsi_DSAppend(jStr, (char*)ubuf, extra, NULL);
................................................................................
            if (n>0)
                Jsi_DSAppendLen(hStr, (char*)buffer, n);
            p = buffer;
        }
    }
    return true;
}

static bool jsi_wsAddStdHeader(Jsi_Interp *interp, jsi_wsCmdObj *cmdPtr, struct lws *wsi,    Jsi_DString *hStr) {
    uchar buffer[JSI_BUFSIZ];
    uchar *p = (unsigned char *)buffer, *end = p + sizeof(buffer);
    const char *srv = cmdPtr->server;
    if (!srv) srv = "jsiWebSocket";
    int n = 0;
    if (srv[0] && lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER, (uchar*)srv, Jsi_Strlen(srv), &p, end))
        return false;
    n = p - buffer;
    if (n>0) {
        Jsi_DSAppendLen(hStr, (char*)buffer, n);
        p = buffer;
    }
    return true;
}

// Read native file only if inside rootdir
static Jsi_RC jsi_wsFileRead(Jsi_Interp *interp, Jsi_Value *name, Jsi_DString *dStr, jsi_wsCmdObj *cmdPtr) {
    Jsi_StatBuf sb;
    Jsi_RC rc = JSI_ERROR;
    int n = Jsi_Stat(interp, name, &sb);
    if (!n && sb.st_size>0) {
................................................................................
    int lvl) {
    Jsi_Value *fval;
    Jsi_RC rc = JSI_OK;
    char *cp, *cp2, *ce, pref[] = "<!--#include file=\"", suffix[] = "\"-->",
        pref2[] = "<!--#include virtual=\"";
    int flen, plen, plen1 = sizeof(pref)-1,  plen2 = sizeof(pref2)-1, slen = sizeof(suffix)-1;
    Jsi_DString tStr = {};
    // Fallback script.
    const char *cs = "<!-- Markdeep: --><style class=\"fallback\">body{visibility:hidden;}</style>\n"
                "<script>window.markdeepOptions={tocStyle:\"medium\"}</script>\n"
                "<!--#include file=\"$inc\"-->\n"
                "<script src=\"markdeep.min.js\"></script>\n"
                "<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility='visible')</script>";
    char *fs, *fname = Jsi_ValueString(interp, fn, &flen), *fend = fname;
    char fbuf[PATH_MAX];
................................................................................
    time_t now = time(NULL);
    char buf[JSI_BUFSIZ];
    int rc = 0, essi = 0;
    buf[0] = 0;
    uchar *p = buffer, *end = &buffer[sizeof(buffer)-1];
    int n;
    Jsi_Value* fname = NULL;
    bool isMdi = 0, isJsiWeb = 0;

    /* if a legal POST URL, let it continue and accept data */
    if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
        return 0;
    if (!pss)
        pss = jsi_wsgetPss(cmdPtr, wsi, user, 1, 1);

................................................................................
            }
        }
    }

    snprintf(buf, sizeof(buf), "%s/%s", cmdPtr->curRoot, inPtr);
    if (cmdPtr->debug>1)
        fprintf(stderr, "FILE: %s in %s | %s\n", buf, cmdPtr->curRoot, Jsi_ValueString(interp, cmdPtr->rootdir, NULL));
    char extBuf[100], *cpde = Jsi_Strrchr(buf, '/');
    isJsiWeb = (cpde && cmdPtr->jsiFnPattern && Jsi_GlobMatch(cmdPtr->jsiFnPattern, cpde+1, 0));
    bool isgzip = 0;
    if (!ext || !ext[1])
        mime = "text/html";
    else {
        const char *eext = ext+1;
        uint elen = Jsi_Strlen(ext);
        if (elen>3 && elen<(sizeof(extBuf)-10) && !Jsi_Strcmp(ext+elen-3,".gz")) {
................................................................................
            goto bail;
    }
    if (cmdPtr->headers && !jsi_wsAddHeader(interp, cmdPtr, wsi, cmdPtr->headers, &hStr))
        goto bail;

    if (pss->headers && !jsi_wsAddHeader(interp, cmdPtr, wsi, pss->headers, &hStr))
        goto bail;
    

    n = Jsi_DSLength(&hStr);

    if (native && !isMdi && !isJsiWeb) {
        Jsi_DecrRefCount(interp, fname);

        if (!jsi_wsAddStdHeader(interp, cmdPtr, wsi, &hStr))
            goto bail;
        int hrc = lws_serve_http_file(wsi, buf, mime, Jsi_DSValue(&hStr), Jsi_DSLength(&hStr));
        if (hrc<0) {
            if (cmdPtr->noWarn==0)
                fprintf(stderr, "can not serve file (%d): %s\n", hrc, buf);
            goto bail;
        } else if (hrc > 0 && lws_http_transaction_completed(wsi))
            goto bail;
    } else {
        // Need to read data for non-native files.
        Jsi_DString dStr = {}, fStr = {};
        if (isMdi)
            rc = jsi_wsTemplateFill(interp, cmdPtr, fname, &fStr, (essi?1:0));
        else {
            rc = jsi_wsFileRead(interp, fname, &fStr, cmdPtr);
            if (isJsiWeb)
                Jsi_DSAppend(&fStr, "\nwindow.jsiWebSocket=true;", NULL);
        }
        if (rc != JSI_OK) {
            Jsi_DSFree(&fStr);
            goto nofile;
        }
        int hrc = jsi_wsServeHeader(pss, wsi, (int)Jsi_DSLength(&fStr), 200, Jsi_DSValue(&hStr), mime, &dStr);
        if (hrc>=0) {
            Jsi_DSAppendLen(&dStr, Jsi_DSValue(&fStr), Jsi_DSLength(&fStr));
................................................................................
    cmdPtr->ietf_version = -1;
    cmdPtr->bufferPwr2 = 0;
    cmdPtr->ws_gid = -1;
    cmdPtr->ws_uid = -1;
    cmdPtr->startTime = time(NULL);
    cmdPtr->hasOpts = 1;
    cmdPtr->includeFile = "include.shtml";
    cmdPtr->jsiFnPattern = "jsi*js";
    if ((arg != NULL && !Jsi_ValueIsNull(interp,arg))
        && Jsi_OptionsProcess(interp, WSOptions, cmdPtr, arg, 0) < 0) {
bail:
        jsi_wswebsocketObjFree(interp, cmdPtr);
        return JSI_ERROR;
    }
    Jsi_PathNormalize(interp, &cmdPtr->rootdir);

Changes to tools/protos.jsi.

1
2
3
4
5
6
7
8
//JSI Command Prototypes: version 2.8.33
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.8.34
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.

1653
1654
1655
1656
1657
1658
1659

1660
1661
1662
1663
1664
1665
1666
....
1682
1683
1684
1685
1686
1687
1688

1689
1690
1691
1692
1693
1694
1695
<tr><td>debug</td><td><i>INT</i></td><td>Set debug level. Setting this to 512 will turn on max libwebsocket log levels.</td><td><i></i></td></tr>
<tr><td>echo</td><td><i>BOOL</i></td><td>LogInfo outputs all websock Send/Recv messages.</td><td><i></i></td></tr>
<tr><td>formParams</td><td><i>STRKEY</i></td><td>Comma seperated list of upload form param names ('text,send,file,upload').</td><td><i>readOnly</i></td></tr>
<tr><td>extArgs</td><td><i>OBJ</i></td><td>Arguments for extension handlers.</td><td><i>initOnly</i></td></tr>
<tr><td>extHandlers</td><td><i>BOOL</i></td><td>Enable builtin handlers for these extensions: .htmli, .cssi, .jsi, and .md.</td><td><i>initOnly</i></td></tr>
<tr><td>getRegexp</td><td><i>REGEXP</i></td><td>Call onGet() only if Url matches pattern.</td><td><i></i></td></tr>
<tr><td>headers</td><td><i>ARRAY</i></td><td>List of name/value output header pairs.</td><td><i>initOnly</i></td></tr>

<tr><td>interface</td><td><i>STRING</i></td><td>Interface for server to listen on, eg. 'eth0' or 'lo'.</td><td><i>initOnly</i></td></tr>
<tr><td>local</td><td><i>BOOL</i></td><td>Limit connections to localhost addresses on the 127 network.</td><td><i></i></td></tr>
<tr><td>localhostName</td><td><i>STRKEY</i></td><td>Client name used by localhost connections ('localhost').</td><td><i></i></td></tr>
<tr><td>maxConnects</td><td><i>INT</i></td><td>In server mode, max number of client connections accepted.</td><td><i></i></td></tr>
<tr><td>maxDownload</td><td><i>INT</i></td><td>Max size of file download.</td><td><i></i></td></tr>
<tr><td>maxUpload</td><td><i>INT</i></td><td>Max size of file upload will accept.</td><td><i></i></td></tr>
<tr><td>mimeTypes</td><td><i>OBJ</i></td><td>Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'}).</td><td><i>initOnly</i></td></tr>
................................................................................
<tr><td>post</td><td><i>STRING</i></td><td>Post string to serve.</td><td><i>initOnly</i></td></tr>
<tr><td>protocol</td><td><i>STRKEY</i></td><td>Name of protocol (ws/wss).</td><td><i></i></td></tr>
<tr><td>realm</td><td><i>STRKEY</i></td><td>Realm for basic auth (jsish).</td><td><i></i></td></tr>
<tr><td>recvBufMax</td><td><i>INT</i></td><td>Size limit of a websocket message.</td><td><i>initOnly</i></td></tr>
<tr><td>recvBufTimeout</td><td><i>INT</i></td><td>Timeout for recv of a websock msg.</td><td><i>initOnly</i></td></tr>
<tr><td>redirMax</td><td><i>BOOL</i></td><td>Temporarily disable redirects when see more than this in 10 minutes.</td><td><i></i></td></tr>
<tr><td>rootdir</td><td><i>STRING</i></td><td>Directory to serve html from (".").</td><td><i></i></td></tr>

<tr><td>stats</td><td><i><a href='#statsOptions'>options</a></i></td><td>Statistical data.</td><td><i>readOnly</i></td></tr>
<tr><td>startTime</td><td><i>TIME_T</i></td><td>Time of websocket start.</td><td><i>readOnly</i></td></tr>
<tr><td>includeFile</td><td><i>STRKEY</i></td><td>Default file when no extension given (include.shtml).</td><td><i></i></td></tr>
<tr><td>urlPrefix</td><td><i>STRKEY</i></td><td>Prefix in url to strip from path; for reverse proxy.</td><td><i></i></td></tr>
<tr><td>urlRedirect</td><td><i>STRKEY</i></td><td>Redirect when no url or / is given. Must match urlPrefix, if given.</td><td><i></i></td></tr>
<tr><td>use_ssl</td><td><i>BOOL</i></td><td>Use https (for client).</td><td><i>initOnly</i></td></tr>
<tr><td>useridPass</td><td><i>STRKEY</i></td><td>The USERID:PASSWORD to use for basic authentication.</td><td><i></i></td></tr>







>







 







>







1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
....
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
<tr><td>debug</td><td><i>INT</i></td><td>Set debug level. Setting this to 512 will turn on max libwebsocket log levels.</td><td><i></i></td></tr>
<tr><td>echo</td><td><i>BOOL</i></td><td>LogInfo outputs all websock Send/Recv messages.</td><td><i></i></td></tr>
<tr><td>formParams</td><td><i>STRKEY</i></td><td>Comma seperated list of upload form param names ('text,send,file,upload').</td><td><i>readOnly</i></td></tr>
<tr><td>extArgs</td><td><i>OBJ</i></td><td>Arguments for extension handlers.</td><td><i>initOnly</i></td></tr>
<tr><td>extHandlers</td><td><i>BOOL</i></td><td>Enable builtin handlers for these extensions: .htmli, .cssi, .jsi, and .md.</td><td><i>initOnly</i></td></tr>
<tr><td>getRegexp</td><td><i>REGEXP</i></td><td>Call onGet() only if Url matches pattern.</td><td><i></i></td></tr>
<tr><td>headers</td><td><i>ARRAY</i></td><td>List of name/value output header pairs.</td><td><i>initOnly</i></td></tr>
<tr><td>jsiFnPattern</td><td><i>STRKEY</i></td><td>A glob-match pattern for files to which is appended 'window.jsiWebSocket=true;' (jsi*.js).</td><td><i>readOnly</i></td></tr>
<tr><td>interface</td><td><i>STRING</i></td><td>Interface for server to listen on, eg. 'eth0' or 'lo'.</td><td><i>initOnly</i></td></tr>
<tr><td>local</td><td><i>BOOL</i></td><td>Limit connections to localhost addresses on the 127 network.</td><td><i></i></td></tr>
<tr><td>localhostName</td><td><i>STRKEY</i></td><td>Client name used by localhost connections ('localhost').</td><td><i></i></td></tr>
<tr><td>maxConnects</td><td><i>INT</i></td><td>In server mode, max number of client connections accepted.</td><td><i></i></td></tr>
<tr><td>maxDownload</td><td><i>INT</i></td><td>Max size of file download.</td><td><i></i></td></tr>
<tr><td>maxUpload</td><td><i>INT</i></td><td>Max size of file upload will accept.</td><td><i></i></td></tr>
<tr><td>mimeTypes</td><td><i>OBJ</i></td><td>Object providing map of file extensions to mime types (eg. {txt:'text/plain', bb:'text/bb'}).</td><td><i>initOnly</i></td></tr>
................................................................................
<tr><td>post</td><td><i>STRING</i></td><td>Post string to serve.</td><td><i>initOnly</i></td></tr>
<tr><td>protocol</td><td><i>STRKEY</i></td><td>Name of protocol (ws/wss).</td><td><i></i></td></tr>
<tr><td>realm</td><td><i>STRKEY</i></td><td>Realm for basic auth (jsish).</td><td><i></i></td></tr>
<tr><td>recvBufMax</td><td><i>INT</i></td><td>Size limit of a websocket message.</td><td><i>initOnly</i></td></tr>
<tr><td>recvBufTimeout</td><td><i>INT</i></td><td>Timeout for recv of a websock msg.</td><td><i>initOnly</i></td></tr>
<tr><td>redirMax</td><td><i>BOOL</i></td><td>Temporarily disable redirects when see more than this in 10 minutes.</td><td><i></i></td></tr>
<tr><td>rootdir</td><td><i>STRING</i></td><td>Directory to serve html from (".").</td><td><i></i></td></tr>
<tr><td>server</td><td><i>STRKEY</i></td><td>String to send out int the header SERVER (jsiWebSocket).</td><td><i></i></td></tr>
<tr><td>stats</td><td><i><a href='#statsOptions'>options</a></i></td><td>Statistical data.</td><td><i>readOnly</i></td></tr>
<tr><td>startTime</td><td><i>TIME_T</i></td><td>Time of websocket start.</td><td><i>readOnly</i></td></tr>
<tr><td>includeFile</td><td><i>STRKEY</i></td><td>Default file when no extension given (include.shtml).</td><td><i></i></td></tr>
<tr><td>urlPrefix</td><td><i>STRKEY</i></td><td>Prefix in url to strip from path; for reverse proxy.</td><td><i></i></td></tr>
<tr><td>urlRedirect</td><td><i>STRKEY</i></td><td>Redirect when no url or / is given. Must match urlPrefix, if given.</td><td><i></i></td></tr>
<tr><td>use_ssl</td><td><i>BOOL</i></td><td>Use https (for client).</td><td><i>initOnly</i></td></tr>
<tr><td>useridPass</td><td><i>STRKEY</i></td><td>The USERID:PASSWORD to use for basic authentication.</td><td><i></i></td></tr>