~ubuntu-branches/ubuntu/wily/luatex/wily

« back to all changes in this revision

Viewing changes to source/texk/web2c/luatexdir/tex/scanning.w

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Preining
  • Date: 2010-04-29 00:47:19 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20100429004719-o42etkqe90n97b9e
Tags: 0.60.1-1
* new upstream release, adapt build-script patch
* disable patch: upstream-epstopdf_cc_no_xpdf_patching, included upstream
* disable patch: libpoppler-0.12, not needed anymore

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
% scanning.w
 
2
 
3
% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org>
 
4
 
 
5
% This file is part of LuaTeX.
 
6
 
 
7
% LuaTeX is free software; you can redistribute it and/or modify it under
 
8
% the terms of the GNU General Public License as published by the Free
 
9
% Software Foundation; either version 2 of the License, or (at your
 
10
% option) any later version.
 
11
 
 
12
% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
 
13
% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
14
% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
15
% License for more details.
 
16
 
 
17
% You should have received a copy of the GNU General Public License along
 
18
% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
 
19
 
 
20
@ @c
 
21
#include "ptexlib.h"
 
22
 
 
23
static const char _svn_version[] =
 
24
    "$Id: scanning.w 3596 2010-04-05 10:12:46Z taco $"
 
25
    "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.1/source/texk/web2c/luatexdir/tex/scanning.w $";
 
26
 
 
27
 
 
28
@ @c
 
29
#define prev_depth cur_list.prev_depth_field
 
30
#define space_factor cur_list.space_factor_field
 
31
#define par_shape_ptr  equiv(par_shape_loc)
 
32
#define font_id_text(A) cs_text(font_id_base+(A))
 
33
 
 
34
#define attribute(A) eqtb[attribute_base+(A)].hh.rh
 
35
#define dimen(A) eqtb[scaled_base+(A)].hh.rh
 
36
#undef skip
 
37
#define skip(A) eqtb[skip_base+(A)].hh.rh
 
38
#define mu_skip(A) eqtb[mu_skip_base+(A)].hh.rh
 
39
#define count(A) eqtb[count_base+(A)].hh.rh
 
40
#define box(A) equiv(box_base+(A))
 
41
 
 
42
#define text_direction int_par(text_direction_code)
 
43
#define body_direction int_par(body_direction_code)
 
44
 
 
45
 
 
46
@ Let's turn now to some procedures that \TeX\ calls upon frequently to digest
 
47
certain kinds of patterns in the input. Most of these are quite simple;
 
48
some are quite elaborate. Almost all of the routines call |get_x_token|,
 
49
which can cause them to be invoked recursively.
 
50
 
 
51
The |scan_left_brace| routine is called when a left brace is supposed to be
 
52
the next non-blank token. (The term ``left brace'' means, more precisely,
 
53
a character whose catcode is |left_brace|.) \TeX\ allows \.{\\relax} to
 
54
appear before the |left_brace|.
 
55
 
 
56
@c
 
57
void scan_left_brace(void)
 
58
{                               /* reads a mandatory |left_brace| */
 
59
    /* Get the next non-blank non-relax non-call token */
 
60
    do {
 
61
        get_x_token();
 
62
    } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
 
63
 
 
64
    if (cur_cmd != left_brace_cmd) {
 
65
        print_err("Missing { inserted");
 
66
        help4("A left brace was mandatory here, so I've put one in.",
 
67
              "You might want to delete and/or insert some corrections",
 
68
              "so that I will find a matching right brace soon.",
 
69
              "If you're confused by all this, try typing `I}' now.");
 
70
        back_error();
 
71
        cur_tok = left_brace_token + '{';
 
72
        cur_cmd = left_brace_cmd;
 
73
        cur_chr = '{';
 
74
        incr(align_state);
 
75
    }
 
76
}
 
77
 
 
78
 
 
79
@ The |scan_optional_equals| routine looks for an optional `\.=' sign preceded
 
80
by optional spaces; `\.{\\relax}' is not ignored here.
 
81
 
 
82
@c
 
83
void scan_optional_equals(void)
 
84
{
 
85
    /* Get the next non-blank non-call token */
 
86
    do {
 
87
        get_x_token();
 
88
    } while (cur_cmd == spacer_cmd);
 
89
    if (cur_tok != other_token + '=')
 
90
        back_input();
 
91
}
 
92
 
 
93
 
 
94
@ Here is a procedure that sounds an alarm when mu and non-mu units
 
95
are being switched.
 
96
 
 
97
@c
 
98
static void mu_error(void)
 
99
{
 
100
    print_err("Incompatible glue units");
 
101
    help1("I'm going to assume that 1mu=1pt when they're mixed.");
 
102
    error();
 
103
}
 
104
 
 
105
 
 
106
@ The next routine `|scan_something_internal|' is used to fetch internal
 
107
numeric quantities like `\.{\\hsize}', and also to handle the `\.{\\the}'
 
108
when expanding constructions like `\.{\\the\\toks0}' and
 
109
`\.{\\the\\baselineskip}'. Soon we will be considering the |scan_int|
 
110
procedure, which calls |scan_something_internal|; on the other hand,
 
111
|scan_something_internal| also calls |scan_int|, for constructions like
 
112
`\.{\\catcode\`\\\$}' or `\.{\\fontdimen} \.3 \.{\\ff}'. So we
 
113
have to declare |scan_int| as a |forward| procedure. A few other
 
114
procedures are also declared at this point.
 
115
 
 
116
\TeX\ doesn't know exactly what to expect when
 
117
|scan_something_internal| begins.  For example, an integer or
 
118
dimension or glue value could occur immediately after `\.{\\hskip}';
 
119
and one can even say \.{\\the} with respect to token lists in
 
120
constructions like `\.{\\xdef\\o\{\\the\\output\}}'.  On the other
 
121
hand, only integers are allowed after a construction like
 
122
`\.{\\count}'. To handle the various possibilities,
 
123
|scan_something_internal| has a |level| parameter, which tells the
 
124
``highest'' kind of quantity that |scan_something_internal| is allowed
 
125
to produce. Eight levels are distinguished, namely |int_val|,
 
126
|attr_val|, |dimen_val|, |glue_val|, |mu_val|, |dir_val|, |ident_val|,
 
127
and |tok_val|.
 
128
 
 
129
The output of |scan_something_internal| (and of the other routines
 
130
|scan_int|, |scan_dimen|, and |scan_glue| below) is put into the global
 
131
variable |cur_val|, and its level is put into |cur_val_level|. The highest
 
132
values of |cur_val_level| are special: |mu_val| is used only when
 
133
|cur_val| points to something in a ``muskip'' register, or to one of the
 
134
three parameters \.{\\thinmuskip}, \.{\\medmuskip}, \.{\\thickmuskip};
 
135
|ident_val| is used only when |cur_val| points to a font identifier;
 
136
|tok_val| is used only when |cur_val| points to |null| or to the reference
 
137
count of a token list. The last two cases are allowed only when
 
138
|scan_something_internal| is called with |level=tok_val|.
 
139
 
 
140
If the output is glue, |cur_val| will point to a glue specification, and
 
141
the reference count of that glue will have been updated to reflect this
 
142
reference; if the output is a nonempty token list, |cur_val| will point to
 
143
its reference count, but in this case the count will not have been updated.
 
144
Otherwise |cur_val| will contain the integer or scaled value in question.
 
145
 
 
146
@c
 
147
int cur_val;                    /* value returned by numeric scanners */
 
148
int cur_val1;                   /* delcodes are sometimes 51 digits */
 
149
int cur_val_level;              /* the ``level'' of this value */
 
150
 
 
151
#define scanned_result(A,B) do {                \
 
152
        cur_val=A;                              \
 
153
        cur_val_level=B;                        \
 
154
    } while (0)
 
155
 
 
156
 
 
157
@ When a |glue_val| changes to a |dimen_val|, we use the width component
 
158
of the glue; there is no need to decrease the reference count, since it
 
159
has not yet been increased.  When a |dimen_val| changes to an |int_val|,
 
160
we use scaled points so that the value doesn't actually change. And when a
 
161
|mu_val| changes to a |glue_val|, the value doesn't change either.
 
162
 
 
163
@c
 
164
static void downgrade_cur_val(boolean delete_glue)
 
165
{
 
166
    halfword m;
 
167
    if (cur_val_level == glue_val_level) {
 
168
        m = cur_val;
 
169
        cur_val = width(m);
 
170
        if (delete_glue)
 
171
            delete_glue_ref(m);
 
172
    } else if (cur_val_level == mu_val_level) {
 
173
        mu_error();
 
174
    }
 
175
    decr(cur_val_level);
 
176
}
 
177
 
 
178
static void negate_cur_val(boolean delete_glue)
 
179
{
 
180
    halfword m;
 
181
    if (cur_val_level >= glue_val_level) {
 
182
        m = cur_val;
 
183
        cur_val = new_spec(m);
 
184
        if (delete_glue)
 
185
            delete_glue_ref(m);
 
186
        /* Negate all three glue components of |cur_val| */
 
187
        negate(width(cur_val));
 
188
        negate(stretch(cur_val));
 
189
        negate(shrink(cur_val));
 
190
 
 
191
    } else {
 
192
        negate(cur_val);
 
193
    }
 
194
}
 
195
 
 
196
 
 
197
@ Some of the internal items can be fetched both routines,
 
198
and these have been split off into the next routine, that
 
199
returns true if the command code was understood 
 
200
 
 
201
@c
 
202
static boolean short_scan_something_internal(int cmd, int chr, int level,
 
203
                                             boolean negative)
 
204
{
 
205
    halfword m;                 /* |chr_code| part of the operand token */
 
206
    halfword q;                 /* general purpose index */
 
207
    int p;                      /* index into |nest| */
 
208
    int save_cur_chr;
 
209
    boolean succeeded = true;
 
210
    m = chr;
 
211
    switch (cmd) {
 
212
    case assign_toks_cmd:
 
213
        scanned_result(equiv(m), tok_val_level);
 
214
        break;
 
215
    case assign_int_cmd:
 
216
        scanned_result(eqtb[m].cint, int_val_level);
 
217
        break;
 
218
    case assign_attr_cmd:
 
219
        scanned_result(eqtb[m].cint, int_val_level);
 
220
        break;
 
221
    case assign_dir_cmd:
 
222
        scanned_result(eqtb[m].cint, dir_val_level);
 
223
        break;
 
224
    case assign_dimen_cmd:
 
225
        scanned_result(eqtb[m].cint, dimen_val_level);
 
226
        break;
 
227
    case assign_glue_cmd:
 
228
        scanned_result(equiv(m), glue_val_level);
 
229
        break;
 
230
    case assign_mu_glue_cmd:
 
231
        scanned_result(equiv(m), mu_val_level);
 
232
        break;
 
233
    case math_style_cmd:
 
234
        scanned_result(m, int_val_level);
 
235
        break;
 
236
    case set_aux_cmd:
 
237
        /* Fetch the |space_factor| or the |prev_depth| */
 
238
        if (abs(cur_list.mode_field) != m) {
 
239
            print_err("Improper ");
 
240
            print_cmd_chr(set_aux_cmd, m);
 
241
            help4("You can refer to \\spacefactor only in horizontal mode;",
 
242
                  "you can refer to \\prevdepth only in vertical mode; and",
 
243
                  "neither of these is meaningful inside \\write. So",
 
244
                  "I'm forgetting what you said and using zero instead.");
 
245
            error();
 
246
            if (level != tok_val_level)
 
247
                scanned_result(0, dimen_val_level);
 
248
            else
 
249
                scanned_result(0, int_val_level);
 
250
        } else if (m == vmode) {
 
251
            scanned_result(prev_depth, dimen_val_level);
 
252
        } else {
 
253
            scanned_result(space_factor, int_val_level);
 
254
        }
 
255
        break;
 
256
    case set_prev_graf_cmd:
 
257
        /* Fetch the |prev_graf| */
 
258
        if (cur_list.mode_field == 0) {
 
259
            scanned_result(0, int_val_level);   /* |prev_graf=0| within \.{\\write} */
 
260
        } else {
 
261
            p = nest_ptr;
 
262
            while (abs(nest[p].mode_field) != vmode)
 
263
                decr(p);
 
264
            scanned_result(nest[p].pg_field, int_val_level);
 
265
        }
 
266
        break;
 
267
    case set_page_int_cmd:
 
268
        /* Fetch the |dead_cycles| or the |insert_penalties| */
 
269
        if (m == 0)
 
270
            cur_val = dead_cycles;
 
271
        else if (m == 2)
 
272
            cur_val = interaction;      /* interactionmode */
 
273
        else
 
274
            cur_val = insert_penalties;
 
275
        cur_val_level = int_val_level;
 
276
        break;
 
277
    case set_page_dimen_cmd:
 
278
        /* Fetch something on the |page_so_far| */
 
279
        if ((page_contents == empty) && (!output_active)) {
 
280
            if (m == 0)
 
281
                cur_val = max_dimen;
 
282
            else
 
283
                cur_val = 0;
 
284
        } else {
 
285
            cur_val = page_so_far[m];
 
286
        }
 
287
        cur_val_level = dimen_val_level;
 
288
        break;
 
289
    case set_tex_shape_cmd:
 
290
        /* Fetch the |par_shape| size */
 
291
        if (par_shape_ptr == null)
 
292
            cur_val = 0;
 
293
        else
 
294
            cur_val = vinfo(par_shape_ptr + 1);
 
295
        cur_val_level = int_val_level;
 
296
        break;
 
297
    case set_etex_shape_cmd:
 
298
        /* Fetch a penalties array element */
 
299
        scan_int();
 
300
        if ((equiv(m) == null) || (cur_val < 0)) {
 
301
            cur_val = 0;
 
302
        } else {
 
303
            if (cur_val > penalty(equiv(m)))
 
304
                cur_val = penalty(equiv(m));
 
305
            cur_val = penalty(equiv(m) + cur_val);
 
306
        }
 
307
        cur_val_level = int_val_level;
 
308
        break;
 
309
    case char_given_cmd:
 
310
    case math_given_cmd:
 
311
    case omath_given_cmd:
 
312
    case xmath_given_cmd:
 
313
        scanned_result(cur_chr, int_val_level);
 
314
        break;
 
315
    case last_item_cmd:
 
316
        /* Because the items in this case directly refer to |cur_chr|,
 
317
           it needs to be saved and restored */
 
318
        save_cur_chr = cur_chr;
 
319
        cur_chr = chr;
 
320
        /* Fetch an item in the current node, if appropriate */
 
321
        /* Here is where \.{\\lastpenalty}, \.{\\lastkern}, and \.{\\lastskip} are
 
322
           implemented. The reference count for \.{\\lastskip} will be updated later. 
 
323
 
 
324
           We also handle \.{\\inputlineno} and \.{\\badness} here, because they are
 
325
           legal in similar contexts. */
 
326
 
 
327
        if (m >= input_line_no_code) {
 
328
            if (m >= eTeX_glue) {
 
329
                /* Process an expression and |return| */
 
330
                if (m < eTeX_mu) {
 
331
                    switch (m) {
 
332
                    case mu_to_glue_code:
 
333
                        scan_mu_glue();
 
334
                        break;
 
335
                    };          /* there are no other cases */
 
336
                    cur_val_level = glue_val_level;
 
337
                } else if (m < eTeX_expr) {
 
338
                    switch (m) {
 
339
                    case glue_to_mu_code:
 
340
                        scan_normal_glue();
 
341
                        break;
 
342
                    }           /* there are no other cases */
 
343
                    cur_val_level = mu_val_level;
 
344
                } else {
 
345
                    cur_val_level = m - eTeX_expr + int_val_level;
 
346
                    scan_expr();
 
347
                }
 
348
                /* This code for reducing |cur_val_level| and\slash or negating the
 
349
                   result is similar to the one for all the other cases of
 
350
                   |scan_something_internal|, with the difference that |scan_expr| has
 
351
                   already increased the reference count of a glue specification. 
 
352
                 */
 
353
                while (cur_val_level > level) {
 
354
                    downgrade_cur_val(true);
 
355
                }
 
356
                if (negative) {
 
357
                    negate_cur_val(true);
 
358
                }
 
359
                return succeeded;
 
360
 
 
361
            } else if (m >= eTeX_dim) {
 
362
                switch (m) {
 
363
                case font_char_wd_code:
 
364
                case font_char_ht_code:
 
365
                case font_char_dp_code:
 
366
                case font_char_ic_code:
 
367
                    scan_font_ident();
 
368
                    q = cur_val;
 
369
                    scan_char_num();
 
370
                    if (char_exists(q, cur_val)) {
 
371
                        switch (m) {
 
372
                        case font_char_wd_code:
 
373
                            cur_val = char_width(q, cur_val);
 
374
                            break;
 
375
                        case font_char_ht_code:
 
376
                            cur_val = char_height(q, cur_val);
 
377
                            break;
 
378
                        case font_char_dp_code:
 
379
                            cur_val = char_depth(q, cur_val);
 
380
                            break;
 
381
                        case font_char_ic_code:
 
382
                            cur_val = char_italic(q, cur_val);
 
383
                            break;
 
384
                        }       /* there are no other cases */
 
385
                    } else {
 
386
                        cur_val = 0;
 
387
                    }
 
388
                    break;
 
389
                case par_shape_length_code:
 
390
                case par_shape_indent_code:
 
391
                case par_shape_dimen_code:
 
392
                    q = cur_chr - par_shape_length_code;
 
393
                    scan_int();
 
394
                    if ((par_shape_ptr == null) || (cur_val <= 0)) {
 
395
                        cur_val = 0;
 
396
                    } else {
 
397
                        if (q == 2) {
 
398
                            q = cur_val % 2;
 
399
                            cur_val = (cur_val + q) / 2;
 
400
                        }
 
401
                        if (cur_val > vinfo(par_shape_ptr + 1))
 
402
                            cur_val = vinfo(par_shape_ptr + 1);
 
403
                        cur_val =
 
404
                            varmem[par_shape_ptr + 2 * cur_val - q + 1].cint;
 
405
                    }
 
406
                    cur_val_level = dimen_val_level;
 
407
                    break;
 
408
                case glue_stretch_code:
 
409
                case glue_shrink_code:
 
410
                    scan_normal_glue();
 
411
                    q = cur_val;
 
412
                    if (m == glue_stretch_code)
 
413
                        cur_val = stretch(q);
 
414
                    else
 
415
                        cur_val = shrink(q);
 
416
                    delete_glue_ref(q);
 
417
                    break;
 
418
                }               /* there are no other cases */
 
419
                cur_val_level = dimen_val_level;
 
420
            } else {
 
421
                switch (m) {
 
422
                case input_line_no_code:
 
423
                    cur_val = line;
 
424
                    break;
 
425
                case badness_code:
 
426
                    cur_val = last_badness;
 
427
                    break;
 
428
                case pdftex_version_code:
 
429
                    cur_val = pdftex_version;
 
430
                    break;
 
431
                case luatex_version_code:
 
432
                    cur_val = get_luatexversion();
 
433
                    break;
 
434
                case pdf_last_obj_code:
 
435
                    cur_val = pdf_last_obj;
 
436
                    break;
 
437
                case pdf_last_xform_code:
 
438
                    cur_val = pdf_last_xform;
 
439
                    break;
 
440
                case pdf_last_ximage_code:
 
441
                    cur_val = pdf_last_ximage;
 
442
                    break;
 
443
                case pdf_last_ximage_pages_code:
 
444
                    cur_val = pdf_last_ximage_pages;
 
445
                    break;
 
446
                case pdf_last_annot_code:
 
447
                    cur_val = pdf_last_annot;
 
448
                    break;
 
449
                case pdf_last_x_pos_code:
 
450
                    cur_val = pdf_last_pos.h;
 
451
                    break;
 
452
                case pdf_last_y_pos_code:
 
453
                    cur_val = pdf_last_pos.v;
 
454
                    break;
 
455
                case pdf_retval_code:
 
456
                    cur_val = pdf_retval;
 
457
                    break;
 
458
                case pdf_last_ximage_colordepth_code:
 
459
                    cur_val = pdf_last_ximage_colordepth;
 
460
                    break;
 
461
                case random_seed_code:
 
462
                    cur_val = random_seed;
 
463
                    break;
 
464
                case pdf_last_link_code:
 
465
                    cur_val = pdf_last_link;
 
466
                    break;
 
467
                case Aleph_version_code:
 
468
                    cur_val = Aleph_version;
 
469
                    break;
 
470
                case Omega_version_code:
 
471
                    cur_val = Omega_version;
 
472
                    break;
 
473
                case eTeX_version_code:
 
474
                    cur_val = eTeX_version;
 
475
                    break;
 
476
                case Aleph_minor_version_code:
 
477
                    cur_val = Aleph_minor_version;
 
478
                    break;
 
479
                case Omega_minor_version_code:
 
480
                    cur_val = Omega_minor_version;
 
481
                    break;
 
482
                case eTeX_minor_version_code:
 
483
                    cur_val = eTeX_minor_version;
 
484
                    break;
 
485
                case current_group_level_code:
 
486
                    cur_val = cur_level - level_one;
 
487
                    break;
 
488
                case current_group_type_code:
 
489
                    cur_val = cur_group;
 
490
                    break;
 
491
                case current_if_level_code:
 
492
                    q = cond_ptr;
 
493
                    cur_val = 0;
 
494
                    while (q != null) {
 
495
                        incr(cur_val);
 
496
                        q = vlink(q);
 
497
                    }
 
498
                    break;
 
499
                case current_if_type_code:
 
500
                    if (cond_ptr == null)
 
501
                        cur_val = 0;
 
502
                    else if (cur_if < unless_code)
 
503
                        cur_val = cur_if + 1;
 
504
                    else
 
505
                        cur_val = -(cur_if - unless_code + 1);
 
506
                    break;
 
507
                case current_if_branch_code:
 
508
                    if ((if_limit == or_code) || (if_limit == else_code))
 
509
                        cur_val = 1;
 
510
                    else if (if_limit == fi_code)
 
511
                        cur_val = -1;
 
512
                    else
 
513
                        cur_val = 0;
 
514
                    break;
 
515
                case glue_stretch_order_code:
 
516
                case glue_shrink_order_code:
 
517
                    scan_normal_glue();
 
518
                    q = cur_val;
 
519
                    if (m == glue_stretch_order_code)
 
520
                        cur_val = stretch_order(q);
 
521
                    else
 
522
                        cur_val = shrink_order(q);
 
523
                    delete_glue_ref(q);
 
524
                    break;
 
525
 
 
526
                }               /* there are no other cases */
 
527
                cur_val_level = int_val_level;
 
528
            }
 
529
        } else {
 
530
            if (cur_chr == glue_val_level)
 
531
                cur_val = zero_glue;
 
532
            else
 
533
                cur_val = 0;
 
534
            if (cur_chr == last_node_type_code) {
 
535
                cur_val_level = int_val_level;
 
536
                if ((cur_list.tail_field == cur_list.head_field)
 
537
                    || (cur_list.mode_field == 0))
 
538
                    cur_val = -1;
 
539
            } else {
 
540
                cur_val_level = cur_chr;        /* assumes identical values */
 
541
            }
 
542
            if ((cur_list.tail_field != contrib_head) &&
 
543
                !is_char_node(cur_list.tail_field) &&
 
544
                (cur_list.mode_field != 0)) {
 
545
                switch (cur_chr) {
 
546
                case lastpenalty_code:
 
547
                    if (type(cur_list.tail_field) == penalty_node)
 
548
                        cur_val = penalty(cur_list.tail_field);
 
549
                    break;
 
550
                case lastkern_code:
 
551
                    if (type(cur_list.tail_field) == kern_node)
 
552
                        cur_val = width(cur_list.tail_field);
 
553
                    break;
 
554
                case lastskip_code:
 
555
                    if (type(cur_list.tail_field) == glue_node)
 
556
                        cur_val = glue_ptr(cur_list.tail_field);
 
557
                    if (subtype(cur_list.tail_field) == mu_glue)
 
558
                        cur_val_level = mu_val_level;
 
559
                    break;
 
560
                case last_node_type_code:
 
561
                    cur_val = visible_last_node_type(cur_list.tail_field);
 
562
                    break;
 
563
                }               /* there are no other cases */
 
564
            } else if ((cur_list.mode_field == vmode)
 
565
                       && (cur_list.tail_field == cur_list.head_field)) {
 
566
                switch (cur_chr) {
 
567
                case lastpenalty_code:
 
568
                    cur_val = last_penalty;
 
569
                    break;
 
570
                case lastkern_code:
 
571
                    cur_val = last_kern;
 
572
                    break;
 
573
                case lastskip_code:
 
574
                    if (last_glue != max_halfword)
 
575
                        cur_val = last_glue;
 
576
                    break;
 
577
                case last_node_type_code:
 
578
                    cur_val = last_node_type;
 
579
                    break;
 
580
                }               /* there are no other cases */
 
581
            }
 
582
        }
 
583
        cur_chr = save_cur_chr;
 
584
        break;
 
585
    default:
 
586
        succeeded = false;
 
587
    }
 
588
    if (succeeded) {
 
589
        while (cur_val_level > level) {
 
590
            /* Convert |cur_val| to a lower level */
 
591
            downgrade_cur_val(false);
 
592
        }
 
593
        /* Fix the reference count, if any, and negate |cur_val| if |negative| */
 
594
        /* If |cur_val| points to a glue specification at this point, the reference
 
595
           count for the glue does not yet include the reference by |cur_val|.
 
596
           If |negative| is |true|, |cur_val_level| is known to be |<=mu_val|.
 
597
         */
 
598
        if (negative) {
 
599
            negate_cur_val(false);
 
600
        } else if ((cur_val_level >= glue_val_level)
 
601
                   && (cur_val_level <= mu_val_level)) {
 
602
            add_glue_ref(cur_val);
 
603
        }
 
604
    }
 
605
    return succeeded;
 
606
}
 
607
 
 
608
@ First, here is a short routine that is called from lua code. All
 
609
the  real work is delegated to |short_scan_something_internal| that
 
610
is shared between this routine and |scan_something_internal|. 
 
611
 
 
612
@c
 
613
void scan_something_simple(halfword cmd, halfword subitem)
 
614
{
 
615
    /* negative is never true */
 
616
    if (!short_scan_something_internal(cmd, subitem, tok_val_level, false)) {
 
617
        /* Complain that |texlib| can not do this; give zero result */
 
618
        print_err("You can't use `");
 
619
        print_cmd_chr((quarterword) cmd, subitem);
 
620
        tprint("' as tex library index");
 
621
        help1("I'm forgetting what you said and using zero instead.");
 
622
        error();
 
623
        scanned_result(0, int_val_level);
 
624
    }
 
625
}
 
626
 
 
627
 
 
628
 
 
629
@ OK, we're ready for |scan_something_internal| itself. A second parameter,
 
630
|negative|, is set |true| if the value that is found should be negated.
 
631
It is assumed that |cur_cmd| and |cur_chr| represent the first token of
 
632
the internal quantity to be scanned; an error will be signalled if
 
633
|cur_cmd<min_internal| or |cur_cmd>max_internal|.
 
634
 
 
635
@c
 
636
void scan_something_internal(int level, boolean negative)
 
637
{
 
638
    /* fetch an internal parameter */
 
639
    halfword m;                 /* |chr_code| part of the operand token */
 
640
    int n, k;                   /* accumulators */
 
641
  RESTART:
 
642
    m = cur_chr;
 
643
    if (!short_scan_something_internal(cur_cmd, cur_chr, level, negative)) {
 
644
        switch (cur_cmd) {
 
645
        case def_char_code_cmd:
 
646
            /* Fetch a character code from some table */
 
647
            scan_char_num();
 
648
            if (m == math_code_base) {
 
649
                cur_val1 = get_math_code_num(cur_val);
 
650
                scanned_result(cur_val1, int_val_level);
 
651
            } else if (m == lc_code_base) {
 
652
                cur_val1 = get_lc_code(cur_val);
 
653
                scanned_result(cur_val1, int_val_level);
 
654
            } else if (m == uc_code_base) {
 
655
                cur_val1 = get_uc_code(cur_val);
 
656
                scanned_result(cur_val1, int_val_level);
 
657
            } else if (m == sf_code_base) {
 
658
                cur_val1 = get_sf_code(cur_val);
 
659
                scanned_result(cur_val1, int_val_level);
 
660
            } else if (m == cat_code_base) {
 
661
                cur_val1 = get_cat_code(int_par(cat_code_table_code), cur_val);
 
662
                scanned_result(cur_val1, int_val_level);
 
663
            } else {
 
664
                confusion("def_char");
 
665
            }
 
666
            break;
 
667
        case def_del_code_cmd:
 
668
            /* Fetch a character code from some table */
 
669
            scan_char_num();
 
670
            cur_val1 = get_del_code_num(cur_val);
 
671
            scanned_result(cur_val1, int_val_level);
 
672
            break;
 
673
        case extdef_math_code_cmd:
 
674
            /* Fetch an extended math code table value */
 
675
            scan_char_num();
 
676
            cur_val1 = get_math_code_num(cur_val);
 
677
            scanned_result(cur_val1, int_val_level);
 
678
            break;
 
679
        case toks_register_cmd:
 
680
        case set_font_cmd:
 
681
        case def_font_cmd:
 
682
        case letterspace_font_cmd:
 
683
        case pdf_copy_font_cmd:
 
684
            /* Fetch a token list or font identifier, provided that |level=tok_val| */
 
685
            if (level != tok_val_level) {
 
686
                print_err("Missing number, treated as zero");
 
687
                help3("A number should have been here; I inserted `0'.",
 
688
                      "(If you can't figure out why I needed to see a number,",
 
689
                      "look up `weird error' in the index to The TeXbook.)");
 
690
                back_error();
 
691
                scanned_result(0, dimen_val_level);
 
692
            } else if (cur_cmd == toks_register_cmd) {
 
693
                scan_register_num();
 
694
                m = toks_base + cur_val;
 
695
                scanned_result(equiv(m), tok_val_level);
 
696
            } else {
 
697
                back_input();
 
698
                scan_font_ident();
 
699
                scanned_result(font_id_base + cur_val, ident_val_level);
 
700
            }
 
701
            break;
 
702
        case def_family_cmd:
 
703
            /* Fetch a math font identifier */
 
704
            scan_char_num();
 
705
            cur_val1 = fam_fnt(cur_val, m);
 
706
            scanned_result(font_id_base + cur_val1, ident_val_level);
 
707
            break;
 
708
        case set_math_param_cmd:
 
709
            /* Fetch a math param */
 
710
            cur_val1 = cur_chr;
 
711
            get_token();
 
712
            if (cur_cmd != math_style_cmd) {
 
713
                print_err("Missing math style, treated as \\displaystyle");
 
714
                help1
 
715
                    ("A style should have been here; I inserted `\\displaystyle'.");
 
716
                cur_val = display_style;
 
717
                back_error();
 
718
            } else {
 
719
                cur_val = cur_chr;
 
720
            }
 
721
            if (cur_val1 < math_param_first_mu_glue) {
 
722
                if (cur_val1 == math_param_radical_degree_raise) {
 
723
                    cur_val1 = get_math_param(cur_val1, cur_chr);
 
724
                    scanned_result(cur_val1, int_val_level);
 
725
                } else {
 
726
                    cur_val1 = get_math_param(cur_val1, cur_chr);
 
727
                    scanned_result(cur_val1, dimen_val_level);
 
728
                }
 
729
            } else {
 
730
                cur_val1 = get_math_param(cur_val1, cur_chr);
 
731
                if (cur_val1 == thin_mu_skip_code)
 
732
                    cur_val1 = glue_par(thin_mu_skip_code);
 
733
                else if (cur_val1 == med_mu_skip_code)
 
734
                    cur_val1 = glue_par(med_mu_skip_code);
 
735
                else if (cur_val1 == thick_mu_skip_code)
 
736
                    cur_val1 = glue_par(thick_mu_skip_code);
 
737
                scanned_result(cur_val1, mu_val_level);
 
738
            }
 
739
            break;
 
740
        case assign_box_dir_cmd:
 
741
            scan_register_num();
 
742
            m = cur_val;
 
743
            if (box(m) != null)
 
744
                cur_val = box_dir(box(m));
 
745
            else
 
746
                cur_val = 0;
 
747
            cur_val_level = dir_val_level;
 
748
            break;
 
749
        case set_box_dimen_cmd:
 
750
            /* Fetch a box dimension */
 
751
            scan_register_num();
 
752
            if (box(cur_val) == null)
 
753
                cur_val = 0;
 
754
            else
 
755
                cur_val = varmem[box(cur_val) + m].cint;
 
756
            cur_val_level = dimen_val_level;
 
757
            break;
 
758
        case assign_font_dimen_cmd:
 
759
            /* Fetch a font dimension */
 
760
            get_font_dimen();
 
761
            break;
 
762
        case assign_font_int_cmd:
 
763
            /* Fetch a font integer */
 
764
            scan_font_ident();
 
765
            if (m == 0) {
 
766
                scanned_result(hyphen_char(cur_val), int_val_level);
 
767
            } else if (m == 1) {
 
768
                scanned_result(skew_char(cur_val), int_val_level);
 
769
            } else if (m == no_lig_code) {
 
770
                scanned_result(test_no_ligatures(cur_val), int_val_level);
 
771
            } else {
 
772
                n = cur_val;
 
773
                scan_char_num();
 
774
                k = cur_val;
 
775
                switch (m) {
 
776
                case lp_code_base:
 
777
                    scanned_result(get_lp_code(n, k), int_val_level);
 
778
                    break;
 
779
                case rp_code_base:
 
780
                    scanned_result(get_rp_code(n, k), int_val_level);
 
781
                    break;
 
782
                case ef_code_base:
 
783
                    scanned_result(get_ef_code(n, k), int_val_level);
 
784
                    break;
 
785
                case tag_code:
 
786
                    scanned_result(get_tag_code(n, k), int_val_level);
 
787
                    break;
 
788
                }
 
789
            }
 
790
            break;
 
791
        case register_cmd:
 
792
            /* Fetch a register */
 
793
            scan_register_num();
 
794
            switch (m) {
 
795
            case int_val_level:
 
796
                cur_val = count(cur_val);
 
797
                break;
 
798
            case attr_val_level:
 
799
                cur_val = attribute(cur_val);
 
800
                break;
 
801
            case dimen_val_level:
 
802
                cur_val = dimen(cur_val);
 
803
                break;
 
804
            case glue_val_level:
 
805
                cur_val = skip(cur_val);
 
806
                break;
 
807
            case mu_val_level:
 
808
                cur_val = mu_skip(cur_val);
 
809
                break;
 
810
            }                   /* there are no other cases */
 
811
            cur_val_level = m;
 
812
            break;
 
813
        case ignore_spaces_cmd:        /* trap unexpandable primitives */
 
814
            if (cur_chr == 1) {
 
815
                /* Reset |cur_tok| for unexpandable primitives, goto restart */
 
816
                /* This block deals with unexpandable \.{\\primitive} appearing at a spot where
 
817
                   an integer or an internal values should have been found. It fetches the
 
818
                   next token then resets |cur_cmd|, |cur_cs|, and |cur_tok|, based on the
 
819
                   primitive value of that token. No expansion takes place, because the
 
820
                   next token may be all sorts of things. This could trigger further
 
821
                   expansion creating new errors.
 
822
                 */
 
823
                get_token();
 
824
                cur_cs = prim_lookup(cs_text(cur_cs));
 
825
                if (cur_cs != undefined_primitive) {
 
826
                    cur_cmd = get_prim_eq_type(cur_cs);
 
827
                    cur_chr = get_prim_equiv(cur_cs);
 
828
                    cur_tok = token_val(cur_cmd, cur_chr);
 
829
                } else {
 
830
                    cur_cmd = relax_cmd;
 
831
                    cur_chr = 0;
 
832
                    cur_tok = cs_token_flag + frozen_relax;
 
833
                    cur_cs = frozen_relax;
 
834
                }
 
835
                goto RESTART;
 
836
            }
 
837
            break;
 
838
        default:
 
839
            /* Complain that \.{\\the} can not do this; give zero result */
 
840
            print_err("You can't use `");
 
841
            print_cmd_chr((quarterword) cur_cmd, cur_chr);
 
842
            tprint("' after \\the");
 
843
            help1("I'm forgetting what you said and using zero instead.");
 
844
            error();
 
845
            if (level != tok_val_level)
 
846
                scanned_result(0, dimen_val_level);
 
847
            else
 
848
                scanned_result(0, int_val_level);
 
849
            break;
 
850
        }
 
851
        while (cur_val_level > level) {
 
852
            /* Convert |cur_val| to a lower level */
 
853
            downgrade_cur_val(false);
 
854
        }
 
855
        /* Fix the reference count, if any, and negate |cur_val| if |negative| */
 
856
        /* If |cur_val| points to a glue specification at this point, the reference
 
857
           count for the glue does not yet include the reference by |cur_val|.
 
858
           If |negative| is |true|, |cur_val_level| is known to be |<=mu_val|.
 
859
         */
 
860
        if (negative) {
 
861
            negate_cur_val(false);
 
862
        } else if ((cur_val_level >= glue_val_level) &&
 
863
                   (cur_val_level <= mu_val_level)) {
 
864
            add_glue_ref(cur_val);
 
865
        }
 
866
    }
 
867
}
 
868
 
 
869
 
 
870
@ It is nice to have routines that say what they do, so the original
 
871
|scan_eight_bit_int| is superceded by |scan_register_num| and
 
872
|scan_mark_num|. It may become split up even further in the future.
 
873
 
 
874
Many of the |restricted classes| routines are the essentially 
 
875
the same except for the upper limit and the error message, so it makes
 
876
sense to combine these all into one function. 
 
877
 
 
878
@c
 
879
void scan_limited_int(int max, const char *name)
 
880
{
 
881
    char hlp[80];
 
882
    scan_int();
 
883
    if ((cur_val < 0) || (cur_val > max)) {
 
884
        if (name == NULL) {
 
885
            snprintf(hlp, 80,
 
886
                     "Since I expected to read a number between 0 and %d,",
 
887
                     max);
 
888
            print_err("Bad number");
 
889
        } else {
 
890
            char msg[80];
 
891
            snprintf(hlp, 80, "A %s must be between 0 and %d.", name, max);
 
892
            snprintf(msg, 80, "Bad %s", name);
 
893
            print_err(msg);
 
894
        }
 
895
        help2(hlp, "I changed this one to zero.");
 
896
        int_error(cur_val);
 
897
        cur_val = 0;
 
898
    }
 
899
}
 
900
 
 
901
@ @c
 
902
void scan_fifteen_bit_int(void)
 
903
{
 
904
    scan_real_fifteen_bit_int();
 
905
    cur_val = ((cur_val / 0x1000) * 0x1000000) +
 
906
        (((cur_val % 0x1000) / 0x100) * 0x10000) + (cur_val % 0x100);
 
907
}
 
908
 
 
909
@ @c
 
910
void scan_fifty_one_bit_int(void)
 
911
{
 
912
    int iiii;
 
913
    scan_int();
 
914
    if ((cur_val < 0) || (cur_val > 0777777777)) {
 
915
        print_err("Bad delimiter code");
 
916
        help2
 
917
            ("A numeric delimiter (first part) must be between 0 and 2^{27}-1.",
 
918
             "I changed this one to zero.");
 
919
        int_error(cur_val);
 
920
        cur_val = 0;
 
921
    }
 
922
    iiii = cur_val;
 
923
    scan_int();
 
924
    if ((cur_val < 0) || (cur_val > 0xFFFFFF)) {
 
925
        print_err("Bad delimiter code");
 
926
        help2
 
927
            ("A numeric delimiter (second part) must be between 0 and 2^{24}-1.",
 
928
             "I changed this one to zero.");
 
929
        int_error(cur_val);
 
930
        cur_val = 0;
 
931
    }
 
932
    cur_val1 = cur_val;
 
933
    cur_val = iiii;
 
934
}
 
935
 
 
936
 
 
937
@ To be able to determine whether \.{\\write18} is enabled from within
 
938
\TeX\ we also implement \.{\\eof18}.  We sort of cheat by having an
 
939
additional route |scan_four_bit_int_or_18| which is the same as
 
940
|scan_four_bit_int| except it also accepts the value 18.
 
941
 
 
942
@c
 
943
void scan_four_bit_int_or_18(void)
 
944
{
 
945
    scan_int();
 
946
    if ((cur_val < 0) || ((cur_val > 15) && (cur_val != 18))) {
 
947
        print_err("Bad number");
 
948
        help2("Since I expected to read a number between 0 and 15,",
 
949
              "I changed this one to zero.");
 
950
        int_error(cur_val);
 
951
        cur_val = 0;
 
952
    }
 
953
}
 
954
 
 
955
 
 
956
@ @c
 
957
void scan_string_argument(void)
 
958
{
 
959
    int s;
 
960
    scan_left_brace();
 
961
    get_x_token();
 
962
    while ((cur_cmd != right_brace_cmd)) {
 
963
        if ((cur_cmd == letter_cmd) || (cur_cmd == other_char_cmd)) {
 
964
            str_room(1);
 
965
            append_char(cur_chr);
 
966
        } else if (cur_cmd == spacer_cmd) {
 
967
            str_room(1);
 
968
            append_char(' ');
 
969
        } else {
 
970
            tprint("Bad token appearing in string argument");
 
971
        }
 
972
        get_x_token();
 
973
    }
 
974
    s = make_string();
 
975
    /* todo: this was just conserving the string pool: */
 
976
#if 0
 
977
       if (str_eq_str("mi",s)) s="mi";
 
978
       if (str_eq_str("mo",s)) s="mo";
 
979
       if (str_eq_str("mn",s)) s="mn";
 
980
#endif
 
981
    cur_val = s;
 
982
}
 
983
 
 
984
 
 
985
@ An integer number can be preceded by any number of spaces and `\.+' or
 
986
`\.-' signs. Then comes either a decimal constant (i.e., radix 10), an
 
987
octal constant (i.e., radix 8, preceded by~'), a hexadecimal constant
 
988
(radix 16, preceded by~"), an alphabetic constant (preceded by~`), or
 
989
an internal variable. After scanning is complete,
 
990
|cur_val| will contain the answer, which must be at most
 
991
$2^{31}-1=2147483647$ in absolute value. The value of |radix| is set to
 
992
10, 8, or 16 in the cases of decimal, octal, or hexadecimal constants,
 
993
otherwise |radix| is set to zero. An optional space follows a constant.
 
994
 
 
995
@c
 
996
int radix;                      /* |scan_int| sets this to 8, 10, 16, or zero */
 
997
 
 
998
 
 
999
@ The |scan_int| routine is used also to scan the integer part of a
 
1000
  fraction; for example, the `\.3' in `\.{3.14159}' will be found by
 
1001
  |scan_int|. The |scan_dimen| routine assumes that |cur_tok=point_token|
 
1002
  after the integer part of such a fraction has been scanned by |scan_int|,
 
1003
  and that the decimal point has been backed up to be scanned again.
 
1004
 
 
1005
@c
 
1006
void scan_int(void)
 
1007
{                               /* sets |cur_val| to an integer */
 
1008
    boolean negative;           /* should the answer be negated? */
 
1009
    int m;                      /* |$2^{31}$ / radix|, the threshold of danger */
 
1010
    int d;                      /* the digit just scanned */
 
1011
    boolean vacuous;            /* have no digits appeared? */
 
1012
    boolean OK_so_far;          /* has an error message been issued? */
 
1013
    radix = 0;
 
1014
    OK_so_far = true;
 
1015
    /* Get the next non-blank non-sign token; set |negative| appropriately */
 
1016
    negative = false;
 
1017
    do {
 
1018
        /* Get the next non-blank non-call token */
 
1019
        do {
 
1020
            get_x_token();
 
1021
        } while (cur_cmd == spacer_cmd);
 
1022
        if (cur_tok == other_token + '-') {
 
1023
            negative = !negative;
 
1024
            cur_tok = other_token + '+';
 
1025
        }
 
1026
    } while (cur_tok == other_token + '+');
 
1027
 
 
1028
  RESTART:
 
1029
    if (cur_tok == alpha_token) {
 
1030
        /* Scan an alphabetic character code into |cur_val| */
 
1031
        /* A space is ignored after an alphabetic character constant, so that
 
1032
           such constants behave like numeric ones. */
 
1033
        get_token();            /* suppress macro expansion */
 
1034
        if (cur_tok < cs_token_flag) {
 
1035
            cur_val = cur_chr;
 
1036
            if (cur_cmd <= right_brace_cmd) {
 
1037
                if (cur_cmd == right_brace_cmd)
 
1038
                    incr(align_state);
 
1039
                else
 
1040
                    decr(align_state);
 
1041
            }
 
1042
        } else {                /* the value of a csname in this context is its name */
 
1043
            str_number txt = cs_text(cur_tok - cs_token_flag);
 
1044
            if (is_active_cs(txt))
 
1045
                cur_val = active_cs_value(txt);
 
1046
            else if (single_letter(txt))
 
1047
                cur_val = pool_to_unichar(str_string(txt));
 
1048
            else
 
1049
                cur_val = (biggest_char + 1);
 
1050
        }
 
1051
        if (cur_val > biggest_char) {
 
1052
            print_err("Improper alphabetic constant");
 
1053
            help2("A one-character control sequence belongs after a ` mark.",
 
1054
                  "So I'm essentially inserting \\0 here.");
 
1055
            cur_val = '0';
 
1056
            back_error();
 
1057
        } else {
 
1058
            /* Scan an optional space */
 
1059
            get_x_token();
 
1060
            if (cur_cmd != spacer_cmd)
 
1061
                back_input();
 
1062
        }
 
1063
 
 
1064
    } else if (cur_tok == cs_token_flag + frozen_primitive) {
 
1065
        /* Reset |cur_tok| for unexpandable primitives, goto restart */
 
1066
        /* This block deals with unexpandable \.{\\primitive} appearing at a spot where
 
1067
           an integer or an internal values should have been found. It fetches the
 
1068
           next token then resets |cur_cmd|, |cur_cs|, and |cur_tok|, based on the
 
1069
           primitive value of that token. No expansion takes place, because the
 
1070
           next token may be all sorts of things. This could trigger further
 
1071
           expansion creating new errors.
 
1072
         */
 
1073
        get_token();
 
1074
        cur_cs = prim_lookup(cs_text(cur_cs));
 
1075
        if (cur_cs != undefined_primitive) {
 
1076
            cur_cmd = get_prim_eq_type(cur_cs);
 
1077
            cur_chr = get_prim_equiv(cur_cs);
 
1078
            cur_tok = token_val(cur_cmd, cur_chr);
 
1079
        } else {
 
1080
            cur_cmd = relax_cmd;
 
1081
            cur_chr = 0;
 
1082
            cur_tok = cs_token_flag + frozen_relax;
 
1083
            cur_cs = frozen_relax;
 
1084
        }
 
1085
        goto RESTART;
 
1086
    } else if (cur_cmd == math_style_cmd) {
 
1087
        cur_val = cur_chr;
 
1088
    } else if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
 
1089
        scan_something_internal(int_val_level, false);
 
1090
    } else {
 
1091
        /* Scan a numeric constant */
 
1092
        radix = 10;
 
1093
        m = 214748364;
 
1094
        if (cur_tok == octal_token) {
 
1095
            radix = 8;
 
1096
            m = 02000000000;
 
1097
            get_x_token();
 
1098
        } else if (cur_tok == hex_token) {
 
1099
            radix = 16;
 
1100
            m = 01000000000;
 
1101
            get_x_token();
 
1102
        }
 
1103
        vacuous = true;
 
1104
        cur_val = 0;
 
1105
        /* Accumulate the constant until |cur_tok| is not a suitable digit */
 
1106
        while (1) {
 
1107
            if ((cur_tok < zero_token + radix) && (cur_tok >= zero_token)
 
1108
                && (cur_tok <= zero_token + 9)) {
 
1109
                d = cur_tok - zero_token;
 
1110
            } else if (radix == 16) {
 
1111
                if ((cur_tok <= A_token + 5) && (cur_tok >= A_token)) {
 
1112
                    d = cur_tok - A_token + 10;
 
1113
                } else if ((cur_tok <= other_A_token + 5)
 
1114
                           && (cur_tok >= other_A_token)) {
 
1115
                    d = cur_tok - other_A_token + 10;
 
1116
                } else {
 
1117
                    break;
 
1118
                }
 
1119
            } else {
 
1120
                break;
 
1121
            }
 
1122
            vacuous = false;
 
1123
            if ((cur_val >= m) && ((cur_val > m) || (d > 7) || (radix != 10))) {
 
1124
                if (OK_so_far) {
 
1125
                    print_err("Number too big");
 
1126
                    help2
 
1127
                        ("I can only go up to 2147483647='17777777777=\"7FFFFFFF,",
 
1128
                         "so I'm using that number instead of yours.");
 
1129
                    error();
 
1130
                    cur_val = infinity;
 
1131
                    OK_so_far = false;
 
1132
                }
 
1133
            } else {
 
1134
                cur_val = cur_val * radix + d;
 
1135
            }
 
1136
            get_x_token();
 
1137
        }
 
1138
        if (vacuous) {
 
1139
            /* Express astonishment that no number was here */
 
1140
            print_err("Missing number, treated as zero");
 
1141
            help3("A number should have been here; I inserted `0'.",
 
1142
                  "(If you can't figure out why I needed to see a number,",
 
1143
                  "look up `weird error' in the index to The TeXbook.)");
 
1144
            back_error();
 
1145
        } else if (cur_cmd != spacer_cmd) {
 
1146
            back_input();
 
1147
        }
 
1148
    }
 
1149
    if (negative)
 
1150
        negate(cur_val);
 
1151
}
 
1152
 
 
1153
 
 
1154
@ The following code is executed when |scan_something_internal| was
 
1155
called asking for |mu_val|, when we really wanted a ``mudimen'' instead
 
1156
of ``muglue.''
 
1157
 
 
1158
@c
 
1159
static void coerce_glue(void)
 
1160
{
 
1161
    int v;
 
1162
    if (cur_val_level >= glue_val_level) {
 
1163
        v = width(cur_val);
 
1164
        delete_glue_ref(cur_val);
 
1165
        cur_val = v;
 
1166
    }
 
1167
}
 
1168
 
 
1169
 
 
1170
 
 
1171
@ The |scan_dimen| routine is similar to |scan_int|, but it sets |cur_val| to
 
1172
a |scaled| value, i.e., an integral number of sp. One of its main tasks
 
1173
is therefore to interpret the abbreviations for various kinds of units and
 
1174
to convert measurements to scaled points.
 
1175
 
 
1176
There are three parameters: |mu| is |true| if the finite units must be
 
1177
`\.{mu}', while |mu| is |false| if `\.{mu}' units are disallowed;
 
1178
|inf| is |true| if the infinite units `\.{fil}', `\.{fill}', `\.{filll}'
 
1179
are permitted; and |shortcut| is |true| if |cur_val| already contains
 
1180
an integer and only the units need to be considered.
 
1181
 
 
1182
The order of infinity that was found in the case of infinite glue is returned
 
1183
in the global variable |cur_order|.
 
1184
 
 
1185
@c
 
1186
int cur_order;                  /* order of infinity found by |scan_dimen| */
 
1187
 
 
1188
 
 
1189
@ Constructions like `\.{-\'77 pt}' are legal dimensions, so |scan_dimen|
 
1190
may begin with |scan_int|. This explains why it is convenient to use
 
1191
|scan_int| also for the integer part of a decimal fraction.
 
1192
 
 
1193
Several branches of |scan_dimen| work with |cur_val| as an integer and
 
1194
with an auxiliary fraction |f|, so that the actual quantity of interest is
 
1195
$|cur_val|+|f|/2^{16}$. At the end of the routine, this ``unpacked''
 
1196
representation is put into the single word |cur_val|, which suddenly
 
1197
switches significance from |integer| to |scaled|.
 
1198
 
 
1199
@c
 
1200
void scan_dimen(boolean mu, boolean inf, boolean shortcut)
 
1201
/* sets |cur_val| to a dimension */
 
1202
{
 
1203
    boolean negative;           /* should the answer be negated? */
 
1204
    int f;                      /* numerator of a fraction whose denominator is $2^{16}$ */
 
1205
    /* Local variables for dimension calculations */
 
1206
    int num, denom;             /* conversion ratio for the scanned units */
 
1207
    int k, kk;                  /* number of digits in a decimal fraction */
 
1208
    halfword p, q;              /* top of decimal digit stack */
 
1209
    scaled v;                   /* an internal dimension */
 
1210
    int save_cur_val;           /* temporary storage of |cur_val| */
 
1211
 
 
1212
    f = 0;
 
1213
    arith_error = false;
 
1214
    cur_order = normal;
 
1215
    negative = false;
 
1216
    if (!shortcut) {
 
1217
        /* Get the next non-blank non-sign... */
 
1218
        negative = false;
 
1219
        do {
 
1220
            /* Get the next non-blank non-call token */
 
1221
            do {
 
1222
                get_x_token();
 
1223
            } while (cur_cmd == spacer_cmd);
 
1224
            if (cur_tok == other_token + '-') {
 
1225
                negative = !negative;
 
1226
                cur_tok = other_token + '+';
 
1227
            }
 
1228
        } while (cur_tok == other_token + '+');
 
1229
 
 
1230
        if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
 
1231
            /* Fetch an internal dimension and |goto attach_sign|,
 
1232
               or fetch an internal integer */
 
1233
            if (mu) {
 
1234
                scan_something_internal(mu_val_level, false);
 
1235
                coerce_glue();
 
1236
                if (cur_val_level == mu_val_level)
 
1237
                    goto ATTACH_SIGN;
 
1238
                if (cur_val_level != int_val_level)
 
1239
                    mu_error();
 
1240
            } else {
 
1241
                scan_something_internal(dimen_val_level, false);
 
1242
                if (cur_val_level == dimen_val_level)
 
1243
                    goto ATTACH_SIGN;
 
1244
            }
 
1245
 
 
1246
        } else {
 
1247
            back_input();
 
1248
            if (cur_tok == continental_point_token) {
 
1249
                cur_tok = point_token;
 
1250
            }
 
1251
            if (cur_tok != point_token) {
 
1252
                scan_int();
 
1253
            } else {
 
1254
                radix = 10;
 
1255
                cur_val = 0;
 
1256
            }
 
1257
            if (cur_tok == continental_point_token)
 
1258
                cur_tok = point_token;
 
1259
            if ((radix == 10) && (cur_tok == point_token)) {
 
1260
                /* Scan decimal fraction */
 
1261
                /* When the following code is executed, we have |cur_tok=point_token|, but this
 
1262
                   token has been backed up using |back_input|; we must first discard it.
 
1263
 
 
1264
                   It turns out that a decimal point all by itself is equivalent to `\.{0.0}'.
 
1265
                   Let's hope people don't use that fact. */
 
1266
 
 
1267
                k = 0;
 
1268
                p = null;
 
1269
                get_token();    /* |point_token| is being re-scanned */
 
1270
                while (1) {
 
1271
                    get_x_token();
 
1272
                    if ((cur_tok > zero_token + 9) || (cur_tok < zero_token))
 
1273
                        break;
 
1274
                    if (k < 17) {       /* digits for |k>=17| cannot affect the result */
 
1275
                        q = get_avail();
 
1276
                        set_token_link(q, p);
 
1277
                        set_token_info(q, cur_tok - zero_token);
 
1278
                        p = q;
 
1279
                        incr(k);
 
1280
                    }
 
1281
                }
 
1282
                for (kk = k; kk >= 1; kk--) {
 
1283
                    dig[kk - 1] = token_info(p);
 
1284
                    q = p;
 
1285
                    p = token_link(p);
 
1286
                    free_avail(q);
 
1287
                }
 
1288
                f = round_decimals(k);
 
1289
                if (cur_cmd != spacer_cmd)
 
1290
                    back_input();
 
1291
            }
 
1292
        }
 
1293
    }
 
1294
    if (cur_val < 0) {          /* in this case |f=0| */
 
1295
        negative = !negative;
 
1296
        negate(cur_val);
 
1297
    }
 
1298
    /* Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$, where there
 
1299
       are |x| sp per unit; |goto attach_sign| if the units are internal */
 
1300
    /* Now comes the harder part: At this point in the program, |cur_val| is a
 
1301
       nonnegative integer and $f/2^{16}$ is a nonnegative fraction less than 1;
 
1302
       we want to multiply the sum of these two quantities by the appropriate
 
1303
       factor, based on the specified units, in order to produce a |scaled|
 
1304
       result, and we want to do the calculation with fixed point arithmetic that
 
1305
       does not overflow.
 
1306
     */
 
1307
 
 
1308
    if (inf) {
 
1309
        /* Scan for (f)\.{fil} units; |goto attach_fraction| if found */
 
1310
        /* In traditional TeX, a specification like `\.{filllll}' or `\.{fill L L
 
1311
           L}' will lead to two error messages (one for each additional keyword
 
1312
           \.{"l"}). 
 
1313
           Not so for luatex, it just parses the construct in reverse. */
 
1314
        if (scan_keyword("filll")) {
 
1315
            cur_order = filll;
 
1316
            goto ATTACH_FRACTION;
 
1317
        } else if (scan_keyword("fill")) {
 
1318
            cur_order = fill;
 
1319
            goto ATTACH_FRACTION;
 
1320
        } else if (scan_keyword("fil")) {
 
1321
            cur_order = fil;
 
1322
            goto ATTACH_FRACTION;
 
1323
        } else if (scan_keyword("fi")) {
 
1324
            cur_order = sfi;
 
1325
            goto ATTACH_FRACTION;
 
1326
        }
 
1327
 
 
1328
    }
 
1329
    /* Scan for (u)units that are internal dimensions;
 
1330
       |goto attach_sign| with |cur_val| set if found */
 
1331
    save_cur_val = cur_val;
 
1332
    /* Get the next non-blank non-call... */
 
1333
    do {
 
1334
        get_x_token();
 
1335
    } while (cur_cmd == spacer_cmd);
 
1336
 
 
1337
    if ((cur_cmd < min_internal_cmd) || (cur_cmd > max_internal_cmd)) {
 
1338
        back_input();
 
1339
    } else {
 
1340
        if (mu) {
 
1341
            scan_something_internal(mu_val_level, false);
 
1342
            coerce_glue();
 
1343
            if (cur_val_level != mu_val_level)
 
1344
                mu_error();
 
1345
        } else {
 
1346
            scan_something_internal(dimen_val_level, false);
 
1347
        }
 
1348
        v = cur_val;
 
1349
        goto FOUND;
 
1350
    }
 
1351
    if (mu)
 
1352
        goto NOT_FOUND;
 
1353
    if (scan_keyword("em")) {
 
1354
        v = (quad(get_cur_font()));
 
1355
    } else if (scan_keyword("ex")) {
 
1356
        v = (x_height(get_cur_font()));
 
1357
    } else if (scan_keyword("px")) {
 
1358
        v = dimen_par(pdf_px_dimen_code);
 
1359
    } else {
 
1360
        goto NOT_FOUND;
 
1361
    }
 
1362
    /* Scan an optional space */
 
1363
    get_x_token();
 
1364
    if (cur_cmd != spacer_cmd)
 
1365
        back_input();
 
1366
 
 
1367
  FOUND:
 
1368
    cur_val = nx_plus_y(save_cur_val, v, xn_over_d(v, f, 0200000));
 
1369
    goto ATTACH_SIGN;
 
1370
  NOT_FOUND:
 
1371
 
 
1372
    if (mu) {
 
1373
        /* Scan for (m)\.{mu} units and |goto attach_fraction| */
 
1374
        if (scan_keyword("mu")) {
 
1375
            goto ATTACH_FRACTION;
 
1376
        } else {
 
1377
            print_err("Illegal unit of measure (mu inserted)");
 
1378
            help4("The unit of measurement in math glue must be mu.",
 
1379
                  "To recover gracefully from this error, it's best to",
 
1380
                  "delete the erroneous units; e.g., type `2' to delete",
 
1381
                  "two letters. (See Chapter 27 of The TeXbook.)");
 
1382
            error();
 
1383
            goto ATTACH_FRACTION;
 
1384
        }
 
1385
    }
 
1386
    if (scan_keyword("true")) {
 
1387
        /* Adjust (f)for the magnification ratio */
 
1388
        prepare_mag();
 
1389
        if (int_par(mag_code) != 1000) {
 
1390
            cur_val = xn_over_d(cur_val, 1000, int_par(mag_code));
 
1391
            f = (1000 * f + 0200000 * tex_remainder) / int_par(mag_code);
 
1392
            cur_val = cur_val + (f / 0200000);
 
1393
            f = f % 0200000;
 
1394
        }
 
1395
    }
 
1396
    if (scan_keyword("pt"))
 
1397
        goto ATTACH_FRACTION;   /* the easy case */
 
1398
    /* Scan for (a)all other units and adjust |cur_val| and |f| accordingly;
 
1399
       |goto done| in the case of scaled points */
 
1400
 
 
1401
    /* The necessary conversion factors can all be specified exactly as
 
1402
       fractions whose numerator and denominator add to 32768 or less.
 
1403
       According to the definitions here, $\rm2660\,dd\approx1000.33297\,mm$;
 
1404
       this agrees well with the value $\rm1000.333\,mm$ cited by Bosshard
 
1405
       \^{Bosshard, Hans Rudolf}
 
1406
       in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980).
 
1407
       The Didot point has been newly standardized in 1978;
 
1408
       it's now exactly $\rm 1\,nd=0.375\,mm$.
 
1409
       Conversion uses the equation $0.375=21681/20320/72.27\cdot25.4$.
 
1410
       The new Cicero follows the new Didot point; $\rm 1\,nc=12\,nd$.
 
1411
       These would lead to the ratios $21681/20320$ and $65043/5080$,
 
1412
       respectively.
 
1413
       The closest approximations supported by the algorithm would be
 
1414
       $11183/10481$ and $1370/107$.  In order to maintain the
 
1415
       relation $\rm 1\,nc=12\,nd$, we pick the ratio $685/642$ for
 
1416
       $\rm nd$, however.
 
1417
     */
 
1418
 
 
1419
#define set_conversion(A,B) do { num=(A); denom=(B); } while(0)
 
1420
 
 
1421
    if (scan_keyword("in")) {
 
1422
        set_conversion(7227, 100);
 
1423
    } else if (scan_keyword("pc")) {
 
1424
        set_conversion(12, 1);
 
1425
    } else if (scan_keyword("cm")) {
 
1426
        set_conversion(7227, 254);
 
1427
    } else if (scan_keyword("mm")) {
 
1428
        set_conversion(7227, 2540);
 
1429
    } else if (scan_keyword("bp")) {
 
1430
        set_conversion(7227, 7200);
 
1431
    } else if (scan_keyword("dd")) {
 
1432
        set_conversion(1238, 1157);
 
1433
    } else if (scan_keyword("cc")) {
 
1434
        set_conversion(14856, 1157);
 
1435
    } else if (scan_keyword("nd")) {
 
1436
        set_conversion(685, 642);
 
1437
    } else if (scan_keyword("nc")) {
 
1438
        set_conversion(1370, 107);
 
1439
    } else if (scan_keyword("sp")) {
 
1440
        goto DONE;
 
1441
    } else {
 
1442
        /* Complain about unknown unit and |goto done2| */
 
1443
        print_err("Illegal unit of measure (pt inserted)");
 
1444
        help6("Dimensions can be in units of em, ex, in, pt, pc,",
 
1445
              "cm, mm, dd, cc, nd, nc, bp, or sp; but yours is a new one!",
 
1446
              "I'll assume that you meant to say pt, for printer's points.",
 
1447
              "To recover gracefully from this error, it's best to",
 
1448
              "delete the erroneous units; e.g., type `2' to delete",
 
1449
              "two letters. (See Chapter 27 of The TeXbook.)");
 
1450
        error();
 
1451
        goto DONE2;
 
1452
    }
 
1453
    cur_val = xn_over_d(cur_val, num, denom);
 
1454
    f = (num * f + 0200000 * tex_remainder) / denom;
 
1455
    cur_val = cur_val + (f / 0200000);
 
1456
    f = f % 0200000;
 
1457
  DONE2:
 
1458
  ATTACH_FRACTION:
 
1459
    if (cur_val >= 040000)
 
1460
        arith_error = true;
 
1461
    else
 
1462
        cur_val = cur_val * unity + f;
 
1463
  DONE:
 
1464
    /* Scan an optional space */
 
1465
    get_x_token();
 
1466
    if (cur_cmd != spacer_cmd)
 
1467
        back_input();
 
1468
  ATTACH_SIGN:
 
1469
    if (arith_error || (abs(cur_val) >= 010000000000)) {
 
1470
        /* Report that this dimension is out of range */
 
1471
        print_err("Dimension too large");
 
1472
        help2("I can't work with sizes bigger than about 19 feet.",
 
1473
              "Continue and I'll use the largest value I can.");
 
1474
        error();
 
1475
        cur_val = max_dimen;
 
1476
        arith_error = false;
 
1477
    }
 
1478
    if (negative)
 
1479
        negate(cur_val);
 
1480
}
 
1481
 
 
1482
 
 
1483
@ The final member of \TeX's value-scanning trio is |scan_glue|, which
 
1484
makes |cur_val| point to a glue specification. The reference count of that
 
1485
glue spec will take account of the fact that |cur_val| is pointing to~it.
 
1486
 
 
1487
The |level| parameter should be either |glue_val| or |mu_val|.
 
1488
 
 
1489
Since |scan_dimen| was so much more complex than |scan_int|, we might expect
 
1490
|scan_glue| to be even worse. But fortunately, it is very simple, since
 
1491
most of the work has already been done.
 
1492
 
 
1493
@c
 
1494
void scan_glue(int level)
 
1495
{                               /* sets |cur_val| to a glue spec pointer */
 
1496
    boolean negative;           /* should the answer be negated? */
 
1497
    halfword q;                 /* new glue specification */
 
1498
    boolean mu;                 /* does |level=mu_val|? */
 
1499
    mu = (level == mu_val_level);
 
1500
    /* Get the next non-blank non-sign... */
 
1501
    negative = false;
 
1502
    do {
 
1503
        /* Get the next non-blank non-call token */
 
1504
        do {
 
1505
            get_x_token();
 
1506
        } while (cur_cmd == spacer_cmd);
 
1507
        if (cur_tok == other_token + '-') {
 
1508
            negative = !negative;
 
1509
            cur_tok = other_token + '+';
 
1510
        }
 
1511
    } while (cur_tok == other_token + '+');
 
1512
 
 
1513
    if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
 
1514
        scan_something_internal(level, negative);
 
1515
        if (cur_val_level >= glue_val_level) {
 
1516
            if (cur_val_level != level)
 
1517
                mu_error();
 
1518
            return;
 
1519
        }
 
1520
        if (cur_val_level == int_val_level)
 
1521
            scan_dimen(mu, false, true);
 
1522
        else if (level == mu_val_level)
 
1523
            mu_error();
 
1524
    } else {
 
1525
        back_input();
 
1526
        scan_dimen(mu, false, false);
 
1527
        if (negative)
 
1528
            negate(cur_val);
 
1529
    }
 
1530
    /* Create a new glue specification whose width is |cur_val|; scan for its
 
1531
       stretch and shrink components  */
 
1532
    q = new_spec(zero_glue);
 
1533
    width(q) = cur_val;
 
1534
    if (scan_keyword("plus")) {
 
1535
        scan_dimen(mu, true, false);
 
1536
        stretch(q) = cur_val;
 
1537
        stretch_order(q) = (quarterword) cur_order;
 
1538
    }
 
1539
    if (scan_keyword("minus")) {
 
1540
        scan_dimen(mu, true, false);
 
1541
        shrink(q) = cur_val;
 
1542
        shrink_order(q) = (quarterword) cur_order;
 
1543
    }
 
1544
    cur_val = q;
 
1545
}
 
1546
 
 
1547
@ This is an omega routine 
 
1548
@c
 
1549
void scan_scaled(void)
 
1550
{                               /* sets |cur_val| to a scaled value */
 
1551
    boolean negative;           /* should the answer be negated? */
 
1552
    int f;                      /* numerator of a fraction whose denominator is $2^{16}$ */
 
1553
    int k, kk;                  /* number of digits in a decimal fraction */
 
1554
    halfword p, q;              /* top of decimal digit stack */
 
1555
    f = 0;
 
1556
    arith_error = false;
 
1557
    negative = false;
 
1558
    /* Get the next non-blank non-sign... */
 
1559
    negative = false;
 
1560
    do {
 
1561
        /* Get the next non-blank non-call token */
 
1562
        do {
 
1563
            get_x_token();
 
1564
        } while (cur_cmd == spacer_cmd);
 
1565
        if (cur_tok == other_token + '-') {
 
1566
            negative = !negative;
 
1567
            cur_tok = other_token + '+';
 
1568
        }
 
1569
    } while (cur_tok == other_token + '+');
 
1570
 
 
1571
    back_input();
 
1572
    if (cur_tok == continental_point_token)
 
1573
        cur_tok = point_token;
 
1574
    if (cur_tok != point_token) {
 
1575
        scan_int();
 
1576
    } else {
 
1577
        radix = 10;
 
1578
        cur_val = 0;
 
1579
    }
 
1580
    if (cur_tok == continental_point_token)
 
1581
        cur_tok = point_token;
 
1582
    if ((radix == 10) && (cur_tok == point_token)) {
 
1583
        /* Scan decimal fraction */
 
1584
        /* TODO: merge this with the same block in |scan_dimen| */
 
1585
        /* When the following code is executed, we have |cur_tok=point_token|, but this
 
1586
           token has been backed up using |back_input|; we must first discard it.
 
1587
 
 
1588
           It turns out that a decimal point all by itself is equivalent to `\.{0.0}'.
 
1589
           Let's hope people don't use that fact. */
 
1590
 
 
1591
        k = 0;
 
1592
        p = null;
 
1593
        get_token();            /* |point_token| is being re-scanned */
 
1594
        while (1) {
 
1595
            get_x_token();
 
1596
            if ((cur_tok > zero_token + 9) || (cur_tok < zero_token))
 
1597
                break;
 
1598
            if (k < 17) {       /* digits for |k>=17| cannot affect the result */
 
1599
                q = get_avail();
 
1600
                set_token_link(q, p);
 
1601
                set_token_info(q, cur_tok - zero_token);
 
1602
                p = q;
 
1603
                incr(k);
 
1604
            }
 
1605
        }
 
1606
        for (kk = k; kk >= 1; kk--) {
 
1607
            dig[kk - 1] = token_info(p);
 
1608
            q = p;
 
1609
            p = token_link(p);
 
1610
            free_avail(q);
 
1611
        }
 
1612
        f = round_decimals(k);
 
1613
        if (cur_cmd != spacer_cmd)
 
1614
            back_input();
 
1615
 
 
1616
    }
 
1617
    if (cur_val < 0) {          /* in this case |f=0| */
 
1618
        negative = !negative;
 
1619
        negate(cur_val);
 
1620
    }
 
1621
    if (cur_val > 040000)
 
1622
        arith_error = true;
 
1623
    else
 
1624
        cur_val = cur_val * unity + f;
 
1625
    if (arith_error || (abs(cur_val) >= 010000000000)) {
 
1626
        print_err("Stack number too large");
 
1627
        error();
 
1628
    }
 
1629
    if (negative)
 
1630
        negate(cur_val);
 
1631
}
 
1632
 
 
1633
 
 
1634
@ This procedure is supposed to scan something like `\.{\\skip\\count12}',
 
1635
i.e., whatever can follow `\.{\\the}', and it constructs a token list
 
1636
containing something like `\.{-3.0pt minus 0.5fill}'.
 
1637
 
 
1638
@c
 
1639
halfword the_toks(void)
 
1640
{
 
1641
    int old_setting;            /* holds |selector| setting */
 
1642
    halfword p, q, r;           /* used for copying a token list */
 
1643
    int c;                      /* value of |cur_chr| */
 
1644
    str_number s;
 
1645
    halfword retval;
 
1646
    /* Handle \.{\\unexpanded} or \.{\\detokenize} and |return| */
 
1647
    if (odd(cur_chr)) {
 
1648
        c = cur_chr;
 
1649
        scan_general_text();
 
1650
        if (c == 1) {
 
1651
            return cur_val;
 
1652
        } else {
 
1653
            old_setting = selector;
 
1654
            selector = new_string;
 
1655
            p = get_avail();
 
1656
            set_token_link(p, token_link(temp_token_head));
 
1657
            token_show(p);
 
1658
            flush_list(p);
 
1659
            selector = old_setting;
 
1660
            s = make_string();
 
1661
            retval = str_toks(str_lstring(s));
 
1662
            flush_str(s);
 
1663
            return retval;
 
1664
        }
 
1665
    }
 
1666
    get_x_token();
 
1667
    scan_something_internal(tok_val_level, false);
 
1668
    if (cur_val_level >= ident_val_level) {
 
1669
        /* Copy the token list */
 
1670
        p = temp_token_head;
 
1671
        set_token_link(p, null);
 
1672
        if (cur_val_level == ident_val_level) {
 
1673
            store_new_token(cs_token_flag + cur_val);
 
1674
        } else if (cur_val != null) {
 
1675
            r = token_link(cur_val);    /* do not copy the reference count */
 
1676
            while (r != null) {
 
1677
                fast_store_new_token(token_info(r));
 
1678
                r = token_link(r);
 
1679
            }
 
1680
        }
 
1681
        return p;
 
1682
    } else {
 
1683
        old_setting = selector;
 
1684
        selector = new_string;
 
1685
        switch (cur_val_level) {
 
1686
        case int_val_level:
 
1687
            print_int(cur_val);
 
1688
            break;
 
1689
        case attr_val_level:
 
1690
            print_int(cur_val);
 
1691
            break;
 
1692
        case dir_val_level:
 
1693
            print_dir(cur_val);
 
1694
            break;
 
1695
        case dimen_val_level:
 
1696
            print_scaled(cur_val);
 
1697
            tprint("pt");
 
1698
            break;
 
1699
        case glue_val_level:
 
1700
            print_spec(cur_val, "pt");
 
1701
            delete_glue_ref(cur_val);
 
1702
            break;
 
1703
        case mu_val_level:
 
1704
            print_spec(cur_val, "mu");
 
1705
            delete_glue_ref(cur_val);
 
1706
            break;
 
1707
        }                       /* there are no other cases */
 
1708
        selector = old_setting;
 
1709
        s = make_string();
 
1710
        retval = str_toks(str_lstring(s));
 
1711
        flush_str(s);
 
1712
        return retval;
 
1713
    }
 
1714
}
 
1715
 
 
1716
@ @c
 
1717
str_number the_scanned_result(void)
 
1718
{
 
1719
    int old_setting;            /* holds |selector| setting */
 
1720
    str_number r;               /* return value * */
 
1721
    old_setting = selector;
 
1722
    selector = new_string;
 
1723
    if (cur_val_level >= ident_val_level) {
 
1724
        if (cur_val != null) {
 
1725
            show_token_list(token_link(cur_val), null, -1);
 
1726
            r = make_string();
 
1727
        } else {
 
1728
            r = get_nullstr();
 
1729
        }
 
1730
    } else {
 
1731
        switch (cur_val_level) {
 
1732
        case int_val_level:
 
1733
            print_int(cur_val);
 
1734
            break;
 
1735
        case attr_val_level:
 
1736
            print_int(cur_val);
 
1737
            break;
 
1738
        case dir_val_level:
 
1739
            print_dir(cur_val);
 
1740
            break;
 
1741
        case dimen_val_level:
 
1742
            print_scaled(cur_val);
 
1743
            tprint("pt");
 
1744
            break;
 
1745
        case glue_val_level:
 
1746
            print_spec(cur_val, "pt");
 
1747
            delete_glue_ref(cur_val);
 
1748
            break;
 
1749
        case mu_val_level:
 
1750
            print_spec(cur_val, "mu");
 
1751
            delete_glue_ref(cur_val);
 
1752
            break;
 
1753
        }                       /* there are no other cases */
 
1754
        r = make_string();
 
1755
    }
 
1756
    selector = old_setting;
 
1757
    return r;
 
1758
}
 
1759
 
 
1760
 
 
1761
 
 
1762
@ The following routine is used to implement `\.{\\fontdimen} |n| |f|'.
 
1763
The boolean parameter |writing| is set |true| if the calling program
 
1764
intends to change the parameter value.
 
1765
 
 
1766
@c
 
1767
static void font_param_error(int f)
 
1768
{
 
1769
    print_err("Font ");
 
1770
    print_esc(font_id_text(f));
 
1771
    tprint(" has only ");
 
1772
    print_int(font_params(f));
 
1773
    tprint(" fontdimen parameters");
 
1774
    help2("To increase the number of font parameters, you must",
 
1775
          "use \\fontdimen immediately after the \\font is loaded.");
 
1776
    error();
 
1777
}
 
1778
 
 
1779
void set_font_dimen(void)
 
1780
{
 
1781
    internal_font_number f;
 
1782
    int n;                      /* the parameter number */
 
1783
    scan_int();
 
1784
    n = cur_val;
 
1785
    scan_font_ident();
 
1786
    f = cur_val;
 
1787
    if (n <= 0) {
 
1788
        font_param_error(f);
 
1789
    } else {
 
1790
        if (n > font_params(f)) {
 
1791
            if (font_used(f)) {
 
1792
                font_param_error(f);
 
1793
            } else {
 
1794
                /* Increase the number of parameters in the font */
 
1795
                do {
 
1796
                    set_font_param(f, (font_params(f) + 1), 0);
 
1797
                } while (n != font_params(f));
 
1798
            }
 
1799
        }
 
1800
    }
 
1801
    scan_optional_equals();
 
1802
    scan_normal_dimen();
 
1803
    set_font_param(f, n, cur_val);
 
1804
}
 
1805
 
 
1806
void get_font_dimen(void)
 
1807
{
 
1808
    internal_font_number f;
 
1809
    int n;                      /* the parameter number */
 
1810
    scan_int();
 
1811
    n = cur_val;
 
1812
    scan_font_ident();
 
1813
    f = cur_val;
 
1814
    cur_val = 0;                /* initialize return value */
 
1815
    if (n <= 0) {
 
1816
        font_param_error(f);
 
1817
        goto EXIT;
 
1818
    } else {
 
1819
        if (n > font_params(f)) {
 
1820
            if (font_used(f)) {
 
1821
                font_param_error(f);
 
1822
                goto EXIT;
 
1823
            } else {
 
1824
                /* Increase the number of parameters in the font */
 
1825
                do {
 
1826
                    set_font_param(f, (font_params(f) + 1), 0);
 
1827
                } while (n != font_params(f));
 
1828
 
 
1829
            }
 
1830
        }
 
1831
    }
 
1832
    cur_val = font_param(f, n);
 
1833
  EXIT:
 
1834
    scanned_result(cur_val, dimen_val_level);
 
1835
}
 
1836
 
 
1837
 
 
1838
@ Here's a similar procedure that returns a pointer to a rule node. This
 
1839
routine is called just after \TeX\ has seen \.{\\hrule} or \.{\\vrule};
 
1840
therefore |cur_cmd| will be either |hrule| or |vrule|. The idea is to store
 
1841
the default rule dimensions in the node, then to override them if
 
1842
`\.{height}' or `\.{width}' or `\.{depth}' specifications are
 
1843
found (in any order).
 
1844
 
 
1845
@c
 
1846
halfword scan_rule_spec(void)
 
1847
{
 
1848
    halfword q;                 /* the rule node being created */
 
1849
    q = new_rule();             /* |width|, |depth|, and |height| all equal |null_flag| now */
 
1850
    if (cur_cmd == vrule_cmd) {
 
1851
        width(q) = default_rule;
 
1852
        rule_dir(q) = body_direction;
 
1853
    } else {
 
1854
        height(q) = default_rule;
 
1855
        depth(q) = 0;
 
1856
        rule_dir(q) = text_direction;
 
1857
    }
 
1858
  RESWITCH:
 
1859
    if (scan_keyword("width")) {
 
1860
        scan_normal_dimen();
 
1861
        width(q) = cur_val;
 
1862
        goto RESWITCH;
 
1863
    }
 
1864
    if (scan_keyword("height")) {
 
1865
        scan_normal_dimen();
 
1866
        height(q) = cur_val;
 
1867
        goto RESWITCH;
 
1868
    }
 
1869
    if (scan_keyword("depth")) {
 
1870
        scan_normal_dimen();
 
1871
        depth(q) = cur_val;
 
1872
        goto RESWITCH;
 
1873
    }
 
1874
    return q;
 
1875
}
 
1876
 
 
1877
 
 
1878
@ Declare procedures that scan font-related stuff
 
1879
 
 
1880
@c
 
1881
void scan_font_ident(void)
 
1882
{
 
1883
    internal_font_number f;
 
1884
    halfword m;
 
1885
    /* Get the next non-blank non-call... */
 
1886
    do {
 
1887
        get_x_token();
 
1888
    } while (cur_cmd == spacer_cmd);
 
1889
 
 
1890
    if ((cur_cmd == def_font_cmd) || (cur_cmd == letterspace_font_cmd)
 
1891
        || (cur_cmd == pdf_copy_font_cmd)) {
 
1892
        f = get_cur_font();
 
1893
    } else if (cur_cmd == set_font_cmd) {
 
1894
        f = cur_chr;
 
1895
        set_font_touched(f, 1);
 
1896
    } else if (cur_cmd == def_family_cmd) {
 
1897
        m = cur_chr;
 
1898
        scan_math_family_int();
 
1899
        f = fam_fnt(cur_val, m);
 
1900
        set_font_touched(f, 1);
 
1901
    } else {
 
1902
        print_err("Missing font identifier");
 
1903
        help2("I was looking for a control sequence whose",
 
1904
              "current meaning has been defined by \\font.");
 
1905
        back_error();
 
1906
        f = null_font;
 
1907
    }
 
1908
    cur_val = f;
 
1909
}
 
1910
 
 
1911
@ The |scan_general_text| procedure is much like |scan_toks(false,false)|,
 
1912
but will be invoked via |expand|, i.e., recursively. 
 
1913
 
 
1914
The token list (balanced text) created by |scan_general_text| begins
 
1915
at |link(temp_token_head)| and ends at |cur_val|.  (If |cur_val=temp_token_head|,
 
1916
the list is empty.)
 
1917
 
 
1918
@c
 
1919
void scan_general_text(void)
 
1920
{
 
1921
    int s;                      /* to save |scanner_status| */
 
1922
    halfword w;                 /* to save |warning_index| */
 
1923
    halfword d;                 /* to save |def_ref| */
 
1924
    halfword p;                 /* tail of the token list being built */
 
1925
    halfword q;                 /* new node being added to the token list via |store_new_token| */
 
1926
    halfword unbalance;         /* number of unmatched left braces */
 
1927
    s = scanner_status;
 
1928
    w = warning_index;
 
1929
    d = def_ref;
 
1930
    scanner_status = absorbing;
 
1931
    warning_index = cur_cs;
 
1932
    p = get_avail();
 
1933
    def_ref = p;
 
1934
    set_token_ref_count(def_ref, 0);
 
1935
    p = def_ref;
 
1936
    scan_left_brace();          /* remove the compulsory left brace */
 
1937
    unbalance = 1;
 
1938
    while (1) {
 
1939
        get_token();
 
1940
        if (cur_tok < right_brace_limit) {
 
1941
            if (cur_cmd < right_brace_cmd) {
 
1942
                incr(unbalance);
 
1943
            } else {
 
1944
                decr(unbalance);
 
1945
                if (unbalance == 0)
 
1946
                    break;
 
1947
            }
 
1948
        }
 
1949
        store_new_token(cur_tok);
 
1950
    }
 
1951
    q = token_link(def_ref);
 
1952
    free_avail(def_ref);        /* discard reference count */
 
1953
    if (q == null)
 
1954
        cur_val = temp_token_head;
 
1955
    else
 
1956
        cur_val = p;
 
1957
    set_token_link(temp_token_head, q);
 
1958
    scanner_status = s;
 
1959
    warning_index = w;
 
1960
    def_ref = d;
 
1961
}
 
1962
 
 
1963
 
 
1964
@ The |get_x_or_protected| procedure is like |get_x_token| except that
 
1965
protected macros are not expanded.
 
1966
 
 
1967
@c
 
1968
void get_x_or_protected(void)
 
1969
{                               /* sets |cur_cmd|, |cur_chr|, |cur_tok|,
 
1970
                                   and expands non-protected macros */
 
1971
    while (1) {
 
1972
        get_token();
 
1973
        if (cur_cmd <= max_command_cmd)
 
1974
            return;
 
1975
        if ((cur_cmd >= call_cmd) && (cur_cmd < end_template_cmd)) {
 
1976
            if (token_info(token_link(cur_chr)) == protected_token)
 
1977
                return;
 
1978
        }
 
1979
        expand();
 
1980
    }
 
1981
}
 
1982
 
 
1983
 
 
1984
@ |scan_toks|. This function returns a pointer to the tail of a new token
 
1985
list, and it also makes |def_ref| point to the reference count at the
 
1986
head of that list.
 
1987
 
 
1988
There are two boolean parameters, |macro_def| and |xpand|. If |macro_def|
 
1989
is true, the goal is to create the token list for a macro definition;
 
1990
otherwise the goal is to create the token list for some other \TeX\
 
1991
primitive: \.{\\mark}, \.{\\output}, \.{\\everypar}, \.{\\lowercase},
 
1992
\.{\\uppercase}, \.{\\message}, \.{\\errmessage}, \.{\\write}, or
 
1993
\.{\\special}. In the latter cases a left brace must be scanned next; this
 
1994
left brace will not be part of the token list, nor will the matching right
 
1995
brace that comes at the end. If |xpand| is false, the token list will
 
1996
simply be copied from the input using |get_token|. Otherwise all expandable
 
1997
tokens will be expanded until unexpandable tokens are left, except that
 
1998
the results of expanding `\.{\\the}' are not expanded further.
 
1999
If both |macro_def| and |xpand| are true, the expansion applies
 
2000
only to the macro body (i.e., to the material following the first
 
2001
|left_brace| character).
 
2002
 
 
2003
The value of |cur_cs| when |scan_toks| begins should be the |eqtb|
 
2004
address of the control sequence to display in ``runaway'' error
 
2005
messages.
 
2006
 
 
2007
@c
 
2008
halfword scan_toks(boolean macro_def, boolean xpand)
 
2009
{
 
2010
    halfword t;                 /* token representing the highest parameter number */
 
2011
    halfword s;                 /* saved token */
 
2012
    halfword p;                 /* tail of the token list being built */
 
2013
    halfword q;                 /* new node being added to the token list via |store_new_token| */
 
2014
    halfword unbalance;         /* number of unmatched left braces */
 
2015
    halfword hash_brace;        /* possible `\.{\#\{}' token */
 
2016
    if (macro_def)
 
2017
        scanner_status = defining;
 
2018
    else
 
2019
        scanner_status = absorbing;
 
2020
    warning_index = cur_cs;
 
2021
    p = get_avail();
 
2022
    def_ref = p;
 
2023
    set_token_ref_count(def_ref, 0);
 
2024
    p = def_ref;
 
2025
    hash_brace = 0;
 
2026
    t = zero_token;
 
2027
    if (macro_def) {
 
2028
        /* Scan and build the parameter part of the macro definition */
 
2029
        while (1) {
 
2030
            get_token();        /* set |cur_cmd|, |cur_chr|, |cur_tok| */
 
2031
            if (cur_tok < right_brace_limit)
 
2032
                break;
 
2033
            if (cur_cmd == mac_param_cmd) {
 
2034
                /* If the next character is a parameter number, make |cur_tok|
 
2035
                   a |match| token; but if it is a left brace, store
 
2036
                   `|left_brace|, |end_match|', set |hash_brace|, and |goto done|;
 
2037
                 */
 
2038
                s = match_token + cur_chr;
 
2039
                get_token();
 
2040
                if (cur_cmd == left_brace_cmd) {
 
2041
                    hash_brace = cur_tok;
 
2042
                    store_new_token(cur_tok);
 
2043
                    store_new_token(end_match_token);
 
2044
                    goto DONE;
 
2045
                }
 
2046
                if (t == zero_token + 9) {
 
2047
                    print_err("You already have nine parameters");
 
2048
                    help1("I'm going to ignore the # sign you just used.");
 
2049
                    error();
 
2050
                } else {
 
2051
                    incr(t);
 
2052
                    if (cur_tok != t) {
 
2053
                        print_err("Parameters must be numbered consecutively");
 
2054
                        help2
 
2055
                            ("I've inserted the digit you should have used after the #.",
 
2056
                             "Type `1' to delete what you did use.");
 
2057
                        back_error();
 
2058
                    }
 
2059
                    cur_tok = s;
 
2060
                }
 
2061
            }
 
2062
            store_new_token(cur_tok);
 
2063
        }
 
2064
        store_new_token(end_match_token);
 
2065
        if (cur_cmd == right_brace_cmd) {
 
2066
            /* Express shock at the missing left brace; |goto found| */
 
2067
            print_err("Missing { inserted");
 
2068
            incr(align_state);
 
2069
            help2
 
2070
                ("Where was the left brace? You said something like `\\def\\a}',",
 
2071
                 "which I'm going to interpret as `\\def\\a{}'.");
 
2072
            error();
 
2073
            goto FOUND;
 
2074
        }
 
2075
 
 
2076
    } else {
 
2077
        scan_left_brace();      /* remove the compulsory left brace */
 
2078
    }
 
2079
  DONE:
 
2080
    /* Scan and build the body of the token list; |goto found| when finished */
 
2081
    unbalance = 1;
 
2082
    while (1) {
 
2083
        if (xpand) {
 
2084
            /* Expand the next part of the input */
 
2085
            /* Here we insert an entire token list created by |the_toks| without
 
2086
               expanding it further. */
 
2087
            while (1) {
 
2088
                get_token_lua();
 
2089
                if (cur_cmd >= call_cmd) {
 
2090
                    if (token_info(token_link(cur_chr)) == protected_token) {
 
2091
                        cur_cmd = relax_cmd;
 
2092
                        cur_chr = no_expand_flag;
 
2093
                    }
 
2094
                }
 
2095
                if (cur_cmd <= max_command_cmd)
 
2096
                    break;
 
2097
                if (cur_cmd != the_cmd) {
 
2098
                    expand();
 
2099
                } else {
 
2100
                    q = the_toks();
 
2101
                    if (token_link(temp_token_head) != null) {
 
2102
                        set_token_link(p, token_link(temp_token_head));
 
2103
                        p = q;
 
2104
                    }
 
2105
                }
 
2106
            }
 
2107
            x_token();
 
2108
 
 
2109
        } else {
 
2110
            get_token();
 
2111
        }
 
2112
        if (cur_tok < right_brace_limit) {
 
2113
            if (cur_cmd < right_brace_cmd) {
 
2114
                incr(unbalance);
 
2115
            } else {
 
2116
                decr(unbalance);
 
2117
                if (unbalance == 0)
 
2118
                    goto FOUND;
 
2119
            }
 
2120
        } else if (cur_cmd == mac_param_cmd) {
 
2121
            if (macro_def) {
 
2122
                /* Look for parameter number or \.{\#\#} */
 
2123
                s = cur_tok;
 
2124
                if (xpand)
 
2125
                    get_x_token();
 
2126
                else
 
2127
                    get_token();
 
2128
                if (cur_cmd != mac_param_cmd) {
 
2129
                    if ((cur_tok <= zero_token) || (cur_tok > t)) {
 
2130
                        print_err("Illegal parameter number in definition of ");
 
2131
                        sprint_cs(warning_index);
 
2132
                        help3("You meant to type ## instead of #, right?",
 
2133
                              "Or maybe a } was forgotten somewhere earlier, and things",
 
2134
                              "are all screwed up? I''m going to assume that you meant ##.");
 
2135
                        back_error();
 
2136
                        cur_tok = s;
 
2137
                    } else {
 
2138
                        cur_tok = out_param_token - '0' + cur_chr;
 
2139
                    }
 
2140
                }
 
2141
            }
 
2142
        }
 
2143
        store_new_token(cur_tok);
 
2144
    }
 
2145
  FOUND:
 
2146
    scanner_status = normal;
 
2147
    if (hash_brace != 0)
 
2148
        store_new_token(hash_brace);
 
2149
    return p;
 
2150
}
 
2151
 
 
2152
 
 
2153
@ Here we declare two trivial procedures in order to avoid mutually
 
2154
recursive procedures with parameters.
 
2155
 
 
2156
@c
 
2157
void scan_normal_glue(void)
 
2158
{
 
2159
    scan_glue(glue_val_level);
 
2160
}
 
2161
 
 
2162
void scan_mu_glue(void)
 
2163
{
 
2164
    scan_glue(mu_val_level);
 
2165
}
 
2166
 
 
2167
@ The |scan_expr| procedure scans and evaluates an expression.
 
2168
 
 
2169
@ Evaluating an expression is a recursive process:  When the left
 
2170
parenthesis of a subexpression is scanned we descend to the next level
 
2171
of recursion; the previous level is resumed with the matching right
 
2172
parenthesis.
 
2173
 
 
2174
@c
 
2175
typedef enum {
 
2176
    expr_none = 0,              /* \.( seen, or \.( $\langle\it expr\rangle$ \.) seen */
 
2177
    expr_add = 1,               /* \.( $\langle\it expr\rangle$ \.+ seen */
 
2178
    expr_sub = 2,               /* \.( $\langle\it expr\rangle$ \.- seen */
 
2179
    expr_mult = 3,              /* $\langle\it term\rangle$ \.* seen */
 
2180
    expr_div = 4,               /* $\langle\it term\rangle$ \./ seen */
 
2181
    expr_scale = 5,             /* $\langle\it term\rangle$ \.*  $\langle\it factor\rangle$ \./ seen */
 
2182
} expression_states;
 
2183
 
 
2184
 
 
2185
@  We want to make sure that each term and (intermediate) result is in
 
2186
  the proper range.  Integer values must not exceed |infinity|
 
2187
  ($2^{31}-1$) in absolute value, dimensions must not exceed |max_dimen|
 
2188
  ($2^{30}-1$).  We avoid the absolute value of an integer, because this
 
2189
  might fail for the value $-2^{31}$ using 32-bit arithmetic.
 
2190
 
 
2191
@   clear a number or dimension and set |arith_error| 
 
2192
 
 
2193
@c
 
2194
#define num_error(A) do {                       \
 
2195
        arith_error=true;                       \
 
2196
        A=0;                                    \
 
2197
    } while (0)
 
2198
 
 
2199
 
 
2200
@   clear a glue spec and set |arith_error| 
 
2201
 
 
2202
@c
 
2203
#define glue_error(A) do {                              \
 
2204
        arith_error=true;                               \
 
2205
        delete_glue_ref(A);                             \
 
2206
        A=new_spec(zero_glue);                          \
 
2207
    } while (0)
 
2208
 
 
2209
 
 
2210
#define normalize_glue(A) do {                          \
 
2211
        if (stretch(A)==0) stretch_order(A)=normal;     \
 
2212
        if (shrink(A)==0) shrink_order(A)=normal;       \
 
2213
    } while (0)
 
2214
 
 
2215
 
 
2216
@ Parenthesized subexpressions can be inside expressions, and this
 
2217
nesting has a stack.  Seven local variables represent the top of the
 
2218
expression stack:  |p| points to pushed-down entries, if any; |l|
 
2219
specifies the type of expression currently beeing evaluated; |e| is the
 
2220
expression so far and |r| is the state of its evaluation; |t| is the
 
2221
term so far and |s| is the state of its evaluation; finally |n| is the
 
2222
numerator for a combined multiplication and division, if any.
 
2223
 
 
2224
@c
 
2225
#define expr_type(A) type((A)+1)
 
2226
#define expr_state(A) subtype((A)+1)
 
2227
#define expr_e_field(A) vlink((A)+1)    /* saved expression so far */
 
2228
#define expr_t_field(A) vlink((A)+2)    /* saved term so far */
 
2229
#define expr_n_field(A) vinfo((A)+2)    /* saved numerator */
 
2230
 
 
2231
 
 
2232
#define expr_add_sub(A,B,C) add_or_sub((A),(B),(C),(r==expr_sub))
 
2233
#define expr_a(A,B) expr_add_sub((A),(B),max_dimen)
 
2234
 
 
2235
@
 
2236
  The function |add_or_sub(x,y,max_answer,negative)| computes the sum
 
2237
  (for |negative=false|) or difference (for |negative=true|) of |x| and
 
2238
  |y|, provided the absolute value of the result does not exceed
 
2239
  |max_answer|.
 
2240
 
 
2241
@c
 
2242
int add_or_sub(int x, int y, int max_answer, boolean negative)
 
2243
{
 
2244
    int a;                      /* the answer */
 
2245
    if (negative)
 
2246
        negate(y);
 
2247
    if (x >= 0) {
 
2248
        if (y <= max_answer - x)
 
2249
            a = x + y;
 
2250
        else
 
2251
            num_error(a);
 
2252
    } else if (y >= -max_answer - x) {
 
2253
        a = x + y;
 
2254
    } else {
 
2255
        num_error(a);
 
2256
    }
 
2257
    return a;
 
2258
}
 
2259
 
 
2260
 
 
2261
#define expr_m(A) A = nx_plus_y((A),f,0)
 
2262
 
 
2263
#define expr_d(A) A=quotient((A),f)
 
2264
 
 
2265
 
 
2266
@ The function |quotient(n,d)| computes the rounded quotient
 
2267
$q=\lfloor n/d+{1\over2}\rfloor$, when $n$ and $d$ are positive.
 
2268
 
 
2269
@c
 
2270
int quotient(int n, int d)
 
2271
{
 
2272
    boolean negative;           /* should the answer be negated? */
 
2273
    int a;                      /* the answer */
 
2274
    if (d == 0) {
 
2275
        num_error(a);
 
2276
    } else {
 
2277
        if (d > 0) {
 
2278
            negative = false;
 
2279
        } else {
 
2280
            negate(d);
 
2281
            negative = true;
 
2282
        }
 
2283
        if (n < 0) {
 
2284
            negate(n);
 
2285
            negative = !negative;
 
2286
        }
 
2287
        a = n / d;
 
2288
        n = n - a * d;
 
2289
        d = n - d;              /* avoid certain compiler optimizations! */
 
2290
        if (d + n >= 0)
 
2291
            incr(a);
 
2292
        if (negative)
 
2293
            negate(a);
 
2294
    }
 
2295
    return a;
 
2296
}
 
2297
 
 
2298
#define expr_s(A) A=fract((A),n,f,max_dimen)
 
2299
 
 
2300
 
 
2301
@ Finally, the function |fract(x,n,d,max_answer)| computes the integer
 
2302
$q=\lfloor xn/d+{1\over2}\rfloor$, when $x$, $n$, and $d$ are positive
 
2303
and the result does not exceed |max_answer|.  We can't use floating
 
2304
point arithmetic since the routine must produce identical results in all
 
2305
cases; and it would be too dangerous to multiply by~|n| and then divide
 
2306
by~|d|, in separate operations, since overflow might well occur.  Hence
 
2307
this subroutine simulates double precision arithmetic, somewhat
 
2308
analogous to Metafont's |make_fraction| and |take_fraction| routines.
 
2309
 
 
2310
@c
 
2311
int fract(int x, int n, int d, int max_answer)
 
2312
{
 
2313
    boolean negative;           /* should the answer be negated? */
 
2314
    int a;                      /* the answer */
 
2315
    int f;                      /* a proper fraction */
 
2316
    int h;                      /* smallest integer such that |2*h>=d| */
 
2317
    int r;                      /* intermediate remainder */
 
2318
    int t;                      /* temp variable */
 
2319
    if (d == 0)
 
2320
        goto TOO_BIG;
 
2321
    a = 0;
 
2322
    if (d > 0) {
 
2323
        negative = false;
 
2324
    } else {
 
2325
        negate(d);
 
2326
        negative = true;
 
2327
    }
 
2328
    if (x < 0) {
 
2329
        negate(x);
 
2330
        negative = !negative;
 
2331
    } else if (x == 0) {
 
2332
        goto DONE;
 
2333
    }
 
2334
    if (n < 0) {
 
2335
        negate(n);
 
2336
        negative = !negative;
 
2337
    }
 
2338
    t = n / d;
 
2339
    if (t > max_answer / x)
 
2340
        goto TOO_BIG;
 
2341
    a = t * x;
 
2342
    n = n - t * d;
 
2343
    if (n == 0)
 
2344
        goto FOUND;
 
2345
    t = x / d;
 
2346
    if (t > (max_answer - a) / n)
 
2347
        goto TOO_BIG;
 
2348
    a = a + t * n;
 
2349
    x = x - t * d;
 
2350
    if (x == 0)
 
2351
        goto FOUND;
 
2352
    if (x < n) {
 
2353
        t = x;
 
2354
        x = n;
 
2355
        n = t;
 
2356
    }
 
2357
 
 
2358
 
 
2359
    /* now |0<n<=x<d| */
 
2360
    /* Compute $f=\lfloor xn/d+{1\over2}\rfloor$; */
 
2361
    /* The loop here preserves the following invariant relations
 
2362
       between |f|, |x|, |n|, and~|r|:
 
2363
       (i)~$f+\lfloor(xn+(r+d))/d\rfloor=\lfloor x_0n_0/d+{1\over2}\rfloor$;
 
2364
       (ii)~|-d<=r<0<n<=x<d|, where $x_0$, $n_0$ are the original values of~$x$
 
2365
       and $n$. */
 
2366
    /* Notice that the computation specifies |(x-d)+x| instead of |(x+x)-d|,
 
2367
       because the latter could overflow. */
 
2368
    f = 0;
 
2369
    r = (d / 2) - d;
 
2370
    h = -r;
 
2371
    while (1) {
 
2372
        if (odd(n)) {
 
2373
            r = r + x;
 
2374
            if (r >= 0) {
 
2375
                r = r - d;
 
2376
                incr(f);
 
2377
            }
 
2378
        }
 
2379
        n = n / 2;
 
2380
        if (n == 0)
 
2381
            break;
 
2382
        if (x < h) {
 
2383
            x = x + x;
 
2384
        } else {
 
2385
            t = x - d;
 
2386
            x = t + x;
 
2387
            f = f + n;
 
2388
            if (x < n) {
 
2389
                if (x == 0)
 
2390
                    break;
 
2391
                t = x;
 
2392
                x = n;
 
2393
                n = t;
 
2394
            }
 
2395
        }
 
2396
    }
 
2397
 
 
2398
    if (f > (max_answer - a))
 
2399
        goto TOO_BIG;
 
2400
    a = a + f;
 
2401
  FOUND:
 
2402
    if (negative)
 
2403
        negate(a);
 
2404
    goto DONE;
 
2405
  TOO_BIG:
 
2406
    num_error(a);
 
2407
  DONE:
 
2408
    return a;
 
2409
}
 
2410
 
 
2411
@ @c
 
2412
void scan_expr(void)
 
2413
{                               /* scans and evaluates an expression */
 
2414
    boolean a, b;               /* saved values of |arith_error| */
 
2415
    int l;                      /* type of expression */
 
2416
    int r;                      /* state of expression so far */
 
2417
    int s;                      /* state of term so far */
 
2418
    int o;                      /* next operation or type of next factor */
 
2419
    int e;                      /* expression so far */
 
2420
    int t;                      /* term so far */
 
2421
    int f;                      /* current factor */
 
2422
    int n;                      /* numerator of combined multiplication and division */
 
2423
    halfword p;                 /* top of expression stack */
 
2424
    halfword q;                 /* for stack manipulations */
 
2425
    l = cur_val_level;
 
2426
    a = arith_error;
 
2427
    b = false;
 
2428
    p = null;
 
2429
    /* Scan and evaluate an expression |e| of type |l| */
 
2430
  RESTART:
 
2431
    r = expr_none;
 
2432
    e = 0;
 
2433
    s = expr_none;
 
2434
    t = 0;
 
2435
    n = 0;
 
2436
  CONTINUE:
 
2437
    if (s == expr_none)
 
2438
        o = l;
 
2439
    else
 
2440
        o = int_val_level;
 
2441
    /* Scan a factor |f| of type |o| or start a subexpression */
 
2442
    /* Get the next non-blank non-call token */
 
2443
    do {
 
2444
        get_x_token();
 
2445
    } while (cur_cmd == spacer_cmd);
 
2446
 
 
2447
    if (cur_tok == other_token + '(') {
 
2448
        /* Push the expression stack and |goto restart| */
 
2449
        q = new_node(expr_node, 0);
 
2450
        vlink(q) = p;
 
2451
        expr_type(q) = (quarterword) l;
 
2452
        expr_state(q) = (quarterword) (4 * s + r);
 
2453
        expr_e_field(q) = e;
 
2454
        expr_t_field(q) = t;
 
2455
        expr_n_field(q) = n;
 
2456
        p = q;
 
2457
        l = o;
 
2458
        goto RESTART;
 
2459
    }
 
2460
    back_input();
 
2461
    if ((o == int_val_level) || (o == attr_val_level))
 
2462
        scan_int();
 
2463
    else if (o == dimen_val_level)
 
2464
        scan_normal_dimen();
 
2465
    else if (o == glue_val_level)
 
2466
        scan_normal_glue();
 
2467
    else
 
2468
        scan_mu_glue();
 
2469
    f = cur_val;
 
2470
 
 
2471
  FOUND:
 
2472
    /* Scan the next operator and set |o| */
 
2473
    /* Get the next non-blank non-call token */
 
2474
    do {
 
2475
        get_x_token();
 
2476
    } while (cur_cmd == spacer_cmd);
 
2477
 
 
2478
    if (cur_tok == other_token + '+') {
 
2479
        o = expr_add;
 
2480
    } else if (cur_tok == other_token + '-') {
 
2481
        o = expr_sub;
 
2482
    } else if (cur_tok == other_token + '*') {
 
2483
        o = expr_mult;
 
2484
    } else if (cur_tok == other_token + '/') {
 
2485
        o = expr_div;
 
2486
    } else {
 
2487
        o = expr_none;
 
2488
        if (p == null) {
 
2489
            if (cur_cmd != relax_cmd)
 
2490
                back_input();
 
2491
        } else if (cur_tok != other_token + ')') {
 
2492
            print_err("Missing ) inserted for expression");
 
2493
            help1("I was expecting to see `+', `-', `*', `/', or `)'. Didn't.");
 
2494
            back_error();
 
2495
        }
 
2496
    }
 
2497
 
 
2498
    arith_error = b;
 
2499
    /* Make sure that |f| is in the proper range */
 
2500
    if (((l == int_val_level) || (l == attr_val_level)) || (s > expr_sub)) {
 
2501
        if ((f > infinity) || (f < -infinity))
 
2502
            num_error(f);
 
2503
    } else if (l == dimen_val_level) {
 
2504
        if (abs(f) > max_dimen)
 
2505
            num_error(f);
 
2506
    } else {
 
2507
        if ((abs(width(f)) > max_dimen) ||
 
2508
            (abs(stretch(f)) > max_dimen) || (abs(shrink(f)) > max_dimen))
 
2509
            glue_error(f);
 
2510
    }
 
2511
 
 
2512
    switch (s) {
 
2513
        /* Cases for evaluation of the current term */
 
2514
    case expr_none:
 
2515
        /*
 
2516
           Applying the factor |f| to the partial term |t| (with the operator
 
2517
           |s|) is delayed until the next operator |o| has been scanned.  Here we
 
2518
           handle the first factor of a partial term.  A glue spec has to be copied
 
2519
           unless the next operator is a right parenthesis; this allows us later on
 
2520
           to simply modify the glue components.
 
2521
         */
 
2522
        if ((l >= glue_val_level) && (o != expr_none)) {
 
2523
            t = new_spec(f);
 
2524
            delete_glue_ref(f);
 
2525
            normalize_glue(t);
 
2526
        } else {
 
2527
            t = f;
 
2528
        }
 
2529
        break;
 
2530
    case expr_mult:
 
2531
        /* If a multiplication is followed by a division, the two operations are
 
2532
           combined into a `scaling' operation.  Otherwise the term |t| is
 
2533
           multiplied by the factor |f|. */
 
2534
        if (o == expr_div) {
 
2535
            n = f;
 
2536
            o = expr_scale;
 
2537
        } else if ((l == int_val_level) || (l == attr_val_level)) {
 
2538
            t = mult_integers(t, f);
 
2539
        } else if (l == dimen_val_level) {
 
2540
            expr_m(t);
 
2541
        } else {
 
2542
            expr_m(width(t));
 
2543
            expr_m(stretch(t));
 
2544
            expr_m(shrink(t));
 
2545
        }
 
2546
        break;
 
2547
    case expr_div:
 
2548
        /* Here we divide the term |t| by the factor |f| */
 
2549
        if (l < glue_val_level) {
 
2550
            expr_d(t);
 
2551
        } else {
 
2552
            expr_d(width(t));
 
2553
            expr_d(stretch(t));
 
2554
            expr_d(shrink(t));
 
2555
        }
 
2556
        break;
 
2557
    case expr_scale:
 
2558
        /* Here the term |t| is multiplied by the quotient $n/f$. */
 
2559
        if ((l == int_val_level) || (l == attr_val_level)) {
 
2560
            t = fract(t, n, f, infinity);
 
2561
        } else if (l == dimen_val_level) {
 
2562
            expr_s(t);
 
2563
        } else {
 
2564
            expr_s(width(t));
 
2565
            expr_s(stretch(t));
 
2566
            expr_s(shrink(t));
 
2567
        }
 
2568
        break;
 
2569
 
 
2570
    }                           /* there are no other cases */
 
2571
    if (o > expr_sub) {
 
2572
        s = o;
 
2573
    } else {
 
2574
        /* Evaluate the current expression */
 
2575
        /* When a term |t| has been completed it is copied to, added to, or
 
2576
           subtracted from the expression |e|. */
 
2577
        s = expr_none;
 
2578
        if (r == expr_none) {
 
2579
            e = t;
 
2580
        } else if ((l == int_val_level) || (l == attr_val_level)) {
 
2581
            e = expr_add_sub(e, t, infinity);
 
2582
        } else if (l == dimen_val_level) {
 
2583
            e = expr_a(e, t);
 
2584
        } else {
 
2585
            /* Compute the sum or difference of two glue specs */
 
2586
            /* We know that |stretch_order(e)>normal| implies |stretch(e)<>0| and
 
2587
               |shrink_order(e)>normal| implies |shrink(e)<>0|. */
 
2588
            width(e) = expr_a(width(e), width(t));
 
2589
            if (stretch_order(e) == stretch_order(t)) {
 
2590
                stretch(e) = expr_a(stretch(e), stretch(t));
 
2591
            } else if ((stretch_order(e) < stretch_order(t))
 
2592
                       && (stretch(t) != 0)) {
 
2593
                stretch(e) = stretch(t);
 
2594
                stretch_order(e) = stretch_order(t);
 
2595
            }
 
2596
            if (shrink_order(e) == shrink_order(t)) {
 
2597
                shrink(e) = expr_a(shrink(e), shrink(t));
 
2598
            } else if ((shrink_order(e) < shrink_order(t)) && (shrink(t) != 0)) {
 
2599
                shrink(e) = shrink(t);
 
2600
                shrink_order(e) = shrink_order(t);
 
2601
            }
 
2602
            delete_glue_ref(t);
 
2603
            normalize_glue(e);
 
2604
        }
 
2605
        r = o;
 
2606
    }
 
2607
    b = arith_error;
 
2608
    if (o != expr_none)
 
2609
        goto CONTINUE;
 
2610
    if (p != null) {
 
2611
        /* Pop the expression stack and |goto found| */
 
2612
        f = e;
 
2613
        q = p;
 
2614
        e = expr_e_field(q);
 
2615
        t = expr_t_field(q);
 
2616
        n = expr_n_field(q);
 
2617
        s = expr_state(q) / 4;
 
2618
        r = expr_state(q) % 4;
 
2619
        l = expr_type(q);
 
2620
        p = vlink(q);
 
2621
        flush_node(q);
 
2622
        goto FOUND;
 
2623
    }
 
2624
 
 
2625
    if (b) {
 
2626
        print_err("Arithmetic overflow");
 
2627
        help2("I can't evaluate this expression,",
 
2628
              "since the result is out of range.");
 
2629
        error();
 
2630
        if (l >= glue_val_level) {
 
2631
            delete_glue_ref(e);
 
2632
            e = zero_glue;
 
2633
            add_glue_ref(e);
 
2634
        } else {
 
2635
            e = 0;
 
2636
        }
 
2637
    }
 
2638
    arith_error = a;
 
2639
    cur_val = e;
 
2640
    cur_val_level = l;
 
2641
}