remove unused code block
[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 /* the third field (type) is currently not used */
43
44 parm_struct img_parms[] = {
45   {NULL,                P__ZERO,       0   },  /* dummy; lua indices run from 1 */
46   {"error_line",        P_ERROR_LINE,  'i' },
47   {"half_error_line",   P_HALF_LINE,   'i' },
48   {"max_print_line",    P_MAX_LINE,    'i' },
49   {"main_memory",       P_MAIN_MEMORY, 'i' },
50   {"hash_size",         P_HASH_SIZE,   'i' },
51   {"hash_prime",        P_HASH_PRIME,  'i' },
52   {"param_size",        P_PARAM_SIZE,  'i' },
53   {"max_in_open",       P_IN_OPEN,     'i' },
54   {"random_seed",       P_RANDOM_SEED, 'i' },
55   {"interaction",       P_INTERACTION, 'e' },
56   {"ini_version",       P_INI_VERSION, 'b' },
57   {"troff_mode",        P_TROFF_MODE,  'b' },
58   {"print_found_names", P_PRINT_NAMES, 'b' },
59   {"command_line",      P_COMMAND_LINE,'s' },
60   {"mem_name",          P_MEM_NAME,    's' },
61   {"job_name",          P_JOB_NAME,    's' },
62   {"find_file",         P_FIND_FILE,   'p' }, /* intercepted */
63   {NULL,                P__SENTINEL,   0   }
64 };
65
66 typedef struct _FILE_ITEM {
67   FILE *f;
68 } _FILE_ITEM ;
69
70 typedef struct _FILE_ITEM File;
71
72 /* Start by defining all the callback routines for the library 
73  * except |run_make_mpx| and |run_editor|.
74  */
75
76 char *mplib_filetype_names[] = {"term", "error", "mp", "log", "ps",
77                               "mem", "tfm", "map", "pfb", "enc", NULL};
78
79 lua_State *LL = NULL;
80
81 char *mplib_find_file (char *fname, char *fmode, int ftype)  {
82   if (LL!=NULL) {
83     lua_State *L = LL;
84     lua_checkstack(L,4);
85     lua_getfield(L,LUA_REGISTRYINDEX,"mplib_file_finder");
86     if (lua_isfunction(L,-1)) {
87       char *s = NULL, *x = NULL;
88       lua_pushstring(L, fname);
89       lua_pushstring(L, fmode);
90       if (ftype >= mp_filetype_text) {
91         lua_pushnumber(L, ftype-mp_filetype_text);
92       } else {
93         lua_pushstring(L, mplib_filetype_names[ftype]);
94       }
95       if(lua_pcall(L,3,1,0) != 0) {
96         fprintf(stdout,"Error in mp.find_file: %s\n", (char *)lua_tostring(L,-1));
97         return NULL;
98       }
99       x = (char *)lua_tostring(L,-1);
100       if (x!=NULL)
101         s = strdup(x);
102       lua_pop(L,1); /* pop the string */
103       return s;
104     } else {
105       lua_pop(L,1);
106     }
107   }
108   if (fmode[0] != 'r' || (! access (fname,R_OK)) || ftype) {  
109      return strdup(fname);
110   }
111   return NULL;
112 }
113
114 static int 
115 mplib_find_file_function (lua_State *L) {
116   if (lua_isfunction(L,-1)) {
117     LL =  L;
118   } else if (lua_isnil(L,-1)) {
119     LL = NULL;
120   } else {
121     return 1; /* error */
122   }
123   lua_pushstring(L, "mplib_file_finder");
124   lua_pushvalue(L,-2);
125   lua_rawset(L,LUA_REGISTRYINDEX);
126   return 0;
127 }
128
129 void *term_file_ptr = NULL;
130 void *err_file_ptr = NULL;
131 void *log_file_ptr = NULL;
132 void *ps_file_ptr = NULL;
133
134 void *mplib_open_file(char *fname, char *fmode, int ftype)  {
135   File *ff = malloc(sizeof (File));
136   if (ff) {
137     ff->f = NULL;
138     if (ftype==mp_filetype_terminal) {
139       if (fmode[0] == 'r') {
140         ff->f = stdin;
141       } else {
142         xfree(term_file_ptr); 
143         ff->f = malloc(1);
144         term_file_ptr = ff->f;
145       }
146     } else if (ftype==mp_filetype_error) {
147       xfree(err_file_ptr); 
148       ff->f = malloc(1);
149       err_file_ptr = ff->f;
150     } else if (ftype == mp_filetype_log) {
151       xfree(log_file_ptr); 
152       ff->f = malloc(1);
153       log_file_ptr = ff->f;
154     } else if (ftype == mp_filetype_postscript) {
155       xfree(ps_file_ptr); 
156       ff->f = malloc(1);
157       ps_file_ptr = ff->f;
158     } else { 
159       char *f = fname;
160       if (fmode[0] == 'r') {
161         f = mplib_find_file(fname,fmode,ftype);
162         if (f==NULL)
163           return NULL;
164       }
165       ff->f = fopen(f, fmode);
166       if ((fmode[0] == 'r') && (ff->f == NULL)) {
167         free(ff);
168         return NULL;  
169       }
170     }
171     return ff;
172   }
173   return NULL;
174 }
175
176 static char * input_data = NULL;
177 static char * input_data_ptr = NULL;
178 static size_t input_data_len = 0;
179
180 #define GET_CHAR() do {                                                 \
181     if (f==stdin && input_data != NULL) {                               \
182       if (input_data_len==0) {                                          \
183         if (input_data_ptr!=NULL)                                       \
184           input_data_ptr = NULL;                                        \
185         else                                                            \
186           input_data = NULL;                                            \
187         c = EOF;                                                        \
188       } else {                                                          \
189         input_data_len--;                                               \
190         c = *input_data_ptr++;                                          \
191       }                                                                 \
192     } else {                                                            \
193       c = fgetc(f);                                                     \
194     }                                                                   \
195   } while (0)
196
197 #define UNGET_CHAR() do {                                               \
198     if (f==stdin && input_data != NULL) {                               \
199       input_data_len++; input_data_ptr--;                               \
200     } else {                                                            \
201       ungetc(c,f);                                                      \
202     }                                                                   \
203   } while (0)
204
205
206 char *mplib_read_ascii_file (void *ff, size_t *size) {
207   int c;
208   size_t len = 0, lim = 128;
209   char *s = NULL;
210   if (ff!=NULL) {
211     FILE *f = ((File *)ff)->f;
212     if (f==NULL)
213       return NULL;
214     *size = 0;
215     GET_CHAR();
216     if (c==EOF)
217       return NULL;
218     s = malloc(lim); 
219     if (s==NULL) return NULL;
220     while (c!=EOF && c!='\n' && c!='\r') { 
221       if (len==lim) {
222         s =realloc(s, (lim+(lim>>2)));
223         if (s==NULL) return NULL;
224         lim+=(lim>>2);
225       }
226       s[len++] = c;
227       GET_CHAR();
228     }
229     if (c=='\r') {
230       GET_CHAR();
231       if (c!=EOF && c!='\n')
232         UNGET_CHAR();
233     }
234     s[len] = 0;
235     *size = len;
236   }
237   return s;
238 }
239
240 static char *term_out = NULL;
241 static char *error_out = NULL;
242 static char *log_out = NULL;
243 static char *ps_out = NULL;
244
245 #define APPEND_STRING(a,b) do {                 \
246     if (a==NULL) {                              \
247       a = strdup(b);                            \
248     } else {                                    \
249       a = realloc(a, strlen(a)+strlen(b)+1);    \
250       strcpy(a+strlen(a),b);                    \
251     }                                           \
252   } while (0)
253
254 void mplib_write_ascii_file (void *ff, char *s) {
255   if (ff!=NULL) {
256     void *f = ((File *)ff)->f;
257     if (f!=NULL) {
258       if (f==term_file_ptr) {
259         APPEND_STRING(term_out,s);
260       } else if (f==err_file_ptr) {
261         APPEND_STRING(error_out,s);
262       } else if (f==log_file_ptr) {
263         APPEND_STRING(log_out,s);
264       } else if (f==ps_file_ptr) {
265         APPEND_STRING(ps_out,s);
266       } else {
267         fprintf((FILE *)f,s);
268       }
269     }
270   }
271 }
272
273 void mplib_read_binary_file (void *ff, void **data, size_t *size) {
274   size_t len = 0;
275   if (ff!=NULL) {
276     FILE *f = ((File *)ff)->f;
277     if (f!=NULL) 
278       len = fread(*data,1,*size,f);
279     *size = len;
280   }
281 }
282
283 void mplib_write_binary_file (void *ff, void *s, size_t size) {
284   if (ff!=NULL) {
285     FILE *f = ((File *)ff)->f;
286     if (f!=NULL)
287       fwrite(s,size,1,f);
288   }
289 }
290
291
292 void mplib_close_file (void *ff) {
293   if (ff!=NULL) {
294     void *f = ((File *)ff)->f;
295     if (f != NULL && f != term_file_ptr && f != err_file_ptr
296         && f != log_file_ptr && f != ps_file_ptr) {
297       fclose(f);
298     }
299     free(ff);
300   }
301 }
302
303 int mplib_eof_file (void *ff) {
304   if (ff!=NULL) {
305     FILE *f = ((File *)ff)->f;
306     if (f==NULL)
307       return 1;
308     if (f==stdin && input_data != NULL) {       
309       return (input_data_len==0);
310     }
311     return feof(f);
312   }
313   return 1;
314 }
315
316 void mplib_flush_file (void *ff) {
317   return ;
318 }
319
320 static struct mp_edge_object *edges = NULL;
321
322 #define APPEND_TO_EDGES(a) do {                 \
323     if (edges==NULL) {                          \
324       edges = hh;                               \
325     } else {                                    \
326       struct mp_edge_object *p = edges;         \
327       while (p->_next!=NULL) { p = p->_next; }  \
328       p->_next = hh;                            \
329     }                                           \
330 } while (0)
331
332 void mplib_shipout_backend (MP mp, int h) {
333   struct mp_edge_object *hh; 
334   hh = mp_gr_export(mp, h);
335   if (hh) {
336     APPEND_TO_EDGES(hh); 
337   }
338 }
339
340
341 static void 
342 mplib_setup_file_ops(struct MP_options * options) {
343   options->find_file         = mplib_find_file;
344   options->open_file         = mplib_open_file;
345   options->close_file        = mplib_close_file;
346   options->eof_file          = mplib_eof_file;
347   options->flush_file        = mplib_flush_file;
348   options->write_ascii_file  = mplib_write_ascii_file;
349   options->read_ascii_file   = mplib_read_ascii_file;
350   options->write_binary_file = mplib_write_binary_file;
351   options->read_binary_file  = mplib_read_binary_file;
352   options->shipout_backend   = mplib_shipout_backend;
353 }
354
355 static int 
356 mplib_new (lua_State *L) {
357   MP *mp_ptr;
358   int h,i;
359   struct MP_options * options; /* instance options */
360   mp_ptr = lua_newuserdata(L, sizeof(MP *));
361   if (mp_ptr) {
362     options = mp_options();
363     mplib_setup_file_ops(options);
364     options->noninteractive = 1; /* required ! */
365     options->print_found_names = 0;
366     if (lua_type(L,1)==LUA_TTABLE) {
367       for (i=1;img_parms[i].name!=NULL;i++) {
368         lua_getfield(L,1,img_parms[i].name);
369         if (lua_isnil(L,-1)) {
370           lua_pop(L,1);
371           continue; /* skip unset */
372         }
373         switch(img_parms[i].idx) {
374         case P_ERROR_LINE: 
375           options->error_line = lua_tointeger(L,-1);
376           break;
377         case P_HALF_LINE:   
378           options->half_error_line = lua_tointeger(L,-1);
379           break;
380         case P_MAX_LINE:
381           options->max_print_line = lua_tointeger(L,-1);
382           break;
383         case P_MAIN_MEMORY:
384           options->main_memory = lua_tointeger(L,-1);
385           break;
386         case P_HASH_SIZE:
387           options->hash_size = lua_tointeger(L,-1);
388           break;
389         case P_HASH_PRIME:
390           options->hash_prime = lua_tointeger(L,-1);
391           break;
392         case P_PARAM_SIZE:
393           options->param_size = lua_tointeger(L,-1);
394           break;
395         case P_IN_OPEN:
396           options->max_in_open = lua_tointeger(L,-1);
397           break;
398         case P_RANDOM_SEED:
399           options->random_seed = lua_tointeger(L,-1);
400           break;
401         case P_INTERACTION:
402           options->interaction = luaL_checkoption(L,-1,"errorstopmode", interaction_options);
403           break;
404         case P_INI_VERSION:
405           options->ini_version = lua_toboolean(L,-1);
406           break;
407         case P_TROFF_MODE:
408           options->troff_mode = lua_toboolean(L,-1);
409           break;
410         case P_PRINT_NAMES:
411           options->print_found_names = lua_toboolean(L,-1);
412           break;
413         case P_COMMAND_LINE:
414           options->command_line = strdup((char *)lua_tostring(L,-1));
415           break;
416         case P_MEM_NAME:
417           options->mem_name = strdup((char *)lua_tostring(L,-1));
418           break;
419         case P_JOB_NAME:
420           options->job_name = strdup((char *)lua_tostring(L,-1));
421           break;
422         case P_FIND_FILE:  
423           if(mplib_find_file_function(L)) { /* error here */
424             fprintf(stdout,"Invalid arguments to mp.new({find_file=...})\n");
425           }
426           break;
427         default:
428           break;
429         }
430         lua_pop(L,1);
431       }
432     }
433     *mp_ptr = mp_new(options);
434     xfree(options->command_line);
435     xfree(options->mem_name);
436     xfree(options->job_name);
437     free(options);
438     if (*mp_ptr) {
439       h = mp_initialize(*mp_ptr);
440       if (!h) {
441         luaL_getmetatable(L,MPLIB_METATABLE);
442         lua_setmetatable(L,-2);
443         return 1;
444       }
445     }
446   }
447   lua_pushnil(L);
448   return 1;
449 }
450
451 static int
452 mplib_collect (lua_State *L) {
453   MP *mp_ptr = is_mp(L,1);
454   if (*mp_ptr!=NULL) {
455     mp_free(*mp_ptr);
456     *mp_ptr=NULL;
457   }
458   return 0;
459 }
460
461 static int
462 mplib_tostring (lua_State *L) {
463   MP *mp_ptr = is_mp(L,1);
464   if (*mp_ptr!=NULL) {
465     lua_pushfstring(L,"<MP %p>",*mp_ptr);
466         return 1;
467   }
468   return 0;
469 }
470
471 static int
472 mplib_run (lua_State *L) {
473   MP *mp_ptr = is_mp(L,1);
474   if (*mp_ptr!=NULL) {
475         int h = mp_run(*mp_ptr);
476         lua_pushnumber(L,h);
477   } else {
478         lua_pushnil(L);
479   }
480   return 1;
481 }
482
483 static int 
484 mplib_wrapresults(lua_State *L,int h) {
485    lua_checkstack(L,5);
486    lua_newtable(L);
487    if (term_out != NULL) {
488      lua_pushstring(L,term_out);
489      lua_setfield(L,-2,"term");
490      free(term_out); term_out = NULL;
491    }
492    if (error_out != NULL) {
493      lua_pushstring(L,error_out);
494      lua_setfield(L,-2,"error");
495      free(error_out); error_out = NULL;
496    } 
497    if (log_out != NULL ) {
498      lua_pushstring(L,log_out);
499      lua_setfield(L,-2,"log");
500      free(log_out); log_out = NULL;
501    }
502    if (edges != NULL ) {
503      struct mp_edge_object **v;
504      struct mp_edge_object *p = edges;
505      int i = 1;
506      lua_newtable(L);
507      while (p!=NULL) { 
508        v = lua_newuserdata (L, sizeof(struct mp_edge_object *));
509        *v = p;
510        luaL_getmetatable(L,MPLIB_FIG_METATABLE);
511        lua_setmetatable(L,-2);
512        lua_rawseti(L,-2,i); i++;
513        p = p->_next;
514      }
515      lua_setfield(L,-2,"fig");
516      edges = NULL;
517    }
518    lua_pushnumber(L,h);
519    lua_setfield(L,-2,"status");
520    return 1;
521 }
522
523 static int
524 mplib_execute (lua_State *L) {
525   MP *mp_ptr = is_mp(L,1);
526   if (*mp_ptr!=NULL && lua_isstring(L,2)) {
527     if (input_data_len>0) {  /* this should NOT happen */
528       fprintf(stderr,"Can't do concurrency yet!\n");
529     } else {
530       input_data = (char *)lua_tolstring(L,2, &input_data_len);
531       input_data_ptr = input_data;
532       int h = mp_execute(*mp_ptr);
533       return mplib_wrapresults(L, h);
534     } 
535
536   } else {
537     lua_pushnil(L);
538   }
539   return 1;
540 }
541
542 static int
543 mplib_finish (lua_State *L) {
544   MP *mp_ptr = is_mp(L,1);
545   if (*mp_ptr!=NULL) {
546     int h = mp_finish(*mp_ptr);
547     return mplib_wrapresults(L, h);
548   } else {
549     lua_pushnil(L);
550   }
551   return 1;
552 }
553
554 /* figure methods */
555
556 static int
557 mplib_fig_collect (lua_State *L) {
558   struct mp_edge_object **hh = is_fig(L,1);
559   if (*hh!=NULL) {
560     mp_gr_toss_objects (*hh);
561     *hh=NULL;
562   }
563   return 0;
564 }
565
566 static int
567 mplib_fig_body (lua_State *L) {
568   int i = 1;
569   struct mp_graphic_object **v;
570   struct mp_graphic_object *p;
571   struct mp_edge_object **hh = is_fig(L,1);
572   lua_newtable(L);
573   p = (*hh)->body;
574   while (p!=NULL) {
575     v = lua_newuserdata (L, sizeof(struct mp_graphic_object *));
576     *v = p;
577     luaL_getmetatable(L,MPLIB_GR_METATABLE);
578     lua_setmetatable(L,-2);
579     lua_rawseti(L,-2,i); i++;
580     p = p->_link_field;
581   }
582   (*hh)->body = NULL; /* prevent double free */
583   return 1;
584 }
585
586
587 static int
588 mplib_fig_tostring (lua_State *L) {
589   struct mp_edge_object **hh = is_fig(L,1);
590   lua_pushfstring(L,"<figure %p>",*hh);
591   return 1;
592 }
593
594
595
596 static int 
597 mp_wrapped_shipout (struct mp_edge_object *hh, int prologues, int procset) {
598   MP mp = hh->_parent;
599   if (setjmp(mp->jump_buf)) {
600     return 0;
601   }
602   mp_gr_ship_out(hh,prologues,procset);
603   return 1;
604 }
605
606 static int
607 mplib_fig_postscript (lua_State *L) {
608   struct mp_edge_object **hh = is_fig(L,1);
609   int prologues = luaL_optnumber(L,2,-1);
610   int procset = luaL_optnumber(L,3,-1);
611   if (ps_out == NULL) {
612     if (mp_wrapped_shipout(*hh,prologues, procset)) {
613       if (ps_out!=NULL ) {
614         lua_pushstring(L, ps_out);
615         free(ps_out); ps_out = NULL;
616       } else {
617         lua_pushnil(L);
618       }
619       return 1;
620     } else {
621       lua_pushnil(L);
622       lua_pushstring(L,log_out);
623       free(ps_out); ps_out = NULL;
624       return 2;
625     }
626   }
627   lua_pushnil(L);
628   return 1;
629 }
630
631 static int
632 mplib_fig_bb (lua_State *L) {
633   struct mp_edge_object **hh = is_fig(L,1);
634   lua_newtable(L);
635   lua_pushnumber(L, (double)(*hh)->_minx/65536.0);
636   lua_rawseti(L,-2,1);
637   lua_pushnumber(L, (double)(*hh)->_miny/65536.0);
638   lua_rawseti(L,-2,2);
639   lua_pushnumber(L, (double)(*hh)->_maxx/65536.0);
640   lua_rawseti(L,-2,3);
641   lua_pushnumber(L, (double)(*hh)->_maxy/65536.0);
642   lua_rawseti(L,-2,4);
643   return 1;
644 }
645
646 /* object methods */
647
648 static int
649 mplib_gr_collect (lua_State *L) {
650   struct mp_graphic_object **hh = is_gr_object(L,1);
651   if (*hh!=NULL) {
652     mp_gr_toss_object(*hh);
653     *hh=NULL;
654   }
655   return 0;
656 }
657
658 static int
659 mplib_gr_tostring (lua_State *L) {
660   struct mp_graphic_object **hh = is_gr_object(L,1);
661   lua_pushfstring(L,"<object %p>",*hh);
662   return 1;
663 }
664
665
666 char *knot_type_enum[]  = {
667   "endpoint", "explicit", "given", "curl", "open", "end_cycle" 
668 };
669
670 char *knot_originator_enum[]  = { "program" ,"user" };
671
672
673
674 static void 
675 mplib_push_path (lua_State *L, struct mp_knot *h ) {
676   struct mp_knot *p; /* for scanning the path */
677   int i=1;
678   p=h;
679   if (p!=NULL) {
680     lua_newtable(L);
681     do {  
682       lua_newtable(L);
683       lua_pushstring(L,knot_originator_enum[p->originator_field]);
684       lua_setfield(L,-2,"originator");
685       lua_pushstring(L,knot_type_enum[p->left_type_field]);
686       lua_setfield(L,-2,"left_type");
687       lua_pushstring(L,knot_type_enum[p->right_type_field]);
688       lua_setfield(L,-2,"right_type");
689       lua_pushnumber(L,p->x_coord_field);
690       lua_setfield(L,-2,"x_coord");
691       lua_pushnumber(L,p->y_coord_field);
692       lua_setfield(L,-2,"y_coord");
693       lua_pushnumber(L,p->left_x_field);
694       lua_setfield(L,-2,"left_x");
695       lua_pushnumber(L,p->left_y_field);
696       lua_setfield(L,-2,"left_y");
697       lua_pushnumber(L,p->right_x_field);
698       lua_setfield(L,-2,"right_x");
699       lua_pushnumber(L,p->right_y_field);
700       lua_setfield(L,-2,"right_y");
701       lua_rawseti(L,-2,i); i++;
702       if ( p->right_type_field==mp_endpoint ) { 
703         return;
704       }
705       p=p->next_field;
706     } while (p!=h) ;
707   } else {
708     lua_pushnil(L);
709   }
710 }
711
712 char *color_model_enum[] = { NULL, "none",  NULL, "grey",
713   NULL, "rgb", NULL, "cmyk", NULL, "uninitialized" };
714
715
716
717 /* this is a bit silly, a better color model representation is needed */
718 static void 
719 mplib_push_color (lua_State *L, struct mp_graphic_object *h ) {
720   if (h!=NULL) {
721     lua_newtable(L);
722     lua_pushstring(L,color_model_enum[h->color_model_field]);
723     lua_setfield(L,-2,"model");
724
725     if (h->color_model_field == mp_rgb_model ||
726         h->color_model_field == mp_uninitialized_model) {
727       lua_newtable(L);
728       lua_pushnumber(L,h->color_field.rgb._red_val);
729       lua_rawseti(L,-2,1);
730       lua_pushnumber(L,h->color_field.rgb._green_val);
731       lua_rawseti(L,-2,2);
732       lua_pushnumber(L,h->color_field.rgb._blue_val);
733       lua_rawseti(L,-2,3);
734       lua_setfield(L,-2,"rgb");
735     }
736
737     if (h->color_model_field == mp_cmyk_model ||
738         h->color_model_field == mp_uninitialized_model) {
739       lua_newtable(L);
740       lua_pushnumber(L,h->color_field.cmyk._cyan_val);
741       lua_rawseti(L,-2,1);
742       lua_pushnumber(L,h->color_field.cmyk._magenta_val);
743       lua_rawseti(L,-2,2);
744       lua_pushnumber(L,h->color_field.cmyk._yellow_val);
745       lua_rawseti(L,-2,3);
746       lua_pushnumber(L,h->color_field.cmyk._black_val);
747       lua_rawseti(L,-2,4);
748       lua_setfield(L,-2,"cmyk");
749     }
750     if (h->color_model_field == mp_grey_model ||
751         h->color_model_field == mp_uninitialized_model) {
752       lua_newtable(L);
753       lua_pushnumber(L,h->color_field.grey._grey_val);
754       lua_rawseti(L,-2,1);
755       lua_setfield(L,-2,"grey");
756     }
757     
758   } else {
759     lua_pushnil(L);
760   }
761 }
762
763 /* dashes are complicated, perhaps it would be better if the
764   object had a PS-compatible representation */
765 static void 
766 mplib_push_dash (lua_State *L, struct mp_graphic_object *h ) {
767   if (h!=NULL) {
768     lua_newtable(L);
769     lua_pushnumber(L,h->dash_scale_field);
770     lua_setfield(L,-2,"scale");
771     /* todo */
772     lua_pushnumber(L,(int)h->dash_p_field);
773     lua_setfield(L,-2,"dashes");
774   } else {
775     lua_pushnil(L);
776   }
777 }
778
779 static void 
780 mplib_push_transform (lua_State *L, struct mp_graphic_object *h ) {
781   int i = 1;
782   if (h!=NULL) {
783     lua_newtable(L);
784     lua_pushnumber(L,h->tx_field);
785     lua_rawseti(L,-2,i); i++;
786     lua_pushnumber(L,h->ty_field);
787     lua_rawseti(L,-2,i); i++;
788     lua_pushnumber(L,h->txx_field);
789     lua_rawseti(L,-2,i); i++;
790     lua_pushnumber(L,h->txy_field);
791     lua_rawseti(L,-2,i); i++;
792     lua_pushnumber(L,h->tyx_field);
793     lua_rawseti(L,-2,i); i++;
794     lua_pushnumber(L,h->tyy_field);
795     lua_rawseti(L,-2,i); i++;
796   } else {
797     lua_pushnil(L);
798   }
799 }
800
801 static char *fill_fields[] = { "type", "path", "htap", "pen", "color", "ljoin", "miterlim", "prescript", "postscript", NULL };
802
803 #define FIELD(A) (strcmp(field,#A)==0)
804
805 static void 
806 mplib_fill_field (lua_State *L, struct mp_graphic_object *h, char *field) {
807   if (FIELD(type)) {
808     lua_pushstring(L,"fill");
809   } else if (FIELD(path)) {
810     mplib_push_path(L, h->path_p_field);
811   } else if (FIELD(htap)) {
812     mplib_push_path(L, h->htap_p_field);
813   } else if (FIELD(pen)) {
814     mplib_push_path(L, h->pen_p_field);
815   } else if (FIELD(color)) {
816     mplib_push_color(L, h);
817   } else if (FIELD(ljoin)) {
818     lua_pushnumber(L,h->ljoin_field);
819   } else if (FIELD(miterlim)) {
820     lua_pushnumber(L,h->miterlim_field);
821   } else if (FIELD(prescript)) {
822     lua_pushstring(L,h->pre_script_field);
823   } else if (FIELD(postscript)) {
824     lua_pushstring(L,h->post_script_field);
825   } else {
826     lua_pushnil(L);
827   }
828 }
829
830 static char *stroked_fields[] = {"type", "path", "pen", "color", "ljoin", "miterlim", "lcap", "dash", "prescript", "postscript", NULL };
831
832 static void 
833 mplib_stroked_field (lua_State *L, struct mp_graphic_object *h, char *field) {
834   if (FIELD(type)) {
835     lua_pushstring(L,"stroked");
836   } else if (FIELD(path)) {
837     mplib_push_path(L, h->path_p_field);
838   } else if (FIELD(pen)) {
839     mplib_push_path(L, h->pen_p_field);
840   } else if (FIELD(color)) {
841     mplib_push_color(L, h);
842   } else if (FIELD(dash)) {
843     mplib_push_dash(L, h);
844   } else if (FIELD(lcap)) {
845     lua_pushnumber(L,h->lcap_field);
846   } else if (FIELD(ljoin)) {
847     lua_pushnumber(L,h->ljoin_field);
848   } else if (FIELD(miterlim)) {
849     lua_pushnumber(L,h->miterlim_field);
850   } else if (FIELD(prescript)) {
851     lua_pushstring(L,h->pre_script_field);
852   } else if (FIELD(postscript)) {
853     lua_pushstring(L,h->post_script_field);
854   } else {
855     lua_pushnil(L);
856   }
857 }
858
859 static char *text_fields[] = { "type", "text", "nametype" "font", "color", "width", "height", "depth", "transform", "prescript", "postscript", NULL };
860
861 /* todo: name_type and font_n do not make sense */
862
863 static void 
864 mplib_text_field (lua_State *L, struct mp_graphic_object *h, char *field) {
865   if (FIELD(type)) {
866     lua_pushstring(L,"text");
867   } else if (FIELD(text)) {
868     lua_pushstring(L,h->text_p_field);
869   } else if (FIELD(nametype)) {
870     lua_pushnumber(L,h->name_type_field);
871   } else if (FIELD(font)) {
872     lua_pushnumber(L,h->font_n_field);
873   } else if (FIELD(color)) {
874     mplib_push_color(L, h);
875   } else if (FIELD(width)) {
876     lua_pushnumber(L,h->width_field);
877   } else if (FIELD(height)) {
878     lua_pushnumber(L,h->height_field);
879   } else if (FIELD(depth)) {
880     lua_pushnumber(L,h->depth_field);
881   } else if (FIELD(transform)) {
882     mplib_push_transform(L,h);
883   } else if (FIELD(prescript)) {
884     lua_pushstring(L,h->pre_script_field);
885   } else if (FIELD(postscript)) {
886     lua_pushstring(L,h->post_script_field);
887   } else {
888     lua_pushnil(L);
889   }
890 }
891
892 static char *special_fields[] = { "type", "prescript", NULL };
893
894 static void 
895 mplib_special_field (lua_State *L, struct mp_graphic_object *h, char *field) {
896   if (FIELD(type)) {
897     lua_pushstring(L,"special");
898   } else if (FIELD(prescript)) {
899     lua_pushstring(L,h->pre_script_field);
900   } else {
901     lua_pushnil(L);
902   }
903 }
904
905 static char *start_bounds_fields[] = { "type", "path", NULL };
906
907 static void 
908 mplib_start_bounds_field (lua_State *L, struct mp_graphic_object *h, char *field) {
909   if (FIELD(type)) {
910     lua_pushstring(L,"start_bounds");
911   } else if (FIELD(path)) {
912     mplib_push_path(L,h->path_p_field);
913   } else {
914     lua_pushnil(L);
915   }
916 }
917
918 static char *start_clip_fields[] = { "type", "path", NULL };
919
920 static void 
921 mplib_start_clip_field (lua_State *L, struct mp_graphic_object *h, char *field) {
922   if (FIELD(type)) {
923     lua_pushstring(L,"start_clip");
924   } else if (FIELD(path)) {
925     mplib_push_path(L,h->path_p_field);
926   } else {
927     lua_pushnil(L);
928   }
929 }
930
931 static char *stop_bounds_fields[] = { "type", NULL };
932
933 static void 
934 mplib_stop_bounds_field (lua_State *L, struct mp_graphic_object *h, char *field) {
935   if (h!=NULL && FIELD(type)) {
936     lua_pushstring(L,"stop_bounds");
937   } else {
938     lua_pushnil(L);
939   }
940 }
941
942 static char *stop_clip_fields[] = { "type", NULL };
943
944 static void 
945 mplib_stop_clip_field (lua_State *L, struct mp_graphic_object *h, char *field) {
946   if (h!=NULL && FIELD(type)) {
947     lua_pushstring(L,"stop_clip");
948   } else {
949     lua_pushnil(L);
950   }
951 }
952
953 static char *no_fields[] =  { NULL };
954
955 static int
956 mplib_gr_fields (lua_State *L) {
957   char **fields;
958   char *f;
959   int i = 1;
960   struct mp_graphic_object **hh = is_gr_object(L,1);
961   if (*hh) {
962     switch ((*hh)->_type_field) {
963     case mp_fill_code:         fields = fill_fields;         break;
964     case mp_stroked_code:      fields = stroked_fields;      break;
965     case mp_text_code:         fields = text_fields;         break;
966     case mp_special_code:      fields = special_fields;      break;
967     case mp_start_clip_code:   fields = start_clip_fields;   break;
968     case mp_start_bounds_code: fields = start_bounds_fields; break;
969     case mp_stop_clip_code:    fields = stop_clip_fields;    break;
970     case mp_stop_bounds_code:  fields = stop_bounds_fields;  break;
971     default:                   fields = no_fields;
972     }
973     lua_newtable(L);
974     for (f = *fields; f != NULL; f++) {
975       lua_pushstring(L,f);
976       lua_rawseti(L,-2,i); i++;
977     }
978   } else {
979     lua_pushnil(L);
980   }
981   return 1;
982 }
983
984 static int
985 mplib_gr_index (lua_State *L) {
986   struct mp_graphic_object **hh = is_gr_object(L,1);
987   char *field = (char *)luaL_checkstring(L,2);
988   if (*hh) {
989     switch ((*hh)->_type_field) {
990     case mp_fill_code:         mplib_fill_field(L,*hh,field);         break;
991     case mp_stroked_code:      mplib_stroked_field(L,*hh,field);      break;
992     case mp_text_code:         mplib_text_field(L,*hh,field);         break;
993     case mp_special_code:      mplib_special_field(L,*hh,field);      break;
994     case mp_start_clip_code:   mplib_start_clip_field(L,*hh,field);   break;
995     case mp_start_bounds_code: mplib_start_bounds_field(L,*hh,field); break;
996     case mp_stop_clip_code:    mplib_stop_clip_field(L,*hh,field);    break;
997     case mp_stop_bounds_code:  mplib_stop_bounds_field(L,*hh,field);  break;
998     default:                   lua_pushnil(L);
999     }    
1000   } else {
1001     lua_pushnil(L);
1002   }
1003   return 1;
1004 }
1005
1006
1007 static const struct luaL_reg mplib_meta[] = {
1008   {"__gc",               mplib_collect}, 
1009   {"__tostring",         mplib_tostring},
1010   {NULL, NULL}                /* sentinel */
1011 };
1012
1013 static const struct luaL_reg mplib_fig_meta[] = {
1014   {"__gc",               mplib_fig_collect    },
1015   {"__tostring",         mplib_fig_tostring   },
1016   {"objects",            mplib_fig_body       },
1017   {"postscript",         mplib_fig_postscript },
1018   {"boundingbox",        mplib_fig_bb         },
1019   {NULL, NULL}                /* sentinel */
1020 };
1021
1022 static const struct luaL_reg mplib_gr_meta[] = {
1023   {"__gc",               mplib_gr_collect  },
1024   {"__tostring",         mplib_gr_tostring },
1025   {"fields",             mplib_gr_fields   },
1026   {"__index",            mplib_gr_index    },
1027   {NULL, NULL}                /* sentinel */
1028 };
1029
1030
1031 static const struct luaL_reg mplib_d [] = {
1032   {"run",                mplib_run },
1033   {"execute",            mplib_execute },
1034   {"finish",             mplib_finish },
1035   {NULL, NULL}  /* sentinel */
1036 };
1037
1038
1039 static const struct luaL_reg mplib_m[] = {
1040   {"new",               mplib_new},
1041   {NULL, NULL}                /* sentinel */
1042 };
1043
1044
1045 int 
1046 luaopen_mp (lua_State *L) {
1047   luaL_newmetatable(L,MPLIB_GR_METATABLE);
1048   lua_pushvalue(L, -1); /* push metatable */
1049   lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1050   luaL_register(L, NULL, mplib_gr_meta);  /* object meta methods */
1051   lua_pop(L,1);
1052
1053   luaL_newmetatable(L,MPLIB_FIG_METATABLE);
1054   lua_pushvalue(L, -1); /* push metatable */
1055   lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1056   luaL_register(L, NULL, mplib_fig_meta);  /* figure meta methods */
1057   lua_pop(L,1);
1058
1059   luaL_newmetatable(L,MPLIB_METATABLE);
1060   lua_pushvalue(L, -1); /* push metatable */
1061   lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1062   luaL_register(L, NULL, mplib_meta);  /* meta methods */
1063   luaL_register(L, NULL, mplib_d);  /* dict methods */
1064   luaL_register(L, "mp", mplib_m); /* module functions */
1065   return 1;
1066 }
1067