some progress on graphic object access
[mplib] / src / texk / web2c / mpdir / lmplib.c
1 /* $Id$ */
2
3 #include <lua.h>
4 #include <lauxlib.h>
5 #include <lualib.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9
10 #include "mplib.h"
11 #include "mpmp.h"
12 #include "mppsout.h" /* for mp_edge_object */
13
14 #define MPLIB_METATABLE     "MPlib"
15 #define MPLIB_FIG_METATABLE "MPlib.fig"
16 #define MPLIB_GR_METATABLE  "MPlib.gr"
17
18 #define xfree(A) if (A!=NULL) free(A)
19
20 #define is_mp(L,b) (MP *)luaL_checkudata(L,b,MPLIB_METATABLE)
21 #define is_fig(L,b) (struct mp_edge_object **)luaL_checkudata(L,b,MPLIB_FIG_METATABLE)
22 #define is_gr_object(L,b) (struct mp_graphic_object **)luaL_checkudata(L,b,MPLIB_GR_METATABLE)
23
24 typedef enum {  
25   P__ZERO,       P_ERROR_LINE,  P_HALF_LINE,   P_MAX_LINE,    P_MAIN_MEMORY, 
26   P_HASH_SIZE,   P_HASH_PRIME,  P_PARAM_SIZE,  P_IN_OPEN,     P_RANDOM_SEED, 
27   P_INTERACTION, P_INI_VERSION, P_TROFF_MODE,  P_PRINT_NAMES, P_COMMAND_LINE,
28   P_MEM_NAME,    P_JOB_NAME,    P_FIND_FILE,   P_OPEN_FILE,   P_CLOSE_FILE,  
29   P_EOF_FILE,    P_FLUSH_FILE,  P_WRITE_ASCII, P_READ_ASCII,  P_WRITE_BINARY,
30   P_READ_BINARY, P_RUN_EDITOR,  P_RUN_MAKEMPX, P_SHIPOUT,     P__SENTINEL,
31 } parm_idx;
32
33 typedef struct {
34     const char *name;           /* parameter name */
35     parm_idx idx;               /* parameter index */
36     int class;                  /* parameter class */
37 } parm_struct;
38
39 const char *interaction_options[] = 
40   { "unknownmode","batchmode","nonstopmode","scrollmode","errorstopmode", NULL};
41
42
43 parm_struct img_parms[] = {
44   {NULL,                P__ZERO,       0   },  /* dummy; lua indices run from 1 */
45   {"error_line",        P_ERROR_LINE,  'i' },
46   {"half_error_line",   P_HALF_LINE,   'i' },
47   {"max_print_line",    P_MAX_LINE,    'i' },
48   {"main_memory",       P_MAIN_MEMORY, 'i' },
49   {"hash_size",         P_HASH_SIZE,   'i' },
50   {"hash_prime",        P_HASH_PRIME,  'i' },
51   {"param_size",        P_PARAM_SIZE,  'i' },
52   {"max_in_open",       P_IN_OPEN,     'i' },
53   {"random_seed",       P_RANDOM_SEED, 'i' },
54   {"interaction",       P_INTERACTION, 'e' },
55   {"ini_version",       P_INI_VERSION, 'b' },
56   {"troff_mode",        P_TROFF_MODE,  'b' },
57   {"print_found_names", P_PRINT_NAMES, 'b' },
58   {"command_line",      P_COMMAND_LINE,'s' },
59   {"mem_name",          P_MEM_NAME,    's' },
60   {"job_name",          P_JOB_NAME,    's' },
61   {"find_file",         P_FIND_FILE,   'p' }, /* intercepted */
62 #if 0
63   {"open_file",         P_OPEN_FILE,   'p' },
64   {"close_file",        P_CLOSE_FILE,  'p' },
65   {"eof_file",          P_EOF_FILE,    'p' },
66   {"flush_file",        P_FLUSH_FILE,  'p' },
67   {"write_ascii_file",  P_WRITE_ASCII, 'p' },
68   {"read_ascii_file",   P_READ_ASCII,  'p' },
69   {"write_binary_file", P_WRITE_BINARY,'p' },
70   {"read_binary_file",  P_READ_BINARY, 'p' },
71   {"run_editor",        P_RUN_EDITOR,  'p' },
72   {"run_make_mpx",      P_RUN_MAKEMPX, 'p' },
73   {"shipout_backend",   P_SHIPOUT,     'p' },
74 #endif
75   {NULL,                P__SENTINEL,   0   }
76 };
77
78 typedef struct _FILE_ITEM {
79   FILE *f;
80 } _FILE_ITEM ;
81
82 typedef struct _FILE_ITEM File;
83
84 /* Start by defining all the callback routines for the library 
85  * except |run_make_mpx| and |run_editor|.
86  */
87
88 char *mplib_filetype_names[] = {"term", "error", "mp", "log", "ps",
89                               "mem", "tfm", "map", "pfb", "enc", NULL};
90
91 lua_State *LL = NULL;
92
93 char *mplib_find_file (char *fname, char *fmode, int ftype)  {
94   if (LL!=NULL) {
95     lua_State *L = LL;
96     lua_checkstack(L,4);
97     lua_getfield(L,LUA_REGISTRYINDEX,"mplib_file_finder");
98     if (lua_isfunction(L,-1)) {
99       char *s = NULL, *x = NULL;
100       lua_pushstring(L, fname);
101       lua_pushstring(L, fmode);
102       if (ftype >= mp_filetype_text) {
103         lua_pushnumber(L, ftype-mp_filetype_text);
104       } else {
105         lua_pushstring(L, mplib_filetype_names[ftype]);
106       }
107       if(lua_pcall(L,3,1,0) != 0) {
108         fprintf(stdout,"Error in mp.find_file: %s\n", (char *)lua_tostring(L,-1));
109         return NULL;
110       }
111       x = (char *)lua_tostring(L,-1);
112       if (x!=NULL)
113         s = strdup(x);
114       lua_pop(L,1); /* pop the string */
115       return s;
116     } else {
117       lua_pop(L,1);
118     }
119   }
120   if (fmode[0] != 'r' || (! access (fname,R_OK)) || ftype) {  
121      return strdup(fname);
122   }
123   return NULL;
124 }
125
126 static int 
127 mplib_find_file_function (lua_State *L) {
128   if (lua_isfunction(L,-1)) {
129     LL =  L;
130   } else if (lua_isnil(L,-1)) {
131     LL = NULL;
132   } else {
133     return 1; /* error */
134   }
135   lua_pushstring(L, "mplib_file_finder");
136   lua_pushvalue(L,-2);
137   lua_rawset(L,LUA_REGISTRYINDEX);
138   return 0;
139 }
140
141 void *term_file_ptr = NULL;
142 void *err_file_ptr = NULL;
143 void *log_file_ptr = NULL;
144 void *ps_file_ptr = NULL;
145
146 void *mplib_open_file(char *fname, char *fmode, int ftype)  {
147   File *ff = malloc(sizeof (File));
148   if (ff) {
149     ff->f = NULL;
150     if (ftype==mp_filetype_terminal) {
151       if (fmode[0] == 'r') {
152         ff->f = stdin;
153       } else {
154         xfree(term_file_ptr); 
155         ff->f = malloc(1);
156         term_file_ptr = ff->f;
157       }
158     } else if (ftype==mp_filetype_error) {
159       xfree(err_file_ptr); 
160       ff->f = malloc(1);
161       err_file_ptr = ff->f;
162     } else if (ftype == mp_filetype_log) {
163       xfree(log_file_ptr); 
164       ff->f = malloc(1);
165       log_file_ptr = ff->f;
166     } else if (ftype == mp_filetype_postscript) {
167       xfree(ps_file_ptr); 
168       ff->f = malloc(1);
169       ps_file_ptr = ff->f;
170     } else { 
171       char *f = fname;
172       if (fmode[0] == 'r') {
173         f = mplib_find_file(fname,fmode,ftype);
174         if (f==NULL)
175           return NULL;
176       }
177       ff->f = fopen(f, fmode);
178       if ((fmode[0] == 'r') && (ff->f == NULL)) {
179         free(ff);
180         return NULL;  
181       }
182     }
183     return ff;
184   }
185   return NULL;
186 }
187
188 static char * input_data = NULL;
189 static char * input_data_ptr = NULL;
190 static size_t input_data_len = 0;
191
192 #define GET_CHAR() do {                                                 \
193     if (f==stdin && input_data != NULL) {                               \
194       if (input_data_len==0) {                                          \
195         if (input_data_ptr!=NULL)                                       \
196           input_data_ptr = NULL;                                        \
197         else                                                            \
198           input_data = NULL;                                            \
199         c = EOF;                                                        \
200       } else {                                                          \
201         input_data_len--;                                               \
202         c = *input_data_ptr++;                                          \
203       }                                                                 \
204     } else {                                                            \
205       c = fgetc(f);                                                     \
206     }                                                                   \
207   } while (0)
208
209 #define UNGET_CHAR() do {                                               \
210     if (f==stdin && input_data != NULL) {                               \
211       input_data_len++; input_data_ptr--;                               \
212     } else {                                                            \
213       ungetc(c,f);                                                      \
214     }                                                                   \
215   } while (0)
216
217
218 char *mplib_read_ascii_file (void *ff, size_t *size) {
219   int c;
220   size_t len = 0, lim = 128;
221   char *s = NULL;
222   if (ff!=NULL) {
223     FILE *f = ((File *)ff)->f;
224     if (f==NULL)
225       return NULL;
226     *size = 0;
227     GET_CHAR();
228     if (c==EOF)
229       return NULL;
230     s = malloc(lim); 
231     if (s==NULL) return NULL;
232     while (c!=EOF && c!='\n' && c!='\r') { 
233       if (len==lim) {
234         s =realloc(s, (lim+(lim>>2)));
235         if (s==NULL) return NULL;
236         lim+=(lim>>2);
237       }
238       s[len++] = c;
239       GET_CHAR();
240     }
241     if (c=='\r') {
242       GET_CHAR();
243       if (c!=EOF && c!='\n')
244         UNGET_CHAR();
245     }
246     s[len] = 0;
247     *size = len;
248   }
249   return s;
250 }
251
252 static char *term_out = NULL;
253 static char *error_out = NULL;
254 static char *log_out = NULL;
255 static char *ps_out = NULL;
256
257 #define APPEND_STRING(a,b) do {                 \
258     if (a==NULL) {                              \
259       a = strdup(b);                            \
260     } else {                                    \
261       a = realloc(a, strlen(a)+strlen(b)+1);    \
262       strcpy(a+strlen(a),b);                    \
263     }                                           \
264   } while (0)
265
266 void mplib_write_ascii_file (void *ff, char *s) {
267   if (ff!=NULL) {
268     void *f = ((File *)ff)->f;
269     if (f!=NULL) {
270       if (f==term_file_ptr) {
271         APPEND_STRING(term_out,s);
272       } else if (f==err_file_ptr) {
273         APPEND_STRING(error_out,s);
274       } else if (f==log_file_ptr) {
275         APPEND_STRING(log_out,s);
276       } else if (f==ps_file_ptr) {
277         APPEND_STRING(ps_out,s);
278       } else {
279         fprintf((FILE *)f,s);
280       }
281     }
282   }
283 }
284
285 void mplib_read_binary_file (void *ff, void **data, size_t *size) {
286   size_t len = 0;
287   if (ff!=NULL) {
288     FILE *f = ((File *)ff)->f;
289     if (f!=NULL) 
290       len = fread(*data,1,*size,f);
291     *size = len;
292   }
293 }
294
295 void mplib_write_binary_file (void *ff, void *s, size_t size) {
296   if (ff!=NULL) {
297     FILE *f = ((File *)ff)->f;
298     if (f!=NULL)
299       fwrite(s,size,1,f);
300   }
301 }
302
303
304 void mplib_close_file (void *ff) {
305   if (ff!=NULL) {
306     void *f = ((File *)ff)->f;
307     if (f != NULL && f != term_file_ptr && f != err_file_ptr
308         && f != log_file_ptr && f != ps_file_ptr) {
309       fclose(f);
310     }
311     free(ff);
312   }
313 }
314
315 int mplib_eof_file (void *ff) {
316   if (ff!=NULL) {
317     FILE *f = ((File *)ff)->f;
318     if (f==NULL)
319       return 1;
320     if (f==stdin && input_data != NULL) {       
321       return (input_data_len==0);
322     }
323     return feof(f);
324   }
325   return 1;
326 }
327
328 void mplib_flush_file (void *ff) {
329   return ;
330 }
331
332 static struct mp_edge_object *edges = NULL;
333
334 #define APPEND_TO_EDGES(a) do {                 \
335     if (edges==NULL) {                          \
336       edges = hh;                               \
337     } else {                                    \
338       struct mp_edge_object *p = edges;         \
339       while (p->_next!=NULL) { p = p->_next; }  \
340       p->_next = hh;                            \
341     }                                           \
342 } while (0)
343
344 void mplib_shipout_backend (MP mp, int h) {
345   struct mp_edge_object *hh; 
346   hh = mp_gr_export(mp, h);
347   if (hh) {
348     APPEND_TO_EDGES(hh); 
349   }
350 }
351
352
353 static void 
354 mplib_setup_file_ops(struct MP_options * options) {
355   options->find_file         = mplib_find_file;
356   options->open_file         = mplib_open_file;
357   options->close_file        = mplib_close_file;
358   options->eof_file          = mplib_eof_file;
359   options->flush_file        = mplib_flush_file;
360   options->write_ascii_file  = mplib_write_ascii_file;
361   options->read_ascii_file   = mplib_read_ascii_file;
362   options->write_binary_file = mplib_write_binary_file;
363   options->read_binary_file  = mplib_read_binary_file;
364   options->shipout_backend   = mplib_shipout_backend;
365 }
366
367 static int 
368 mplib_new (lua_State *L) {
369   MP *mp_ptr;
370   int h,i;
371   struct MP_options * options; /* instance options */
372   mp_ptr = lua_newuserdata(L, sizeof(MP *));
373   if (mp_ptr) {
374     options = mp_options();
375     mplib_setup_file_ops(options);
376     options->noninteractive = 1; /* required ! */
377     options->print_found_names = 0;
378     if (lua_type(L,1)==LUA_TTABLE) {
379       for (i=1;img_parms[i].name!=NULL;i++) {
380         lua_getfield(L,1,img_parms[i].name);
381         if (lua_isnil(L,-1)) {
382           lua_pop(L,1);
383           continue; /* skip unset */
384         }
385         switch(img_parms[i].idx) {
386         case P_ERROR_LINE: 
387           options->error_line = lua_tointeger(L,-1);
388           break;
389         case P_HALF_LINE:   
390           options->half_error_line = lua_tointeger(L,-1);
391           break;
392         case P_MAX_LINE:
393           options->max_print_line = lua_tointeger(L,-1);
394           break;
395         case P_MAIN_MEMORY:
396           options->main_memory = lua_tointeger(L,-1);
397           break;
398         case P_HASH_SIZE:
399           options->hash_size = lua_tointeger(L,-1);
400           break;
401         case P_HASH_PRIME:
402           options->hash_prime = lua_tointeger(L,-1);
403           break;
404         case P_PARAM_SIZE:
405           options->param_size = lua_tointeger(L,-1);
406           break;
407         case P_IN_OPEN:
408           options->max_in_open = lua_tointeger(L,-1);
409           break;
410         case P_RANDOM_SEED:
411           options->random_seed = lua_tointeger(L,-1);
412           break;
413         case P_INTERACTION:
414           options->interaction = luaL_checkoption(L,-1,"errorstopmode", interaction_options);
415           break;
416         case P_INI_VERSION:
417           options->ini_version = lua_toboolean(L,-1);
418           break;
419         case P_TROFF_MODE:
420           options->troff_mode = lua_toboolean(L,-1);
421           break;
422         case P_PRINT_NAMES:
423           options->print_found_names = lua_toboolean(L,-1);
424           break;
425         case P_COMMAND_LINE:
426           options->command_line = strdup((char *)lua_tostring(L,-1));
427           break;
428         case P_MEM_NAME:
429           options->mem_name = strdup((char *)lua_tostring(L,-1));
430           break;
431         case P_JOB_NAME:
432           options->job_name = strdup((char *)lua_tostring(L,-1));
433           break;
434         case P_FIND_FILE:  
435           if(mplib_find_file_function(L)) { /* error here */
436             fprintf(stdout,"Invalid arguments to mp.new({find_file=...})\n");
437           }
438           break;
439 #if 0
440         case P_OPEN_FILE:
441         case P_CLOSE_FILE:
442         case P_EOF_FILE:
443         case P_FLUSH_FILE:
444         case P_WRITE_ASCII:
445         case P_READ_ASCII:
446         case P_WRITE_BINARY:
447         case P_READ_BINARY:
448           break;
449         case P_SHIPOUT:
450           break;
451         case P_RUN_EDITOR:
452           break;
453         case P_RUN_MAKEMPX:
454           break;
455 #endif
456         default:
457           break;
458         }
459         lua_pop(L,1);
460       }
461     }
462     *mp_ptr = mp_new(options);
463     xfree(options->command_line);
464     xfree(options->mem_name);
465     xfree(options->job_name);
466     free(options);
467     if (*mp_ptr) {
468       h = mp_initialize(*mp_ptr);
469       if (!h) {
470         luaL_getmetatable(L,MPLIB_METATABLE);
471         lua_setmetatable(L,-2);
472         return 1;
473       }
474     }
475   }
476   lua_pushnil(L);
477   return 1;
478 }
479
480 static int
481 mplib_collect (lua_State *L) {
482   MP *mp_ptr = is_mp(L,1);
483   if (*mp_ptr!=NULL) {
484     mp_free(*mp_ptr);
485     *mp_ptr=NULL;
486   }
487   return 0;
488 }
489
490 static int
491 mplib_tostring (lua_State *L) {
492   MP *mp_ptr = is_mp(L,1);
493   if (*mp_ptr!=NULL) {
494     lua_pushfstring(L,"<MP %p>",*mp_ptr);
495         return 1;
496   }
497   return 0;
498 }
499
500 static int
501 mplib_run (lua_State *L) {
502   MP *mp_ptr = is_mp(L,1);
503   if (*mp_ptr!=NULL) {
504         int h = mp_run(*mp_ptr);
505         lua_pushnumber(L,h);
506   } else {
507         lua_pushnil(L);
508   }
509   return 1;
510 }
511
512 static int 
513 mplib_wrapresults(lua_State *L,int h) {
514    lua_checkstack(L,5);
515    lua_newtable(L);
516    if (term_out != NULL) {
517      lua_pushstring(L,term_out);
518      lua_setfield(L,-2,"term");
519      free(term_out); term_out = NULL;
520    }
521    if (error_out != NULL) {
522      lua_pushstring(L,error_out);
523      lua_setfield(L,-2,"error");
524      free(error_out); error_out = NULL;
525    } 
526    if (log_out != NULL ) {
527      lua_pushstring(L,log_out);
528      lua_setfield(L,-2,"log");
529      free(log_out); log_out = NULL;
530    }
531    if (edges != NULL ) {
532      struct mp_edge_object **v;
533      struct mp_edge_object *p = edges;
534      int i = 1;
535      lua_newtable(L);
536      while (p!=NULL) { 
537        v = lua_newuserdata (L, sizeof(struct mp_edge_object *));
538        *v = p;
539        luaL_getmetatable(L,MPLIB_FIG_METATABLE);
540        lua_setmetatable(L,-2);
541        lua_rawseti(L,-2,i); i++;
542        p = p->_next;
543      }
544      lua_setfield(L,-2,"fig");
545      edges = NULL;
546    }
547    lua_pushnumber(L,h);
548    lua_setfield(L,-2,"status");
549    return 1;
550 }
551
552 static int
553 mplib_execute (lua_State *L) {
554   MP *mp_ptr = is_mp(L,1);
555   if (*mp_ptr!=NULL && lua_isstring(L,2)) {
556     if (input_data_len>0) {  /* this should NOT happen */
557       fprintf(stderr,"Can't do concurrency yet!\n");
558     } else {
559       input_data = (char *)lua_tolstring(L,2, &input_data_len);
560       input_data_ptr = input_data;
561       int h = mp_execute(*mp_ptr);
562       return mplib_wrapresults(L, h);
563     } 
564
565   } else {
566     lua_pushnil(L);
567   }
568   return 1;
569 }
570
571 static int
572 mplib_finish (lua_State *L) {
573   MP *mp_ptr = is_mp(L,1);
574   if (*mp_ptr!=NULL) {
575     int h = mp_finish(*mp_ptr);
576     return mplib_wrapresults(L, h);
577   } else {
578     lua_pushnil(L);
579   }
580   return 1;
581 }
582
583 /* figure methods */
584
585 static int
586 mplib_fig_collect (lua_State *L) {
587   struct mp_edge_object **hh = is_fig(L,1);
588   if (*hh!=NULL) {
589     mp_gr_toss_objects (*hh);
590     *hh=NULL;
591   }
592   return 0;
593 }
594
595 static int
596 mplib_fig_body (lua_State *L) {
597   struct mp_edge_object **hh = is_fig(L,1);
598   struct mp_graphic_object **v;
599   struct mp_graphic_object *p;
600     /* create a table from body */
601   lua_newtable(L);
602   p = (*hh)->body;
603   while (p!=NULL) {
604     /* TODO */
605     p = p->_link_field;
606   }
607   (*hh)->body = NULL; /* prevent double free */
608   return 1;
609 }
610
611
612 static int
613 mplib_fig_tostring (lua_State *L) {
614   struct mp_edge_object **hh = is_fig(L,1);
615   lua_pushfstring(L,"<figure %p>",*hh);
616   return 1;
617 }
618
619
620
621 static int 
622 mp_wrapped_shipout (struct mp_edge_object *hh, int prologues, int procset) {
623   MP mp = hh->_parent;
624   if (setjmp(mp->jump_buf)) {
625     return 0;
626   }
627   mp_gr_ship_out(hh,prologues,procset);
628   return 1;
629 }
630
631 static int
632 mplib_fig_postscript (lua_State *L) {
633   struct mp_edge_object **hh = is_fig(L,1);
634   int prologues = luaL_optnumber(L,2,-1);
635   int procset = luaL_optnumber(L,3,-1);
636   if (ps_out == NULL) {
637     if (mp_wrapped_shipout(*hh,prologues, procset)) {
638       if (ps_out!=NULL ) {
639         lua_pushstring(L, ps_out);
640         free(ps_out); ps_out = NULL;
641       } else {
642         lua_pushnil(L);
643       }
644       return 1;
645     } else {
646       lua_pushnil(L);
647       lua_pushstring(L,log_out);
648       free(ps_out); ps_out = NULL;
649       return 2;
650     }
651   }
652   lua_pushnil(L);
653   return 1;
654 }
655
656 static int
657 mplib_fig_bb (lua_State *L) {
658   struct mp_edge_object **hh = is_fig(L,1);
659   lua_newtable(L);
660   lua_pushnumber(L, (double)(*hh)->_minx/65536.0);
661   lua_rawseti(L,-2,1);
662   lua_pushnumber(L, (double)(*hh)->_miny/65536.0);
663   lua_rawseti(L,-2,2);
664   lua_pushnumber(L, (double)(*hh)->_maxx/65536.0);
665   lua_rawseti(L,-2,3);
666   lua_pushnumber(L, (double)(*hh)->_maxy/65536.0);
667   lua_rawseti(L,-2,4);
668   return 1;
669 }
670
671 /* object methods */
672
673 static int
674 mplib_gr_collect (lua_State *L) {
675   struct mp_graphic_object **hh = is_gr_object(L,1);
676   if (*hh!=NULL) {
677     mp_gr_toss_object(*hh);
678     *hh=NULL;
679   }
680   return 0;
681 }
682
683 static int
684 mplib_gr_tostring (lua_State *L) {
685   struct mp_graphic_object **hh = is_gr_object(L,1);
686   lua_pushfstring(L,"<object %p>",*hh);
687   return 1;
688 }
689
690
691 static const struct luaL_reg mplib_meta[] = {
692   {"__gc",               mplib_collect}, 
693   {"__tostring",         mplib_tostring},
694   {NULL, NULL}                /* sentinel */
695 };
696
697 static const struct luaL_reg mplib_fig_meta[] = {
698   {"__gc",               mplib_fig_collect},
699   {"__tostring",         mplib_fig_tostring},
700   {"postscript",         mplib_fig_postscript},
701   {"boundingbox",        mplib_fig_bb},
702   {NULL, NULL}                /* sentinel */
703 };
704
705 static const struct luaL_reg mplib_gr_meta[] = {
706   {"__gc",               mplib_gr_collect},
707   {"__tostring",         mplib_gr_tostring},
708   {NULL, NULL}                /* sentinel */
709 };
710
711
712 static const struct luaL_reg mplib_d [] = {
713   {"run",                mplib_run },
714   {"execute",            mplib_execute },
715   {"finish",             mplib_finish },
716   {NULL, NULL}  /* sentinel */
717 };
718
719
720 static const struct luaL_reg mplib_m[] = {
721   {"new",               mplib_new},
722   {NULL, NULL}                /* sentinel */
723 };
724
725
726 int 
727 luaopen_mp (lua_State *L) {
728   luaL_newmetatable(L,MPLIB_GR_METATABLE);
729   lua_pushvalue(L, -1); /* push metatable */
730   lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
731   luaL_register(L, NULL, mplib_gr_meta);  /* object meta methods */
732   lua_pop(L,1);
733
734   luaL_newmetatable(L,MPLIB_FIG_METATABLE);
735   lua_pushvalue(L, -1); /* push metatable */
736   lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
737   luaL_register(L, NULL, mplib_fig_meta);  /* figure meta methods */
738   lua_pop(L,1);
739
740   luaL_newmetatable(L,MPLIB_METATABLE);
741   lua_pushvalue(L, -1); /* push metatable */
742   lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
743   luaL_register(L, NULL, mplib_meta);  /* meta methods */
744   luaL_register(L, NULL, mplib_d);  /* dict methods */
745   luaL_register(L, "mp", mplib_m); /* module functions */
746   return 1;
747 }
748