beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / lua / ltexlib.c
blob872b2994e2382027082cd454e30f305fd0d3e9b5
1 /* ltexlib.c
3 Copyright 2006-2012 Taco Hoekwater <taco@luatex.org>
5 This file is part of LuaTeX.
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.
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.
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/>. */
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. */
24 #include "ptexlib.h"
25 #include "lua/luatex-api.h"
27 #define attribute(A) eqtb[attribute_base+(A)].hh.rh
28 #define dimen(A) eqtb[scaled_base+(A)].hh.rh
29 #undef skip
30 #define skip(A) eqtb[skip_base+(A)].hh.rh
31 #define mu_skip(A) eqtb[mu_skip_base+(A)].hh.rh
32 #define count(A) eqtb[count_base+(A)].hh.rh
33 #define box(A) equiv(box_base+(A))
35 /* tex random generators */
36 extern int unif_rand(int );
37 extern int norm_rand(void );
38 extern void init_randoms(int );
40 typedef struct {
41 char *text;
42 unsigned int tsize;
43 void *next;
44 boolean partial;
45 int cattable;
46 /* halfword tok; */
47 } rope;
49 typedef struct {
50 rope *head;
51 rope *tail;
52 char complete; /* currently still writing ? */
53 } spindle;
55 #define PARTIAL_LINE 1
56 #define FULL_LINE 0
58 #define write_spindle spindles[spindle_index]
59 #define read_spindle spindles[(spindle_index-1)]
61 static int spindle_size = 0;
62 static spindle *spindles = NULL;
63 static int spindle_index = 0;
65 static void luac_store(lua_State * L, int i, int partial, int cattable)
67 const char *sttemp;
68 char *st;
69 size_t tsize;
70 rope *rn = NULL;
71 sttemp = lua_tolstring(L, i, &tsize);
72 st = xmalloc((unsigned) (tsize + 1));
73 memcpy(st, sttemp, (tsize + 1));
74 if (st) {
75 luacstrings++;
76 rn = (rope *) xmalloc(sizeof(rope));
77 rn->text = st;
78 rn->tsize = (unsigned) tsize;
79 rn->partial = partial;
80 rn->cattable = cattable;
81 rn->next = NULL;
82 /* rn->tok = 0; */
83 if (write_spindle.head == NULL) {
84 assert(write_spindle.tail == NULL);
85 write_spindle.head = rn;
86 } else {
87 write_spindle.tail->next = rn;
89 write_spindle.tail = rn;
90 write_spindle.complete = 0;
94 static int do_luacprint(lua_State * L, int partial, int deftable)
96 int cattable = deftable;
97 int startstrings = 1;
98 int n = lua_gettop(L);
99 if (cattable != NO_CAT_TABLE) {
100 if (lua_type(L, 1) == LUA_TNUMBER && n > 1) {
101 cattable = lua_tointeger(L, 1);
102 startstrings = 2;
103 if (cattable != -1 && cattable != -2 && !valid_catcode_table(cattable)) {
104 cattable = DEFAULT_CAT_TABLE;
108 if (lua_type(L, startstrings) == LUA_TTABLE) {
109 int i;
110 for (i = 1;; i++) {
111 lua_rawgeti(L, startstrings, i);
112 if (lua_isstring(L,-1)) { /* or number */
113 luac_store(L, -1, partial, cattable);
114 lua_pop(L, 1);
115 } else {
116 break;
119 } else {
120 int i;
121 for (i = startstrings; i <= n; i++) {
122 if (!lua_isstring(L,1)) { /* or number */
123 luaL_error(L, "no string to print");
125 luac_store(L, i, partial, cattable);
127 /* hh: We could use this but it makes not much different, apart from allocating more ropes so less
128 memory. To be looked into: lua 5.2 buffer mechanism as now we still hash the concatination. This
129 test was part of the why-eis-luajit-so-slow on crited experiments. */
131 if (startstrings == n) {
132 luac_store(L, n, partial, cattable);
133 } else {
134 lua_concat(L,n-startstrings+1);
135 luac_store(L, startstrings, partial, cattable);
139 return 0;
144 // some first experiments .. somewhat tricky at the other end
146 int luatwrite(lua_State * L)
148 int top = lua_gettop(L);
149 if (top>0) {
150 rope *rn = xmalloc(sizeof(rope)); // overkill
151 int i = 1 ;
152 luacstrings++; // should be luactokens
153 rn->text = NULL;
154 rn->tsize = 0;
155 rn->partial = 0;
156 rn->cattable = DEFAULT_CAT_TABLE;
157 rn->next = NULL;
158 rn->tok = 0;
159 if (write_spindle.head == NULL) {
160 write_spindle.head = rn;
161 } else {
162 write_spindle.tail->next = rn;
164 write_spindle.tail = rn;
165 write_spindle.complete = 0;
166 while (1) {
167 rn->tok = lua_tointeger(L,i);
168 if (i<top) {
169 rope *r = xmalloc(sizeof(rope)); // overkill
170 r->text = NULL;
171 r->tsize = 0;
172 r->partial = 0;
173 r->cattable = DEFAULT_CAT_TABLE;
174 r->next = NULL;
175 r->tok = 0;
176 rn->next = r;
177 rn = r;
178 write_spindle.tail = rn;
179 i++;
180 } else {
181 break;
185 return 0;
190 static int luacwrite(lua_State * L)
192 return do_luacprint(L, FULL_LINE, NO_CAT_TABLE);
195 static int luacprint(lua_State * L)
197 return do_luacprint(L, FULL_LINE, DEFAULT_CAT_TABLE);
200 static int luacsprint(lua_State * L)
202 return do_luacprint(L, PARTIAL_LINE, DEFAULT_CAT_TABLE);
205 static int luactprint(lua_State * L)
207 int i, j;
208 int cattable, startstrings;
209 int n = lua_gettop(L);
210 for (i = 1; i <= n; i++) {
211 cattable = DEFAULT_CAT_TABLE;
212 startstrings = 1;
213 if (lua_type(L, i) != LUA_TTABLE) {
214 luaL_error(L, "no string to print");
216 lua_pushvalue(L, i); /* push the table */
217 lua_pushinteger(L, 1);
218 lua_gettable(L, -2);
219 if (lua_type(L, -1) == LUA_TNUMBER) {
220 cattable = lua_tointeger(L, -1);
221 startstrings = 2;
222 if (cattable != -1 && cattable != -2 && !valid_catcode_table(cattable)) {
223 cattable = DEFAULT_CAT_TABLE;
226 lua_pop(L, 1);
227 for (j = startstrings;; j++) {
228 lua_pushinteger(L, j);
229 lua_gettable(L, -2);
230 if (lua_isstring(L, -1)) { /* or number */
231 luac_store(L, -1, PARTIAL_LINE, cattable);
232 lua_pop(L, 1);
233 } else {
234 lua_pop(L, 1);
235 break;
238 lua_pop(L, 1); /* pop the table */
240 return 0;
243 int luacstring_cattable(void)
245 return (int) read_spindle.tail->cattable;
248 int luacstring_partial(void)
250 return read_spindle.tail->partial;
253 int luacstring_final_line(void)
255 return (read_spindle.tail->next == NULL);
258 int luacstring_input(void)
260 rope *t = read_spindle.head;
261 int ret = 1 ;
262 if (!read_spindle.complete) {
263 read_spindle.complete = 1;
264 read_spindle.tail = NULL;
266 if (t == NULL) {
267 if (read_spindle.tail != NULL)
268 free(read_spindle.tail);
269 read_spindle.tail = NULL;
270 return 0;
272 if (t->text != NULL) {
273 /* put that thing in the buffer */
274 char *st = t->text;
275 int ret = first;
276 last = first;
277 check_buffer_overflow(last + (int) t->tsize);
278 while (t->tsize-- > 0)
279 buffer[last++] = (packed_ASCII_code) * st++;
280 if (!t->partial) {
281 while (last - 1 > ret && buffer[last - 1] == ' ')
282 last--;
284 free(t->text);
285 t->text = NULL;
287 } else if (t->tok > 0) {
288 ret = - t->tok;
291 if (read_spindle.tail != NULL) { /* not a one-liner */
292 free(read_spindle.tail);
294 read_spindle.tail = t;
295 read_spindle.head = t->next;
296 return ret;
299 /* open for reading, and make a new one for writing */
300 void luacstring_start(int n)
302 (void) n; /* for -W */
303 spindle_index++;
304 if (spindle_size == spindle_index) { /* add a new one */
305 spindles = xrealloc(spindles, (unsigned) (sizeof(spindle) * (unsigned) (spindle_size + 1)));
306 spindles[spindle_index].head = NULL;
307 spindles[spindle_index].tail = NULL;
308 spindles[spindle_index].complete = 0;
309 spindle_size++;
313 /* close for reading */
315 void luacstring_close(int n)
317 rope *next, *t;
318 (void) n; /* for -W */
319 next = read_spindle.head;
320 while (next != NULL) {
321 if (next->text != NULL)
322 free(next->text);
323 t = next;
324 next = next->next;
325 if (t==read_spindle.tail) {
326 read_spindle.tail = NULL;
328 free(t);
330 read_spindle.head = NULL;
331 if (read_spindle.tail != NULL)
332 free(read_spindle.tail);
333 read_spindle.tail = NULL;
334 read_spindle.complete = 0;
335 spindle_index--;
338 /* local (static) versions */
340 #define check_index_range(j,s) \
341 if (j<0 || j > 65535) { \
342 luaL_error(L, "incorrect index specification for tex.%s()", s); }
344 #define check_register(base) do { \
345 int k = get_item_index(L, lua_gettop(L), base); \
346 if ((k>=0) && (k <= 65535)) { \
347 lua_pushinteger(L,k); \
348 } else { \
349 lua_pushboolean(L,false); \
351 return 1; \
352 } while (1)
354 static const char *scan_integer_part(lua_State * L, const char *ss, int *ret, int *radix_ret)
356 boolean negative = false; /* should the answer be negated? */
357 int m = 214748364; /* |$2^{31}$ / radix|, the threshold of danger */
358 int d; /* the digit just scanned */
359 boolean vacuous = true; /* have no digits appeared? */
360 boolean OK_so_far = true; /* has an error message been issued? */
361 int radix1 = 10; /* the radix of the integer */
362 int c = 0; /* the current character */
363 const char *s; /* where we stopped in the string |ss| */
364 integer val = 0; /* return value */
365 s = ss;
366 do {
367 do {
368 c = *s++;
369 } while (c && c == ' ');
370 if (c == '-') {
371 negative = !negative;
372 c = '+';
374 } while (c == '+');
375 if (c == '\'') {
376 radix1 = 8;
377 m = 02000000000;
378 c = *s++;
379 } else if (c == '"') {
380 radix1 = 16;
381 m = 01000000000;
382 c = *s++;
384 /* Accumulate the constant until |cur_tok| is not a suitable digit */
385 while (1) {
386 if ((c < '0' + radix1) && (c >= '0') && (c <= '0' + 9)) {
387 d = c - '0';
388 } else if (radix1 == 16) {
389 if ((c <= 'A' + 5) && (c >= 'A')) {
390 d = c - 'A' + 10;
391 } else if ((c <= 'a' + 5) && (c >= 'a')) {
392 d = c - 'a' + 10;
393 } else {
394 break;
396 } else {
397 break;
399 vacuous = false;
400 if ((val >= m) && ((val > m) || (d > 7) || (radix1 != 10))) {
401 if (OK_so_far) {
402 luaL_error(L, "Number too big");
403 val = infinity;
404 OK_so_far = false;
406 } else {
407 val = val * radix1 + d;
409 c = *s++;
411 if (vacuous) {
412 /* Express astonishment that no number was here */
413 luaL_error(L, "Missing number, treated as zero");
415 if (negative)
416 val = -val;
417 *ret = val;
418 *radix_ret = radix1;
419 if (c != ' ' && s > ss)
420 s--;
421 return s;
424 #define set_conversion(A,B) do { num=(A); denom=(B); } while(0)
427 static const char *scan_dimen_part(lua_State * L, const char *ss, int *ret)
428 /* sets |cur_val| to a dimension */
430 boolean negative = false; /* should the answer be negated? */
431 int f = 0; /* numerator of a fraction whose denominator is $2^{16}$ */
432 int num, denom; /* conversion ratio for the scanned units */
433 int k; /* number of digits in a decimal fraction */
434 scaled v; /* an internal dimension */
435 int save_cur_val; /* temporary storage of |cur_val| */
436 int c; /* the current character */
437 const char *s = ss; /* where we are in the string */
438 int radix1 = 0; /* the current radix */
439 int rdig[18]; /* to save the |dig[]| array */
440 int saved_tex_remainder; /* to save |tex_remainder| */
441 int saved_arith_error; /* to save |arith_error| */
442 int saved_cur_val; /* to save the global |cur_val| */
443 saved_tex_remainder = tex_remainder;
444 saved_arith_error = arith_error;
445 saved_cur_val = cur_val;
446 /* Get the next non-blank non-sign... */
447 do {
448 /* Get the next non-blank non-call token */
449 do {
450 c = *s++;
451 } while (c && c == ' ');
452 if (c == '-') {
453 negative = !negative;
454 c = '+';
456 } while (c == '+');
457 if (c == ',') {
458 c = '.';
460 if (c != '.') {
461 s = scan_integer_part(L, (s > ss ? (s - 1) : ss), &cur_val, &radix1);
462 c = *s;
463 } else {
464 radix1 = 10;
465 cur_val = 0;
466 c = *(--s);
468 if (c == ',')
469 c = '.';
470 if ((radix1 == 10) && (c == '.')) {
471 /* Scan decimal fraction */
472 for (k = 0; k < 18; k++)
473 rdig[k] = dig[k];
474 k = 0;
475 s++; /* get rid of the '.' */
476 while (1) {
477 c = *s++;
478 if ((c > '0' + 9) || (c < '0'))
479 break;
480 if (k < 17) { /* digits for |k>=17| cannot affect the result */
481 dig[k++] = c - '0';
484 f = round_decimals(k);
485 if (c != ' ')
486 c = *(--s);
487 for (k = 0; k < 18; k++)
488 dig[k] = rdig[k];
490 if (cur_val < 0) { /* in this case |f=0| */
491 negative = !negative;
492 cur_val = -cur_val;
494 /* Scan for (u)units that are internal dimensions;
495 |goto attach_sign| with |cur_val| set if found */
496 save_cur_val = cur_val;
497 /* Get the next non-blank non-call... */
498 do {
499 c = *s++;
500 } while (c && c == ' ');
501 if (c != ' ')
502 c = *(--s);
503 if (strncmp(s, "em", 2) == 0) {
504 s += 2;
505 v = (quad(get_cur_font()));
506 } else if (strncmp(s, "ex", 2) == 0) {
507 s += 2;
508 v = (x_height(get_cur_font()));
509 } else if (strncmp(s, "px", 2) == 0) {
510 s += 2;
511 v = dimen_par(px_dimen_code);
512 } else {
513 goto NOT_FOUND;
515 c = *s++;
516 if (c != ' ') {
517 c = *(--s);
519 cur_val = nx_plus_y(save_cur_val, v, xn_over_d(v, f, 0200000));
520 goto ATTACH_SIGN;
521 NOT_FOUND:
522 /* Scan for (m)\.{mu} units and |goto attach_fraction| */
523 if (strncmp(s, "mu", 2) == 0) {
524 s += 2;
525 goto ATTACH_FRACTION;
527 if (strncmp(s, "true", 4) == 0) {
528 /* Adjust (f)for the magnification ratio */
529 s += 4;
530 if (output_mode_used == OMODE_DVI) {
531 prepare_mag();
532 if (int_par(mag_code) != 1000) {
533 cur_val = xn_over_d(cur_val, 1000, int_par(mag_code));
534 f = (1000 * f + 0200000 * tex_remainder) / int_par(mag_code);
535 cur_val = cur_val + (f / 0200000);
536 f = f % 0200000;
539 do {
540 c = *s++;
541 } while (c && c == ' ');
542 c = *(--s);
544 if (strncmp(s, "pt", 2) == 0) {
545 s += 2;
546 goto ATTACH_FRACTION; /* the easy case */
548 /* Scan for (a)all other units and adjust |cur_val| and |f| accordingly;
549 |goto done| in the case of scaled points */
550 if (strncmp(s, "mm", 2) == 0) {
551 s += 2;
552 set_conversion(7227, 2540);
553 } else if (strncmp(s, "cm", 2) == 0) {
554 s += 2;
555 set_conversion(7227, 254);
556 } else if (strncmp(s, "sp", 2) == 0) {
557 s += 2;
558 goto DONE;
559 } else if (strncmp(s, "bp", 2) == 0) {
560 s += 2;
561 set_conversion(7227, 7200);
562 } else if (strncmp(s, "in", 2) == 0) {
563 s += 2;
564 set_conversion(7227, 100);
565 } else if (strncmp(s, "dd", 2) == 0) {
566 s += 2;
567 set_conversion(1238, 1157);
568 } else if (strncmp(s, "cc", 2) == 0) {
569 s += 2;
570 set_conversion(14856, 1157);
571 } else if (strncmp(s, "pc", 2) == 0) {
572 s += 2;
573 set_conversion(12, 1);
574 } else if (strncmp(s, "nd", 2) == 0) {
575 s += 2;
576 set_conversion(685, 642);
577 } else if (strncmp(s, "nc", 2) == 0) {
578 s += 2;
579 set_conversion(1370, 107);
580 } else {
581 /* Complain about unknown unit and |goto done2| */
582 luaL_error(L, "Illegal unit of measure (pt inserted)");
583 goto DONE2;
585 cur_val = xn_over_d(cur_val, num, denom);
586 f = (num * f + 0200000 * tex_remainder) / denom;
587 cur_val = cur_val + (f / 0200000);
588 f = f % 0200000;
589 DONE2:
590 ATTACH_FRACTION:
591 if (cur_val >= 040000)
592 arith_error = true;
593 else
594 cur_val = cur_val * 65536 + f;
595 DONE:
596 /* Scan an optional space */
597 c = *s++;
598 if (c != ' ')
599 s--;
600 ATTACH_SIGN:
601 if (arith_error || (abs(cur_val) >= 010000000000)) {
602 /* Report that this dimension is out of range */
603 luaL_error(L, "Dimension too large");
604 cur_val = max_dimen;
606 if (negative)
607 cur_val = -cur_val;
608 *ret = cur_val;
609 tex_remainder = saved_tex_remainder;
610 arith_error = saved_arith_error;
611 cur_val = saved_cur_val;
612 return s;
615 int dimen_to_number(lua_State * L, const char *s)
617 int j = 0;
618 const char *d = scan_dimen_part(L, s, &j);
619 if (*d) {
620 luaL_error(L, "conversion failed (trailing junk?)");
621 j = 0;
623 return j;
626 static int tex_scaledimen(lua_State * L)
628 int sp;
629 int t = lua_type(L, 1);
630 if (t == LUA_TNUMBER) {
631 sp = lua_tointeger(L, 1);
632 } else if (t == LUA_TSTRING) {
633 sp = dimen_to_number(L, lua_tostring(L, 1));
634 } else {
635 luaL_error(L, "argument must be a string or a number");
636 return 0;
638 lua_pushinteger(L, sp);
639 return 1;
642 static int texerror (lua_State * L)
644 const char **errhlp = NULL;
645 const char *error = luaL_checkstring(L,1);
646 int n = lua_gettop(L);
647 if (n==2 && lua_type(L, n) == LUA_TTABLE) {
648 int i;
649 int l = 1; /* |errhlp| is terminated by a NULL entry */
650 for (i = 1;; i++) {
651 lua_rawgeti(L, n, i);
652 if (lua_type(L,-1) == LUA_TSTRING) {
653 l++;
654 lua_pop(L, 1);
655 } else {
656 lua_pop(L, 1);
657 break;
660 if (l>1) {
661 errhlp = xmalloc(l * sizeof(char *));
662 memset(errhlp,0,l * sizeof(char *));
663 for (i = 1;; i++) {
664 lua_rawgeti(L, n, i);
665 if (lua_type(L,-1) == LUA_TSTRING) {
666 errhlp[(i-1)] = lua_tostring(L,-1);
667 lua_pop(L, 1);
668 } else {
669 break;
674 deletions_allowed = false;
675 tex_error(error, errhlp);
676 if (errhlp)
677 xfree(errhlp);
678 deletions_allowed = true;
679 return 0;
682 static int get_item_index(lua_State * L, int i, int base)
684 size_t kk;
685 int k;
686 int cur_cs1;
687 const char *s;
688 switch (lua_type(L, i)) {
689 case LUA_TSTRING:
690 s = lua_tolstring(L, i, &kk);
691 cur_cs1 = string_lookup(s, kk);
692 if (cur_cs1 == undefined_control_sequence || cur_cs1 == undefined_cs_cmd)
693 k = -1; /* guarandeed invalid */
694 else
695 k = (equiv(cur_cs1) - base);
696 break;
697 case LUA_TNUMBER:
698 k = luaL_checkinteger(L, i);
699 break;
700 default:
701 luaL_error(L, "argument must be a string or a number");
702 k = -1; /* not a valid index */
704 return k;
707 #define check_item_global(L,top,isglobal) \
708 if (top == 3 && (lua_type(L,1) == LUA_TSTRING)) { \
709 const char *s = lua_tostring(L, 1); \
710 if (lua_key_eq(s,global)) { \
711 isglobal = 1; \
715 #define set_item_index_plus(L, where, base, what, value, is_global, is_assign, set_register, glue) { \
716 size_t len; \
717 const char *str; \
718 int key, err, cs; \
719 int save_global_defs = int_par(global_defs_code); \
720 if (is_global) { \
721 int_par(global_defs_code) = 1; \
723 switch (lua_type(L, where)) { \
724 case LUA_TSTRING: \
725 str = lua_tolstring(L, where, &len); \
726 cs = string_lookup(str, len); \
727 if (cs == undefined_control_sequence || cs == undefined_cs_cmd) { \
728 luaL_error(L, "incorrect %s name", what); \
729 } else { \
730 key = equiv(cs) - base; \
731 if (key >= 0 && key <= 65535) { \
732 err = set_register(key, value); \
733 if (err) { \
734 luaL_error(L, "incorrect %s value", what); \
736 } else if (is_assign(eq_type(cs))) { \
737 if (glue) { \
738 int a = is_global; \
739 define(equiv(cs), assign_glue_cmd, value); \
740 } else { \
741 assign_internal_value((is_global ? 4 : 0), equiv(cs), value); \
743 } else { \
744 luaL_error(L, "incorrect %s name", what); \
747 break; \
748 case LUA_TNUMBER: \
749 key = luaL_checkinteger(L, where); \
750 if (key>=0 && key <= 65535) { \
751 err = set_register(key, value); \
752 if (err) { \
753 luaL_error(L, "incorrect %s value", what); \
755 } else { \
756 luaL_error(L, "incorrect %s index", what); \
758 break; \
759 default: \
760 luaL_error(L, "argument of 'set%s' must be a string or a number", what); \
762 int_par(global_defs_code) = save_global_defs; \
765 static int gettex(lua_State * L);
767 #define get_item_index_plus(L, where, base, what, value, is_assign, get_register, glue) { \
768 size_t len; \
769 const char *str; \
770 int key, cs; \
771 switch (lua_type(L, where)) { \
772 case LUA_TSTRING: \
773 str = lua_tolstring(L, where, &len); \
774 cs = string_lookup(str, len); \
775 if (cs == undefined_control_sequence || cs == undefined_cs_cmd) { \
776 luaL_error(L, "incorrect %s name", what); \
777 } else { \
778 key = equiv(cs) - base; \
779 if (key >= 0 && key <= 65535) { \
780 value = get_register(key); \
781 } else if (is_assign(eq_type(cs))) { \
782 gettex(L); /* lazy */ \
783 } else { \
784 luaL_error(L, "incorrect %s name", what); \
787 break; \
788 case LUA_TNUMBER: \
789 key = luaL_checkinteger(L, where); \
790 if (key>=0 && key <= 65535) { \
791 value = get_register(key); \
792 } else { \
793 luaL_error(L, "incorrect %s index", what); \
795 break; \
796 default: \
797 luaL_error(L, "argument of 'get%s' must be a string or a number", what); \
801 static int isdimen(lua_State * L)
803 check_register(scaled_base);
806 static int setdimen(lua_State * L)
808 int isglobal = 0;
809 int value = 0;
810 int top = lua_gettop(L);
811 int t = lua_type(L, top);
812 check_item_global(L,top,isglobal);
813 if (t == LUA_TNUMBER) {
814 value = lua_tointeger(L, top);
815 } else if (t == LUA_TSTRING) {
816 value = dimen_to_number(L, lua_tostring(L, top));
817 } else {
818 luaL_error(L, "unsupported %s value type","dimen");
820 set_item_index_plus(L, top-1, scaled_base, "dimen", value, isglobal, is_dim_assign, set_tex_dimen_register, false);
821 return 0;
824 static int getdimen(lua_State * L)
826 int value = 0;
827 get_item_index_plus(L, lua_gettop(L), scaled_base, "dimen", value, is_dim_assign, get_tex_dimen_register, false);
828 lua_pushinteger(L, value);
829 return 1;
832 static int isskip(lua_State * L)
834 check_register(skip_base);
837 static int setskip(lua_State * L)
839 int isglobal = 0;
840 halfword *value = NULL;
841 int top = lua_gettop(L);
842 check_item_global(L,top,isglobal);
843 value = check_isnode(L, top);
844 set_item_index_plus(L, top-1, skip_base, "skip", *value, isglobal, is_glue_assign, set_tex_skip_register, true);
845 return 0;
848 static int getskip(lua_State * L)
850 int value = 0;
851 get_item_index_plus(L, lua_gettop(L), skip_base, "skip", value, is_glue_assign, get_tex_skip_register, true);
852 if (value == null) {
853 lua_nodelib_push_fast(L, copy_node(zero_glue));
854 } else {
855 lua_nodelib_push_fast(L, copy_node(value));
857 return 1;
860 static int ismuskip(lua_State * L)
862 check_register(mu_skip_base);
865 static int setmuskip(lua_State * L)
867 int isglobal = 0;
868 halfword *value = NULL;
869 int top = lua_gettop(L);
870 check_item_global(L,top,isglobal);
871 value = check_isnode(L, top);
872 set_item_index_plus(L, top-1, mu_skip_base, "muskip", *value, isglobal, is_mu_glue_assign, set_tex_mu_skip_register, true);
873 return 0;
876 static int getmuskip(lua_State * L)
878 int value = 0;
879 get_item_index_plus(L, lua_gettop(L), mu_skip_base, "muskip", value, is_mu_glue_assign, get_tex_mu_skip_register, true);
880 lua_nodelib_push_fast(L, copy_node(value));
881 return 1;
884 static int iscount(lua_State * L)
886 check_register(count_base);
889 static int setcount(lua_State * L)
891 int t;
892 int isglobal = 0;
893 int value = 0;
894 int top = lua_gettop(L);
895 check_item_global(L,top,isglobal);
896 t = lua_type(L,top);
897 if (t == LUA_TNUMBER) {
898 value = lua_tointeger(L, top);
899 } else {
900 luaL_error(L, "unsupported %s value type","count");
902 set_item_index_plus(L, top-1, count_base, "count", value, isglobal, is_int_assign, set_tex_count_register, false);
903 return 0;
906 static int getcount(lua_State * L)
908 int value = 0;
909 get_item_index_plus(L, lua_gettop(L), count_base, "count", value, is_int_assign, get_tex_count_register, false);
910 lua_pushinteger(L, value);
911 return 1;
914 static int isattribute(lua_State * L)
916 check_register(attribute_base);
919 /* there are no system set attributes so this is a bit overkill */
921 static int setattribute(lua_State * L)
923 int t;
924 int isglobal = 0;
925 int value = 0;
926 int top = lua_gettop(L);
927 check_item_global(L,top,isglobal);
928 t = lua_type(L,top);
929 if (t == LUA_TNUMBER) {
930 value = lua_tointeger(L, top);
931 } else {
932 luaL_error(L, "unsupported %s value type","attribute");
934 set_item_index_plus(L, top-1, attribute_base, "attribute", value, isglobal, is_attr_assign, set_tex_attribute_register, false);
935 return 0;
938 static int getattribute(lua_State * L)
940 int value = 0;
941 get_item_index_plus(L, lua_gettop(L), attribute_base, "attribute", value, is_attr_assign, get_tex_attribute_register, false);
942 lua_pushinteger(L, value);
943 return 1;
946 /* todo: we can avoid memcpy as there is no need to go through the pool */
948 /* use string_to_toks */
950 static int istoks(lua_State * L)
952 check_register(toks_base);
955 static int settoks(lua_State * L)
957 int i, err, k;
958 lstring str;
959 char *s;
960 const char *ss;
961 int is_global = 0;
962 int save_global_defs = int_par(global_defs_code);
963 int n = lua_gettop(L);
964 if (n == 3 && (lua_type(L,1) == LUA_TSTRING)) {
965 const char *s = lua_tostring(L, 1);
966 if (lua_key_eq(s,global))
967 is_global = 1;
969 if (is_global)
970 int_par(global_defs_code) = 1;
971 i = lua_gettop(L);
972 if (lua_type(L,i) != LUA_TSTRING) {
973 luaL_error(L, "unsupported value type");
975 ss = lua_tolstring(L, i, &str.l);
976 s = xmalloc (str.l+1);
977 memcpy (s, ss, str.l+1);
978 str.s = (unsigned char *)s;
979 k = get_item_index(L, (i - 1), toks_base);
980 check_index_range(k, "settoks");
981 err = set_tex_toks_register(k, str);
982 xfree(str.s);
983 int_par(global_defs_code) = save_global_defs;
984 if (err) {
985 luaL_error(L, "incorrect value");
987 return 0;
990 static int scantoks(lua_State * L)
992 int i, err, k, c;
993 lstring str;
994 char *s;
995 const char *ss;
996 int is_global = 0;
997 int save_global_defs = int_par(global_defs_code);
998 int n = lua_gettop(L);
999 if (n == 4 && (lua_type(L,1) == LUA_TSTRING)) {
1000 const char *s = lua_tostring(L, 1);
1001 if (lua_key_eq(s,global))
1002 is_global = 1;
1004 /* action : vsettokscct(L, is_global); */
1005 if (is_global)
1006 int_par(global_defs_code) = 1;
1007 i = lua_gettop(L);
1008 if (lua_type(L,i) != LUA_TSTRING) {
1009 luaL_error(L, "unsupported value type");
1011 ss = lua_tolstring(L, i, &str.l);
1012 s = xmalloc (str.l+1);
1013 memcpy (s, ss, str.l+1);
1014 str.s = (unsigned char *)s;
1015 k = get_item_index(L, (i - 2), toks_base);
1016 c = luaL_checkinteger(L, i - 1);
1017 check_index_range(k, "settoks");
1018 err = scan_tex_toks_register(k, c, str);
1019 xfree(str.s);
1020 int_par(global_defs_code) = save_global_defs;
1021 if (err) {
1022 luaL_error(L, "incorrect value");
1024 return 0;
1027 static int gettoks(lua_State * L)
1029 char *ss;
1030 str_number t;
1031 int k = get_item_index(L, lua_gettop(L), toks_base);
1032 check_index_range(k, "gettoks");
1033 t = get_tex_toks_register(k);
1034 ss = makecstring(t);
1035 lua_pushstring(L, ss);
1036 free(ss);
1037 flush_str(t);
1038 return 1;
1041 static int get_box_id(lua_State * L, int i, boolean report)
1043 const char *s;
1044 int cur_cs1, cur_cmd1;
1045 size_t k = 0;
1046 int j = -1;
1047 switch (lua_type(L, i)) {
1048 case LUA_TSTRING:
1049 s = lua_tolstring(L, i, &k);
1050 cur_cs1 = string_lookup(s, k);
1051 cur_cmd1 = eq_type(cur_cs1);
1052 if (cur_cmd1 == char_given_cmd ||
1053 cur_cmd1 == math_given_cmd) {
1054 j = equiv(cur_cs1);
1056 break;
1057 case LUA_TNUMBER:
1058 j = lua_tointeger(L, (i));
1059 break;
1060 default:
1061 if (report) {
1062 luaL_error(L, "argument must be a string or a number");
1064 j = -1; /* not a valid box id */
1066 return j;
1069 static int getbox(lua_State * L)
1071 int t;
1072 int k = get_box_id(L, -1, true);
1073 check_index_range(k, "getbox");
1074 t = get_tex_box_register(k);
1075 nodelist_to_lua(L, t);
1076 return 1;
1079 static int splitbox(lua_State * L)
1081 const char *s;
1082 int k = get_box_id(L, 1, true);
1083 check_index_range(k, "splitbox");
1084 if (lua_isnumber(L, 2)) {
1085 int m = 1;
1086 if (lua_type(L, 3) == LUA_TSTRING) {
1087 s = lua_tostring(L, 3);
1088 if (lua_key_eq(s, exactly)) {
1089 m = 0;
1090 } else if (lua_key_eq(s, additional)) {
1091 m = 1;
1093 } else if (lua_type(L, 3) == LUA_TNUMBER) {
1094 m = (int) lua_tointeger(L, 3);
1096 if ((m<0) || (m>1)) {
1097 luaL_error(L, "wrong mode in splitbox");
1099 nodelist_to_lua(L, vsplit(k,lua_tointeger(L,2),m));
1100 } else {
1101 /* maybe a warning */
1102 lua_pushnil(L);
1104 return 1;
1107 static int isbox(lua_State * L)
1109 int k = get_box_id(L, -1, false);
1110 lua_pushboolean(L,(k>=0 && k<=65535));
1111 return 1;
1114 static int vsetbox(lua_State * L, int is_global)
1116 int j, k, err;
1117 int save_global_defs = int_par(global_defs_code);
1118 if (is_global)
1119 int_par(global_defs_code) = 1;
1120 k = get_box_id(L, -2, true);
1121 check_index_range(k, "setbox");
1122 if (lua_isboolean(L, -1)) {
1123 j = lua_toboolean(L, -1);
1124 if (j == 0)
1125 j = null;
1126 else
1127 return 0;
1128 } else {
1129 j = nodelist_from_lua(L);
1130 if (j != null && type(j) != hlist_node && type(j) != vlist_node) {
1131 luaL_error(L, "setbox: incompatible node type (%s)\n", get_node_name(type(j), subtype(j)));
1132 return 0;
1136 err = set_tex_box_register(k, j);
1137 int_par(global_defs_code) = save_global_defs;
1138 if (err) {
1139 luaL_error(L, "incorrect value");
1141 return 0;
1144 static int setbox(lua_State * L)
1146 int isglobal = 0;
1147 int n = lua_gettop(L);
1148 if (n == 3 && (lua_type(L,1) == LUA_TSTRING)) {
1149 const char *s = lua_tostring(L, 1);
1150 if (lua_key_eq(s,global))
1151 isglobal = 1;
1153 return vsetbox(L, isglobal);
1156 #define check_char_range(j,s,lim) \
1157 if (j<0 || j >= lim) { \
1158 luaL_error(L, "incorrect character value %d for tex.%s()", (int) j, s); \
1161 static int setcode (lua_State *L, void (*setone)(int,halfword,quarterword),
1162 void (*settwo)(int,halfword,quarterword), const char *name, int lim)
1164 int ch;
1165 halfword val, ucval;
1166 int level = cur_level;
1167 int n = lua_gettop(L);
1168 int f = 1;
1169 if (n>1 && lua_type(L,1) == LUA_TTABLE)
1170 f++;
1171 if (n>2 && (lua_type(L,f) == LUA_TSTRING)) {
1172 const char *s = lua_tostring(L, f);
1173 if (lua_key_eq(s,global)) {
1174 level = level_one;
1175 f++;
1178 ch = luaL_checkinteger(L, f);
1179 check_char_range(ch, name, 65536*17);
1180 val = (halfword) luaL_checkinteger(L, f+1);
1181 check_char_range(val, name, lim);
1182 (setone)(ch, val, level);
1183 if (settwo != NULL && n-f == 2) {
1184 ucval = (halfword) luaL_checkinteger(L, f+2);
1185 check_char_range(ucval, name, lim);
1186 (settwo)(ch, ucval, level);
1188 return 0;
1191 static int setlccode(lua_State * L)
1193 return setcode(L, &set_lc_code, &set_uc_code, "setlccode", 65536*17);
1196 static int getlccode(lua_State * L)
1198 int ch = luaL_checkinteger(L, -1);
1199 check_char_range(ch, "getlccode", 65536*17);
1200 lua_pushinteger(L, get_lc_code(ch));
1201 return 1;
1204 static int setuccode(lua_State * L)
1206 return setcode(L, &set_uc_code, &set_lc_code, "setuccode", 65536*17);
1209 static int getuccode(lua_State * L)
1211 int ch = luaL_checkinteger(L, -1);
1212 check_char_range(ch, "getuccode", 65536*17);
1213 lua_pushinteger(L, get_uc_code(ch));
1214 return 1;
1217 static int setsfcode(lua_State * L)
1219 return setcode(L, &set_sf_code, NULL, "setsfcode", 32768);
1222 static int getsfcode(lua_State * L)
1224 int ch = luaL_checkinteger(L, -1);
1225 check_char_range(ch, "getsfcode", 65536*17);
1226 lua_pushinteger(L, get_sf_code(ch));
1227 return 1;
1230 static int setcatcode(lua_State * L)
1232 int ch;
1233 halfword val;
1234 int level = cur_level;
1235 int cattable = int_par(cat_code_table_code);
1236 int n = lua_gettop(L);
1237 int f = 1;
1238 if (n>1 && lua_type(L,1) == LUA_TTABLE)
1239 f++;
1240 if (n>2 && (lua_type(L,f) == LUA_TSTRING)) {
1241 const char *s = lua_tostring(L, f);
1242 if (lua_key_eq(s,global)) {
1243 level = level_one;
1244 f++;
1247 if (n-f == 2) {
1248 cattable = luaL_checkinteger(L, -3);
1250 ch = luaL_checkinteger(L, -2);
1251 check_char_range(ch, "setcatcode", 65536*17);
1252 val = (halfword) luaL_checkinteger(L, -1);
1253 check_char_range(val, "setcatcode", 16);
1254 set_cat_code(cattable, ch, val, level);
1255 return 0;
1258 static int getcatcode(lua_State * L)
1260 int cattable = int_par(cat_code_table_code);
1261 int ch = luaL_checkinteger(L, -1);
1262 if (lua_gettop(L)>=2 && lua_type(L,-2)==LUA_TNUMBER) {
1263 cattable = luaL_checkinteger(L, -2);
1265 check_char_range(ch, "getcatcode", 65536*17);
1266 lua_pushinteger(L, get_cat_code(cattable, ch));
1267 return 1;
1271 static int setmathcode(lua_State * L)
1273 int ch;
1274 halfword cval, fval, chval;
1275 int level = cur_level;
1276 int n = lua_gettop(L);
1277 int f = 1;
1278 if (n>1 && lua_type(L,1) == LUA_TTABLE)
1279 f++;
1280 if (n>2 && (lua_type(L,f) == LUA_TSTRING)) {
1281 const char *s = lua_tostring(L, f);
1282 if (lua_key_eq(s,global)) {
1283 level = level_one;
1284 f++;
1287 if (n-f!=1 || lua_type(L,f+1) != LUA_TTABLE) {
1288 luaL_error(L, "Bad arguments for tex.setmathcode()");
1290 ch = luaL_checkinteger(L, -2);
1291 check_char_range(ch, "setmathcode", 65536*17);
1293 lua_rawgeti(L, -1, 1);
1294 cval = (halfword) luaL_checkinteger(L, -1);
1295 lua_rawgeti(L, -2, 2);
1296 fval = (halfword) luaL_checkinteger(L, -1);
1297 lua_rawgeti(L, -3, 3);
1298 chval = (halfword) luaL_checkinteger(L, -1);
1299 lua_pop(L,3);
1301 check_char_range(cval, "setmathcode", 8);
1302 check_char_range(fval, "setmathcode", 256);
1303 check_char_range(chval, "setmathcode", 65536*17);
1304 set_math_code(ch, cval,fval, chval, (quarterword) (level));
1305 return 0;
1308 static int getmathcode(lua_State * L)
1310 mathcodeval mval = { 0, 0, 0 };
1311 int ch = luaL_checkinteger(L, -1);
1312 check_char_range(ch, "getmathcode", 65536*17);
1313 mval = get_math_code(ch);
1314 lua_newtable(L);
1315 lua_pushinteger(L,mval.class_value);
1316 lua_rawseti(L, -2, 1);
1317 lua_pushinteger(L,mval.family_value);
1318 lua_rawseti(L, -2, 2);
1319 lua_pushinteger(L,mval.character_value);
1320 lua_rawseti(L, -2, 3);
1321 return 1;
1324 static int getmathcodes(lua_State * L)
1326 mathcodeval mval = { 0, 0, 0 };
1327 int ch = luaL_checkinteger(L, -1);
1328 check_char_range(ch, "getmathcodes", 65536*17);
1329 mval = get_math_code(ch);
1330 lua_pushinteger(L,mval.class_value);
1331 lua_pushinteger(L,mval.family_value);
1332 lua_pushinteger(L,mval.character_value);
1333 return 3;
1336 static int setdelcode(lua_State * L)
1338 int ch;
1339 halfword sfval, scval, lfval, lcval;
1340 int level = cur_level;
1341 int n = lua_gettop(L);
1342 int f = 1;
1343 if (n>1 && lua_type(L,1) == LUA_TTABLE)
1344 f++;
1345 if (n>2 && (lua_type(L,f) == LUA_TSTRING)) {
1346 const char *s = lua_tostring(L, f);
1347 if (lua_key_eq(s,global)) {
1348 level = level_one;
1349 f++;
1352 if (n-f!=1 || lua_type(L,f+1) != LUA_TTABLE) {
1353 luaL_error(L, "Bad arguments for tex.setdelcode()");
1355 ch = luaL_checkinteger(L, -2);
1356 check_char_range(ch, "setdelcode", 65536*17);
1357 lua_rawgeti(L, -1, 1);
1358 sfval = (halfword) luaL_checkinteger(L, -1);
1359 lua_rawgeti(L, -2, 2);
1360 scval = (halfword) luaL_checkinteger(L, -1);
1361 lua_rawgeti(L, -3, 3);
1362 lfval = (halfword) luaL_checkinteger(L, -1);
1363 lua_rawgeti(L, -4, 4);
1364 lcval = (halfword) luaL_checkinteger(L, -1);
1365 lua_pop(L,4);
1367 check_char_range(sfval, "setdelcode", 256);
1368 check_char_range(scval, "setdelcode", 65536*17);
1369 check_char_range(lfval, "setdelcode", 256);
1370 check_char_range(lcval, "setdelcode", 65536*17);
1371 set_del_code(ch, sfval, scval, lfval, lcval, (quarterword) (level));
1373 return 0;
1376 static int getdelcode(lua_State * L)
1378 delcodeval mval = { 0, 0, 0, 0, 0 };
1379 int ch = luaL_checkinteger(L, -1);
1380 check_char_range(ch, "getdelcode", 65536*17);
1381 mval = get_del_code(ch);
1382 lua_newtable(L);
1383 lua_pushinteger(L,mval.small_family_value);
1384 lua_rawseti(L, -2, 1);
1385 lua_pushinteger(L,mval.small_character_value);
1386 lua_rawseti(L, -2, 2);
1387 lua_pushinteger(L,mval.large_family_value);
1388 lua_rawseti(L, -2, 3);
1389 lua_pushinteger(L,mval.large_character_value);
1390 lua_rawseti(L, -2, 4);
1391 return 1;
1394 static int getdelcodes(lua_State * L)
1396 delcodeval mval = { 0, 0, 0, 0, 0 };
1397 int ch = luaL_checkinteger(L, -1);
1398 check_char_range(ch, "getdelcodes", 65536*17);
1399 mval = get_del_code(ch);
1400 lua_pushinteger(L,mval.small_family_value);
1401 lua_pushinteger(L,mval.small_character_value);
1402 lua_pushinteger(L,mval.large_family_value);
1403 lua_pushinteger(L,mval.large_character_value);
1404 return 4;
1407 static int settex(lua_State * L)
1409 const char *st;
1410 int texstr;
1411 size_t k;
1412 int cur_cs1, cur_cmd1;
1413 int isglobal = 0;
1414 int j = 0;
1415 int i = lua_gettop(L);
1416 if (lua_type(L,i-1) == LUA_TSTRING) {
1417 st = lua_tolstring(L, (i - 1), &k);
1418 if (lua_key_eq(st,prevdepth)) {
1419 if (lua_type(L, i) == LUA_TNUMBER) {
1420 cur_list.prev_depth_field = lua_tointeger(L, i);
1421 } else if (lua_type(L, i) == LUA_TSTRING) {
1422 cur_list.prev_depth_field = dimen_to_number(L, lua_tostring(L, i));
1423 } else {
1424 luaL_error(L, "unsupported value type");
1426 return 0;
1427 } else if (lua_key_eq(st,prevgraf)) {
1428 if (lua_type(L, i) == LUA_TNUMBER) {
1429 cur_list.pg_field = lua_tointeger(L, i);
1430 } else {
1431 luaL_error(L, "unsupported value type");
1433 return 0;
1434 } else if (lua_key_eq(st,spacefactor)) {
1435 if (lua_type(L, i) == LUA_TNUMBER) {
1436 cur_list.space_factor_field = lua_tointeger(L, i);
1437 } else {
1438 luaL_error(L, "unsupported value type");
1440 return 0;
1442 texstr = maketexlstring(st, k);
1443 if (is_primitive(texstr)) {
1444 if (i == 3 && (lua_type(L,1) == LUA_TSTRING)) {
1445 const char *s = lua_tostring(L, 1);
1446 if (lua_key_eq(s,global))
1447 isglobal = 1;
1449 cur_cs1 = string_lookup(st, k);
1450 flush_str(texstr);
1451 cur_cmd1 = eq_type(cur_cs1);
1452 if (is_int_assign(cur_cmd1)) {
1453 if (lua_type(L, i) == LUA_TNUMBER) {
1454 int luai = lua_tointeger(L, i);
1455 assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), luai);
1456 } else {
1457 luaL_error(L, "unsupported value type");
1459 } else if (is_dim_assign(cur_cmd1)) {
1460 if (lua_type(L, i) == LUA_TNUMBER) {
1461 j = lua_tointeger(L, i);
1462 } else if (lua_type(L, i) == LUA_TSTRING) {
1463 j = dimen_to_number(L, lua_tostring(L, i));
1464 } else {
1465 luaL_error(L, "unsupported value type");
1467 assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), j);
1468 } else if (is_glue_assign(cur_cmd1)) {
1469 halfword *j1 = check_isnode(L, i); /* the value */
1471 int a = isglobal;
1472 define(equiv(cur_cs1), assign_glue_cmd, *j1);
1474 } else if (is_toks_assign(cur_cmd1)) {
1475 if (lua_type(L,i) == LUA_TSTRING) {
1476 j = tokenlist_from_lua(L); /* uses stack -1 */
1477 assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), j);
1479 } else {
1480 luaL_error(L, "unsupported value type");
1483 } else if (lua_istable(L, (i - 2))) {
1485 people may want to add keys that are also primitives |tex.wd| for example)
1486 so creating an error is not right here
1488 lua_rawset(L, (i - 2));
1490 } else if (lua_istable(L, (i - 2))) {
1491 lua_rawset(L, (i - 2));
1493 } else if (lua_istable(L, (i - 2))) {
1494 lua_rawset(L, (i - 2));
1496 return 0;
1499 /* todo: some will to the pdf namespace .. ignore > 31 */
1501 static int do_convert(lua_State * L, int cur_code)
1503 int texstr;
1504 int i = -1;
1505 char *str = NULL;
1506 switch (cur_code) {
1507 /* ignored (yet) */
1509 case insert_ht_code: /* arg <register int> */
1510 case lua_code: /* arg complex */
1511 case lua_escape_string_code: /* arg token list */
1512 case left_margin_kern_code: /* arg box */
1513 case right_margin_kern_code: /* arg box */
1514 case string_code: /* arg token */
1515 case cs_string_code: /* arg token */
1516 case meaning_code: /* arg token */
1517 break;
1519 /* the next fall through, and come from 'official' indices! */
1521 case font_name_code: /* arg fontid */
1522 case font_identifier_code: /* arg fontid */
1523 case uniform_deviate_code: /* arg int */
1524 case number_code: /* arg int */
1525 case roman_numeral_code: /* arg int */
1527 if (lua_gettop(L) < 1) {
1528 /* error */
1530 i = lua_tointeger(L, 1);
1532 /* these fall through! */
1534 default:
1535 /* no backend here */
1536 if (cur_code < 32) {
1537 texstr = the_convert_string(cur_code, i);
1538 if (texstr) {
1539 str = makecstring(texstr);
1540 flush_str(texstr);
1544 /* end */
1545 if (str) {
1546 lua_pushstring(L, str);
1547 free(str);
1548 } else {
1549 lua_pushnil(L);
1551 return 1;
1554 static int do_scan_internal(lua_State * L, int cur_cmd1, int cur_code)
1556 int texstr;
1557 char *str = NULL;
1558 int save_cur_val, save_cur_val_level;
1559 save_cur_val = cur_val;
1560 save_cur_val_level = cur_val_level;
1561 scan_something_simple(cur_cmd1, cur_code);
1562 switch (cur_val_level) {
1563 case int_val_level:
1564 case dimen_val_level:
1565 case attr_val_level:
1566 lua_pushinteger(L, cur_val);
1567 break;
1568 case glue_val_level:
1569 case mu_val_level:
1570 lua_nodelib_push_fast(L, copy_node(cur_val));
1571 break;
1572 default:
1573 texstr = the_scanned_result();
1574 str = makecstring(texstr);
1575 if (str) {
1576 lua_pushstring(L, str);
1577 free(str);
1578 } else {
1579 lua_pushnil(L);
1581 flush_str(texstr);
1582 break;
1584 cur_val = save_cur_val;
1585 cur_val_level = save_cur_val_level;
1586 return 1;
1589 static int do_lastitem(lua_State * L, int cur_code)
1591 int retval = 1;
1592 switch (cur_code) {
1593 /* the next two do not actually exist */
1594 case lastattr_code:
1595 case attrexpr_code:
1596 lua_pushnil(L);
1597 break;
1598 /* the expressions do something complicated with arguments, yuck */
1599 case numexpr_code:
1600 case dimexpr_code:
1601 case glueexpr_code:
1602 case muexpr_code:
1603 lua_pushnil(L);
1604 break;
1605 /* these read a glue or muglue, todo */
1606 case mu_to_glue_code:
1607 case glue_to_mu_code:
1608 case glue_stretch_order_code:
1609 case glue_shrink_order_code:
1610 case glue_stretch_code:
1611 case glue_shrink_code:
1612 lua_pushnil(L);
1613 break;
1614 /* these read a fontid and a char, todo */
1615 case font_char_wd_code:
1616 case font_char_ht_code:
1617 case font_char_dp_code:
1618 case font_char_ic_code:
1619 lua_pushnil(L);
1620 break;
1621 /* these read an integer, todo */
1622 case par_shape_length_code:
1623 case par_shape_indent_code:
1624 case par_shape_dimen_code:
1625 lua_pushnil(L);
1626 break;
1627 case lastpenalty_code:
1628 case lastkern_code:
1629 case lastskip_code:
1630 case last_node_type_code:
1631 case input_line_no_code:
1632 case badness_code:
1633 case last_saved_box_resource_index_code:
1634 case last_saved_image_resource_index_code:
1635 case last_saved_image_resource_pages_code:
1636 case last_x_pos_code:
1637 case last_y_pos_code:
1638 case random_seed_code:
1639 case luatex_version_code:
1640 case eTeX_minor_version_code:
1641 case eTeX_version_code:
1642 case current_group_level_code:
1643 case current_group_type_code:
1644 case current_if_level_code:
1645 case current_if_type_code:
1646 case current_if_branch_code:
1647 retval = do_scan_internal(L, last_item_cmd, cur_code);
1648 break;
1649 default:
1650 lua_pushnil(L);
1651 break;
1653 return retval;
1656 static int tex_setmathparm(lua_State * L)
1658 int i, j;
1659 int k;
1660 int l = cur_level;
1661 void *p;
1662 int n = lua_gettop(L);
1663 if ((n == 3) || (n == 4)) {
1664 if (n == 4 && (lua_type(L,1) == LUA_TSTRING)) {
1665 const char *s = lua_tostring(L, 1);
1666 if (lua_key_eq(s,global))
1667 l = 1;
1669 i = luaL_checkoption(L, (n - 2), NULL, math_param_names);
1670 j = luaL_checkoption(L, (n - 1), NULL, math_style_names);
1671 if (i<0 && i>=math_param_last) {
1672 /* invalid spec, just ignore it */
1673 } else if (i>=math_param_first_mu_glue) {
1674 p = lua_touserdata(L, n);
1675 k = *((halfword *)p);
1676 def_math_param(i, j, (scaled) k, l);
1677 } else if (lua_type(L, n) == LUA_TNUMBER) {
1678 k = lua_tointeger(L, n);
1679 def_math_param(i, j, (scaled) k, l);
1680 } else {
1681 luaL_error(L, "argument must be a number");
1684 return 0;
1687 static int tex_getmathparm(lua_State * L)
1689 if ((lua_gettop(L) == 2)) {
1690 int i = luaL_checkoption(L, 1, NULL, math_param_names);
1691 int j = luaL_checkoption(L, 2, NULL, math_style_names);
1692 scaled k = get_math_param(i, j);
1693 if (i<0 && i>=math_param_last) {
1694 lua_pushnil(L);
1695 } else if (i>=math_param_first_mu_glue) {
1696 if (k <= thick_mu_skip_code) {
1697 k = glue_par(k);
1699 lua_nodelib_push_fast(L, k);
1700 } else {
1701 lua_pushinteger(L, k);
1704 return 1;
1707 static int getfontname(lua_State * L)
1709 return do_convert(L, font_name_code);
1712 static int getfontidentifier(lua_State * L)
1714 return do_convert(L, font_identifier_code);
1717 static int getuniformdeviate(lua_State * L)
1719 return do_convert(L, uniform_deviate_code);
1722 static int getnumber(lua_State * L)
1724 return do_convert(L, number_code);
1727 static int getromannumeral(lua_State * L)
1729 return do_convert(L, roman_numeral_code);
1732 static int get_parshape(lua_State * L)
1734 halfword par_shape_ptr = equiv(par_shape_loc);
1735 if (par_shape_ptr != 0) {
1736 int m = 1;
1737 int n = vinfo(par_shape_ptr + 1);
1738 lua_createtable(L, n, 0);
1739 while (m <= n) {
1740 lua_createtable(L, 2, 0);
1741 lua_pushinteger(L, vlink((par_shape_ptr) + (2 * (m - 1)) + 2));
1742 lua_rawseti(L, -2, 1);
1743 lua_pushinteger(L, vlink((par_shape_ptr) + (2 * (m - 1)) + 3));
1744 lua_rawseti(L, -2, 2);
1745 lua_rawseti(L, -2, m);
1746 m++;
1748 } else {
1749 lua_pushnil(L);
1751 return 1;
1754 static int gettex(lua_State * L)
1756 int cur_cs1 = -1;
1757 int retval = 1; /* default is to return nil */
1758 int t = lua_gettop(L);
1759 if (lua_type(L,t) == LUA_TSTRING) { /* 1 == 'tex', 2 == 'boxmaxdepth', or 1 == 'boxmaxdepth' */
1760 int texstr;
1761 size_t k;
1762 const char *st = lua_tolstring(L, t, &k);
1763 if (lua_key_eq(st,prevdepth)) {
1764 lua_pushinteger(L, cur_list.prev_depth_field);
1765 return 1;
1766 } else if (lua_key_eq(st,prevgraf)) {
1767 lua_pushinteger(L, cur_list.pg_field);
1768 return 1;
1769 } else if (lua_key_eq(st,spacefactor)) {
1770 lua_pushinteger(L, cur_list.space_factor_field);
1771 return 1;
1773 texstr = maketexlstring(st, k);
1774 cur_cs1 = prim_lookup(texstr); /* not found == relax == 0 */
1775 flush_str(texstr);
1777 if (cur_cs1 > 0) {
1778 int cur_cmd1 = get_prim_eq_type(cur_cs1);
1779 int cur_code = get_prim_equiv(cur_cs1);
1780 switch (cur_cmd1) {
1781 case last_item_cmd:
1782 retval = do_lastitem(L, cur_code);
1783 break;
1784 case convert_cmd:
1785 retval = do_convert(L, cur_code);
1786 break;
1787 case assign_toks_cmd:
1788 case assign_int_cmd:
1789 case assign_attr_cmd:
1790 case assign_dir_cmd:
1791 case assign_dimen_cmd:
1792 case assign_glue_cmd:
1793 case assign_mu_glue_cmd:
1794 case set_aux_cmd:
1795 case set_prev_graf_cmd:
1796 case set_page_int_cmd:
1797 case set_page_dimen_cmd:
1798 case char_given_cmd:
1799 case math_given_cmd:
1800 retval = do_scan_internal(L, cur_cmd1, cur_code);
1801 break;
1802 case set_tex_shape_cmd:
1803 retval = get_parshape(L);
1804 break;
1805 default:
1806 lua_pushnil(L);
1807 break;
1809 } else if (t == 2) {
1810 lua_rawget(L, 1);
1812 return retval;
1815 static int getlist(lua_State * L)
1817 const char *str;
1818 if (lua_type(L,2) == LUA_TSTRING) {
1819 str = lua_tostring(L, 2);
1820 if (lua_key_eq(str,page_ins_head)) {
1821 if (vlink(page_ins_head) == page_ins_head)
1822 lua_pushinteger(L, null);
1823 else
1824 lua_pushinteger(L, vlink(page_ins_head));
1825 lua_nodelib_push(L);
1826 } else if (lua_key_eq(str,contrib_head)) {
1827 alink(vlink(contrib_head)) = null ;
1828 lua_pushinteger(L, vlink(contrib_head));
1829 lua_nodelib_push(L);
1830 } else if (lua_key_eq(str,page_head)) {
1831 alink(vlink(page_head)) = null ;/*hh-ls */
1832 lua_pushinteger(L, vlink(page_head));
1833 lua_nodelib_push(L);
1834 } else if (lua_key_eq(str,temp_head)) {
1835 alink(vlink(temp_head)) = null ;/*hh-ls */
1836 lua_pushinteger(L, vlink(temp_head));
1837 lua_nodelib_push(L);
1838 } else if (lua_key_eq(str,hold_head)) {
1839 alink(vlink(hold_head)) = null ;/*hh-ls */
1840 lua_pushinteger(L, vlink(hold_head));
1841 lua_nodelib_push(L);
1842 } else if (lua_key_eq(str,adjust_head)) {
1843 alink(vlink(adjust_head)) = null ;/*hh-ls */
1844 lua_pushinteger(L, vlink(adjust_head));
1845 lua_nodelib_push(L);
1846 } else if (lua_key_eq(str,best_page_break)) {
1847 lua_pushinteger(L, best_page_break);
1848 lua_nodelib_push(L);
1849 } else if (lua_key_eq(str,least_page_cost)) {
1850 lua_pushinteger(L, least_page_cost);
1851 } else if (lua_key_eq(str,best_size)) {
1852 lua_pushinteger(L, best_size);
1853 } else if (lua_key_eq(str,pre_adjust_head)) {
1854 alink(vlink(pre_adjust_head)) = null ;/*hh-ls */
1855 lua_pushinteger(L, vlink(pre_adjust_head));
1856 lua_nodelib_push(L);
1857 } else if (lua_key_eq(str,align_head)) {
1858 alink(vlink(align_head)) = null ;/*hh-ls */
1859 lua_pushinteger(L, vlink(align_head));
1860 lua_nodelib_push(L);
1861 } else {
1862 lua_pushnil(L);
1864 } else {
1865 lua_pushnil(L);
1867 return 1;
1870 static int setlist(lua_State * L)
1872 if (lua_type(L,2) == LUA_TSTRING) {
1873 const char *str = lua_tostring(L, 2);
1874 if (lua_key_eq(str,best_size)) {
1875 best_size = (int) lua_tointeger(L, 3);
1876 } else if (lua_key_eq(str,least_page_cost)) {
1877 least_page_cost = (int) lua_tointeger(L, 3);
1878 } else {
1879 halfword *n_ptr;
1880 halfword n = 0;
1881 if (!lua_isnil(L, 3)) {
1882 n_ptr = check_isnode(L, 3);
1883 n = *n_ptr;
1885 if (lua_key_eq(str,page_ins_head)) {
1886 if (n == 0) {
1887 vlink(page_ins_head) = page_ins_head;
1888 } else {
1889 halfword m;
1890 vlink(page_ins_head) = n;
1891 m = tail_of_list(n);
1892 vlink(m) = page_ins_head;
1894 } else if (lua_key_eq(str,contrib_head)) {
1895 vlink(contrib_head) = n;
1896 if (n == 0) {
1897 contrib_tail = contrib_head;
1899 } else if (lua_key_eq(str,best_page_break)) {
1900 best_page_break = n;
1901 } else if (lua_key_eq(str,page_head)) {
1902 vlink(page_head) = n;
1903 page_tail = (n == 0 ? page_head : tail_of_list(n));
1904 } else if (lua_key_eq(str,temp_head)) {
1905 vlink(temp_head) = n;
1906 } else if (lua_key_eq(str,hold_head)) {
1907 vlink(hold_head) = n;
1908 } else if (lua_key_eq(str,adjust_head)) {
1909 vlink(adjust_head) = n;
1910 adjust_tail = (n == 0 ? adjust_head : tail_of_list(n));
1911 } else if (lua_key_eq(str,pre_adjust_head)) {
1912 vlink(pre_adjust_head) = n;
1913 pre_adjust_tail = (n == 0 ? pre_adjust_head : tail_of_list(n));
1914 } else if (lua_key_eq(str,align_head)) {
1915 vlink(align_head) = n;
1919 return 0;
1922 #define NEST_METATABLE "luatex.nest"
1924 static int lua_nest_getfield(lua_State * L)
1926 list_state_record *r, **rv = lua_touserdata(L, -2);
1927 const char *field = lua_tostring(L, -1);
1928 r = *rv;
1929 if (lua_key_eq(field,mode)) {
1930 lua_pushinteger(L, r->mode_field);
1931 } else if (lua_key_eq(field,head)) {
1932 lua_nodelib_push_fast(L, r->head_field);
1933 } else if (lua_key_eq(field,tail)) {
1934 lua_nodelib_push_fast(L, r->tail_field);
1935 } else if (lua_key_eq(field,delimptr)) {
1936 lua_pushinteger(L, r->eTeX_aux_field);
1937 lua_nodelib_push(L);
1938 } else if (lua_key_eq(field,prevgraf)) {
1939 lua_pushinteger(L, r->pg_field);
1940 } else if (lua_key_eq(field,modeline)) {
1941 lua_pushinteger(L, r->ml_field);
1942 } else if (lua_key_eq(field,prevdepth)) {
1943 lua_pushinteger(L, r->prev_depth_field);
1944 } else if (lua_key_eq(field,spacefactor)) {
1945 lua_pushinteger(L, r->space_factor_field);
1946 } else if (lua_key_eq(field,noad)) {
1947 lua_pushinteger(L, r->incompleat_noad_field);
1948 lua_nodelib_push(L);
1949 } else if (lua_key_eq(field,dirs)) {
1950 lua_pushinteger(L, r->dirs_field);
1951 lua_nodelib_push(L);
1952 } else if (lua_key_eq(field,mathdir)) {
1953 lua_pushboolean(L, r->math_field);
1954 } else if (lua_key_eq(field,mathstyle)) {
1955 lua_pushinteger(L, r->math_style_field);
1956 } else {
1957 lua_pushnil(L);
1959 return 1;
1962 static int lua_nest_setfield(lua_State * L)
1964 halfword *n;
1965 int i;
1966 list_state_record *r, **rv = lua_touserdata(L, -3);
1967 const char *field = lua_tostring(L, -2);
1968 r = *rv;
1969 if (lua_key_eq(field,mode)) {
1970 i = lua_tointeger(L, -1);
1971 r->mode_field = i;
1972 } else if (lua_key_eq(field,head)) {
1973 n = check_isnode(L, -1);
1974 r->head_field = *n;
1975 } else if (lua_key_eq(field,tail)) {
1976 n = check_isnode(L, -1);
1977 r->tail_field = *n;
1978 } else if (lua_key_eq(field,delimptr)) {
1979 n = check_isnode(L, -1);
1980 r->eTeX_aux_field = *n;
1981 } else if (lua_key_eq(field,prevgraf)) {
1982 i = lua_tointeger(L, -1);
1983 r->pg_field = i;
1984 } else if (lua_key_eq(field,modeline)) {
1985 i = lua_tointeger(L, -1);
1986 r->ml_field = i;
1987 } else if (lua_key_eq(field,prevdepth)) {
1988 i = lua_tointeger(L, -1);
1989 r->prev_depth_field = i;
1990 } else if (lua_key_eq(field,spacefactor)) {
1991 i = lua_tointeger(L, -1);
1992 r->space_factor_field = i;
1993 } else if (lua_key_eq(field,noad)) {
1994 n = check_isnode(L, -1);
1995 r->incompleat_noad_field = *n;
1996 } else if (lua_key_eq(field,dirs)) {
1997 n = check_isnode(L, -1);
1998 r->dirs_field = *n;
1999 } else if (lua_key_eq(field,mathdir)) {
2000 r->math_field = lua_toboolean(L, -1);
2001 } else if (lua_key_eq(field,mathstyle)) {
2002 i = lua_tointeger(L, -1);
2003 r->math_style_field = i;
2005 return 0;
2008 static const struct luaL_Reg nest_m[] = {
2009 {"__index", lua_nest_getfield},
2010 {"__newindex", lua_nest_setfield},
2011 {NULL, NULL} /* sentinel */
2014 static void init_nest_lib(lua_State * L)
2016 luaL_newmetatable(L, NEST_METATABLE);
2017 luaL_register(L, NULL, nest_m);
2018 lua_pop(L, 1);
2021 static int getnest(lua_State * L)
2023 list_state_record **nestitem;
2024 int t = lua_type(L, 2);
2025 if (t == LUA_TNUMBER) {
2026 int ptr = lua_tointeger(L, 2);
2027 if (ptr >= 0 && ptr <= nest_ptr) {
2028 nestitem = lua_newuserdata(L, sizeof(list_state_record *));
2029 *nestitem = &nest[ptr];
2030 luaL_getmetatable(L, NEST_METATABLE);
2031 lua_setmetatable(L, -2);
2032 } else {
2033 lua_pushnil(L);
2035 } else if (t == LUA_TSTRING) {
2036 const char *s = lua_tostring(L, 2);
2037 if (lua_key_eq(s,ptr)) {
2038 lua_pushinteger(L, nest_ptr);
2039 } else {
2040 lua_pushnil(L);
2042 } else {
2043 lua_pushnil(L);
2045 return 1;
2048 static int setnest(lua_State * L)
2050 luaL_error(L, "You can't modify the semantic nest array directly");
2051 return 2;
2054 static int do_integer_error(double m)
2056 const char *help[] = {
2057 "I can only go up to 2147483647='17777777777=" "7FFFFFFF,",
2058 "so I'm using that number instead of yours.",
2059 NULL
2061 tex_error("Number too big", help);
2062 return (m > 0.0 ? infinity : -infinity);
2065 static int tex_roundnumber(lua_State * L)
2067 double m = (double) lua_tonumber(L, 1) + 0.5; /* integer or float */
2068 if (abs(m) > (double) infinity)
2069 lua_pushinteger(L, do_integer_error(m));
2070 else
2071 lua_pushinteger(L, floor(m));
2072 return 1;
2075 static int tex_scaletable(lua_State * L)
2077 double delta = luaL_checknumber(L, 2);
2078 if (lua_istable(L, 1)) {
2079 lua_newtable(L); /* the new table is at index 3 */
2080 lua_pushnil(L);
2081 while (lua_next(L, 1) != 0) { /* numeric value */
2082 lua_pushvalue(L, -2);
2083 lua_insert(L, -2);
2084 if (lua_type(L,-2) == LUA_TNUMBER) {
2085 double m = (double) lua_tonumber(L, -1) * delta + 0.5; /* integer or float */
2086 lua_pop(L, 1);
2087 if (abs(m) > (double) infinity)
2088 lua_pushinteger(L, do_integer_error(m));
2089 else
2090 lua_pushinteger(L, floor(m));
2092 lua_rawset(L, 3);
2094 } else if (lua_type(L,1) == LUA_TNUMBER) {
2095 double m = (double) lua_tonumber(L, 1) * delta + 0.5; /* integer or float */
2096 if (abs(m) > (double) infinity)
2097 lua_pushinteger(L, do_integer_error(m));
2098 else
2099 lua_pushinteger(L, floor(m));
2100 } else {
2101 lua_pushnil(L);
2103 return 1;
2106 #define hash_text(A) hash[(A)].rh
2108 static int tex_definefont(lua_State * L)
2110 const char *csname;
2111 int f, u;
2112 str_number t;
2113 size_t l;
2114 int i = 1;
2115 int a = 0;
2116 if (!no_new_control_sequence) {
2117 const char *help[] = { "You can't create a new font inside a \\csname\\endcsname pair", NULL };
2118 tex_error("Definition active", help);
2120 if ((lua_gettop(L) == 3) && lua_isboolean(L, 1)) {
2121 a = lua_toboolean(L, 1);
2122 i = 2;
2124 csname = luaL_checklstring(L, i, &l);
2125 f = luaL_checkinteger(L, (i + 1));
2126 t = maketexlstring(csname, l);
2127 no_new_control_sequence = 0;
2128 u = string_lookup(csname, l);
2129 no_new_control_sequence = 1;
2130 if (a)
2131 geq_define(u, set_font_cmd, f);
2132 else
2133 eq_define(u, set_font_cmd, f);
2134 eqtb[font_id_base + f] = eqtb[u];
2135 hash_text(font_id_base + f) = t;
2136 return 0;
2139 static int tex_hashpairs(lua_State * L)
2141 int cmd, chr;
2142 str_number s = 0;
2143 int cs = 1;
2144 lua_newtable(L);
2145 while (cs < hash_size) {
2146 s = hash_text(cs);
2147 if (s > 0) {
2148 char *ss = makecstring(s);
2149 lua_pushstring(L, ss);
2150 free(ss);
2151 cmd = eq_type(cs);
2152 chr = equiv(cs);
2153 make_token_table(L, cmd, chr, cs);
2154 lua_rawset(L, -3);
2156 cs++;
2158 return 1;
2161 static int tex_primitives(lua_State * L)
2163 int cmd, chr;
2164 str_number s = 0;
2165 int cs = 0;
2166 lua_newtable(L);
2167 while (cs < prim_size) {
2168 s = get_prim_text(cs);
2169 if (s > 0) {
2170 char *ss = makecstring(s);
2171 lua_pushstring(L, ss);
2172 free(ss);
2173 cmd = get_prim_eq_type(cs);
2174 chr = get_prim_equiv(cs);
2175 make_token_table(L, cmd, chr, 0);
2176 lua_rawset(L, -3);
2178 cs++;
2180 return 1;
2183 static int tex_extraprimitives(lua_State * L)
2185 int n, i;
2186 int mask = 0;
2187 int cs = 0;
2188 n = lua_gettop(L);
2189 if (n == 0) {
2190 mask = etex_command + luatex_command;
2191 } else {
2192 for (i = 1; i <= n; i++) {
2193 if (lua_type(L,i) == LUA_TSTRING) {
2194 const char *s = lua_tostring(L, i);
2195 if (lua_key_eq(s,etex)) {
2196 mask |= etex_command;
2197 } else if (lua_key_eq(s,tex)) {
2198 mask |= tex_command;
2199 } else if (lua_key_eq(s,core)) {
2200 mask |= core_command;
2201 } else if (lua_key_eq(s,luatex)) {
2202 mask |= luatex_command;
2207 lua_newtable(L);
2208 i = 1;
2209 while (cs < prim_size) {
2210 str_number s = 0;
2211 s = get_prim_text(cs);
2212 if (s > 0) {
2213 if (get_prim_origin(cs) & mask) {
2214 char *ss = makecstring(s);
2215 lua_pushstring(L, ss);
2216 free(ss);
2217 lua_rawseti(L, -2, i++);
2220 cs++;
2222 return 1;
2225 static int tex_enableprimitives(lua_State * L)
2227 int n = lua_gettop(L);
2228 if (n != 2) {
2229 luaL_error(L, "wrong number of arguments");
2230 } else {
2231 size_t l;
2232 int i;
2233 const char *pre = luaL_checklstring(L, 1, &l);
2234 if (lua_istable(L, 2)) {
2235 int nncs = no_new_control_sequence;
2236 no_new_control_sequence = true;
2237 i = 1;
2238 while (1) {
2239 lua_rawgeti(L, 2, i);
2240 if (lua_type(L,3) == LUA_TSTRING) {
2241 const char *prim = lua_tostring(L, 3);
2242 str_number s = maketexstring(prim);
2243 halfword prim_val = prim_lookup(s);
2244 if (prim_val != undefined_primitive) {
2245 char *newprim;
2246 int val;
2247 size_t newl;
2248 halfword cur_cmd1 = get_prim_eq_type(prim_val);
2249 halfword cur_chr1 = get_prim_equiv(prim_val);
2250 if (strncmp(pre, prim, l) != 0) { /* not a prefix */
2251 newl = strlen(prim) + l;
2252 newprim = (char *) xmalloc((unsigned) (newl + 1));
2253 strcpy(newprim, pre);
2254 strcat(newprim + l, prim);
2255 } else {
2256 newl = strlen(prim);
2257 newprim = (char *) xmalloc((unsigned) (newl + 1));
2258 strcpy(newprim, prim);
2260 val = string_lookup(newprim, newl);
2261 if (val == undefined_control_sequence ||
2262 eq_type(val) == undefined_cs_cmd) {
2263 primitive_def(newprim, newl, (quarterword) cur_cmd1, cur_chr1);
2265 free(newprim);
2267 flush_str(s);
2268 } else {
2269 lua_pop(L, 1);
2270 break;
2272 lua_pop(L, 1);
2273 i++;
2275 lua_pop(L, 1); /* the table */
2276 no_new_control_sequence = nncs;
2277 } else {
2278 luaL_error(L, "Expected an array of names as second argument");
2281 return 0;
2284 #define get_int_par(A,B,C) do { \
2285 lua_pushstring(L,(A)); \
2286 lua_gettable(L,-2); \
2287 if (lua_type(L, -1) == LUA_TNUMBER) { \
2288 B = (int) lua_tointeger(L, -1); \
2289 } else { \
2290 B = (C); \
2292 lua_pop(L,1); \
2293 } while (0)
2296 #define get_intx_par(A,B,C,D,E) do { \
2297 lua_pushstring(L,(A)); \
2298 lua_gettable(L,-2); \
2299 if (lua_type(L, -1) == LUA_TNUMBER) { \
2300 B = (int) lua_tointeger(L, -1); \
2301 D = null; \
2302 } else if (lua_type(L, -1) == LUA_TTABLE){ \
2303 B = 0; \
2304 D = nodelib_topenalties(L, lua_gettop(L)); \
2305 } else { \
2306 B = (C); \
2307 D = (E); \
2309 lua_pop(L,1); \
2310 } while (0)
2312 #define get_dimen_par(A,B,C) do { \
2313 lua_pushstring(L,(A)); \
2314 lua_gettable(L,-2); \
2315 if (lua_type(L, -1) == LUA_TNUMBER) { \
2316 B = (int) lua_tointeger(L, -1); \
2317 } else { \
2318 B = (C); \
2320 lua_pop(L,1); \
2321 } while (0)
2323 #define get_glue_par(A,B,C) do { \
2324 lua_pushstring(L,(A)); \
2325 lua_gettable(L,-2); \
2326 if (lua_type(L, -1) != LUA_TNIL) { \
2327 B = *check_isnode(L, -1); \
2328 } else { \
2329 B = (C); \
2331 lua_pop(L,1); \
2332 } while (0)
2334 static halfword nodelib_toparshape(lua_State * L, int i)
2336 halfword p;
2337 int n = 0;
2338 int width, indent, j;
2339 /* find |n| */
2340 lua_pushnil(L);
2341 while (lua_next(L, i) != 0) {
2342 n++;
2343 lua_pop(L, 1);
2345 if (n == 0)
2346 return null;
2347 p = new_node(shape_node, 2 * (n + 1) + 1);
2348 vinfo(p + 1) = n;
2349 /* fill |p| */
2350 lua_pushnil(L);
2351 j = 0;
2352 while (lua_next(L, i) != 0) {
2353 /* don't give an error for non-tables, we may add special syntaxes at some point */
2354 j++;
2355 if (lua_type(L, i) == LUA_TTABLE) {
2356 lua_rawgeti(L, -1, 1); /* indent */
2357 if (lua_type(L, -1) == LUA_TNUMBER) {
2358 indent = lua_tointeger(L, -1);
2359 lua_pop(L, 1);
2360 lua_rawgeti(L, -1, 2); /* width */
2361 if (lua_type(L, -1) == LUA_TNUMBER) {
2362 width = lua_tointeger(L, -1);
2363 lua_pop(L, 1);
2364 varmem[p + 2 * j].cint = indent;
2365 varmem[p + 2 * j + 1].cint = width;
2369 lua_pop(L, 1);
2371 return p;
2374 /* penalties */
2376 static halfword nodelib_topenalties(lua_State * L, int i)
2378 halfword p;
2379 int n = 0;
2380 int j;
2381 /* find |n| */
2382 lua_pushnil(L);
2383 while (lua_next(L, i) != 0) {
2384 n++;
2385 lua_pop(L, 1);
2387 if (n == 0)
2388 return null;
2389 p = new_node(shape_node, 2 * ((n / 2) + 1) + 1 + 1);
2390 vinfo(p + 1) = (n / 2) + 1;
2391 varmem[p + 2].cint = n;
2392 lua_pushnil(L);
2393 j = 2;
2394 while (lua_next(L, i) != 0) {
2395 j++;
2396 if (lua_type(L, -1) == LUA_TNUMBER) {
2397 int pen = lua_tointeger(L, -1);
2398 varmem[p+j].cint = pen;
2400 lua_pop(L, 1);
2402 if (!odd(n))
2403 varmem[p+j+1].cint = 0;
2404 return p;
2407 static int tex_run_linebreak(lua_State * L)
2410 halfword *j;
2411 halfword p;
2412 halfword final_par_glue;
2413 int paragraph_dir = 0;
2414 /* locally initialized parameters for line breaking */
2415 int pretolerance, tracingparagraphs, tolerance, looseness,
2416 adjustspacing, adjdemerits, protrudechars,
2417 linepenalty, lastlinefit, doublehyphendemerits, finalhyphendemerits,
2418 hangafter, interlinepenalty, widowpenalty, clubpenalty, brokenpenalty;
2419 halfword emergencystretch, hangindent, hsize, leftskip, rightskip,parshape;
2420 int fewest_demerits = 0, actual_looseness = 0;
2421 halfword clubpenalties, interlinepenalties, widowpenalties;
2422 int save_vlink_tmp_head;
2423 /* push a new nest level */
2424 push_nest();
2425 save_vlink_tmp_head = vlink(temp_head);
2427 j = check_isnode(L, 1); /* the value */
2428 vlink(temp_head) = *j;
2429 p = *j;
2430 if ((!is_char_node(vlink(*j))) && ((type(vlink(*j)) == local_par_node))) {
2431 paragraph_dir = local_par_dir(vlink(*j));
2434 while (vlink(p) != null)
2435 p = vlink(p);
2436 final_par_glue = p;
2438 /* initialize local parameters */
2440 if (lua_gettop(L) != 2 || lua_type(L, 2) != LUA_TTABLE) {
2441 lua_checkstack(L, 3);
2442 lua_newtable(L);
2444 lua_pushstring(L, "pardir");
2445 lua_gettable(L, -2);
2446 if (lua_type(L, -1) == LUA_TSTRING) {
2447 paragraph_dir = nodelib_getdir(L, -1, 1);
2449 lua_pop(L, 1);
2451 lua_pushstring(L, "parshape");
2452 lua_gettable(L, -2);
2453 if (lua_type(L, -1) == LUA_TTABLE) {
2454 parshape = nodelib_toparshape(L, lua_gettop(L));
2455 } else {
2456 parshape = equiv(par_shape_loc);
2458 lua_pop(L, 1);
2460 get_int_par("pretolerance",
2461 pretolerance, int_par(pretolerance_code));
2462 get_int_par("tracingparagraphs",
2463 tracingparagraphs, int_par(tracing_paragraphs_code));
2464 get_int_par("tolerance",
2465 tolerance, int_par(tolerance_code));
2466 get_int_par("looseness",
2467 looseness, int_par(looseness_code));
2468 get_int_par("adjustspacing",
2469 adjustspacing, int_par(adjust_spacing_code));
2470 get_int_par("adjdemerits",
2471 adjdemerits, int_par(adj_demerits_code));
2472 get_int_par("protrudechars",
2473 protrudechars, int_par(protrude_chars_code));
2474 get_int_par("linepenalty",
2475 linepenalty, int_par(line_penalty_code));
2476 get_int_par("lastlinefit",
2477 lastlinefit, int_par(last_line_fit_code));
2478 get_int_par("doublehyphendemerits",
2479 doublehyphendemerits, int_par(double_hyphen_demerits_code));
2480 get_int_par("finalhyphendemerits",
2481 finalhyphendemerits, int_par(final_hyphen_demerits_code));
2482 get_int_par("hangafter",
2483 hangafter, int_par(hang_after_code));
2484 get_intx_par("interlinepenalty",
2485 interlinepenalty,int_par(inter_line_penalty_code), interlinepenalties, equiv(inter_line_penalties_loc));
2486 get_intx_par("clubpenalty",
2487 clubpenalty, int_par(club_penalty_code), clubpenalties, equiv(club_penalties_loc));
2488 get_intx_par("widowpenalty",
2489 widowpenalty, int_par(widow_penalty_code), widowpenalties, equiv(widow_penalties_loc));
2490 get_int_par("brokenpenalty",
2491 brokenpenalty, int_par(broken_penalty_code));
2492 get_dimen_par("emergencystretch",
2493 emergencystretch, dimen_par(emergency_stretch_code));
2494 get_dimen_par("hangindent",
2495 hangindent, dimen_par(hang_indent_code));
2496 get_dimen_par("hsize",
2497 hsize, dimen_par(hsize_code));
2498 get_glue_par("leftskip",
2499 leftskip, glue_par(left_skip_code));
2500 get_glue_par("rightskip",
2501 rightskip, glue_par(right_skip_code));
2503 ext_do_line_break(paragraph_dir,
2504 pretolerance, tracingparagraphs, tolerance,
2505 emergencystretch, looseness,
2506 adjustspacing,
2507 parshape,
2508 adjdemerits, protrudechars,
2509 linepenalty, lastlinefit,
2510 doublehyphendemerits, finalhyphendemerits,
2511 hangindent, hsize, hangafter, leftskip, rightskip,
2512 interlinepenalties,
2513 interlinepenalty, clubpenalty,
2514 clubpenalties,
2515 widowpenalties,
2516 widowpenalty, brokenpenalty,
2517 final_par_glue);
2519 /* return the generated list, and its prevdepth */
2520 get_linebreak_info (&fewest_demerits, &actual_looseness) ;
2521 lua_nodelib_push_fast(L, vlink(cur_list.head_field));
2522 lua_newtable(L);
2523 lua_pushstring(L, "demerits");
2524 lua_pushinteger(L, fewest_demerits);
2525 lua_settable(L, -3);
2526 lua_pushstring(L, "looseness");
2527 lua_pushinteger(L, actual_looseness);
2528 lua_settable(L, -3);
2529 lua_pushstring(L, "prevdepth");
2530 lua_pushinteger(L, cur_list.prev_depth_field);
2531 lua_settable(L, -3);
2532 lua_pushstring(L, "prevgraf");
2533 lua_pushinteger(L, cur_list.pg_field);
2534 lua_settable(L, -3);
2536 /* restore nest stack */
2537 vlink(temp_head) = save_vlink_tmp_head;
2538 pop_nest();
2539 if (parshape != equiv(par_shape_loc))
2540 flush_node(parshape);
2541 return 2;
2544 static int tex_shipout(lua_State * L)
2546 int boxnum = get_box_id(L, 1, true);
2547 ship_out(static_pdf, box(boxnum), SHIPPING_PAGE);
2548 box(boxnum) = null;
2549 return 0;
2552 static int tex_badness(lua_State * L)
2554 scaled t = lua_tointeger(L,1);
2555 scaled s = lua_tointeger(L,2);
2556 lua_pushinteger(L, badness(t,s));
2557 return 1;
2560 static int tex_run_boot(lua_State * L)
2562 int n = lua_gettop(L);
2563 const char *format = NULL;
2564 if (n >= 1) {
2565 ini_version = 0;
2566 format = luaL_checkstring(L, 1);
2567 } else {
2568 ini_version = 1;
2570 if (main_initialize()) { /* > 0 = failure */
2571 lua_pushboolean(L, 0); /* false */
2572 return 1;
2574 if (format) {
2575 if (!zopen_w_input(&fmt_file, format, DUMP_FORMAT, FOPEN_RBIN_MODE)) {
2576 lua_pushboolean(L, 0); /* false */
2577 return 1;
2579 if (!load_fmt_file(format)) {
2580 zwclose(fmt_file);
2581 lua_pushboolean(L, 0); /* false */
2582 return 1;
2584 zwclose(fmt_file);
2586 fix_date_and_time();
2587 random_seed = (microseconds * 1000) + (epochseconds % 1000000);
2588 init_randoms(random_seed);
2589 initialize_math();
2590 fixup_selector(log_opened_global);
2591 check_texconfig_init();
2592 text_dir_ptr = new_dir(0);
2593 history = spotless; /* ready to go! */
2594 /* Initialize synctex primitive */
2595 synctexinitcommand();
2596 /* tex is ready to go, now */
2597 unhide_lua_table(Luas, "tex", tex_table_id);
2598 unhide_lua_table(Luas, "pdf", pdf_table_id);
2599 unhide_lua_table(Luas, "token", token_table_id);
2600 unhide_lua_table(Luas, "oldtoken", oldtoken_table_id);
2601 unhide_lua_table(Luas, "node", node_table_id);
2603 lua_pushboolean(L, 1); /* true */
2604 return 1;
2607 /* tex random generators */
2609 static int tex_init_rand(lua_State * L)
2611 int sp;
2612 if (lua_type(L, 1) != LUA_TNUMBER) {
2613 luaL_error(L, "argument must be a number");
2614 return 0;
2616 sp = lua_tointeger(L, 1);
2617 init_randoms(sp);
2618 return 0;
2621 static int tex_unif_rand(lua_State * L)
2623 int sp;
2624 if (lua_type(L, 1) != LUA_TNUMBER) {
2625 luaL_error(L, "argument must be a number");
2626 return 0;
2628 sp = lua_tointeger(L, 1);
2629 lua_pushinteger(L, unif_rand(sp));
2630 return 1;
2633 static int tex_norm_rand(lua_State * L)
2635 lua_pushinteger(L, norm_rand());
2636 return 1;
2639 /* Same as lua but with tex rng */
2641 static int lua_math_random (lua_State *L)
2643 lua_Number rand_max = 0x7fffffff ;
2644 lua_Number r = unif_rand(rand_max) ;
2645 r = (r>=0 ? 0+r : 0-r) ;
2646 r = r / rand_max;
2647 switch (lua_gettop(L)) { /* check number of arguments */
2648 case 0: { /* no arguments */
2649 lua_pushnumber(L, r); /* float: [0, 1] */
2650 break;
2652 case 1: { /* only upper limit */
2653 lua_Number u = luaL_checknumber(L, 1);
2654 luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty");
2655 lua_pushnumber(L, floor(r*u) + (lua_Number)(1.0)); /* float: [1, u] */
2656 break;
2658 case 2: { /* lower and upper limits */
2659 lua_Number l = luaL_checknumber(L, 1);
2660 lua_Number u = luaL_checknumber(L, 2);
2661 luaL_argcheck(L, l <= u, 2, "interval is empty");
2662 lua_pushnumber(L, floor(r*(u-l+1)) + l); /* float: [l, u] */
2663 break;
2665 default:
2666 return luaL_error(L, "wrong number of arguments");
2668 return 1;
2671 static int tex_run_main(lua_State * L)
2673 (void) L;
2674 main_control();
2675 return 0;
2678 static int tex_run_end(lua_State * L)
2680 (void) L;
2681 final_cleanup(); /* prepare for death */
2682 close_files_and_terminate();
2683 do_final_end();
2684 return 0;
2687 static int tex_show_context(lua_State * L)
2689 (void) L;
2690 show_context();
2691 return 0;
2694 static int tex_save_box_resource(lua_State * L)
2696 halfword boxdata;
2697 int index = null;
2698 int attributes = null;
2699 int resources = null;
2700 boolean immediate = false;
2701 /* box attributes resources */
2702 halfword boxnumber = lua_tointeger(L,1);
2703 if (lua_type(L,2) == LUA_TSTRING) {
2704 lua_pushvalue(L, 2);
2705 attributes = luaL_ref(L, LUA_REGISTRYINDEX);
2707 if (lua_type(L,3) == LUA_TSTRING) {
2708 lua_pushvalue(L, 3);
2709 resources = luaL_ref(L, LUA_REGISTRYINDEX);
2711 if (lua_type(L,4) == LUA_TBOOLEAN) {
2712 immediate = lua_toboolean(L, 4);
2714 /* more or less same as scanner variant */
2715 boxdata = box(boxnumber);
2716 if (boxdata == null)
2717 normal_error("pdf backend", "xforms cannot be used with a void box");
2718 static_pdf->xform_count++;
2719 index = pdf_create_obj(static_pdf, obj_type_xform, static_pdf->xform_count);
2720 set_obj_data_ptr(static_pdf, index, pdf_get_mem(static_pdf, pdfmem_xform_size));
2721 set_obj_xform_attr(static_pdf, index, null);
2722 set_obj_xform_attr_str(static_pdf, index, attributes);
2723 set_obj_xform_resources(static_pdf, index, null);
2724 set_obj_xform_resources_str(static_pdf, index, resources);
2725 set_obj_xform_box(static_pdf, index, (int) boxdata);
2726 set_obj_xform_width(static_pdf, index, width(boxdata));
2727 set_obj_xform_height(static_pdf, index, height(boxdata));
2728 set_obj_xform_depth(static_pdf, index, depth(boxdata));
2729 box(boxnumber) = null;
2730 last_saved_box_index = index;
2731 lua_pushinteger(L, index);
2732 if (immediate) {
2733 pdf_cur_form = last_saved_box_index;
2734 ship_out(static_pdf, obj_xform_box(static_pdf, last_saved_box_index), SHIPPING_FORM);
2736 return 1;
2739 static int tex_use_box_resource(lua_State * L)
2741 halfword rule;
2742 int index = 0;
2743 scaled_whd alt, nat, dim;
2744 if (lua_type(L,1) != LUA_TNUMBER) {
2745 lua_pushnil(L);
2746 lua_pushnil(L);
2747 lua_pushnil(L);
2748 lua_pushnil(L);
2749 } else {
2750 index = lua_tointeger(L,1);
2751 alt.wd = null_flag;
2752 alt.ht = null_flag;
2753 alt.dp = null_flag;
2754 if (lua_type(L,2) == LUA_TNUMBER) {
2755 alt.wd = (scaled) lua_tointeger(L,2);
2757 if (lua_type(L,3) == LUA_TNUMBER) {
2758 alt.ht = (scaled) lua_tointeger(L,3);
2760 if (lua_type(L,4) == LUA_TNUMBER) {
2761 alt.dp = (scaled) lua_tointeger(L,4);
2763 /* sort of the same as backend */
2764 check_obj_type(static_pdf, obj_type_xform, index);
2765 nat.wd = obj_xform_width(static_pdf, index);
2766 nat.ht = obj_xform_height(static_pdf, index);
2767 nat.dp = obj_xform_depth(static_pdf, index);
2768 if (alt.wd != null_flag || alt.ht != null_flag || alt.dp != null_flag) {
2769 dim = tex_scale(nat, alt);
2770 } else {
2771 dim = nat;
2773 rule = new_rule(box_rule);
2774 rule_index(rule) = index;
2775 width(rule) = dim.wd;
2776 height(rule) = dim.ht;
2777 depth(rule) = dim.dp;
2778 nodelist_to_lua(L, rule);
2779 lua_pushinteger(L, (int) dim.wd);
2780 lua_pushinteger(L, (int) dim.ht);
2781 lua_pushinteger(L, (int) dim.dp);
2783 return 4;
2786 static int tex_get_box_resource_dimensions(lua_State * L)
2788 int index = 0;
2789 if (lua_type(L,1) != LUA_TNUMBER) {
2790 lua_pushnil(L);
2791 lua_pushnil(L);
2792 lua_pushnil(L);
2793 } else {
2794 index = lua_tointeger(L,1);
2795 check_obj_type(static_pdf, obj_type_xform, index);
2796 lua_pushinteger(L, (int) obj_xform_width(static_pdf, index));
2797 lua_pushinteger(L, (int) obj_xform_height(static_pdf, index));
2798 lua_pushinteger(L, (int) obj_xform_depth(static_pdf, index));
2800 return 3;
2803 static int tex_build_page(lua_State * L)
2805 build_page();
2806 return 0;
2809 void init_tex_table(lua_State * L)
2811 lua_createtable(L, 0, 3);
2812 lua_pushcfunction(L, tex_run_boot);
2813 lua_setfield(L, -2, "initialize");
2814 lua_pushcfunction(L, tex_run_main);
2815 lua_setfield(L, -2, "run");
2816 lua_pushcfunction(L, tex_run_end);
2817 lua_setfield(L, -2, "finish");
2818 lua_setglobal(L, "tex");
2821 static const struct luaL_Reg texlib[] = {
2822 { "run", tex_run_main }, /* may be needed */
2823 { "finish", tex_run_end }, /* may be needed */
2824 { "write", luacwrite },
2825 { "print", luacprint },
2826 { "tprint", luactprint },
2827 { "error", texerror },
2828 { "sprint", luacsprint },
2829 { "set", settex },
2830 { "get", gettex },
2831 { "isdimen", isdimen },
2832 { "setdimen", setdimen },
2833 { "getdimen", getdimen },
2834 { "isskip", isskip },
2835 { "setskip", setskip },
2836 { "getskip", getskip },
2837 { "ismuskip", ismuskip },
2838 { "setmuskip", setmuskip },
2839 { "getmuskip", getmuskip },
2840 { "isattribute", isattribute },
2841 { "setattribute", setattribute },
2842 { "getattribute", getattribute },
2843 { "iscount", iscount },
2844 { "setcount", setcount },
2845 { "getcount", getcount },
2846 { "istoks", istoks },
2847 { "settoks", settoks },
2848 { "scantoks", scantoks },
2849 { "gettoks", gettoks },
2850 { "isbox", isbox },
2851 { "setbox", setbox },
2852 { "getbox", getbox },
2853 { "splitbox", splitbox },
2854 { "setlist", setlist },
2855 { "getlist", getlist },
2856 { "setnest", setnest },
2857 { "getnest", getnest },
2858 { "setcatcode", setcatcode },
2859 { "getcatcode", getcatcode },
2860 { "setdelcode", setdelcode },
2861 { "getdelcode", getdelcode },
2862 { "getdelcodes", getdelcodes },
2863 { "setlccode", setlccode },
2864 { "getlccode", getlccode },
2865 { "setmathcode", setmathcode },
2866 { "getmathcode", getmathcode },
2867 { "getmathcodes", getmathcodes },
2868 { "setsfcode", setsfcode },
2869 { "getsfcode", getsfcode },
2870 { "setuccode", setuccode },
2871 { "getuccode", getuccode },
2872 { "round", tex_roundnumber },
2873 { "scale", tex_scaletable },
2874 { "sp", tex_scaledimen },
2875 { "fontname", getfontname },
2876 { "fontidentifier", getfontidentifier },
2877 { "uniformdeviate", getuniformdeviate },
2878 { "number", getnumber },
2879 { "romannumeral", getromannumeral },
2880 { "definefont", tex_definefont },
2881 { "hashtokens", tex_hashpairs },
2882 { "primitives", tex_primitives },
2883 { "extraprimitives", tex_extraprimitives },
2884 { "enableprimitives", tex_enableprimitives },
2885 { "shipout", tex_shipout },
2886 { "badness", tex_badness },
2887 { "setmath", tex_setmathparm },
2888 { "getmath", tex_getmathparm },
2889 { "linebreak", tex_run_linebreak },
2890 /* tex random generators */
2891 { "init_rand", tex_init_rand },
2892 { "uniform_rand",tex_unif_rand },
2893 { "normal_rand", tex_norm_rand },
2894 { "lua_math_randomseed", tex_init_rand }, /* syntactic sugar */
2895 { "lua_math_random", lua_math_random },
2896 { "show_context", tex_show_context },
2897 { "saveboxresource", tex_save_box_resource },
2898 { "useboxresource", tex_use_box_resource },
2899 { "getboxresourcedimensions", tex_get_box_resource_dimensions },
2900 /* just for testing: it will probably stay but maybe with options */
2901 { "triggerbuildpage", tex_build_page },
2902 /* sentinel */
2903 { NULL, NULL }
2906 int luaopen_tex(lua_State * L)
2908 luaL_register(L, "tex", texlib);
2909 /* *INDENT-OFF* */
2910 make_table(L, "attribute", "tex.attribute", "getattribute", "setattribute");
2911 make_table(L, "skip", "tex.skip", "getskip", "setskip");
2912 make_table(L, "muskip", "tex.muskip", "getmuskip", "setmuskip");
2913 make_table(L, "dimen", "tex.dimen", "getdimen", "setdimen");
2914 make_table(L, "count", "tex.count", "getcount", "setcount");
2915 make_table(L, "toks", "tex.toks", "gettoks", "settoks");
2916 make_table(L, "box", "tex.box", "getbox", "setbox");
2917 make_table(L, "sfcode", "tex.sfcode", "getsfcode", "setsfcode");
2918 make_table(L, "lccode", "tex.lccode", "getlccode", "setlccode");
2919 make_table(L, "uccode", "tex.uccode", "getuccode", "setuccode");
2920 make_table(L, "catcode", "tex.catcode", "getcatcode", "setcatcode");
2921 make_table(L, "mathcode", "tex.mathcode", "getmathcode", "setmathcode");
2922 make_table(L, "delcode", "tex.delcode", "getdelcode", "setdelcode");
2923 make_table(L, "lists", "tex.lists", "getlist", "setlist");
2924 make_table(L, "nest", "tex.nest", "getnest", "setnest");
2925 /* *INDENT-ON* */
2926 init_nest_lib(L);
2927 /* make the meta entries */
2928 /* fetch it back */
2929 luaL_newmetatable(L, "tex.meta");
2930 lua_pushstring(L, "__index");
2931 lua_pushcfunction(L, gettex);
2932 lua_settable(L, -3);
2933 lua_pushstring(L, "__newindex");
2934 lua_pushcfunction(L, settex);
2935 lua_settable(L, -3);
2936 lua_setmetatable(L, -2); /* meta to itself */
2937 /* initialize the I/O stack: */
2938 spindles = xmalloc(sizeof(spindle));
2939 spindle_index = 0;
2940 spindles[0].head = NULL;
2941 spindles[0].tail = NULL;
2942 spindle_size = 1;
2943 /* a somewhat odd place for this assert, maybe */
2944 assert(command_names[data_cmd].command_offset == data_cmd);
2945 return 1;