fix getsup (HH)
[luatex.git] / source / texk / web2c / luatexdir / lua / ltexlib.c
bloba38b608e40fd1af53cc24eb43cd477e929714500
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 /* tex random generators */
28 extern int unif_rand(int );
29 extern int norm_rand(void );
30 extern void init_randoms(int );
32 typedef struct {
33 char *text;
34 unsigned int tsize;
35 void *next;
36 boolean partial;
37 int cattable;
38 /* halfword tok; */
39 } rope;
41 typedef struct {
42 rope *head;
43 rope *tail;
44 char complete; /* currently still writing ? */
45 } spindle;
47 #define PARTIAL_LINE 1
48 #define FULL_LINE 0
50 #define write_spindle spindles[spindle_index]
51 #define read_spindle spindles[(spindle_index-1)]
53 static int spindle_size = 0;
54 static spindle *spindles = NULL;
55 static int spindle_index = 0;
57 static void luac_store(lua_State * L, int i, int partial, int cattable)
59 const char *sttemp;
60 char *st;
61 size_t tsize;
62 rope *rn = NULL;
63 sttemp = lua_tolstring(L, i, &tsize);
64 st = xmalloc((unsigned) (tsize + 1));
65 memcpy(st, sttemp, (tsize + 1));
66 if (st) {
67 luacstrings++;
68 rn = (rope *) xmalloc(sizeof(rope));
69 rn->text = st;
70 rn->tsize = (unsigned) tsize;
71 rn->partial = partial;
72 rn->cattable = cattable;
73 rn->next = NULL;
74 /* rn->tok = 0; */
75 if (write_spindle.head == NULL) {
76 assert(write_spindle.tail == NULL);
77 write_spindle.head = rn;
78 } else {
79 write_spindle.tail->next = rn;
81 write_spindle.tail = rn;
82 write_spindle.complete = 0;
86 static int do_luacprint(lua_State * L, int partial, int deftable)
88 int cattable = deftable;
89 int startstrings = 1;
90 int n = lua_gettop(L);
91 if (cattable != NO_CAT_TABLE) {
92 if (lua_type(L, 1) == LUA_TNUMBER && n > 1) {
93 cattable = lua_tointeger(L, 1);
94 startstrings = 2;
95 if (cattable != -1 && cattable != -2 && !valid_catcode_table(cattable)) {
96 cattable = DEFAULT_CAT_TABLE;
100 if (lua_type(L, startstrings) == LUA_TTABLE) {
101 int i;
102 for (i = 1;; i++) {
103 lua_rawgeti(L, startstrings, i);
104 if (lua_isstring(L,-1)) { /* or number */
105 luac_store(L, -1, partial, cattable);
106 lua_pop(L, 1);
107 } else {
108 break;
111 } else {
112 int i;
113 for (i = startstrings; i <= n; i++) {
114 if (!lua_isstring(L,i)) { /* or number */
115 luaL_error(L, "no string to print");
117 luac_store(L, i, partial, cattable);
119 /* hh: We could use this but it makes not much different, apart from allocating more ropes so less
120 memory. To be looked into: lua 5.2 buffer mechanism as now we still hash the concatination. This
121 test was part of the why-eis-luajit-so-slow on crited experiments. */
123 if (startstrings == n) {
124 luac_store(L, n, partial, cattable);
125 } else {
126 lua_concat(L,n-startstrings+1);
127 luac_store(L, startstrings, partial, cattable);
131 return 0;
136 // some first experiments .. somewhat tricky at the other end
138 int luatwrite(lua_State * L)
140 int top = lua_gettop(L);
141 if (top>0) {
142 rope *rn = xmalloc(sizeof(rope)); // overkill
143 int i = 1 ;
144 luacstrings++; // should be luactokens
145 rn->text = NULL;
146 rn->tsize = 0;
147 rn->partial = 0;
148 rn->cattable = DEFAULT_CAT_TABLE;
149 rn->next = NULL;
150 rn->tok = 0;
151 if (write_spindle.head == NULL) {
152 write_spindle.head = rn;
153 } else {
154 write_spindle.tail->next = rn;
156 write_spindle.tail = rn;
157 write_spindle.complete = 0;
158 while (1) {
159 rn->tok = lua_tointeger(L,i);
160 if (i<top) {
161 rope *r = xmalloc(sizeof(rope)); // overkill
162 r->text = NULL;
163 r->tsize = 0;
164 r->partial = 0;
165 r->cattable = DEFAULT_CAT_TABLE;
166 r->next = NULL;
167 r->tok = 0;
168 rn->next = r;
169 rn = r;
170 write_spindle.tail = rn;
171 i++;
172 } else {
173 break;
177 return 0;
182 static int luacwrite(lua_State * L)
184 return do_luacprint(L, FULL_LINE, NO_CAT_TABLE);
187 static int luacprint(lua_State * L)
189 return do_luacprint(L, FULL_LINE, DEFAULT_CAT_TABLE);
192 static int luacsprint(lua_State * L)
194 return do_luacprint(L, PARTIAL_LINE, DEFAULT_CAT_TABLE);
197 static int luaccprint(lua_State * L)
199 /* so a negative value is a specific catcode with offset 1 */
200 int cattable = lua_tointeger(L,1);
201 if (cattable < 0 || cattable > 15) {
202 cattable = - 12 - 0xFF ;
203 } else {
204 cattable = - cattable - 0xFF;
206 if (lua_type(L, 2) == LUA_TTABLE) {
207 int i;
208 for (i = 1;; i++) {
209 lua_rawgeti(L, 2, i);
210 if (lua_isstring(L,-1)) { /* or number */
211 luac_store(L, -1, PARTIAL_LINE, cattable);
212 lua_pop(L, 1);
213 } else {
214 break;
217 } else {
218 int i;
219 int n = lua_gettop(L);
220 for (i = 2; i <= n; i++) {
221 if (!lua_isstring(L,i)) { /* or number */
222 luaL_error(L, "no string to print");
224 luac_store(L, i, PARTIAL_LINE, cattable);
227 return 0;
230 static int luactprint(lua_State * L)
232 int i, j;
233 int cattable, startstrings;
234 int n = lua_gettop(L);
235 for (i = 1; i <= n; i++) {
236 cattable = DEFAULT_CAT_TABLE;
237 startstrings = 1;
238 if (lua_type(L, i) != LUA_TTABLE) {
239 luaL_error(L, "no string to print");
241 lua_pushvalue(L, i); /* push the table */
242 lua_pushinteger(L, 1);
243 lua_gettable(L, -2);
244 if (lua_type(L, -1) == LUA_TNUMBER) {
245 cattable = lua_tointeger(L, -1);
246 startstrings = 2;
247 if (cattable != -1 && cattable != -2 && !valid_catcode_table(cattable)) {
248 cattable = DEFAULT_CAT_TABLE;
251 lua_pop(L, 1);
252 for (j = startstrings;; j++) {
253 lua_pushinteger(L, j);
254 lua_gettable(L, -2);
255 if (lua_isstring(L, -1)) { /* or number */
256 luac_store(L, -1, PARTIAL_LINE, cattable);
257 lua_pop(L, 1);
258 } else {
259 lua_pop(L, 1);
260 break;
263 lua_pop(L, 1); /* pop the table */
265 return 0;
268 int luacstring_cattable(void)
270 return (int) read_spindle.tail->cattable;
273 int luacstring_partial(void)
275 return read_spindle.tail->partial;
278 int luacstring_final_line(void)
280 return (read_spindle.tail->next == NULL);
283 int luacstring_input(void)
285 rope *t = read_spindle.head;
286 int ret = 1 ;
287 if (!read_spindle.complete) {
288 read_spindle.complete = 1;
289 read_spindle.tail = NULL;
291 if (t == NULL) {
292 if (read_spindle.tail != NULL)
293 free(read_spindle.tail);
294 read_spindle.tail = NULL;
295 return 0;
297 if (t->text != NULL) {
298 /* put that thing in the buffer */
299 char *st = t->text;
300 int ret = first;
301 last = first;
302 check_buffer_overflow(last + (int) t->tsize);
303 while (t->tsize-- > 0)
304 buffer[last++] = (packed_ASCII_code) * st++;
305 if (!t->partial) {
306 while (last - 1 > ret && buffer[last - 1] == ' ')
307 last--;
309 free(t->text);
310 t->text = NULL;
312 } else if (t->tok > 0) {
313 ret = - t->tok;
316 if (read_spindle.tail != NULL) { /* not a one-liner */
317 free(read_spindle.tail);
319 read_spindle.tail = t;
320 read_spindle.head = t->next;
321 return ret;
324 /* open for reading, and make a new one for writing */
325 void luacstring_start(int n)
327 (void) n; /* for -W */
328 spindle_index++;
329 if (spindle_size == spindle_index) { /* add a new one */
330 spindles = xrealloc(spindles, (unsigned) (sizeof(spindle) * (unsigned) (spindle_size + 1)));
331 spindles[spindle_index].head = NULL;
332 spindles[spindle_index].tail = NULL;
333 spindles[spindle_index].complete = 0;
334 spindle_size++;
338 /* close for reading */
340 void luacstring_close(int n)
342 rope *next, *t;
343 (void) n; /* for -W */
344 next = read_spindle.head;
345 while (next != NULL) {
346 if (next->text != NULL)
347 free(next->text);
348 t = next;
349 next = next->next;
350 if (t==read_spindle.tail) {
351 read_spindle.tail = NULL;
353 free(t);
355 read_spindle.head = NULL;
356 if (read_spindle.tail != NULL)
357 free(read_spindle.tail);
358 read_spindle.tail = NULL;
359 read_spindle.complete = 0;
360 spindle_index--;
363 /* local (static) versions */
365 #define check_index_range(j,s) \
366 if (j<0 || j > 65535) { \
367 luaL_error(L, "incorrect index specification for tex.%s()", s); }
369 #define check_register(base) do { \
370 int k = get_item_index(L, lua_gettop(L), base); \
371 if ((k>=0) && (k <= 65535)) { \
372 lua_pushinteger(L,k); \
373 } else { \
374 lua_pushboolean(L,false); \
376 return 1; \
377 } while (1)
379 static const char *scan_integer_part(lua_State * L, const char *ss, int *ret, int *radix_ret)
381 boolean negative = false; /* should the answer be negated? */
382 int m = 214748364; /* |$2^{31}$ / radix|, the threshold of danger */
383 int d; /* the digit just scanned */
384 boolean vacuous = true; /* have no digits appeared? */
385 boolean OK_so_far = true; /* has an error message been issued? */
386 int radix1 = 10; /* the radix of the integer */
387 int c = 0; /* the current character */
388 const char *s; /* where we stopped in the string |ss| */
389 integer val = 0; /* return value */
390 s = ss;
391 do {
392 do {
393 c = *s++;
394 } while (c && c == ' ');
395 if (c == '-') {
396 negative = !negative;
397 c = '+';
399 } while (c == '+');
400 if (c == '\'') {
401 radix1 = 8;
402 m = 02000000000;
403 c = *s++;
404 } else if (c == '"') {
405 radix1 = 16;
406 m = 01000000000;
407 c = *s++;
409 /* Accumulate the constant until |cur_tok| is not a suitable digit */
410 while (1) {
411 if ((c < '0' + radix1) && (c >= '0') && (c <= '0' + 9)) {
412 d = c - '0';
413 } else if (radix1 == 16) {
414 if ((c <= 'A' + 5) && (c >= 'A')) {
415 d = c - 'A' + 10;
416 } else if ((c <= 'a' + 5) && (c >= 'a')) {
417 d = c - 'a' + 10;
418 } else {
419 break;
421 } else {
422 break;
424 vacuous = false;
425 if ((val >= m) && ((val > m) || (d > 7) || (radix1 != 10))) {
426 if (OK_so_far) {
427 luaL_error(L, "Number too big");
428 val = infinity;
429 OK_so_far = false;
431 } else {
432 val = val * radix1 + d;
434 c = *s++;
436 if (vacuous) {
437 /* Express astonishment that no number was here */
438 luaL_error(L, "Missing number, treated as zero");
440 if (negative)
441 val = -val;
442 *ret = val;
443 *radix_ret = radix1;
444 if (c != ' ' && s > ss)
445 s--;
446 return s;
449 #define set_conversion(A,B) do { num=(A); denom=(B); } while(0)
452 static const char *scan_dimen_part(lua_State * L, const char *ss, int *ret)
453 /* sets |cur_val| to a dimension */
455 boolean negative = false; /* should the answer be negated? */
456 int f = 0; /* numerator of a fraction whose denominator is $2^{16}$ */
457 int num, denom; /* conversion ratio for the scanned units */
458 int k; /* number of digits in a decimal fraction */
459 scaled v; /* an internal dimension */
460 int save_cur_val; /* temporary storage of |cur_val| */
461 int c; /* the current character */
462 const char *s = ss; /* where we are in the string */
463 int radix1 = 0; /* the current radix */
464 int rdig[18]; /* to save the |dig[]| array */
465 int saved_tex_remainder; /* to save |tex_remainder| */
466 int saved_arith_error; /* to save |arith_error| */
467 int saved_cur_val; /* to save the global |cur_val| */
468 saved_tex_remainder = tex_remainder;
469 saved_arith_error = arith_error;
470 saved_cur_val = cur_val;
471 /* Get the next non-blank non-sign... */
472 do {
473 /* Get the next non-blank non-call token */
474 do {
475 c = *s++;
476 } while (c && c == ' ');
477 if (c == '-') {
478 negative = !negative;
479 c = '+';
481 } while (c == '+');
482 if (c == ',') {
483 c = '.';
485 if (c != '.') {
486 s = scan_integer_part(L, (s > ss ? (s - 1) : ss), &cur_val, &radix1);
487 c = *s;
488 } else {
489 radix1 = 10;
490 cur_val = 0;
491 c = *(--s);
493 if (c == ',')
494 c = '.';
495 if ((radix1 == 10) && (c == '.')) {
496 /* Scan decimal fraction */
497 for (k = 0; k < 18; k++)
498 rdig[k] = dig[k];
499 k = 0;
500 s++; /* get rid of the '.' */
501 while (1) {
502 c = *s++;
503 if ((c > '0' + 9) || (c < '0'))
504 break;
505 if (k < 17) { /* digits for |k>=17| cannot affect the result */
506 dig[k++] = c - '0';
509 f = round_decimals(k);
510 if (c != ' ')
511 c = *(--s);
512 for (k = 0; k < 18; k++)
513 dig[k] = rdig[k];
515 if (cur_val < 0) { /* in this case |f=0| */
516 negative = !negative;
517 cur_val = -cur_val;
519 /* Scan for (u)units that are internal dimensions;
520 |goto attach_sign| with |cur_val| set if found */
521 save_cur_val = cur_val;
522 /* Get the next non-blank non-call... */
523 do {
524 c = *s++;
525 } while (c && c == ' ');
526 if (c != ' ')
527 c = *(--s);
528 if (strncmp(s, "em", 2) == 0) {
529 s += 2;
530 v = (quad(get_cur_font()));
531 } else if (strncmp(s, "ex", 2) == 0) {
532 s += 2;
533 v = (x_height(get_cur_font()));
534 } else if (strncmp(s, "px", 2) == 0) {
535 s += 2;
536 v = px_dimen_par;
537 } else {
538 goto NOT_FOUND;
540 c = *s++;
541 if (c != ' ') {
542 c = *(--s);
544 cur_val = nx_plus_y(save_cur_val, v, xn_over_d(v, f, 0200000));
545 goto ATTACH_SIGN;
546 NOT_FOUND:
547 /* Scan for (m)\.{mu} units and |goto attach_fraction| */
548 if (strncmp(s, "mu", 2) == 0) {
549 s += 2;
550 goto ATTACH_FRACTION;
552 if (strncmp(s, "true", 4) == 0) {
553 /* Adjust (f)for the magnification ratio */
554 s += 4;
555 if (output_mode_used <= OMODE_DVI) {
556 prepare_mag();
557 if (mag_par != 1000) {
558 cur_val = xn_over_d(cur_val, 1000, mag_par);
559 f = (1000 * f + 0200000 * tex_remainder) / mag_par;
560 cur_val = cur_val + (f / 0200000);
561 f = f % 0200000;
564 do {
565 c = *s++;
566 } while (c && c == ' ');
567 c = *(--s);
569 if (strncmp(s, "pt", 2) == 0) {
570 s += 2;
571 goto ATTACH_FRACTION; /* the easy case */
573 /* Scan for (a)all other units and adjust |cur_val| and |f| accordingly;
574 |goto done| in the case of scaled points */
575 if (strncmp(s, "mm", 2) == 0) {
576 s += 2;
577 set_conversion(7227, 2540);
578 } else if (strncmp(s, "cm", 2) == 0) {
579 s += 2;
580 set_conversion(7227, 254);
581 } else if (strncmp(s, "sp", 2) == 0) {
582 s += 2;
583 goto DONE;
584 } else if (strncmp(s, "bp", 2) == 0) {
585 s += 2;
586 set_conversion(7227, 7200);
587 } else if (strncmp(s, "in", 2) == 0) {
588 s += 2;
589 set_conversion(7227, 100);
590 } else if (strncmp(s, "dd", 2) == 0) {
591 s += 2;
592 set_conversion(1238, 1157);
593 } else if (strncmp(s, "cc", 2) == 0) {
594 s += 2;
595 set_conversion(14856, 1157);
596 } else if (strncmp(s, "pc", 2) == 0) {
597 s += 2;
598 set_conversion(12, 1);
599 } else if (strncmp(s, "nd", 2) == 0) {
600 s += 2;
601 set_conversion(685, 642);
602 } else if (strncmp(s, "nc", 2) == 0) {
603 s += 2;
604 set_conversion(1370, 107);
605 } else {
606 /* Complain about unknown unit and |goto done2| */
607 luaL_error(L, "Illegal unit of measure (pt inserted)");
608 goto DONE2;
610 cur_val = xn_over_d(cur_val, num, denom);
611 f = (num * f + 0200000 * tex_remainder) / denom;
612 cur_val = cur_val + (f / 0200000);
613 f = f % 0200000;
614 DONE2:
615 ATTACH_FRACTION:
616 if (cur_val >= 040000)
617 arith_error = true;
618 else
619 cur_val = cur_val * 65536 + f;
620 DONE:
621 /* Scan an optional space */
622 c = *s++;
623 if (c != ' ')
624 s--;
625 ATTACH_SIGN:
626 if (arith_error || (abs(cur_val) >= 010000000000)) {
627 /* Report that this dimension is out of range */
628 luaL_error(L, "Dimension too large");
629 cur_val = max_dimen;
631 if (negative)
632 cur_val = -cur_val;
633 *ret = cur_val;
634 tex_remainder = saved_tex_remainder;
635 arith_error = saved_arith_error;
636 cur_val = saved_cur_val;
637 return s;
640 int dimen_to_number(lua_State * L, const char *s)
642 int j = 0;
643 const char *d = scan_dimen_part(L, s, &j);
644 if (*d) {
645 luaL_error(L, "conversion failed (trailing junk?)");
646 j = 0;
648 return j;
651 static int tex_scaledimen(lua_State * L)
653 int sp;
654 int t = lua_type(L, 1);
655 if (t == LUA_TNUMBER) {
656 sp = lua_roundnumber(L, 1);
657 } else if (t == LUA_TSTRING) {
658 sp = dimen_to_number(L, lua_tostring(L, 1));
659 } else {
660 luaL_error(L, "argument must be a string or a number");
661 return 0;
663 lua_pushinteger(L, sp);
664 return 1;
667 static int texerror (lua_State * L)
669 const char **errhlp = NULL;
670 const char *error = luaL_checkstring(L,1);
671 int n = lua_gettop(L);
672 if (n==2 && lua_type(L, n) == LUA_TTABLE) {
673 int i;
674 int l = 1; /* |errhlp| is terminated by a NULL entry */
675 for (i = 1;; i++) {
676 lua_rawgeti(L, n, i);
677 if (lua_type(L,-1) == LUA_TSTRING) {
678 l++;
679 lua_pop(L, 1);
680 } else {
681 lua_pop(L, 1);
682 break;
685 if (l>1) {
686 errhlp = xmalloc(l * sizeof(char *));
687 memset(errhlp,0,l * sizeof(char *));
688 for (i = 1;; i++) {
689 lua_rawgeti(L, n, i);
690 if (lua_type(L,-1) == LUA_TSTRING) {
691 errhlp[(i-1)] = lua_tostring(L,-1);
692 lua_pop(L, 1);
693 } else {
694 break;
699 deletions_allowed = false;
700 tex_error(error, errhlp);
701 if (errhlp)
702 xfree(errhlp);
703 deletions_allowed = true;
704 return 0;
707 static int get_item_index(lua_State * L, int i, int base)
709 size_t kk;
710 int k;
711 int cur_cs1;
712 const char *s;
713 switch (lua_type(L, i)) {
714 case LUA_TSTRING:
715 s = lua_tolstring(L, i, &kk);
716 cur_cs1 = string_lookup(s, kk);
717 if (cur_cs1 == undefined_control_sequence || cur_cs1 == undefined_cs_cmd)
718 k = -1; /* guarandeed invalid */
719 else
720 k = (equiv(cur_cs1) - base);
721 break;
722 case LUA_TNUMBER:
723 k = luaL_checkinteger(L, i);
724 break;
725 default:
726 luaL_error(L, "argument must be a string or a number");
727 k = -1; /* not a valid index */
729 return k;
732 #define check_item_global(L,top,isglobal) \
733 if (top == 3 && (lua_type(L,1) == LUA_TSTRING)) { \
734 const char *s = lua_tostring(L, 1); \
735 if (lua_key_eq(s,global)) { \
736 isglobal = 1; \
740 #define set_item_index_plus(L, where, base, what, value, is_global, is_assign, set_register, glue) { \
741 size_t len; \
742 const char *str; \
743 int key, err, cs; \
744 int save_global_defs = global_defs_par; \
745 if (is_global) { \
746 global_defs_par = 1; \
748 switch (lua_type(L, where)) { \
749 case LUA_TSTRING: \
750 str = lua_tolstring(L, where, &len); \
751 cs = string_lookup(str, len); \
752 if (cs == undefined_control_sequence || cs == undefined_cs_cmd) { \
753 luaL_error(L, "incorrect %s name", what); \
754 } else { \
755 key = equiv(cs) - base; \
756 if (key >= 0 && key <= 65535) { \
757 err = set_register(key, value); \
758 if (err) { \
759 luaL_error(L, "incorrect %s value", what); \
761 } else if (is_assign(eq_type(cs))) { \
762 if (glue) { \
763 int a = is_global; \
764 define(equiv(cs), assign_glue_cmd, value); \
765 } else { \
766 assign_internal_value((is_global ? 4 : 0), equiv(cs), value); \
768 } else { \
769 luaL_error(L, "incorrect %s name", what); \
772 break; \
773 case LUA_TNUMBER: \
774 key = luaL_checkinteger(L, where); \
775 if (key>=0 && key <= 65535) { \
776 err = set_register(key, value); \
777 if (err) { \
778 luaL_error(L, "incorrect %s value", what); \
780 } else { \
781 luaL_error(L, "incorrect %s index", what); \
783 break; \
784 default: \
785 luaL_error(L, "argument of 'set%s' must be a string or a number", what); \
787 global_defs_par = save_global_defs; \
790 static int gettex(lua_State * L);
792 #define get_item_index_plus(L, where, base, what, value, is_assign, get_register, glue) { \
793 size_t len; \
794 const char *str; \
795 int key, cs; \
796 switch (lua_type(L, where)) { \
797 case LUA_TSTRING: \
798 str = lua_tolstring(L, where, &len); \
799 cs = string_lookup(str, len); \
800 if (cs == undefined_control_sequence || cs == undefined_cs_cmd) { \
801 luaL_error(L, "incorrect %s name", what); \
802 } else { \
803 key = equiv(cs) - base; \
804 if (key >= 0 && key <= 65535) { \
805 value = get_register(key); \
806 } else if (is_assign(eq_type(cs))) { \
807 gettex(L); /* lazy */ \
808 } else { \
809 luaL_error(L, "incorrect %s name", what); \
812 break; \
813 case LUA_TNUMBER: \
814 key = luaL_checkinteger(L, where); \
815 if (key>=0 && key <= 65535) { \
816 value = get_register(key); \
817 } else { \
818 luaL_error(L, "incorrect %s index", what); \
820 break; \
821 default: \
822 luaL_error(L, "argument of 'get%s' must be a string or a number", what); \
826 static int isdimen(lua_State * L)
828 check_register(scaled_base);
831 static int setdimen(lua_State * L)
833 int isglobal = 0;
834 int value = 0;
835 int top = lua_gettop(L);
836 int t = lua_type(L, top);
837 check_item_global(L,top,isglobal);
838 if (t == LUA_TNUMBER) {
839 value = lua_roundnumber(L, top);
840 } else if (t == LUA_TSTRING) {
841 value = dimen_to_number(L, lua_tostring(L, top));
842 } else {
843 luaL_error(L, "unsupported %s value type","dimen");
845 set_item_index_plus(L, top-1, scaled_base, "dimen", value, isglobal, is_dim_assign, set_tex_dimen_register, false);
846 return 0;
849 static int getdimen(lua_State * L)
851 int value = 0;
852 get_item_index_plus(L, lua_gettop(L), scaled_base, "dimen", value, is_dim_assign, get_tex_dimen_register, false);
853 lua_pushinteger(L, value);
854 return 1;
857 static int isskip(lua_State * L)
859 check_register(skip_base);
862 static int setskip(lua_State * L)
864 int isglobal = 0;
865 halfword *value = NULL;
866 int top = lua_gettop(L);
867 check_item_global(L,top,isglobal);
868 value = check_isnode(L, top);
869 if (type(*value) == glue_spec_node) {
870 set_item_index_plus(L, top-1, skip_base, "skip", *value, isglobal, is_glue_assign, set_tex_skip_register, true);
871 } else {
872 luaL_error(L, "glue_spec expected");
874 return 0;
877 static int getskip(lua_State * L)
879 int value = 0;
880 get_item_index_plus(L, lua_gettop(L), skip_base, "skip", value, is_glue_assign, get_tex_skip_register, true);
881 if (value == null) {
882 lua_nodelib_push_fast(L, copy_node(zero_glue));
883 } else {
884 lua_nodelib_push_fast(L, copy_node(value));
886 return 1;
889 static int setglue(lua_State * L)
891 int isglobal = 0;
892 int index = 1;
893 halfword value = copy_node(zero_glue);
894 int top = lua_gettop(L);
895 check_item_global(L,top,isglobal);
896 if (isglobal) {
897 index = 2;
898 top -= 1;
900 /* [global] slot [width] [stretch] [shrink] [stretch_order] [shrink_order] */
901 if (top > 1) { width(value) = lua_roundnumber(L,index+1); }
902 if (top > 2) { stretch(value) = lua_roundnumber(L,index+2); }
903 if (top > 3) { shrink(value) = lua_roundnumber(L,index+3); }
904 if (top > 4) { stretch_order(value) = lua_tointeger(L,index+4); }
905 if (top > 5) { shrink_order(value) = lua_tointeger(L,index+5); }
906 set_item_index_plus(L, index, skip_base, "skip", value, isglobal, is_glue_assign, set_tex_skip_register, true);
907 return 0;
910 static int getglue(lua_State * L)
912 int value = 0;
913 int top = lua_gettop(L);
914 get_item_index_plus(L, top, skip_base, "skip", value, is_glue_assign, get_tex_skip_register, true);
915 if (value == null) {
916 lua_pushinteger(L,0);
917 lua_pushinteger(L,0);
918 lua_pushinteger(L,0);
919 lua_pushinteger(L,0);
920 lua_pushinteger(L,0);
921 } else {
922 lua_pushinteger(L,width(value));
923 lua_pushinteger(L,stretch(value));
924 lua_pushinteger(L,shrink(value));
925 lua_pushinteger(L,stretch_order(value));
926 lua_pushinteger(L,shrink_order(value));
928 return 5;
931 static int ismuskip(lua_State * L)
933 check_register(mu_skip_base);
936 static int setmuskip(lua_State * L)
938 int isglobal = 0;
939 halfword *value = NULL;
940 int top = lua_gettop(L);
941 check_item_global(L,top,isglobal);
942 value = check_isnode(L, top);
943 set_item_index_plus(L, top-1, mu_skip_base, "muskip", *value, isglobal, is_mu_glue_assign, set_tex_mu_skip_register, true);
944 return 0;
947 static int getmuskip(lua_State * L)
949 int value = 0;
950 get_item_index_plus(L, lua_gettop(L), mu_skip_base, "muskip", value, is_mu_glue_assign, get_tex_mu_skip_register, true);
951 lua_nodelib_push_fast(L, copy_node(value));
952 return 1;
955 static int setmuglue(lua_State * L)
957 int isglobal = 0;
958 int index = 1;
959 halfword value = copy_node(zero_glue);
960 int top = lua_gettop(L);
961 check_item_global(L,top,isglobal);
962 if (isglobal) {
963 index = 2;
964 top -= 1;
966 /* [global] slot [width] [stretch] [shrink] [stretch_order] [shrink_order] */
967 if (top > 1) { width(value) = lua_roundnumber(L,index+1); }
968 if (top > 2) { stretch(value) = lua_roundnumber(L,index+2); }
969 if (top > 3) { shrink(value) = lua_roundnumber(L,index+3); }
970 if (top > 4) { stretch_order(value) = lua_tointeger(L,index+4); }
971 if (top > 5) { shrink_order(value) = lua_tointeger(L,index+5); }
972 set_item_index_plus(L, index, mu_skip_base, "muskip", value, isglobal, is_mu_glue_assign, set_tex_mu_skip_register, true);
973 return 0;
976 static int getmuglue(lua_State * L)
978 int value = 0;
979 get_item_index_plus(L, lua_gettop(L), mu_skip_base, "muskip", value, is_mu_glue_assign, get_tex_mu_skip_register, true);
980 if (value == null) {
981 lua_pushnil(L);
982 return 1;
983 } else {
984 lua_pushinteger(L,width(value));
985 lua_pushinteger(L,stretch(value));
986 lua_pushinteger(L,shrink(value));
987 lua_pushinteger(L,stretch_order(value));
988 lua_pushinteger(L,shrink_order(value));
989 return 5;
993 static int iscount(lua_State * L)
995 check_register(count_base);
998 static int setcount(lua_State * L)
1000 int t;
1001 int isglobal = 0;
1002 int value = 0;
1003 int top = lua_gettop(L);
1004 check_item_global(L,top,isglobal);
1005 t = lua_type(L,top);
1006 if (t == LUA_TNUMBER) {
1007 value = lua_tointeger(L, top);
1008 } else {
1009 luaL_error(L, "unsupported %s value type","count");
1011 set_item_index_plus(L, top-1, count_base, "count", value, isglobal, is_int_assign, set_tex_count_register, false);
1012 return 0;
1015 static int getcount(lua_State * L)
1017 int value = 0;
1018 get_item_index_plus(L, lua_gettop(L), count_base, "count", value, is_int_assign, get_tex_count_register, false);
1019 lua_pushinteger(L, value);
1020 return 1;
1023 static int isattribute(lua_State * L)
1025 check_register(attribute_base);
1028 /* there are no system set attributes so this is a bit overkill */
1030 static int setattribute(lua_State * L)
1032 int t;
1033 int isglobal = 0;
1034 int value = 0;
1035 int top = lua_gettop(L);
1036 check_item_global(L,top,isglobal);
1037 t = lua_type(L,top);
1038 if (t == LUA_TNUMBER) {
1039 value = lua_tointeger(L, top);
1040 } else {
1041 luaL_error(L, "unsupported %s value type","attribute");
1043 set_item_index_plus(L, top-1, attribute_base, "attribute", value, isglobal, is_attr_assign, set_tex_attribute_register, false);
1044 return 0;
1047 static int getattribute(lua_State * L)
1049 int value = 0;
1050 get_item_index_plus(L, lua_gettop(L), attribute_base, "attribute", value, is_attr_assign, get_tex_attribute_register, false);
1051 lua_pushinteger(L, value);
1052 return 1;
1055 /* todo: we can avoid memcpy as there is no need to go through the pool */
1057 /* use string_to_toks */
1059 static int istoks(lua_State * L)
1061 check_register(toks_base);
1064 static int settoks(lua_State * L)
1066 int i, err, k;
1067 lstring str;
1068 char *s;
1069 const char *ss;
1070 int is_global = 0;
1071 int save_global_defs = global_defs_par;
1072 int n = lua_gettop(L);
1073 if (n == 3 && (lua_type(L,1) == LUA_TSTRING)) {
1074 const char *s = lua_tostring(L, 1);
1075 if (lua_key_eq(s,global))
1076 is_global = 1;
1078 if (is_global)
1079 global_defs_par = 1;
1080 i = lua_gettop(L);
1081 if (lua_type(L,i) != LUA_TSTRING) {
1082 luaL_error(L, "unsupported value type");
1084 ss = lua_tolstring(L, i, &str.l);
1085 s = xmalloc (str.l+1);
1086 memcpy (s, ss, str.l+1);
1087 str.s = (unsigned char *)s;
1088 k = get_item_index(L, (i - 1), toks_base);
1089 check_index_range(k, "settoks");
1090 err = set_tex_toks_register(k, str);
1091 xfree(str.s);
1092 global_defs_par = save_global_defs;
1093 if (err) {
1094 luaL_error(L, "incorrect value");
1096 return 0;
1099 static int scantoks(lua_State * L)
1101 int i, err, k, c;
1102 lstring str;
1103 char *s;
1104 const char *ss;
1105 int is_global = 0;
1106 int save_global_defs = global_defs_par;
1107 int n = lua_gettop(L);
1108 if (n == 4 && (lua_type(L,1) == LUA_TSTRING)) {
1109 const char *s = lua_tostring(L, 1);
1110 if (lua_key_eq(s,global))
1111 is_global = 1;
1113 /* action : vsettokscct(L, is_global); */
1114 if (is_global)
1115 global_defs_par = 1;
1116 i = lua_gettop(L);
1117 if (lua_type(L,i) != LUA_TSTRING) {
1118 luaL_error(L, "unsupported value type");
1120 ss = lua_tolstring(L, i, &str.l);
1121 s = xmalloc (str.l+1);
1122 memcpy (s, ss, str.l+1);
1123 str.s = (unsigned char *)s;
1124 k = get_item_index(L, (i - 2), toks_base);
1125 c = luaL_checkinteger(L, i - 1);
1126 check_index_range(k, "settoks");
1127 err = scan_tex_toks_register(k, c, str);
1128 xfree(str.s);
1129 global_defs_par = save_global_defs;
1130 if (err) {
1131 luaL_error(L, "incorrect value");
1133 return 0;
1136 static int gettoks(lua_State * L)
1138 char *ss;
1139 str_number t;
1140 int k = get_item_index(L, lua_gettop(L), toks_base);
1141 check_index_range(k, "gettoks");
1142 t = get_tex_toks_register(k);
1143 ss = makecstring(t);
1144 lua_pushstring(L, ss);
1145 free(ss);
1146 flush_str(t);
1147 return 1;
1150 static int get_box_id(lua_State * L, int i, boolean report)
1152 const char *s;
1153 int cur_cs1, cur_cmd1;
1154 size_t k = 0;
1155 int j = -1;
1156 switch (lua_type(L, i)) {
1157 case LUA_TSTRING:
1158 s = lua_tolstring(L, i, &k);
1159 cur_cs1 = string_lookup(s, k);
1160 cur_cmd1 = eq_type(cur_cs1);
1161 if (cur_cmd1 == char_given_cmd ||
1162 cur_cmd1 == math_given_cmd) {
1163 j = equiv(cur_cs1);
1165 break;
1166 case LUA_TNUMBER:
1167 j = lua_tointeger(L, (i));
1168 break;
1169 default:
1170 if (report) {
1171 luaL_error(L, "argument must be a string or a number");
1173 j = -1; /* not a valid box id */
1175 return j;
1178 static int getbox(lua_State * L)
1180 int t;
1181 int k = get_box_id(L, -1, true);
1182 check_index_range(k, "getbox");
1183 t = get_tex_box_register(k);
1184 nodelist_to_lua(L, t);
1185 return 1;
1188 static int splitbox(lua_State * L)
1190 const char *s;
1191 int k = get_box_id(L, 1, true);
1192 check_index_range(k, "splitbox");
1193 if (lua_isnumber(L, 2)) {
1194 int m = 1;
1195 if (lua_type(L, 3) == LUA_TSTRING) {
1196 s = lua_tostring(L, 3);
1197 if (lua_key_eq(s, exactly)) {
1198 m = 0;
1199 } else if (lua_key_eq(s, additional)) {
1200 m = 1;
1202 } else if (lua_type(L, 3) == LUA_TNUMBER) {
1203 m = (int) lua_tointeger(L, 3);
1205 if ((m<0) || (m>1)) {
1206 luaL_error(L, "wrong mode in splitbox");
1208 nodelist_to_lua(L, vsplit(k,lua_roundnumber(L,2),m));
1209 } else {
1210 /* maybe a warning */
1211 lua_pushnil(L);
1213 return 1;
1216 static int isbox(lua_State * L)
1218 int k = get_box_id(L, -1, false);
1219 lua_pushboolean(L,(k>=0 && k<=65535));
1220 return 1;
1223 static int vsetbox(lua_State * L, int is_global)
1225 int j, k, err, t;
1226 int save_global_defs;
1227 k = get_box_id(L, -2, true);
1228 check_index_range(k, "setbox");
1229 t = lua_type(L, -1);
1230 if (t == LUA_TBOOLEAN) {
1231 j = lua_toboolean(L, -1);
1232 if (j == 0) {
1233 j = null;
1234 } else {
1235 return 0;
1237 } else if (t == LUA_TNIL) {
1238 j = null;
1239 } else {
1240 j = nodelist_from_lua(L);
1241 if (j != null && type(j) != hlist_node && type(j) != vlist_node) {
1242 luaL_error(L, "setbox: incompatible node type (%s)\n", get_node_name(type(j), subtype(j)));
1243 return 0;
1246 save_global_defs = global_defs_par;
1247 if (is_global) {
1248 global_defs_par = 1;
1250 err = set_tex_box_register(k, j);
1251 global_defs_par = save_global_defs;
1252 if (err) {
1253 luaL_error(L, "incorrect value");
1255 return 0;
1258 static int setbox(lua_State * L)
1260 int isglobal = 0;
1261 int n = lua_gettop(L);
1262 if (n == 3 && (lua_type(L,1) == LUA_TSTRING)) {
1263 const char *s = lua_tostring(L, 1);
1264 if (lua_key_eq(s,global))
1265 isglobal = 1;
1267 return vsetbox(L, isglobal);
1270 #define check_char_range(j,s,lim) \
1271 if (j<0 || j >= lim) { \
1272 luaL_error(L, "incorrect character value %d for tex.%s()", (int) j, s); \
1275 static int setcode (lua_State *L, void (*setone)(int,halfword,quarterword),
1276 void (*settwo)(int,halfword,quarterword), const char *name, int lim)
1278 int ch;
1279 halfword val, ucval;
1280 int level = cur_level;
1281 int n = lua_gettop(L);
1282 int f = 1;
1283 if (n>1 && lua_type(L,1) == LUA_TTABLE)
1284 f++;
1285 if (n>2 && (lua_type(L,f) == LUA_TSTRING)) {
1286 const char *s = lua_tostring(L, f);
1287 if (lua_key_eq(s,global)) {
1288 level = level_one;
1289 f++;
1292 ch = luaL_checkinteger(L, f);
1293 check_char_range(ch, name, 65536*17);
1294 val = (halfword) luaL_checkinteger(L, f+1);
1295 check_char_range(val, name, lim);
1296 (setone)(ch, val, level);
1297 if (settwo != NULL && n-f == 2) {
1298 ucval = (halfword) luaL_checkinteger(L, f+2);
1299 check_char_range(ucval, name, lim);
1300 (settwo)(ch, ucval, level);
1302 return 0;
1305 static int setlccode(lua_State * L)
1307 return setcode(L, &set_lc_code, &set_uc_code, "setlccode", 65536*17);
1310 static int getlccode(lua_State * L)
1312 int ch = luaL_checkinteger(L, -1);
1313 check_char_range(ch, "getlccode", 65536*17);
1314 lua_pushinteger(L, get_lc_code(ch));
1315 return 1;
1318 static int setuccode(lua_State * L)
1320 return setcode(L, &set_uc_code, &set_lc_code, "setuccode", 65536*17);
1323 static int getuccode(lua_State * L)
1325 int ch = luaL_checkinteger(L, -1);
1326 check_char_range(ch, "getuccode", 65536*17);
1327 lua_pushinteger(L, get_uc_code(ch));
1328 return 1;
1331 static int setsfcode(lua_State * L)
1333 return setcode(L, &set_sf_code, NULL, "setsfcode", 32768);
1336 static int getsfcode(lua_State * L)
1338 int ch = luaL_checkinteger(L, -1);
1339 check_char_range(ch, "getsfcode", 65536*17);
1340 lua_pushinteger(L, get_sf_code(ch));
1341 return 1;
1344 static int setcatcode(lua_State * L)
1346 int ch;
1347 halfword val;
1348 int level = cur_level;
1349 int cattable = cat_code_table_par;
1350 int n = lua_gettop(L);
1351 int f = 1;
1352 if (n>1 && lua_type(L,1) == LUA_TTABLE)
1353 f++;
1354 if (n>2 && (lua_type(L,f) == LUA_TSTRING)) {
1355 const char *s = lua_tostring(L, f);
1356 if (lua_key_eq(s,global)) {
1357 level = level_one;
1358 f++;
1361 if (n-f == 2) {
1362 cattable = luaL_checkinteger(L, -3);
1364 ch = luaL_checkinteger(L, -2);
1365 check_char_range(ch, "setcatcode", 65536*17);
1366 val = (halfword) luaL_checkinteger(L, -1);
1367 check_char_range(val, "setcatcode", 16);
1368 set_cat_code(cattable, ch, val, level);
1369 return 0;
1372 static int getcatcode(lua_State * L)
1374 int cattable = cat_code_table_par;
1375 int ch = luaL_checkinteger(L, -1);
1376 if (lua_gettop(L)>=2 && lua_type(L,-2)==LUA_TNUMBER) {
1377 cattable = luaL_checkinteger(L, -2);
1379 check_char_range(ch, "getcatcode", 65536*17);
1380 lua_pushinteger(L, get_cat_code(cattable, ch));
1381 return 1;
1386 static int setmathcode(lua_State * L)
1388 int ch;
1389 halfword cval, fval, chval;
1390 int level = cur_level;
1391 int n = lua_gettop(L);
1392 int f = 1;
1393 if (n>1 && lua_type(L,1) == LUA_TTABLE)
1394 f++;
1395 if (n>2 && (lua_type(L,f) == LUA_TSTRING)) {
1396 const char *s = lua_tostring(L, f);
1397 if (lua_key_eq(s,global)) {
1398 level = level_one;
1399 f++;
1402 if (n-f!=1 || lua_type(L,f+1) != LUA_TTABLE) {
1403 luaL_error(L, "Bad arguments for tex.setmathcode()");
1405 ch = luaL_checkinteger(L, -2);
1406 check_char_range(ch, "setmathcode", 65536*17);
1408 lua_rawgeti(L, -1, 1);
1409 cval = (halfword) luaL_checkinteger(L, -1);
1410 lua_rawgeti(L, -2, 2);
1411 fval = (halfword) luaL_checkinteger(L, -1);
1412 lua_rawgeti(L, -3, 3);
1413 chval = (halfword) luaL_checkinteger(L, -1);
1414 lua_pop(L,3);
1416 check_char_range(cval, "setmathcode", 8);
1417 check_char_range(fval, "setmathcode", 256);
1418 check_char_range(chval, "setmathcode", 65536*17);
1419 set_math_code(ch, cval,fval, chval, (quarterword) (level));
1420 return 0;
1426 [global] code { c f ch }
1427 [global] code c f ch (a bit easier on memory, counterpart of getter)
1430 static int setmathcode(lua_State * L)
1432 int ch;
1433 halfword cval, fval, chval;
1434 int level = cur_level;
1435 int f = 1;
1436 if (lua_type(L,1) == LUA_TSTRING) {
1437 const char *s = lua_tostring(L,1);
1438 if (lua_key_eq(s,global)) {
1439 level = level_one;
1440 f = 2;
1443 ch = luaL_checkinteger(L, f);
1444 check_char_range(ch, "setmathcode", 65536*17);
1445 f += 1 ;
1446 if (lua_type(L,f) == LUA_TNUMBER) {
1447 cval = luaL_checkinteger(L, f);
1448 fval = luaL_checkinteger(L, f+1);
1449 chval = luaL_checkinteger(L, f+2);
1450 } else if (lua_type(L,f) == LUA_TTABLE) {
1451 lua_rawgeti(L, f, 1);
1452 cval = (halfword) luaL_checkinteger(L, -1);
1453 lua_rawgeti(L, f, 2);
1454 fval = (halfword) luaL_checkinteger(L, -1);
1455 lua_rawgeti(L, f, 3);
1456 chval = (halfword) luaL_checkinteger(L, -1);
1457 lua_pop(L,3);
1458 } else {
1459 luaL_error(L, "Bad arguments for tex.setmathcode()");
1460 return 0;
1462 check_char_range(cval, "setmathcode", 8);
1463 check_char_range(fval, "setmathcode", 256);
1464 check_char_range(chval, "setmathcode", 65536*17);
1465 set_math_code(ch, cval,fval, chval, (quarterword) (level));
1466 return 0;
1469 static int getmathcode(lua_State * L)
1471 mathcodeval mval = { 0, 0, 0 };
1472 int ch = luaL_checkinteger(L, -1);
1473 check_char_range(ch, "getmathcode", 65536*17);
1474 mval = get_math_code(ch);
1475 lua_newtable(L);
1476 lua_pushinteger(L,mval.class_value);
1477 lua_rawseti(L, -2, 1);
1478 lua_pushinteger(L,mval.family_value);
1479 lua_rawseti(L, -2, 2);
1480 lua_pushinteger(L,mval.character_value);
1481 lua_rawseti(L, -2, 3);
1482 return 1;
1485 static int getmathcodes(lua_State * L)
1487 mathcodeval mval = { 0, 0, 0 };
1488 int ch = luaL_checkinteger(L, -1);
1489 check_char_range(ch, "getmathcodes", 65536*17);
1490 mval = get_math_code(ch);
1491 lua_pushinteger(L,mval.class_value);
1492 lua_pushinteger(L,mval.family_value);
1493 lua_pushinteger(L,mval.character_value);
1494 return 3;
1499 static int setdelcode(lua_State * L)
1501 int ch;
1502 halfword sfval, scval, lfval, lcval;
1503 int level = cur_level;
1504 int n = lua_gettop(L);
1505 int f = 1;
1506 if (n>1 && lua_type(L,1) == LUA_TTABLE)
1507 f++;
1508 if (n>2 && (lua_type(L,f) == LUA_TSTRING)) {
1509 const char *s = lua_tostring(L, f);
1510 if (lua_key_eq(s,global)) {
1511 level = level_one;
1512 f++;
1515 if (n-f!=1 || lua_type(L,f+1) != LUA_TTABLE) {
1516 luaL_error(L, "Bad arguments for tex.setdelcode()");
1518 ch = luaL_checkinteger(L, -2);
1519 check_char_range(ch, "setdelcode", 65536*17);
1520 lua_rawgeti(L, -1, 1);
1521 sfval = (halfword) luaL_checkinteger(L, -1);
1522 lua_rawgeti(L, -2, 2);
1523 scval = (halfword) luaL_checkinteger(L, -1);
1524 lua_rawgeti(L, -3, 3);
1525 lfval = (halfword) luaL_checkinteger(L, -1);
1526 lua_rawgeti(L, -4, 4);
1527 lcval = (halfword) luaL_checkinteger(L, -1);
1528 lua_pop(L,4);
1530 check_char_range(sfval, "setdelcode", 256);
1531 check_char_range(scval, "setdelcode", 65536*17);
1532 check_char_range(lfval, "setdelcode", 256);
1533 check_char_range(lcval, "setdelcode", 65536*17);
1534 set_del_code(ch, sfval, scval, lfval, lcval, (quarterword) (level));
1536 return 0;
1542 [global] code { c f ch }
1543 [global] code c f ch (a bit easier on memory, counterpart of getter)
1546 static int setdelcode(lua_State * L)
1548 int ch;
1549 halfword sfval, scval, lfval, lcval;
1550 int level = cur_level;
1551 int f = 1;
1552 if (lua_type(L,1) == LUA_TSTRING) {
1553 const char *s = lua_tostring(L,1);
1554 if (lua_key_eq(s,global)) {
1555 level = level_one;
1556 f = 2;
1559 ch = luaL_checkinteger(L, f);
1560 check_char_range(ch, "setdelcode", 65536*17);
1561 f += 1;
1562 if (lua_type(L,f) == LUA_TNUMBER) {
1563 sfval = luaL_checkinteger(L, f);
1564 scval = luaL_checkinteger(L, f+1);
1565 lfval = luaL_checkinteger(L, f+2);
1566 lcval = luaL_checkinteger(L, f+3);
1567 } else if (lua_type(L,f) == LUA_TTABLE) {
1568 lua_rawgeti(L, f, 1);
1569 sfval = (halfword) luaL_checkinteger(L, -1);
1570 lua_rawgeti(L, f, 2);
1571 scval = (halfword) luaL_checkinteger(L, -1);
1572 lua_rawgeti(L, f, 3);
1573 lfval = (halfword) luaL_checkinteger(L, -1);
1574 lua_rawgeti(L, f, 4);
1575 lcval = (halfword) luaL_checkinteger(L, -1);
1576 lua_pop(L,4);
1577 } else {
1578 luaL_error(L, "Bad arguments for tex.setdelcode()");
1579 return 0;
1581 check_char_range(sfval, "setdelcode", 256);
1582 check_char_range(scval, "setdelcode", 65536*17);
1583 check_char_range(lfval, "setdelcode", 256);
1584 check_char_range(lcval, "setdelcode", 65536*17);
1585 set_del_code(ch, sfval, scval, lfval, lcval, (quarterword) (level));
1586 return 0;
1589 static int getdelcode(lua_State * L)
1591 delcodeval mval = { 0, 0, 0, 0, 0 };
1592 int ch = luaL_checkinteger(L, -1);
1593 check_char_range(ch, "getdelcode", 65536*17);
1594 mval = get_del_code(ch);
1595 lua_newtable(L);
1596 lua_pushinteger(L,mval.small_family_value);
1597 lua_rawseti(L, -2, 1);
1598 lua_pushinteger(L,mval.small_character_value);
1599 lua_rawseti(L, -2, 2);
1600 lua_pushinteger(L,mval.large_family_value);
1601 lua_rawseti(L, -2, 3);
1602 lua_pushinteger(L,mval.large_character_value);
1603 lua_rawseti(L, -2, 4);
1604 return 1;
1607 static int getdelcodes(lua_State * L)
1609 delcodeval mval = { 0, 0, 0, 0, 0 };
1610 int ch = luaL_checkinteger(L, -1);
1611 check_char_range(ch, "getdelcodes", 65536*17);
1612 mval = get_del_code(ch);
1613 lua_pushinteger(L,mval.small_family_value);
1614 lua_pushinteger(L,mval.small_character_value);
1615 lua_pushinteger(L,mval.large_family_value);
1616 lua_pushinteger(L,mval.large_character_value);
1617 return 4;
1620 static int settex(lua_State * L)
1622 const char *st;
1623 int texstr;
1624 size_t k;
1625 int cur_cs1, cur_cmd1;
1626 int isglobal = 0;
1627 int j = 0;
1628 int i = lua_gettop(L);
1629 if (lua_type(L,i-1) == LUA_TSTRING) {
1630 st = lua_tolstring(L, (i - 1), &k);
1631 if (lua_key_eq(st,prevdepth)) {
1632 if (lua_type(L, i) == LUA_TNUMBER) {
1633 cur_list.prev_depth_field = lua_roundnumber(L, i);
1634 } else if (lua_type(L, i) == LUA_TSTRING) {
1635 cur_list.prev_depth_field = dimen_to_number(L, lua_tostring(L, i));
1636 } else {
1637 luaL_error(L, "unsupported value type");
1639 return 0;
1640 } else if (lua_key_eq(st,prevgraf)) {
1641 if (lua_type(L, i) == LUA_TNUMBER) {
1642 cur_list.pg_field = lua_tointeger(L, i);
1643 } else {
1644 luaL_error(L, "unsupported value type");
1646 return 0;
1647 } else if (lua_key_eq(st,spacefactor)) {
1648 if (lua_type(L, i) == LUA_TNUMBER) {
1649 cur_list.space_factor_field = lua_roundnumber(L, i);
1650 } else {
1651 luaL_error(L, "unsupported value type");
1653 return 0;
1655 texstr = maketexlstring(st, k);
1656 if (is_primitive(texstr)) {
1657 if (i == 3 && (lua_type(L,1) == LUA_TSTRING)) {
1658 const char *s = lua_tostring(L, 1);
1659 if (lua_key_eq(s,global))
1660 isglobal = 1;
1662 cur_cs1 = string_lookup(st, k);
1663 flush_str(texstr);
1664 cur_cmd1 = eq_type(cur_cs1);
1665 if (is_int_assign(cur_cmd1)) {
1666 if (lua_type(L, i) == LUA_TNUMBER) {
1667 int luai = lua_tointeger(L, i);
1668 assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), luai);
1669 } else {
1670 luaL_error(L, "unsupported value type");
1672 } else if (is_dim_assign(cur_cmd1)) {
1673 if (lua_type(L, i) == LUA_TNUMBER) {
1674 j = lua_roundnumber(L, i);
1675 } else if (lua_type(L, i) == LUA_TSTRING) {
1676 j = dimen_to_number(L, lua_tostring(L, i));
1677 } else {
1678 luaL_error(L, "unsupported value type");
1680 assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), j);
1681 } else if (is_glue_assign(cur_cmd1)) {
1682 int a = isglobal;
1683 if (lua_type(L, i) == LUA_TNUMBER) {
1684 halfword value = copy_node(zero_glue);
1685 width(value) = lua_roundnumber(L,i);
1686 if (i > 1) { stretch(value) = lua_roundnumber(L,i+1); }
1687 if (i > 3) { shrink(value) = lua_roundnumber(L,i+2); }
1688 if (i > 4) { stretch_order(value) = lua_tointeger(L,i+3); }
1689 if (i > 5) { shrink_order(value) = lua_tointeger(L,i+4); }
1690 define(equiv(cur_cs1), assign_glue_cmd, value);
1691 } else {
1692 halfword *j1 = check_isnode(L, i); /* the value */
1693 define(equiv(cur_cs1), assign_glue_cmd, *j1);
1695 } else if (is_toks_assign(cur_cmd1)) {
1696 if (lua_type(L,i) == LUA_TSTRING) {
1697 j = tokenlist_from_lua(L); /* uses stack -1 */
1698 assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), j);
1700 } else {
1701 luaL_error(L, "unsupported value type");
1704 } else if (lua_istable(L, (i - 2))) {
1706 people may want to add keys that are also primitives |tex.wd| for example)
1707 so creating an error is not right here
1709 lua_rawset(L, (i - 2));
1711 } else if (lua_istable(L, (i - 2))) {
1712 lua_rawset(L, (i - 2));
1714 } else if (lua_istable(L, (i - 2))) {
1715 lua_rawset(L, (i - 2));
1717 return 0;
1720 /* todo: some will to the pdf namespace .. ignore > 31 */
1722 static int do_convert(lua_State * L, int cur_code)
1724 int texstr;
1725 int i = -1;
1726 char *str = NULL;
1727 switch (cur_code) {
1728 /* ignored (yet) */
1730 case insert_ht_code: /* arg <register int> */
1731 case lua_code: /* arg complex */
1732 case lua_escape_string_code: /* arg token list */
1733 case left_margin_kern_code: /* arg box */
1734 case right_margin_kern_code: /* arg box */
1735 case string_code: /* arg token */
1736 case cs_string_code: /* arg token */
1737 case meaning_code: /* arg token */
1738 break;
1740 /* the next fall through, and come from 'official' indices! */
1742 case font_name_code: /* arg fontid */
1743 case font_identifier_code: /* arg fontid */
1744 case uniform_deviate_code: /* arg int */
1745 case number_code: /* arg int */
1746 case roman_numeral_code: /* arg int */
1748 if (lua_gettop(L) < 1) {
1749 /* error */
1751 i = lua_tointeger(L, 1);
1753 /* these fall through! */
1755 default:
1756 /* no backend here */
1757 if (cur_code < 32) {
1758 texstr = the_convert_string(cur_code, i);
1759 if (texstr) {
1760 str = makecstring(texstr);
1761 flush_str(texstr);
1765 /* end */
1766 if (str) {
1767 lua_pushstring(L, str);
1768 free(str);
1769 } else {
1770 lua_pushnil(L);
1772 return 1;
1775 static int do_scan_internal(lua_State * L, int cur_cmd1, int cur_code, int values)
1777 int texstr;
1778 char *str = NULL;
1779 int save_cur_val, save_cur_val_level;
1780 save_cur_val = cur_val;
1781 save_cur_val_level = cur_val_level;
1782 scan_something_simple(cur_cmd1, cur_code);
1783 switch (cur_val_level) {
1784 case int_val_level:
1785 case dimen_val_level:
1786 case attr_val_level:
1787 lua_pushinteger(L, cur_val);
1788 break;
1789 case glue_val_level:
1790 case mu_val_level:
1791 if (values == 0) {
1792 lua_pushinteger(L,width(cur_val));
1793 } else if (values == 1) {
1794 lua_pushinteger(L,width(cur_val));
1795 lua_pushinteger(L,stretch(cur_val));
1796 lua_pushinteger(L,shrink(cur_val));
1797 lua_pushinteger(L,stretch_order(cur_val));
1798 lua_pushinteger(L,shrink_order(cur_val));
1799 return 5;
1800 } else {
1801 lua_nodelib_push_fast(L, cur_val);
1803 break;
1804 default:
1805 texstr = the_scanned_result();
1806 str = makecstring(texstr);
1807 if (str) {
1808 lua_pushstring(L, str);
1809 free(str);
1810 } else {
1811 lua_pushnil(L);
1813 flush_str(texstr);
1814 break;
1816 cur_val = save_cur_val;
1817 cur_val_level = save_cur_val_level;
1818 return 1;
1821 static int do_lastitem(lua_State * L, int cur_code)
1823 int retval = 1;
1824 switch (cur_code) {
1825 /* the next two do not actually exist */
1826 case lastattr_code:
1827 case attrexpr_code:
1828 lua_pushnil(L);
1829 break;
1830 /* the expressions do something complicated with arguments, yuck */
1831 case numexpr_code:
1832 case dimexpr_code:
1833 case glueexpr_code:
1834 case muexpr_code:
1835 lua_pushnil(L);
1836 break;
1837 /* these read a glue or muglue, todo */
1838 case mu_to_glue_code:
1839 case glue_to_mu_code:
1840 case glue_stretch_order_code:
1841 case glue_shrink_order_code:
1842 case glue_stretch_code:
1843 case glue_shrink_code:
1844 lua_pushnil(L);
1845 break;
1846 /* these read a fontid and a char, todo */
1847 case font_char_wd_code:
1848 case font_char_ht_code:
1849 case font_char_dp_code:
1850 case font_char_ic_code:
1851 lua_pushnil(L);
1852 break;
1853 /* these read an integer, todo */
1854 case par_shape_length_code:
1855 case par_shape_indent_code:
1856 case par_shape_dimen_code:
1857 lua_pushnil(L);
1858 break;
1859 case lastpenalty_code:
1860 case lastkern_code:
1861 case lastskip_code:
1862 case last_node_type_code:
1863 case input_line_no_code:
1864 case badness_code:
1865 case last_saved_box_resource_index_code:
1866 case last_saved_image_resource_index_code:
1867 case last_saved_image_resource_pages_code:
1868 case last_x_pos_code:
1869 case last_y_pos_code:
1870 case random_seed_code:
1871 case luatex_version_code:
1872 case eTeX_minor_version_code:
1873 case eTeX_version_code:
1874 case current_group_level_code:
1875 case current_group_type_code:
1876 case current_if_level_code:
1877 case current_if_type_code:
1878 case current_if_branch_code:
1879 retval = do_scan_internal(L, last_item_cmd, cur_code, -1);
1880 break;
1881 default:
1882 lua_pushnil(L);
1883 break;
1885 return retval;
1888 static int tex_setmathparm(lua_State * L)
1890 int i, j;
1891 int k;
1892 int l = cur_level;
1893 void *p;
1894 int n = lua_gettop(L);
1895 if ((n == 3) || (n == 4)) {
1896 if (n == 4 && (lua_type(L,1) == LUA_TSTRING)) {
1897 const char *s = lua_tostring(L, 1);
1898 if (lua_key_eq(s,global))
1899 l = 1;
1901 i = luaL_checkoption(L, (n - 2), NULL, math_param_names);
1902 j = luaL_checkoption(L, (n - 1), NULL, math_style_names);
1903 if (i<0 && i>=math_param_last) {
1904 /* invalid spec, just ignore it */
1905 } else if (i>=math_param_first_mu_glue) {
1906 p = lua_touserdata(L, n);
1907 k = *((halfword *)p);
1908 def_math_param(i, j, (scaled) k, l);
1909 } else if (lua_type(L, n) == LUA_TNUMBER) {
1910 k = lua_roundnumber(L, n);
1911 def_math_param(i, j, (scaled) k, l);
1912 } else {
1913 luaL_error(L, "argument must be a number");
1916 return 0;
1919 static int tex_getmathparm(lua_State * L)
1921 if ((lua_gettop(L) == 2)) {
1922 int i = luaL_checkoption(L, 1, NULL, math_param_names);
1923 int j = luaL_checkoption(L, 2, NULL, math_style_names);
1924 scaled k = get_math_param(i, j);
1925 if (i<0 && i>=math_param_last) {
1926 lua_pushnil(L);
1927 } else if (i>=math_param_first_mu_glue) {
1928 if (k <= thick_mu_skip_code) {
1929 k = glue_par(k);
1931 lua_nodelib_push_fast(L, k);
1932 } else {
1933 lua_pushinteger(L, k);
1936 return 1;
1939 static int getfontname(lua_State * L)
1941 return do_convert(L, font_name_code);
1944 static int getfontidentifier(lua_State * L)
1946 return do_convert(L, font_identifier_code);
1949 static int getuniformdeviate(lua_State * L)
1951 return do_convert(L, uniform_deviate_code);
1954 static int getnumber(lua_State * L)
1956 return do_convert(L, number_code);
1959 static int getromannumeral(lua_State * L)
1961 return do_convert(L, roman_numeral_code);
1964 static int get_parshape(lua_State * L)
1966 halfword par_shape_ptr = par_shape_par_ptr;
1967 if (par_shape_ptr != 0) {
1968 int m = 1;
1969 int n = vinfo(par_shape_ptr + 1);
1970 lua_createtable(L, n, 0);
1971 while (m <= n) {
1972 lua_createtable(L, 2, 0);
1973 lua_pushinteger(L, vlink((par_shape_ptr) + (2 * (m - 1)) + 2));
1974 lua_rawseti(L, -2, 1);
1975 lua_pushinteger(L, vlink((par_shape_ptr) + (2 * (m - 1)) + 3));
1976 lua_rawseti(L, -2, 2);
1977 lua_rawseti(L, -2, m);
1978 m++;
1980 } else {
1981 lua_pushnil(L);
1983 return 1;
1986 static int gettex(lua_State * L)
1988 int cur_cs1 = -1;
1989 int retval = 1; /* default is to return nil */
1990 int t = lua_gettop(L);
1991 int b = -1 ;
1992 if (t > 1 && lua_type(L,t) == LUA_TBOOLEAN) {
1994 0 == flush width only
1995 1 == flush all glue parameters
1997 b = lua_toboolean(L,t);
1998 t = t - 1;
2000 if (lua_type(L,t) == LUA_TSTRING) {
2002 1 == tex
2003 2 == boxmaxdepth
2005 1 == boxmaxdepth
2007 int texstr;
2008 size_t k;
2009 const char *st = lua_tolstring(L, t, &k);
2010 if (lua_key_eq(st,prevdepth)) {
2011 lua_pushinteger(L, cur_list.prev_depth_field);
2012 return 1;
2013 } else if (lua_key_eq(st,prevgraf)) {
2014 lua_pushinteger(L, cur_list.pg_field);
2015 return 1;
2016 } else if (lua_key_eq(st,spacefactor)) {
2017 lua_pushinteger(L, cur_list.space_factor_field);
2018 return 1;
2020 texstr = maketexlstring(st, k);
2021 cur_cs1 = prim_lookup(texstr); /* not found == relax == 0 */
2022 flush_str(texstr);
2024 if (cur_cs1 > 0) {
2025 int cur_cmd1 = get_prim_eq_type(cur_cs1);
2026 int cur_code = get_prim_equiv(cur_cs1);
2027 switch (cur_cmd1) {
2028 case last_item_cmd:
2029 retval = do_lastitem(L, cur_code);
2030 break;
2031 case convert_cmd:
2032 retval = do_convert(L, cur_code);
2033 break;
2034 case assign_toks_cmd:
2035 case assign_int_cmd:
2036 case assign_attr_cmd:
2037 case assign_dir_cmd:
2038 case assign_dimen_cmd:
2039 case set_aux_cmd:
2040 case set_prev_graf_cmd:
2041 case set_page_int_cmd:
2042 case set_page_dimen_cmd:
2043 case char_given_cmd:
2044 case math_given_cmd:
2045 retval = do_scan_internal(L, cur_cmd1, cur_code, -1);
2046 break;
2047 case assign_glue_cmd:
2048 case assign_mu_glue_cmd:
2049 retval = do_scan_internal(L, cur_cmd1, cur_code, b);
2050 break;
2051 case set_tex_shape_cmd:
2052 retval = get_parshape(L);
2053 break;
2054 default:
2055 lua_pushnil(L);
2056 break;
2058 } else if ((t == 2) && (lua_type(L,2) == LUA_TSTRING)) {
2059 lua_rawget(L, 1);
2061 return retval;
2064 static int getlist(lua_State * L)
2066 const char *str;
2067 if (lua_type(L,2) == LUA_TSTRING) {
2068 str = lua_tostring(L, 2);
2069 if (lua_key_eq(str,page_ins_head)) {
2070 if (vlink(page_ins_head) == page_ins_head)
2071 lua_pushinteger(L, null);
2072 else
2073 lua_pushinteger(L, vlink(page_ins_head));
2074 lua_nodelib_push(L);
2075 } else if (lua_key_eq(str,contrib_head)) {
2076 alink(vlink(contrib_head)) = null ;
2077 lua_pushinteger(L, vlink(contrib_head));
2078 lua_nodelib_push(L);
2079 } else if (lua_key_eq(str,page_discards_head)) {
2080 alink(vlink(page_disc)) = null ;
2081 lua_pushinteger(L, page_disc);
2082 lua_nodelib_push(L);
2083 } else if (lua_key_eq(str,split_discards_head)) {
2084 alink(vlink(split_disc)) = null ;
2085 lua_pushinteger(L, split_disc);
2086 lua_nodelib_push(L);
2087 } else if (lua_key_eq(str,page_head)) {
2088 alink(vlink(page_head)) = null ;/*hh-ls */
2089 lua_pushinteger(L, vlink(page_head));
2090 lua_nodelib_push(L);
2091 } else if (lua_key_eq(str,temp_head)) {
2092 alink(vlink(temp_head)) = null ;/*hh-ls */
2093 lua_pushinteger(L, vlink(temp_head));
2094 lua_nodelib_push(L);
2095 } else if (lua_key_eq(str,hold_head)) {
2096 alink(vlink(hold_head)) = null ;/*hh-ls */
2097 lua_pushinteger(L, vlink(hold_head));
2098 lua_nodelib_push(L);
2099 } else if (lua_key_eq(str,adjust_head)) {
2100 alink(vlink(adjust_head)) = null ;/*hh-ls */
2101 lua_pushinteger(L, vlink(adjust_head));
2102 lua_nodelib_push(L);
2103 } else if (lua_key_eq(str,best_page_break)) {
2104 lua_pushinteger(L, best_page_break);
2105 lua_nodelib_push(L);
2106 } else if (lua_key_eq(str,least_page_cost)) {
2107 lua_pushinteger(L, least_page_cost);
2108 } else if (lua_key_eq(str,best_size)) {
2109 lua_pushinteger(L, best_size);
2110 } else if (lua_key_eq(str,pre_adjust_head)) {
2111 alink(vlink(pre_adjust_head)) = null ;/*hh-ls */
2112 lua_pushinteger(L, vlink(pre_adjust_head));
2113 lua_nodelib_push(L);
2114 } else if (lua_key_eq(str,align_head)) {
2115 alink(vlink(align_head)) = null ;/*hh-ls */
2116 lua_pushinteger(L, vlink(align_head));
2117 lua_nodelib_push(L);
2118 } else {
2119 lua_pushnil(L);
2121 } else {
2122 lua_pushnil(L);
2124 return 1;
2127 static int setlist(lua_State * L)
2129 if (lua_type(L,2) == LUA_TSTRING) {
2130 const char *str = lua_tostring(L, 2);
2131 if (lua_key_eq(str,best_size)) {
2132 best_size = (int) lua_tointeger(L, 3);
2133 } else if (lua_key_eq(str,least_page_cost)) {
2134 least_page_cost = (int) lua_tointeger(L, 3);
2135 } else {
2136 halfword *n_ptr;
2137 halfword n = 0;
2138 if (!lua_isnil(L, 3)) {
2139 n_ptr = check_isnode(L, 3);
2140 n = *n_ptr;
2142 if (lua_key_eq(str,page_ins_head)) {
2143 if (n == 0) {
2144 vlink(page_ins_head) = page_ins_head;
2145 } else {
2146 halfword m;
2147 vlink(page_ins_head) = n;
2148 m = tail_of_list(n);
2149 vlink(m) = page_ins_head;
2151 } else if (lua_key_eq(str,contrib_head)) {
2152 vlink(contrib_head) = n;
2153 if (n == 0) {
2154 contrib_tail = contrib_head;
2156 } else if (lua_key_eq(str,best_page_break)) {
2157 best_page_break = n;
2158 } else if (lua_key_eq(str,page_head)) {
2159 vlink(page_head) = n;
2160 page_tail = (n == 0 ? page_head : tail_of_list(n));
2161 } else if (lua_key_eq(str,temp_head)) {
2162 vlink(temp_head) = n;
2163 } else if (lua_key_eq(str,page_discards_head)) {
2164 page_disc = n;
2165 } else if (lua_key_eq(str,split_discards_head)) {
2166 split_disc = n;
2167 } else if (lua_key_eq(str,hold_head)) {
2168 vlink(hold_head) = n;
2169 } else if (lua_key_eq(str,adjust_head)) {
2170 vlink(adjust_head) = n;
2171 adjust_tail = (n == 0 ? adjust_head : tail_of_list(n));
2172 } else if (lua_key_eq(str,pre_adjust_head)) {
2173 vlink(pre_adjust_head) = n;
2174 pre_adjust_tail = (n == 0 ? pre_adjust_head : tail_of_list(n));
2175 } else if (lua_key_eq(str,align_head)) {
2176 vlink(align_head) = n;
2180 return 0;
2183 #define NEST_METATABLE "luatex.nest"
2185 static int lua_nest_getfield(lua_State * L)
2187 list_state_record *r, **rv = lua_touserdata(L, -2);
2188 const char *field = lua_tostring(L, -1);
2189 r = *rv;
2190 if (lua_key_eq(field,mode)) {
2191 lua_pushinteger(L, r->mode_field);
2192 } else if (lua_key_eq(field,head)) {
2193 lua_nodelib_push_fast(L, r->head_field);
2194 } else if (lua_key_eq(field,tail)) {
2195 lua_nodelib_push_fast(L, r->tail_field);
2196 } else if (lua_key_eq(field,delimptr)) {
2197 lua_pushinteger(L, r->eTeX_aux_field);
2198 lua_nodelib_push(L);
2199 } else if (lua_key_eq(field,prevgraf)) {
2200 lua_pushinteger(L, r->pg_field);
2201 } else if (lua_key_eq(field,modeline)) {
2202 lua_pushinteger(L, r->ml_field);
2203 } else if (lua_key_eq(field,prevdepth)) {
2204 lua_pushinteger(L, r->prev_depth_field);
2205 } else if (lua_key_eq(field,spacefactor)) {
2206 lua_pushinteger(L, r->space_factor_field);
2207 } else if (lua_key_eq(field,noad)) {
2208 lua_pushinteger(L, r->incompleat_noad_field);
2209 lua_nodelib_push(L);
2210 } else if (lua_key_eq(field,dirs)) {
2211 lua_pushinteger(L, r->dirs_field);
2212 lua_nodelib_push(L);
2213 } else if (lua_key_eq(field,mathdir)) {
2214 lua_pushboolean(L, r->math_field);
2215 } else if (lua_key_eq(field,mathstyle)) {
2216 lua_pushinteger(L, r->math_style_field);
2217 } else {
2218 lua_pushnil(L);
2220 return 1;
2223 static int lua_nest_setfield(lua_State * L)
2225 halfword *n;
2226 int i;
2227 list_state_record *r, **rv = lua_touserdata(L, -3);
2228 const char *field = lua_tostring(L, -2);
2229 r = *rv;
2230 if (lua_key_eq(field,mode)) {
2231 i = lua_tointeger(L, -1);
2232 r->mode_field = i;
2233 } else if (lua_key_eq(field,head)) {
2234 n = check_isnode(L, -1);
2235 r->head_field = *n;
2236 } else if (lua_key_eq(field,tail)) {
2237 n = check_isnode(L, -1);
2238 r->tail_field = *n;
2239 } else if (lua_key_eq(field,delimptr)) {
2240 n = check_isnode(L, -1);
2241 r->eTeX_aux_field = *n;
2242 } else if (lua_key_eq(field,prevgraf)) {
2243 i = lua_tointeger(L, -1);
2244 r->pg_field = i;
2245 } else if (lua_key_eq(field,modeline)) {
2246 i = lua_tointeger(L, -1);
2247 r->ml_field = i;
2248 } else if (lua_key_eq(field,prevdepth)) {
2249 i = lua_roundnumber(L, -1);
2250 r->prev_depth_field = i;
2251 } else if (lua_key_eq(field,spacefactor)) {
2252 i = lua_roundnumber(L, -1);
2253 r->space_factor_field = i;
2254 } else if (lua_key_eq(field,noad)) {
2255 n = check_isnode(L, -1);
2256 r->incompleat_noad_field = *n;
2257 } else if (lua_key_eq(field,dirs)) {
2258 n = check_isnode(L, -1);
2259 r->dirs_field = *n;
2260 } else if (lua_key_eq(field,mathdir)) {
2261 r->math_field = lua_toboolean(L, -1);
2262 } else if (lua_key_eq(field,mathstyle)) {
2263 i = lua_tointeger(L, -1);
2264 r->math_style_field = i;
2266 return 0;
2269 static const struct luaL_Reg nest_m[] = {
2270 {"__index", lua_nest_getfield},
2271 {"__newindex", lua_nest_setfield},
2272 {NULL, NULL} /* sentinel */
2275 static void init_nest_lib(lua_State * L)
2277 luaL_newmetatable(L, NEST_METATABLE);
2278 luaL_register(L, NULL, nest_m);
2279 lua_pop(L, 1);
2282 static int getnest(lua_State * L)
2284 list_state_record **nestitem;
2285 int t = lua_type(L, 2);
2286 if (t == LUA_TNUMBER) {
2287 int ptr = lua_tointeger(L, 2);
2288 if (ptr >= 0 && ptr <= nest_ptr) {
2289 nestitem = lua_newuserdata(L, sizeof(list_state_record *));
2290 *nestitem = &nest[ptr];
2291 luaL_getmetatable(L, NEST_METATABLE);
2292 lua_setmetatable(L, -2);
2293 } else {
2294 lua_pushnil(L);
2296 } else if (t == LUA_TSTRING) {
2297 const char *s = lua_tostring(L, 2);
2298 if (lua_key_eq(s,ptr)) {
2299 lua_pushinteger(L, nest_ptr);
2300 } else {
2301 lua_pushnil(L);
2303 } else {
2304 lua_pushnil(L);
2306 return 1;
2309 static int setnest(lua_State * L)
2311 luaL_error(L, "You can't modify the semantic nest array directly");
2312 return 2;
2315 static int do_integer_error(double m)
2317 const char *help[] = {
2318 "I can only go up to 2147483647='17777777777=" "7FFFFFFF,",
2319 "so I'm using that number instead of yours.",
2320 NULL
2322 tex_error("Number too big", help);
2323 return (m > 0.0 ? infinity : -infinity);
2326 static int tex_roundnumber(lua_State * L)
2328 double m = (double) lua_tonumber(L, 1) + 0.5; /* integer or float */
2329 if (abs(m) > (double) infinity)
2330 lua_pushinteger(L, do_integer_error(m));
2331 else
2332 lua_pushinteger(L, floor(m));
2333 return 1;
2336 static int tex_scaletable(lua_State * L)
2338 double delta = luaL_checknumber(L, 2);
2339 if (lua_istable(L, 1)) {
2340 lua_newtable(L); /* the new table is at index 3 */
2341 lua_pushnil(L);
2342 while (lua_next(L, 1) != 0) { /* numeric value */
2343 lua_pushvalue(L, -2);
2344 lua_insert(L, -2);
2345 if (lua_type(L,-2) == LUA_TNUMBER) {
2346 double m = (double) lua_tonumber(L, -1) * delta + 0.5; /* integer or float */
2347 lua_pop(L, 1);
2348 if (abs(m) > (double) infinity)
2349 lua_pushinteger(L, do_integer_error(m));
2350 else
2351 lua_pushinteger(L, floor(m));
2353 lua_rawset(L, 3);
2355 } else if (lua_type(L,1) == LUA_TNUMBER) {
2356 double m = (double) lua_tonumber(L, 1) * delta + 0.5; /* integer or float */
2357 if (abs(m) > (double) infinity)
2358 lua_pushinteger(L, do_integer_error(m));
2359 else
2360 lua_pushinteger(L, floor(m));
2361 } else {
2362 lua_pushnil(L);
2364 return 1;
2367 #define hash_text(A) hash[(A)].rh
2369 static int tex_definefont(lua_State * L)
2371 const char *csname;
2372 int f, u;
2373 str_number t;
2374 size_t l;
2375 int i = 1;
2376 int a = 0;
2377 if (!no_new_control_sequence) {
2378 const char *help[] = { "You can't create a new font inside a \\csname\\endcsname pair", NULL };
2379 tex_error("Definition active", help);
2381 if ((lua_gettop(L) == 3) && lua_isboolean(L, 1)) {
2382 a = lua_toboolean(L, 1);
2383 i = 2;
2385 csname = luaL_checklstring(L, i, &l);
2386 f = luaL_checkinteger(L, (i + 1));
2387 t = maketexlstring(csname, l);
2388 no_new_control_sequence = 0;
2389 u = string_lookup(csname, l);
2390 no_new_control_sequence = 1;
2391 if (a)
2392 geq_define(u, set_font_cmd, f);
2393 else
2394 eq_define(u, set_font_cmd, f);
2395 eqtb[font_id_base + f] = eqtb[u];
2396 hash_text(font_id_base + f) = t;
2397 return 0;
2401 static int tex_hashpairs(lua_State * L)
2403 int cmd, chr;
2404 str_number s = 0;
2405 int cs = 1;
2406 lua_newtable(L);
2407 while (cs < hash_size) {
2408 s = hash_text(cs);
2409 if (s > 0) {
2410 char *ss = makecstring(s);
2411 lua_pushstring(L, ss);
2412 free(ss);
2413 cmd = eq_type(cs);
2414 chr = equiv(cs);
2415 make_token_table(L, cmd, chr, cs);
2416 lua_rawset(L, -3);
2417 cs++;
2420 return 1;
2423 static int tex_primitives(lua_State * L)
2425 int cmd, chr;
2426 str_number s = 0;
2427 int cs = 0;
2428 lua_newtable(L);
2429 while (cs < prim_size) {
2430 s = get_prim_text(cs);
2431 if (s > 0) {
2432 char *ss = makecstring(s);
2433 lua_pushstring(L, ss);
2434 free(ss);
2435 cmd = get_prim_eq_type(cs);
2436 chr = get_prim_equiv(cs);
2437 make_token_table(L, cmd, chr, 0);
2438 lua_rawset(L, -3);
2440 cs++;
2442 return 1;
2445 static int tex_extraprimitives(lua_State * L)
2447 int n, i;
2448 int mask = 0;
2449 int cs = 0;
2450 n = lua_gettop(L);
2451 if (n == 0) {
2452 mask = etex_command + luatex_command;
2453 } else {
2454 for (i = 1; i <= n; i++) {
2455 if (lua_type(L,i) == LUA_TSTRING) {
2456 const char *s = lua_tostring(L, i);
2457 if (lua_key_eq(s,etex)) {
2458 mask |= etex_command;
2459 } else if (lua_key_eq(s,tex)) {
2460 mask |= tex_command;
2461 } else if (lua_key_eq(s,core)) {
2462 mask |= core_command;
2463 } else if (lua_key_eq(s,luatex)) {
2464 mask |= luatex_command;
2469 lua_newtable(L);
2470 i = 1;
2471 while (cs < prim_size) {
2472 str_number s = 0;
2473 s = get_prim_text(cs);
2474 if (s > 0) {
2475 if (get_prim_origin(cs) & mask) {
2476 char *ss = makecstring(s);
2477 lua_pushstring(L, ss);
2478 free(ss);
2479 lua_rawseti(L, -2, i++);
2482 cs++;
2484 return 1;
2489 static int tex_hashpairs(lua_State * L)
2491 str_number s = 0;
2492 int cs = 1;
2493 int nt = 0;
2494 lua_newtable(L);
2495 while (cs < hash_size) {
2496 s = hash_text(cs);
2497 if (s > 0) {
2498 char *ss = makecstring(s);
2499 lua_pushstring(L, ss);
2500 free(ss);
2501 lua_rawseti(L, -2, ++nt);
2503 cs++;
2505 return 1;
2508 static int tex_primitives(lua_State * L)
2510 str_number s = 0;
2511 int cs = 0;
2512 int nt = 0;
2513 lua_newtable(L);
2514 while (cs < prim_size) {
2515 s = get_prim_text(cs);
2516 if (s > 0) {
2517 char *ss = makecstring(s);
2518 lua_pushstring(L, ss);
2519 free(ss);
2520 lua_rawseti(L, -2, ++nt);
2522 cs++;
2524 return 1;
2527 static int tex_extraprimitives(lua_State * L)
2529 int n, i;
2530 int mask = 0;
2531 int cs = 0;
2532 int nt = 0;
2533 n = lua_gettop(L);
2534 if (n == 0) {
2535 mask = etex_command + luatex_command;
2536 } else {
2537 for (i = 1; i <= n; i++) {
2538 if (lua_type(L,i) == LUA_TSTRING) {
2539 const char *s = lua_tostring(L, i);
2540 if (lua_key_eq(s,etex)) {
2541 mask |= etex_command;
2542 } else if (lua_key_eq(s,tex)) {
2543 mask |= tex_command;
2544 } else if (lua_key_eq(s,core)) {
2545 mask |= core_command;
2546 } else if (lua_key_eq(s,luatex)) {
2547 mask |= luatex_command;
2552 lua_newtable(L);
2553 while (cs < prim_size) {
2554 str_number s = 0;
2555 s = get_prim_text(cs);
2556 if (s > 0) {
2557 if (get_prim_origin(cs) & mask) {
2558 char *ss = makecstring(s);
2559 lua_pushstring(L, ss);
2560 free(ss);
2561 lua_rawseti(L, -2, ++nt);
2564 cs++;
2566 return 1;
2569 static int tex_enableprimitives(lua_State * L)
2571 int n = lua_gettop(L);
2572 if (n != 2) {
2573 luaL_error(L, "wrong number of arguments");
2574 } else {
2575 size_t l;
2576 int i;
2577 const char *pre = luaL_checklstring(L, 1, &l);
2578 if (lua_istable(L, 2)) {
2579 int nncs = no_new_control_sequence;
2580 no_new_control_sequence = true;
2581 i = 1;
2582 while (1) {
2583 lua_rawgeti(L, 2, i);
2584 if (lua_type(L,3) == LUA_TSTRING) {
2585 const char *prim = lua_tostring(L, 3);
2586 str_number s = maketexstring(prim);
2587 halfword prim_val = prim_lookup(s);
2588 if (prim_val != undefined_primitive) {
2589 char *newprim;
2590 int val;
2591 size_t newl;
2592 halfword cur_cmd1 = get_prim_eq_type(prim_val);
2593 halfword cur_chr1 = get_prim_equiv(prim_val);
2594 if (strncmp(pre, prim, l) != 0) { /* not a prefix */
2595 newl = strlen(prim) + l;
2596 newprim = (char *) xmalloc((unsigned) (newl + 1));
2597 strcpy(newprim, pre);
2598 strcat(newprim + l, prim);
2599 } else {
2600 newl = strlen(prim);
2601 newprim = (char *) xmalloc((unsigned) (newl + 1));
2602 strcpy(newprim, prim);
2604 val = string_lookup(newprim, newl);
2605 if (val == undefined_control_sequence ||
2606 eq_type(val) == undefined_cs_cmd) {
2607 primitive_def(newprim, newl, (quarterword) cur_cmd1, cur_chr1);
2609 free(newprim);
2611 flush_str(s);
2612 } else {
2613 lua_pop(L, 1);
2614 break;
2616 lua_pop(L, 1);
2617 i++;
2619 lua_pop(L, 1); /* the table */
2620 no_new_control_sequence = nncs;
2621 } else {
2622 luaL_error(L, "Expected an array of names as second argument");
2625 return 0;
2628 #define get_int_par(A,B) do { \
2629 lua_key_rawgeti(A); \
2630 if (lua_type(L, -1) == LUA_TNUMBER) { \
2631 A = (int) lua_tointeger(L, -1); \
2632 } else { \
2633 A = (B); \
2635 lua_pop(L,1); \
2636 } while (0)
2638 #define get_intx_par(A,B,C,D) do { \
2639 lua_key_rawgeti(A); \
2640 if (lua_type(L, -1) == LUA_TNUMBER) { \
2641 A = (int) lua_tointeger(L, -1); \
2642 C = null; \
2643 } else if (lua_type(L, -1) == LUA_TTABLE){ \
2644 A = 0; \
2645 C = nodelib_topenalties(L, lua_gettop(L)); \
2646 } else { \
2647 A = (B); \
2648 C = (D); \
2650 lua_pop(L,1); \
2651 } while (0)
2653 #define get_dimen_par(A,B) do { \
2654 lua_key_rawgeti(A); \
2655 if (lua_type(L, -1) == LUA_TNUMBER) { \
2656 A = (int) lua_tointeger(L, -1); \
2657 } else { \
2658 A = (B); \
2660 lua_pop(L,1); \
2661 } while (0)
2663 #define get_glue_par(A,B) do { \
2664 lua_key_rawgeti(A); \
2665 if (lua_type(L, -1) != LUA_TNIL) { \
2666 A = *check_isnode(L, -1); \
2667 } else { \
2668 A = (B); \
2670 lua_pop(L,1); \
2671 } while (0)
2673 static halfword nodelib_toparshape(lua_State * L, int i)
2675 halfword p;
2676 int n = 0;
2677 int width, indent, j;
2678 /* find |n| */
2679 lua_pushnil(L);
2680 while (lua_next(L, i) != 0) {
2681 n++;
2682 lua_pop(L, 1);
2684 if (n == 0)
2685 return null;
2686 p = new_node(shape_node, 2 * (n + 1) + 1);
2687 vinfo(p + 1) = n;
2688 /* fill |p| */
2689 lua_pushnil(L);
2690 j = 0;
2691 while (lua_next(L, i) != 0) {
2692 /* don't give an error for non-tables, we may add special syntaxes at some point */
2693 j++;
2694 if (lua_type(L, i) == LUA_TTABLE) {
2695 lua_rawgeti(L, -1, 1); /* indent */
2696 if (lua_type(L, -1) == LUA_TNUMBER) {
2697 indent = lua_roundnumber(L, -1);
2698 lua_pop(L, 1);
2699 lua_rawgeti(L, -1, 2); /* width */
2700 if (lua_type(L, -1) == LUA_TNUMBER) {
2701 width = lua_roundnumber(L, -1);
2702 lua_pop(L, 1);
2703 varmem[p + 2 * j].cint = indent;
2704 varmem[p + 2 * j + 1].cint = width;
2708 lua_pop(L, 1);
2710 return p;
2713 /* penalties */
2715 static halfword nodelib_topenalties(lua_State * L, int i)
2717 halfword p;
2718 int n = 0;
2719 int j;
2720 /* find |n| */
2721 lua_pushnil(L);
2722 while (lua_next(L, i) != 0) {
2723 n++;
2724 lua_pop(L, 1);
2726 if (n == 0)
2727 return null;
2728 p = new_node(shape_node, 2 * ((n / 2) + 1) + 1 + 1);
2729 vinfo(p + 1) = (n / 2) + 1;
2730 varmem[p + 2].cint = n;
2731 lua_pushnil(L);
2732 j = 2;
2733 while (lua_next(L, i) != 0) {
2734 j++;
2735 if (lua_type(L, -1) == LUA_TNUMBER) {
2736 int pen = lua_tointeger(L, -1);
2737 varmem[p+j].cint = pen;
2739 lua_pop(L, 1);
2741 if (!odd(n))
2742 varmem[p+j+1].cint = 0;
2743 return p;
2746 static int tex_run_linebreak(lua_State * L)
2749 halfword *j;
2750 halfword p;
2751 halfword final_par_glue;
2752 int paragraph_dir = 0;
2753 /* locally initialized parameters for line breaking */
2754 int pretolerance, tracingparagraphs, tolerance, looseness,
2755 adjustspacing, adjdemerits, protrudechars,
2756 linepenalty, lastlinefit, doublehyphendemerits, finalhyphendemerits,
2757 hangafter, interlinepenalty, widowpenalty, clubpenalty, brokenpenalty;
2758 halfword emergencystretch, hangindent, hsize, leftskip, rightskip,parshape;
2759 int fewest_demerits = 0, actual_looseness = 0;
2760 halfword clubpenalties, interlinepenalties, widowpenalties;
2761 int save_vlink_tmp_head;
2762 /* push a new nest level */
2763 push_nest();
2764 save_vlink_tmp_head = vlink(temp_head);
2766 j = check_isnode(L, 1); /* the value */
2767 vlink(temp_head) = *j;
2768 p = *j;
2769 if ((!is_char_node(vlink(*j))) && ((type(vlink(*j)) == local_par_node))) {
2770 paragraph_dir = local_par_dir(vlink(*j));
2773 while (vlink(p) != null)
2774 p = vlink(p);
2775 final_par_glue = p;
2777 /* initialize local parameters */
2779 if (lua_gettop(L) != 2 || lua_type(L, 2) != LUA_TTABLE) {
2780 lua_checkstack(L, 3);
2781 lua_newtable(L);
2783 lua_key_rawgeti(pardir);
2784 if (lua_type(L, -1) == LUA_TSTRING) {
2785 paragraph_dir = nodelib_getdir(L, -1, 1);
2787 lua_pop(L, 1);
2789 lua_key_rawgeti(parshape);
2790 if (lua_type(L, -1) == LUA_TTABLE) {
2791 parshape = nodelib_toparshape(L, lua_gettop(L));
2792 } else {
2793 parshape = equiv(par_shape_loc);
2795 lua_pop(L, 1);
2797 get_int_par (pretolerance, pretolerance_par);
2798 get_int_par (tracingparagraphs, tracing_paragraphs_par);
2799 get_int_par (tolerance, tolerance_par);
2800 get_int_par (looseness, looseness_par);
2801 get_int_par (adjustspacing, adjust_spacing_par);
2802 get_int_par (adjdemerits, adj_demerits_par);
2803 get_int_par (protrudechars, protrude_chars_par);
2804 get_int_par (linepenalty, line_penalty_par);
2805 get_int_par (lastlinefit, last_line_fit_par);
2806 get_int_par (doublehyphendemerits, double_hyphen_demerits_par);
2807 get_int_par (finalhyphendemerits, final_hyphen_demerits_par);
2808 get_int_par (hangafter, hang_after_par);
2809 get_intx_par (interlinepenalty,inter_line_penalty_par, interlinepenalties, equiv(inter_line_penalties_loc));
2810 get_intx_par (clubpenalty, club_penalty_par, clubpenalties, equiv(club_penalties_loc));
2811 get_intx_par (widowpenalty, widow_penalty_par, widowpenalties, equiv(widow_penalties_loc));
2812 get_int_par (brokenpenalty, broken_penalty_par);
2813 get_dimen_par(emergencystretch, emergency_stretch_par);
2814 get_dimen_par(hangindent, hang_indent_par);
2815 get_dimen_par(hsize, hsize_par);
2816 get_glue_par (leftskip, left_skip_par);
2817 get_glue_par (rightskip, right_skip_par);
2818 ext_do_line_break(paragraph_dir,
2819 pretolerance,
2820 tracingparagraphs,
2821 tolerance,
2822 emergencystretch,
2823 looseness,
2824 adjustspacing,
2825 parshape,
2826 adjdemerits,
2827 protrudechars,
2828 linepenalty,
2829 lastlinefit,
2830 doublehyphendemerits,
2831 finalhyphendemerits,
2832 hangindent,
2833 hsize,
2834 hangafter,
2835 leftskip,
2836 rightskip,
2837 interlinepenalties,
2838 interlinepenalty,
2839 clubpenalty,
2840 clubpenalties,
2841 widowpenalties,
2842 widowpenalty,
2843 brokenpenalty,
2844 final_par_glue);
2846 /* return the generated list, and its prevdepth */
2847 get_linebreak_info (&fewest_demerits, &actual_looseness) ;
2848 lua_nodelib_push_fast(L, vlink(cur_list.head_field));
2849 lua_newtable(L);
2850 lua_push_key(demerits);
2851 lua_pushinteger(L, fewest_demerits);
2852 lua_settable(L, -3);
2853 lua_push_key(looseness);
2854 lua_pushinteger(L, actual_looseness);
2855 lua_settable(L, -3);
2856 lua_push_key(prevdepth);
2857 lua_pushinteger(L, cur_list.prev_depth_field);
2858 lua_settable(L, -3);
2859 lua_push_key(prevgraf);
2860 lua_pushinteger(L, cur_list.pg_field);
2861 lua_settable(L, -3);
2863 /* restore nest stack */
2864 vlink(temp_head) = save_vlink_tmp_head;
2865 pop_nest();
2866 if (parshape != equiv(par_shape_loc))
2867 flush_node(parshape);
2868 return 2;
2871 static int tex_reset_paragraph(lua_State * L)
2873 (void) L;
2874 normal_paragraph();
2875 return 0;
2878 static int tex_shipout(lua_State * L)
2880 int boxnum = get_box_id(L, 1, true);
2881 ship_out(static_pdf, box(boxnum), SHIPPING_PAGE);
2882 box(boxnum) = null;
2883 return 0;
2886 static int tex_badness(lua_State * L)
2888 scaled t = lua_tointeger(L,1);
2889 scaled s = lua_tointeger(L,2);
2890 lua_pushinteger(L, badness(t,s));
2891 return 1;
2894 static int tex_run_boot(lua_State * L)
2896 int n = lua_gettop(L);
2897 const char *format = NULL;
2898 if (n >= 1) {
2899 ini_version = 0;
2900 format = luaL_checkstring(L, 1);
2901 } else {
2902 ini_version = 1;
2904 if (main_initialize()) { /* > 0 = failure */
2905 lua_pushboolean(L, 0); /* false */
2906 return 1;
2908 if (format) {
2909 if (!zopen_w_input(&fmt_file, format, DUMP_FORMAT, FOPEN_RBIN_MODE)) {
2910 lua_pushboolean(L, 0); /* false */
2911 return 1;
2913 if (!load_fmt_file(format)) {
2914 zwclose(fmt_file);
2915 lua_pushboolean(L, 0); /* false */
2916 return 1;
2918 zwclose(fmt_file);
2920 pdf_init_map_file("pdftex.map");
2921 /* */
2922 if (end_line_char_inactive)
2923 decr(ilimit);
2924 else
2925 buffer[ilimit] = (packed_ASCII_code) end_line_char_par;
2926 fix_date_and_time();
2927 random_seed = (microseconds * 1000) + (epochseconds % 1000000);
2928 init_randoms(random_seed);
2929 initialize_math();
2930 fixup_selector(log_opened_global);
2931 check_texconfig_init();
2932 text_dir_ptr = new_dir(0);
2933 history = spotless; /* ready to go! */
2934 /* Initialize synctex primitive */
2935 synctexinitcommand();
2936 /* tex is ready to go, now */
2937 unhide_lua_table(Luas, "tex", tex_table_id);
2938 unhide_lua_table(Luas, "pdf", pdf_table_id);
2939 unhide_lua_table(Luas, "token", token_table_id);
2940 unhide_lua_table(Luas, "node", node_table_id);
2942 lua_pushboolean(L, 1); /* true */
2943 return 1;
2946 /* tex random generators */
2948 static int tex_init_rand(lua_State * L)
2950 int sp;
2951 if (lua_type(L, 1) != LUA_TNUMBER) {
2952 luaL_error(L, "argument must be a number");
2953 return 0;
2955 sp = lua_roundnumber(L, 1);
2956 init_randoms(sp);
2957 return 0;
2960 static int tex_unif_rand(lua_State * L)
2962 int sp;
2963 if (lua_type(L, 1) != LUA_TNUMBER) {
2964 luaL_error(L, "argument must be a number");
2965 return 0;
2967 sp = lua_roundnumber(L, 1);
2968 lua_pushinteger(L, unif_rand(sp));
2969 return 1;
2972 static int tex_norm_rand(lua_State * L)
2974 lua_pushinteger(L, norm_rand());
2975 return 1;
2978 /* Same as lua but with tex rng */
2980 static int lua_math_random (lua_State *L)
2982 lua_Number rand_max = 0x7fffffff ;
2983 lua_Number r = unif_rand(rand_max) ;
2984 r = (r>=0 ? 0+r : 0-r) ;
2985 r = r / rand_max;
2986 switch (lua_gettop(L)) { /* check number of arguments */
2987 case 0: { /* no arguments */
2988 lua_pushnumber(L, r); /* float: [0, 1] */
2989 break;
2991 case 1: { /* only upper limit */
2992 lua_Number u = luaL_checknumber(L, 1);
2993 luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty");
2994 lua_pushnumber(L, floor(r*u) + (lua_Number)(1.0)); /* float: [1, u] */
2995 break;
2997 case 2: { /* lower and upper limits */
2998 lua_Number l = luaL_checknumber(L, 1);
2999 lua_Number u = luaL_checknumber(L, 2);
3000 luaL_argcheck(L, l <= u, 2, "interval is empty");
3001 lua_pushnumber(L, floor(r*(u-l+1)) + l); /* float: [l, u] */
3002 break;
3004 default:
3005 return luaL_error(L, "wrong number of arguments");
3007 return 1;
3010 static int tex_run_main(lua_State * L)
3012 (void) L;
3013 main_control();
3014 return 0;
3017 static int tex_run_end(lua_State * L)
3019 (void) L;
3020 final_cleanup(); /* prepare for death */
3021 close_files_and_terminate();
3022 do_final_end();
3023 return 0;
3026 static int tex_show_context(lua_State * L)
3028 (void) L;
3029 show_context();
3030 return 0;
3033 static int tex_save_box_resource(lua_State * L)
3035 halfword boxdata;
3036 int index = null;
3037 int attributes = null;
3038 int resources = null;
3039 int type = 0;
3040 boolean immediate = false;
3041 /* box attributes resources */
3042 halfword boxnumber = lua_tointeger(L,1);
3043 if (lua_type(L,2) == LUA_TSTRING) {
3044 lua_pushvalue(L, 2);
3045 attributes = luaL_ref(L, LUA_REGISTRYINDEX);
3047 if (lua_type(L,3) == LUA_TSTRING) {
3048 lua_pushvalue(L, 3);
3049 resources = luaL_ref(L, LUA_REGISTRYINDEX);
3051 if (lua_type(L,4) == LUA_TBOOLEAN) {
3052 immediate = lua_toboolean(L, 4);
3054 if (lua_type(L,5) == LUA_TNUMBER) {
3055 type = lua_tointeger(L, 5);
3057 /* more or less same as scanner variant */
3058 boxdata = box(boxnumber);
3059 if (boxdata == null)
3060 normal_error("pdf backend", "xforms cannot be used with a void box");
3061 static_pdf->xform_count++;
3062 index = pdf_create_obj(static_pdf, obj_type_xform, static_pdf->xform_count);
3063 set_obj_data_ptr(static_pdf, index, pdf_get_mem(static_pdf, pdfmem_xform_size));
3064 set_obj_xform_attr(static_pdf, index, null);
3065 set_obj_xform_attr_str(static_pdf, index, attributes);
3066 set_obj_xform_resources(static_pdf, index, null);
3067 set_obj_xform_resources_str(static_pdf, index, resources);
3068 set_obj_xform_box(static_pdf, index, (int) boxdata);
3069 set_obj_xform_width(static_pdf, index, width(boxdata));
3070 set_obj_xform_height(static_pdf, index, height(boxdata));
3071 set_obj_xform_depth(static_pdf, index, depth(boxdata));
3072 set_obj_xform_type(static_pdf, index, type);
3073 box(boxnumber) = null;
3074 last_saved_box_index = index;
3075 lua_pushinteger(L, index);
3076 if (immediate) {
3077 pdf_cur_form = last_saved_box_index;
3078 ship_out(static_pdf, obj_xform_box(static_pdf, last_saved_box_index), SHIPPING_FORM);
3080 return 1;
3083 static int tex_use_box_resource(lua_State * L)
3085 halfword rule;
3086 int index = 0;
3087 scaled_whd alt, nat, dim;
3088 if (lua_type(L,1) != LUA_TNUMBER) {
3089 lua_pushnil(L);
3090 lua_pushnil(L);
3091 lua_pushnil(L);
3092 lua_pushnil(L);
3093 } else {
3094 index = lua_tointeger(L,1);
3095 alt.wd = null_flag;
3096 alt.ht = null_flag;
3097 alt.dp = null_flag;
3098 if (lua_type(L,2) == LUA_TNUMBER) {
3099 alt.wd = (scaled) lua_roundnumber(L,2);
3101 if (lua_type(L,3) == LUA_TNUMBER) {
3102 alt.ht = (scaled) lua_roundnumber(L,3);
3104 if (lua_type(L,4) == LUA_TNUMBER) {
3105 alt.dp = (scaled) lua_roundnumber(L,4);
3107 /* sort of the same as backend */
3108 check_obj_type(static_pdf, obj_type_xform, index);
3109 nat.wd = obj_xform_width(static_pdf, index);
3110 nat.ht = obj_xform_height(static_pdf, index);
3111 nat.dp = obj_xform_depth(static_pdf, index);
3112 if (alt.wd != null_flag || alt.ht != null_flag || alt.dp != null_flag) {
3113 dim = tex_scale(nat, alt);
3114 } else {
3115 dim = nat;
3117 rule = new_rule(box_rule);
3118 rule_index(rule) = index;
3119 width(rule) = dim.wd;
3120 height(rule) = dim.ht;
3121 depth(rule) = dim.dp;
3122 nodelist_to_lua(L, rule);
3123 lua_pushinteger(L, (int) dim.wd);
3124 lua_pushinteger(L, (int) dim.ht);
3125 lua_pushinteger(L, (int) dim.dp);
3127 return 4;
3130 static int tex_get_box_resource_dimensions(lua_State * L)
3132 int index = 0;
3133 if (lua_type(L,1) != LUA_TNUMBER) {
3134 lua_pushnil(L);
3135 lua_pushnil(L);
3136 lua_pushnil(L);
3137 } else {
3138 index = lua_tointeger(L,1);
3139 check_obj_type(static_pdf, obj_type_xform, index);
3140 lua_pushinteger(L, (int) obj_xform_width(static_pdf, index));
3141 lua_pushinteger(L, (int) obj_xform_height(static_pdf, index));
3142 lua_pushinteger(L, (int) obj_xform_depth(static_pdf, index));
3144 return 3;
3147 static int tex_build_page(lua_State * L)
3149 build_page();
3150 return 0;
3153 void init_tex_table(lua_State * L)
3155 lua_createtable(L, 0, 3);
3156 lua_pushcfunction(L, tex_run_boot);
3157 lua_setfield(L, -2, "initialize");
3158 lua_pushcfunction(L, tex_run_main);
3159 lua_setfield(L, -2, "run");
3160 lua_pushcfunction(L, tex_run_end);
3161 lua_setfield(L, -2, "finish");
3162 lua_setglobal(L, "tex");
3165 static const struct luaL_Reg texlib[] = {
3166 { "run", tex_run_main }, /* may be needed */
3167 { "finish", tex_run_end }, /* may be needed */
3168 { "write", luacwrite },
3169 { "print", luacprint },
3170 { "tprint", luactprint },
3171 { "cprint", luaccprint },
3172 { "error", texerror },
3173 { "sprint", luacsprint },
3174 { "set", settex },
3175 { "get", gettex },
3176 { "isdimen", isdimen },
3177 { "setdimen", setdimen },
3178 { "getdimen", getdimen },
3179 { "isskip", isskip },
3180 { "setskip", setskip },
3181 { "getskip", getskip },
3182 { "setglue", setglue },
3183 { "getglue", getglue },
3184 { "ismuskip", ismuskip },
3185 { "setmuskip", setmuskip },
3186 { "getmuskip", getmuskip },
3187 { "setmuglue", setmuglue },
3188 { "getmuglue", getmuglue },
3189 { "isattribute", isattribute },
3190 { "setattribute", setattribute },
3191 { "getattribute", getattribute },
3192 { "iscount", iscount },
3193 { "setcount", setcount },
3194 { "getcount", getcount },
3195 { "istoks", istoks },
3196 { "settoks", settoks },
3197 { "scantoks", scantoks },
3198 { "gettoks", gettoks },
3199 { "isbox", isbox },
3200 { "setbox", setbox },
3201 { "getbox", getbox },
3202 { "splitbox", splitbox },
3203 { "setlist", setlist },
3204 { "getlist", getlist },
3205 { "setnest", setnest },
3206 { "getnest", getnest },
3207 { "setcatcode", setcatcode },
3208 { "getcatcode", getcatcode },
3209 { "setdelcode", setdelcode },
3210 { "getdelcode", getdelcode },
3211 { "getdelcodes", getdelcodes },
3212 { "setlccode", setlccode },
3213 { "getlccode", getlccode },
3214 { "setmathcode", setmathcode },
3215 { "getmathcode", getmathcode },
3216 { "getmathcodes", getmathcodes },
3217 { "setsfcode", setsfcode },
3218 { "getsfcode", getsfcode },
3219 { "setuccode", setuccode },
3220 { "getuccode", getuccode },
3221 { "round", tex_roundnumber },
3222 { "scale", tex_scaletable },
3223 { "sp", tex_scaledimen },
3224 { "fontname", getfontname },
3225 { "fontidentifier", getfontidentifier },
3226 { "uniformdeviate", getuniformdeviate },
3227 { "number", getnumber },
3228 { "romannumeral", getromannumeral },
3229 { "definefont", tex_definefont },
3230 { "hashtokens", tex_hashpairs },
3231 { "primitives", tex_primitives },
3232 { "extraprimitives", tex_extraprimitives },
3233 { "enableprimitives", tex_enableprimitives },
3234 { "shipout", tex_shipout },
3235 { "badness", tex_badness },
3236 { "setmath", tex_setmathparm },
3237 { "getmath", tex_getmathparm },
3238 { "linebreak", tex_run_linebreak },
3239 { "resetparagraph", tex_reset_paragraph },
3240 /* tex random generators */
3241 { "init_rand", tex_init_rand },
3242 { "uniform_rand",tex_unif_rand },
3243 { "normal_rand", tex_norm_rand },
3244 { "lua_math_randomseed", tex_init_rand }, /* syntactic sugar */
3245 { "lua_math_random", lua_math_random },
3246 { "show_context", tex_show_context },
3247 { "saveboxresource", tex_save_box_resource },
3248 { "useboxresource", tex_use_box_resource },
3249 { "getboxresourcedimensions", tex_get_box_resource_dimensions },
3250 /* just for testing: it will probably stay but maybe with options */
3251 { "triggerbuildpage", tex_build_page },
3252 /* sentinel */
3253 { NULL, NULL }
3256 int luaopen_tex(lua_State * L)
3258 luaL_register(L, "tex", texlib);
3259 /* *INDENT-OFF* */
3260 make_table(L, "attribute", "tex.attribute", "getattribute", "setattribute");
3261 make_table(L, "skip", "tex.skip", "getskip", "setskip");
3262 make_table(L, "glue", "tex.glue", "getglue", "setglue");
3263 make_table(L, "muskip", "tex.muskip", "getmuskip", "setmuskip");
3264 make_table(L, "muglue", "tex.muglue", "getmuglue", "setmuglue");
3265 make_table(L, "dimen", "tex.dimen", "getdimen", "setdimen");
3266 make_table(L, "count", "tex.count", "getcount", "setcount");
3267 make_table(L, "toks", "tex.toks", "gettoks", "settoks");
3268 make_table(L, "box", "tex.box", "getbox", "setbox");
3269 make_table(L, "sfcode", "tex.sfcode", "getsfcode", "setsfcode");
3270 make_table(L, "lccode", "tex.lccode", "getlccode", "setlccode");
3271 make_table(L, "uccode", "tex.uccode", "getuccode", "setuccode");
3272 make_table(L, "catcode", "tex.catcode", "getcatcode", "setcatcode");
3273 make_table(L, "mathcode", "tex.mathcode", "getmathcode", "setmathcode");
3274 make_table(L, "delcode", "tex.delcode", "getdelcode", "setdelcode");
3275 make_table(L, "lists", "tex.lists", "getlist", "setlist");
3276 make_table(L, "nest", "tex.nest", "getnest", "setnest");
3277 /* *INDENT-ON* */
3278 init_nest_lib(L);
3279 /* make the meta entries */
3280 /* fetch it back */
3281 luaL_newmetatable(L, "tex.meta");
3282 lua_pushstring(L, "__index");
3283 lua_pushcfunction(L, gettex);
3284 lua_settable(L, -3);
3285 lua_pushstring(L, "__newindex");
3286 lua_pushcfunction(L, settex);
3287 lua_settable(L, -3);
3288 lua_setmetatable(L, -2); /* meta to itself */
3289 /* initialize the I/O stack: */
3290 spindles = xmalloc(sizeof(spindle));
3291 spindle_index = 0;
3292 spindles[0].head = NULL;
3293 spindles[0].tail = NULL;
3294 spindle_size = 1;
3295 /* a somewhat odd place for this assert, maybe */
3296 assert(command_names[data_cmd].command_offset == data_cmd);
3297 return 1;