61 |
62 | struct timeval {
63 | long tv_sec;
64 | long tv_usec;
65 | };
66 |
67 | int gettimeofday(struct timeval *tv, void *unused);
68 |
69 | #define HAVE_OPENDIR
70 | struct dirent {
71 | char *d_name;
72 | };
73 |
74 | typedef struct DIR {
75 | long handle; /* -1 for failed rewind */
76 | struct _finddata_t info;
77 | struct dirent result; /* d_name null iff first time */
78 | char *name; /* null-terminated char string */
79 | } DIR;
80 |
81 | DIR *opendir(const char *name);
82 | int closedir(DIR *dir);
83 | struct dirent *readdir(DIR *dir);
84 | #endif /* _MSC_VER */
85 |
86 | #endif
87 |
88 | #endif /* WIN32 */
89 |
--------------------------------------------------------------------------------
/tools/geany/filetypes.javascript:
--------------------------------------------------------------------------------
1 | # For complete documentation of this file, please see Geany's main documentation
2 | [styling]
3 | # foreground;background;bold;italic
4 | default=default
5 | comment=comment
6 | commentline=comment
7 | commentdoc=commentdoc
8 | number=number
9 | word=keyword
10 | word2=keyword2
11 | string=string
12 | character=string
13 | uuid=extra
14 | preprocessor=preprocessor
15 | operator=operator
16 | identifier=default
17 | stringeol=stringeol
18 | # @"verbatim"
19 | verbatim=extra
20 | # (/regex/)
21 | regex=extra
22 | commentlinedoc=commentdoc,bold
23 | commentdockeyword=commentdoc,bold,italic
24 | commentdockeyworderror=commentdoc
25 | globalclass=type
26 |
27 | [keywords]
28 | # all items must be in one line
29 | primary=break case catch const continue default delete do each else false finally for function get if in Infinity instanceof let NaN new null return set switch this throw true try typeof undefined var void while with yield sys zvfs console info file puts source signal setTimeout setInterval clearInterval exit load assert quote sprintf
30 |
31 | secondary=Array Boolean Date Function Math Number Object String RegExp EvalError Error RangeError ReferenceError SyntaxError TypeError URIError prototype decodeURI decodeURIComponent encodeURI encodeURIComponent eval isFinite isNaN parseFloat parseInt Sqlite Websocket JSON Interp File
32 |
33 | [settings]
34 | # default extension used when saving files
35 | extension=js
36 |
37 | # the following characters are these which a "word" can contains, see documentation
38 | #wordchars=_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
39 |
40 | # single comments, like # in this file
41 | comment_single=//
42 | # multiline comments
43 | comment_open=/*
44 | comment_close=*/
45 |
46 | # set to false if a comment character/string should start at column 0 of a line, true uses any
47 | # indentation of the line, e.g. setting to true causes the following on pressing CTRL+d
48 | #command_example();
49 | # setting to false would generate this
50 | # command_example();
51 | # This setting works only for single line comments
52 | comment_use_indent=true
53 |
54 | # context action command (please see Geany's main documentation for details)
55 | context_action_cmd=
56 |
57 | [indentation]
58 | #width=4
59 | # 0 is spaces, 1 is tabs, 2 is tab & spaces
60 | #type=1
61 |
62 | [build_settings]
63 | # %f will be replaced by the complete filename
64 | # %e will be replaced by the filename without extension
65 | # (use only one of it at one time)
66 | compiler=
67 | run=
68 |
69 |
70 |
--------------------------------------------------------------------------------
/tests/block.js:
--------------------------------------------------------------------------------
1 | /*
2 | =!EXPECTSTART!=
3 | 2 7 6
4 | 9 5 1
5 | 4 3 8
6 | --------
7 | 2 9 4
8 | 7 5 3
9 | 6 1 8
10 | --------
11 | 4 3 8
12 | 9 5 1
13 | 2 7 6
14 | --------
15 | 4 9 2
16 | 3 5 7
17 | 8 1 6
18 | --------
19 | 6 1 8
20 | 7 5 3
21 | 2 9 4
22 | --------
23 | 6 7 2
24 | 1 5 9
25 | 8 3 4
26 | --------
27 | 8 1 6
28 | 3 5 7
29 | 4 9 2
30 | --------
31 | 8 3 4
32 | 1 5 9
33 | 6 7 2
34 | --------
35 | =!EXPECTEND!=
36 | */
37 |
38 | for (a = 1; a < 10; ++a) {
39 | for (b = 1; b < 10; ++b) {
40 | if (b == a) continue;
41 | for (c = 1; c < 10; ++c) {
42 | if (c == a || c == b) continue;
43 | for (d = 1; d < 10; ++d) {
44 | if (d == a || d == b || d == c) continue;
45 | for (e = 1; e < 10; ++e) {
46 | if (e == a || e == b || e == c || e == d) continue;
47 | for (f = 1; f < 10; ++f) {
48 | if (f == a || f == b || f == c || f == d || f == e) continue;
49 | for (g = 1; g < 10; ++g) {
50 | if (g == a || g == b || g == c || g == d || g == e || g == f) continue;
51 | for (h = 1; h < 10; ++h) {
52 | if (h == a || h == b || h == c || h == d || h == e || h == f || h == g) continue;
53 | for (i = 1; i < 10; ++i) {
54 | if (i == a || i == b || i == c || i == d || i == e || i == f || i == g || i == h) continue;
55 |
56 | if (a + b + c == 15 &&
57 | d + e + f == 15 &&
58 | g + h + i == 15 &&
59 | a + d + g == 15 &&
60 | b + e + h == 15 &&
61 | c + f + i == 15 &&
62 | a + e + i == 15 &&
63 | c + e + g == 15) {
64 | puts(a + " " + b + " " + c);
65 | puts(d + " " + e + " " + f);
66 | puts(g + " " + h + " " + i);
67 | puts("--------");
68 | }
69 | }
70 | }
71 | }
72 | }
73 | }
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/www/c-json.wiki:
--------------------------------------------------------------------------------
1 | C-API: JSON
2 |
3 | Description
4 |
5 | The JSON C API is provided by just two extern functions, whose use should be fairly intuitive.
6 |
7 |
8 | enum { JSI_JSON_STRICT=1, JSI_JSON_STRKEYS=2 }; /* flags */
9 |
10 | extern int Jsi_JSONParse(Jsi_Interp *interp, const char *js, Jsi_Value *ret, int flags);
11 | extern int Jsi_JSONParseFmt(Jsi_Interp *interp, Jsi_Value *ret, const char *fmt, ...);
12 |
13 |
14 | The parser itself is highly efficient. It uses a single
15 | array of tokens for output so that for small JSON strings
16 | no memory is allocated during the parse.
17 | When memory does get allocated, it is only to increase the size of the token array.
18 |
19 |
20 | Simplifying C with JSON
21 |
22 | JSON can be enlisted to reduce C-code complexity, particularly when writing commands
23 | that return objects and/or arrays.
24 | While the wisdom of using JSON this way may seem counter-intuitive,
25 | the JSON parser handles this quite efficiently.
26 |
27 | For example, suppose we want to create an object with a couple of values:
28 |
29 |
30 | Jsi_Obj *nobj = Jsi_ObjectNew(interp);
31 | Jsi_ValueMakeObject(interp, ret, nobj);
32 | Jsi_ObjInsertFromValue( interp, nobj, Jsi_ValueNewStringKey(interp, "file"),
33 | Jsi_ValueNewStringKey(interp, file));
34 | Jsi_ObjInsertFromValue( interp, nobj, Jsi_ValueNewStringKey(interp, "line"),
35 | Jsi_ValueNewNumber(interp, line));
36 |
37 |
38 | Using a JSON string parse, this can be simplified to:
39 |
40 |
41 | sprintf(buf, "{file:\"%s\", line:%d}", file, line);
42 | return Jsi_JSONParse(interp, buf, ret, 0);
43 |
44 |
45 | The more deeply nested the structure, the greater the code simplification, eg:
46 |
47 |
48 | Jsi_JSONParseFmt(interp, ret, buf, "{ a: [ {x:%d, y:%d}, {x:%d, y:[%d,%d,%d]}] }",a,b,c,d,e,f);
49 |
50 |
51 | Note: [./js-json.wiki#scan|permissive] mode is the default. So there is
52 | no need to quote property names which in C rapidly becomes tedious:
53 |
54 |
55 | "{\"os\":\"%s\", \"platform\":\"%s\", \"hasThreads\":%s, \"pointerSize\":%d, "
56 |
57 |
58 | Note: the above trick works only for cases where data does not contain
59 | special JSON characters.
60 |
61 | Sub-Interps
62 |
63 | Any data sent between sub-[./js-interp.wiki|interps] will first be converted to/from JSON.
64 | This because all data objects are private to an interp.
65 |
66 |
--------------------------------------------------------------------------------
/www/usingjsi.wiki:
--------------------------------------------------------------------------------
1 | Using Jsi
2 |
3 | The easiest way to get play around with Jsi is interactively. eg. On Ubuntu:
4 |
5 |
6 | ./jsish
7 | # var a = [1,2,3];
8 | # for (var i in a) { puts(a[i]); }
9 | 1
10 | 2
11 | 3
12 | ...
13 |
14 |
15 | Or, you can run a script with arguments:
16 | jsish prog.js arg1 arg2 ...
17 | Or evaluate javascript from the command line with -e:
18 |
19 |
20 | jsish -e 'var i = 0; while (i++<10) puts(i);'
21 |
22 |
23 | Command Options
24 |
25 | Various commands in Jsi can take an options object containing properties to parametrize behaviour. For example:
26 |
27 |
28 | var db = new Sqlite('/tmp/testsql.db',{maxStmts:1000, readonly:true});
29 | db.conf( {debug:1} );
30 | puts( db.conf() );
31 |
32 |
33 | In the case of object commands, a conf() method provides access to options after creation.
34 | Introspection
35 |
36 | There are several levels of introspection built-in to Jsi. The conf() method above is one example. Another is apparent upon and invalid method invocation, eg:
37 |
38 |
39 | # info.xxx()
40 | error: 'info', sub-commands are: cmds data error event executable funcs interp
41 | keywords named platform revisions script vars version. (at or near "xxx")
42 |
43 |
44 | However, the collection of info methods provide the most important introspection:
45 |
46 |
47 | # info.cmds()
48 | [ "Array", "Boolean", "File", "Function", "Interp", "JSON", "Math", "Number",
49 | "Object", "RegExp", "Sqlite", "String", "Websocket", "assert", "clearInterval",
50 | "console", "decodeURI", "encodeURI", "exit", "file", "include", "info",
51 | "isFinite", "isNaN", "load", "parseFloat", "parseInt", "puts", "quote",
52 | "setInterval", "setTimeout", "signal", "sprintf", "sys", "zvfs" ]
53 |
54 |
55 | Doing More
56 |
57 | All built-in Jsi commands (as well as their options) are documented in the Reference.
58 |
59 | Executable Scripts
60 |
61 | To make a script executable (under unix) the first line of a Jsi script should start with #!, eg:
62 |
63 |
64 | cat > myargs <
73 |
74 | rlwrap
75 |
76 | If you are running the statically compiled Linux version,
77 | you can use rlwrap to provide command-line editing:
78 |
79 |
80 | rlwrap ./jsish
81 |
82 |
83 | Limitations
84 |
85 | A return is not supported within a try/catch.
86 |
87 |
--------------------------------------------------------------------------------
/www/js-files.wiki:
--------------------------------------------------------------------------------
1 | Files
2 | There are 2 ways to access files in JSI:
3 | File object for IO to a single file, and
4 | file.* commands for general file access.
5 |
6 | new File
7 | A File object can be created for reading and/or writing individual files.
8 | Generally an object is instantiated to open the file and then read/write operations are performed.
9 |
10 |
11 | var f = new File('tests/filetest.txt');
12 | if (f) {
13 | while((n = f.gets())!=undefined) {
14 | puts(n);
15 | }
16 | } else console.log('Can not open tests/filetest.txt');
17 |
18 |
19 | File
20 |
21 | Synopsis: new File(file,?mode?)
22 | Commands for accessing File objects.
23 | Methods
24 |
25 | The following methods are available in "File":
26 |
27 |
28 | | Method | Description |
29 | | close() | close the file |
30 | | eof() | Return true if read to end-of-file |
31 | | filename() | Get file name |
32 | | gets() | Get one line of input |
33 | | mode() | Get file mode used with open |
34 | | open(file,?mode?) | Open the file (after close) |
35 | | puts(str) | Write one line of output |
36 | | read() | Read entire file into object |
37 |
38 |
39 | file.*
40 |
41 | The file sub-methods are used for accessing various attributes and information on files where just basic IO is not necessarily the goal.
42 |
43 |
44 | file.mkdir('XX1');
45 | file.mkdir('XX1/AA');
46 | file.mkdir('XX1/BB');
47 | file.rename('XX1/BB','XX1/CC.txt');
48 | puts(file.glob(null,'XX1').sort());
49 | puts(file.dirname('XX1/AA'));
50 | puts(file.rootname('XX1/CC.txt'));
51 | puts(file.tail('XX1/CC.txt'));
52 | puts(file.type('XX1/CC.txt'));
53 | puts(file.extension('XX1/CC.txt'));
54 | //puts(file.realpath('XX1/CC.txt'));
55 | puts(file.writable('XX1/CC.txt'));
56 | puts(file.readable('XX1/CC.txt'));
57 | puts(file.exists('XX1/CC.txt'));
58 | puts(file.isdir('XX1/CC.txt'));
59 | puts(file.isfile('XX1/CC.txt'));
60 | file.remove('XX1',true);
61 |
62 |
63 | Output is:
64 |
65 |
66 | [ "AA", "CC.txt" ]
67 | XX1
68 | XX1/CC
69 | CC.txt
70 | directory
71 | .txt
72 | true
73 | true
74 | true
75 | true
76 | false
77 | file
78 |
79 |
80 |
81 | File.glob
82 |
83 | The file glob method returns an array of matching files.
84 | With no arguments (or null) returns all files/directories in current directory.
85 | If first argument is a pattern (either a glob or regexp) just files are returned.
86 | If second argument is a string, it denotes the directory to search in.
87 | If second argument is a function, this function is called with each path.
88 | Otherwise second argument is a set of options.
89 |
90 |
91 | file.glob();
92 | file.glob("*.c");
93 | file.glob(/^jsi.*\.c$/);
94 | file.glob('*','tests');
95 | file.glob('*.js',{dir:'tests', recurse:true});
96 |
97 |
98 |
--------------------------------------------------------------------------------
/tests/expr.js:
--------------------------------------------------------------------------------
1 | /*
2 | =!EXPECTSTART!=
3 | undefined
4 | -1
5 | 0
6 | NaN
7 | -Infinity
8 | -1
9 | -123
10 | 0
11 | 3
12 | 3.6
13 | 1.212.3
14 | 5
15 | 2342true
16 | [object Object]12
17 | NaN
18 | NaNNaN
19 | NaN
20 | NaN
21 | ================
22 | 16
23 | 16777216
24 | 0
25 | -1
26 | ===============
27 | true
28 | undefined
29 | false
30 | true
31 | false
32 | false
33 | true
34 | true
35 | false
36 | false
37 | true
38 | true
39 | false
40 | true
41 | true
42 | true
43 | ===============
44 | true
45 | false
46 | false
47 | true
48 | false
49 | true
50 | true
51 | ===================
52 | false
53 | false
54 | false
55 | true
56 | true
57 | ============
58 | 31
59 | 106
60 | 1190
61 | ===============
62 | 16
63 | 12
64 | 3
65 | 12
66 | 0
67 | 0
68 | 0
69 | 1
70 | 1fock
71 | { a:124 }
72 | { a:120 }
73 | { a:30 }
74 | { a:120 }
75 | { a:0 }
76 | { a:0 }
77 | { a:0 }
78 | { a:1 }
79 | { a:"1fock" }
80 | =!EXPECTEND!=
81 | */
82 |
83 | //test void expr
84 | puts(void 1);
85 |
86 | //test - expr
87 | puts(-1);
88 | puts(-0);
89 | puts(-NaN);
90 | puts(-Infinity);
91 | puts(- true);
92 | puts(- "123" );
93 |
94 | //wrong: NaN, not 0
95 | puts(- {a:1});
96 |
97 | //test + expr
98 | puts(1 + 2);
99 | puts(1.3 + 2.3);
100 | puts(1.2 + "12.3");
101 | puts(4 + true);
102 | puts("2342" + true);
103 | puts({} + 12);
104 | puts(NaN + NaN);
105 | puts(NaN + "NaN");
106 | puts(Infinity - Infinity);
107 | puts(NaN + 3);
108 |
109 | puts("================");
110 | puts(1<<4);
111 | puts(1<<344.3);
112 | puts(2>>4);
113 | puts(-200000 >> -4);
114 |
115 | puts("===============");
116 | puts(1.0 < 2.3);
117 | puts(NaN < NaN);
118 | puts(Infinity < -Infinity);
119 | puts(Infinity > -Infinity);
120 | puts(10000.456 < 10000.456);
121 | puts(10000.456 > 10000.456);
122 | puts(10000.456 <= 10000.456);
123 | puts(10000.456 >= 10000.456);
124 | puts("10000.456" < "10000.456");
125 | puts("10000.456" > "10000.456");
126 | puts("10000.456" <= "10000.456");
127 | puts("10000.456" >= "10000.456");
128 | puts("a" > "b");
129 | puts("a" >= "a");
130 | puts("a" < "aa");
131 | puts("a" < "b");
132 | puts("===============");
133 | puts(1 == 1);
134 | puts(2 == 1);
135 | puts(NaN == NaN);
136 | puts("2" == 2);
137 | puts(true == null);
138 | puts("234234" == "234234");
139 | puts(true == 1);
140 |
141 | puts("===================");
142 | puts(1 === true);
143 | puts(1 === "1");
144 | puts(NaN === NaN);
145 | puts("abc" === "abc");
146 | puts(3.1415926 === 3.1415926);
147 |
148 | puts("============");
149 | puts(1 | 2 | 4 | 8 | 16);
150 | puts(123 & 234);
151 | puts(3456 ^ 2342);
152 |
153 | puts("===============");
154 | var a = 12;
155 | a += 4;
156 | puts(a);
157 | a -= 4;
158 | puts(a);
159 | a /= 4;
160 | puts(a);
161 | a *= 4;
162 | puts(a);
163 | a %= 4;
164 | puts(a);
165 | a <<= 4;
166 | puts(a);
167 | a >>= 3;
168 | puts(a);
169 | a += true;
170 | puts(a);
171 | a += "fock";
172 | puts(a);
173 |
174 | a = { a: 120 };
175 | a.a += 4;
176 | puts(a);
177 | a.a -= 4;
178 | puts(a);
179 | a.a /= 4;
180 | puts(a);
181 | a.a *= 4;
182 | puts(a);
183 | a.a %= 4;
184 | puts(a);
185 | a.a <<= 4;
186 | puts(a);
187 | a.a >>= 3;
188 | puts(a);
189 | a.a += true;
190 | puts(a);
191 | a.a += "fock";
192 | puts(a);
193 |
--------------------------------------------------------------------------------
/.depend:
--------------------------------------------------------------------------------
1 | jsiLexer.o: jsiLexer.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
2 | jsiLexer.h
3 | jsiFunc.o: jsiFunc.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
4 | jsiLexer.h
5 | jsiValue.o: jsiValue.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
6 | jsiLexer.h
7 | jsiRegexp.o: jsiRegexp.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
8 | jsiLexer.h
9 | jsiPstate.o: jsiPstate.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
10 | jsiLexer.h
11 | jsiInterp.o: jsiInterp.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
12 | jsiLexer.h
13 | jsiUtils.o: jsiUtils.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
14 | jsiLexer.h
15 | jsiProto.o: jsiProto.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
16 | jsiLexer.h
17 | jsiFilesys.o: jsiFilesys.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
18 | jsiLexer.h
19 | jsiChar.o: jsiChar.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
20 | jsiLexer.h
21 | jsiString.o: jsiString.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
22 | jsiLexer.h
23 | jsiBool.o: jsiBool.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
24 | jsiLexer.h
25 | jsiNumber.o: jsiNumber.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
26 | jsiLexer.h
27 | jsiArray.o: jsiArray.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
28 | jsiLexer.h
29 | jsiLoad.o: jsiLoad.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
30 | jsiLexer.h
31 | jsiHash.o: jsiHash.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
32 | jsiLexer.h
33 | jsiOptions.o: jsiOptions.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
34 | jsiLexer.h
35 | jsiStubs.o: jsiStubs.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
36 | jsiLexer.h jsiStubs.h
37 | jsiFormat.o: jsiFormat.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
38 | jsiLexer.h jsiUtf8.h
39 | jsiExec.o: jsiExec.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
40 | jsiLexer.h
41 | jsiJSON.o: jsiJSON.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
42 | jsiLexer.h jsmn.h
43 | jsiTclUtil.o: jsiTclUtil.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
44 | jsiLexer.h jsiUtf8.h
45 | jsiCmds.o: jsiCmds.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
46 | jsiLexer.h
47 | jsiFileCmds.o: jsiFileCmds.c jsiInt.h jsi.h jsiPstate.h parser.h \
48 | jsiCode.h jsiLexer.h
49 | jsiObj.o: jsiObj.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
50 | jsiLexer.h
51 | jsiSignal.o: jsiSignal.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
52 | jsiLexer.h
53 | jsiTree.o: jsiTree.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
54 | jsiLexer.h
55 | jsiMD5.o: jsiMD5.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
56 | jsiLexer.h
57 | jsiDString.o: jsiDString.c jsi.h
58 | jsiMath.o: jsiMath.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
59 | jsiLexer.h
60 | jsmn.o: jsmn.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h jsiLexer.h \
61 | jsmn.h
62 | jsiZvfs.o: jsiZvfs.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
63 | jsiLexer.h
64 | jsiUtf8.o: jsiUtf8.c jsiUtf8.h jsiInt.h jsi.h jsiPstate.h parser.h \
65 | jsiCode.h jsiLexer.h
66 | jsiUserObj.o: jsiUserObj.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
67 | jsiLexer.h
68 | parser.o: parser.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
69 | jsiLexer.h jsiCode.c
70 | jsiWebsocket.o: jsiWebsocket.c jsi.h
71 | jsiSqlite.o: jsiSqlite.c jsi.h
72 | jsiEval.o: jsiEval.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \
73 | jsiLexer.h
74 |
--------------------------------------------------------------------------------
/jsmn.h:
--------------------------------------------------------------------------------
1 | #ifndef __JSMN_H__
2 | #define __JSMN_H__
3 |
4 | #define JSMN_STATIC_DEFAULT 100
5 |
6 | #define JSMN_DECLARE(p,token) \
7 | jsmn_parser p = {0}; \
8 | jsmntok_t tokens[JSMN_STATIC_DEFAULT]; \
9 | jsmn_init(&p, tokens, JSMN_STATIC_DEFAULT)
10 |
11 | /**
12 | * JSON type identifier. Basic types are:
13 | * o Object
14 | * o Array
15 | * o String
16 | * o Other primitive: number, boolean (true/false) or null
17 | */
18 | typedef enum {
19 | JSMN_PRIMITIVE = 0,
20 | JSMN_OBJECT = 1,
21 | JSMN_ARRAY = 2,
22 | JSMN_STRING = 3
23 | } jsmntype_t;
24 |
25 | typedef enum {
26 | /* Not enough tokens were provided */
27 | JSMN_ERROR_NOMEM = -1,
28 | /* Invalid character inside JSON string */
29 | JSMN_ERROR_INVAL = -2,
30 | /* The string is not a full JSON packet, more bytes expected */
31 | JSMN_ERROR_PART = -3,
32 | /* Everything was fine */
33 | JSMN_SUCCESS = 0
34 | } jsmnerr_t;
35 |
36 | /**
37 | * JSON token description.
38 | * @param type type (object, array, string etc.)
39 | * @param start start position in JSON data string
40 | * @param end end position in JSON data string
41 | */
42 | typedef struct {
43 | jsmntype_t type;
44 | int start;
45 | int end;
46 | int size;
47 | #ifdef JSMN_PARENT_LINKS
48 | int parent;
49 | #endif
50 | } jsmntok_t;
51 |
52 | /**
53 | * JSON parser. Contains an array of token blocks available. Also stores
54 | * the string being parsed now and current position in that string
55 | */
56 | typedef struct {
57 | unsigned int pos; /* offset in the JSON string */
58 | int toknext; /* next token to allocate */
59 | int toksuper; /* superior token node, e.g parent object or array */
60 | jsmntok_t *tokens, *static_tokens;
61 | unsigned int num_tokens;
62 | int no_malloc; /* Disallow parser to dynamically grow tokens array. */
63 | unsigned char strict; /* Strict parsing. */
64 | unsigned char flags;
65 | const char *errStr;
66 | } jsmn_parser;
67 |
68 | /**
69 | * Setup JSON parser with a static array of tokens and size.
70 | * If static_tokens is NULL, malloc array of size num_tokens (0 means use default of 100).
71 | */
72 | void jsmn_init(jsmn_parser *parser, jsmntok_t *static_tokens, unsigned int num_tokens);
73 |
74 | /**
75 | * Reset parser before another call to parse()
76 | */
77 | void jsmn_reset(jsmn_parser *parser);
78 |
79 | /**
80 | * Free allocated memory after parse.
81 | */
82 | void jsmn_free(jsmn_parser *parser);
83 |
84 | /**
85 | * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
86 | * a single JSON object. Called after jsmn_init().
87 | */
88 | jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js);
89 |
90 | /**
91 | * Helper functions.
92 | */
93 | jsmntok_t *jsmn_token(jsmn_parser *parser, unsigned int index);
94 | jsmntype_t jsmn_type(jsmn_parser *parser, unsigned int index);
95 | int jsmn_toklen(jsmn_parser *parser, unsigned int index);
96 | const char* jsmn_tokstr(jsmn_parser *parser, const char *js, unsigned int index, int *len);
97 | const char* jsmn_typename(int type);
98 | const char* jsmn_errname(int code);
99 | void jsmn_dump(jsmn_parser *parser, const char *js);
100 |
101 | #endif /* __JSMN_H_ */
102 |
--------------------------------------------------------------------------------
/www/c-extensions.wiki:
--------------------------------------------------------------------------------
1 | C-API: Extensions
2 |
3 | Jsi can be extended in several ways.
4 | Embedding C
5 |
6 |
7 | make USERSRC=demo
8 |
9 |
10 | Dynamic Extensions
11 |
12 | If libjsi.so is being used on your system, you can load shared libraries into Jsi using the load() command.
13 | Or they can be statically compiled in. Basically, all that is required is defining a C function
14 | Jsi_InitXXXX to handle the initialization on load.
15 |
16 | Following is a brief but complete shared library example for Linux.
17 | Given the file user/demo.c:
18 |
19 |
20 | #include "jsi.h"
21 |
22 | JSI_EXTENSION_INI
23 |
24 | Jsi_CmdProcDecl(DemoCmd) {
25 | int i, n = Jsi_ValueGetLength(interp, args);
26 | printf("demo called with %d args\n", n);
27 | for (i=0; i
44 |
45 | We compile and load it thus:
46 |
47 |
48 | cc -g -Wall -DJSI_USE_STUBS -I. -shared -fpic user/demo.c -o user/demo.so
49 | ./jsish
50 | load('user/demo.so');
51 |
52 |
53 | Static API Access
54 |
55 | Usually an extension would want to access the Jsi API to create commands, etc.
56 | Here is the sample dyn.c extension included with the distribution:
57 |
58 |
59 | #include "jsi.h"
60 |
61 | Jsi_CmdProcDecl(DynCmd) {
62 | puts("dyn called");
63 | return JSI_OK;
64 | }
65 |
66 | int Jsi_Initdyn(Jsi_Interp *interp) {
67 | puts("LOADED DYN");
68 | Jsi_CommandCreate(interp, "dyn", DynCmd, NULL);
69 | return JSI_OK;
70 | }
71 |
72 | To build this into the application, just type "make dyn".
73 |
74 | Dynamic API Access
75 |
76 | To load the above dynamically requires using, a shared library version of Jsi (jsish),
77 | and the -ljsi option be added to the link line. Essentially, this requires installing
78 | the shared version of Jsi onto your system.
79 | Builtins
80 |
81 | JSI comes with the following builtin extensions.
82 |
83 | # Sqlite A small database engine
84 | # WebSockets Direct communication with web browsers
85 | # Zvfs A Zip virtual file system
86 |
87 | Although JSI can be compiled without these extensions, they generally come already compiled-in so
88 | that web application development is ready to go
89 |
90 |
91 | $ time ./jsish tests/prime.js
92 | Have native helper: false
93 | 1999 2999 4999 8999
94 |
95 | real 0m0.384s
96 | user 0m0.376s
97 | sys 0m0.004s
98 |
99 | $ make prime.so
100 | cc -g -Wall -I. -shared -fpic user/prime.c -o prime.so
101 | $ time ./jsish tests/prime.js
102 | Have native helper: true
103 | 1999 2999 4999 8999
104 |
105 | real 0m0.169s
106 | user 0m0.164s
107 | sys 0m0.004s
108 |
109 |
110 |
--------------------------------------------------------------------------------
/www/license.wiki:
--------------------------------------------------------------------------------
1 | License
2 |
3 | There are broadly speaking 2 licenses to be aware of.
4 | Jsi itself is covered by the following MIT license:
5 |
6 |
7 | The MIT License (MIT)
8 |
9 | Copyright (c) 2013 Peter MacDonald
10 |
11 | Permission is hereby granted, free of charge, to any person obtaining a copy
12 | of this software and associated documentation files (the "Software"), to deal
13 | in the Software without restriction, including without limitation the rights
14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | copies of the Software, and to permit persons to whom the Software is
16 | furnished to do so, subject to the following conditions:
17 |
18 | The above copyright notice and this permission notice shall be included in
19 | all copies or substantial portions of the Software.
20 |
21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | THE SOFTWARE.
28 |
29 |
30 | Note: Jsish is based in part on the work of the libwebsockets project
31 | (http://libwebsockets.org).
32 |
33 | Libwebsockets
34 |
35 | If you are linking in websocket support (the default) the following license
36 | also applies:
37 |
38 |
39 | Jsi source bundles a version of Libwebockets, which is covered by LGPL, with an additional clause allowing static linking. Here is the preamble:
40 | Libwebsockets and included programs are provided under the terms of the GNU
41 | Library General Public License (LGPL) 2.1, with the following exceptions:
42 |
43 | 1) Static linking of programs with the libwebsockets library does not
44 | constitute a derivative work and does not require the author to provide
45 | source code for the program, use the shared libwebsockets libraries, or
46 | link their program against a user-supplied version of libwebsockets.
47 |
48 | If you link the program to a modified version of libwebsockets, then the
49 | changes to libwebsockets must be provided under the terms of the LGPL in
50 | sections 1, 2, and 4.
51 |
52 | 2) You do not have to provide a copy of the libwebsockets license with
53 | programs that are linked to the libwebsockets library, nor do you have to
54 | identify the libwebsockets license in your program or documentation as
55 | required by section 6 of the LGPL.
56 |
57 | However, programs must still identify their use of libwebsockets. The
58 | following example statement can be included in user documentation to
59 | satisfy this requirement:
60 |
61 | "[program] is based in part on the work of the libwebsockets project
62 | (http://libwebsockets.org)"
63 |
64 | GNU LESSER GENERAL PUBLIC LICENSE
65 | Version 2.1, February 1999
66 | ...
67 |
68 |
69 | Note this seems to to say that as long as libwebsockets is not modified,
70 | all that is required is an acknowledgement in your user documentation.
71 |
72 | Others
73 |
74 | Other software including sqlite, miniz, jsmn, etc are either public domain, BSD or MIT compatible.
75 |
76 |
77 |
--------------------------------------------------------------------------------
/tools/testjs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Driver for jsi test programs.
3 | # Runs *.js files in tests/ and compares output to EXPECTSTART/END in file comment.
4 | RUNVALG=0
5 | QUIET=0
6 | LOUD=0
7 | JSISH=./jsish
8 | INPSTR="input\ntest\nabc@gmail.com\n"
9 | USESTR="Usage: testjs.sh [-loud|-quiet|-memcheck] "
10 |
11 | while [ $# -gt 1 ]; do
12 | case $1 in
13 | "-memcheck") RUNVALG=1; shift;;
14 | "-loud") LOUD=1; shift;;
15 | "-quiet") QUIET=1; shift;;
16 | "-input") INPSTR=$2; shift; shift;;
17 | -*)
18 | if [ ! -e "$1" ]; then
19 | echo "Unknown option: $1."
20 | echo $USESTR
21 | exit 1
22 | fi
23 | break;;
24 | *)
25 | break;;
26 | esac
27 | done
28 |
29 | if [ $# != 1 ]; then
30 | echo "Too many args at: $*."
31 | echo $USESTR
32 | exit 1
33 | fi
34 | if [ ! -e "$1" ]; then
35 | echo "File or directory expected: $1."
36 | echo $USESTR
37 | exit 1
38 | fi
39 |
40 | function test1file()
41 | {
42 | file=$1
43 | awk '{
44 | if ($0 ~ /^=\!EXPECTSTART\!=$/) start = 1;
45 | else if ($0 ~ /=\!EXPECTEND\!=/) start = 0;
46 | else if (start) print
47 | }' $file >/tmp/ss_expected
48 |
49 | echo -e $INPSTR | "$JSISH" $file g 2 3 2>&1 >/tmp/ss_result
50 | ORC=$?
51 | if [ $ORC != 0 ]; then
52 | echo "[ BADRC ] $file: RC=$ORC"
53 | return;
54 | fi
55 |
56 | if ! diff /tmp/ss_expected /tmp/ss_result >/dev/null; then
57 | DATA=`cat /tmp/ss_expected`
58 | if [ "$DATA" == "" ]; then CM='*'; else CM=' '; fi
59 | echo -e "[ FAILED ] $CM $file"
60 | if [ $LOUD != 0 ]; then
61 | echo "============expected============="
62 | cat /tmp/ss_expected
63 | echo "------------result---------------"
64 | cat /tmp/ss_result
65 | echo "-------------diff----------------"
66 | diff -u /tmp/ss_expected /tmp/ss_result | tail -n +3
67 | echo "==============end==============="
68 | return
69 | fi
70 | if [ $QUIET != 1 ]; then
71 | echo "-------------diff----------------"
72 | diff -u /tmp/ss_expected /tmp/ss_result | tail -n +3
73 | return
74 | fi
75 | else
76 | echo -e "[ OK ] $file"
77 | fi
78 | }
79 |
80 | function testdir()
81 | {
82 | allfiles=`find "$1" -maxdepth 1 -name "*.js" | sort -r`
83 | for file in $allfiles; do
84 | echo "Executing $file"
85 | test1file $file $2
86 | done
87 | }
88 |
89 | function runvalgind()
90 | {
91 | allfiles=`find "$1" -name "*.js"`
92 | rm -f valgrind.report.txt
93 |
94 | for file in $allfiles; do
95 | echo -n "Executing $file"
96 | echo "**************** $file ******************" >>valgrind.report.txt
97 | f=$(basename $file)
98 | if [ "$f" != "block.js" -a "$f" != "block2.js" ]; then
99 | echo -e "input\ntest\npmacdona@gmail.com\n" | valgrind "$JSISH" $file 1 2 3 >>valgrind.report.txt 2>&1
100 | fi
101 | echo -e "[ DONE ] $file"
102 | done
103 | echo "All done, report: valgrind.report.txt"
104 | }
105 |
106 | if [ "$2" == "-m" ]; then
107 | runvalgind "$1"
108 | return
109 | fi
110 | if [ -d "$1" ]; then
111 | testdir "$1" "$2"
112 | else
113 | test1file "$1" "$2"
114 | fi
115 |
--------------------------------------------------------------------------------
/jsiCodeInt.h:
--------------------------------------------------------------------------------
1 | static OpCodes *codes_new(int size);
2 | static OpCodes *codes_join(OpCodes *a, OpCodes *b);
3 | static OpCodes *codes_join3(OpCodes *a, OpCodes *b, OpCodes *c);
4 | static OpCodes *codes_join4(OpCodes *a, OpCodes *b, OpCodes *c, OpCodes *d);
5 | static OpCodes *code_push_undef();
6 | static OpCodes *code_push_bool(int v);
7 | static OpCodes *code_push_num(Jsi_Number *v);
8 | static OpCodes *code_push_string(jsi_Pstate *p, jsi_Pline *line, const char *str);
9 | static OpCodes *code_push_index(jsi_Pstate *p, jsi_Pline *line, char *varname);
10 | static OpCodes *code_push_this(jsi_Pstate *p, jsi_Pline *line);
11 | static OpCodes *code_push_top();
12 | static OpCodes *code_push_top2() ;
13 | static OpCodes *code_unref() ;
14 | static OpCodes *code_push_args() ;
15 | static OpCodes *code_push_func(jsi_Pstate *p, jsi_Pline *line, struct Jsi_Func *fun) ;
16 | static OpCodes *code_push_regex(jsi_Pstate *p, jsi_Pline *line, Jsi_Regex *reg) ;
17 | static OpCodes *code_local(jsi_Pstate *p, jsi_Pline *line, const char *varname) ;
18 | static OpCodes *code_nop() ;
19 | static OpCodes *code_neg() ;
20 | static OpCodes *code_pos() ;
21 | static OpCodes *code_bnot() ;
22 | static OpCodes *code_not() ;
23 | static OpCodes *code_mul() ;
24 | static OpCodes *code_div() ;
25 | static OpCodes *code_mod() ;
26 | static OpCodes *code_add() ;
27 | static OpCodes *code_sub() ;
28 | static OpCodes *code_in() ;
29 | static OpCodes *code_less() ;
30 | static OpCodes *code_greater() ;
31 | static OpCodes *code_lessequ() ;
32 | static OpCodes *code_greaterequ() ;
33 | static OpCodes *code_equal() ;
34 | static OpCodes *code_notequal() ;
35 | static OpCodes *code_eequ() ;
36 | static OpCodes *code_nneq() ;
37 | static OpCodes *code_band() ;
38 | static OpCodes *code_bor() ;
39 | static OpCodes *code_bxor() ;
40 | static OpCodes *code_shf(int right) ;
41 | static OpCodes *code_instanceof() ;
42 | static OpCodes *code_assign(jsi_Pstate *p, jsi_Pline *line, int h) ;
43 | static OpCodes *code_subscript(jsi_Pstate *p, jsi_Pline *line, int right_val) ;
44 | static OpCodes *code_inc(jsi_Pstate *p, jsi_Pline *line, int e) ;
45 | static OpCodes *code_dec(jsi_Pstate *p, jsi_Pline *line, int e) ;
46 | static OpCodes *code_typeof(jsi_Pstate *p, jsi_Pline *line, int e) ;
47 | static OpCodes *code_fcall(jsi_Pstate *p, jsi_Pline *line, int argc) ;
48 | static OpCodes *code_newfcall(jsi_Pstate *p, jsi_Pline *line, int argc) ;
49 | static OpCodes *code_ret(int n) ;
50 | static OpCodes *code_delete(int n) ;
51 | static OpCodes *code_chthis(int n) ;
52 | static OpCodes *code_pop(int n) ;
53 | static OpCodes *code_jfalse(int off) ;
54 | static OpCodes *code_jtrue(int off) ;
55 | static OpCodes *code_jfalse_np(int off) ;
56 | static OpCodes *code_jtrue_np(int off) ;
57 | static OpCodes *code_jmp(int off) ;
58 | static OpCodes *code_object(jsi_Pstate *p, jsi_Pline *line, int c) ;
59 | static OpCodes *code_array(jsi_Pstate *p, jsi_Pline *line, int c) ;
60 | static OpCodes *code_key() ;
61 | static OpCodes *code_next() ;
62 | static OpCodes *code_eval(jsi_Pstate *p, jsi_Pline *line, int argc) ;
63 | static OpCodes *code_stry(jsi_Pstate *p, jsi_Pline *line, int trylen, int catchlen, int finlen)
64 | static OpCodes *code_etry(jsi_Pstate *p, jsi_Pline *line) ;
65 | static OpCodes *code_scatch(jsi_Pstate *p, jsi_Pline *line, const char *var) ;
66 | static OpCodes *code_ecatch(jsi_Pstate *p, jsi_Pline *line) ;
67 | static OpCodes *code_sfinal(jsi_Pstate *p, jsi_Pline *line) ;
68 | static OpCodes *code_efinal(jsi_Pstate *p, jsi_Pline *line) ;
69 | static OpCodes *code_throw(jsi_Pstate *p, jsi_Pline *line) ;
70 | static OpCodes *code_with(jsi_Pstate *p, jsi_Pline *line, int withlen) ;
71 | static OpCodes *code_ewith(jsi_Pstate *p, jsi_Pline *line) ;
72 | static OpCodes *code_debug(jsi_Pstate *p, jsi_Pline *line) ;
73 | static OpCodes *code_reserved(jsi_Pstate *p, jsi_Pline *line, int type, char *id);
74 |
--------------------------------------------------------------------------------
/tests/block2.js:
--------------------------------------------------------------------------------
1 | /*
2 | =!EXPECTSTART!=
3 | 2 7 6
4 | 9 5 1
5 | 4 3 8
6 | --------
7 | 2 9 4
8 | 7 5 3
9 | 6 1 8
10 | --------
11 | 4 3 8
12 | 9 5 1
13 | 2 7 6
14 | --------
15 | 4 9 2
16 | 3 5 7
17 | 8 1 6
18 | --------
19 | 6 1 8
20 | 7 5 3
21 | 2 9 4
22 | --------
23 | 6 7 2
24 | 1 5 9
25 | 8 3 4
26 | --------
27 | 8 1 6
28 | 3 5 7
29 | 4 9 2
30 | --------
31 | 8 3 4
32 | 1 5 9
33 | 6 7 2
34 | --------
35 | =!EXPECTEND!=
36 | */
37 |
38 | for (a = 1; a < 10; ++a) {
39 | for (b = 1; b < 10; ++b) {
40 | if (b == a) continue;
41 | for (c = 1; c < 10; ++c) {
42 | if (c == a) continue;
43 | if (c == b) continue;
44 | for (d = 1; d < 10; ++d) {
45 | if (d == a) continue;
46 | if (d == b) continue;
47 | if (d == c) continue;
48 | for (e = 1; e < 10; ++e) {
49 | if (e == a) continue;
50 | if (e == b) continue;
51 | if (e == c) continue;
52 | if (e == d) continue;
53 | for (f = 1; f < 10; ++f) {
54 | if (f == a) continue;
55 | if (f == b) continue;
56 | if (f == c) continue;
57 | if (f == d) continue;
58 | if (f == e) continue;
59 | for (g = 1; g < 10; ++g) {
60 | if (g == a) continue;
61 | if (g == b) continue;
62 | if (g == c) continue;
63 | if (g == d) continue;
64 | if (g == e) continue;
65 | if (g == f) continue;
66 | for (h = 1; h < 10; ++h) {
67 | if (h == a) continue;
68 | if (h == b) continue;
69 | if (h == c) continue;
70 | if (h == d) continue;
71 | if (h == e) continue;
72 | if (h == f) continue;
73 | if (h == g) continue;
74 | for (i = 1; i < 10; ++i) {
75 | if (i == a) continue;
76 | if (i == b) continue;
77 | if (i == c) continue;
78 | if (i == d) continue;
79 | if (i == e) continue;
80 | if (i == f) continue;
81 | if (i == g) continue;
82 | if (i == h) continue;
83 |
84 | if (a + b + c != 15) continue;
85 | if (d + e + f != 15) continue;
86 | if (g + h + i != 15) continue;
87 | if (a + d + g != 15) continue;
88 | if (b + e + h != 15) continue;
89 | if (c + f + i != 15) continue;
90 | if (a + e + i != 15) continue;
91 | if (c + e + g != 15) continue;
92 |
93 | puts(a + " " + b + " " + c);
94 | puts(d + " " + e + " " + f);
95 | puts(g + " " + h + " " + i);
96 | puts("--------");
97 | }
98 | }
99 | }
100 | }
101 | }
102 | }
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/win/regex.h:
--------------------------------------------------------------------------------
1 | #ifdef __WIN32
2 | #ifndef JSIREGEXP_H
3 | #define JSIREGEXP_H
4 |
5 | #if defined(HAVE_REGCOMP) && !defined(JSI_REGEXP)
6 | /* Use POSIX regex */
7 | #include
8 |
9 | #else
10 |
11 | #include
12 |
13 | /*
14 | * Definitions etc. for regexp(3) routines.
15 | *
16 | * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
17 | * not the System V one.
18 | *
19 | * 11/04/02 (seiwald) - const-ing for string literals
20 | */
21 |
22 | typedef struct {
23 | int rm_so;
24 | int rm_eo;
25 | } regmatch_t;
26 |
27 | /*
28 | * The "internal use only" fields in regexp.h are present to pass info from
29 | * compile to execute that permits the execute phase to run lots faster on
30 | * simple cases. They are:
31 | *
32 | * regstart char that must begin a match; '\0' if none obvious
33 | * reganch is the match anchored (at beginning-of-line only)?
34 | * regmust string (pointer into program) that match must include, or NULL
35 | * regmlen length of regmust string
36 | *
37 | * Regstart and reganch permit very fast decisions on suitable starting points
38 | * for a match, cutting down the work a lot. Regmust permits fast rejection
39 | * of lines that cannot possibly match. The regmust tests are costly enough
40 | * that regcomp() supplies a regmust only if the r.e. contains something
41 | * potentially expensive (at present, the only such thing detected is * or +
42 | * at the start of the r.e., which can involve a lot of backup). Regmlen is
43 | * supplied because the test in regexec() needs it and regcomp() is computing
44 | * it anyway.
45 | */
46 |
47 | typedef struct regexp {
48 | /* -- public -- */
49 | int re_nsub; /* number of parenthesized subexpressions */
50 |
51 | /* -- private -- */
52 | int cflags; /* Flags used when compiling */
53 | int err; /* Any error which occurred during compile */
54 | int regstart; /* Internal use only. */
55 | int reganch; /* Internal use only. */
56 | int regmust; /* Internal use only. */
57 | int regmlen; /* Internal use only. */
58 | int *program; /* Allocated */
59 |
60 | /* working state - compile */
61 | const char *regparse; /* Input-scan pointer. */
62 | int p; /* Current output pos in program */
63 | int proglen; /* Allocated program size */
64 |
65 | /* working state - exec */
66 | int eflags; /* Flags used when executing */
67 | const char *start; /* Initial string pointer. */
68 | const char *reginput; /* Current input pointer. */
69 | const char *regbol; /* Beginning of input, for ^ check. */
70 |
71 | /* Input to regexec() */
72 | regmatch_t *pmatch; /* submatches will be stored here */
73 | int nmatch; /* size of pmatch[] */
74 | } regexp;
75 |
76 | typedef regexp regex_t;
77 |
78 | #define REG_EXTENDED 0
79 | #define REG_NEWLINE 1
80 | #define REG_ICASE 2
81 |
82 | #define REG_NOTBOL 16
83 |
84 | enum {
85 | REG_NOERROR, /* Success. */
86 | REG_NOMATCH, /* Didn't find a match (for regexec). */
87 | REG_BADPAT, /* >= REG_BADPAT is an error */
88 | REG_ERR_NULL_ARGUMENT,
89 | REG_ERR_UNKNOWN,
90 | REG_ERR_TOO_BIG,
91 | REG_ERR_NOMEM,
92 | REG_ERR_TOO_MANY_PAREN,
93 | REG_ERR_UNMATCHED_PAREN,
94 | REG_ERR_UNMATCHED_BRACES,
95 | REG_ERR_BAD_COUNT,
96 | REG_ERR_JUNK_ON_END,
97 | REG_ERR_OPERAND_COULD_BE_EMPTY,
98 | REG_ERR_NESTED_COUNT,
99 | REG_ERR_INTERNAL,
100 | REG_ERR_COUNT_FOLLOWS_NOTHING,
101 | REG_ERR_TRAILING_BACKSLASH,
102 | REG_ERR_CORRUPTED,
103 | REG_ERR_NULL_CHAR,
104 | REG_ERR_NUM
105 | };
106 |
107 | int regcomp(regex_t *preg, const char *regex, int cflags);
108 | int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
109 | size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
110 | void regfree(regex_t *preg);
111 |
112 | #endif
113 | #endif
114 | #endif
115 |
--------------------------------------------------------------------------------
/tools/mkstubs.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env jsish
2 | // Generate stubs file for shared lib loading.
3 | // Unfinished, but can be used to generate stubs for arbitrary libs.
4 | var opts = { prefix:'jsi', inFile:'', outFile:'' };
5 |
6 | //Parse command line args.
7 | var args = console.args;
8 | for (var i = 0; isig == \\\n';
83 | rc += ' JSI_STUBS_SIG?jsiStubsPtr->_Jsi_Stubs__initialize(interp, flags, "'+opts.prefix+'", \\\n';
84 | rc += ' '+opts.preu+'_VERSION, '+opts.preu+'_STUBS_MD5, '+opts.preu+'_STUBS_BLDFLAGS, sizeof(';
85 | rc += opts.pret+'_Stubs), (void**)&'+opts.prefix+'StubsPtr):JSI_ERROR)\n';
86 | rc += '#endif\n\n';
87 | rc += fstub;
88 | rc += 'extern '+opts.pret+'_Stubs* '+opts.prefix+'StubsPtr;\n\n';
89 | rc += '#define __'+opts.preu+'_STUBS_INIT__\\\n'+finit+' NULL\n\n';
90 | rc += '#ifdef JSI_USE_STUBS\n\n'+fdefs+'\n#endif\n\n#endif\n';
91 | file.write(opts.outFile, rc);
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/lib/zip.jsi:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env jsish
2 |
3 | // Utility for creating and managing zip files, especially when appended to a jsish executable-archive.
4 |
5 | function jsi_zip(args) {
6 |
7 | var rc = 0, iszip = 0;
8 | function usage(str) {
9 | console.log(str);
10 | console.log("usage: list file|truncate file|unzip file.zip ?dir?|zip file.zip dir|fuse file.zip|create ...");
11 | return 1;
12 | }
13 |
14 | if (!args || args.length < 2)
15 | return usage('missing args');
16 |
17 | var zdir, fname = args[1], dolib = 0;
18 | if (args[0] !== 'zip' && !file.exists(fname))
19 | return usage(fname+' does not exist');
20 |
21 | switch (args[0]) {
22 | case "truncate": // Truncate zip files off of executable.
23 | zvfs.truncate(fname);
24 | break;
25 |
26 | case "list": // List files in zip.
27 | fname = file.realpath(fname);
28 | if (fname === info.executable())
29 | zdir = '/zvfs';
30 | else
31 | zdir = zvfs.mount(fname);
32 | puts(file.glob('*', {dir:zdir,recurse:true}));
33 | break;
34 |
35 | case "zip": // Create zip file.
36 | if (argc < 3)
37 | return usage("too few arguments");
38 | else if (argc > 3)
39 | return usage("too many arguments");
40 | if (file.extension(fname) !== '.zip')
41 | return usage("must give a .zip file name");
42 | if (file.isfile(fname))
43 | file.remove(fname);
44 | iszip = 1;
45 |
46 | case "create": // Create standalone executable.
47 | zdir = args[2];
48 | if (!file.isdir(zdir))
49 | return usage("must give a directory to zip");
50 | var i = 0, zargs = [];
51 | zargs[i++] = file.realpath(fname);
52 | zargs[i++] = file.glob(zdir+'/*', {recurse:true});
53 | zargs[i++] = zdir;
54 | for (var n = 3; n
3 | #include
4 | #ifdef VALUE_DEBUG
5 | #include "jsiInt.h"
6 | #else
7 | #include "jsi.h"
8 | #endif
9 |
10 | static int deleted = 0, exitCode = 0;
11 | static int InterpDelete(Jsi_Interp *interp, void *ptr) {
12 | exitCode = (int)ptr;
13 | deleted = 1;
14 | return JSI_OK;
15 | }
16 |
17 | int main(int argc, char **argv)
18 | {
19 | int rc = JSI_OK, jsFound = 0;
20 | Jsi_Interp* interp = Jsi_InterpCreate(NULL, argc, argv, 0);
21 | Jsi_InterpOnDelete(interp, &InterpDelete);
22 |
23 | #ifndef NO_JAZ
24 | /* Mount zip at end of executable */
25 | Jsi_Value *v = Jsi_Executable(interp);
26 | const char *exeFile = Jsi_ValueString(interp, v, NULL);
27 | if (argc != 2 || Jsi_Strcmp(argv[1], "--nozvfs")) {
28 | rc = Jsi_ExecZip(interp, exeFile, JSI_ZVFS_DIR, &jsFound);
29 | if (rc >= 0) {
30 | if (!jsFound) {
31 | #if (!defined(JSI_OMIT_FILESYS)) && (!defined(JSI_OMIT_ZVFS))
32 | fprintf(stderr, "warning: no main.jsi or jsiIndex.jsi\n");
33 | #endif
34 | }
35 | if (deleted)
36 | exit(exitCode);
37 | else if (rc != JSI_OK) {
38 | fprintf(stderr, "Error\n");
39 | exit(1);
40 | }
41 | }
42 | }
43 | #endif
44 |
45 | #ifdef USER_EXTENSION
46 | extern int USER_EXTENSION(Jsi_Interp *interp);
47 | if (USER_EXTENSION (interp) != JSI_OK) {
48 | fprintf(stderr, "extension load failed");
49 | exit(1);
50 | }
51 | #endif
52 | Jsi_ShiftArgs(interp);
53 | if (argc == 1) {
54 | rc = Jsi_Interactive(interp, JSI_OUTPUT_QUOTE|JSI_OUTPUT_NEWLINES);
55 | } else {
56 | if (argc == 2 && (Jsi_Strcmp(argv[1], "--help")==0 || Jsi_Strcmp(argv[1], "-h" )==0)) {
57 | puts("usage: jsi ?--help | -e SCRIPT | FILE arg arg ...?");
58 | exit(0);
59 | }
60 | if (argc == 2 && (Jsi_Strcmp(argv[1], "--version")==0 || Jsi_Strcmp(argv[1], "-v" )==0)) {
61 | char str[200] = "\n";
62 | Jsi_Channel chan = Jsi_Open(interp, Jsi_ValueNewStringKey(interp, "/zvfs/lib/sourceid.txt"), "r");
63 | if (chan)
64 | Jsi_Read(chan, str, sizeof(str));
65 | printf("%d.%d.%d (%" JSI_NUMGFMT ") %s", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE, Jsi_Version(), str);
66 | exit(0);
67 | }
68 | if (argc > 2 && (Jsi_Strcmp(argv[1], "--invoke")==0 || Jsi_Strcmp(argv[1], "-i" )==0)) {
69 | Jsi_DString dStr = {};
70 | Jsi_DSAppend(&dStr, "jsi_invokeCmd(\"", argv[2], "\",console.args.slice(1));", NULL);
71 | rc = Jsi_EvalString(interp, Jsi_DSValue(&dStr), JSI_EVAL_NOSKIPBANG);
72 | Jsi_DSFree(&dStr);
73 | }
74 | else if (argc == 3 && (Jsi_Strcmp(argv[1], "--eval")==0 || Jsi_Strcmp(argv[1], "-e" )==0))
75 | rc = Jsi_EvalString(interp, argv[2], JSI_EVAL_NOSKIPBANG);
76 | else {
77 | Jsi_Value *vf = NULL;
78 | const char *ext = strrchr(argv[1], '.');
79 | /* Support running "main.jsi" from a zip file. */
80 | if (ext && (strcmp(ext,".zip")==0 ||strcmp(ext,".jsz")==0 ) ) {
81 | rc = Jsi_ExecZip(interp, argv[1], NULL, &jsFound);
82 | if (rc<0) {
83 | fprintf(stderr, "zip mount failed\n");
84 | exit(1);
85 | }
86 | if (!(jsFound&JSI_ZIP_MAIN)) {
87 | fprintf(stderr, "main.jsi not found\n");
88 | exit(1);
89 | }
90 | } else {
91 | if (argc>1)
92 | vf = Jsi_ValueNewStringKey(interp, argv[1]);
93 | rc = Jsi_EvalFile(interp, vf, JSI_EVAL_ARGV0|JSI_EVAL_INDEX);
94 | }
95 | }
96 | if (deleted)
97 | exit(exitCode);
98 | if (rc == 0) {
99 | /* Skip output from an ending semicolon which evaluates to undefined */
100 | Jsi_Value *ret = Jsi_ReturnValue(interp);
101 | if (!Jsi_ValueIsType(interp, ret, JSI_VT_UNDEF)) {
102 | Jsi_DString dStr = {};
103 | fputs(Jsi_ValueGetDString(interp, ret, &dStr, 0), stdout);
104 | Jsi_DSFree(&dStr);
105 | fputs("\n", stdout);
106 | }
107 | } else
108 | fputs("ERROR\n", stderr);
109 |
110 | }
111 | if (!deleted)
112 | Jsi_InterpDelete(interp);
113 | return rc;
114 | }
115 |
116 |
--------------------------------------------------------------------------------
/lib/websrv.jsi:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env jsish
2 |
3 | // Instantiates a simple web server
4 |
5 | function jsi_websrv(args,opts)
6 | {
7 | var that = this; // Give functions access to this[].
8 | var init = {
9 | // Options
10 | debug:0, // Debugging flag.
11 | local:true, // Accept only local connections.
12 | port: 8765, // Start search for port.
13 | maxPort: 1000, // Max to add to above port.
14 | nowait: false, // Caller will be calling sys.update();
15 | timeout:0, // Timed timeout (in ms).
16 | closeTimeout:5000, // Grace time after last client closes socket before exit (in ms).
17 | rootdir: null, // Where main.js lives.
18 | url: "/main.ihtml",
19 | browsers: { // Not used, yet.
20 | unix:[ "xdg-open", "gnome-open", "firefox", "google-chrome" ],
21 | win: [ "start" ],
22 | mac: [ "open" ]
23 | }
24 | };
25 |
26 | function dputs(str) { if (that.debug) console.log(str); }
27 |
28 | function DoExit() // Notify all going down, then exit.
29 | {
30 | WebSend(-1, 'exit');
31 | setTimeout(function () {that.done = 1; }, 1000);
32 | }
33 |
34 | function CloseNow()
35 | {
36 | that.closeId = null;
37 | if (that.ws.conf('connectCnt')>0)
38 | return;
39 | dputs("Last client has closed");
40 | that.done = 1;
41 | }
42 |
43 | function CloseLast(now) // Wait around for a while for reconnect or new clients before exiting
44 | {
45 | if (that.closeId)
46 | clearInterval(that.closeId);
47 | if (that.closeTimeout>0)
48 | that.closeId = setTimeout(function () { CloseNow(); }, that.closeTimeout);
49 | return true;
50 | }
51 |
52 | function WebSend (id,label,data,type)
53 | {
54 | if (type === undefined)
55 | type = "";
56 | var dat = {type: type, label:label, data:data };
57 | dat = JSON.stringify(dat);
58 | //dputs("SEND: "+dat);
59 | that.ws.send(dat,id);
60 | }
61 |
62 | function WebRecv(data, id)
63 | {
64 | var buf, buf0, buf1, buf2;
65 | dputs("SERVER GOT: "+ id +": "+data);
66 | var dat = JSON.parse(data);
67 | dputs("JSON: "+dat.toString());
68 | switch (dat.label) {
69 | case 'loadAll': return loadAll(id);
70 | case 'exit': DoExit(); break;
71 |
72 | default: dputs("unknown webmsg: "+dat.label); break;
73 | }
74 | }
75 |
76 | // MAIN BEGIN
77 | if (typeof args !== 'object' || args.length>1)
78 | throw "expected 0 or 1 args";
79 | jsi_parseOpts(this, opts, init);
80 | if (args.length) {
81 | this.url = file.tail(args[0]);
82 | this.rootdir = file.dirname(args[0]);
83 | }
84 | this.done = 0;
85 |
86 | if (!this.rootdir)
87 | this.rootdir=info.scriptDir();
88 | if (this.url && this.url.length) {
89 | var ufn = this.rootdir+'/'+this.url;
90 | if (!file.isfile(ufn))
91 | throw("file not found: "+ufn);
92 | }
93 | this.wsopts = {
94 | port:this.port, rootdir:this.rootdir, callback:WebRecv,
95 | onCloseLast:CloseLast, debug:this.debug
96 | };
97 | if (this.local)
98 | this.wsopts.interface = 'lo';
99 |
100 |
101 | /* Try opening websocket on first available port. */
102 | var i;
103 | for (i=0; i=this.maxPort) {
111 | console.log("Failed to get port");
112 | return;
113 | }
114 |
115 | this.ws.handler('.ihtml', 'jsi_wpp');
116 | dputs("Listen on "+this.wsopts.port);
117 | var prog = "xdg-open";
118 | switch (info.platform().os) {
119 | case 'win': prog = 'start'; break;
120 | }
121 | // Display page in browser.
122 | dputs("URL: "+this.url);
123 | if (this.url && this.url.length) {
124 | sys.exec(prog + " http://127.0.0.1:"+this.wsopts.port+'/'+this.url+" &");
125 | }
126 | if (this.nowait) return;
127 | if (this.timeout)
128 | setTimeout(function () { that.done = 1; }, this.timeout);
129 | while (this.done == 0 && sys.update(100) ) ;
130 | delete this.ws;
131 | }
132 |
133 | if (info.isInvoked()) {
134 | jsi_invokeCmd('jsi_websrv');
135 | }
136 |
--------------------------------------------------------------------------------
/lib/wpp.jsi:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env jsish
2 | // jsi_wpp preprocesses html, evaluating the javascript in between ?> tags (like php).
3 | // Evaluation occurs within a subinterp. Two commands are added: include(file,...) and echo(str).
4 |
5 | function jsi_wpp(files, opts)
6 | {
7 | var that = this; // Give functions access to this[].
8 | var init = {
9 | rc:'', files:[], chpos:0, curdir:'', data:'', errs:'',
10 | incsMax:1000, noCatch:true, delInterp:true,
11 | starttag:'', endtag:'?>', interp:null, interpOpts:{}
12 | };
13 |
14 | function echo(s) // Echo a string to output.
15 | {
16 | that.rc += s;
17 | }
18 |
19 | function error(s) // Format an error with file/line number.
20 | {
21 | var fn = that.files[that.files.length-1];
22 | var line = that.data.split('\n').length;
23 | return 'Error at '+fn+':'+line+': '+ s;
24 | }
25 |
26 | function include() // Include and evaluate files, recusively.
27 | {
28 | var ai, fn, args = arguments, slen = that.starttag.length, elen = that.starttag.length;
29 | var odata = that.data;
30 | if (args.length == 1 && args[0] != undefined && typeof args[0] == 'object')
31 | args = args[0];
32 | that.data = '';
33 | for (ai=0; ai that.incsMax)
35 | throw error("recursive include");
36 | fn = args[ai];
37 | if (that.files.length) {
38 | var pfn = that.files[that.files.length-1];
39 | fn = file.join(file.dirname(pfn), fn);
40 | } else {
41 | fn = file.realpath(fn);
42 | }
43 | if (!file.exists(fn)) {
44 | that.data = odata;
45 | throw error("file not found: "+fn);
46 | }
47 | // Break up on tag boundaries.
48 | var x = file.read(fn);
49 | var s = [], e = [];
50 | var n=0;
51 | while (1) {
52 | n = x.indexOf(that.starttag, n);
53 | if (n<0) break;
54 | s.push(n);
55 | n++;
56 | }
57 | if (s.length<=0) {
58 | return echo(x);
59 | }
60 | that.files.push(fn);
61 | n = 0;
62 | while (1) {
63 | n = x.indexOf(that.endtag, n);
64 | if (n<0) break;
65 | e.push(n);
66 | n++;
67 | }
68 | if (s.length != e.length)
69 | throw error('tags not balanced');
70 | var pre;
71 | for (var i in s) {
72 | if (s[i]>e[i])
73 | throw error('begin/end out of order');
74 | }
75 | // Now do the work: collect data/evaluate code.
76 | n = 0;
77 | var data = '';
78 | for (var i in s) {
79 | pre = x.substr(n,s[i]-n);
80 | echo(pre);
81 | data += pre;
82 | that.chpos = n = e[i]+elen;
83 | var code = x.substr(s[i]+slen, e[i]-s[i]-elen);
84 | that.data = data;
85 | try {
86 | that.interp.eval(code);
87 | } catch(e) {
88 | throw error('while evaling code:'+code+'\n'+e);
89 | }
90 | data += ''+code+'?>';
91 | that.data = data;
92 | }
93 | var l = s.length-1;
94 | if (e[e.length-1] < x.length-1) {
95 | pre = x.substr(e[i]+elen);
96 | echo(pre);
97 | }
98 | that.files.pop();
99 | }
100 | that.data = odata;
101 | }
102 |
103 | // Start of main function.
104 | jsi_parseOpts(this, opts, init);
105 | var oint = this.interp;
106 | if (!this.interp)
107 | this.interp = new Interp(this.interpOpts);
108 | if (!this.interp.alias('echo'))
109 | this.interp.alias('echo', echo, null);
110 | if (!this.interp.alias('include'))
111 | this.interp.alias('include', include, null);
112 |
113 | if (this.noCatch)
114 | include(files);
115 | else {
116 | try {
117 | include(files);
118 | } catch(e) {
119 | this.rc = "JSI ERROR
";
120 | this.rc += e;
121 | this.rc += '\n\n'+this.errs+"
";
122 | }
123 | }
124 | if (this.delInterp) {
125 | delete this.interp;
126 | this.interp = null;
127 | }
128 | return this.rc;
129 | };
130 |
131 |
132 | if (info.isInvoked()) {
133 | puts(jsi_invokeCmd('jsi_wpp'));
134 | }
135 |
136 |
--------------------------------------------------------------------------------
/tests/sqlite.js:
--------------------------------------------------------------------------------
1 | /*
2 | =!EXPECTSTART!=
3 | B=1, A=99
4 | B=2, A=95
5 | B=3, A=91
6 | [ { a:99, b:1 }, { a:95, b:2 }, { a:91, b:3 } ]
7 | CONF: { bindWarn:false, debug:0, errorCnt:0, execOpts:{ callback:null, cdata:null, headers:false, limit:0, mapundef:false, mode:"rows", nocache:false, nullvalue:null, separator:null, table:null, width:undefined }, forceInt:false, maxStmts:1000, mutex:"default", name:"", nocreate:false, readonly:false, trace:[ ], vfs:null }
8 | 95
9 | EXECING: select * from foo;
10 | [ { a:99, b:1 }, { a:95, b:2 }, { a:91, b:3 } ]
11 | EXECING: select * from foo;
12 | 99|1
13 | 95|2
14 | 91|3
15 | EXECING: select * from foo;
16 | a|b
17 | 99|1
18 | 95|2
19 | 91|3
20 | EXECING: select * from foo;
21 | | 99 | 1 |
22 | | 95 | 2 |
23 | | 91 | 3 |
24 | EXECING: select * from foo;
25 | | a | b |
26 | | 99 | 1 |
27 | | 95 | 2 |
28 | | 91 | 3 |
29 | EXECING: select * from foo;
30 | 99,1
31 | 95,2
32 | 91,3
33 | EXECING: select * from foo;
34 | a,b
35 | 99,1
36 | 95,2
37 | 91,3
38 | EXECING: select * from foo;
39 | a b 99 1
40 | 95 2
41 | 91 3
42 | EXECING: select * from foo;
43 | a b
44 | ---------- ----------
45 | 99 1
46 | 95 2
47 | 91 3
48 | EXECING: select * from foo;
49 | [ {"a":99, "b":1}, {"a":95, "b":2}, {"a":91, "b":3} ]
50 | EXECING: select * from foo;
51 | [ ["a", "b"], [99, 1], [95, 2], [91, 3] ]
52 | EXECING: select * from foo;
53 | { "names": [ "a", "b" ], "values": [ [99, 1 ], [95, 2 ], [91, 3 ] ] }
54 | EXECING: select * from foo;
55 | 99 1
56 | 95 2
57 | 91 3
58 | EXECING: select * from foo;
59 | a b
60 | 99 1
61 | 95 2
62 | 91 3
63 | EXECING: select * from foo;
64 | a = 99 b = 1
65 | a = 95
66 | b = 2
67 | a = 91
68 | b = 3
69 | EXECING: select * from foo;
70 | INSERT INTO table VALUES(99,NULL);
71 | INSERT INTO table VALUES(95,NULL);
72 | INSERT INTO table VALUES(91,NULL);
73 | TRACING: select bar(a) from foo where b == 2;
74 | 95.000
75 | function (sql) {...}
76 | =!EXPECTEND!=
77 | */
78 |
79 |
80 | var db = new Sqlite('/tmp/testsql.db',{maxStmts:1000, readonly:false});
81 | //var db = new Sqlite('/tmp/testsql.db');
82 |
83 | db.evaluate('drop table IF EXISTS foo;');
84 | try {
85 | db.exec('drop table foo;', null);
86 | } catch(e) {
87 | //puts("OK");
88 | };
89 |
90 | db.evaluate('drop table IF EXISTS foo; create table foo(a,b);');
91 | //db.evaluate('drop table IF EXISTS foo; create table foo(a,b);');
92 | var n = 0;
93 | var x = 99;
94 | while (n++ < 3) {
95 | db.exec('insert into foo values(@x,@n);');
96 | x -= 4;
97 |
98 | //db.exec('insert into foo values("x",' + n + ');');
99 | }
100 | db.exec('select * from foo;', function (n) {
101 | puts("B="+n.b + ", A="+n.a);
102 | });
103 |
104 | puts(db.exec('select * from foo;').toString());
105 |
106 | db.exec('select * from foo;', null);
107 |
108 | puts("CONF: "+db.conf().toString());
109 | db.profile(function(sql,time) { puts("EXECING: "+sql); });
110 |
111 | puts(db.onecolumn('select a from foo where b == 2;'));
112 | var s = {};
113 | s.b = 2;
114 |
115 | puts(db.exec('select * from foo;'));
116 | puts(db.exec('select * from foo;',{mode:'list'}));
117 | puts(db.exec('select * from foo;',{mode:'list',headers:true}));
118 | puts(db.exec('select * from foo;',{mode:'html'}));
119 | puts(db.exec('select * from foo;',{mode:'html',headers:true}));
120 | puts(db.exec('select * from foo;',{mode:'csv'}));
121 | puts(db.exec('select * from foo;',{mode:'csv',headers:true}));
122 | puts(db.exec('select * from foo;',{mode:'column'}));
123 | puts(db.exec('select * from foo;',{mode:'column',headers:true}));
124 | puts(x=db.exec('select * from foo;',{mode:'json'}));
125 | JSON.parse(x);
126 | puts(x=db.exec('select * from foo;',{mode:'json',headers:true}));
127 | JSON.parse(x);
128 | puts(x=db.exec('select * from foo;',{mode:'json2'}));
129 | JSON.parse(x);
130 | puts(db.exec('select * from foo;',{mode:'tabs'}));
131 | puts(db.exec('select * from foo;',{mode:'tabs',headers:true}));
132 | puts(db.exec('select * from foo;',{mode:'line'}));
133 | puts(db.exec('select * from foo;',{mode:'insert'}));
134 |
135 | db.func('bar',function(n) { return n+'.000'; });
136 |
137 |
138 | db.trace(function(sql) { puts("TRACING: "+sql); });
139 | puts(db.onecolumn('select bar(a) from foo where b == 2;'));
140 | puts(db.trace());
141 |
142 | //puts(db.version());
143 | delete db;
144 |
145 |
146 | /*
147 | var res1 = db.exec('select * from table foo(a,b);');
148 | for (i in res1) {
149 | puts("CONS: "+i.toString());
150 | }
151 |
152 |
153 | var curs, n;
154 | for (curs = db.exec('select * from table foo(a,b);'),
155 | (n = db.getresult(curs))!=undefined,
156 | db.nextresult(curs)) {
157 | puts(n.toString());
158 | }
159 | db.endresult(curs);
160 |
161 |
162 | */
163 |
--------------------------------------------------------------------------------
/lib/parseOpts.jsi:
--------------------------------------------------------------------------------
1 | // Parse command line options.
2 |
3 | /*
4 | =!EXPECTSTART!=
5 | RC=1 { a:2, b:1, c:2 }
6 | RC=1 { a:3, b:1, c:2 }
7 | =!EXPECTEND!=
8 | */
9 |
10 |
11 | /* Used for command line invocation with the --invoke/-i option, eg:
12 | jsish --invoke command -opt1 val1 -opt2 val2 ... arg1 arg2 ...
13 | which invokes:
14 | command([arg1,arg2,...],{opt1:val1,opt2:val2,...});*/
15 | function jsi_invokeCmdOld(cmd, opts) {
16 | if (!opts)
17 | opts = console.args;
18 | var i, c = "", n = 1, astr = '', ostr, s0;
19 | for (i=0; opts && iExec
2 |
3 | Description
4 |
5 | The method sys.exec(cmd?,option?) execute an operating system command and returns the result, eg.
6 |
7 |
8 | sys.exec('ls -l');
9 | sys.exec(['ls','-l','/tmp']);
10 | sys.exec('ls -l > /tmp/ls.txt', false);
11 |
12 |
13 | A command pipeline is created with support for redirection. The input command is either an array,
14 | or a string which is split on the space char. Note, this means a string can have one, and only one,
15 | space between each token.
16 |
17 | A command ending in a single & is executed in the background (ie. no waiting).
18 | The second boolean argument if given as false means do not error-out on non-zero result code,
19 | and true means returned value is an object with data in the 'output' property.
20 |
21 | Details
22 |
23 | This command treats its arguments as the specification of one or more UNIX commands to execute as
24 | subprocesses. The commands take the form of a standard shell pipeline; | arguments separate commands
25 | in the pipeline and cause standard output of the preceding command to be piped into standard input
26 | of the next command (or |& for both standard output and standard error).
27 |
28 | Under normal conditions the result of the exec command consists of the standard output produced
29 | by the last command in the pipeline.
30 |
31 | If any of the commands in the pipeline exit abnormally or are killed or suspended,
32 | then exec will return an error and the error message will include the pipeline’s output
33 | followed by error messages describing the abnormal terminations.
34 |
35 | If any of the commands writes to its standard error file, then exec will return an error,
36 | and the error message will include the pipeline’s output, followed by messages about abnormal
37 | terminations (if any), followed by the standard error output.
38 |
39 | If the last character of the result or error message is a newline then that character is deleted
40 | from the result or error message for consistency with normal Tcl return values.
41 |
42 | An arg may have one of the following special forms:
43 |
44 |
45 |
46 | - >filename
47 | - The standard output of the last command in the pipeline is redirected to the file.
48 | In this situation exec will normally return an empty string.
49 |
50 |
51 | - >>filename
52 | - As above, but append to the file.
53 |
54 |
55 | - >@fileId
56 | - The standard output of the last command in the pipeline is redirected to the given (writable)
57 | File object. In this situation exec will normally return an empty string.
58 |
59 |
60 | - 2>filename
61 | - The standard error of the last command in the pipeline is redirected to the file.
62 |
63 |
64 | - 2>>filename
65 | - As above, but append to the file.
66 |
67 |
- 2>@fileId
68 | - The standard error of the last command in the pipeline is redirected to the given (writable) File object.
69 |
70 |
71 | - 2>@1
72 | - The standard error of the last command in the pipeline is redirected to the same file descriptor
73 | as the standard output.
74 |
75 |
76 | - >&filename
77 | - Both the standard output and standard error of the last command in the pipeline is redirected to the file.
78 |
79 |
80 | - >>&filename
81 | - As above, but append to the file.
82 |
83 |
84 | - <filename
85 | - The standard input of the first command in the pipeline is taken from the file.
86 |
87 |
88 | - <<string
89 | - The standard input of the first command is taken as the given immediate value.
90 |
91 |
92 | - <@fileId
93 | - The standard input of the first command in the pipeline is taken from the given (readable) file descriptor.
94 |
95 |
96 |
97 |
98 |
99 | If there is no redirection of standard input, standard error or standard output, these are connected
100 | to the corresponding input or output of the application.
101 |
102 | If the last arg is & then the command will be executed in background. In this case the standard output
103 | from the last command in the pipeline will go to the application’s standard output unless redirected
104 | in the command, and error output from all the commands in the pipeline will go to the application’s
105 | standard error file. The return value of exec in this case is a list of process ids (pids) in the pipeline.
106 |
107 | Each arg becomes one word for a command, except for |, <, <<, >, and & arguments, and
108 | the arguments that follow <, <<, and >.
109 |
110 | The first word in each command is taken as the command name; the directories in the PATH environment
111 | variable are searched for an executable by the given name.
112 |
113 | No glob expansion or other shell-like substitutions are performed on the arguments to commands.
114 |
--------------------------------------------------------------------------------
/jsiPstate.c:
--------------------------------------------------------------------------------
1 | #ifndef JSI_LITE_ONLY
2 | #ifndef JSI_AMALGAMATION
3 | #include "jsiInt.h"
4 | #endif
5 |
6 | #define MAX_SCOPE (BUFSIZ/2)
7 |
8 | Jsi_ScopeStrs *jsi_ScopeStrsNew(struct jsi_Pstate *ps)
9 | {
10 | Jsi_ScopeStrs *ret = Jsi_Calloc(1, sizeof(*ret));
11 | return ret;
12 | }
13 |
14 | void jsi_ScopeStrsPush(struct jsi_Pstate *ps, Jsi_ScopeStrs *ss, const char *string)
15 | {
16 | if (ss->count >= ss->_size) {
17 | ss->_size += 5;
18 | ss->strings = Jsi_Realloc(ss->strings, (ss->_size) * sizeof(char *));
19 | }
20 | ss->strings[ss->count] = (char*)Jsi_KeyAdd(ps->interp, string);
21 | ss->count++;
22 | }
23 |
24 | static Jsi_ScopeStrs *strs_dup(struct jsi_Pstate *ps, Jsi_ScopeStrs *ss)
25 | {
26 | Jsi_ScopeStrs *n = jsi_ScopeStrsNew(ps);
27 | int i;
28 | if (!ss) return n;
29 | for (i = 0; i < ss->count; ++i) {
30 | jsi_ScopeStrsPush(ps, n, ss->strings[i]);
31 | }
32 | return n;
33 | }
34 |
35 | const char *jsi_ScopeStrsGet(Jsi_ScopeStrs *ss, int i)
36 | {
37 | if (i < 0 || i >= ss->count) return NULL;
38 | return ss->strings[i];
39 | }
40 |
41 | void jsi_ScopeStrsFree(Jsi_ScopeStrs *ss)
42 | {
43 | if (!ss) return;
44 | Jsi_Free(ss->strings);
45 | Jsi_Free(ss);
46 | }
47 |
48 | /* lexical scope */
49 | static Jsi_ScopeStrs *scopes[MAX_SCOPE];
50 | static int cur_scope;
51 |
52 | void jsi_ScopePush(struct jsi_Pstate *ps)
53 | {
54 | Jsi_Interp *interp = ps->interp;
55 | if (cur_scope >= MAX_SCOPE - 1) Jsi_LogBug("Scope chain to short\n");
56 | cur_scope++;
57 | }
58 |
59 | void jsi_ScopePop(struct jsi_Pstate *ps)
60 | {
61 | Jsi_Interp *interp = ps->interp;
62 | if (cur_scope <= 0) Jsi_LogBug("No more scope to pop\n");
63 | jsi_ScopeStrsFree(scopes[cur_scope]);
64 | scopes[cur_scope] = NULL;
65 | cur_scope--;
66 | }
67 |
68 | void jsi_ScopeAddVar(jsi_Pstate *ps, const char *str)
69 | {
70 | int i;
71 | if (scopes[cur_scope] == NULL) scopes[cur_scope] = jsi_ScopeStrsNew(ps);
72 |
73 | for (i = 0; i < scopes[cur_scope]->count; ++i) {
74 | if (Jsi_Strcmp(str, scopes[cur_scope]->strings[i]) == 0) return;
75 | }
76 | jsi_ScopeStrsPush(ps, scopes[cur_scope], str);
77 | }
78 |
79 | Jsi_ScopeStrs *jsi_ScopeGetVarlist(jsi_Pstate *ps)
80 | {
81 | return strs_dup(ps, scopes[cur_scope]);
82 | }
83 |
84 |
85 | static int fastVarFree(Jsi_Interp *interp, void *ptr) {
86 | FastVar *fv = ptr;
87 | Jsi_Value *v = fv->var.lval;
88 | if (v) {
89 | //printf("FV FREE: %p (%d/%d)\n", fv, v->refCnt, v->vt == JSI_VT_OBJECT?v->d.obj->refcnt:-99);
90 | //Jsi_DecrRefCount(interp, v);
91 | }
92 | return JSI_OK;
93 | }
94 |
95 | jsi_Pstate *jsi_PstateNew(Jsi_Interp *interp)
96 | {
97 | Jsi_Value sval = VALINITS;
98 | jsi_Pstate *ps = Jsi_Calloc(1,sizeof(*ps));
99 | SIGINIT(ps,PARSER);
100 | ps->lexer = Jsi_Calloc(1,sizeof(*ps->lexer));
101 | ps->lexer->pstate = ps;
102 | ps->interp = interp;
103 | ps->last_exception = sval;
104 | ps->argsTbl = Jsi_HashNew(interp, JSI_KEYS_ONEWORD, jsi_ArglistFree);
105 | ps->fastVarTbl = Jsi_HashNew(interp, JSI_KEYS_ONEWORD, fastVarFree);
106 | ps->strTbl = Jsi_HashNew(interp, JSI_KEYS_STRING, NULL);
107 | return ps;
108 | }
109 |
110 | const char *jsi_PstateGetFilename(jsi_Pstate *ps)
111 | {
112 | Jsi_Interp *interp = ps->interp;
113 | return interp->curFile;
114 | }
115 |
116 | void jsi_PstateClear(jsi_Pstate *ps)
117 | {
118 | Lexer* l = ps->lexer;
119 | if (l->ltype == LT_FILE)
120 | {
121 | if (l->d.fp)
122 | Jsi_Close(l->d.fp);
123 | l->d.fp = NULL;
124 | }
125 | if (l->ltype == LT_STRING)
126 | {
127 | l->d.str = NULL;
128 | }
129 | l->ltype = LT_NONE;
130 | l->last_token = 0;
131 | l->cur_line = 1;
132 | l->cur_char = 0;
133 | l->cur = 0;
134 | ps->err_count = 0;
135 | }
136 |
137 | int jsi_PstateSetFile(jsi_Pstate *ps, Jsi_Channel fp, int skipbang)
138 | {
139 | Lexer *l = ps->lexer;
140 | jsi_PstateClear(ps);
141 | l->ltype = LT_FILE;
142 | l->d.fp = fp;
143 | Jsi_Rewind(fp);
144 | if (skipbang) {
145 | char buf[1000];
146 | if (Jsi_Gets(fp, buf, 1000) && (buf[0] != '#' || buf[1] != '!')) {
147 | Jsi_Rewind(fp);
148 | }
149 | }
150 |
151 | return JSI_OK;
152 | }
153 |
154 |
155 | int jsi_PstateSetString(jsi_Pstate *ps, const char *str)
156 | {
157 | Jsi_Interp *interp = ps->interp;
158 | Lexer *l = ps->lexer;
159 | jsi_PstateClear(ps);
160 | l->ltype = LT_STRING;
161 | Jsi_HashEntry *hPtr = Jsi_HashEntryCreate(interp->codeTbl, (void*)str, NULL);
162 | assert(hPtr);
163 | l->d.str = Jsi_HashKeyGet(hPtr);
164 | return JSI_OK;
165 | }
166 |
167 | void jsi_PstateFree(jsi_Pstate *ps)
168 | {
169 | /* TODO: when do we free opcodes */
170 | jsi_PstateClear(ps);
171 | Jsi_Free(ps->lexer);
172 | if (ps->opcodes)
173 | jsi_FreeOpcodes(ps->opcodes);
174 | if (ps->hPtr)
175 | Jsi_HashEntryDelete(ps->hPtr);
176 | Jsi_HashDelete(ps->argsTbl);
177 | Jsi_HashDelete(ps->strTbl);
178 | Jsi_HashDelete(ps->fastVarTbl);
179 | MEMCLEAR(ps);
180 | Jsi_Free(ps);
181 | }
182 |
183 | #endif
184 |
--------------------------------------------------------------------------------
/www/buildjsi.wiki:
--------------------------------------------------------------------------------
1 | Building
2 | Linux
3 |
4 | In order to build Jsi on Linux, a few packages need to be installed.
5 | On Ubuntu we do this:
6 |
7 |
8 | sudo apt-get install build-essential bison cmake libreadline-dev
9 |
10 |
11 | Then just type make (in the jsi directory).
12 |
13 | Build Options
14 |
15 | Jsi does not use configure.
16 | Instead, various build options are controled via make command-line options:
17 |
18 |
19 | | Option | Description |
20 | | EXTSRC=name | Root name of a .c file to build in as a user extension |
21 | | EXTNAME=name | User extension name for above (if different) |
22 | | NOSQLITE=1 | Exclude sqlite support |
23 | | NOWEBSOCK=1 | Exclude websockets |
24 | | USEMUSL=1 | Static, zero dependancy build with Musl-libc |
25 | | USEMINIZ=1 | Use the miniz compression extension, instead of builtin -lz |
26 | | WIN=1 | Cross-compile to Windows binary |
27 | | ZIPDIR=name | Directory to zip to end of binary jsiz (default dir is zdir) |
28 |
29 |
30 |
31 | For example, the following builds without WebSockets :
32 |
33 |
34 | make NOWEBSOCK=1
35 |
36 |
37 | Windows
38 |
39 | To build for Windows, first install the Mingw32 package on Linux:
40 |
41 |
42 | sudo apt-get install gcc-mingw32
43 |
44 |
45 | Jsi can be cross compiled to Windows using:
46 |
47 |
48 | make WIN=1
49 |
50 |
51 | Note, you must do this twice, as it will initially fail.
52 |
53 | Note that some features (eg. signals) are currently disabled in the Windows build.
54 | There are also minor differences in some file-system access functions.
55 |
56 | Static Build
57 |
58 | A static build is useful when you need a standalone executable with no external dependancies.
59 |
60 | To create a static image, Jsi uses the Musl library.
61 |
62 | The first step is to download [http://www.musl-libc.org|Musl] and unpack it.
63 | Then change to the musl dir and:
64 |
65 |
66 | ./configure --prefix=$HOME/usr && make install
67 |
68 |
69 | Ensure that ~/usr/bin is in your path with export PATH=$PATH:$HOME/usr/bin.
70 | Then back in the jsi dir do the following:
71 |
72 |
73 | echo '#define __P(x) x' > ~/usr/include/sys/cdefs.h
74 | echo '#include ' > ~/usr/include/zlib.h
75 | cp -pr miniz ~/usr/include/
76 |
77 |
78 | A static jsish can be built with:
79 |
80 |
81 | make USEMUSL=1
82 |
83 |
84 | You must do this twice, as it will initially fail.
85 | The resulting executable will require no system libraries.
86 |
87 |
88 | Basic Extension
89 |
90 | The following steps detail a simple way to add your own code to Jsi. Code is placed in the user directory,
91 | and make invoked with the EXTSRC=name argument. The named code gets linked into the Jsi build.
92 | Example
93 |
94 | The sample extension user/demo.c included with the Jsi distribution.
95 | It simply creates a new javascript method demo() that echo's its arguments.
96 |
97 |
98 | #include "jsi.h"
99 |
100 | Jsi_CmdProcDecl(DemoCmd) {
101 | int i, n = Jsi_ValueGetLength(interp, args);
102 | printf("demo called with %d args\n", n);
103 | for (i=0; i
117 |
118 | To build this into the application:
119 |
120 | make EXTSRC=demo
121 |
122 |
123 |
124 | Multi-method Object Extension
125 |
126 | Sometimes in javascript it is desirable to create a new object with a number of related methods,
127 | rather than just single commands. This is achieved by registering a table of methods.
128 |
129 | The sample extension user/demos.c comes included with the
130 | Jsi distribution does this:
131 |
132 |
133 | #include "jsi.h"
134 |
135 | Jsi_CmdProcDecl(DemoCmd) {
136 | int i, n = Jsi_ValueGetLength(interp, args);
137 | printf("demo called with %d args\n", n);
138 | for (i=0; i
157 | To build this into the application:
158 |
159 |
160 | make EXTSRC=demos
161 |
162 |
163 | This named code gets linked into the Jsi build. At startup it simply creates new javascript methods
164 | demos.foo() and demos.bar().
165 |
166 |
--------------------------------------------------------------------------------
/tools/mkref.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env jsish
2 | // Generate documentation for Jsi builtin cmds in fossil wiki format.
3 |
4 | function jsi_mkref() {
5 |
6 | function DumpOpts(opts, nam, isconf) {
7 | //if (cnam.indexOf('.')<0) cnam=cnam+'.conf';
8 | var rv = '';//, opts = info.cmds(cnam).options;
9 | rv += '\n\n\n';
10 | rv += 'Options for "'+nam+'"
\n';
11 | rv += "\nThe following options are available for \""+nam+"\"\n\n";
12 | rv += "\n";
13 | rv += "| Option | Type | Description | Default |
\n";
14 | //puts(opts);
15 | for (var o in opts) {
16 | ci = opts[o];
17 | if (isconf && ci.initOnly) continue;
18 | var help = (ci.help?ci.help+'.':'');
19 | if (ci.readOnly) help += " (readonly)";
20 | if (ci.customArg && ci.customArg.data)
21 | help += ' '+ ci.customArg.data;
22 | rv += "| "+ci.name+" | "+ci.type+" | "+ help +" | "+ (ci.init?ci.init:'') +' |
\n';
23 | }
24 | rv += "
\n";
25 | return rv;
26 | }
27 |
28 | function DumpCmd(cinf) {
29 | var rv = '';
30 | var cnam = sprintf("%s(%s)", cinf.name, cinf.argStr);
31 | index += ""+cnam+"\n";
32 | rv += '\n';
33 | rv += '\n
\n';
34 | rv += 'Return to top\n';
35 | rv += '\n\n'+cinf.name+'
\n\n';
36 | rv += sprintf("Synopsis: %s(%s)\n\n", cinf.name, cinf.argStr);
37 | if (cinf.help)
38 | rv += cinf.help+".\n\n";
39 | if (cinf.info)
40 | rv += cinf.info+'\n\n';
41 | if (cinf.options != NULL) {
42 | rv += DumpOpts(cinf.options, cinf.name, false);
43 | }
44 | rv += '\n';
45 | return rv+'\n';
46 | }
47 | function LinkOpts(astr,name) {
48 | var ii;
49 | if ((ii=astr.indexOf('options'))<0)
50 | return astr;
51 | var ss = '';
52 | if (ii>0)
53 | ss += astr.slice(0, ii);
54 | ss += "options";
55 | ss += astr.slice(ii+7);
56 | return ss;
57 | }
58 |
59 | function DumpObj(tinf) {
60 | var hasconf, ro = '', rv = '', ci, cnam = tinf.name, cmds = info.cmds(cnam+'.*');
61 | index += "
"+cnam+"\n";
62 | rv += '\n';
63 | rv += '\n
\n';
64 | rv += 'Return to top\n';
65 | rv += '\n\n'+cnam+'
\n\n';
66 | rv += "Synopsis:";
67 | if (tinf.constructor) {
68 | rv += 'new '+cnam+"("+tinf.argStr+")\n\n";
69 | } else {
70 | rv += cnam+".method(...)\n\n";
71 | }
72 | rv += "";
73 | if (tinf.help)
74 | rv += tinf.help+".\n\n";
75 | if (tinf.info)
76 | rv += tinf.info+'\n\n';
77 | rv += '\n
Methods
\n';
78 | rv += "\nThe following methods are available in \""+cnam+"\":\n\n";
79 | rv += "\n";
80 | rv += '| Method | Description |
\n';
81 | if (tinf.constructor) {
82 | ci = info.cmds(cnam+'.'+cnam,true);
83 | var conhelp = (ci.help?ci.help+'.':''), aastr;
84 | if (ci.info) conhelp += ci.info;
85 | aastr = tinf.argStr;
86 | if (tinf.options) {
87 | aastr = LinkOpts(aastr, "new "+cnam);
88 | }
89 | rv += "| new "+cnam+"("+aastr+") | "+conhelp+' |
\n';
90 | }
91 | if (cmds !== undefined) {
92 | for (var cmd in cmds) {
93 | var nam = cmds[cmd].split('.')[1];
94 | if (nam == cnam)
95 | continue;
96 | ci = info.cmds(cnam+'.'+nam);
97 | var conhelp = (ci.help?ci.help+'.':'');
98 | if (ci.info) conhelp += ' '+ci.info;
99 | if (ci.options) {
100 | ro += DumpOpts(ci.options, cnam+'.'+nam, (nam === 'conf'));
101 | aastr = LinkOpts(ci.argStr, cnam+'.'+nam);
102 | } else {
103 | aastr = ci.argStr;
104 | }
105 | //if (nam == 'conf') hasconf = ci.options;
106 | rv += "| "+nam+"("+aastr+") | "+conhelp+' |
\n';
107 | }
108 | }
109 | rv += "
\n";
110 | if (tinf.options)
111 | rv += DumpOpts(tinf.options, 'new '+cnam, (nam === 'conf'));
112 | rv += ro;
113 | rv += '\n';
114 | return rv;
115 | }
116 |
117 |
118 | //*************** BEGIN MAIN **************
119 | var rv = '', tinf, lst = info.cmds();
120 | var vv = info.version(true);
121 | var ver = vv.major+'.'+vv.minor+'.'+vv.release;
122 |
123 | puts("Reference");
124 | var index = "";
125 |
126 | for (var i in lst) {
127 | tinf = info.cmds(lst[i]);
128 | switch (tinf.type) {
129 | case 'object':
130 | rv += DumpObj(tinf);
131 | break;
132 | case 'command':
133 | rv += DumpCmd(tinf);
134 | break;
135 | default:
136 | throw("bad id");
137 | continue;
138 | }
139 | }
140 | rv += "";
141 | index + "
\n";
142 | return 'JSI Command Reference: version '+ver+'
\n\n' + index + rv;
143 | }
144 |
145 | if (info.isInvoked()) {
146 | puts(jsi_mkref());
147 | }
148 |
--------------------------------------------------------------------------------