prepare the ssl module.
[apps/madmutt.git] / tools / cpkg2c.mll
1 (*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or (at
5  *  your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful, but
8  *  WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  *  General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
15  *  MA 02110-1301, USA.
16  *
17  *  Copyright © 2007 Pierre Habouzit
18  *)
19 {
20   open Printf
21   module L = Lexing
22   module H = Hashtbl
23   module B = Buffer
24
25   type 'a anchor   = ('a * string * int)
26   let t1 (a, _, _) = a
27
28   let die lpos fpos s =
29     output_string stderr (sprintf "%s:%d: %s\n" fpos lpos s);
30     exit 1
31
32   let put_line = printf "#line %d \"%s\"\n"
33
34   let isspace = function |' '|'\t' -> true | _ -> false
35
36   let strip s =
37     let l = ref 0 and r = ref (String.length s) in
38     while (isspace s.[!l]     && !l < !r) do incr l done;
39     while (isspace s.[!r - 1] && !l < !r) do decr r done;
40     String.sub s !l (!r - !l)
41
42 (* @types related {{{ *)
43
44   type typedef =
45     { lpos: int; fpos: string;
46       ctype: string anchor;
47       check: string anchor;
48       push : string anchor;
49       ctor : string anchor option;
50       dtor : string anchor option;
51     }
52   let typedef0 =
53     { lpos  = 0; fpos = "";
54       ctype = "", "", 0;
55       check = "", "", 0;
56       push  = "", "", 0;
57       ctor  = None;
58       dtor = None
59     }
60   let types = H.create 1031
61
62
63   let (@:=) id  t =
64     List.iter (function ((s,_,_), x) -> if String.length s == 0 then
65       die t.lpos t.fpos (sprintf "type `%s' has no `%s' set" id x))
66     [(t.ctype, "ctype"); (t.check, "check"); (t.push, "push")];
67     H.add types id t
68
69 (* }}} *)
70 (* @packages related {{{ *)
71
72   type typinst = bool * typedef
73
74   type members =
75     { typ: typinst; mname: string;
76       init: string anchor; onchange: string anchor option; }
77   let member0 =
78     { typ   = false, typedef0;
79       mname = "";
80       init = "", "", 0;
81       onchange = None;
82     }
83
84   type methods =
85     { rettype: typinst list; args: (typinst * string) list;
86       fname: string; body: string }
87
88   type package =
89     { line: int; file: string; name: string;
90       members: members anchor list;
91       methods: methods anchor list;
92       static: bool;
93     }
94
95   let newpkg lpos fpos name static =
96     { static = static; line = lpos; file = fpos; name = name; members = []; methods = []; }
97
98   let type_find lpos fpos t =
99     try Hashtbl.find types t
100     with Not_found -> die lpos fpos (sprintf "Unknown type `%s'" t)
101
102   let parse_rettype lpos fpos s =
103     let aux t =
104       match Str.split (Str.regexp "[ \t]+") t with
105       | ["const"; t] -> (true,  type_find lpos fpos t)
106       | [t]          -> (false, type_find lpos fpos t)
107       | _ -> assert false
108     in
109     match strip s with
110     | "void" -> []
111     | s      -> List.map aux (Str.split (Str.regexp "[ \t]*,[ \t]*") s)
112
113   let parse_args lpos fpos s =
114     let aux t =
115       match Str.split (Str.regexp "[ \t]+") t with
116       | ["const"; t; n] -> ((true,  type_find lpos fpos t), n)
117       | [t; n]          -> ((false, type_find lpos fpos t), n)
118       | _ -> assert false
119     in
120     match strip s with
121     | "void" -> []
122     | s      -> List.map aux (Str.split (Str.regexp "[ \t]*,[ \t]*") s)
123
124 (* }}} *)
125 (* parsing helpers {{{ *)
126
127   type stanza = Buf of string anchor | Pkg of package
128
129   let nextl lexbuf =
130     let pos = lexbuf.L.lex_curr_p in
131     lexbuf.L.lex_curr_p <-
132       { pos with
133         L.pos_lnum = pos.L.pos_lnum + 1;
134         L.pos_bol  = pos.L.pos_cnum; };
135     lexbuf
136   ;;
137
138   let lnum lexbuf = lexbuf.L.lex_curr_p.L.pos_lnum
139
140   let (@.)  buf s = B.add_string buf s; buf
141   let (@<)  buf c = B.add_char   buf c; buf
142
143   let getchunk lpos fpos buf lexbuf =
144     let res = B.contents buf in
145     B.clear buf;
146     Buf(res, fpos, lpos)
147
148   let startchunk f fpos lexbuf =
149     f (lnum lexbuf) fpos (B.create 4096) lexbuf
150
151   let newchunk f lpos fpos buf lexbuf =
152     let res = getchunk lpos fpos buf lexbuf in
153     res::(f (lnum lexbuf, fpos) buf lexbuf)
154
155   let find_import relpath file =
156     if Filename.is_relative file then
157       match Filename.dirname relpath with
158       | "." -> file
159       | s   -> Filename.concat s file
160     else
161       file
162
163 (* }}} *)
164 }
165
166 (* regex aliases {{{ *)
167
168 let to_eol = [^'\n']* '\n'
169 let ident  = ['a'-'z''A'-'Z''_']['a'-'z''A'-'Z''_''0'-'9']*
170 let sp     = [' ''\t']
171
172 let typdecl = sp* ("const" sp+)? ident sp*
173
174 (* }}} *)
175 (* entry point {{{ *)
176
177 rule cLine lpos fpos buf = parse
178 | sp* "@type" sp+ (ident as id) sp* (':' sp* (ident as id0) sp*)? '{'
179                     {
180                       let line = lnum lexbuf in
181                       let t0 = match id0 with
182                       | None     -> typedef0
183                       | Some id0 ->
184                           try H.find types id0
185                           with Not_found ->
186                             die line fpos (sprintf "Uknown type `%s'" id0)
187                       in try
188                         let t = H.find types id in
189                         die line fpos
190                           (sprintf "type `%s' already defined at %s:%d"
191                             id t.fpos t.lpos)
192                       with Not_found ->
193                         (getchunk lpos fpos buf lexbuf) :: (
194                           ext_type id {t0 with lpos = line; fpos = fpos}
195                             lexbuf
196                         )
197                     }
198 | sp* "@import" sp+ '"' ([^'"''\n']* as file) '"' sp* '\n'
199                     {
200                       let file = find_import fpos file in
201                       let _ = startchunk cLine file
202                                 (L.from_channel (open_in file)) in
203                       cLine lpos fpos (buf @< '\n') (nextl lexbuf)
204                     }
205 | sp* ("@package"|"@static_package" as kw) sp+ (ident as pkg) sp* '{'
206                     {
207                       let a = getchunk lpos fpos buf lexbuf in
208                       let line = lnum lexbuf in
209                       a::(ext_pkg (newpkg line fpos pkg
210                                     (kw = "@static_package")) lexbuf)
211                     }
212 | sp* '@'           { die (lnum lexbuf) fpos "Syntax error" }
213 | sp* '#' as s      { let buf = cPP (buf @. s) lexbuf in
214                       cLine lpos fpos buf lexbuf }
215 | ""                { let buf = cCode buf lexbuf in
216                       cLine lpos fpos buf lexbuf }
217 | eof               { [getchunk lpos fpos buf lexbuf] }
218
219 (* }}} *)
220 (* cCode block parser {{{ *)
221
222 and cCode buf = parse
223 | '\n'    as c      { let _ = nextl lexbuf in buf @< c }
224 | '"'     as c      { let buf = cString (buf @< c) lexbuf in
225                       cCode buf lexbuf }
226 | "/*"    as s      { let buf = cComment (buf @. s) lexbuf in
227                       cCode buf lexbuf }
228 | "//" to_eol as s  { cCode (buf @. s) (nextl lexbuf) }
229 | "'\"'"  as s      { cCode (buf @. s) lexbuf }
230 | _       as c      { cCode (buf @< c) lexbuf }
231
232 (* }}} *)
233 (* helper rules: comment, string, cPP {{{ *)
234
235 and cComment buf = parse
236 | "*/"    as s { buf @. s }
237 | '\n'    as c { cComment (buf @< c) (nextl lexbuf) }
238 | _       as c { cComment (buf @< c) lexbuf }
239
240 and cString buf = parse
241 | '"'     as c { buf @< c }
242 | "\\\""  as s { cString (buf @. s) lexbuf }
243 | "\\\n"  as s { cString (buf @. s) (nextl lexbuf) }
244 | [^'\n'] as c { cString (buf @< c) lexbuf }
245
246 and cPP buf = parse
247 | [^'\n']* "\\\n" as s { cPP (buf @. s) (nextl lexbuf) }
248 | to_eol          as s { let _ = nextl lexbuf in buf @. s }
249
250 (* }}} *)
251 (* parse @type {{{ *)
252
253 and ext_type id typ = parse
254 | sp+
255 | "//" to_eol       { ext_type id typ lexbuf }
256 | '\n'              { ext_type id typ (nextl lexbuf) }
257 | "/*"              { let _ = cComment (B.create 1024) lexbuf in
258                       ext_type id typ lexbuf }
259 | '.' (ident as member) sp* '=' sp* ([^';''\n']+ as s) ';'
260                     {
261                       ext_type id (
262                         let do_anch s = s, typ.fpos, lnum lexbuf in
263                         match member with
264                         | "ctype" -> {typ with ctype = do_anch s}
265                         | "check" -> {typ with check = do_anch s}
266                         | "push"  -> {typ with push  = do_anch s}
267                         | "ctor"  -> {typ with ctor  = Some (do_anch s)}
268                         | "dtor"  -> {typ with dtor  = Some (do_anch s)}
269                         | _       ->
270                             die (lnum lexbuf) typ.fpos
271                               (sprintf "Unknown directive `%s'" member)
272                       ) lexbuf
273                     }
274 | '}' sp* ';' (sp* '\n' as s)?
275                     { id @:= typ; startchunk cLine typ.fpos
276                       (if s = None then lexbuf else nextl lexbuf) }
277 | ""                { die (lnum lexbuf) typ.fpos "Syntax error" }
278
279 (* }}} *)
280 (* parse @package {{{ *)
281
282 and ext_pkg pkg = parse
283 | sp+
284 | "//" to_eol       { ext_pkg pkg lexbuf }
285 | '\n'              { ext_pkg pkg (nextl lexbuf) }
286 | "/*"              { let _ = cComment (B.create 1024) lexbuf in
287                       ext_pkg pkg lexbuf }
288 | ("const" sp+ as const)? (ident as typ) sp+
289   (ident as member) sp* '=' sp* '{'
290                     {
291                       let m = {member0 with mname = member;
292                                typ = const != None, type_find (lnum lexbuf)
293                                pkg.file typ; } in
294                       let m = ext_member m pkg.file lexbuf in
295                       ext_pkg {pkg with members = (m, pkg.file, lnum lexbuf)::pkg.members} lexbuf
296                     }
297 | ("const" sp+ as const)? (ident as typ) sp+
298   (ident as member) sp* '=' sp* ([^';''\n']* as init)';'
299                     {
300                       let m = { typ   = const != None,
301                                         type_find (lnum lexbuf) pkg.file typ;
302                                 mname = member;
303                                 init  = init, pkg.file, lnum lexbuf;
304                                 onchange = None; }, pkg.file, lnum lexbuf in
305                       ext_pkg {pkg with members = m::pkg.members} lexbuf
306                     }
307 | '(' ((typdecl ',')* typdecl as ret) ')' sp*
308    (ident as fname)
309    '('((typdecl ident sp* ',')* typdecl ident sp* as args)')' sp*
310 | (typdecl as ret) (ident as fname)
311    '('((typdecl ident sp* ',')* typdecl ident sp* as args)')' sp*
312                     {
313                       let rettype = parse_rettype (lnum lexbuf) pkg.file ret in
314                       let args    = parse_args    (lnum lexbuf) pkg.file args in
315                       let body    = ext_body pkg (B.create 1024) lexbuf in
316                       let m       = { rettype = rettype;
317                                       args = args;
318                                       fname = fname;
319                                       body = body }, pkg.file, lnum lexbuf in
320                       ext_pkg {pkg with methods = m::pkg.methods} lexbuf
321                     }
322 | '}' sp* ';' (sp* '\n' as s)?
323                     { Pkg({pkg with members = List.rev(pkg.members)}) :: (
324                         startchunk cLine pkg.file
325                         (if s = None then lexbuf else nextl lexbuf)
326                       )
327                     }
328 | ""                { die (lnum lexbuf) pkg.file "Syntax error" }
329
330 and ext_body pkg buf = parse
331 | sp+         as s
332 | "//" to_eol as s  { ext_body pkg (buf @. s) lexbuf }
333 | '\n'        as c  { ext_body pkg (buf @< c) lexbuf }
334 | "/*"              { let buf = cComment (buf @. "/*") lexbuf in
335                       ext_body pkg buf lexbuf }
336 | ';'               { B.contents buf }
337 | '{'         as c  { let buf = ext_bodycode (buf @< c) lexbuf in
338                       ext_body pkg buf lexbuf }
339 | ""                { die (lnum lexbuf) pkg.file "Syntax error" }
340
341 and ext_bodycode buf = parse
342 | '\n'    as c      { ext_bodycode (buf @< c) (nextl lexbuf) }
343 | '"'     as c      { let buf = cString (buf @< c) lexbuf in
344                       ext_bodycode buf lexbuf }
345 | "/*"    as s      { let buf = cComment (buf @. s) lexbuf in
346                       ext_bodycode buf lexbuf }
347 | "//" to_eol as s  { ext_bodycode (buf @. s) (nextl lexbuf) }
348 | "'\"'"  as s      { ext_bodycode (buf @. s) lexbuf }
349 | '{'     as c      { let buf = ext_bodycode (buf @< c) lexbuf in ext_bodycode buf lexbuf }
350 | '}'     as c      { buf @< c }
351 | _       as c      { ext_bodycode (buf @< c) lexbuf }
352
353 (* }}} *)
354 (* parse extended member {{{ *)
355
356 and ext_member m f = parse
357 | sp+
358 | "//" to_eol       { ext_member m f lexbuf }
359 | '\n'              { ext_member m f (nextl lexbuf) }
360 | "/*"              { let _ = cComment (B.create 1024) lexbuf in
361                       ext_member m f lexbuf }
362 | '.' (ident as member) sp* '=' sp* ([^';''\n']+ as s) ';'
363                     {
364                       ext_member (
365                         let do_anch s = s, f, lnum lexbuf in
366                         match member with
367                         | "init"     -> {m with init = do_anch s}
368                         | "onchange" -> {m with onchange = Some(do_anch s)}
369                         | _       ->
370                             die (lnum lexbuf) f
371                               (sprintf "Unknown directive `%s'" member)
372                       ) f lexbuf
373                     }
374 | '}' sp* ';'       { m }
375 | ""                { die (lnum lexbuf) f "Syntax error" }
376
377 (* }}} *)
378
379 {
380 (* templating functions {{{ *)
381
382   let upper = String.uppercase
383   let tplize tpl v =
384     Str.global_replace (Str.regexp_string "$L") "L" (
385       Str.global_replace (Str.regexp_string "$$") v tpl
386     )
387
388   let dump_struct_type begwith pkg endwith =
389     printf "%sstruct luaM_%s_t {\n" begwith pkg.name;
390     List.iter (function (m, f, l) ->
391       put_line l f;
392       let ctype = t1 (snd m.typ).ctype in
393       print_string "    ";
394       if fst m.typ then print_string "const ";
395       let i = try String.index ctype ':' with Not_found -> String.length ctype in
396       printf "%s %s%s;\n" (Str.string_before ctype i)
397         m.mname (Str.string_after ctype i)
398     ) pkg.members;
399     print_endline ("}" ^ endwith)
400
401   let do_h =
402     let do_h_aux = function
403       | Buf _ -> ()
404       | Pkg pkg ->
405           printf "\n#ifndef MUTT_LUA_%s_H\n" (upper pkg.name);
406           printf "#define MUTT_LUA_%s_H\n\n" (upper pkg.name);
407           if not pkg.static then (
408             dump_struct_type "" pkg ";";
409             printf "extern struct luaM_%s_t %s;\n" pkg.name pkg.name;
410           );
411           printf "\nint luaopen_%s(lua_State *L);\n\n" pkg.name;
412           printf "#endif /* MUTT_LUA_%s_H */\n" (upper pkg.name);
413     in List.iter do_h_aux
414
415   let do_func pkg (fn, f, l) = 
416     (* return inline function *)
417     printf "\nstatic int luaM_ret_%s_%s(lua_State *L" pkg.name fn.fname;
418     let retlen = List.fold_left (fun i t ->
419       let i = i + 1 in
420       match t with
421       | true, typ -> printf ", const %s luaM_x%d" (t1 typ.ctype) i; i
422       | false, typ -> printf ", %s luaM_x%d" (t1 typ.ctype) i; i
423       ) 0 fn.rettype in
424     printf ")\n{\n";
425     ignore (List.fold_left (fun i (const, typ) ->
426       let i = i + 1 in
427       let (p, f, l) = typ.push in
428       put_line l f;
429       printf "    %s;\n" (tplize p (sprintf "luaM_x%d" i));
430       if not const then (
431         match typ.dtor with
432         | None             -> ()
433         | Some(dtor, f, l) ->
434             put_line l f;
435             printf "    %s;\n" (tplize dtor (sprintf "&luaM_x%d" i))
436       ); i
437     ) 0 fn.rettype) ;
438     printf "    return %d;\n}\n" retlen;
439
440     (* main function *)
441     printf "\nstatic int luaM_%s_%s(lua_State *L)\n{\n" pkg.name fn.fname;
442     ignore (List.fold_left (fun i ((const, typ), name) ->
443       let i = i + 1 in
444       let ctype = t1 typ.ctype in
445       if const then (
446         let (c, f, l) = typ.check in
447         put_line l f;
448         printf "    const %s %s = %s;\n" ctype name (tplize c (string_of_int i))
449       ) else (
450         match typ.ctor with
451         | None ->
452           let (c, f, l) = typ.check in
453           put_line l f;
454           printf "    %s %s = %s;\n" ctype name (tplize c (string_of_int i))
455         | Some (ctor, f, l) ->
456           let v =
457             let c, f, l = typ.check in
458             tplize (sprintf "\n#line %d \"%s\"\n        %s" l f c)
459               (string_of_int i)
460           in
461           put_line l f;
462           printf "    %s %s = %s;\n" ctype name (tplize ctor v)
463       ); i
464     ) 0 fn.args);
465     printf "\n#define RAISE(s)  luaL_error(L, (s))\n";
466     if fn.rettype = [] then (
467       printf "#define RETURN()  return luaM_ret_%s_%s(L)\n" pkg.name fn.fname
468     ) else (
469       printf "#define RETURN(luaM_x1";
470       for i = 2 to retlen do printf ", luaM_x%d" i done;
471       printf ") \\\n        return luaM_ret_%s_%s(L" pkg.name fn.fname;
472       for i = 1 to retlen do printf ", luaM_x%d" i done;
473       printf ")\n"
474     );
475     put_line l f;
476     printf "    %s\n#undef RAISE\n#undef RETURN\n}\n" fn.body
477
478   let do_c =
479     let do_c_aux = function
480       | Buf (s, f, l) -> put_line l f; print_string s
481       | Pkg pkg       ->
482           (* dump struct const init *)
483           (if pkg.static then
484             dump_struct_type "static " pkg (sprintf " %s = {\n" pkg.name)
485           else
486             printf "struct luaM_%s_t %s = {\n" pkg.name pkg.name
487           );
488           List.iter (function (m, _, _) ->
489               let (init, f, l) = m.init in
490               put_line l f;
491               printf "    %s,\n" (if fst m.typ then init else "0")
492             ) pkg.members;
493           printf "};\n";
494
495           (* dump struct init func *)
496           printf "\nstatic void %s_init(void)\n{\n" pkg.name;
497           List.iter (function (m, _, _) ->
498             if not (fst m.typ) then
499               let init, f, l = m.init in
500               let field = sprintf "%s.%s" pkg.name m.mname in
501               put_line l f;
502               printf "    %s = %s;\n" field init;
503               match m.onchange with
504               | None           -> ()
505               | Some(on, f, l) ->
506                   put_line l f; printf "    %s;\n" (tplize on field)
507             ) pkg.members;
508           printf "};\n\n";
509
510           (* dump __index *)
511           printf "static int luaM_%s_index(lua_State *L)\n{\n" pkg.name;
512           printf "    const char *idx = luaL_checkstring(L, 2);\n\n";
513           printf "    switch (mlua_which_token(idx, -1)) {\n";
514           List.iter (function (m, _, _) ->
515             printf "      case LTK_%s:\n" (upper m.mname);
516             let push, f, l = (snd m.typ).push in
517             put_line l f;
518             printf "        %s;\n" (tplize push (sprintf "%s.%s" pkg.name m.mname));
519             printf "        return 1;\n"
520           ) pkg.members;
521           printf "      default:\n";
522           printf "        lua_rawget(L, lua_upvalueindex(1));\n";
523           printf "        return 1;\n";
524           printf "    }\n}\n\n";
525
526           (* dump __newindex *)
527           printf "static int luaM_%s_newindex(lua_State *L)\n{\n" pkg.name;
528           printf "    const char *idx = luaL_checkstring(L, 2);\n\n";
529           printf "    switch (mlua_which_token(idx, -1)) {\n";
530           List.iter (function (m, _, _) ->
531             let field = sprintf "%s.%s" pkg.name m.mname in
532             match m.typ with
533             | true, _ -> ()
534             | false, t ->
535               printf "      case LTK_%s:\n" (upper m.mname);
536               (match t.dtor with
537               | None -> ()
538               | Some (dtor, f, l) ->
539                   put_line l f;
540                   printf "        %s;\n" (tplize dtor ("&" ^ field))
541               );
542               (match t.ctor with
543               | None ->
544                   let (c, f, l) = t.check in
545                   put_line l f;
546                   printf "        %s = %s;\n" field (tplize c "3")
547               | Some (ctor, f, l) ->
548                   let v =
549                     let c, f, l = t.check in
550                     tplize (sprintf "\n#line %d \"%s\"\n            %s" l f c) "3"
551                   in
552                   put_line l f;
553                   printf "        %s = %s;\n" field (tplize ctor v)
554               );
555               (match m.onchange with
556               | None           -> ()
557               | Some(on, f, l) ->
558                   put_line l f;
559                   printf "        %s;\n" (tplize on field)
560               );
561               printf "        return 1;\n"
562           ) pkg.members;
563           printf "      default:\n";
564           printf "        lua_rawset(L, lua_upvalueindex(1));\n";
565           printf "        return 1;\n";
566           printf "    }\n}\n";
567
568           (* dump methods *)
569           List.iter (do_func pkg) pkg.methods;
570           printf "\nstatic const luaL_reg luaM_%s_methods[] = {\n" pkg.name;
571           List.iter (function (f, _, _) ->
572               printf "    { \"%s\", luaM_%s_%s },\n" f.fname pkg.name f.fname)
573             pkg.methods;
574           print_string (Str.global_replace (Str.regexp "%s") pkg.name
575 "    { NULL, NULL },
576 };
577
578 int luaopen_%s(lua_State *L)
579 {
580     int mt, members, methods;
581
582     %s_init();
583
584     /* create methods table, add it the the table of globals */
585     luaL_openlib(L, \"%s\", luaM_%s_methods, 0);
586     methods = lua_gettop(L);
587
588     lua_newtable(L);                            /* for new members   */
589     members = lua_gettop(L);
590
591     /* create metatable for %s, add it to the registry */
592     luaL_newmetatable(L, \"%s\");
593     mt = lua_gettop(L);
594
595     lua_pushliteral(L, \"__index\");
596     lua_pushvalue(L, members);                  /* upvalue  1        */
597     lua_pushcclosure(L, &luaM_%s_index, 1);
598     lua_rawset(L, mt);                          /* set mt.__index    */
599
600     lua_pushliteral(L, \"__newindex\");
601     lua_pushvalue(L, members);                  /* upvalue  1        */
602     lua_pushcclosure(L, &luaM_%s_newindex, 1);
603     lua_rawset(L, mt);                          /* set mt.__newindex */
604
605     lua_pushliteral(L, \"__metatable\");
606     lua_pushvalue(L, methods);                  /* dup methods table */
607     lua_rawset(L, mt);                          /* hide metatable    */
608
609     lua_setmetatable(L, methods);
610
611     lua_pop(L, 3);
612     return 1;
613 }
614
615 ")
616     in List.iter do_c_aux
617
618 (* }}} *)
619
620   let usage () =
621     output_string stderr "usage: cpkg2c (-h | -c) file.cpkg\n";
622     exit 1
623
624   let _ =
625     let warn () = print_endline "/*** THIS FILE IS AUTOGENERATED !!! ***/" in
626     if Array.length Sys.argv <= 2 then usage();
627     let file   = Sys.argv.(2) in
628     let lexbuf = L.from_channel (open_in file) in
629     let l      = (startchunk cLine file lexbuf) in
630     match Sys.argv.(1) with
631     | "-h" -> warn (); do_h l
632     | "-c" -> warn (); do_c l
633     | _    -> usage ()
634 }