xref: /freebsd/contrib/lyaml/ext/yaml/scanner.c (revision 2bc180ef045e5911cce0cea1c2a139cffd2b577a)
1*2bc180efSBaptiste Daroussin /*
2*2bc180efSBaptiste Daroussin  * scanner.c, libyaml scanner binding for Lua
3*2bc180efSBaptiste Daroussin  * Written by Gary V. Vaughan, 2013
4*2bc180efSBaptiste Daroussin  *
5*2bc180efSBaptiste Daroussin  * Copyright (C) 2013-2022 Gary V. Vaughan
6*2bc180efSBaptiste Daroussin  *
7*2bc180efSBaptiste Daroussin  * Permission is hereby granted, free of charge, to any person obtaining a copy
8*2bc180efSBaptiste Daroussin  * of this software and associated documentation files (the "Software"), to deal
9*2bc180efSBaptiste Daroussin  * in the Software without restriction, including without limitation the rights
10*2bc180efSBaptiste Daroussin  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11*2bc180efSBaptiste Daroussin  * copies of the Software, and to permit persons to whom the Software is
12*2bc180efSBaptiste Daroussin  * furnished to do so, subject to the following conditions:
13*2bc180efSBaptiste Daroussin  *
14*2bc180efSBaptiste Daroussin  * The above copyright notice and this permission notice shall be included in
15*2bc180efSBaptiste Daroussin  * all copies or substantial portions of the Software.
16*2bc180efSBaptiste Daroussin  *
17*2bc180efSBaptiste Daroussin  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18*2bc180efSBaptiste Daroussin  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19*2bc180efSBaptiste Daroussin  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20*2bc180efSBaptiste Daroussin  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21*2bc180efSBaptiste Daroussin  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22*2bc180efSBaptiste Daroussin  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23*2bc180efSBaptiste Daroussin  * THE SOFTWARE.
24*2bc180efSBaptiste Daroussin  */
25*2bc180efSBaptiste Daroussin 
26*2bc180efSBaptiste Daroussin #include "lyaml.h"
27*2bc180efSBaptiste Daroussin 
28*2bc180efSBaptiste Daroussin 
29*2bc180efSBaptiste Daroussin typedef struct {
30*2bc180efSBaptiste Daroussin    lua_State	 *L;
31*2bc180efSBaptiste Daroussin    yaml_parser_t  parser;
32*2bc180efSBaptiste Daroussin    yaml_token_t	  token;
33*2bc180efSBaptiste Daroussin    char		  validtoken;
34*2bc180efSBaptiste Daroussin    int		  document_count;
35*2bc180efSBaptiste Daroussin } lyaml_scanner;
36*2bc180efSBaptiste Daroussin 
37*2bc180efSBaptiste Daroussin 
38*2bc180efSBaptiste Daroussin static void
scanner_delete_token(lyaml_scanner * scanner)39*2bc180efSBaptiste Daroussin scanner_delete_token (lyaml_scanner *scanner)
40*2bc180efSBaptiste Daroussin {
41*2bc180efSBaptiste Daroussin    if (scanner->validtoken)
42*2bc180efSBaptiste Daroussin    {
43*2bc180efSBaptiste Daroussin       yaml_token_delete (&scanner->token);
44*2bc180efSBaptiste Daroussin       scanner->validtoken = 0;
45*2bc180efSBaptiste Daroussin    }
46*2bc180efSBaptiste Daroussin }
47*2bc180efSBaptiste Daroussin 
48*2bc180efSBaptiste Daroussin /* With the token result table on the top of the stack, insert
49*2bc180efSBaptiste Daroussin    a mark entry. */
50*2bc180efSBaptiste Daroussin static void
scanner_set_mark(lua_State * L,const char * k,yaml_mark_t mark)51*2bc180efSBaptiste Daroussin scanner_set_mark (lua_State *L, const char *k, yaml_mark_t mark)
52*2bc180efSBaptiste Daroussin {
53*2bc180efSBaptiste Daroussin    lua_pushstring  (L, k);
54*2bc180efSBaptiste Daroussin    lua_createtable (L, 0, 3);
55*2bc180efSBaptiste Daroussin #define MENTRY(_s)	RAWSET_INTEGER (#_s, mark._s)
56*2bc180efSBaptiste Daroussin          MENTRY( index	);
57*2bc180efSBaptiste Daroussin          MENTRY( line	);
58*2bc180efSBaptiste Daroussin          MENTRY( column	);
59*2bc180efSBaptiste Daroussin #undef MENTRY
60*2bc180efSBaptiste Daroussin    lua_rawset (L, -3);
61*2bc180efSBaptiste Daroussin }
62*2bc180efSBaptiste Daroussin 
63*2bc180efSBaptiste Daroussin /* Push a new token table, pre-populated with shared elements. */
64*2bc180efSBaptiste Daroussin static void
scanner_push_tokentable(lyaml_scanner * scanner,const char * v,int n)65*2bc180efSBaptiste Daroussin scanner_push_tokentable (lyaml_scanner *scanner, const char *v, int n)
66*2bc180efSBaptiste Daroussin {
67*2bc180efSBaptiste Daroussin    lua_State *L = scanner->L;
68*2bc180efSBaptiste Daroussin 
69*2bc180efSBaptiste Daroussin    lua_createtable (L, 0, n + 3);
70*2bc180efSBaptiste Daroussin    RAWSET_STRING   ("type", v);
71*2bc180efSBaptiste Daroussin 
72*2bc180efSBaptiste Daroussin #define MENTRY(_s)	scanner_set_mark (L, #_s, scanner->token._s)
73*2bc180efSBaptiste Daroussin          MENTRY( start_mark	);
74*2bc180efSBaptiste Daroussin          MENTRY( end_mark	);
75*2bc180efSBaptiste Daroussin #undef MENTRY
76*2bc180efSBaptiste Daroussin }
77*2bc180efSBaptiste Daroussin 
78*2bc180efSBaptiste Daroussin static void
scan_STREAM_START(lyaml_scanner * scanner)79*2bc180efSBaptiste Daroussin scan_STREAM_START (lyaml_scanner *scanner)
80*2bc180efSBaptiste Daroussin {
81*2bc180efSBaptiste Daroussin #define EVENTF(_f)	(scanner->token.data.stream_start._f)
82*2bc180efSBaptiste Daroussin    lua_State *L = scanner->L;
83*2bc180efSBaptiste Daroussin    const char *encoding;
84*2bc180efSBaptiste Daroussin 
85*2bc180efSBaptiste Daroussin    switch (EVENTF (encoding))
86*2bc180efSBaptiste Daroussin    {
87*2bc180efSBaptiste Daroussin #define MENTRY(_s)		\
88*2bc180efSBaptiste Daroussin       case YAML_##_s##_ENCODING: encoding = #_s; break
89*2bc180efSBaptiste Daroussin          MENTRY( UTF8		);
90*2bc180efSBaptiste Daroussin          MENTRY( UTF16LE	);
91*2bc180efSBaptiste Daroussin          MENTRY( UTF16BE	);
92*2bc180efSBaptiste Daroussin #undef MENTRY
93*2bc180efSBaptiste Daroussin 
94*2bc180efSBaptiste Daroussin       default:
95*2bc180efSBaptiste Daroussin          lua_pushfstring (L, "invalid encoding %d", EVENTF (encoding));
96*2bc180efSBaptiste Daroussin          lua_error (L);
97*2bc180efSBaptiste Daroussin    }
98*2bc180efSBaptiste Daroussin 
99*2bc180efSBaptiste Daroussin    scanner_push_tokentable (scanner, "STREAM_START", 1);
100*2bc180efSBaptiste Daroussin    RAWSET_STRING ("encoding", encoding);
101*2bc180efSBaptiste Daroussin #undef EVENTF
102*2bc180efSBaptiste Daroussin }
103*2bc180efSBaptiste Daroussin 
104*2bc180efSBaptiste Daroussin static void
scan_VERSION_DIRECTIVE(lyaml_scanner * scanner)105*2bc180efSBaptiste Daroussin scan_VERSION_DIRECTIVE (lyaml_scanner *scanner)
106*2bc180efSBaptiste Daroussin {
107*2bc180efSBaptiste Daroussin #define EVENTF(_f)	(scanner->token.data.version_directive._f)
108*2bc180efSBaptiste Daroussin    lua_State *L = scanner->L;
109*2bc180efSBaptiste Daroussin 
110*2bc180efSBaptiste Daroussin    scanner_push_tokentable (scanner, "VERSION_DIRECTIVE", 2);
111*2bc180efSBaptiste Daroussin 
112*2bc180efSBaptiste Daroussin #define MENTRY(_s)	RAWSET_INTEGER (#_s, EVENTF (_s))
113*2bc180efSBaptiste Daroussin          MENTRY( major	);
114*2bc180efSBaptiste Daroussin          MENTRY( minor	);
115*2bc180efSBaptiste Daroussin #undef MENTRY
116*2bc180efSBaptiste Daroussin #undef EVENTF
117*2bc180efSBaptiste Daroussin }
118*2bc180efSBaptiste Daroussin 
119*2bc180efSBaptiste Daroussin static void
scan_TAG_DIRECTIVE(lyaml_scanner * scanner)120*2bc180efSBaptiste Daroussin scan_TAG_DIRECTIVE (lyaml_scanner *scanner)
121*2bc180efSBaptiste Daroussin {
122*2bc180efSBaptiste Daroussin #define EVENTF(_f)	(scanner->token.data.tag_directive._f)
123*2bc180efSBaptiste Daroussin    lua_State *L = scanner->L;
124*2bc180efSBaptiste Daroussin 
125*2bc180efSBaptiste Daroussin    scanner_push_tokentable (scanner, "TAG_DIRECTIVE", 2);
126*2bc180efSBaptiste Daroussin    RAWSET_EVENTF( handle	);
127*2bc180efSBaptiste Daroussin    RAWSET_EVENTF( prefix	);
128*2bc180efSBaptiste Daroussin #undef EVENTF
129*2bc180efSBaptiste Daroussin }
130*2bc180efSBaptiste Daroussin 
131*2bc180efSBaptiste Daroussin static void
scan_ALIAS(lyaml_scanner * scanner)132*2bc180efSBaptiste Daroussin scan_ALIAS (lyaml_scanner *scanner)
133*2bc180efSBaptiste Daroussin {
134*2bc180efSBaptiste Daroussin #define EVENTF(_f)	(scanner->token.data.alias._f)
135*2bc180efSBaptiste Daroussin    lua_State *L = scanner->L;
136*2bc180efSBaptiste Daroussin 
137*2bc180efSBaptiste Daroussin    scanner_push_tokentable (scanner, "ALIAS", 1);
138*2bc180efSBaptiste Daroussin    RAWSET_EVENTF (value);
139*2bc180efSBaptiste Daroussin #undef EVENTF
140*2bc180efSBaptiste Daroussin }
141*2bc180efSBaptiste Daroussin 
142*2bc180efSBaptiste Daroussin static void
scan_ANCHOR(lyaml_scanner * scanner)143*2bc180efSBaptiste Daroussin scan_ANCHOR (lyaml_scanner *scanner)
144*2bc180efSBaptiste Daroussin {
145*2bc180efSBaptiste Daroussin #define EVENTF(_f)	(scanner->token.data.anchor._f)
146*2bc180efSBaptiste Daroussin    lua_State *L = scanner->L;
147*2bc180efSBaptiste Daroussin 
148*2bc180efSBaptiste Daroussin    scanner_push_tokentable (scanner, "ANCHOR", 1);
149*2bc180efSBaptiste Daroussin    RAWSET_EVENTF (value);
150*2bc180efSBaptiste Daroussin #undef EVENTF
151*2bc180efSBaptiste Daroussin }
152*2bc180efSBaptiste Daroussin 
153*2bc180efSBaptiste Daroussin static void
scan_TAG(lyaml_scanner * scanner)154*2bc180efSBaptiste Daroussin scan_TAG(lyaml_scanner *scanner)
155*2bc180efSBaptiste Daroussin {
156*2bc180efSBaptiste Daroussin #define EVENTF(_f)	(scanner->token.data.tag._f)
157*2bc180efSBaptiste Daroussin    lua_State *L = scanner->L;
158*2bc180efSBaptiste Daroussin 
159*2bc180efSBaptiste Daroussin    scanner_push_tokentable (scanner, "TAG", 2);
160*2bc180efSBaptiste Daroussin    RAWSET_EVENTF( handle	);
161*2bc180efSBaptiste Daroussin    RAWSET_EVENTF( suffix	);
162*2bc180efSBaptiste Daroussin #undef EVENTF
163*2bc180efSBaptiste Daroussin }
164*2bc180efSBaptiste Daroussin 
165*2bc180efSBaptiste Daroussin static void
scan_SCALAR(lyaml_scanner * scanner)166*2bc180efSBaptiste Daroussin scan_SCALAR (lyaml_scanner *scanner)
167*2bc180efSBaptiste Daroussin {
168*2bc180efSBaptiste Daroussin #define EVENTF(_f)	(scanner->token.data.scalar._f)
169*2bc180efSBaptiste Daroussin    lua_State *L = scanner->L;
170*2bc180efSBaptiste Daroussin    const char *style;
171*2bc180efSBaptiste Daroussin 
172*2bc180efSBaptiste Daroussin    switch (EVENTF (style))
173*2bc180efSBaptiste Daroussin    {
174*2bc180efSBaptiste Daroussin #define MENTRY(_s)		\
175*2bc180efSBaptiste Daroussin       case YAML_##_s##_SCALAR_STYLE: style = #_s; break
176*2bc180efSBaptiste Daroussin 
177*2bc180efSBaptiste Daroussin         MENTRY( PLAIN		);
178*2bc180efSBaptiste Daroussin         MENTRY( SINGLE_QUOTED	);
179*2bc180efSBaptiste Daroussin         MENTRY( DOUBLE_QUOTED	);
180*2bc180efSBaptiste Daroussin 	MENTRY( LITERAL		);
181*2bc180efSBaptiste Daroussin 	MENTRY( FOLDED		);
182*2bc180efSBaptiste Daroussin #undef MENTRY
183*2bc180efSBaptiste Daroussin 
184*2bc180efSBaptiste Daroussin       default:
185*2bc180efSBaptiste Daroussin          lua_pushfstring (L, "invalid scalar style %d", EVENTF (style));
186*2bc180efSBaptiste Daroussin          lua_error (L);
187*2bc180efSBaptiste Daroussin    }
188*2bc180efSBaptiste Daroussin 
189*2bc180efSBaptiste Daroussin    scanner_push_tokentable (scanner, "SCALAR", 3);
190*2bc180efSBaptiste Daroussin    RAWSET_EVENTF  (value);
191*2bc180efSBaptiste Daroussin    RAWSET_INTEGER ("length", EVENTF (length));
192*2bc180efSBaptiste Daroussin    RAWSET_STRING  ("style", style);
193*2bc180efSBaptiste Daroussin #undef EVENTF
194*2bc180efSBaptiste Daroussin }
195*2bc180efSBaptiste Daroussin 
196*2bc180efSBaptiste Daroussin static void
scanner_generate_error_message(lyaml_scanner * scanner)197*2bc180efSBaptiste Daroussin scanner_generate_error_message (lyaml_scanner *scanner)
198*2bc180efSBaptiste Daroussin {
199*2bc180efSBaptiste Daroussin    yaml_parser_t *P = &scanner->parser;
200*2bc180efSBaptiste Daroussin    char buf[256];
201*2bc180efSBaptiste Daroussin    luaL_Buffer b;
202*2bc180efSBaptiste Daroussin 
203*2bc180efSBaptiste Daroussin    luaL_buffinit (scanner->L, &b);
204*2bc180efSBaptiste Daroussin    luaL_addstring (&b, P->problem ? P->problem : "A problem");
205*2bc180efSBaptiste Daroussin    snprintf (buf, sizeof (buf), " at document: %d", scanner->document_count);
206*2bc180efSBaptiste Daroussin    luaL_addstring (&b, buf);
207*2bc180efSBaptiste Daroussin 
208*2bc180efSBaptiste Daroussin    if (P->problem_mark.line || P->problem_mark.column)
209*2bc180efSBaptiste Daroussin    {
210*2bc180efSBaptiste Daroussin       snprintf (buf, sizeof (buf), ", line: %lu, column: %lu",
211*2bc180efSBaptiste Daroussin          (unsigned long) P->problem_mark.line + 1,
212*2bc180efSBaptiste Daroussin          (unsigned long) P->problem_mark.column + 1);
213*2bc180efSBaptiste Daroussin       luaL_addstring (&b, buf);
214*2bc180efSBaptiste Daroussin    }
215*2bc180efSBaptiste Daroussin    luaL_addstring (&b, "\n");
216*2bc180efSBaptiste Daroussin 
217*2bc180efSBaptiste Daroussin    if (P->context)
218*2bc180efSBaptiste Daroussin    {
219*2bc180efSBaptiste Daroussin       snprintf (buf, sizeof (buf), "%s at line: %lu, column: %lu\n",
220*2bc180efSBaptiste Daroussin          P->context,
221*2bc180efSBaptiste Daroussin          (unsigned long) P->context_mark.line + 1,
222*2bc180efSBaptiste Daroussin          (unsigned long) P->context_mark.column + 1);
223*2bc180efSBaptiste Daroussin       luaL_addstring (&b, buf);
224*2bc180efSBaptiste Daroussin    }
225*2bc180efSBaptiste Daroussin 
226*2bc180efSBaptiste Daroussin    luaL_pushresult (&b);
227*2bc180efSBaptiste Daroussin }
228*2bc180efSBaptiste Daroussin 
229*2bc180efSBaptiste Daroussin static int
token_iter(lua_State * L)230*2bc180efSBaptiste Daroussin token_iter (lua_State *L)
231*2bc180efSBaptiste Daroussin {
232*2bc180efSBaptiste Daroussin    lyaml_scanner *scanner = (lyaml_scanner *)lua_touserdata(L, lua_upvalueindex(1));
233*2bc180efSBaptiste Daroussin    char *str;
234*2bc180efSBaptiste Daroussin 
235*2bc180efSBaptiste Daroussin    scanner_delete_token (scanner);
236*2bc180efSBaptiste Daroussin    if (yaml_parser_scan (&scanner->parser, &scanner->token) != 1)
237*2bc180efSBaptiste Daroussin    {
238*2bc180efSBaptiste Daroussin       scanner_generate_error_message (scanner);
239*2bc180efSBaptiste Daroussin       return lua_error (L);
240*2bc180efSBaptiste Daroussin    }
241*2bc180efSBaptiste Daroussin 
242*2bc180efSBaptiste Daroussin    scanner->validtoken = 1;
243*2bc180efSBaptiste Daroussin 
244*2bc180efSBaptiste Daroussin    lua_newtable    (L);
245*2bc180efSBaptiste Daroussin    lua_pushliteral (L, "type");
246*2bc180efSBaptiste Daroussin 
247*2bc180efSBaptiste Daroussin    switch (scanner->token.type)
248*2bc180efSBaptiste Daroussin    {
249*2bc180efSBaptiste Daroussin       /* First the simple tokens, generated right here... */
250*2bc180efSBaptiste Daroussin #define MENTRY(_s)			\
251*2bc180efSBaptiste Daroussin       case YAML_##_s##_TOKEN: scanner_push_tokentable (scanner, #_s, 0); break
252*2bc180efSBaptiste Daroussin          MENTRY( STREAM_END		);
253*2bc180efSBaptiste Daroussin          MENTRY( DOCUMENT_START		);
254*2bc180efSBaptiste Daroussin          MENTRY( DOCUMENT_END		);
255*2bc180efSBaptiste Daroussin          MENTRY( BLOCK_SEQUENCE_START	);
256*2bc180efSBaptiste Daroussin          MENTRY( BLOCK_MAPPING_START	);
257*2bc180efSBaptiste Daroussin          MENTRY( BLOCK_END		);
258*2bc180efSBaptiste Daroussin          MENTRY( FLOW_SEQUENCE_START	);
259*2bc180efSBaptiste Daroussin          MENTRY( FLOW_SEQUENCE_END	);
260*2bc180efSBaptiste Daroussin          MENTRY( FLOW_MAPPING_START	);
261*2bc180efSBaptiste Daroussin          MENTRY( FLOW_MAPPING_END	);
262*2bc180efSBaptiste Daroussin 	 MENTRY( BLOCK_ENTRY		);
263*2bc180efSBaptiste Daroussin 	 MENTRY( FLOW_ENTRY		);
264*2bc180efSBaptiste Daroussin 	 MENTRY( KEY			);
265*2bc180efSBaptiste Daroussin 	 MENTRY( VALUE			);
266*2bc180efSBaptiste Daroussin #undef MENTRY
267*2bc180efSBaptiste Daroussin 
268*2bc180efSBaptiste Daroussin       /* ...then the complex tokens, generated by a function call. */
269*2bc180efSBaptiste Daroussin #define MENTRY(_s)		\
270*2bc180efSBaptiste Daroussin       case YAML_##_s##_TOKEN: scan_##_s (scanner); break
271*2bc180efSBaptiste Daroussin          MENTRY( STREAM_START		);
272*2bc180efSBaptiste Daroussin 	 MENTRY( VERSION_DIRECTIVE	);
273*2bc180efSBaptiste Daroussin 	 MENTRY( TAG_DIRECTIVE		);
274*2bc180efSBaptiste Daroussin          MENTRY( ALIAS			);
275*2bc180efSBaptiste Daroussin 	 MENTRY( ANCHOR			);
276*2bc180efSBaptiste Daroussin 	 MENTRY( TAG			);
277*2bc180efSBaptiste Daroussin          MENTRY( SCALAR			);
278*2bc180efSBaptiste Daroussin #undef MENTRY
279*2bc180efSBaptiste Daroussin 
280*2bc180efSBaptiste Daroussin       case YAML_NO_TOKEN:
281*2bc180efSBaptiste Daroussin          lua_pushnil (L);
282*2bc180efSBaptiste Daroussin          break;
283*2bc180efSBaptiste Daroussin       default:
284*2bc180efSBaptiste Daroussin          lua_pushfstring  (L, "invalid token %d", scanner->token.type);
285*2bc180efSBaptiste Daroussin          return lua_error (L);
286*2bc180efSBaptiste Daroussin    }
287*2bc180efSBaptiste Daroussin 
288*2bc180efSBaptiste Daroussin    return 1;
289*2bc180efSBaptiste Daroussin }
290*2bc180efSBaptiste Daroussin 
291*2bc180efSBaptiste Daroussin static int
scanner_gc(lua_State * L)292*2bc180efSBaptiste Daroussin scanner_gc (lua_State *L)
293*2bc180efSBaptiste Daroussin {
294*2bc180efSBaptiste Daroussin    lyaml_scanner *scanner = (lyaml_scanner *) lua_touserdata (L, 1);
295*2bc180efSBaptiste Daroussin 
296*2bc180efSBaptiste Daroussin    if (scanner)
297*2bc180efSBaptiste Daroussin    {
298*2bc180efSBaptiste Daroussin       scanner_delete_token (scanner);
299*2bc180efSBaptiste Daroussin       yaml_parser_delete (&scanner->parser);
300*2bc180efSBaptiste Daroussin    }
301*2bc180efSBaptiste Daroussin    return 0;
302*2bc180efSBaptiste Daroussin }
303*2bc180efSBaptiste Daroussin 
304*2bc180efSBaptiste Daroussin void
scanner_init(lua_State * L)305*2bc180efSBaptiste Daroussin scanner_init (lua_State *L)
306*2bc180efSBaptiste Daroussin {
307*2bc180efSBaptiste Daroussin    luaL_newmetatable (L, "lyaml.scanner");
308*2bc180efSBaptiste Daroussin    lua_pushcfunction (L, scanner_gc);
309*2bc180efSBaptiste Daroussin    lua_setfield      (L, -2, "__gc");
310*2bc180efSBaptiste Daroussin }
311*2bc180efSBaptiste Daroussin 
312*2bc180efSBaptiste Daroussin int
Pscanner(lua_State * L)313*2bc180efSBaptiste Daroussin Pscanner (lua_State *L)
314*2bc180efSBaptiste Daroussin {
315*2bc180efSBaptiste Daroussin    lyaml_scanner *scanner;
316*2bc180efSBaptiste Daroussin    const unsigned char *str;
317*2bc180efSBaptiste Daroussin 
318*2bc180efSBaptiste Daroussin    /* requires a single string type argument */
319*2bc180efSBaptiste Daroussin    luaL_argcheck (L, lua_isstring (L, 1), 1, "must provide a string argument");
320*2bc180efSBaptiste Daroussin    str = (const unsigned char *) lua_tostring (L, 1);
321*2bc180efSBaptiste Daroussin 
322*2bc180efSBaptiste Daroussin    /* create a user datum to store the scanner */
323*2bc180efSBaptiste Daroussin    scanner = (lyaml_scanner *) lua_newuserdata (L, sizeof (*scanner));
324*2bc180efSBaptiste Daroussin    memset ((void *) scanner, 0, sizeof (*scanner));
325*2bc180efSBaptiste Daroussin    scanner->L = L;
326*2bc180efSBaptiste Daroussin 
327*2bc180efSBaptiste Daroussin    /* set its metatable */
328*2bc180efSBaptiste Daroussin    luaL_getmetatable (L, "lyaml.scanner");
329*2bc180efSBaptiste Daroussin    lua_setmetatable  (L, -2);
330*2bc180efSBaptiste Daroussin 
331*2bc180efSBaptiste Daroussin    /* try to initialize the scanner */
332*2bc180efSBaptiste Daroussin    if (yaml_parser_initialize (&scanner->parser) == 0)
333*2bc180efSBaptiste Daroussin       luaL_error (L, "cannot initialize parser for %s", str);
334*2bc180efSBaptiste Daroussin    yaml_parser_set_input_string (&scanner->parser, str, lua_strlen (L, 1));
335*2bc180efSBaptiste Daroussin 
336*2bc180efSBaptiste Daroussin    /* create and return the iterator function, with the loader userdatum as
337*2bc180efSBaptiste Daroussin       its sole upvalue */
338*2bc180efSBaptiste Daroussin    lua_pushcclosure (L, token_iter, 1);
339*2bc180efSBaptiste Daroussin    return 1;
340*2bc180efSBaptiste Daroussin }
341