support -Wwrite-strings and some other cleanup
[mplib] / src / texk / web2c / mpdir / lmplib.c
1 /* $Id$ */
2
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6
7 #ifndef pdfTeX
8 #include <lua.h>
9 #include <lauxlib.h>
10 #include <lualib.h>
11 #else
12 #include <../lua51/lua.h>
13 #include <../lua51/lauxlib.h>
14 #include <../lua51/lualib.h>
15 #endif
16
17 #include "mplib.h"
18 #include "mpmp.h"
19 #include "mppsout.h" /* for mp_edge_object */
20
21 #define MPLIB_METATABLE     "MPlib"
22 #define MPLIB_FIG_METATABLE "MPlib.fig"
23 #define MPLIB_GR_METATABLE  "MPlib.gr"
24
25 #define mplib_init_S(a) do {                                                                                    \
26     lua_pushliteral(L,#a);                                              \
27         mplib_##a##_ptr = (char *)lua_tostring(L,-1);                                           \
28     mplib_##a##_index = luaL_ref (L,LUA_REGISTRYINDEX);                                 \
29   } while (0)
30
31 #define mplib_push_S(a) do {                                                                    \
32     lua_rawgeti(L,LUA_REGISTRYINDEX,mplib_##a##_index);                 \
33   } while (0)
34
35 #define mplib_is_S(a,i) (mplib_##a##_ptr==(char *)lua_tostring(L,i))
36
37 #define mplib_make_S(a)                                                                                                 \
38   static int mplib_##a##_index = 0;                                                                             \
39   static char *mplib_##a##_ptr = NULL
40
41 static int mplib_type_Ses[mp_special_code+1] = {0}; /* [0] is not used */
42
43 mplib_make_S(fill);
44 mplib_make_S(outline);
45 mplib_make_S(text);
46 mplib_make_S(special);
47 mplib_make_S(start_bounds);
48 mplib_make_S(stop_bounds);
49 mplib_make_S(start_clip);
50 mplib_make_S(stop_clip);
51
52 mplib_make_S(left_type);
53 mplib_make_S(right_type);
54 mplib_make_S(x_coord);
55 mplib_make_S(y_coord);
56 mplib_make_S(left_x);
57 mplib_make_S(left_y);
58 mplib_make_S(right_x);
59 mplib_make_S(right_y);
60
61 mplib_make_S(color);
62 mplib_make_S(dash);
63 mplib_make_S(depth);
64 mplib_make_S(dsize);
65 mplib_make_S(font);
66 mplib_make_S(height);
67 mplib_make_S(htap);
68 mplib_make_S(linecap);
69 mplib_make_S(linejoin);
70 mplib_make_S(miterlimit);
71 mplib_make_S(path);
72 mplib_make_S(pen);
73 mplib_make_S(postscript);
74 mplib_make_S(prescript);
75 mplib_make_S(transform);
76 mplib_make_S(type);
77 mplib_make_S(width);
78
79 void mplib_init_Ses(lua_State *L) {
80   mplib_init_S(fill);
81   mplib_init_S(outline);
82   mplib_init_S(text);
83   mplib_init_S(start_bounds);
84   mplib_init_S(stop_bounds);
85   mplib_init_S(start_clip);
86   mplib_init_S(stop_clip);
87   mplib_init_S(special);  
88
89   mplib_type_Ses[mp_fill_code]         = mplib_fill_index;
90   mplib_type_Ses[mp_stroked_code]      = mplib_outline_index;
91   mplib_type_Ses[mp_text_code]         = mplib_text_index;
92   mplib_type_Ses[mp_start_bounds_code] = mplib_start_bounds_index;
93   mplib_type_Ses[mp_stop_bounds_code]  = mplib_stop_bounds_index;
94   mplib_type_Ses[mp_start_clip_code]   = mplib_start_clip_index;
95   mplib_type_Ses[mp_stop_clip_code]    = mplib_stop_clip_index;
96   mplib_type_Ses[mp_special_code]      = mplib_special_index;
97
98   mplib_init_S(left_type);
99   mplib_init_S(right_type);
100   mplib_init_S(x_coord);
101   mplib_init_S(y_coord);
102   mplib_init_S(left_x);
103   mplib_init_S(left_y);
104   mplib_init_S(right_x);
105   mplib_init_S(right_y);
106
107   mplib_init_S(color);
108   mplib_init_S(dash);
109   mplib_init_S(depth);
110   mplib_init_S(dsize);
111   mplib_init_S(font);
112   mplib_init_S(height);
113   mplib_init_S(htap);
114   mplib_init_S(linecap);
115   mplib_init_S(linejoin);
116   mplib_init_S(miterlimit);
117   mplib_init_S(path);
118   mplib_init_S(pen);
119   mplib_init_S(postscript);
120   mplib_init_S(prescript);
121   mplib_init_S(transform);
122   mplib_init_S(type);
123   mplib_init_S(width);
124 }
125
126
127
128
129 #define xfree(A) if ((A)!=NULL) { free((A)); A = NULL; }
130
131 #define is_mp(L,b) (MP *)luaL_checkudata(L,b,MPLIB_METATABLE)
132 #define is_fig(L,b) (struct mp_edge_object **)luaL_checkudata(L,b,MPLIB_FIG_METATABLE)
133 #define is_gr_object(L,b) (struct mp_graphic_object **)luaL_checkudata(L,b,MPLIB_GR_METATABLE)
134
135 /* Enumeration string arrays */
136
137 static const char *interaction_options[] = 
138   { "unknown","batch","nonstop","scroll","errorstop", NULL};
139
140 static const char *mplib_filetype_names[] = 
141   {"term", "error", "mp", "log", "ps", "mem", "tfm", "map", "pfb", "enc", NULL};
142
143 /* only "endpoint" and "explicit" actually happen in paths, 
144    as well as "open" in elliptical pens */
145
146 static const char *knot_type_enum[]  = 
147   { "endpoint", "explicit", "given", "curl", "open", "end_cycle"  };
148
149 /* object fields */
150
151 static const char *fill_fields[] = 
152   { "type", "path", "htap", "pen", "color", "linejoin", "miterlimit", 
153     "prescript", "postscript", NULL };
154
155 static const  char *stroked_fields[] = 
156   { "type", "path", "pen", "color", "linejoin", "miterlimit", "linecap", "dash", 
157     "prescript", "postscript", NULL };
158
159 static const char *text_fields[] = 
160   { "type", "text", "dsize", "font", "color", "width", "height", "depth", "transform", 
161     "prescript", "postscript", NULL };
162
163 static const char *special_fields[] = 
164   { "type", "prescript", NULL };
165
166 static const char *start_bounds_fields[] = 
167   { "type", "path", NULL };
168
169 static const char *start_clip_fields[] = 
170   { "type", "path", NULL };
171
172 static const char *stop_bounds_fields[] = 
173   { "type", NULL };
174
175 static const char *stop_clip_fields[] = 
176   { "type", NULL };
177
178 static const char *no_fields[] =  
179   { NULL };
180
181 typedef enum {  
182   P_ERROR_LINE,  P_HALF_LINE,   P_MAX_LINE,    P_MAIN_MEMORY, 
183   P_HASH_SIZE,   P_HASH_PRIME,  P_PARAM_SIZE,  P_IN_OPEN,     P_RANDOM_SEED, 
184   P_INTERACTION, P_INI_VERSION, P_TROFF_MODE,  P_PRINT_NAMES, P_MEM_NAME, 
185   P_JOB_NAME,    P_FIND_FILE,   P__SENTINEL
186 } mplib_parm_idx;
187
188 typedef struct {
189     const char *name;           /* parameter name */
190     mplib_parm_idx idx;         /* parameter index */
191 } mplib_parm_struct;
192
193 static mplib_parm_struct mplib_parms[] = {
194   {"error_line",        P_ERROR_LINE   },
195   {"half_error_line",   P_HALF_LINE    },
196   {"max_print_line",    P_MAX_LINE     },
197   {"main_memory",       P_MAIN_MEMORY  },
198   {"hash_size",         P_HASH_SIZE    },
199   {"hash_prime",        P_HASH_PRIME   },
200   {"param_size",        P_PARAM_SIZE   },
201   {"max_in_open",       P_IN_OPEN      },
202   {"random_seed",       P_RANDOM_SEED  },
203   {"interaction",       P_INTERACTION  },
204   {"ini_version",       P_INI_VERSION  },
205   {"troff_mode",        P_TROFF_MODE   },
206   {"print_found_names", P_PRINT_NAMES  },
207   {"mem_name",          P_MEM_NAME     },
208   {"job_name",          P_JOB_NAME     },
209   {"find_file",         P_FIND_FILE    },
210   {NULL,                P__SENTINEL    }
211 };
212
213 typedef struct _FILE_ITEM {
214   FILE *f;
215 } _FILE_ITEM ;
216
217 typedef struct _FILE_ITEM File;
218
219 #define make_stream_buf(A) char *A; size_t A##_size; size_t A##_used
220
221 #define free_stream_buf(A) xfree(mplib_data->A); mplib_data->A##_size = 0; mplib_data->A##_used = 0
222
223 typedef struct _MPLIB_INSTANCE_DATA {
224   void *term_file_ptr;
225   void *err_file_ptr;
226   void *log_file_ptr;
227   void *ps_file_ptr;
228   make_stream_buf(term_out);
229   make_stream_buf(error_out);
230   make_stream_buf(log_out);
231   make_stream_buf(ps_out);
232   char *input_data;
233   char *input_data_ptr;
234   size_t input_data_len;
235   struct mp_edge_object *edges ;
236   lua_State *LL;
237 } _MPLIB_INSTANCE_DATA;
238
239 typedef struct _MPLIB_INSTANCE_DATA mplib_instance;
240
241 static mplib_instance *mplib_get_data (MP mp) {
242   return (mplib_instance *)mp->userdata;
243 }
244
245 static mplib_instance *mplib_make_data (void) {
246   mplib_instance *mplib_data = malloc(sizeof(mplib_instance));
247   memset(mplib_data,0,sizeof(mplib_instance));
248   return mplib_data ;
249 }
250
251
252 /* Start by defining all the callback routines for the library 
253  * except |run_make_mpx| and |run_editor|.
254  */
255
256
257 char *mplib_find_file (MP mp, const char *fname, const char *fmode, int ftype)  {
258   mplib_instance *mplib_data = mplib_get_data(mp);
259   lua_State *L = mplib_data->LL;
260   lua_checkstack(L,4);
261   lua_getfield(L,LUA_REGISTRYINDEX,"mplib_file_finder");
262   if (lua_isfunction(L,-1)) {
263     char *s = NULL, *x = NULL;
264     lua_pushstring(L, fname);
265     lua_pushstring(L, fmode);
266     if (ftype >= mp_filetype_text) {
267       lua_pushnumber(L, ftype-mp_filetype_text);
268     } else {
269       lua_pushstring(L, mplib_filetype_names[ftype]);
270     }
271     if(lua_pcall(L,3,1,0) != 0) {
272       fprintf(stdout,"Error in mp.find_file: %s\n", (char *)lua_tostring(L,-1));
273       return NULL;
274     }
275     x = (char *)lua_tostring(L,-1);
276     if (x!=NULL)
277       s = strdup(x);
278         lua_pop(L,1); /* pop the string */
279         return s;
280   } else {
281     lua_pop(L,1);
282   }
283   if (fmode[0] != 'r' || (! access (fname,R_OK)) || ftype) {  
284      return strdup(fname);
285   }
286   return NULL;
287 }
288
289 static int 
290 mplib_find_file_function (lua_State *L) {
291   if (! (lua_isfunction(L,-1)|| lua_isnil(L,-1) )) {
292     return 1; /* error */
293   }
294   lua_pushstring(L, "mplib_file_finder");
295   lua_pushvalue(L,-2);
296   lua_rawset(L,LUA_REGISTRYINDEX);
297   return 0;
298 }
299
300 void *mplib_open_file(MP mp, const char *fname, const char *fmode, int ftype)  {
301   File *ff = malloc(sizeof (File));
302   if (ff) {
303     mplib_instance *mplib_data = mplib_get_data(mp);
304     ff->f = NULL;
305     if (ftype==mp_filetype_terminal) {
306       if (fmode[0] == 'r') {
307                 ff->f = stdin;
308       } else {
309                 xfree(mplib_data->term_file_ptr); 
310                 ff->f = malloc(1);
311                 mplib_data->term_file_ptr = ff->f;
312       }
313     } else if (ftype==mp_filetype_error) {
314       xfree(mplib_data->err_file_ptr); 
315       ff->f = malloc(1);
316       mplib_data->err_file_ptr = ff->f;
317     } else if (ftype == mp_filetype_log) {
318       xfree(mplib_data->log_file_ptr); 
319       ff->f = malloc(1);
320       mplib_data->log_file_ptr = ff->f;
321     } else if (ftype == mp_filetype_postscript) {
322       xfree(mplib_data->ps_file_ptr); 
323       ff->f = malloc(1);
324       mplib_data->ps_file_ptr = ff->f;
325     } else { 
326       char realmode[3];
327       char *f = mplib_find_file(mp, fname,fmode,ftype);
328           if (f==NULL)
329                 return NULL;
330           realmode[0] = *fmode;
331           realmode[1] = 'b';
332           realmode[2] = 0;
333       ff->f = fopen(f, realmode);
334       if ((fmode[0] == 'r') && (ff->f == NULL)) {
335                 free(ff);
336                 return NULL;  
337       }
338     }
339     return ff;
340   }
341   return NULL;
342 }
343
344 static int 
345 mplib_get_char (void *f, mplib_instance *mplib_data) {
346   int c;
347   if (f==stdin && mplib_data->input_data != NULL) {
348         if (mplib_data->input_data_len==0) {
349           if (mplib_data->input_data_ptr!=NULL)
350                 mplib_data->input_data_ptr = NULL;
351           else
352                 mplib_data->input_data = NULL;
353           c = EOF;
354         } else {
355           mplib_data->input_data_len--;
356           c = *(mplib_data->input_data_ptr)++;
357       }
358   } else {
359         c = fgetc(f);
360   }
361   return c;
362 }
363
364 static void
365 mplib_unget_char (void *f, mplib_instance *mplib_data, int c) {
366   if (f==stdin && mplib_data->input_data_ptr != NULL) {
367         mplib_data->input_data_len++;   
368         mplib_data->input_data_ptr--;
369   } else {
370         ungetc(c,f);
371   }
372 }
373
374
375 char *mplib_read_ascii_file (MP mp, void *ff, size_t *size) {
376   char *s = NULL;
377   if (ff!=NULL) {
378         int c;
379         size_t len = 0, lim = 128;
380     mplib_instance *mplib_data = mplib_get_data(mp);
381     FILE *f = ((File *)ff)->f;
382     if (f==NULL)
383       return NULL;
384     *size = 0;
385     c = mplib_get_char(f,mplib_data);
386     if (c==EOF)
387       return NULL;
388     s = malloc(lim); 
389     if (s==NULL) return NULL;
390     while (c!=EOF && c!='\n' && c!='\r') { 
391       if (len==lim) {
392         s =realloc(s, (lim+(lim>>2)));
393         if (s==NULL) return NULL;
394         lim+=(lim>>2);
395       }
396       s[len++] = c;
397       c = mplib_get_char(f,mplib_data);
398     }
399     if (c=='\r') {
400       c = mplib_get_char(f,mplib_data);
401       if (c!=EOF && c!='\n')
402         mplib_unget_char(f,mplib_data,c);
403     }
404     s[len] = 0;
405     *size = len;
406   }
407   return s;
408 }
409
410 #define APPEND_STRING(a,b) do {                                         \
411     if ((mplib_data->a##_used+strlen(b))>=mplib_data->a##_size) {       \
412       mplib_data->a##_size += 256+(mplib_data->a##_size)/5+strlen(b);   \
413       mplib_data->a = realloc(mplib_data->a,mplib_data->a##_size);      \
414     }                                                                   \
415     (void)strcpy(mplib_data->a+mplib_data->a##_used,b);                 \
416     mplib_data->a##_used += strlen(b);                                  \
417   } while (0)
418
419 void mplib_write_ascii_file (MP mp, void *ff, const char *s) {
420   if (ff!=NULL) {
421     void *f = ((File *)ff)->f;
422     mplib_instance *mplib_data = mplib_get_data(mp);
423     if (f!=NULL) {
424       if (f==mplib_data->term_file_ptr) {
425         APPEND_STRING(term_out,s);
426       } else if (f==mplib_data->err_file_ptr) {
427         APPEND_STRING(error_out,s);
428       } else if (f==mplib_data->log_file_ptr) {
429         APPEND_STRING(log_out,s);
430       } else if (f==mplib_data->ps_file_ptr) {
431         APPEND_STRING(ps_out,s);
432       } else {
433         fprintf((FILE *)f,s);
434       }
435     }
436   }
437 }
438
439 void mplib_read_binary_file (MP mp, void *ff, void **data, size_t *size) {
440   (void)mp;
441   if (ff!=NULL) {
442     size_t len = 0;
443     FILE *f = ((File *)ff)->f;
444     if (f!=NULL) 
445       len = fread(*data,1,*size,f);
446     *size = len;
447   }
448 }
449
450 void mplib_write_binary_file (MP mp, void *ff, void *s, size_t size) {
451   (void)mp;
452   if (ff!=NULL) {
453     FILE *f = ((File *)ff)->f;
454     if (f!=NULL)
455       fwrite(s,size,1,f);
456   }
457 }
458
459
460 void mplib_close_file (MP mp, void *ff) {
461   if (ff!=NULL) {
462     mplib_instance *mplib_data = mplib_get_data(mp);
463     void *f = ((File *)ff)->f;
464     if (f != NULL && f != mplib_data->term_file_ptr && f != mplib_data->err_file_ptr
465         && f != mplib_data->log_file_ptr && f != mplib_data->ps_file_ptr) {
466       fclose(f);
467     }
468     free(ff);
469   }
470 }
471
472 int mplib_eof_file (MP mp, void *ff) {
473   if (ff!=NULL) {
474     mplib_instance *mplib_data = mplib_get_data(mp);
475     FILE *f = ((File *)ff)->f;
476     if (f==NULL)
477       return 1;
478     if (f==stdin && mplib_data->input_data != NULL) {   
479       return (mplib_data->input_data_len==0);
480     }
481     return feof(f);
482   }
483   return 1;
484 }
485
486 void mplib_flush_file (MP mp, void *ff) {
487   (void)mp;
488   (void)ff;
489   return ;
490 }
491
492 #define APPEND_TO_EDGES(a) do {                                                 \
493     if (mplib_data->edges==NULL) {                                              \
494       mplib_data->edges = hh;                                                   \
495     } else {                                                                                    \
496       struct mp_edge_object *p = mplib_data->edges;             \
497       while (p->_next!=NULL) { p = p->_next; }                  \
498       p->_next = hh;                                                                    \
499     }                                                                                                   \
500 } while (0)
501
502 void mplib_shipout_backend (MP mp, int h) {
503   struct mp_edge_object *hh = mp_gr_export(mp, h);
504   if (hh) {
505     mplib_instance *mplib_data = mplib_get_data(mp);
506     APPEND_TO_EDGES(hh); 
507   }
508 }
509
510
511 static void 
512 mplib_setup_file_ops(struct MP_options * options) {
513   options->find_file         = mplib_find_file;
514   options->open_file         = mplib_open_file;
515   options->close_file        = mplib_close_file;
516   options->eof_file          = mplib_eof_file;
517   options->flush_file        = mplib_flush_file;
518   options->write_ascii_file  = mplib_write_ascii_file;
519   options->read_ascii_file   = mplib_read_ascii_file;
520   options->write_binary_file = mplib_write_binary_file;
521   options->read_binary_file  = mplib_read_binary_file;
522   options->shipout_backend   = mplib_shipout_backend;
523 }
524
525 static int 
526 mplib_new (lua_State *L) {
527   MP *mp_ptr;
528   mp_ptr = lua_newuserdata(L, sizeof(MP *));
529   if (mp_ptr) {
530         int i;
531         mplib_instance *mplib_data;
532         struct MP_options * options; /* instance options */
533     options = mp_options();
534     mplib_setup_file_ops(options);
535     mplib_data = mplib_make_data();
536     mplib_data->LL = L;
537     options->userdata = (void *)mplib_data;
538     options->noninteractive = 1; /* required ! */
539     options->print_found_names = 0;
540     if (lua_type(L,1)==LUA_TTABLE) {
541       for (i=0;mplib_parms[i].name!=NULL;i++) {
542         lua_getfield(L,1,mplib_parms[i].name);
543         if (lua_isnil(L,-1)) {
544           lua_pop(L,1);
545           continue; /* skip unset */
546         }
547         switch(mplib_parms[i].idx) {
548         case P_ERROR_LINE: 
549           options->error_line = lua_tointeger(L,-1);
550           break;
551         case P_HALF_LINE:   
552           options->half_error_line = lua_tointeger(L,-1);
553           break;
554         case P_MAX_LINE:
555           options->max_print_line = lua_tointeger(L,-1);
556           break;
557         case P_MAIN_MEMORY:
558           options->main_memory = lua_tointeger(L,-1);
559           break;
560         case P_HASH_SIZE:
561           options->hash_size = lua_tointeger(L,-1);
562           break;
563         case P_HASH_PRIME:
564           options->hash_prime = lua_tointeger(L,-1);
565           break;
566         case P_PARAM_SIZE:
567           options->param_size = lua_tointeger(L,-1);
568           break;
569         case P_IN_OPEN:
570           options->max_in_open = lua_tointeger(L,-1);
571           break;
572         case P_RANDOM_SEED:
573           options->random_seed = lua_tointeger(L,-1);
574           break;
575         case P_INTERACTION:
576           options->interaction = luaL_checkoption(L,-1,"errorstopmode", interaction_options);
577           break;
578         case P_INI_VERSION:
579           options->ini_version = lua_toboolean(L,-1);
580           break;
581         case P_TROFF_MODE:
582           options->troff_mode = lua_toboolean(L,-1);
583           break;
584         case P_PRINT_NAMES:
585           options->print_found_names = lua_toboolean(L,-1);
586           break;
587           /*      
588         case P_COMMAND_LINE:
589           options->command_line = strdup((char *)lua_tostring(L,-1));
590           break;
591           */
592         case P_MEM_NAME:
593           options->mem_name = strdup((char *)lua_tostring(L,-1));
594           break;
595         case P_JOB_NAME:
596           options->job_name = strdup((char *)lua_tostring(L,-1));
597           break;
598         case P_FIND_FILE:  
599           if(mplib_find_file_function(L)) { /* error here */
600             fprintf(stdout,"Invalid arguments to mp.new({find_file=...})\n");
601           }
602           break;
603         default:
604           break;
605         }
606         lua_pop(L,1);
607       }
608     }
609     *mp_ptr = mp_new(options);
610     xfree(options->command_line);
611     xfree(options->mem_name);
612     xfree(options->job_name);
613     free(options);
614     if (*mp_ptr) {
615       luaL_getmetatable(L,MPLIB_METATABLE);
616       lua_setmetatable(L,-2);
617       return 1;
618     }
619   }
620   lua_pushnil(L);
621   return 1;
622 }
623
624 static int
625 mplib_collect (lua_State *L) {
626   MP *mp_ptr = is_mp(L,1);
627   xfree(*mp_ptr);
628   return 0;
629 }
630
631 static int
632 mplib_tostring (lua_State *L) {
633   MP *mp_ptr = is_mp(L,1);
634   if (*mp_ptr!=NULL) {
635     lua_pushfstring(L,"<MP %p>",*mp_ptr);
636      return 1;
637   }
638   return 0;
639 }
640
641 static int 
642 mplib_wrapresults(lua_State *L, mplib_instance *mplib_data, int h) {
643    lua_checkstack(L,5);
644    lua_newtable(L);
645    if (mplib_data->term_out != NULL) {
646      lua_pushstring(L,mplib_data->term_out);
647      lua_setfield(L,-2,"term");
648      free_stream_buf(term_out);
649    }
650    if (mplib_data->error_out != NULL) {
651      lua_pushstring(L,mplib_data->error_out);
652      lua_setfield(L,-2,"error");
653      free_stream_buf(error_out);
654    } 
655    if (mplib_data->log_out != NULL ) {
656      lua_pushstring(L,mplib_data->log_out);
657      lua_setfield(L,-2,"log");
658      free_stream_buf(log_out);
659    }
660    if (mplib_data->edges != NULL ) {
661      struct mp_edge_object **v;
662      struct mp_edge_object *p = mplib_data->edges;
663      int i = 1;
664      lua_newtable(L);
665      while (p!=NULL) { 
666        v = lua_newuserdata (L, sizeof(struct mp_edge_object *));
667        *v = p;
668        luaL_getmetatable(L,MPLIB_FIG_METATABLE);
669        lua_setmetatable(L,-2);
670        lua_rawseti(L,-2,i); i++;
671        p = p->_next;
672      }
673      lua_setfield(L,-2,"fig");
674      mplib_data->edges = NULL;
675    }
676    lua_pushnumber(L,h);
677    lua_setfield(L,-2,"status");
678    return 1;
679 }
680
681 static int
682 mplib_execute (lua_State *L) {
683   MP *mp_ptr = is_mp(L,1);
684   if (*mp_ptr!=NULL && lua_isstring(L,2)) {
685     int h;
686     mplib_instance *mplib_data = mplib_get_data(*mp_ptr);
687     mplib_data->input_data = (char *)lua_tolstring(L,2, &(mplib_data->input_data_len));
688     mplib_data->input_data_ptr = mplib_data->input_data;
689     if ((*mp_ptr)->run_state==0) {
690       h = mp_initialize(*mp_ptr);
691     }
692     h = mp_execute(*mp_ptr);
693     if (mplib_data->input_data_len!=0) {
694       mplib_data->input_data = NULL;
695           mplib_data->input_data_ptr = NULL;
696       mplib_data->input_data_len=0;
697     }
698     return mplib_wrapresults(L, mplib_data, h);
699   } else {
700     lua_pushnil(L);
701   }
702   return 1;
703 }
704
705 static int
706 mplib_finish (lua_State *L) {
707   MP *mp_ptr = is_mp(L,1);
708   if (*mp_ptr!=NULL) {
709     mplib_instance *mplib_data = mplib_get_data(*mp_ptr);
710     int h = mp_finish(*mp_ptr);
711     return mplib_wrapresults(L, mplib_data, h);
712   } else {
713     lua_pushnil(L);
714   }
715   return 1;
716 }
717
718 static int 
719 mplib_statistics (lua_State *L) {
720   MP *mp_ptr = is_mp(L,1);
721   if (*mp_ptr!=NULL) {
722         lua_newtable(L);
723         lua_pushnumber(L, mp_memory_usage (*mp_ptr));
724         lua_setfield(L,-2,"main_memory");
725         lua_pushnumber(L, mp_hash_usage (*mp_ptr));
726         lua_setfield(L,-2,"hash_size");
727         lua_pushnumber(L, mp_param_usage (*mp_ptr));
728         lua_setfield(L,-2,"param_size");
729         lua_pushnumber(L, mp_open_usage (*mp_ptr));
730         lua_setfield(L,-2,"max_in_open");
731   } else {
732     lua_pushnil(L);
733   }
734   return 1;
735 }
736
737
738 /* figure methods */
739
740 static int
741 mplib_fig_collect (lua_State *L) {
742   struct mp_edge_object **hh = is_fig(L,1);
743   if (*hh!=NULL) {
744     mp_gr_toss_objects (*hh);
745     *hh=NULL;
746   }
747   return 0;
748 }
749
750 static int
751 mplib_fig_body (lua_State *L) {
752   int i = 1;
753   struct mp_graphic_object **v;
754   struct mp_graphic_object *p;
755   struct mp_edge_object **hh = is_fig(L,1);
756   lua_newtable(L);
757   p = (*hh)->body;
758   while (p!=NULL) {
759     v = lua_newuserdata (L, sizeof(struct mp_graphic_object *));
760     *v = p;
761     luaL_getmetatable(L,MPLIB_GR_METATABLE);
762     lua_setmetatable(L,-2);
763     lua_rawseti(L,-2,i); i++;
764     p = p->_link_field;
765   }
766   (*hh)->body = NULL; /* prevent double free */
767   return 1;
768 }
769
770 static int
771 mplib_fig_copy_body (lua_State *L) {
772   int i = 1;
773   struct mp_graphic_object **v;
774   struct mp_graphic_object *p;
775   struct mp_edge_object **hh = is_fig(L,1);
776   lua_newtable(L);
777   p = (*hh)->body;
778   while (p!=NULL) {
779     v = lua_newuserdata (L, sizeof(struct mp_graphic_object *));
780     *v = mp_gr_copy_object((*hh)->_parent,p);
781     luaL_getmetatable(L,MPLIB_GR_METATABLE);
782     lua_setmetatable(L,-2);
783     lua_rawseti(L,-2,i); i++;
784     p = p->_link_field;
785   }
786   return 1;
787 }
788
789
790 static int
791 mplib_fig_tostring (lua_State *L) {
792   struct mp_edge_object **hh = is_fig(L,1);
793   lua_pushfstring(L,"<figure %p>",*hh);
794   return 1;
795 }
796
797
798
799 static int 
800 mp_wrapped_shipout (struct mp_edge_object *hh, int prologues, int procset) {
801   MP mp = hh->_parent;
802   if (setjmp(mp->jump_buf)) {
803     return 0;
804   }
805   mp_gr_ship_out(hh,prologues,procset);
806   return 1;
807 }
808
809 static int
810 mplib_fig_postscript (lua_State *L) {
811   struct mp_edge_object **hh = is_fig(L,1);
812   int prologues = luaL_optnumber(L,2,-1);
813   int procset = luaL_optnumber(L,3,-1);
814   mplib_instance *mplib_data = mplib_get_data((*hh)->_parent);
815   if (mplib_data->ps_out == NULL) {
816     if (mp_wrapped_shipout(*hh,prologues, procset)) {
817       if (mplib_data->ps_out!=NULL ) {
818         lua_pushstring(L, mplib_data->ps_out);
819         free_stream_buf(ps_out);
820       } else {
821         lua_pushnil(L);
822       }
823       return 1;
824     } else {
825       lua_pushnil(L);
826       lua_pushstring(L,mplib_data->log_out);
827       xfree(mplib_data->ps_out); 
828       return 2;
829     }
830   }
831   lua_pushnil(L);
832   return 1;
833 }
834
835 static int
836 mplib_fig_filename (lua_State *L) {
837   struct mp_edge_object **hh = is_fig(L,1);
838   if (*hh!= NULL) { 
839         char *s = (*hh)->_filename;
840         lua_pushstring(L,s);
841   } else {
842         lua_pushnil(L);
843   }
844   return 1;
845 }
846
847
848 static int
849 mplib_fig_bb (lua_State *L) {
850   struct mp_edge_object **hh = is_fig(L,1);
851   lua_newtable(L);
852   lua_pushnumber(L, (double)(*hh)->_minx/65536.0);
853   lua_rawseti(L,-2,1);
854   lua_pushnumber(L, (double)(*hh)->_miny/65536.0);
855   lua_rawseti(L,-2,2);
856   lua_pushnumber(L, (double)(*hh)->_maxx/65536.0);
857   lua_rawseti(L,-2,3);
858   lua_pushnumber(L, (double)(*hh)->_maxy/65536.0);
859   lua_rawseti(L,-2,4);
860   return 1;
861 }
862
863 /* object methods */
864
865 static int
866 mplib_gr_collect (lua_State *L) {
867   struct mp_graphic_object **hh = is_gr_object(L,1);
868   if (*hh!=NULL) {
869     mp_gr_toss_object(*hh);
870     *hh=NULL;
871   }
872   return 0;
873 }
874
875 static int
876 mplib_gr_tostring (lua_State *L) {
877   struct mp_graphic_object **hh = is_gr_object(L,1);
878   lua_pushfstring(L,"<object %p>",*hh);
879   return 1;
880 }
881
882
883 static int
884 mplib_gr_fields (lua_State *L) {
885   const char **fields;
886   const char *f;
887   int i = 1;
888   struct mp_graphic_object **hh = is_gr_object(L,1);
889   if (*hh) {
890     switch ((*hh)->_type_field) {
891     case mp_fill_code:         fields = fill_fields;         break;
892     case mp_stroked_code:      fields = stroked_fields;      break;
893     case mp_text_code:         fields = text_fields;         break;
894     case mp_special_code:      fields = special_fields;      break;
895     case mp_start_clip_code:   fields = start_clip_fields;   break;
896     case mp_start_bounds_code: fields = start_bounds_fields; break;
897     case mp_stop_clip_code:    fields = stop_clip_fields;    break;
898     case mp_stop_bounds_code:  fields = stop_bounds_fields;  break;
899     default:                   fields = no_fields;
900     }
901     lua_newtable(L);
902     for (f = *fields; f != NULL; f++) {
903       lua_pushstring(L,f);
904       lua_rawseti(L,-2,i); i++;
905     }
906   } else {
907     lua_pushnil(L);
908   }
909   return 1;
910 }
911
912
913 #define mplib_push_number(L,x) lua_pushnumber(L,(lua_Number)(x)/65536.0)
914
915 #define MPLIB_PATH 0
916 #define MPLIB_PEN 1
917
918 static void 
919 mplib_push_path (lua_State *L, struct mp_knot *h, int is_pen) {
920   struct mp_knot *p; /* for scanning the path */
921   int i=1;
922   p=h;
923   if (p!=NULL) {
924     lua_newtable(L);
925     do {  
926       lua_createtable(L,0,6);
927       if (!is_pen) {
928         if (p->left_type_field != mp_explicit) {
929           mplib_push_S(left_type);
930           lua_pushstring(L,knot_type_enum[p->left_type_field]);
931           lua_rawset(L,-3);
932         }
933         if (p->right_type_field != mp_explicit) {
934           mplib_push_S(right_type);
935           lua_pushstring(L,knot_type_enum[p->right_type_field]);
936           lua_rawset(L,-3);
937         }
938       }
939       mplib_push_S(x_coord);
940       mplib_push_number(L,p->x_coord_field);
941       lua_rawset(L,-3);
942       mplib_push_S(y_coord);
943       mplib_push_number(L,p->y_coord_field);
944       lua_rawset(L,-3);
945       mplib_push_S(left_x);
946       mplib_push_number(L,p->left_x_field);
947       lua_rawset(L,-3);
948       mplib_push_S(left_y);
949       mplib_push_number(L,p->left_y_field);
950       lua_rawset(L,-3);
951       mplib_push_S(right_x);
952       mplib_push_number(L,p->right_x_field);
953       lua_rawset(L,-3);
954       mplib_push_S(right_y);
955       mplib_push_number(L,p->right_y_field);
956       lua_rawset(L,-3);
957       lua_rawseti(L,-2,i); i++;
958       if ( p->right_type_field==mp_endpoint ) { 
959         return;
960       }
961       p=p->next_field;
962     } while (p!=h) ;
963   } else {
964     lua_pushnil(L);
965   }
966 }
967
968 #define set_color_objects(pq)                           \
969   object_color_model = pq->color_model_field;           \
970   object_color_a = pq->color_field._a_val;              \
971   object_color_b = pq->color_field._b_val;              \
972   object_color_c = pq->color_field._c_val;              \
973   object_color_d = pq->color_field._d_val; 
974
975
976 static void 
977 mplib_push_color (lua_State *L, struct mp_graphic_object *p ) {
978   int object_color_model;
979   int object_color_a, object_color_b, object_color_c, object_color_d ; 
980   if (p!=NULL) {
981     if (p->_type_field == mp_fill_code) {
982       mp_fill_object *h = (mp_fill_object *)p;
983       set_color_objects(h);
984     } else if (p->_type_field == mp_stroked_code) {
985       mp_stroked_object *h = (mp_stroked_object *)p;
986       set_color_objects(h);
987     } else {
988       mp_text_object *h = (mp_text_object *)p;
989       set_color_objects(h);
990     }
991     lua_newtable(L);
992     if (object_color_model >= mp_grey_model) {
993       mplib_push_number(L,object_color_a);
994       lua_rawseti(L,-2,1);
995       if (object_color_model >= mp_rgb_model) {
996         mplib_push_number(L,object_color_b);
997         lua_rawseti(L,-2,2);
998         mplib_push_number(L,object_color_c);
999         lua_rawseti(L,-2,3);
1000         if (object_color_model == mp_cmyk_model) {      
1001           mplib_push_number(L,object_color_d);
1002           lua_rawseti(L,-2,4);
1003         }
1004       }
1005     }
1006   } else {
1007     lua_pushnil(L);
1008   }
1009 }
1010
1011 /* the dash scale is not exported, the field has no external value */
1012 static void 
1013 mplib_push_dash (lua_State *L, struct mp_stroked_object *h ) {
1014   mp_dash_object *d;
1015   if (h!=NULL && h->dash_p_field != NULL) {
1016     d  = h->dash_p_field;
1017     lua_newtable(L);
1018     mplib_push_number(L,d->offset_field);
1019     lua_setfield(L,-2,"offset");
1020     if (d->array_field!=NULL ) {
1021       int i = 0;
1022       lua_newtable(L);
1023       while (*(d->array_field+i) != -1) {
1024         mplib_push_number(L, *(d->array_field+1));
1025         i++;
1026         lua_rawseti(L,-2,i);
1027       }
1028       lua_setfield(L,-2,"dashes");
1029     }
1030   } else {
1031     lua_pushnil(L);
1032   }
1033 }
1034
1035 static void 
1036 mplib_push_transform (lua_State *L, struct mp_text_object *h ) {
1037   int i = 1;
1038   if (h!=NULL) {
1039     lua_createtable(L,6,0);
1040     mplib_push_number(L,h->tx_field);
1041     lua_rawseti(L,-2,i); i++;
1042     mplib_push_number(L,h->ty_field);
1043     lua_rawseti(L,-2,i); i++;
1044     mplib_push_number(L,h->txx_field);
1045     lua_rawseti(L,-2,i); i++;
1046     mplib_push_number(L,h->tyx_field);
1047     lua_rawseti(L,-2,i); i++;
1048     mplib_push_number(L,h->txy_field);
1049     lua_rawseti(L,-2,i); i++;
1050     mplib_push_number(L,h->tyy_field);
1051     lua_rawseti(L,-2,i); i++;
1052   } else {
1053     lua_pushnil(L);
1054   }
1055 }
1056
1057 #define FIELD(A) (mplib_is_S(A,2))
1058
1059 static void 
1060 mplib_fill_field (lua_State *L, struct mp_fill_object *h) {
1061   if (FIELD(path)) {
1062     mplib_push_path(L, h->path_p_field, MPLIB_PATH);
1063   } else if (FIELD(htap)) {
1064     mplib_push_path(L, h->htap_p_field, MPLIB_PATH);
1065   } else if (FIELD(pen)) {
1066     mplib_push_path(L, h->pen_p_field, MPLIB_PEN);
1067   } else if (FIELD(color)) {
1068     mplib_push_color(L,(mp_graphic_object *)h);
1069   } else if (FIELD(linejoin)) {
1070     lua_pushnumber(L,h->ljoin_field);
1071   } else if (FIELD(miterlimit)) {
1072     mplib_push_number(L,h->miterlim_field);
1073   } else if (FIELD(prescript)) {
1074     lua_pushstring(L,h->pre_script_field);
1075   } else if (FIELD(postscript)) {
1076     lua_pushstring(L,h->post_script_field);
1077   } else {
1078     lua_pushnil(L);
1079   }
1080 }
1081
1082 static void 
1083 mplib_stroked_field (lua_State *L, struct mp_stroked_object *h) {
1084   if (FIELD(path)) {
1085     mplib_push_path(L, h->path_p_field, MPLIB_PATH);
1086   } else if (FIELD(pen)) {
1087     mplib_push_path(L, h->pen_p_field, MPLIB_PEN);
1088   } else if (FIELD(color)) {
1089     mplib_push_color(L, (mp_graphic_object *)h);
1090   } else if (FIELD(dash)) {
1091     mplib_push_dash(L,h);
1092   } else if (FIELD(linecap)) {
1093     lua_pushnumber(L,h->lcap_field);
1094   } else if (FIELD(linejoin)) {
1095     lua_pushnumber(L,h->ljoin_field);
1096   } else if (FIELD(miterlimit)) {
1097     mplib_push_number(L,h->miterlim_field);
1098   } else if (FIELD(prescript)) {
1099     lua_pushstring(L,h->pre_script_field);
1100   } else if (FIELD(postscript)) {
1101     lua_pushstring(L,h->post_script_field);
1102   } else {
1103     lua_pushnil(L);
1104   }
1105 }
1106
1107 static void 
1108 mplib_text_field (lua_State *L, struct mp_text_object *h) {
1109   if (FIELD(text)) {
1110     lua_pushstring(L,h->text_p_field);
1111   } else if (FIELD(dsize)) {
1112     mplib_push_number(L,(h->font_dsize_field/16));
1113   } else if (FIELD(font)) {
1114     lua_pushstring(L,h->font_name_field);
1115   } else if (FIELD(color)) {
1116     mplib_push_color(L,(mp_graphic_object *)h);
1117   } else if (FIELD(width)) {
1118     mplib_push_number(L,h->width_field);
1119   } else if (FIELD(height)) {
1120     mplib_push_number(L,h->height_field);
1121   } else if (FIELD(depth)) {
1122     mplib_push_number(L,h->depth_field);
1123   } else if (FIELD(transform)) {
1124     mplib_push_transform(L,h);
1125   } else if (FIELD(prescript)) {
1126     lua_pushstring(L,h->pre_script_field);
1127   } else if (FIELD(postscript)) {
1128     lua_pushstring(L,h->post_script_field);
1129   } else {
1130     lua_pushnil(L);
1131   }
1132 }
1133
1134 static void 
1135 mplib_special_field (lua_State *L, struct mp_special_object *h) {
1136   if (FIELD(prescript)) {
1137     lua_pushstring(L,h->pre_script_field);
1138   } else {
1139     lua_pushnil(L);
1140   }
1141 }
1142
1143 static void 
1144 mplib_start_bounds_field (lua_State *L, struct mp_bounds_object *h) {
1145   if (FIELD(path)) {
1146     mplib_push_path(L,h->path_p_field, MPLIB_PATH);
1147   } else {
1148     lua_pushnil(L);
1149   }
1150 }
1151
1152 static void 
1153 mplib_start_clip_field (lua_State *L, struct mp_clip_object *h) {
1154   if (FIELD(path)) {
1155     mplib_push_path(L,h->path_p_field,  MPLIB_PATH);
1156   } else {
1157     lua_pushnil(L);
1158   }
1159 }
1160
1161 static int
1162 mplib_gr_index (lua_State *L) {
1163   struct mp_graphic_object **hh = is_gr_object(L,1);
1164   if (*hh) {
1165     struct mp_graphic_object *h = *hh;
1166     if (mplib_is_S(type,2)) {
1167       lua_rawgeti(L,LUA_REGISTRYINDEX,mplib_type_Ses[h->_type_field]);
1168     } else {
1169       switch (h->_type_field) {
1170       case mp_fill_code:         mplib_fill_field(L,(mp_fill_object *)h);           break;
1171       case mp_stroked_code:      mplib_stroked_field(L,(mp_stroked_object *)h);     break;
1172       case mp_text_code:         mplib_text_field(L,(mp_text_object *)h);           break;
1173       case mp_special_code:      mplib_special_field(L,(mp_special_object *)h);     break;
1174       case mp_start_clip_code:   mplib_start_clip_field(L,(mp_clip_object *)h);     break;
1175       case mp_start_bounds_code: mplib_start_bounds_field(L,(mp_bounds_object *)h); break;
1176         /* case mp_stop_clip_code:    */
1177         /* case mp_stop_bounds_code:  */
1178       default:                   lua_pushnil(L);
1179       }    
1180     }
1181   } else {
1182     lua_pushnil(L);
1183   }
1184   return 1;
1185 }
1186
1187
1188 static const struct luaL_reg mplib_meta[] = {
1189   {"__gc",               mplib_collect}, 
1190   {"__tostring",         mplib_tostring},
1191   {NULL, NULL}                /* sentinel */
1192 };
1193
1194 static const struct luaL_reg mplib_fig_meta[] = {
1195   {"__gc",               mplib_fig_collect    },
1196   {"__tostring",         mplib_fig_tostring   },
1197   {"objects",            mplib_fig_body       },
1198   {"copy_objects",       mplib_fig_copy_body  },
1199   {"filename",           mplib_fig_filename   },
1200   {"postscript",         mplib_fig_postscript },
1201   {"boundingbox",        mplib_fig_bb         },
1202   {NULL, NULL}                /* sentinel */
1203 };
1204
1205 static const struct luaL_reg mplib_gr_meta[] = {
1206   {"__gc",               mplib_gr_collect  },
1207   {"__tostring",         mplib_gr_tostring },
1208   {"__index",            mplib_gr_index    },
1209   {"fields",             mplib_gr_fields   },
1210   {NULL, NULL}                /* sentinel */
1211 };
1212
1213
1214 static const struct luaL_reg mplib_d [] = {
1215   {"execute",            mplib_execute },
1216   {"finish",             mplib_finish },
1217   {"statistics",         mplib_statistics },
1218   {NULL, NULL}  /* sentinel */
1219 };
1220
1221
1222 static const struct luaL_reg mplib_m[] = {
1223   {"new",                 mplib_new},
1224   {NULL, NULL}                /* sentinel */
1225 };
1226
1227
1228 int 
1229 luaopen_mp (lua_State *L) {
1230   mplib_init_Ses(L);
1231   luaL_newmetatable(L,MPLIB_GR_METATABLE);
1232   lua_pushvalue(L, -1); /* push metatable */
1233   lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1234   luaL_register(L, NULL, mplib_gr_meta);  /* object meta methods */
1235   lua_pop(L,1);
1236
1237   luaL_newmetatable(L,MPLIB_FIG_METATABLE);
1238   lua_pushvalue(L, -1); /* push metatable */
1239   lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1240   luaL_register(L, NULL, mplib_fig_meta);  /* figure meta methods */
1241   lua_pop(L,1);
1242
1243   luaL_newmetatable(L,MPLIB_METATABLE);
1244   lua_pushvalue(L, -1); /* push metatable */
1245   lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1246   luaL_register(L, NULL, mplib_meta);  /* meta methods */
1247   luaL_register(L, NULL, mplib_d);  /* dict methods */
1248   luaL_register(L, "mplib", mplib_m); /* module functions */
1249   return 1;
1250 }
1251