1 /* ltexlib.c
2 
3    Copyright 2006-2012 Taco Hoekwater <taco@luatex.org>
4 
5    This file is part of LuaTeX.
6 
7    LuaTeX is free software; you can redistribute it and/or modify it under
8    the terms of the GNU General Public License as published by the Free
9    Software Foundation; either version 2 of the License, or (at your
10    option) any later version.
11 
12    LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15    License for more details.
16 
17    You should have received a copy of the GNU General Public License along
18    with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
19 
20 /* hh-ls: Because the lists start with a temp node, we have to set the prev link
21 to nil because otherwise at the lua end we expose temp which can create havoc. In the
22 setter no prev link is created so we can presume that it's not used later on. */
23 
24 #include "ptexlib.h"
25 #include "lua/luatex-api.h"
26 
27 
28 #define attribute(A) eqtb[attribute_base+(A)].hh.rh
29 #define dimen(A) eqtb[scaled_base+(A)].hh.rh
30 #undef skip
31 #define skip(A) eqtb[skip_base+(A)].hh.rh
32 #define mu_skip(A) eqtb[mu_skip_base+(A)].hh.rh
33 #define count(A) eqtb[count_base+(A)].hh.rh
34 #define box(A) equiv(box_base+(A))
35 
36 /* tex random generators */
37 extern int unif_rand(int );
38 extern int norm_rand(void );
39 extern void init_randoms(int );
40 
41 
42 typedef struct {
43     char *text;
44     unsigned int tsize;
45     void *next;
46     boolean partial;
47     int cattable;
48 } rope;
49 
50 typedef struct {
51     rope *head;
52     rope *tail;
53     char complete;              /* currently still writing ? */
54 } spindle;
55 
56 #define  PARTIAL_LINE       1
57 #define  FULL_LINE          0
58 
59 #define  write_spindle spindles[spindle_index]
60 #define  read_spindle  spindles[(spindle_index-1)]
61 
62 static int spindle_size = 0;
63 static spindle *spindles = NULL;
64 static int spindle_index = 0;
65 
66 
67 
luac_store(lua_State * L,int i,int partial,int cattable)68 static void luac_store(lua_State * L, int i, int partial, int cattable)
69 {
70     char *st;
71     const char *sttemp;
72     size_t tsize;
73     rope *rn = NULL;
74     sttemp = lua_tolstring(L, i, &tsize);
75     st = xmalloc((unsigned) (tsize + 1));
76     memcpy(st, sttemp, (tsize + 1));
77     if (st) {
78         luacstrings++;
79         rn = (rope *) xmalloc(sizeof(rope));
80         rn->text = st;
81         rn->tsize = (unsigned) tsize;
82         rn->partial = partial;
83         rn->cattable = cattable;
84         rn->next = NULL;
85         if (write_spindle.head == NULL) {
86             assert(write_spindle.tail == NULL);
87             write_spindle.head = rn;
88         } else {
89             write_spindle.tail->next = rn;
90         }
91         write_spindle.tail = rn;
92         write_spindle.complete = 0;
93     }
94 }
95 
96 
do_luacprint(lua_State * L,int partial,int deftable)97 static int do_luacprint(lua_State * L, int partial, int deftable)
98 {
99     int i, n;
100     int cattable = deftable;
101     int startstrings = 1;
102     n = lua_gettop(L);
103     if (cattable != NO_CAT_TABLE) {
104         if (lua_type(L, 1) == LUA_TNUMBER && n > 1) {
105             cattable=(int)lua_tonumber(L, 1);
106             startstrings = 2;
107             if (cattable != -1 && cattable != -2 && !valid_catcode_table(cattable)) {
108        cattable = DEFAULT_CAT_TABLE;
109      }
110         }
111     }
112     if (lua_type(L, startstrings) == LUA_TTABLE) {
113         for (i = 1;; i++) {
114             lua_rawgeti(L, startstrings, i);
115             if (lua_isstring(L, -1)) {
116                 luac_store(L, -1, partial, cattable);
117                 lua_pop(L, 1);
118             } else {
119                 break;
120             }
121         }
122     } else {
123         for (i = startstrings; i <= n; i++) {
124             if (!lua_isstring(L, i)) {
125                 luaL_error(L, "no string to print");
126             }
127             luac_store(L, i, partial, cattable);
128         }
129         /* hh: We could use this but it makes not much different, apart from allocating more ropes so less
130            memory. To be looked into: lua 5.2 buffer mechanism as now we still hash the concatination. This
131            test was part of the why-eis-luajit-so-slow on crited experiments. */
132         /*
133         if (startstrings == n) {
134             luac_store(L, n, partial, cattable);
135         } else {
136             lua_concat(L,n-startstrings+1);
137             luac_store(L, startstrings, partial, cattable);
138         }
139         */
140     }
141     return 0;
142 }
143 
144 
145 
146 
luacwrite(lua_State * L)147 static int luacwrite(lua_State * L)
148 {
149     return do_luacprint(L, FULL_LINE, NO_CAT_TABLE);
150 }
151 
luacprint(lua_State * L)152 static int luacprint(lua_State * L)
153 {
154     return do_luacprint(L, FULL_LINE, DEFAULT_CAT_TABLE);
155 }
156 
luacsprint(lua_State * L)157 static int luacsprint(lua_State * L)
158 {
159     return do_luacprint(L, PARTIAL_LINE, DEFAULT_CAT_TABLE);
160 }
161 
luactprint(lua_State * L)162 static int luactprint(lua_State * L)
163 {
164     int i, j, n;
165     int cattable, startstrings;
166     n = lua_gettop(L);
167     for (i = 1; i <= n; i++) {
168         cattable = DEFAULT_CAT_TABLE;
169         startstrings = 1;
170         if (lua_type(L, i) != LUA_TTABLE) {
171             luaL_error(L, "no string to print");
172         }
173         lua_pushvalue(L, i);    /* push the table */
174         lua_pushnumber(L, 1);
175         lua_gettable(L, -2);
176         if (lua_type(L, -1) == LUA_TNUMBER) {
177             cattable=(int)lua_tonumber(L, -1);
178             startstrings = 2;
179             if (cattable != -1 && cattable != -2 && !valid_catcode_table(cattable)) {
180 	      cattable = DEFAULT_CAT_TABLE;
181 	    }
182         }
183         lua_pop(L, 1);
184 
185         for (j = startstrings;; j++) {
186             lua_pushnumber(L, j);
187             lua_gettable(L, -2);
188             if (lua_type(L, -1) == LUA_TSTRING) {
189                 luac_store(L, -1, PARTIAL_LINE, cattable);
190                 lua_pop(L, 1);
191             } else {
192                 lua_pop(L, 1);
193                 break;
194             }
195         }
196         lua_pop(L, 1);          /* pop the table */
197     }
198     return 0;
199 }
200 
201 
luacstring_cattable(void)202 int luacstring_cattable(void)
203 {
204     return (int) read_spindle.tail->cattable;
205 }
206 
luacstring_partial(void)207 int luacstring_partial(void)
208 {
209     return read_spindle.tail->partial;
210 }
211 
luacstring_final_line(void)212 int luacstring_final_line(void)
213 {
214     return (read_spindle.tail->next == NULL);
215 }
216 
luacstring_input(void)217 int luacstring_input(void)
218 {
219     char *st;
220     int ret;
221     rope *t = read_spindle.head;
222     if (!read_spindle.complete) {
223         read_spindle.complete = 1;
224         read_spindle.tail = NULL;
225     }
226     if (t == NULL) {
227         if (read_spindle.tail != NULL)
228             free(read_spindle.tail);
229         read_spindle.tail = NULL;
230         return 0;
231     }
232     if (t->text != NULL) {
233         st = t->text;
234         /* put that thing in the buffer */
235         last = first;
236         ret = last;
237         check_buffer_overflow(last + (int) t->tsize);
238 
239         while (t->tsize-- > 0)
240             buffer[last++] = (packed_ASCII_code) * st++;
241         if (!t->partial) {
242             while (last - 1 > ret && buffer[last - 1] == ' ')
243                 last--;
244         }
245         free(t->text);
246         t->text = NULL;
247     }
248     if (read_spindle.tail != NULL) {    /* not a one-liner */
249         free(read_spindle.tail);
250     }
251     read_spindle.tail = t;
252     read_spindle.head = t->next;
253     return 1;
254 }
255 
256 /* open for reading, and make a new one for writing */
luacstring_start(int n)257 void luacstring_start(int n)
258 {
259     (void) n;                   /* for -W */
260     spindle_index++;
261     if (spindle_size == spindle_index) {        /* add a new one */
262         spindles =
263             xrealloc(spindles,
264                      (unsigned) (sizeof(spindle) *
265                                  (unsigned) (spindle_size + 1)));
266         spindles[spindle_index].head = NULL;
267         spindles[spindle_index].tail = NULL;
268         spindles[spindle_index].complete = 0;
269         spindle_size++;
270     }
271 }
272 
273 /* close for reading */
274 
luacstring_close(int n)275 void luacstring_close(int n)
276 {
277     rope *next, *t;
278     (void) n;                   /* for -W */
279     next = read_spindle.head;
280     while (next != NULL) {
281         if (next->text != NULL)
282             free(next->text);
283         t = next;
284         next = next->next;
285         if (t==read_spindle.tail) {
286 	    read_spindle.tail = NULL; // prevent double-free
287 	}
288         free(t);
289     }
290     read_spindle.head = NULL;
291     if (read_spindle.tail != NULL)
292         free(read_spindle.tail);
293     read_spindle.tail = NULL;
294     read_spindle.complete = 0;
295     spindle_index--;
296 }
297 
298 /* local (static) versions */
299 
300 #define check_index_range(j,s)						\
301   if (j<0 || j > 65535) {							\
302     luaL_error(L, "incorrect index value %d for tex.%s()", (int)j, s);  }
303 
304 
scan_integer_part(lua_State * L,const char * ss,int * ret,int * radix_ret)305 static const char *scan_integer_part(lua_State * L, const char *ss, int *ret,
306                                      int *radix_ret)
307 {
308     boolean negative = false;   /* should the answer be negated? */
309     int m;                      /* |$2^{31}$ / radix|, the threshold of danger */
310     int d;                      /* the digit just scanned */
311     boolean vacuous;            /* have no digits appeared? */
312     boolean OK_so_far;          /* has an error message been issued? */
313     int radix1 = 0;              /* the radix of the integer */
314     int c = 0;                  /* the current character */
315     const char *s;              /* where we stopped in the string |ss| */
316     integer val = 0;        /* return value */
317     s = ss;
318     do {
319         do {
320             c = *s++;
321         } while (c && c == ' ');
322         if (c == '-') {
323             negative = !negative;
324             c = '+';
325         }
326     } while (c == '+');
327 
328 
329     radix1 = 10;
330     m = 214748364;
331     if (c == '\'') {
332         radix1 = 8;
333         m = 02000000000;
334         c = *s++;
335     } else if (c == '"') {
336         radix1 = 16;
337         m = 01000000000;
338         c = *s++;
339     }
340     vacuous = true;
341     val = 0;
342     OK_so_far = true;
343 
344     /* Accumulate the constant until |cur_tok| is not a suitable digit */
345     while (1) {
346         if ((c < '0' + radix1) && (c >= '0') && (c <= '0' + 9)) {
347             d = c - '0';
348         } else if (radix1 == 16) {
349             if ((c <= 'A' + 5) && (c >= 'A')) {
350                 d = c - 'A' + 10;
351             } else if ((c <= 'a' + 5) && (c >= 'a')) {
352                 d = c - 'a' + 10;
353             } else {
354                 break;
355             }
356         } else {
357             break;
358         }
359         vacuous = false;
360         if ((val >= m) && ((val > m) || (d > 7) || (radix1 != 10))) {
361             if (OK_so_far) {
362 		luaL_error(L, "Number too big");
363                 val = infinity;
364                 OK_so_far = false;
365             }
366         } else {
367             val = val * radix1 + d;
368         }
369         c = *s++;
370     }
371     if (vacuous) {
372         /* Express astonishment that no number was here */
373         luaL_error(L, "Missing number, treated as zero");
374     }
375     if (negative)
376         val = -val;
377     *ret = val;
378     *radix_ret = radix1;
379     if (c != ' ' && s > ss)
380         s--;
381     return s;
382 }
383 
384 #define set_conversion(A,B) do { num=(A); denom=(B); } while(0)
385 
386 
scan_dimen_part(lua_State * L,const char * ss,int * ret)387 static const char *scan_dimen_part(lua_State * L, const char *ss, int *ret)
388 /* sets |cur_val| to a dimension */
389 {
390     boolean negative = false;   /* should the answer be negated? */
391     int f = 0;                  /* numerator of a fraction whose denominator is $2^{16}$ */
392     int num, denom;             /* conversion ratio for the scanned units */
393     int k;                      /* number of digits in a decimal fraction */
394     scaled v;                   /* an internal dimension */
395     int save_cur_val;           /* temporary storage of |cur_val| */
396     int c;                      /* the current character */
397     const char *s = ss;         /* where we are in the string */
398     int radix1 = 0;              /* the current radix */
399     int rdig[18];               /* to save the |dig[]| array */
400     int saved_tex_remainder;    /* to save |tex_remainder|  */
401     int saved_arith_error;      /* to save |arith_error|  */
402     int saved_cur_val;          /* to save the global |cur_val| */
403     saved_tex_remainder = tex_remainder;
404     saved_arith_error = arith_error;
405     saved_cur_val = cur_val;
406     /* Get the next non-blank non-sign... */
407     do {
408         /* Get the next non-blank non-call token */
409         do {
410             c = *s++;
411         } while (c && c == ' ');
412         if (c == '-') {
413             negative = !negative;
414             c = '+';
415         }
416     } while (c == '+');
417 
418     if (c == ',') {
419         c = '.';
420     }
421     if (c != '.') {
422         s = scan_integer_part(L, (s > ss ? (s - 1) : ss), &cur_val, &radix1);
423         c = *s;
424     } else {
425         radix1 = 10;
426         cur_val = 0;
427         c = *(--s);
428     }
429     if (c == ',')
430         c = '.';
431     if ((radix1 == 10) && (c == '.')) {
432         /* Scan decimal fraction */
433         for (k = 0; k < 18; k++)
434             rdig[k] = dig[k];
435         k = 0;
436         s++;                    /* get rid of the '.' */
437         while (1) {
438             c = *s++;
439             if ((c > '0' + 9) || (c < '0'))
440                 break;
441             if (k < 17) {       /* digits for |k>=17| cannot affect the result */
442                 dig[k++] = c - '0';
443             }
444         }
445         f = round_decimals(k);
446         if (c != ' ')
447             c = *(--s);
448         for (k = 0; k < 18; k++)
449             dig[k] = rdig[k];
450     }
451     if (cur_val < 0) {          /* in this case |f=0| */
452         negative = !negative;
453         cur_val = -cur_val;
454     }
455 
456     /* Scan for (u)units that are internal dimensions;
457        |goto attach_sign| with |cur_val| set if found */
458     save_cur_val = cur_val;
459     /* Get the next non-blank non-call... */
460     do {
461         c = *s++;
462     } while (c && c == ' ');
463     if (c != ' ')
464         c = *(--s);
465     if (strncmp(s, "em", 2) == 0) {
466         s += 2;
467         v = (quad(get_cur_font()));
468     } else if (strncmp(s, "ex", 2) == 0) {
469         s += 2;
470         v = (x_height(get_cur_font()));
471     } else if (strncmp(s, "px", 2) == 0) {
472         s += 2;
473         v = dimen_par(pdf_px_dimen_code);
474     } else {
475         goto NOT_FOUND;
476     }
477     c = *s++;
478     if (c != ' ') {
479         c = *(--s);
480     }
481     cur_val = nx_plus_y(save_cur_val, v, xn_over_d(v, f, 0200000));
482     goto ATTACH_SIGN;
483   NOT_FOUND:
484 
485     /* Scan for (m)\.{mu} units and |goto attach_fraction| */
486     if (strncmp(s, "mu", 2) == 0) {
487         s += 2;
488         goto ATTACH_FRACTION;
489     }
490     if (strncmp(s, "true", 4) == 0) {
491         /* Adjust (f)for the magnification ratio */
492         s += 4;
493         prepare_mag();
494         if (int_par(mag_code) != 1000) {
495             cur_val = xn_over_d(cur_val, 1000, int_par(mag_code));
496             f = (1000 * f + 0200000 * tex_remainder) / int_par(mag_code);
497             cur_val = cur_val + (f / 0200000);
498             f = f % 0200000;
499         }
500         do {
501             c = *s++;
502         } while (c && c == ' ');
503         c = *(--s);
504     }
505     if (strncmp(s, "pt", 2) == 0) {
506         s += 2;
507         goto ATTACH_FRACTION;   /* the easy case */
508     }
509     /* Scan for (a)all other units and adjust |cur_val| and |f| accordingly;
510        |goto done| in the case of scaled points */
511 
512     if (strncmp(s, "in", 2) == 0) {
513         s += 2;
514         set_conversion(7227, 100);
515     } else if (strncmp(s, "pc", 2) == 0) {
516         s += 2;
517         set_conversion(12, 1);
518     } else if (strncmp(s, "cm", 2) == 0) {
519         s += 2;
520         set_conversion(7227, 254);
521     } else if (strncmp(s, "mm", 2) == 0) {
522         s += 2;
523         set_conversion(7227, 2540);
524     } else if (strncmp(s, "bp", 2) == 0) {
525         s += 2;
526         set_conversion(7227, 7200);
527     } else if (strncmp(s, "dd", 2) == 0) {
528         s += 2;
529         set_conversion(1238, 1157);
530     } else if (strncmp(s, "cc", 2) == 0) {
531         s += 2;
532         set_conversion(14856, 1157);
533     } else if (strncmp(s, "nd", 2) == 0) {
534         s += 2;
535         set_conversion(685, 642);
536     } else if (strncmp(s, "nc", 2) == 0) {
537         s += 2;
538         set_conversion(1370, 107);
539     } else if (strncmp(s, "sp", 2) == 0) {
540         s += 2;
541         goto DONE;
542     } else {
543         /* Complain about unknown unit and |goto done2| */
544         luaL_error(L, "Illegal unit of measure (pt inserted)");
545         goto DONE2;
546     }
547     cur_val = xn_over_d(cur_val, num, denom);
548     f = (num * f + 0200000 * tex_remainder) / denom;
549     cur_val = cur_val + (f / 0200000);
550     f = f % 0200000;
551   DONE2:
552   ATTACH_FRACTION:
553     if (cur_val >= 040000)
554         arith_error = true;
555     else
556         cur_val = cur_val * 65536 + f;
557   DONE:
558     /* Scan an optional space */
559     c = *s++;
560     if (c != ' ')
561         s--;
562   ATTACH_SIGN:
563     if (arith_error || (abs(cur_val) >= 010000000000)) {
564         /* Report that this dimension is out of range */
565         luaL_error(L, "Dimension too large");
566         cur_val = max_dimen;
567     }
568     if (negative)
569         cur_val = -cur_val;
570     *ret = cur_val;
571     tex_remainder = saved_tex_remainder;
572     arith_error = saved_arith_error;
573     cur_val = saved_cur_val;
574     return s;
575 }
576 
dimen_to_number(lua_State * L,const char * s)577 int dimen_to_number(lua_State * L, const char *s)
578 {
579     int j = 0;
580     const char *d = scan_dimen_part(L, s, &j);
581     if (*d) {
582         luaL_error(L, "conversion failed (trailing junk?)");
583         j = 0;
584     }
585     return j;
586 }
587 
588 
tex_scaledimen(lua_State * L)589 static int tex_scaledimen(lua_State * L)
590 {                               /* following vsetdimen() */
591     int sp;
592     if (!lua_isnumber(L, 1)) {
593         if (lua_isstring(L, 1)) {
594             sp = dimen_to_number(L, lua_tostring(L, 1));
595         } else {
596             luaL_error(L, "argument must be a string or a number");
597             return 0;
598         }
599     } else {
600         sp=(int)lua_tonumber(L, 1);
601     }
602     lua_pushnumber(L, sp);
603     return 1;
604 }
605 
texerror(lua_State * L)606 static int texerror (lua_State * L)
607 {
608     int i, n, l;
609     const char **errhlp = NULL;
610     const char *error = luaL_checkstring(L,1);
611     n = lua_gettop(L);
612     if (n==2 && lua_type(L, n) == LUA_TTABLE) {
613         l = 1; /* |errhlp| is terminated by a NULL entry */
614         for (i = 1;; i++) {
615             lua_rawgeti(L, n, i);
616             if (lua_isstring(L, -1)) {
617                 l++;
618                 lua_pop(L, 1);
619             } else {
620                 lua_pop(L, 1);
621                 break;
622             }
623         }
624         if (l>1) {
625           errhlp = xmalloc(l * sizeof(char *));
626           memset(errhlp,0,l * sizeof(char *));
627           for (i = 1;; i++) {
628             lua_rawgeti(L, n, i);
629             if (lua_isstring(L, -1)) {
630                 errhlp[(i-1)] = lua_tostring(L,-1);
631                 lua_pop(L, 1);
632             } else {
633                 break;
634             }
635 	  }
636 	}
637     }
638     deletions_allowed = false;
639     tex_error(error, errhlp);
640     if (errhlp)
641       xfree(errhlp);
642     deletions_allowed = true;
643     return 0;
644 }
645 
get_item_index(lua_State * L,int i,int base)646 static int get_item_index(lua_State * L, int i, int base)
647 {
648     size_t kk;
649     int k;
650     int cur_cs1;
651     const char *s;
652     switch (lua_type(L, i)) {
653     case LUA_TSTRING:
654         s = lua_tolstring(L, i, &kk);
655         cur_cs1 = string_lookup(s, kk);
656         if (cur_cs1 == undefined_control_sequence || cur_cs1 == undefined_cs_cmd)
657             k = -1;             /* guarandeed invalid */
658         else
659             k = (equiv(cur_cs1) - base);
660         break;
661     case LUA_TNUMBER:
662         k = (int) luaL_checkinteger(L, i);
663         break;
664     default:
665         luaL_error(L, "argument must be a string or a number");
666         k = -1;                 /* not a valid index */
667     }
668     return k;
669 }
670 
vsetdimen(lua_State * L,int is_global)671 static int vsetdimen(lua_State * L, int is_global)
672 {
673     int i, j, err;
674     int k;
675     int save_global_defs = int_par(global_defs_code);
676     if (is_global)
677         int_par(global_defs_code) = 1;
678     i = lua_gettop(L);
679     j = 0;
680     /* find the value */
681     if (!lua_isnumber(L, i)) {
682         if (lua_isstring(L, i)) {
683             j = dimen_to_number(L, lua_tostring(L, i));
684         } else {
685             luaL_error(L, "unsupported value type");
686         }
687     } else {
688         j=(int)lua_tonumber(L, i);
689     }
690     k = get_item_index(L, (i - 1), scaled_base);
691     check_index_range(k, "setdimen");
692     err = set_tex_dimen_register(k, j);
693     int_par(global_defs_code) = save_global_defs;
694     if (err) {
695         luaL_error(L, "incorrect value");
696     }
697     return 0;
698 }
699 
setdimen(lua_State * L)700 static int setdimen(lua_State * L)
701 {
702     int isglobal = 0;
703     int n = lua_gettop(L);
704     if (n == 3 && lua_isstring(L, 1)) {
705         const char *s = lua_tostring(L, 1);
706         if (lua_key_eq(s,global))
707             isglobal = 1;
708     }
709     return vsetdimen(L, isglobal);
710 }
711 
getdimen(lua_State * L)712 static int getdimen(lua_State * L)
713 {
714     int j;
715     int k;
716     k = get_item_index(L, lua_gettop(L), scaled_base);
717     check_index_range(k, "getdimen");
718     j = get_tex_dimen_register(k);
719     lua_pushnumber(L, j);
720     return 1;
721 }
722 
vsetskip(lua_State * L,int is_global)723 static int vsetskip(lua_State * L, int is_global)
724 {
725     int i, err;
726     halfword *j;
727     int k;
728     int save_global_defs = int_par(global_defs_code);
729     if (is_global)
730         int_par(global_defs_code) = 1;
731     i = lua_gettop(L);
732     j = check_isnode(L, i);     /* the value */
733     k = get_item_index(L, (i - 1), skip_base);
734     check_index_range(k, "setskip");    /* the index */
735     err = set_tex_skip_register(k, *j);
736     int_par(global_defs_code) = save_global_defs;
737     if (err) {
738         luaL_error(L, "incorrect value");
739     }
740     return 0;
741 }
742 
setskip(lua_State * L)743 static int setskip(lua_State * L)
744 {
745     int isglobal = 0;
746     int n = lua_gettop(L);
747     if (n == 3 && lua_isstring(L, 1)) {
748         const char *s = lua_tostring(L, 1);
749         if (lua_key_eq(s,global))
750             isglobal = 1;
751     }
752     return vsetskip(L, isglobal);
753 }
754 
getskip(lua_State * L)755 static int getskip(lua_State * L)
756 {
757     halfword j;
758     int k;
759     k = get_item_index(L, lua_gettop(L), skip_base);
760     check_index_range(k, "getskip");
761     j = get_tex_skip_register(k);
762     lua_nodelib_push_fast(L, j);
763     return 1;
764 }
765 
766 
767 
vsetcount(lua_State * L,int is_global)768 static int vsetcount(lua_State * L, int is_global)
769 {
770     int i, j, err;
771     int k;
772     int save_global_defs = int_par(global_defs_code);
773     if (is_global)
774         int_par(global_defs_code) = 1;
775     i = lua_gettop(L);
776     j = (int) luaL_checkinteger(L, i);
777     k = get_item_index(L, (i - 1), count_base);
778     check_index_range(k, "setcount");
779     err = set_tex_count_register(k, j);
780     int_par(global_defs_code) = save_global_defs;
781     if (err) {
782         luaL_error(L, "incorrect value");
783     }
784     return 0;
785 }
786 
setcount(lua_State * L)787 static int setcount(lua_State * L)
788 {
789     int isglobal = 0;
790     int n = lua_gettop(L);
791     if (n == 3 && lua_isstring(L, 1)) {
792         const char *s = lua_tostring(L, 1);
793         if (lua_key_eq(s,global))
794             isglobal = 1;
795     }
796     return vsetcount(L, isglobal);
797 }
798 
getcount(lua_State * L)799 static int getcount(lua_State * L)
800 {
801     int j;
802     int k;
803     k = get_item_index(L, lua_gettop(L), count_base);
804     check_index_range(k, "getcount");
805     j = get_tex_count_register(k);
806     lua_pushnumber(L, j);
807     return 1;
808 }
809 
810 
vsetattribute(lua_State * L,int is_global)811 static int vsetattribute(lua_State * L, int is_global)
812 {
813     int i, j, err;
814     int k;
815     int save_global_defs = int_par(global_defs_code);
816     if (is_global)
817         int_par(global_defs_code) = 1;
818     i = lua_gettop(L);
819     j = (int) luaL_checkinteger(L, i);
820     k = get_item_index(L, (i - 1), attribute_base);
821     check_index_range(k, "setattribute");
822     err = set_tex_attribute_register(k, j);
823     int_par(global_defs_code) = save_global_defs;
824     if (err) {
825         luaL_error(L, "incorrect value");
826     }
827     return 0;
828 }
829 
setattribute(lua_State * L)830 static int setattribute(lua_State * L)
831 {
832     int isglobal = 0;
833     int n = lua_gettop(L);
834     if (n == 3 && lua_isstring(L, 1)) {
835         const char *s = lua_tostring(L, 1);
836         if (lua_key_eq(s,global))
837             isglobal = 1;
838     }
839     return vsetattribute(L, isglobal);
840 }
841 
getattribute(lua_State * L)842 static int getattribute(lua_State * L)
843 {
844     int j;
845     int k;
846     k = get_item_index(L, lua_gettop(L), attribute_base);
847     check_index_range(k, "getattribute");
848     j = get_tex_attribute_register(k);
849     lua_pushnumber(L, j);
850     return 1;
851 }
852 
vsettoks(lua_State * L,int is_global)853 static int vsettoks(lua_State * L, int is_global)
854 {
855     int i, err;
856     int k;
857     lstring str;
858     char *s;
859     const char *ss;
860     int save_global_defs = int_par(global_defs_code);
861     if (is_global)
862         int_par(global_defs_code) = 1;
863     i = lua_gettop(L);
864     if (!lua_isstring(L, i)) {
865         luaL_error(L, "unsupported value type");
866     }
867     ss = lua_tolstring(L, i, &str.l);
868     s = xmalloc (str.l+1);
869     memcpy (s, ss, str.l+1);
870     str.s = (unsigned char *)s;
871     k = get_item_index(L, (i - 1), toks_base);
872     check_index_range(k, "settoks");
873     err = set_tex_toks_register(k, str);
874     xfree(str.s);
875     int_par(global_defs_code) = save_global_defs;
876     if (err) {
877         luaL_error(L, "incorrect value");
878     }
879     return 0;
880 }
881 
settoks(lua_State * L)882 static int settoks(lua_State * L)
883 {
884     int isglobal = 0;
885     int n = lua_gettop(L);
886     if (n == 3 && lua_isstring(L, 1)) {
887         const char *s = lua_tostring(L, 1);
888         if (lua_key_eq(s,global))
889             isglobal = 1;
890     }
891     return vsettoks(L, isglobal);
892 }
893 
gettoks(lua_State * L)894 static int gettoks(lua_State * L)
895 {
896     int k;
897     str_number t;
898     char *ss;
899     k = get_item_index(L, lua_gettop(L), toks_base);
900     check_index_range(k, "gettoks");
901     t = get_tex_toks_register(k);
902     ss = makecstring(t);
903     lua_pushstring(L, ss);
904     free(ss);
905     flush_str(t);
906     return 1;
907 }
908 
get_box_id(lua_State * L,int i)909 static int get_box_id(lua_State * L, int i)
910 {
911     const char *s;
912     int cur_cs1, cur_cmd1;
913     size_t k = 0;
914     int j = -1;
915     switch (lua_type(L, i)) {
916     case LUA_TSTRING:
917         s = lua_tolstring(L, i, &k);
918         cur_cs1 = string_lookup(s, k);
919         cur_cmd1 = eq_type(cur_cs1);
920         if (cur_cmd1 == char_given_cmd ||
921             cur_cmd1 == math_given_cmd) {
922             j = equiv(cur_cs1);
923         }
924         break;
925     case LUA_TNUMBER:
926         j=(int)lua_tonumber(L, (i));
927         break;
928     default:
929         luaL_error(L, "argument must be a string or a number");
930         j = -1;                 /* not a valid box id */
931     }
932     return j;
933 }
934 
getbox(lua_State * L)935 static int getbox(lua_State * L)
936 {
937     int k, t;
938     k = get_box_id(L, -1);
939     check_index_range(k, "getbox");
940     t = get_tex_box_register(k);
941     nodelist_to_lua(L, t);
942     return 1;
943 }
944 
vsetbox(lua_State * L,int is_global)945 static int vsetbox(lua_State * L, int is_global)
946 {
947     int j, k, err;
948     int save_global_defs = int_par(global_defs_code);
949     if (is_global)
950         int_par(global_defs_code) = 1;
951     k = get_box_id(L, -2);
952     check_index_range(k, "setbox");
953     if (lua_isboolean(L, -1)) {
954         j = lua_toboolean(L, -1);
955         if (j == 0)
956             j = null;
957         else
958             return 0;
959     } else {
960         j = nodelist_from_lua(L);
961         if (j != null && type(j) != hlist_node && type(j) != vlist_node) {
962             luaL_error(L, "setbox: incompatible node type (%s)\n",
963                             get_node_name(type(j), subtype(j)));
964             return 0;
965         }
966 
967     }
968     err = set_tex_box_register(k, j);
969     int_par(global_defs_code) = save_global_defs;
970     if (err) {
971         luaL_error(L, "incorrect value");
972     }
973     return 0;
974 }
975 
setbox(lua_State * L)976 static int setbox(lua_State * L)
977 {
978     int isglobal = 0;
979     int n = lua_gettop(L);
980     if (n == 3 && lua_isstring(L, 1)) {
981         const char *s = lua_tostring(L, 1);
982         if (lua_key_eq(s,global))
983             isglobal = 1;
984     }
985     return vsetbox(L, isglobal);
986 }
987 
988 #define check_char_range(j,s,lim)					\
989     if (j<0 || j >= lim) {						\
990 	luaL_error(L, "incorrect character value %d for tex.%s()", (int)j, s);  }
991 
992 
setcode(lua_State * L,void (* setone)(int,halfword,quarterword),void (* settwo)(int,halfword,quarterword),const char * name,int lim)993 static int setcode (lua_State *L, void (*setone)(int,halfword,quarterword),
994 		    void (*settwo)(int,halfword,quarterword), const char *name, int lim)
995 {
996     int ch;
997     halfword val, ucval;
998     int level = cur_level;
999     int n = lua_gettop(L);
1000     int f = 1;
1001     if (n>1 && lua_type(L,1) == LUA_TTABLE)
1002 	f++;
1003     if (n>2 && lua_isstring(L, f)) {
1004         const char *s = lua_tostring(L, f);
1005         if (lua_key_eq(s,global)) {
1006             level = level_one;
1007 	    f++;
1008 	}
1009     }
1010     ch = (int) luaL_checkinteger(L, f);
1011     check_char_range(ch, name, 65536*17);
1012     val = (halfword) luaL_checkinteger(L, f+1);
1013     check_char_range(val, name, lim);
1014     (setone)(ch, val, level);
1015     if (settwo != NULL && n-f == 2) {
1016 	ucval = (halfword) luaL_checkinteger(L, f+2);
1017         check_char_range(ucval, name, lim);
1018 	(settwo)(ch, ucval, level);
1019     }
1020     return 0;
1021 }
1022 
setlccode(lua_State * L)1023 static int setlccode(lua_State * L)
1024 {
1025     return setcode(L, &set_lc_code, &set_uc_code, "setlccode",  65536*17);
1026 }
1027 
getlccode(lua_State * L)1028 static int getlccode(lua_State * L)
1029 {
1030     int ch = (int) luaL_checkinteger(L, -1);
1031     check_char_range(ch, "getlccode", 65536*17);
1032     lua_pushnumber(L, get_lc_code(ch));
1033     return 1;
1034 }
1035 
setuccode(lua_State * L)1036 static int setuccode(lua_State * L)
1037 {
1038     return setcode(L, &set_uc_code, &set_lc_code, "setuccode", 65536*17);
1039 }
1040 
getuccode(lua_State * L)1041 static int getuccode(lua_State * L)
1042 {
1043     int ch = (int) luaL_checkinteger(L, -1);
1044     check_char_range(ch, "getuccode",  65536*17);
1045     lua_pushnumber(L, get_uc_code(ch));
1046     return 1;
1047 }
1048 
setsfcode(lua_State * L)1049 static int setsfcode(lua_State * L)
1050 {
1051     return setcode(L, &set_sf_code, NULL, "setsfcode", 32768);
1052 }
1053 
getsfcode(lua_State * L)1054 static int getsfcode(lua_State * L)
1055 {
1056     int ch = (int) luaL_checkinteger(L, -1);
1057     check_char_range(ch, "getsfcode",  65536*17);
1058     lua_pushnumber(L, get_sf_code(ch));
1059     return 1;
1060 }
1061 
setcatcode(lua_State * L)1062 static int setcatcode(lua_State * L)
1063 {
1064     int ch;
1065     halfword val;
1066     int level = cur_level;
1067     int cattable = int_par(cat_code_table_code);
1068     int n = lua_gettop(L);
1069     int f = 1;
1070     if (n>1 && lua_type(L,1) == LUA_TTABLE)
1071 	f++;
1072     if (n>2 && lua_isstring(L, f)) {
1073         const char *s = lua_tostring(L, f);
1074         if (lua_key_eq(s,global)) {
1075             level = level_one;
1076 	    f++;
1077 	}
1078     }
1079     if (n-f == 2) {
1080 	cattable = (int) luaL_checkinteger(L, -3);
1081     }
1082     ch = (int) luaL_checkinteger(L, -2);
1083     check_char_range(ch, "setcatcode", 65536*17);
1084     val = (halfword) luaL_checkinteger(L, -1);
1085     check_char_range(val, "setcatcode", 16);
1086     set_cat_code(cattable, ch, val, level);
1087     return 0;
1088 }
1089 
getcatcode(lua_State * L)1090 static int getcatcode(lua_State * L)
1091 {
1092     int cattable = int_par(cat_code_table_code);
1093     int ch = (int) luaL_checkinteger(L, -1);
1094     if (lua_gettop(L)>=2 && lua_type(L,-2)==LUA_TNUMBER) {
1095 	cattable = luaL_checkinteger(L, -2);
1096     }
1097     check_char_range(ch, "getcatcode",  65536*17);
1098     lua_pushnumber(L, get_cat_code(cattable, ch));
1099     return 1;
1100 }
1101 
1102 
setmathcode(lua_State * L)1103 static int setmathcode(lua_State * L)
1104 {
1105     int ch;
1106     halfword cval, fval, chval;
1107     int level = cur_level;
1108     int n = lua_gettop(L);
1109     int f = 1;
1110     if (n>1 && lua_type(L,1) == LUA_TTABLE)
1111 	f++;
1112     if (n>2 && lua_isstring(L, f)) {
1113         const char *s = lua_tostring(L, f);
1114         if (lua_key_eq(s,global)) {
1115             level = level_one;
1116 	    f++;
1117 	}
1118     }
1119     if (n-f!=1 || lua_type(L,f+1) != LUA_TTABLE) {
1120 	luaL_error(L, "Bad arguments for tex.setmathcode()");
1121     }
1122     ch = (int) luaL_checkinteger(L, -2);
1123     check_char_range(ch, "setmathcode", 65536*17);
1124 
1125     lua_rawgeti(L, -1, 1);
1126     cval = (halfword) luaL_checkinteger(L, -1);
1127     lua_rawgeti(L, -2, 2);
1128     fval = (halfword) luaL_checkinteger(L, -1);
1129     lua_rawgeti(L, -3, 3);
1130     chval = (halfword) luaL_checkinteger(L, -1);
1131     lua_pop(L,3);
1132 
1133     check_char_range(cval, "setmathcode", 8);
1134     check_char_range(fval, "setmathcode", 256);
1135     check_char_range(chval, "setmathcode", 65536*17);
1136     set_math_code(ch, xetex_mathcode, cval,fval, chval, (quarterword) (level));
1137     return 0;
1138 }
1139 
getmathcode(lua_State * L)1140 static int getmathcode(lua_State * L)
1141 {
1142     mathcodeval mval = { 0, 0, 0, 0 };
1143     int ch = (int) luaL_checkinteger(L, -1);
1144     check_char_range(ch, "getmathcode",  65536*17);
1145     mval = get_math_code(ch);
1146     lua_newtable(L);
1147     lua_pushnumber(L,mval.class_value);
1148     lua_rawseti(L, -2, 1);
1149     lua_pushnumber(L,mval.family_value);
1150     lua_rawseti(L, -2, 2);
1151     lua_pushnumber(L,mval.character_value);
1152     lua_rawseti(L, -2, 3);
1153     return 1;
1154 }
1155 
1156 
1157 
setdelcode(lua_State * L)1158 static int setdelcode(lua_State * L)
1159 {
1160     int ch;
1161     halfword sfval, scval, lfval, lcval;
1162     int level = cur_level;
1163     int n = lua_gettop(L);
1164     int f = 1;
1165     if (n>1 && lua_type(L,1) == LUA_TTABLE)
1166 	f++;
1167     if (n>2 && lua_isstring(L, f)) {
1168         const char *s = lua_tostring(L, f);
1169         if (lua_key_eq(s,global)) {
1170             level = level_one;
1171 	    f++;
1172 	}
1173     }
1174     if (n-f!=1 || lua_type(L,f+1) != LUA_TTABLE) {
1175 	luaL_error(L, "Bad arguments for tex.setdelcode()");
1176     }
1177     ch = (int) luaL_checkinteger(L, -2);
1178     check_char_range(ch, "setdelcode", 65536*17);
1179     lua_rawgeti(L, -1, 1);
1180     sfval = (halfword) luaL_checkinteger(L, -1);
1181     lua_rawgeti(L, -2, 2);
1182     scval = (halfword) luaL_checkinteger(L, -1);
1183     lua_rawgeti(L, -3, 3);
1184     lfval = (halfword) luaL_checkinteger(L, -1);
1185     lua_rawgeti(L, -4, 4);
1186     lcval = (halfword) luaL_checkinteger(L, -1);
1187     lua_pop(L,4);
1188 
1189     check_char_range(sfval, "setdelcode", 256);
1190     check_char_range(scval, "setdelcode", 65536*17);
1191     check_char_range(lfval, "setdelcode", 256);
1192     check_char_range(lcval, "setdelcode", 65536*17);
1193     set_del_code(ch, xetex_mathcode, sfval, scval, lfval, lcval, (quarterword) (level));
1194 
1195     return 0;
1196 }
1197 
getdelcode(lua_State * L)1198 static int getdelcode(lua_State * L)
1199 {
1200     delcodeval mval = { 0, 0, 0, 0, 0, 0 };
1201     int ch = (int) luaL_checkinteger(L, -1);
1202     check_char_range(ch, "getdelcode",  65536*17);
1203     mval = get_del_code(ch);
1204     /* lua_pushnumber(L, mval.class_value); */
1205     /* lua_pushnumber(L, mval.origin_value); */
1206     lua_newtable(L);
1207     lua_pushnumber(L,mval.small_family_value);
1208     lua_rawseti(L, -2, 1);
1209     lua_pushnumber(L,mval.small_character_value);
1210     lua_rawseti(L, -2, 2);
1211     lua_pushnumber(L,mval.large_family_value);
1212     lua_rawseti(L, -2, 3);
1213     lua_pushnumber(L,mval.large_character_value);
1214     lua_rawseti(L, -2, 4);
1215     return 1;
1216 }
1217 
1218 
1219 
settex(lua_State * L)1220 static int settex(lua_State * L)
1221 {
1222     const char *st;
1223     int i, j, texstr;
1224     size_t k;
1225     int cur_cs1, cur_cmd1;
1226     int isglobal = 0;
1227     j = 0;
1228     i = lua_gettop(L);
1229     if (lua_isstring(L, (i - 1))) {
1230         st = lua_tolstring(L, (i - 1), &k);
1231         texstr = maketexlstring(st, k);
1232         if (is_primitive(texstr)) {
1233             if (i == 3 && lua_isstring(L, 1)) {
1234                 const char *s = lua_tostring(L, 1);
1235                 if (lua_key_eq(s,global))
1236                     isglobal = 1;
1237             }
1238             cur_cs1 = string_lookup(st, k);
1239             flush_str(texstr);
1240             cur_cmd1 = eq_type(cur_cs1);
1241             if (is_int_assign(cur_cmd1)) {
1242                 if (lua_isnumber(L, i)) {
1243                     int luai;
1244                     luai=(int)lua_tonumber(L, i);
1245                     assign_internal_value((isglobal ? 4 : 0),
1246                                           equiv(cur_cs1), luai);
1247                 } else {
1248                     luaL_error(L, "unsupported value type");
1249                 }
1250             } else if (is_dim_assign(cur_cmd1)) {
1251                 if (!lua_isnumber(L, i)) {
1252                     if (lua_isstring(L, i)) {
1253                         j = dimen_to_number(L, lua_tostring(L, i));
1254                     } else {
1255                         luaL_error(L, "unsupported value type");
1256                     }
1257                 } else {
1258                     j=(int)lua_tonumber(L, i);
1259                 }
1260                 assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), j);
1261             } else if (is_glue_assign(cur_cmd1)) {
1262                 halfword *j1 = check_isnode(L, i);     /* the value */
1263                     { int a = isglobal;
1264    		      define(equiv(cur_cs1), assign_glue_cmd, *j1);
1265                     }
1266             } else if (is_toks_assign(cur_cmd1)) {
1267                 if (lua_isstring(L, i)) {
1268                     j = tokenlist_from_lua(L);  /* uses stack -1 */
1269                     assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), j);
1270 
1271                 } else {
1272                     luaL_error(L, "unsupported value type");
1273                 }
1274 
1275             } else {
1276 		/* people may want to add keys that are also primitives
1277 		   (|tex.wd| for example) so creating an error is not
1278 		   right here */
1279 		if (lua_istable(L, (i - 2)))
1280 		    lua_rawset(L, (i - 2));
1281                 /* luaL_error(L, "unsupported tex internal assignment"); */
1282             }
1283         } else {
1284             if (lua_istable(L, (i - 2)))
1285                 lua_rawset(L, (i - 2));
1286         }
1287     } else {
1288         if (lua_istable(L, (i - 2)))
1289             lua_rawset(L, (i - 2));
1290     }
1291     return 0;
1292 }
1293 
do_convert(lua_State * L,int cur_code)1294 static int do_convert(lua_State * L, int cur_code)
1295 {
1296     int texstr;
1297     int i = -1;
1298     char *str = NULL;
1299     switch (cur_code) {
1300     case pdf_creation_date_code:       /* ? */
1301     case pdf_insert_ht_code:   /* arg <register int> */
1302     case pdf_ximage_bbox_code: /* arg 2 ints */
1303     case lua_code:             /* arg complex */
1304     case lua_escape_string_code:       /* arg token list */
1305     case pdf_colorstack_init_code:     /* arg complex */
1306     case left_margin_kern_code:        /* arg box */
1307     case right_margin_kern_code:       /* arg box */
1308         break;
1309     case string_code:          /* arg token */
1310     case meaning_code:         /* arg token */
1311         break;
1312 
1313         /* the next fall through, and come from 'official' indices! */
1314     case font_name_code:       /* arg fontid */
1315     case font_identifier_code: /* arg fontid */
1316     case pdf_font_name_code:   /* arg fontid */
1317     case pdf_font_objnum_code: /* arg fontid */
1318     case pdf_font_size_code:   /* arg fontid */
1319     case uniform_deviate_code: /* arg int */
1320     case number_code:          /* arg int */
1321     case roman_numeral_code:   /* arg int */
1322     case pdf_page_ref_code:    /* arg int */
1323     case pdf_xform_name_code:  /* arg int */
1324         if (lua_gettop(L) < 1) {
1325             /* error */
1326         }
1327         i=(int)lua_tonumber(L, 1);  /* these fall through! */
1328     default:
1329         texstr = the_convert_string(cur_code, i);
1330         if (texstr) {
1331             str = makecstring(texstr);
1332             flush_str(texstr);
1333         }
1334     }
1335     if (str) {
1336         lua_pushstring(L, str);
1337         free(str);
1338     } else {
1339         lua_pushnil(L);
1340     }
1341     return 1;
1342 }
1343 
1344 
do_scan_internal(lua_State * L,int cur_cmd1,int cur_code)1345 static int do_scan_internal(lua_State * L, int cur_cmd1, int cur_code)
1346 {
1347     int texstr;
1348     char *str = NULL;
1349     int save_cur_val, save_cur_val_level;
1350     save_cur_val = cur_val;
1351     save_cur_val_level = cur_val_level;
1352     scan_something_simple(cur_cmd1, cur_code);
1353 
1354     if (cur_val_level == int_val_level ||
1355         cur_val_level == dimen_val_level || cur_val_level == attr_val_level) {
1356         lua_pushnumber(L, cur_val);
1357     } else if (cur_val_level == glue_val_level) {
1358         lua_nodelib_push_fast(L, cur_val);
1359     } else {                    /* dir_val_level, mu_val_level, tok_val_level */
1360         texstr = the_scanned_result();
1361         str = makecstring(texstr);
1362         if (str) {
1363             lua_pushstring(L, str);
1364             free(str);
1365         } else {
1366             lua_pushnil(L);
1367         }
1368         flush_str(texstr);
1369     }
1370     cur_val = save_cur_val;
1371     cur_val_level = save_cur_val_level;
1372     return 1;
1373 }
1374 
do_lastitem(lua_State * L,int cur_code)1375 static int do_lastitem(lua_State * L, int cur_code)
1376 {
1377     int retval = 1;
1378     switch (cur_code) {
1379         /* the next two do not actually exist */
1380     case lastattr_code:
1381     case attrexpr_code:
1382         lua_pushnil(L);
1383         break;
1384         /* the expressions do something complicated with arguments, yuck */
1385     case numexpr_code:
1386     case dimexpr_code:
1387     case glueexpr_code:
1388     case muexpr_code:
1389         lua_pushnil(L);
1390         break;
1391         /* these read a glue or muglue, todo */
1392     case mu_to_glue_code:
1393     case glue_to_mu_code:
1394     case glue_stretch_order_code:
1395     case glue_shrink_order_code:
1396     case glue_stretch_code:
1397     case glue_shrink_code:
1398         lua_pushnil(L);
1399         break;
1400         /* these read a fontid and a char, todo */
1401     case font_char_wd_code:
1402     case font_char_ht_code:
1403     case font_char_dp_code:
1404     case font_char_ic_code:
1405         lua_pushnil(L);
1406         break;
1407         /* these read an integer, todo */
1408     case par_shape_length_code:
1409     case par_shape_indent_code:
1410     case par_shape_dimen_code:
1411         lua_pushnil(L);
1412         break;
1413     case lastpenalty_code:
1414     case lastkern_code:
1415     case lastskip_code:
1416     case last_node_type_code:
1417     case input_line_no_code:
1418     case badness_code:
1419     case pdftex_version_code:
1420     case pdf_last_obj_code:
1421     case pdf_last_xform_code:
1422     case pdf_last_ximage_code:
1423     case pdf_last_ximage_pages_code:
1424     case pdf_last_annot_code:
1425     case pdf_last_x_pos_code:
1426     case pdf_last_y_pos_code:
1427     case pdf_retval_code:
1428     case pdf_last_ximage_colordepth_code:
1429     case random_seed_code:
1430     case pdf_last_link_code:
1431     case luatex_version_code:
1432     case eTeX_minor_version_code:
1433     case eTeX_version_code:
1434     case current_group_level_code:
1435     case current_group_type_code:
1436     case current_if_level_code:
1437     case current_if_type_code:
1438     case current_if_branch_code:
1439         retval = do_scan_internal(L, last_item_cmd, cur_code);
1440         break;
1441     default:
1442         lua_pushnil(L);
1443         break;
1444     }
1445     return retval;
1446 }
1447 
tex_setmathparm(lua_State * L)1448 static int tex_setmathparm(lua_State * L)
1449 {
1450     int i, j;
1451     int k;
1452     int n;
1453     int l = cur_level;
1454     n = lua_gettop(L);
1455 
1456     if ((n == 3) || (n == 4)) {
1457         if (n == 4 && lua_isstring(L, 1)) {
1458             const char *s = lua_tostring(L, 1);
1459             if (lua_key_eq(s,global))
1460                 l = 1;
1461         }
1462         i = luaL_checkoption(L, (n - 2), NULL, math_param_names);
1463         j = luaL_checkoption(L, (n - 1), NULL, math_style_names);
1464         if (!lua_isnumber(L, n))
1465             luaL_error(L, "argument must be a number");
1466         k=(int)lua_tonumber(L, n);
1467         def_math_param(i, j, (scaled) k, l);
1468     }
1469     return 0;
1470 }
1471 
tex_getmathparm(lua_State * L)1472 static int tex_getmathparm(lua_State * L)
1473 {
1474     int i, j;
1475     scaled k;
1476     if ((lua_gettop(L) == 2)) {
1477         i = luaL_checkoption(L, 1, NULL, math_param_names);
1478         j = luaL_checkoption(L, 2, NULL, math_style_names);
1479         k = get_math_param(i, j);
1480         lua_pushnumber(L, k);
1481     }
1482     return 1;
1483 }
1484 
getfontname(lua_State * L)1485 static int getfontname(lua_State * L)
1486 {
1487     return do_convert(L, font_name_code);
1488 }
1489 
getfontidentifier(lua_State * L)1490 static int getfontidentifier(lua_State * L)
1491 {
1492     return do_convert(L, font_identifier_code);
1493 }
1494 
getpdffontname(lua_State * L)1495 static int getpdffontname(lua_State * L)
1496 {
1497     return do_convert(L, pdf_font_name_code);
1498 }
1499 
getpdffontobjnum(lua_State * L)1500 static int getpdffontobjnum(lua_State * L)
1501 {
1502     return do_convert(L, pdf_font_objnum_code);
1503 }
1504 
getpdffontsize(lua_State * L)1505 static int getpdffontsize(lua_State * L)
1506 {
1507     return do_convert(L, pdf_font_size_code);
1508 }
1509 
getuniformdeviate(lua_State * L)1510 static int getuniformdeviate(lua_State * L)
1511 {
1512     return do_convert(L, uniform_deviate_code);
1513 }
1514 
getnumber(lua_State * L)1515 static int getnumber(lua_State * L)
1516 {
1517     return do_convert(L, number_code);
1518 }
1519 
getromannumeral(lua_State * L)1520 static int getromannumeral(lua_State * L)
1521 {
1522     return do_convert(L, roman_numeral_code);
1523 }
1524 
getpdfpageref(lua_State * L)1525 static int getpdfpageref(lua_State * L)
1526 {
1527     return do_convert(L, pdf_page_ref_code);
1528 }
1529 
getpdfxformname(lua_State * L)1530 static int getpdfxformname(lua_State * L)
1531 {
1532     return do_convert(L, pdf_xform_name_code);
1533 }
1534 
1535 
get_parshape(lua_State * L)1536 static int get_parshape(lua_State * L)
1537 {
1538     int n;
1539     halfword par_shape_ptr = equiv(par_shape_loc);
1540     if (par_shape_ptr != 0) {
1541         int m = 1;
1542         n = vinfo(par_shape_ptr + 1);
1543         lua_createtable(L, n, 0);
1544         while (m <= n) {
1545             lua_createtable(L, 2, 0);
1546             lua_pushnumber(L, vlink((par_shape_ptr) + (2 * (m - 1)) + 2));
1547             lua_rawseti(L, -2, 1);
1548             lua_pushnumber(L, vlink((par_shape_ptr) + (2 * (m - 1)) + 3));
1549             lua_rawseti(L, -2, 2);
1550             lua_rawseti(L, -2, m);
1551             m++;
1552         }
1553     } else {
1554         lua_pushnil(L);
1555     }
1556     return 1;
1557 }
1558 
1559 
gettex(lua_State * L)1560 static int gettex(lua_State * L)
1561 {
1562     int cur_cs1 = -1;
1563     int retval = 1;             /* default is to return nil  */
1564     int t = lua_gettop(L);
1565     if (lua_isstring(L, t)) {   /* 1 == 'tex', 2 == 'boxmaxdepth', or 1 == 'boxmaxdepth' */
1566         int texstr;
1567         size_t k;
1568         const char *st = lua_tolstring(L, t, &k);
1569         texstr = maketexlstring(st, k);
1570         cur_cs1 = prim_lookup(texstr);   /* not found == relax == 0 */
1571         flush_str(texstr);
1572     }
1573     if (cur_cs1 > 0) {
1574         int cur_cmd1, cur_code;
1575         cur_cmd1 = get_prim_eq_type(cur_cs1);
1576         cur_code = get_prim_equiv(cur_cs1);
1577         switch (cur_cmd1) {
1578         case last_item_cmd:
1579             retval = do_lastitem(L, cur_code);
1580             break;
1581         case convert_cmd:
1582             retval = do_convert(L, cur_code);
1583             break;
1584         case assign_toks_cmd:
1585         case assign_int_cmd:
1586         case assign_attr_cmd:
1587         case assign_dir_cmd:
1588         case assign_dimen_cmd:
1589         case assign_glue_cmd:
1590         case assign_mu_glue_cmd:
1591         case set_aux_cmd:
1592         case set_prev_graf_cmd:
1593         case set_page_int_cmd:
1594         case set_page_dimen_cmd:
1595         case char_given_cmd:
1596         case math_given_cmd:
1597             retval = do_scan_internal(L, cur_cmd1, cur_code);
1598             break;
1599         case set_tex_shape_cmd:
1600             retval = get_parshape(L);
1601             break;
1602         default:
1603             lua_pushnil(L);
1604             break;
1605         }
1606     } else {
1607 	if (t == 2) {
1608 	    lua_rawget(L, 1);
1609 	}
1610     }
1611     return retval;
1612 }
1613 
1614 
getlist(lua_State * L)1615 static int getlist(lua_State * L)
1616 {
1617     const char *str;
1618     if (lua_isstring(L, 2)) {
1619         str = lua_tostring(L, 2);
1620         if (lua_key_eq(str,page_ins_head)) {
1621             if (vlink(page_ins_head) == page_ins_head)
1622                 lua_pushnumber(L, null);
1623             else
1624                 lua_pushnumber(L, vlink(page_ins_head));
1625             lua_nodelib_push(L);
1626         } else if (lua_key_eq(str,contrib_head)) {
1627 	    alink(vlink(contrib_head)) = null ;
1628             lua_pushnumber(L, vlink(contrib_head));
1629             lua_nodelib_push(L);
1630         } else if (lua_key_eq(str,page_head)) {
1631 	    alink(vlink(page_head)) = null ;/*hh-ls */
1632             lua_pushnumber(L, vlink(page_head));
1633             lua_nodelib_push(L);
1634         } else if (lua_key_eq(str,temp_head)) {
1635 	    alink(vlink(temp_head)) = null ;/*hh-ls */
1636             lua_pushnumber(L, vlink(temp_head));
1637             lua_nodelib_push(L);
1638         } else if (lua_key_eq(str,hold_head)) {
1639             alink(vlink(hold_head)) = null ;/*hh-ls */
1640             lua_pushnumber(L, vlink(hold_head));
1641             lua_nodelib_push(L);
1642         } else if (lua_key_eq(str,adjust_head)) {
1643             alink(vlink(adjust_head)) = null ;/*hh-ls */
1644             lua_pushnumber(L, vlink(adjust_head));
1645             lua_nodelib_push(L);
1646         } else if (lua_key_eq(str,best_page_break)) {
1647             lua_pushnumber(L, best_page_break);
1648             lua_nodelib_push(L);
1649         } else if (lua_key_eq(str,least_page_cost)) {
1650             lua_pushnumber(L, least_page_cost);
1651         } else if (lua_key_eq(str,best_size)) {
1652             lua_pushnumber(L, best_size);
1653         } else if (lua_key_eq(str,pre_adjust_head)) {
1654             alink(vlink(pre_adjust_head)) = null ;/*hh-ls */
1655             lua_pushnumber(L, vlink(pre_adjust_head));
1656             lua_nodelib_push(L);
1657         } else if (lua_key_eq(str,align_head)) {
1658             alink(vlink(align_head)) = null ;/*hh-ls */
1659             lua_pushnumber(L, vlink(align_head));
1660             lua_nodelib_push(L);
1661         } else {
1662             lua_pushnil(L);
1663         }
1664     } else {
1665         lua_pushnil(L);
1666     }
1667     return 1;
1668 }
1669 
setlist(lua_State * L)1670 static int setlist(lua_State * L)
1671 {
1672     halfword *n_ptr;
1673     const char *str;
1674     halfword n = 0;
1675     if (lua_isstring(L, 2)) {
1676         str = lua_tostring(L, 2);
1677         if (lua_key_eq(str,best_size)) {
1678             best_size = (int) lua_tointeger(L, 3);
1679         } else if (lua_key_eq(str,least_page_cost)) {
1680             least_page_cost = (int) lua_tointeger(L, 3);
1681         } else {
1682             if (!lua_isnil(L, 3)) {
1683                 n_ptr = check_isnode(L, 3);
1684                 n = *n_ptr;
1685             }
1686             if (lua_key_eq(str,page_ins_head)) {
1687                 if (n == 0) {
1688                     vlink(page_ins_head) = page_ins_head;
1689                 } else {
1690                     halfword m;
1691                     vlink(page_ins_head) = n;
1692                     m = tail_of_list(n);
1693                     vlink(m) = page_ins_head;
1694                 }
1695             } else if (lua_key_eq(str,contrib_head)) {
1696                 vlink(contrib_head) = n;
1697                 if (n == 0) {
1698                     contrib_tail = contrib_head;
1699                 }
1700             } else if (lua_key_eq(str,best_page_break)) {
1701                 best_page_break = n;
1702             } else if (lua_key_eq(str,page_head)) {
1703                 vlink(page_head) = n;
1704                 page_tail = (n == 0 ? page_head : tail_of_list(n));
1705             } else if (lua_key_eq(str,temp_head)) {
1706                 vlink(temp_head) = n;
1707             } else if (lua_key_eq(str,hold_head)) {
1708                 vlink(hold_head) = n;
1709             } else if (lua_key_eq(str,adjust_head)) {
1710                 vlink(adjust_head) = n;
1711                 adjust_tail = (n == 0 ? adjust_head : tail_of_list(n));
1712             } else if (lua_key_eq(str,pre_adjust_head)) {
1713                 vlink(pre_adjust_head) = n;
1714                 pre_adjust_tail = (n == 0 ? pre_adjust_head : tail_of_list(n));
1715             } else if (lua_key_eq(str,align_head)) {
1716                 vlink(align_head) = n;
1717             }
1718         }
1719     }
1720     return 0;
1721 }
1722 
1723 #define NEST_METATABLE "luatex.nest"
1724 
lua_nest_getfield(lua_State * L)1725 static int lua_nest_getfield(lua_State * L)
1726 {
1727     list_state_record *r, **rv = lua_touserdata(L, -2);
1728     const char *field = lua_tostring(L, -1);
1729     r = *rv;
1730     if (lua_key_eq(field,mode)) {
1731         lua_pushnumber(L, r->mode_field);
1732     } else if (lua_key_eq(field,head)) {
1733         lua_nodelib_push_fast(L, r->head_field);
1734     } else if (lua_key_eq(field,tail)) {
1735         lua_nodelib_push_fast(L, r->tail_field);
1736     } else if (lua_key_eq(field,delimptr)) {
1737         lua_pushnumber(L, r->eTeX_aux_field);
1738         lua_nodelib_push(L);
1739     } else if (lua_key_eq(field,prevgraf)) {
1740         lua_pushnumber(L, r->pg_field);
1741     } else if (lua_key_eq(field,modeline)) {
1742         lua_pushnumber(L, r->ml_field);
1743     } else if (lua_key_eq(field,prevdepth)) {
1744         lua_pushnumber(L, r->prev_depth_field);
1745     } else if (lua_key_eq(field,spacefactor)) {
1746         lua_pushnumber(L, r->space_factor_field);
1747     } else if (lua_key_eq(field,noad)) {
1748         lua_pushnumber(L, r->incompleat_noad_field);
1749         lua_nodelib_push(L);
1750     } else if (lua_key_eq(field,dirs)) {
1751         lua_pushnumber(L, r->dirs_field);
1752         lua_nodelib_push(L);
1753     } else if (lua_key_eq(field,mathdir)) {
1754         lua_pushboolean(L, r->math_field);
1755     } else if (lua_key_eq(field,mathstyle)) {
1756         lua_pushnumber(L, r->math_style_field);
1757     } else {
1758         lua_pushnil(L);
1759     }
1760     return 1;
1761 }
1762 
lua_nest_setfield(lua_State * L)1763 static int lua_nest_setfield(lua_State * L)
1764 {
1765     halfword *n;
1766     int i;
1767     list_state_record *r, **rv = lua_touserdata(L, -3);
1768     const char *field = lua_tostring(L, -2);
1769     r = *rv;
1770     if (lua_key_eq(field,mode)) {
1771         i=(int)lua_tonumber(L, -1);
1772         r->mode_field = i;
1773     } else if (lua_key_eq(field,head)) {
1774         n = check_isnode(L, -1);
1775         r->head_field = *n;
1776     } else if (lua_key_eq(field,tail)) {
1777         n = check_isnode(L, -1);
1778         r->tail_field = *n;
1779     } else if (lua_key_eq(field,delimptr)) {
1780         n = check_isnode(L, -1);
1781         r->eTeX_aux_field = *n;
1782     } else if (lua_key_eq(field,prevgraf)) {
1783         i=(int)lua_tonumber(L, -1);
1784         r->pg_field = i;
1785     } else if (lua_key_eq(field,modeline)) {
1786         i=(int)lua_tonumber(L, -1);
1787         r->ml_field = i;
1788     } else if (lua_key_eq(field,prevdepth)) {
1789         i=(int)lua_tonumber(L, -1);
1790         r->prev_depth_field = i;
1791     } else if (lua_key_eq(field,spacefactor)) {
1792         i=(int)lua_tonumber(L, -1);
1793         r->space_factor_field = i;
1794     } else if (lua_key_eq(field,noad)) {
1795         n = check_isnode(L, -1);
1796         r->incompleat_noad_field = *n;
1797     } else if (lua_key_eq(field,dirs)) {
1798         n = check_isnode(L, -1);
1799         r->dirs_field = *n;
1800     } else if (lua_key_eq(field,mathdir)) {
1801         r->math_field = lua_toboolean(L, -1);
1802     } else if (lua_key_eq(field,mathstyle)) {
1803         i=(int)lua_tonumber(L, -1);
1804         r->math_style_field = i;
1805     }
1806     return 0;
1807 }
1808 
1809 static const struct luaL_Reg nest_m[] = {
1810     {"__index", lua_nest_getfield},
1811     {"__newindex", lua_nest_setfield},
1812     {NULL, NULL}                /* sentinel */
1813 };
1814 
init_nest_lib(lua_State * L)1815 static void init_nest_lib(lua_State * L)
1816 {
1817     luaL_newmetatable(L, NEST_METATABLE);
1818     luaL_register(L, NULL, nest_m);
1819     lua_pop(L, 1);
1820 }
1821 
getnest(lua_State * L)1822 static int getnest(lua_State * L)
1823 {
1824     int ptr;
1825     list_state_record **nestitem;
1826     if (lua_isnumber(L, 2)) {
1827         ptr=(int)lua_tonumber(L, 2);
1828         if (ptr >= 0 && ptr <= nest_ptr) {
1829             nestitem = lua_newuserdata(L, sizeof(list_state_record *));
1830             *nestitem = &nest[ptr];
1831             luaL_getmetatable(L, NEST_METATABLE);
1832             lua_setmetatable(L, -2);
1833         } else {
1834             lua_pushnil(L);
1835         }
1836     } else if (lua_isstring(L, 2)) {
1837         const char *s = lua_tostring(L, 2);
1838         if (lua_key_eq(s,ptr)) {
1839             lua_pushnumber(L, nest_ptr);
1840         } else {
1841             lua_pushnil(L);
1842         }
1843     } else {
1844         lua_pushnil(L);
1845     }
1846     return 1;
1847 }
1848 
setnest(lua_State * L)1849 static int setnest(lua_State * L)
1850 {
1851     luaL_error(L, "You can't modify the semantic nest array directly");
1852     return 2;
1853 }
1854 
do_integer_error(double m)1855 static int do_integer_error(double m)
1856 {
1857     const char *help[] =
1858         { "I can only go up to 2147483647='17777777777=" "7FFFFFFF,",
1859         "so I'm using that number instead of yours.",
1860         NULL
1861     };
1862     tex_error("Number too big", help);
1863     return (m > 0.0 ? infinity : -infinity);
1864 }
1865 
1866 
tex_roundnumber(lua_State * L)1867 static int tex_roundnumber(lua_State * L)
1868 {
1869     double m = (double) lua_tonumber(L, 1) + 0.5;
1870     if (abs(m) > (double) infinity)
1871         lua_pushnumber(L, do_integer_error(m));
1872     else
1873         lua_pushnumber(L, floor(m));
1874     return 1;
1875 }
1876 
tex_scaletable(lua_State * L)1877 static int tex_scaletable(lua_State * L)
1878 {
1879     double delta = luaL_checknumber(L, 2);
1880     if (lua_istable(L, 1)) {
1881         lua_newtable(L);        /* the new table is at index 3 */
1882         lua_pushnil(L);
1883         while (lua_next(L, 1) != 0) {   /* numeric value */
1884             lua_pushvalue(L, -2);
1885             lua_insert(L, -2);
1886             if (lua_isnumber(L, -1)) {
1887                 double m = (double) lua_tonumber(L, -1) * delta + 0.5;
1888                 lua_pop(L, 1);
1889                 if (abs(m) > (double) infinity)
1890                     lua_pushnumber(L, do_integer_error(m));
1891                 else
1892                     lua_pushnumber(L, floor(m));
1893             }
1894             lua_rawset(L, 3);
1895         }
1896     } else if (lua_isnumber(L, 1)) {
1897         double m = (double) lua_tonumber(L, 1) * delta + 0.5;
1898         if (abs(m) > (double) infinity)
1899             lua_pushnumber(L, do_integer_error(m));
1900         else
1901             lua_pushnumber(L, floor(m));
1902     } else {
1903         lua_pushnil(L);
1904     }
1905     return 1;
1906 }
1907 
1908 #define hash_text(A) hash[(A)].rh
1909 
tex_definefont(lua_State * L)1910 static int tex_definefont(lua_State * L)
1911 {
1912     const char *csname;
1913     int f, u;
1914     str_number t;
1915     size_t l;
1916     int i = 1;
1917     int a = 0;
1918     if (!no_new_control_sequence) {
1919         const char *help[] =
1920             { "You can't create a new font inside a \\csname\\endcsname pair",
1921             NULL
1922         };
1923         tex_error("Definition active", help);
1924     }
1925     if ((lua_gettop(L) == 3) && lua_isboolean(L, 1)) {
1926         a = lua_toboolean(L, 1);
1927         i = 2;
1928     }
1929     csname = luaL_checklstring(L, i, &l);
1930     f = (int) luaL_checkinteger(L, (i + 1));
1931     t = maketexlstring(csname, l);
1932     no_new_control_sequence = 0;
1933     u = string_lookup(csname, l);
1934     no_new_control_sequence = 1;
1935     if (a)
1936         geq_define(u, set_font_cmd, f);
1937     else
1938         eq_define(u, set_font_cmd, f);
1939     eqtb[font_id_base + f] = eqtb[u];
1940     hash_text(font_id_base + f) = t;
1941     return 0;
1942 }
1943 
tex_hashpairs(lua_State * L)1944 static int tex_hashpairs(lua_State * L)
1945 {
1946     int cmd, chr;
1947     str_number s = 0;
1948     int cs = 1;
1949     lua_newtable(L);
1950     while (cs < hash_size) {
1951         s = hash_text(cs);
1952         if (s > 0) {
1953             char *ss = makecstring(s);
1954             lua_pushstring(L, ss);
1955             free(ss);
1956             cmd = eq_type(cs);
1957             chr = equiv(cs);
1958             make_token_table(L, cmd, chr, cs);
1959             lua_rawset(L, -3);
1960         }
1961         cs++;
1962     }
1963     return 1;
1964 }
1965 
tex_primitives(lua_State * L)1966 static int tex_primitives(lua_State * L)
1967 {
1968     int cmd, chr;
1969     str_number s = 0;
1970     int cs = 0;
1971     lua_newtable(L);
1972     while (cs < prim_size) {
1973         s = get_prim_text(cs);
1974         if (s > 0) {
1975             char *ss = makecstring(s);
1976             lua_pushstring(L, ss);
1977             free(ss);
1978             cmd = get_prim_eq_type(cs);
1979             chr = get_prim_equiv(cs);
1980             make_token_table(L, cmd, chr, 0);
1981             lua_rawset(L, -3);
1982         }
1983         cs++;
1984     }
1985     return 1;
1986 }
1987 
tex_extraprimitives(lua_State * L)1988 static int tex_extraprimitives(lua_State * L)
1989 {
1990     int n, i;
1991     int mask = 0;
1992     int cs = 0;
1993     n = lua_gettop(L);
1994     if (n == 0) {
1995         mask = etex_command + aleph_command + omega_command +
1996             pdftex_command + luatex_command + umath_command;
1997     } else {
1998         for (i = 1; i <= n; i++) {
1999             if (lua_isstring(L, i)) {
2000                 const char *s = lua_tostring(L, i);
2001                 if (lua_key_eq(s,etex)) {
2002                     mask |= etex_command;
2003                 } else if (lua_key_eq(s,tex)) {
2004                     mask |= tex_command;
2005                 } else if (lua_key_eq(s,core)) {
2006                     mask |= core_command;
2007                 } else if (lua_key_eq(s,pdftex)) {
2008                     mask |= pdftex_command;
2009                 } else if (lua_key_eq(s,aleph)) {
2010                     mask |= aleph_command;
2011                 } else if (lua_key_eq(s,omega)) {
2012                     mask |= omega_command;
2013                 } else if (lua_key_eq(s,luatex)) {
2014                     mask |= luatex_command | umath_command;
2015                 } else if (lua_key_eq(s,umath)) {
2016                     mask |= umath_command;
2017                 }
2018             }
2019         }
2020     }
2021     lua_newtable(L);
2022     i = 1;
2023     while (cs < prim_size) {
2024 	str_number s = 0;
2025         s = get_prim_text(cs);
2026         if (s > 0) {
2027             if (get_prim_origin(cs) & mask) {
2028                 char *ss = makecstring(s);
2029                 lua_pushstring(L, ss);
2030                 free(ss);
2031                 lua_rawseti(L, -2, i++);
2032             }
2033         }
2034         cs++;
2035     }
2036     return 1;
2037 }
2038 
tex_enableprimitives(lua_State * L)2039 static int tex_enableprimitives(lua_State * L)
2040 {
2041     int n = lua_gettop(L);
2042     if (n != 2) {
2043         luaL_error(L, "wrong number of arguments");
2044     } else {
2045         size_t l;
2046         int i;
2047         const char *pre = luaL_checklstring(L, 1, &l);
2048         if (lua_istable(L, 2)) {
2049             int nncs = no_new_control_sequence;
2050             no_new_control_sequence = true;
2051             i = 1;
2052             while (1) {
2053                 lua_rawgeti(L, 2, i);
2054                 if (lua_isstring(L, 3)) {
2055                     const char *prim = lua_tostring(L, 3);
2056                     str_number s = maketexstring(prim);
2057                     halfword prim_val = prim_lookup(s);
2058                     if (prim_val != undefined_primitive) {
2059                         char *newprim;
2060                         int val;
2061                         size_t newl;
2062                         halfword cur_cmd1 = get_prim_eq_type(prim_val);
2063                         halfword cur_chr1 = get_prim_equiv(prim_val);
2064                         if (strncmp(pre, prim, l) != 0) {       /* not a prefix */
2065                             newl = strlen(prim) + l;
2066                             newprim = (char *) xmalloc((unsigned) (newl + 1));
2067                             strcpy(newprim, pre);
2068                             strcat(newprim + l, prim);
2069                         } else {
2070                             newl = strlen(prim);
2071                             newprim = (char *) xmalloc((unsigned) (newl + 1));
2072                             strcpy(newprim, prim);
2073                         }
2074                         val = string_lookup(newprim, newl);
2075                         if (val == undefined_control_sequence ||
2076                             eq_type(val) == undefined_cs_cmd) {
2077                             primitive_def(newprim, newl, (quarterword) cur_cmd1,
2078                                           cur_chr1);
2079                         }
2080                         free(newprim);
2081                     }
2082                     flush_str(s);
2083                 } else {
2084                     lua_pop(L, 1);
2085                     break;
2086                 }
2087                 lua_pop(L, 1);
2088                 i++;
2089             }
2090             lua_pop(L, 1);      /* the table */
2091             no_new_control_sequence = nncs;
2092         } else {
2093             luaL_error(L, "Expected an array of names as second argument");
2094         }
2095     }
2096     return 0;
2097 }
2098 
2099 #define get_int_par(A,B,C)  do {			\
2100     	lua_pushstring(L,(A));				\
2101 	lua_gettable(L,-2);				\
2102 	if (lua_type(L, -1) == LUA_TNUMBER) {		\
2103 	    B=(int)lua_tonumber(L, -1);			\
2104 	} else {					\
2105 	    B = (C);					\
2106 	}						\
2107 	lua_pop(L,1);					\
2108     } while (0)
2109 
2110 
2111 #define get_intx_par(A,B,C,D,E)  do {			\
2112     	lua_pushstring(L,(A));				\
2113 	lua_gettable(L,-2);				\
2114 	if (lua_type(L, -1) == LUA_TNUMBER) {		\
2115 	    B=(int)lua_tonumber(L, -1);			\
2116 	    D = null;					\
2117 	} else if (lua_type(L, -1) == LUA_TTABLE){	\
2118 	    B = 0;					\
2119 	    D = nodelib_topenalties(L, lua_gettop(L));	\
2120 	} else {					\
2121 	    B = (C);					\
2122 	    D = (E);					\
2123 	}						\
2124 	lua_pop(L,1);					\
2125     } while (0)
2126 
2127 #define get_dimen_par(A,B,C)  do {			\
2128     	lua_pushstring(L,(A));				\
2129 	lua_gettable(L,-2);				\
2130 	if (lua_type(L, -1) == LUA_TNUMBER) {		\
2131 	    B=(int)lua_tonumber(L, -1);			\
2132 	} else {					\
2133 	    B = (C);					\
2134 	}						\
2135 	lua_pop(L,1);					\
2136     } while (0)
2137 
2138 
2139 #define get_glue_par(A,B,C)  do {			\
2140     	lua_pushstring(L,(A));				\
2141 	lua_gettable(L,-2);				\
2142 	if (lua_type(L, -1) != LUA_TNIL) {		\
2143 	    B = *check_isnode(L, -1);			\
2144 	} else {					\
2145 	    B = (C);					\
2146 	}						\
2147 	lua_pop(L,1);					\
2148     } while (0)
2149 
2150 
nodelib_toparshape(lua_State * L,int i)2151 static halfword nodelib_toparshape(lua_State * L, int i)
2152 {
2153     halfword p;
2154     int n = 0;
2155     int width, indent, j;
2156     /* find |n| */
2157     lua_pushnil(L);
2158     while (lua_next(L, i) != 0) {
2159         n++;
2160         lua_pop(L, 1);
2161     }
2162     if (n == 0)
2163         return null;
2164     p = new_node(shape_node, 2 * (n + 1) + 1);
2165     vinfo(p + 1) = n;
2166     /* fill |p| */
2167     lua_pushnil(L);
2168     j = 0;
2169     while (lua_next(L, i) != 0) {
2170         /* don't give an error for non-tables, we may add special syntaxes at some point */
2171         j++;
2172         if (lua_type(L, i) == LUA_TTABLE) {
2173             lua_rawgeti(L, -1, 1);      /* indent */
2174             if (lua_type(L, -1) == LUA_TNUMBER) {
2175                 indent=(int)lua_tonumber(L, -1);
2176                 lua_pop(L, 1);
2177                 lua_rawgeti(L, -1, 2);  /* width */
2178                 if (lua_type(L, -1) == LUA_TNUMBER) {
2179                     width=(int)lua_tonumber(L, -1);
2180                     lua_pop(L, 1);
2181                     varmem[p + 2 * j].cint = indent;
2182                     varmem[p + 2 * j + 1].cint = width;
2183                 }
2184             }
2185         }
2186         lua_pop(L, 1);
2187     }
2188     return p;
2189 }
2190 
2191 /* penalties */
2192 
nodelib_topenalties(lua_State * L,int i)2193 static halfword nodelib_topenalties(lua_State * L, int i)
2194 {
2195     halfword p;
2196     int n = 0;
2197     int j;
2198     /* find |n| */
2199     lua_pushnil(L);
2200     while (lua_next(L, i) != 0) {
2201         n++;
2202         lua_pop(L, 1);
2203     }
2204     if (n == 0)
2205         return null;
2206     p = new_node(shape_node, 2 * ((n / 2) + 1) + 1 + 1);
2207     vinfo(p + 1) = (n / 2) + 1;
2208     varmem[p + 2].cint = n;
2209     lua_pushnil(L);
2210     j = 2;
2211     while (lua_next(L, i) != 0) {
2212 	j++;
2213 	if (lua_isnumber(L, -1)) {
2214 	    int pen = 0;
2215 	    pen=(int)lua_tonumber(L, -1);
2216 	    varmem[p+j].cint = pen;
2217 	}
2218 	lua_pop(L, 1);
2219     }
2220     if (!odd(n))
2221 	varmem[p+j+1].cint = 0;
2222     return p;
2223 }
2224 
2225 
2226 
2227 
tex_run_linebreak(lua_State * L)2228 static int tex_run_linebreak(lua_State * L)
2229 {
2230 
2231     halfword *j;
2232     halfword p;
2233     halfword final_par_glue;
2234     int paragraph_dir = 0;
2235     /* locally initialized parameters for line breaking */
2236     int pretolerance, tracingparagraphs, tolerance, looseness, hyphenpenalty,
2237         exhyphenpenalty, pdfadjustspacing, adjdemerits, pdfprotrudechars,
2238         linepenalty, lastlinefit, doublehyphendemerits, finalhyphendemerits,
2239         hangafter, interlinepenalty, widowpenalty, clubpenalty, brokenpenalty;
2240     halfword emergencystretch, hangindent, hsize, leftskip, rightskip,
2241         pdfeachlineheight, pdfeachlinedepth, pdffirstlineheight,
2242         pdflastlinedepth, pdfignoreddimen, parshape;
2243     int fewest_demerits = 0, actual_looseness = 0;
2244     halfword clubpenalties, interlinepenalties, widowpenalties;
2245     int save_vlink_tmp_head;
2246     /* push a new nest level */
2247     push_nest();
2248     save_vlink_tmp_head = vlink(temp_head);
2249 
2250     j = check_isnode(L, 1);     /* the value */
2251     vlink(temp_head) = *j;
2252     p = *j;
2253     if ((!is_char_node(vlink(*j)))
2254         && ((type(vlink(*j)) == whatsit_node)
2255             && (subtype(vlink(*j)) == local_par_node))) {
2256         paragraph_dir = local_par_dir(vlink(*j));
2257     }
2258 
2259     while (vlink(p) != null)
2260         p = vlink(p);
2261     final_par_glue = p;
2262 
2263     /* initialize local parameters */
2264 
2265     if (lua_gettop(L) != 2 || lua_type(L, 2) != LUA_TTABLE) {
2266         lua_checkstack(L, 3);
2267         lua_newtable(L);
2268     }
2269     lua_pushstring(L, "pardir");
2270     lua_gettable(L, -2);
2271     if (lua_type(L, -1) == LUA_TSTRING) {
2272         paragraph_dir = nodelib_getdir(L, -1, 1);
2273     }
2274     lua_pop(L, 1);
2275 
2276     lua_pushstring(L, "parshape");
2277     lua_gettable(L, -2);
2278     if (lua_type(L, -1) == LUA_TTABLE) {
2279         parshape = nodelib_toparshape(L, lua_gettop(L));
2280     } else {
2281         parshape = equiv(par_shape_loc);
2282     }
2283     lua_pop(L, 1);
2284 
2285     get_int_par("pretolerance", pretolerance, int_par(pretolerance_code));
2286     get_int_par("tracingparagraphs", tracingparagraphs,
2287                 int_par(tracing_paragraphs_code));
2288     get_int_par("tolerance", tolerance, int_par(tolerance_code));
2289     get_int_par("looseness", looseness, int_par(looseness_code));
2290     get_int_par("hyphenpenalty", hyphenpenalty, int_par(hyphen_penalty_code));
2291     get_int_par("exhyphenpenalty", exhyphenpenalty,
2292                 int_par(ex_hyphen_penalty_code));
2293     get_int_par("pdfadjustspacing", pdfadjustspacing,
2294                 int_par(pdf_adjust_spacing_code));
2295     get_int_par("adjdemerits", adjdemerits, int_par(adj_demerits_code));
2296     get_int_par("pdfprotrudechars", pdfprotrudechars,
2297                 int_par(pdf_protrude_chars_code));
2298     get_int_par("linepenalty", linepenalty, int_par(line_penalty_code));
2299     get_int_par("lastlinefit", lastlinefit, int_par(last_line_fit_code));
2300     get_int_par("doublehyphendemerits", doublehyphendemerits,
2301                 int_par(double_hyphen_demerits_code));
2302     get_int_par("finalhyphendemerits", finalhyphendemerits,
2303                 int_par(final_hyphen_demerits_code));
2304     get_int_par("hangafter", hangafter, int_par(hang_after_code));
2305     get_intx_par("interlinepenalty", interlinepenalty,int_par(inter_line_penalty_code),
2306 		 interlinepenalties, equiv(inter_line_penalties_loc));
2307     get_intx_par("clubpenalty", clubpenalty, int_par(club_penalty_code),
2308 		 clubpenalties, equiv(club_penalties_loc));
2309     get_intx_par("widowpenalty", widowpenalty, int_par(widow_penalty_code),
2310 		 widowpenalties, equiv(widow_penalties_loc));
2311     get_int_par("brokenpenalty", brokenpenalty, int_par(broken_penalty_code));
2312     get_dimen_par("emergencystretch", emergencystretch,
2313                   dimen_par(emergency_stretch_code));
2314     get_dimen_par("hangindent", hangindent, dimen_par(hang_indent_code));
2315     get_dimen_par("hsize", hsize, dimen_par(hsize_code));
2316     get_glue_par("leftskip", leftskip, glue_par(left_skip_code));
2317     get_glue_par("rightskip", rightskip, glue_par(right_skip_code));
2318     get_dimen_par("pdfeachlineheight", pdfeachlineheight,
2319                   dimen_par(pdf_each_line_height_code));
2320     get_dimen_par("pdfeachlinedepth", pdfeachlinedepth,
2321                   dimen_par(pdf_each_line_depth_code));
2322     get_dimen_par("pdffirstlineheight", pdffirstlineheight,
2323                   dimen_par(pdf_first_line_height_code));
2324     get_dimen_par("pdflastlinedepth", pdflastlinedepth,
2325                   dimen_par(pdf_last_line_depth_code));
2326     get_dimen_par("pdfignoreddimen", pdfignoreddimen,
2327                   dimen_par(pdf_ignored_dimen_code));
2328 
2329     ext_do_line_break(paragraph_dir,
2330                       pretolerance, tracingparagraphs, tolerance,
2331                       emergencystretch,
2332                       looseness, hyphenpenalty, exhyphenpenalty,
2333                       pdfadjustspacing,
2334                       parshape,
2335                       adjdemerits, pdfprotrudechars,
2336                       linepenalty, lastlinefit,
2337                       doublehyphendemerits, finalhyphendemerits,
2338                       hangindent, hsize, hangafter, leftskip, rightskip,
2339                       pdfeachlineheight, pdfeachlinedepth,
2340                       pdffirstlineheight, pdflastlinedepth,
2341                       interlinepenalties,
2342                       interlinepenalty, clubpenalty,
2343                       clubpenalties,
2344                       widowpenalties,
2345                       widowpenalty, brokenpenalty,
2346                       final_par_glue, pdfignoreddimen);
2347 
2348     /* return the generated list, and its prevdepth */
2349     get_linebreak_info (&fewest_demerits, &actual_looseness) ;
2350     lua_nodelib_push_fast(L, vlink(cur_list.head_field));
2351     lua_newtable(L);
2352     lua_pushstring(L, "demerits");
2353     lua_pushnumber(L, fewest_demerits);
2354     lua_settable(L, -3);
2355     lua_pushstring(L, "looseness");
2356     lua_pushnumber(L, actual_looseness);
2357     lua_settable(L, -3);
2358     lua_pushstring(L, "prevdepth");
2359     lua_pushnumber(L, cur_list.prev_depth_field);
2360     lua_settable(L, -3);
2361     lua_pushstring(L, "prevgraf");
2362     lua_pushnumber(L, cur_list.pg_field);
2363     lua_settable(L, -3);
2364 
2365     /* restore nest stack */
2366     vlink(temp_head) = save_vlink_tmp_head;
2367     pop_nest();
2368     if (parshape != equiv(par_shape_loc))
2369         flush_node(parshape);
2370     return 2;
2371 }
2372 
tex_shipout(lua_State * L)2373 static int tex_shipout(lua_State * L)
2374 {
2375     int boxnum = get_box_id(L, 1);
2376     ship_out(static_pdf, box(boxnum), SHIPPING_PAGE);
2377     box(boxnum) = null;
2378     return 0;
2379 }
2380 
tex_badness(lua_State * L)2381 static int tex_badness(lua_State * L)
2382 {
2383     scaled t,s;
2384     t=(int)lua_tonumber(L,1);
2385     s=(int)lua_tonumber(L,2);
2386     lua_pushnumber(L, badness(t,s));
2387     return 1;
2388 }
2389 
2390 
tex_run_boot(lua_State * L)2391 static int tex_run_boot(lua_State * L)
2392 {
2393     int n = lua_gettop(L);
2394     const char *format = NULL;
2395     if (n >= 1) {
2396         ini_version = 0;
2397         format = luaL_checkstring(L, 1);
2398     } else {
2399         ini_version = 1;
2400     }
2401     if (main_initialize()) {    /* > 0 = failure */
2402         lua_pushboolean(L, 0);  /* false */
2403         return 1;
2404     }
2405     if (format) {
2406         if (!zopen_w_input(&fmt_file, format, DUMP_FORMAT, FOPEN_RBIN_MODE)) {
2407             lua_pushboolean(L, 0);      /* false */
2408             return 1;
2409         }
2410         if (!load_fmt_file(format)) {
2411             zwclose(fmt_file);
2412             lua_pushboolean(L, 0);      /* false */
2413             return 1;
2414         }
2415         zwclose(fmt_file);
2416     }
2417     fix_date_and_time();
2418     /* if (format == NULL) */
2419     /*     make_pdftex_banner(); */
2420     random_seed = (microseconds * 1000) + (epochseconds % 1000000);
2421     init_randoms(random_seed);
2422     initialize_math();
2423     fixup_selector(log_opened_global);
2424     check_texconfig_init();
2425     text_dir_ptr = new_dir(0);
2426     history = spotless;         /* ready to go! */
2427     /* Initialize synctex primitive */
2428     synctexinitcommand();
2429     /* tex is ready to go, now */
2430     unhide_lua_table(Luas, "tex", tex_table_id);
2431     unhide_lua_table(Luas, "pdf", pdf_table_id);
2432     unhide_lua_table(Luas, "newtoken", newtoken_table_id);
2433     unhide_lua_table(Luas, "token", token_table_id);
2434     unhide_lua_table(Luas, "node", node_table_id);
2435 
2436     lua_pushboolean(L, 1);      /* true */
2437     return 1;
2438 
2439 }
2440 
2441 /* tex random generators */
tex_init_rand(lua_State * L)2442 static int tex_init_rand(lua_State * L)
2443 {
2444   int sp;
2445   if (!lua_isnumber(L, 1)) {
2446       luaL_error(L, "argument must be a number");
2447       return 0;
2448   }
2449   sp=(int)lua_tonumber(L, 1);
2450   init_randoms(sp);
2451   return 0;
2452 }
2453 
tex_unif_rand(lua_State * L)2454 static int tex_unif_rand(lua_State * L)
2455 {
2456   int sp;
2457   if (!lua_isnumber(L, 1)) {
2458       luaL_error(L, "argument must be a number");
2459       return 0;
2460   }
2461   sp=(int)lua_tonumber(L, 1);
2462   lua_pushnumber(L, unif_rand(sp));
2463   return 1;
2464 }
2465 
tex_norm_rand(lua_State * L)2466 static int tex_norm_rand(lua_State * L)
2467 {
2468     lua_pushnumber(L, norm_rand());
2469     return 1;
2470 }
2471 
2472 /* Same as lua but  with tex rng */
lua_math_random(lua_State * L)2473 static int lua_math_random (lua_State *L)
2474 {
2475   lua_Number rand_max = 0x7fffffff ;
2476   lua_Number r =  unif_rand(rand_max) ;
2477   r = (r>=0 ? 0+r : 0-r) ;
2478   r = r / rand_max;
2479   switch (lua_gettop(L)) {  /* check number of arguments */
2480     case 0: {  /* no arguments */
2481       lua_pushnumber(L, r);  /* Number between 0 and 1 */
2482       break;
2483     }
2484     case 1: {  /* only upper limit */
2485       lua_Number u = luaL_checknumber(L, 1);
2486       luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty");
2487       lua_pushnumber(L, floor(r*u) + (lua_Number)(1.0));  /* [1, u] */
2488       break;
2489     }
2490     case 2: {  /* lower and upper limits */
2491       lua_Number l = luaL_checknumber(L, 1);
2492       lua_Number u = luaL_checknumber(L, 2);
2493       luaL_argcheck(L, l <= u, 2, "interval is empty");
2494       lua_pushnumber(L, floor(r*(u-l+1)) + l);  /* [l, u] */
2495       break;
2496     }
2497     default: return luaL_error(L, "wrong number of arguments");
2498   }
2499   return 1;
2500 }
2501 
2502 
2503 
2504 /* Experimental code can either become permanent or disappear. It is
2505 undocumented and mostly present in the experimental branch but for
2506 practical reasons we also have the setup code in the regular binary.
2507 The experimental_code array is indexed by i with 1<= i <= max_experimental_code,
2508 position 0 is not used */
2509 int experimental_code[MAX_EXPERIMENTAL_CODE_SIZE] = { 0 };
2510 
2511 
set_experimental_code(lua_State * L)2512 static int set_experimental_code(lua_State *L)
2513 {
2514     int e, b, i ;
2515 
2516     if (lua_isboolean(L,1)) {
2517         e = 0 ;
2518         b = lua_toboolean(L,1) ;
2519     } else if (lua_isnumber(L,1) && lua_isboolean(L,2)) {
2520         e = (int) lua_tonumber(L, 1);
2521         b = lua_toboolean(L,2) ;
2522     } else {
2523         return luaL_error(L, "boolean or number and boolean expected");
2524     }
2525     if (e==0) {
2526         for (i=1;i<=max_experimental_code;i++) {
2527             experimental_code[i] = b;
2528         }
2529     } else if (0<e && e<=max_experimental_code  ) {
2530         experimental_code[e] = b;
2531     } else {
2532       return luaL_error(L, "first number out of range");
2533     }
2534     return 0;
2535 }
2536 
tex_run_main(lua_State * L)2537 static int tex_run_main(lua_State * L)
2538 {
2539     (void) L;
2540     main_control();
2541     return 0;
2542 }
2543 
tex_run_end(lua_State * L)2544 static int tex_run_end(lua_State * L)
2545 {
2546     (void) L;
2547     final_cleanup();            /* prepare for death */
2548     close_files_and_terminate();
2549     do_final_end();
2550     return 0;
2551 }
2552 
tex_show_context(lua_State * L)2553 static int tex_show_context(lua_State * L)
2554 {
2555     (void) L;
2556     show_context();
2557     return 0;
2558 }
2559 
init_tex_table(lua_State * L)2560 void init_tex_table(lua_State * L)
2561 {
2562     lua_createtable(L, 0, 3);
2563     lua_pushcfunction(L, tex_run_boot);
2564     lua_setfield(L, -2, "initialize");
2565     lua_pushcfunction(L, tex_run_main);
2566     lua_setfield(L, -2, "run");
2567     lua_pushcfunction(L, tex_run_end);
2568     lua_setfield(L, -2, "finish");
2569     lua_setglobal(L, "tex");
2570 }
2571 
2572 
2573 
2574 
2575 static const struct luaL_Reg texlib[] = {
2576     {"run", tex_run_main},      /* may be needed  */
2577     {"finish", tex_run_end},    /* may be needed  */
2578     {"write", luacwrite},
2579     {"print", luacprint},
2580     {"tprint", luactprint},
2581     {"error", texerror},
2582     {"sprint", luacsprint},
2583     {"set", settex},
2584     {"get", gettex},
2585     {"setdimen", setdimen},
2586     {"getdimen", getdimen},
2587     {"setskip", setskip},
2588     {"getskip", getskip},
2589     {"setattribute", setattribute},
2590     {"getattribute", getattribute},
2591     {"setcount", setcount},
2592     {"getcount", getcount},
2593     {"settoks", settoks},
2594     {"gettoks", gettoks},
2595     {"setbox", setbox},
2596     {"getbox", getbox},
2597     {"setlist", setlist},
2598     {"getlist", getlist},
2599     {"setnest", setnest},
2600     {"getnest", getnest},
2601     {"setcatcode", setcatcode},
2602     {"getcatcode", getcatcode},
2603     {"setdelcode", setdelcode},
2604     {"getdelcode", getdelcode},
2605     {"setlccode", setlccode},
2606     {"getlccode", getlccode},
2607     {"setmathcode", setmathcode},
2608     {"getmathcode", getmathcode},
2609     {"setsfcode", setsfcode},
2610     {"getsfcode", getsfcode},
2611     {"setuccode", setuccode},
2612     {"getuccode", getuccode},
2613     {"round", tex_roundnumber},
2614     {"scale", tex_scaletable},
2615     {"sp", tex_scaledimen},
2616     {"fontname", getfontname},
2617     {"fontidentifier", getfontidentifier},
2618     {"pdffontname", getpdffontname},
2619     {"pdffontobjnum", getpdffontobjnum},
2620     {"pdffontsize", getpdffontsize},
2621     {"uniformdeviate", getuniformdeviate},
2622     {"number", getnumber},
2623     {"romannumeral", getromannumeral},
2624     {"pdfpageref", getpdfpageref},
2625     {"pdfxformname", getpdfxformname},
2626     {"definefont", tex_definefont},
2627     {"hashtokens", tex_hashpairs},
2628     {"primitives", tex_primitives},
2629     {"extraprimitives", tex_extraprimitives},
2630     {"enableprimitives", tex_enableprimitives},
2631     {"shipout", tex_shipout},
2632     {"badness", tex_badness},
2633     {"setmath", tex_setmathparm},
2634     {"getmath", tex_getmathparm},
2635     {"linebreak", tex_run_linebreak},
2636     /* tex random generators     */
2637     {"init_rand",   tex_init_rand},
2638     {"uniform_rand",tex_unif_rand},
2639     {"normal_rand", tex_norm_rand},
2640     {"lua_math_randomseed", tex_init_rand}, /* syntactic sugar  */
2641     {"lua_math_random", lua_math_random},
2642     {"set_experimental_code",set_experimental_code},
2643     {"show_context", tex_show_context},
2644     {NULL, NULL}                /* sentinel */
2645 };
2646 
luaopen_tex(lua_State * L)2647 int luaopen_tex(lua_State * L)
2648 {
2649     luaL_register(L, "tex", texlib);
2650     /* *INDENT-OFF* */
2651     make_table(L, "attribute", "tex.attribute"   ,"getattribute", "setattribute");
2652     make_table(L, "skip",      "tex.skip"        ,"getskip",      "setskip");
2653     make_table(L, "dimen",     "tex.dimen"       ,"getdimen",     "setdimen");
2654     make_table(L, "count",     "tex.count"       ,"getcount",     "setcount");
2655     make_table(L, "toks",      "tex.toks"        ,"gettoks",      "settoks");
2656     make_table(L, "box",       "tex.box"         ,"getbox",       "setbox");
2657     make_table(L, "sfcode",    "tex.sfcode"      ,"getsfcode",    "setsfcode");
2658     make_table(L, "lccode",    "tex.lccode"      ,"getlccode",    "setlccode");
2659     make_table(L, "uccode",    "tex.uccode"      ,"getuccode",    "setuccode");
2660     make_table(L, "catcode",   "tex.catcode"     ,"getcatcode",   "setcatcode");
2661     make_table(L, "mathcode",   "tex.mathcode"    ,"getmathcode",  "setmathcode");
2662     make_table(L, "delcode",   "tex.delcode"     ,"getdelcode",   "setdelcode");
2663     make_table(L, "lists",     "tex.lists"       ,"getlist",      "setlist");
2664     make_table(L, "nest",      "tex.nest"        ,"getnest",      "setnest");
2665     /* *INDENT-ON* */
2666     init_nest_lib(L);
2667     /* make the meta entries */
2668     /* fetch it back */
2669     luaL_newmetatable(L, "tex.meta");
2670     lua_pushstring(L, "__index");
2671     lua_pushcfunction(L, gettex);
2672     lua_settable(L, -3);
2673     lua_pushstring(L, "__newindex");
2674     lua_pushcfunction(L, settex);
2675     lua_settable(L, -3);
2676     lua_setmetatable(L, -2);    /* meta to itself */
2677     /* initialize the I/O stack: */
2678     spindles = xmalloc(sizeof(spindle));
2679     spindle_index = 0;
2680     spindles[0].head = NULL;
2681     spindles[0].tail = NULL;
2682     spindle_size = 1;
2683     /* a somewhat odd place for this assert, maybe */
2684     assert(command_names[data_cmd].command_offset == data_cmd);
2685     return 1;
2686 }
2687