3 % Copyright
2009-2010 Taco Hoekwater
<taco@@luatex.org
>
5 % This file is part of LuaTeX.
7 % LuaTeX is free software
; you can redistribute it and
/or modify it under
8 % the terms of the GNU General Public License as published by the Free
9 % Software Foundation
; either version
2 of the License
, or
(at your
10 % option
) any later version.
12 % LuaTeX is distributed in the hope that it will be useful
, but WITHOUT
13 % ANY WARRANTY
; without even the implied warranty of MERCHANTABILITY or
14 % FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 % License for more details.
17 % You should have received a copy of the GNU General Public License along
18 % with LuaTeX
; if not
, see
<http
://www.gnu.org
/licenses
/>.
23 #include
"lua/luatex-api.h"
25 /* these will move to equivalents.h
*/
28 #define lp_code_base
2
29 #define rp_code_base
3
30 #define ef_code_base
4
33 #define gp_code_base
7
35 #define prev_depth cur_list.prev_depth_field
36 #define space_factor cur_list.space_factor_field
37 #define par_shape_ptr equiv
(par_shape_loc
)
39 #define cur_lang int_par
(cur_lang_code
)
40 #define global_defs int_par
(global_defs_code
)
41 #define output_box int_par
(output_box_code
)
42 #define end_line_char int_par
(end_line_char_code
)
43 #define new_line_char int_par
(new_line_char_code
)
44 #define tracing_online int_par
(tracing_online_code
)
45 #define no_local_whatsits int_par
(no_local_whatsits_code
)
46 #define no_local_dirs int_par
(no_local_dirs_code
)
47 #define err_help equiv
(err_help_loc
)
48 #define every_par equiv
(every_par_loc
)
50 #define page_left_offset dimen_par
(page_left_offset_code
)
51 #define page_top_offset dimen_par
(page_top_offset_code
)
52 #define page_right_offset dimen_par
(page_right_offset_code
)
53 #define page_bottom_offset dimen_par
(page_bottom_offset_code
)
54 #define px_dimen dimen_par
(px_dimen_code
)
56 #define math_eqno_gap_step int_par
(math_eqno_gap_step_code
)
58 #define escape_char int_par
(escape_char_code
)
59 #define max_dead_cycles int_par
(max_dead_cycles_code
)
60 #define tolerance int_par
(tolerance_code
)
61 #define mag int_par
(mag_code
)
62 #define cat_code_table int_par
(cat_code_table_code
)
64 #define par_indent dimen_par
(par_indent_code
)
65 #define looseness int_par
(looseness_code
)
66 #define space_skip glue_par
(space_skip_code
)
67 #define xspace_skip glue_par
(xspace_skip_code
)
68 #define math_skip glue_par
(math_skip_code
)
69 #define every_vbox equiv
(every_vbox_loc
)
71 #define split_top_skip glue_par
(split_top_skip_code
)
72 #define split_max_depth dimen_par
(split_max_depth_code
)
74 #define hang_indent dimen_par
(hang_indent_code
)
75 #define hang_after int_par
(hang_after_code
)
76 #define inter_line_penalties_ptr equiv
(inter_line_penalties_loc
)
78 #define box
(A
) eqtb
[box_base
+(A
)].hh.rh
79 #define cur_font equiv
(cur_font_loc
)
80 #define hsize dimen_par
(hsize_code
)
81 #define ex_hyphen_char int_par
(ex_hyphen_char_code
)
82 #define floating_penalty int_par
(floating_penalty_code
)
84 #define mode cur_list.mode_field
85 #define tail cur_list.tail_field
86 #define head cur_list.head_field
87 #define prev_graf cur_list.pg_field
88 #define dir_save cur_list.dirs_field
90 #define var_code
7 /* math code meaning ``use the current family''
*/
92 @ We come now to the |main_control| routine
, which contains the master
93 switch that causes all the various pieces of \TeX\ to do their things
,
96 In a sense
, this is the grand climax of the program
: It applies all the
97 tools that we have worked so hard to construct. In another sense
, this is
98 the messiest part of the program
: It necessarily refers to other pieces
99 of code all over the place
, so that a person can't fully understand what is
100 going on without paging back and forth to be reminded of conventions that
101 are defined elsewhere. We are now at the hub of the web
, the central nervous
102 system that touches most of the other parts and ties them together.
105 The structure of |main_control| itself is quite simple. There's a label
106 called |big_switch|
, at which point the next token of input is fetched
107 using |get_x_token|. Then the program branches at high speed into one of
108 about
100 possible directions
, based on the value of the current
109 mode and the newly fetched command code
; the sum |abs
(mode
)+cur_cmd|
110 indicates what to do next. For example
, the case `|vmode
+letter|' arises
111 when a letter occurs in vertical mode
(or internal vertical mode
); this
112 case leads to instructions that initialize a new paragraph and enter
115 The big |case| statement that contains this multiway switch has been labeled
116 |reswitch|
, so that the program can |goto reswitch| when the next token
117 has already been fetched. Most of the cases are quite short
; they call
118 an ``action procedure'' that does the work for that case
, and then they
119 either |goto reswitch| or they ``fall through'' to the end of the |case|
120 statement
, which returns control back to |big_switch|. Thus
, |main_control|
121 is not an extremely large procedure
, in spite of the multiplicity of things
122 it must do
; it is small enough to be handled by
PASCAL compilers that put
123 severe restrictions on procedure size.
124 @
!@^action procedure@
>
126 One case is singled out for special treatment
, because it accounts for most
127 of \TeX's activities in typical applications. The process of reading simple
128 text and converting it into |char_node| records
, while looking for ligatures
129 and kerns
, is part of \TeX's ``inner loop''
; the whole program runs
130 efficiently when its inner loop is fast
, so this part has been written
131 with particular care.
133 We leave the |space_factor| unchanged if |sf_code
(cur_chr
)=0|
; otherwise we
134 set it equal to |sf_code
(cur_chr
)|
, except that it should never change
135 from a value less than
1000 to a value exceeding
1000. The most common
136 case is |sf_code
(cur_chr
)=1000|
, so we want that case to be fast.
139 void adjust_space_factor
(void
)
141 halfword s
= get_sf_code
(cur_chr
);
144 } else if
(s
< 1000) {
147 } else if
(space_factor
< 1000) {
154 @ From Knuth
: ``Having |font_glue| allocated for each text font saves
155 both time and memory.'' That may be true
, but it also punches through
156 the API wall for fonts
, so I removed that
-- Taco. But a bit of caching
157 is very welcome
, which is why I need to have the next two globals
:
159 @ To handle the execution state of |main_control|'s eternal loop
,
160 an extra global variable is used
, along with a macro to define
165 #define goto_skip_token
1
166 #define goto_return
2
168 static int main_control_state
;
170 @
* Main control helpers.
172 Here are all the functions that are called from |main_control| that
173 are not already defined elsewhere. For the moment
, this list simply
174 in the order that the appear in |init_main_control|
, below.
178 static void run_char_num
(void
) {
181 adjust_space_factor
();
182 tail_append
(new_char
(cur_font
, cur_chr
));
185 static void run_char
(void
) {
186 adjust_space_factor
();
187 tail_append
(new_char
(cur_font
, cur_chr
));
191 The occurrence of blank spaces is almost part of \TeX's inner loop
,
192 since we usually encounter about one space for every five non-blank characters.
193 Therefore |main_control| gives second-highest priority to ordinary spaces.
195 When a glue parameter like \.
{\\spaceskip
} is set to `\.
{0pt
}'
, we will
196 see to it later that the corresponding glue specification is precisely
197 |zero_glue|
, not merely a pointer to some specification that happens
198 to be full of zeroes. Therefore it is simple to test whether a glue parameter
202 static void run_app_space
(void
) {
203 halfword p
; /* was a global temp_ptr
*/
204 int method
= int_par
(disable_space_code
) ;
206 /* don't inject anything
, not even zero skip
*/
207 } else if
(method
== 2) {
208 p
= new_glue
(zero_glue
);
209 couple_nodes
(tail
,p
);
211 } else if
((abs
(mode
) + cur_cmd
== hmode
+ spacer_cmd
) && (!(space_factor == 1000))) {
214 /* Append a normal inter-word space to the current list
*/
215 if
(glue_is_zero
(space_skip
)) {
216 /* Find the glue specification for text spaces in the current font
*/
217 p
= new_glue
(zero_glue
);
218 width
(p
) = space
(cur_font
);
219 stretch
(p
) = space_stretch
(cur_font
);
220 shrink
(p
) = space_shrink
(cur_font
);
223 p
= new_param_glue
(space_skip_code
);
225 /* so from now we have a subtype with spaces
: */
226 subtype
(p
) = space_skip_code
+ 1 ;
227 couple_nodes
(tail
,p
);
232 @ Append a |boundary_node|
234 static void run_boundary
(void
) {
236 n
= new_node
(boundary_node
,cur_chr
);
237 if
((cur_chr
== 1) ||
(cur_chr
== 2) ) {
238 /* user boundary or protrusion boundary
*/
240 boundary_value
(n
) = cur_val
;
242 couple_nodes
(tail
, n
);
247 static void run_char_ghost
(void
) {
251 if
((cur_cmd
== letter_cmd
) ||
(cur_cmd
== other_char_cmd
)
252 ||
(cur_cmd
== char_given_cmd
) ||
(cur_cmd
== char_num_cmd
)) {
253 halfword p
= new_glyph
(get_cur_font
(), cur_chr
);
257 set_is_rightghost
(p
);
264 static void run_relax
(void
) {
268 @ |ignore_spaces| is a special case
: after it has acted
, |get_x_token| has already
269 fetched the next token from the input
, so that operation in |main_control|
273 static void run_ignore_spaces
(void
) {
275 /* Get the next non-blank non-call...
*/
278 } while
(cur_cmd
== spacer_cmd
);
279 main_control_state
= goto_skip_token
;
281 int t
= scanner_status
;
282 scanner_status
= normal
;
285 cur_cs
= prim_lookup
(cs_text
(cur_cs
));
286 if
(cur_cs
!= undefined_primitive
) {
287 cur_cmd
= get_prim_eq_type
(cur_cs
);
288 cur_chr
= get_prim_equiv
(cur_cs
);
289 cur_tok
= (cur_cmd
* STRING_OFFSET
) + cur_chr
;
290 main_control_state
= goto_skip_token
;
295 @ |stop| is the second special case. We want |main_control| to return to its caller
296 if there is nothing left to do.
299 static void run_stop
(void
) {
301 main_control_state
= goto_return
; /* this is the only way out
*/
305 static void run_non_math_math
(void
) {
311 static void run_math_char_num
(void
) {
312 mathcodeval mval
; /* to build up an argument to |set_math_char|
*/
314 mval
= scan_mathchar
(tex_mathcode
);
315 else if
(cur_chr
== 1)
316 mval
= scan_mathchar
(umath_mathcode
);
318 mval
= scan_mathchar
(umathnum_mathcode
);
319 math_char_in_text
(mval
);
323 static void run_math_given
(void
) {
324 mathcodeval mval
; /* to build up an argument to |set_math_char|
*/
325 mval
= mathchar_from_integer
(cur_chr
, tex_mathcode
);
326 math_char_in_text
(mval
);
329 static void run_xmath_given
(void
) {
330 mathcodeval mval
; /* to build up an argument to |set_math_char|
*/
331 mval
= mathchar_from_integer
(cur_chr
, umath_mathcode
);
332 math_char_in_text
(mval
);
335 @ The most important parts of |main_control| are concerned with \TeX's
336 chief mission of box-making. We need to control the activities that put
337 entries on vlists and hlists
, as well as the activities that convert
338 those lists into boxes. All of the necessary machinery has already been
339 developed
; it remains for us to ``push the buttons'' at the right times.
341 As an introduction to these routines
, let's consider one of the simplest
342 cases
: What happens when `\.
{\\hrule
}' occurs in vertical mode
, or
343 `\.
{\\vrule
}' in horizontal mode or math mode? The code in |main_control|
344 is short
, since the |scan_rule_spec| routine already does most of what is
345 required
; thus
, there is no need for a special action procedure.
347 Note that baselineskip calculations are disabled after a rule in vertical
348 mode
, by setting |prev_depth
:=ignore_depth|.
351 static void run_rule
(void
) {
352 tail_append
(scan_rule_spec
());
353 if
(abs
(mode
) == vmode
)
354 prev_depth
= ignore_depth
;
355 else if
(abs
(mode
) == hmode
)
360 Many of the actions related to box-making are triggered by the appearance
361 of braces in the input. For example
, when the user says `\.
{\\hbox
}
362 \.
{to
} \.
{100pt\
{$\langle\
,\hbox
{hlist
}\
,\rangle$\
}}' in vertical mode
,
363 the information about the box size
(100pt
, |exactly|
) is put onto |save_stack|
364 with a level boundary word just above it
, and |cur_group
:=adjusted_hbox_group|
;
365 \TeX\ enters restricted horizontal mode to process the hlist. The right
366 brace eventually causes |save_stack| to be restored to its former state
,
367 at which time the information about the box size
(100pt
, |exactly|
) is
368 available once again
; a box is packaged and we leave restricted horizontal
369 mode
, appending the new box to the current list of the enclosing mode
370 (in this case to the current list of vertical mode
), followed by any
371 vertical adjustments that were removed from the box by |hpack|.
373 The next few sections of the program are therefore concerned with the
374 treatment of left and right curly braces.
376 If a left brace occurs in the middle of a page or paragraph
, it simply
377 introduces a new level of grouping
, and the matching right brace will not have
378 such a drastic effect. Such grouping affects neither the mode nor the
382 static void run_left_brace
(void
) {
383 new_save_level
(simple_group
);
384 eq_word_define
(int_base
+ no_local_whatsits_code
, 0);
385 eq_word_define
(int_base
+ no_local_dirs_code
, 0);
388 static void run_begin_group
(void
) {
389 new_save_level
(semi_simple_group
);
390 eq_word_define
(int_base
+ no_local_whatsits_code
, 0);
391 eq_word_define
(int_base
+ no_local_dirs_code
, 0);
394 static void run_end_group
(void
) {
395 if
(cur_group
== semi_simple_group
) {
402 @ Constructions that require a box are started by calling |scan_box| with
403 a specified context code. The |scan_box| routine verifies
404 that a |make_box| command comes next and then it calls |begin_box|.
407 static void run_move
(void
) {
417 static void run_leader_ship
(void
) {
418 scan_box
(leader_flag
- a_leaders
+ cur_chr
);
422 static void run_make_box
(void
) {
427 static void run_box_dir
(void
) {
429 cur_box
= box
(cur_val
);
430 scan_optional_equals
();
433 box_dir
(cur_box
) = cur_val
;
436 @ There is a really small patch to add a new primitive called
437 \.
{\\quitvmode
}. In vertical modes
, it is identical to \.
{\\indent
},
438 but in horizontal and math modes it is really a no-op
(as opposed to
439 \.
{\\indent
}, which executes the |indent_in_hmode| procedure
).
441 A paragraph begins when horizontal-mode material occurs in vertical mode
,
442 or when the paragraph is explicitly started by `\.
{\\quitvmode
}'
,
443 `\.
{\\indent
}' or `\.
{\\noindent
}'.
446 static void run_start_par_vmode
(void
) {
447 new_graf
((cur_chr
> 0));
451 static void run_start_par
(void
) {
457 static void run_new_graf
(void
) {
462 @ A paragraph ends when a |par_end| command is sensed
, or when we are in
463 horizontal mode when reaching the right brace of vertical-mode routines
464 like \.
{\\vbox
}, \.
{\\insert
}, or \.
{\\output
}.
467 static void run_par_end_vmode
(void
) {
470 checked_page_filter
(vmode_par
);
476 static void run_par_end_hmode
(void
) {
478 off_save
(); /* this tries to recover from an alignment that didn't end properly
*/
479 end_graf
(bottom_level
); /* this takes us to the enclosing mode
, if |mode
>0|
*/
481 checked_page_filter
(hmode_par
);
487 static void append_italic_correction_mmode
(void
) {
488 tail_append
(new_kern
(0)); /* what subtype to use
*/
492 static void run_local_box
(void
) {
493 append_local_box
(cur_chr
);
497 static void run_halign_mmode
(void
) {
499 if
(cur_group
== math_shift_group
)
507 static void run_eq_no
(void
) {
509 if
(cur_group
== math_shift_group
)
517 static void run_letter_mmode
(void
) {
518 set_math_char
(get_math_code
(cur_chr
));
522 static void run_char_num_mmode
(void
) {
525 set_math_char
(get_math_code
(cur_chr
));
529 static void run_math_char_num_mmode
(void
) {
530 mathcodeval mval
; /* to build up an argument to |set_math_char|
*/
532 mval
= scan_mathchar
(tex_mathcode
);
533 else if
(cur_chr
== 1)
534 mval
= scan_mathchar
(umath_mathcode
);
536 mval
= scan_mathchar
(umathnum_mathcode
);
541 static void run_math_given_mmode
(void
) {
542 mathcodeval mval
; /* to build up an argument to |set_math_char|
*/
543 mval
= mathchar_from_integer
(cur_chr
, tex_mathcode
);
547 static void run_xmath_given_mmode
(void
) {
548 mathcodeval mval
; /* to build up an argument to |set_math_char|
*/
549 mval
= mathchar_from_integer
(cur_chr
, umath_mathcode
);
554 static void run_delim_num
(void
) {
555 mathcodeval mval
; /* to build up an argument to |set_math_char|
*/
557 mval
= scan_delimiter_as_mathchar
(tex_mathcode
);
559 mval
= scan_delimiter_as_mathchar
(umath_mathcode
);
565 static void run_vcenter
(void
) {
566 scan_spec
(vcenter_group
);
570 prev_depth
= ignore_depth
;
571 if
(every_vbox
!= null
)
572 begin_token_list
(every_vbox
, every_vbox_text
);
576 static void run_math_style
(void
) {
577 tail_append
(new_style
((small_number
) cur_chr
));
581 static void run_non_script
(void
) {
582 tail_append
(new_glue
(zero_glue
));
583 subtype
(tail
) = cond_math_glue
;
587 static void run_math_choice
(void
) {
595 static void run_math_shift
(void
) {
596 if
(cur_group
== math_shift_group
)
603 static void run_after_assignment
(void
) {
605 after_token
= cur_tok
;
609 static void run_after_group
(void
) {
611 save_for_after
(cur_tok
);
615 static void run_extension
(void
) {
619 static void run_normal
(void
) {
623 new_whatsit
(save_pos_node
);
625 case save_cat_code_table_code
:
627 if
((cur_val
< 0) ||
(cur_val
> 0x7FFF)) {
628 print_err
("Invalid \\catcode table");
629 help1
("All \\catcode table ids must be between 0 and 0x7FFF");
632 if
(cur_val
== cat_code_table
) {
633 print_err
("Invalid \\catcode table");
634 help1
("You cannot overwrite the current \\catcode table");
637 copy_cat_codes
(cat_code_table
, cur_val
);
641 case init_cat_code_table_code
:
643 if
((cur_val
< 0) ||
(cur_val
> 0x7FFF)) {
644 print_err
("Invalid \\catcode table");
645 help1
("All \\catcode table ids must be between 0 and 0x7FFF");
648 if
(cur_val
== cat_code_table
) {
649 print_err
("Invalid \\catcode table");
650 help1
("You cannot overwrite the current \\catcode table");
653 initex_cat_codes
(cur_val
);
657 case set_random_seed_code
:
658 /* Negative random seed values are silently converted to positive ones
*/
662 random_seed
= cur_val
;
663 init_randoms
(random_seed
);
666 new_whatsit
(late_lua_node
); /* type
== normal
*/
667 late_lua_name
(tail
) = scan_lua_state
();
668 (void
) scan_toks
(false
, false
);
669 late_lua_data
(tail
) = def_ref
;
671 case expand_font_code
:
682 this is experimental and not used for production
, only for testing and writing
683 macros
(some options stay
)
687 #define mathoption_set_int
(A
) \
689 word_define
(mathoption_int_base
+A
, cur_val
);
691 static void run_option
(void
) {
694 case math_option_code
:
695 if
(scan_keyword
("old")) {
696 mathoption_set_int
(c_mathoption_old_code
);
697 } else if
(scan_keyword
("noitaliccompensation")) {
698 mathoption_set_int
(c_mathoption_no_italic_compensation_code
);
699 } else if
(scan_keyword
("nocharitalic")) {
700 mathoption_set_int
(c_mathoption_no_char_italic_code
);
701 } else if
(scan_keyword
("useoldfractionscaling")) {
702 mathoption_set_int
(c_mathoption_use_old_fraction_scaling_code
);
703 } else if
(scan_keyword
("umathcodemeaning")) {
704 mathoption_set_int
(c_mathoption_umathcode_meaning_code
);
706 normal_warning
("mathoption","unknown key");
715 @ For mode-independent commands
, the following macro is useful.
717 Also
, there is a list of cases where the user has probably gotten into or out of math
718 mode by mistake. \TeX\ will insert a dollar sign and rescan the current token
, and
719 it makes sense ot have a macro for that as well.
722 #define any_mode
(A
,B
) jump_table
[vmode
+(A
)]=B
; jump_table
[hmode
+(A
)]=B
; jump_table
[mmode
+(A
)]=B
723 #define non_math
(A
,B
) jump_table
[vmode
+(A
)]=B
; jump_table
[hmode
+(A
)]=B
;
726 @ The |main_control| uses a jump table
, and |init_main_control| sets that table up.
728 typedef void
(*main_control_function
) (void
);
729 main_control_function
*jump_table
;
731 static void init_main_control
(void
) {
732 jump_table
= xmalloc
((mmode
+max_command_cmd
+1) * sizeof
(main_control_function
)) ;
734 jump_table
[hmode
+ char_num_cmd
] = run_char_num
;
735 jump_table
[hmode
+ letter_cmd
] = run_char
;
736 jump_table
[hmode
+ other_char_cmd
] = run_char
;
737 jump_table
[hmode
+ char_given_cmd
] = run_char
;
738 jump_table
[hmode
+ spacer_cmd
] = run_app_space
;
739 jump_table
[hmode
+ ex_space_cmd
] = run_app_space
;
740 jump_table
[mmode
+ ex_space_cmd
] = run_app_space
;
741 jump_table
[hmode
+ boundary_cmd
] = run_boundary
;
742 jump_table
[hmode
+ char_ghost_cmd
] = run_char_ghost
;
743 jump_table
[mmode
+ char_ghost_cmd
] = run_char_ghost
;
744 any_mode
(relax_cmd
, run_relax
);
745 jump_table
[vmode
+ spacer_cmd
] = run_relax
;
746 jump_table
[mmode
+ spacer_cmd
] = run_relax
;
747 jump_table
[mmode
+ boundary_cmd
] = run_relax
;
748 any_mode
(ignore_spaces_cmd
,run_ignore_spaces
);
749 jump_table
[vmode
+ stop_cmd
] = run_stop
;
750 jump_table
[vmode
+ math_char_num_cmd
] = run_non_math_math
;
751 jump_table
[vmode
+ math_given_cmd
] = run_non_math_math
;
752 jump_table
[vmode
+ xmath_given_cmd
] = run_non_math_math
;
753 jump_table
[hmode
+ math_char_num_cmd
] = run_math_char_num
;
754 jump_table
[hmode
+ math_given_cmd
] = run_math_given
;
755 jump_table
[hmode
+ xmath_given_cmd
] = run_xmath_given
;
757 jump_table
[vmode
+ vmove_cmd
] = report_illegal_case
;
758 jump_table
[hmode
+ hmove_cmd
] = report_illegal_case
;
759 jump_table
[mmode
+ hmove_cmd
] = report_illegal_case
;
760 any_mode
(last_item_cmd
, report_illegal_case
);
761 jump_table
[vmode
+ vadjust_cmd
] = report_illegal_case
;
762 jump_table
[vmode
+ ital_corr_cmd
] = report_illegal_case
;
763 non_math
(eq_no_cmd
,report_illegal_case
);
764 any_mode
(mac_param_cmd
,report_illegal_case
);
766 non_math
(sup_mark_cmd
, insert_dollar_sign
);
767 non_math
(sub_mark_cmd
, insert_dollar_sign
);
768 non_math
(super_sub_script_cmd
, insert_dollar_sign
);
769 non_math
(math_comp_cmd
, insert_dollar_sign
);
770 non_math
(delim_num_cmd
, insert_dollar_sign
);
771 non_math
(left_right_cmd
, insert_dollar_sign
);
772 non_math
(above_cmd
, insert_dollar_sign
);
773 non_math
(radical_cmd
, insert_dollar_sign
);
774 non_math
(math_style_cmd
, insert_dollar_sign
);
775 non_math
(math_choice_cmd
, insert_dollar_sign
);
776 non_math
(vcenter_cmd
, insert_dollar_sign
);
777 non_math
(non_script_cmd
, insert_dollar_sign
);
778 non_math
(mkern_cmd
, insert_dollar_sign
);
779 non_math
(limit_switch_cmd
, insert_dollar_sign
);
780 non_math
(mskip_cmd
, insert_dollar_sign
);
781 non_math
(math_accent_cmd
, insert_dollar_sign
);
782 jump_table
[mmode
+ endv_cmd
] = insert_dollar_sign
;
783 jump_table
[mmode
+ par_end_cmd
] = insert_dollar_sign_par_end
;
784 jump_table
[mmode
+ stop_cmd
] = insert_dollar_sign
;
785 jump_table
[mmode
+ vskip_cmd
] = insert_dollar_sign
;
786 jump_table
[mmode
+ un_vbox_cmd
] = insert_dollar_sign
;
787 jump_table
[mmode
+ valign_cmd
] = insert_dollar_sign
;
788 jump_table
[mmode
+ hrule_cmd
] = insert_dollar_sign
;
789 jump_table
[mmode
+ no_hrule_cmd
] = insert_dollar_sign
;
790 jump_table
[vmode
+ hrule_cmd
] = run_rule
;
791 jump_table
[vmode
+ no_hrule_cmd
] = run_rule
;
792 jump_table
[hmode
+ vrule_cmd
] = run_rule
;
793 jump_table
[hmode
+ no_vrule_cmd
] = run_rule
;
794 jump_table
[mmode
+ vrule_cmd
] = run_rule
;
795 jump_table
[mmode
+ no_vrule_cmd
] = run_rule
;
796 jump_table
[vmode
+ vskip_cmd
] = append_glue
;
797 jump_table
[hmode
+ hskip_cmd
] = append_glue
;
798 jump_table
[mmode
+ hskip_cmd
] = append_glue
;
799 jump_table
[mmode
+ mskip_cmd
] = append_glue
;
800 any_mode
(kern_cmd
, append_kern
);
801 jump_table
[mmode
+ mkern_cmd
] = append_kern
;
802 non_math
(left_brace_cmd
, run_left_brace
);
803 any_mode
(begin_group_cmd
,run_begin_group
);
804 any_mode
(end_group_cmd
, run_end_group
);
805 any_mode
(right_brace_cmd
, handle_right_brace
);
806 jump_table
[vmode
+ hmove_cmd
] = run_move
;
807 jump_table
[hmode
+ vmove_cmd
] = run_move
;
808 jump_table
[mmode
+ vmove_cmd
] = run_move
;
809 any_mode
(leader_ship_cmd
, run_leader_ship
);
810 any_mode
(make_box_cmd
, run_make_box
);
811 any_mode
(assign_box_dir_cmd
, run_box_dir
);
812 jump_table
[vmode
+ start_par_cmd
] = run_start_par_vmode
;
813 jump_table
[hmode
+ start_par_cmd
] = run_start_par
;
814 jump_table
[mmode
+ start_par_cmd
] = run_start_par
;
815 jump_table
[vmode
+ letter_cmd
] = run_new_graf
;
816 jump_table
[vmode
+ other_char_cmd
] = run_new_graf
;
817 jump_table
[vmode
+ char_num_cmd
] = run_new_graf
;
818 jump_table
[vmode
+ char_given_cmd
] = run_new_graf
;
819 jump_table
[vmode
+ char_ghost_cmd
] = run_new_graf
;
820 jump_table
[vmode
+ math_shift_cmd
] = run_new_graf
;
821 jump_table
[vmode
+ math_shift_cs_cmd
] = run_new_graf
;
822 jump_table
[vmode
+ un_hbox_cmd
] = run_new_graf
;
823 jump_table
[vmode
+ vrule_cmd
] = run_new_graf
;
824 jump_table
[vmode
+ no_vrule_cmd
] = run_new_graf
;
825 jump_table
[vmode
+ accent_cmd
] = run_new_graf
;
826 jump_table
[vmode
+ discretionary_cmd
] = run_new_graf
;
827 jump_table
[vmode
+ hskip_cmd
] = run_new_graf
;
828 jump_table
[vmode
+ valign_cmd
] = run_new_graf
;
829 jump_table
[vmode
+ ex_space_cmd
] = run_new_graf
;
830 jump_table
[vmode
+ boundary_cmd
] = run_new_graf
;
831 jump_table
[vmode
+ par_end_cmd
] = run_par_end_vmode
;
832 jump_table
[hmode
+ par_end_cmd
] = run_par_end_hmode
;
833 jump_table
[hmode
+ stop_cmd
] = head_for_vmode
;
834 jump_table
[hmode
+ vskip_cmd
] = head_for_vmode
;
835 jump_table
[hmode
+ hrule_cmd
] = head_for_vmode
;
836 jump_table
[hmode
+ no_hrule_cmd
] = head_for_vmode
;
837 jump_table
[hmode
+ un_vbox_cmd
] = head_for_vmode
;
838 jump_table
[hmode
+ halign_cmd
] = head_for_vmode
;
839 any_mode
(insert_cmd
,begin_insert_or_adjust
);
840 jump_table
[hmode
+ vadjust_cmd
] = begin_insert_or_adjust
;
841 jump_table
[mmode
+ vadjust_cmd
] = begin_insert_or_adjust
;
842 any_mode
(mark_cmd
, handle_mark
);
843 any_mode
(break_penalty_cmd
, append_penalty
);
844 any_mode
(remove_item_cmd
, delete_last
);
845 jump_table
[vmode
+ un_vbox_cmd
] = unpackage
;
846 jump_table
[hmode
+ un_hbox_cmd
] = unpackage
;
847 jump_table
[mmode
+ un_hbox_cmd
] = unpackage
;
848 jump_table
[hmode
+ ital_corr_cmd
] = append_italic_correction
;
849 jump_table
[mmode
+ ital_corr_cmd
] = append_italic_correction_mmode
;
850 jump_table
[hmode
+ discretionary_cmd
] = append_discretionary
;
851 jump_table
[mmode
+ discretionary_cmd
] = append_discretionary
;
852 any_mode
(assign_local_box_cmd
, run_local_box
);
853 jump_table
[hmode
+ accent_cmd
] = make_accent
;
854 any_mode
(car_ret_cmd
,align_error
);
855 any_mode
(tab_mark_cmd
,align_error
);
856 any_mode
(no_align_cmd
,no_align_error
);
857 any_mode
(omit_cmd
, omit_error
);
858 jump_table
[vmode
+ halign_cmd
] = init_align
;
859 jump_table
[hmode
+ valign_cmd
] = init_align
;
860 jump_table
[mmode
+ halign_cmd
] = run_halign_mmode
;
861 jump_table
[vmode
+ endv_cmd
] = do_endv
;
862 jump_table
[hmode
+ endv_cmd
] = do_endv
;
863 any_mode
(end_cs_name_cmd
, cs_error
);
864 jump_table
[hmode
+ math_shift_cmd
] = init_math
;
865 jump_table
[hmode
+ math_shift_cs_cmd
] = init_math
;
866 jump_table
[mmode
+ eq_no_cmd
] = run_eq_no
;
867 jump_table
[mmode
+ left_brace_cmd
] = math_left_brace
;
868 jump_table
[mmode
+ letter_cmd
] = run_letter_mmode
;
869 jump_table
[mmode
+ other_char_cmd
] = run_letter_mmode
;
870 jump_table
[mmode
+ char_given_cmd
] = run_letter_mmode
;
871 jump_table
[mmode
+ char_num_cmd
] = run_char_num_mmode
;
872 jump_table
[mmode
+ math_char_num_cmd
] = run_math_char_num_mmode
;
873 jump_table
[mmode
+ math_given_cmd
] = run_math_given_mmode
;
874 jump_table
[mmode
+ xmath_given_cmd
] = run_xmath_given_mmode
;
875 jump_table
[mmode
+ delim_num_cmd
] = run_delim_num
;
876 jump_table
[mmode
+ math_comp_cmd
] = math_math_comp
;
877 jump_table
[mmode
+ limit_switch_cmd
] = math_limit_switch
;
878 jump_table
[mmode
+ radical_cmd
] = math_radical
;
879 jump_table
[mmode
+ accent_cmd
] = math_ac
;
880 jump_table
[mmode
+ math_accent_cmd
] = math_ac
;
881 jump_table
[mmode
+ vcenter_cmd
] = run_vcenter
;
882 jump_table
[mmode
+ math_style_cmd
] = run_math_style
;
883 jump_table
[mmode
+ non_script_cmd
] = run_non_script
;
884 jump_table
[mmode
+ math_choice_cmd
] = run_math_choice
;
885 jump_table
[mmode
+ above_cmd
] = math_fraction
;
886 jump_table
[mmode
+ sub_mark_cmd
] = sub_sup
;
887 jump_table
[mmode
+ sup_mark_cmd
] = sub_sup
;
888 jump_table
[mmode
+ super_sub_script_cmd
] = sub_sup
;
889 jump_table
[mmode
+ left_right_cmd
] = math_left_right
;
890 jump_table
[mmode
+ math_shift_cmd
] = run_math_shift
;
891 jump_table
[mmode
+ math_shift_cs_cmd
] = run_math_shift
;
892 any_mode
(toks_register_cmd
, prefixed_command
);
893 any_mode
(assign_toks_cmd
, prefixed_command
);
894 any_mode
(assign_int_cmd
, prefixed_command
);
895 any_mode
(assign_attr_cmd
, prefixed_command
);
896 any_mode
(assign_dir_cmd
, prefixed_command
);
897 any_mode
(assign_dimen_cmd
, prefixed_command
);
898 any_mode
(assign_glue_cmd
, prefixed_command
);
899 any_mode
(assign_mu_glue_cmd
, prefixed_command
);
900 any_mode
(assign_font_dimen_cmd
, prefixed_command
);
901 any_mode
(assign_font_int_cmd
, prefixed_command
);
902 any_mode
(set_aux_cmd
, prefixed_command
);
903 any_mode
(set_prev_graf_cmd
, prefixed_command
);
904 any_mode
(set_page_dimen_cmd
, prefixed_command
);
905 any_mode
(set_page_int_cmd
, prefixed_command
);
906 any_mode
(set_box_dimen_cmd
, prefixed_command
);
907 any_mode
(set_tex_shape_cmd
, prefixed_command
);
908 any_mode
(set_etex_shape_cmd
, prefixed_command
);
909 any_mode
(def_char_code_cmd
, prefixed_command
);
910 any_mode
(def_del_code_cmd
, prefixed_command
);
911 any_mode
(extdef_math_code_cmd
, prefixed_command
);
912 any_mode
(extdef_del_code_cmd
, prefixed_command
);
913 any_mode
(def_family_cmd
, prefixed_command
);
914 any_mode
(set_math_param_cmd
, prefixed_command
);
915 any_mode
(set_font_cmd
, prefixed_command
);
916 any_mode
(def_font_cmd
, prefixed_command
);
917 any_mode
(letterspace_font_cmd
, prefixed_command
);
918 any_mode
(copy_font_cmd
, prefixed_command
);
919 any_mode
(set_font_id_cmd
, prefixed_command
);
920 any_mode
(register_cmd
, prefixed_command
);
921 any_mode
(advance_cmd
, prefixed_command
);
922 any_mode
(multiply_cmd
, prefixed_command
);
923 any_mode
(divide_cmd
, prefixed_command
);
924 any_mode
(prefix_cmd
, prefixed_command
);
925 any_mode
(let_cmd
, prefixed_command
);
926 any_mode
(shorthand_def_cmd
, prefixed_command
);
927 any_mode
(read_to_cs_cmd
, prefixed_command
);
928 any_mode
(def_cmd
, prefixed_command
);
929 any_mode
(set_box_cmd
, prefixed_command
);
930 any_mode
(hyph_data_cmd
, prefixed_command
);
931 any_mode
(set_interaction_cmd
, prefixed_command
);
932 any_mode
(after_assignment_cmd
,run_after_assignment
);
933 any_mode
(after_group_cmd
,run_after_group
);
934 any_mode
(in_stream_cmd
,open_or_close_in
);
935 any_mode
(message_cmd
,issue_message
);
936 any_mode
(case_shift_cmd
, shift_case
);
937 any_mode
(xray_cmd
, show_whatever
);
938 any_mode
(normal_cmd
, run_normal
);
939 any_mode
(extension_cmd
, run_extension
);
940 any_mode
(option_cmd
, run_option
);
943 @ And here is |main_control| itself. It is quite short nowadays.
946 void main_control
(void
)
948 main_control_state
= goto_next
;
949 init_main_control
() ;
951 if
(equiv
(every_job_loc
) != null
)
952 begin_token_list
(equiv
(every_job_loc
), every_job_text
);
955 if
(main_control_state
== goto_skip_token
)
956 main_control_state
= goto_next
; /* reset
*/
960 /* Give diagnostic information
, if requested
*/
961 /* When a new token has just been fetched at |big_switch|
, we have an
962 ideal place to monitor \TeX's activity.
*/
963 if
(interrupt
!= 0 && OK_to_interrupt) {
968 if
(int_par
(tracing_commands_code
) > 0)
971 (jump_table
[(abs
(mode
) + cur_cmd
)])(); /* run the command
*/
973 if
(main_control_state
== goto_return
) {
977 return
; /* not reached
*/
982 { /* handle spaces when |space_factor
<>1000|
*/
983 halfword q
; /* glue node
*/
984 if
((space_factor
>= 2000) && (! glue_is_zero(xspace_skip))) {
985 q
= new_param_glue
(xspace_skip_code
);
986 /* so from now we have a subtype with spaces
: */
987 subtype
(q
) = xspace_skip_code
+ 1;
989 if
(!glue_is_zero
(space_skip
)) {
990 q
= new_glue
(space_skip
);
992 q
= new_glue
(zero_glue
);
993 width
(q
) = space
(cur_font
);
994 stretch
(q
) = space_stretch
(cur_font
);
995 shrink
(q
) = space_shrink
(cur_font
);
997 /* Modify the glue specification in |q| according to the space factor
*/
998 if
(space_factor
>= 2000)
999 width
(q
) = width
(q
) + extra_space
(cur_font
);
1000 stretch
(q
) = xn_over_d
(stretch
(q
), space_factor
, 1000);
1001 shrink
(q
) = xn_over_d
(shrink
(q
), 1000, space_factor
);
1003 /* so from now we have a subtype with spaces
: */
1004 subtype
(q
) = space_skip_code
+ 1;
1006 couple_nodes
(tail
, q
);
1011 void insert_dollar_sign
(void
)
1014 cur_tok
= math_shift_token
+ '$'
;
1015 print_err
("Missing $ inserted");
1016 help2
("I've inserted a begin-math/end-math symbol since I think",
1017 "you left one out. Proceed, with fingers crossed.");
1021 @ We can silently ignore \.
{\\par
}s in a math formula.
1024 void insert_dollar_sign_par_end
(void
)
1026 if
(!int_par
(suppress_mathpar_error_code
)) {
1027 insert_dollar_sign
() ;
1031 @ The `|you_cant|' procedure prints a line saying that the current command
1032 is illegal in the current mode
; it identifies these things symbolically.
1037 print_err
("You can't use `");
1038 print_cmd_chr
((quarterword
) cur_cmd
, cur_chr
);
1039 print_in_mode
(mode
);
1043 When erroneous situations arise
, \TeX\ usually issues an error message
1044 specific to the particular error. For example
, `\.
{\\noalign
}' should
1045 not appear in any mode
, since it is recognized by the |align_peek| routine
1046 in all of its legitimate appearances
; a special error message is given
1047 when `\.
{\\noalign
}' occurs elsewhere. But sometimes the most appropriate
1048 error message is simply that the user is not allowed to do what he or she
1049 has attempted. For example
, `\.
{\\moveleft
}' is allowed only in vertical mode
,
1050 and `\.
{\\lower
}' only in non-vertical modes. Such cases are enumerated
1051 here and in the other sections referred to under `See also \dots.'
1054 void report_illegal_case
(void
)
1057 help4
("Sorry, but I'm not programmed to handle this case;",
1058 "I'll just pretend that you didn''t ask for it.",
1059 "If you're in the wrong mode, you might be able to",
1060 "return to the right one by typing `I}' or `I$' or `I\\par'.");
1064 @ Some operations are allowed only in privileged modes
, i.e.
, in cases
1065 that |mode
>0|. The |privileged| function is used to detect violations
1066 of this rule
; it issues an error message and returns |false| if the
1067 current |mode| is negative.
1070 boolean privileged
(void
)
1075 report_illegal_case
();
1080 @ We don't want to leave |main_control| immediately when a |stop| command
1081 is sensed
, because it may be necessary to invoke an \.
{\\output
} routine
1082 several times before things really grind to a halt.
(The output routine
1083 might even say `\.
{\\gdef\\end\
{...\
}}'
, to prolong the life of the job.
)
1084 Therefore |its_all_over| is |true| only when the current page
1085 and contribution list are empty
, and when the last output was not a
1089 boolean its_all_over
(void
)
1090 { /* do this when \.
{\\end
} or \.
{\\dump
} occurs
*/
1092 if
((page_head
== page_tail
) && (head == tail) && (dead_cycles == 0)) {
1095 back_input
(); /* we will try to end again after ejecting residual material
*/
1096 tail_append
(new_null_box
());
1097 width
(tail
) = hsize
;
1098 tail_append
(new_glue
(fill_glue
));
1099 tail_append
(new_penalty
(-010000000000));
1100 normal_page_filter
(end
);
1101 build_page
(); /* append \.
{\\hbox to \\hsize\
{\
}\\vfill\\penalty-'
10000000000} */
1107 @ The |hskip| and |vskip| command codes are used for control sequences
1108 like \.
{\\hss
} and \.
{\\vfil
} as well as for \.
{\\hskip
} and \.
{\\vskip
}.
1109 The difference is in the value of |cur_chr|.
1111 All the work relating to glue creation has been relegated to the
1112 following subroutine. It does not call |build_page|
, because it is
1113 used in at least one place where that would be a mistake.
1116 void append_glue
(void
)
1121 cur_val
= new_glue
(fil_glue
);
1124 cur_val
= new_glue
(fill_glue
);
1127 cur_val
= new_glue
(ss_glue
);
1130 cur_val
= new_glue
(fil_neg_glue
);
1133 scan_glue
(glue_val_level
);
1136 scan_glue
(mu_val_level
);
1139 /* now |cur_val| points to the glue specification
*/
1140 tail_append
(new_glue
(cur_val
));
1141 flush_node
(cur_val
);
1142 if
(s
> skip_code
) {
1143 subtype
(tail
) = mu_glue
;
1148 void append_kern
(void
)
1150 int s
; /* |subtype| of the kern node
*/
1152 scan_dimen
((s
== mu_glue
), false
, false
);
1153 tail_append
(new_kern
(cur_val
));
1154 subtype
(tail
) = (quarterword
) s
;
1157 @ We have to deal with errors in which braces and such things are not
1158 properly nested. Sometimes the user makes an error of commission by
1159 inserting an extra symbol
, but sometimes the user makes an error of omission.
1160 \TeX\ can't always tell one from the other
, so it makes a guess and tries
1161 to avoid getting into a loop.
1163 The |off_save| routine is called when the current group code is wrong. It tries
1164 to insert something into the user's input that will help clean off
1170 halfword p
, q
; /* inserted token
*/
1171 if
(cur_group
== bottom_level
) {
1172 /* Drop current token and complain that it was unmatched
*/
1173 print_err
("Extra ");
1174 print_cmd_chr
((quarterword
) cur_cmd
, cur_chr
);
1175 help1
("Things are pretty mixed up, but I think the worst is over.");
1181 set_token_link
(temp_token_head
, p
);
1182 print_err
("Missing ");
1183 /* Prepare to insert a token that matches |cur_group|
, and print what it is
*/
1184 /* At this point
, |link
(temp_token_head
)=p|
, a pointer to an empty one-word node.
*/
1185 switch
(cur_group
) {
1186 case semi_simple_group
:
1187 set_token_info
(p
, cs_token_flag
+ frozen_end_group
);
1188 tprint_esc
("endgroup");
1190 case math_shift_group
:
1191 set_token_info
(p
, math_shift_token
+ '$'
);
1194 case math_left_group
:
1195 set_token_info
(p
, cs_token_flag
+ frozen_right
);
1197 set_token_link
(p
, q
);
1199 set_token_info
(p
, other_token
+ '.'
);
1200 tprint_esc
("right.");
1203 set_token_info
(p
, right_brace_token
+ '
}'
);
1207 tprint
(" inserted");
1208 ins_list
(token_link
(temp_token_head
));
1209 help5
("I've inserted something that you may have forgotten.",
1210 "(See the <inserted text> above.)",
1211 "With luck, this will get me unwedged. But if you",
1212 "really didn't forget anything, try typing `2' now; then",
1213 "my insertion and my current dilemma will both disappear.");
1218 @ The routine for a |right_brace| character branches into many subcases
,
1219 since a variety of things may happen
, depending on |cur_group|. Some
1220 types of groups are not supposed to be ended by a right brace
; error
1221 messages are given in hopes of pinpointing the problem. Most branches
1222 of this routine will be filled in later
, when we are ready to understand
1223 them
; meanwhile
, we must prepare ourselves to deal with such errors.
1226 void handle_right_brace
(void
)
1228 halfword p
, q
; /* for short-term use
*/
1229 scaled d
; /* holds |split_max_depth| in |insert_group|
*/
1230 int f
; /* holds |floating_penalty| in |insert_group|
*/
1232 switch
(cur_group
) {
1237 print_err
("Too many }'s");
1238 help2
("You've closed more groups than you opened.",
1239 "Such booboos are generally harmless, so keep going.");
1242 case semi_simple_group
:
1243 case math_shift_group
:
1244 case math_left_group
:
1245 extra_right_brace
();
1248 /* When the right brace occurs at the end of an \.
{\\hbox
} or \.
{\\vbox
} or
1249 \.
{\\vtop
} construction
, the |package| routine comes into action. We might
1250 also have to finish a paragraph that hasn't ended.
*/
1253 case adjusted_hbox_group
:
1254 adjust_tail
= adjust_head
;
1255 pre_adjust_tail
= pre_adjust_head
;
1259 end_graf
(vbox_group
);
1263 end_graf
(vtop_group
);
1267 end_graf
(insert_group
);
1268 q
= new_glue
(split_top_skip
);
1269 d
= split_max_depth
;
1270 f
= floating_penalty
;
1273 /* now |saved_value
(0)| is the insertion number
, or the |vadjust| subtype
*/
1274 p
= vpack
(vlink
(head
), 0, additional
, -1);
1276 if
(saved_type
(0) == saved_insert
) {
1277 tail_append
(new_node
(ins_node
, saved_value
(0)));
1278 height
(tail
) = height
(p
) + depth
(p
);
1279 ins_ptr
(tail
) = list_ptr
(p
);
1280 split_top_ptr
(tail
) = q
;
1282 float_cost
(tail
) = f
;
1283 } else if
(saved_type
(0) == saved_adjust
) {
1284 tail_append
(new_node
(adjust_node
, saved_value
(0)));
1285 adjust_ptr
(tail
) = list_ptr
(p
);
1288 confusion
("insert_group");
1292 if
(nest_ptr
== 0) {
1293 checked_page_filter
(insert
);
1298 /* this is needed in case the \.
{\\output
} executes a \.
{\\textdir
} command.
*/
1299 if
(dir_level
(text_dir_ptr
) == cur_level
) {
1300 /* DIR: Remove from |text_dir_ptr|
*/
1301 halfword text_dir_tmp
= vlink
(text_dir_ptr
);
1302 flush_node
(text_dir_ptr
);
1303 text_dir_ptr
= text_dir_tmp
;
1305 resume_after_output
();
1308 build_discretionary
();
1310 case local_box_group
:
1315 cur_tok
= cs_token_flag
+ frozen_cr
;
1316 print_err
("Missing \\cr inserted");
1317 help1
("I'm guessing that you meant to end an alignment here.");
1320 case no_align_group
:
1321 end_graf
(no_align_group
);
1326 end_graf
(vcenter_group
);
1329 case math_choice_group
:
1333 close_math_group
(p
);
1336 confusion
("rightbrace");
1342 void extra_right_brace
(void
)
1344 print_err
("Extra }, or forgotten ");
1345 switch
(cur_group
) {
1346 case semi_simple_group
:
1347 tprint_esc
("endgroup");
1349 case math_shift_group
:
1352 case math_left_group
:
1353 tprint_esc
("right");
1356 help5
("I've deleted a group-closing symbol because it seems to be",
1357 "spurious, as in `$x}$'. But perhaps the } is legitimate and",
1358 "you forgot something else, as in `\\hbox{$x}'. In such cases",
1359 "the way to recover is to insert both the forgotten and the",
1360 "deleted material, e.g., by typing `I$}'.");
1365 @ Here is where we clear the parameters that are supposed to revert to their
1366 default values after every paragraph and when internal vertical mode is entered.
1369 void normal_paragraph
(void
)
1372 eq_word_define
(int_base
+ looseness_code
, 0);
1373 if
(hang_indent
!= 0)
1374 eq_word_define
(dimen_base
+ hang_indent_code
, 0);
1375 if
(hang_after
!= 1)
1376 eq_word_define
(int_base
+ hang_after_code
, 1);
1377 if
(par_shape_ptr
!= null
)
1378 eq_define
(par_shape_loc
, shape_ref_cmd
, null
);
1379 if
(inter_line_penalties_ptr
!= null
)
1380 eq_define
(inter_line_penalties_loc
, shape_ref_cmd
, null
);
1383 @ The global variable |cur_box| will point to a newly-made box. If the box
1384 is void
, we will have |cur_box
=null|. Otherwise we will have
1385 |type
(cur_box
)=hlist_node| or |vlist_node| or |rule_node|
; the |rule_node|
1386 case can occur only with leaders.
1389 halfword cur_box
; /* box to be placed into its context
*/
1391 @ The |box_end| procedure does the right thing with |cur_box|
, if
1392 |box_context| represents the context as explained above.
1395 void box_end
(int box_context
)
1397 if
(box_context
< box_flag
) {
1398 /* Append box |cur_box| to the current list
, shifted by |box_context|
*/
1400 The global variable |adjust_tail| will be non-null if and only if the
1401 current box might include adjustments that should be appended to the
1402 current vertical list.
1404 if
(cur_box
!= null
) {
1405 shift_amount
(cur_box
) = box_context
;
1406 if
(abs
(mode
) == vmode
) {
1407 if
(pre_adjust_tail
!= null
) {
1408 if
(pre_adjust_head
!= pre_adjust_tail
)
1409 append_list
(pre_adjust_head
, pre_adjust_tail
);
1410 pre_adjust_tail
= null
;
1412 append_to_vlist
(cur_box
,lua_key_index
(box
));
1413 if
(adjust_tail
!= null
) {
1414 if
(adjust_head
!= adjust_tail
)
1415 append_list
(adjust_head
, adjust_tail
);
1419 checked_page_filter
(box
);
1423 if
(abs
(mode
) == hmode
)
1424 space_factor
= 1000;
1426 cur_box
= new_sub_box
(cur_box
);
1427 couple_nodes
(tail
, cur_box
);
1431 } else if
(box_context
< ship_out_flag
) {
1432 /* Store |cur_box| in a box register
*/
1433 if
(box_context
< global_box_flag
)
1434 eq_define
(box_base
+ box_context
- box_flag
, box_ref_cmd
, cur_box
);
1436 geq_define
(box_base
+ box_context
- global_box_flag
, box_ref_cmd
, cur_box
);
1437 } else if
(cur_box
!= null
) {
1438 if
(box_context
> ship_out_flag
) {
1439 /* Append a new leader node that uses |cur_box|
*/
1440 /* Get the next non-blank non-relax...
*/
1443 } while
((cur_cmd
== spacer_cmd
) ||
(cur_cmd
== relax_cmd
));
1444 if
(((cur_cmd
== hskip_cmd
) && (abs(mode) != vmode)) ||
1445 ((cur_cmd
== vskip_cmd
) && (abs(mode) == vmode))) {
1447 subtype
(tail
) = (quarterword
) (box_context
- (leader_flag
- a_leaders
));
1448 leader_ptr
(tail
) = cur_box
;
1450 print_err
("Leaders not followed by proper glue");
1452 ("You should say `\\leaders <box or rule><hskip or vskip>'.",
1453 "I found the <box or rule>, but there's no suitable",
1454 "<hskip or vskip>, so I'm ignoring these leaders.");
1456 flush_node_list
(cur_box
);
1459 ship_out
(static_pdf
, cur_box
, SHIPPING_PAGE
);
1464 @ the next input should specify a box or perhaps a rule
1467 void scan_box
(int box_context
)
1469 /* Get the next non-blank non-relax...
*/
1472 } while
((cur_cmd
== spacer_cmd
) ||
(cur_cmd
== relax_cmd
));
1473 if
(cur_cmd
== make_box_cmd
) {
1474 begin_box
(box_context
);
1475 } else if
((box_context
>= leader_flag
) &&
1476 ((cur_cmd
== hrule_cmd
) ||
(cur_cmd
== vrule_cmd
) ||
1477 (cur_cmd
== no_hrule_cmd
) ||
(cur_cmd
== no_vrule_cmd
))) {
1478 cur_box
= scan_rule_spec
();
1479 box_end
(box_context
);
1481 print_err
("A <box> was supposed to be here");
1482 help3
("I was expecting to see \\hbox or \\vbox or \\copy or \\box or",
1483 "something like that. So you might find something missing in",
1484 "your output. But keep trying; you can fix this later.");
1490 void new_graf
(boolean indented
)
1492 halfword p
, q
, dir_graf_tmp
;
1495 if
((mode
== vmode
) ||
(head
!= tail
)) {
1496 tail_append
(new_param_glue
(par_skip_code
));
1500 space_factor
= 1000;
1501 /* LOCAL
: Add local paragraph node
*/
1502 tail_append
(make_local_par_node
(0));
1505 box_dir
(p
) = par_direction
;
1506 width
(p
) = par_indent
;
1507 subtype
(p
) = indent_list
;
1513 dir_rover
= text_dir_ptr
;
1514 while
(dir_rover
!= null
) {
1515 if
((vlink
(dir_rover
) != null
) ||
(dir_dir
(dir_rover
) != par_direction
)) {
1516 dir_graf_tmp
= new_dir
(dir_dir
(dir_rover
));
1517 try_couple_nodes
(dir_graf_tmp
,vlink
(q
));
1518 couple_nodes
(q
,dir_graf_tmp
);
1520 dir_rover
= vlink
(dir_rover
);
1523 while
(vlink
(q
) != null
)
1526 if
(every_par
!= null
)
1527 begin_token_list
(every_par
, every_par_text
);
1528 if
(nest_ptr
== 1) {
1529 checked_page_filter
(new_graf
);
1530 build_page
(); /* put |par_skip| glue on current page
*/
1535 void indent_in_hmode
(void
)
1538 if
(cur_chr
> 0) { /* \.
{\\indent
} */
1540 width
(p
) = par_indent
;
1541 if
(abs
(mode
) == hmode
)
1542 space_factor
= 1000;
1550 void head_for_vmode
(void
)
1553 if
((cur_cmd
!= hrule_cmd
) && (cur_cmd != no_hrule_cmd)) {
1556 print_err
("You can't use `\\hrule' here except with leaders");
1557 help2
("To put a horizontal rule in an hbox or an alignment,",
1558 "you should use \\leaders or \\hrulefill (see The TeXbook).");
1563 cur_tok
= par_token
;
1565 token_type
= inserted
;
1569 @ TODO
(BUG?
): |dir_save| would have been set by |line_break| by means
1570 of |post_line_break|
, but this is not done right now
, as it introduces
1571 pretty heavy memory leaks. This means the current code is probably
1572 wrong in some way that relates to in-paragraph displays.
1575 void end_graf
(int line_break_context
)
1577 if
(mode
== hmode
) {
1578 if
((head
== tail
) ||
(vlink
(head
) == tail
)) {
1579 if
(vlink
(head
) == tail
)
1580 flush_node
(vlink
(head
));
1581 pop_nest
(); /* null paragraphs are ignored
, all contain a |local_paragraph| node
*/
1583 line_break
(false
, line_break_context
);
1585 if
(dir_save
!= null
) {
1586 flush_node_list
(dir_save
);
1595 void begin_insert_or_adjust
(void
)
1597 if
(cur_cmd
!= vadjust_cmd
) {
1598 scan_register_num
();
1599 if
(cur_val
== output_box
) {
1600 print_err
("You can't \\insert");
1601 print_int
(output_box
);
1602 help1
("I'm changing to \\insert0; box \\outputbox is special.");
1606 set_saved_record
(0, saved_insert
, 0, cur_val
);
1607 } else if
(scan_keyword
("pre")) {
1608 set_saved_record
(0, saved_adjust
, 0, 1);
1610 set_saved_record
(0, saved_adjust
, 0, 0);
1613 new_save_level
(insert_group
);
1618 prev_depth
= ignore_depth
;
1621 @ I
(TH
)'ve renamed the |make_mark| procedure to this
, because if the
1622 current chr code is
1, then the actual command was \.
{\\clearmarks
},
1623 which does not generate a mark node but instead destroys the current
1627 void handle_mark
(void
)
1629 halfword p
; /* new node
*/
1630 halfword c
; /* the mark class
*/
1631 if
(cur_chr
== clear_marks_code
) {
1636 delete_first_mark
(c
);
1637 delete_split_first_mark
(c
);
1638 delete_split_bot_mark
(c
);
1645 if
(c
> biggest_used_mark
)
1646 biggest_used_mark
= c
;
1648 p
= scan_toks
(false
, true
);
1649 p
= new_node
(mark_node
, 0); /* the |subtype| is not used
*/
1651 mark_ptr
(p
) = def_ref
;
1652 couple_nodes
(tail
, p
);
1658 void append_penalty
(void
)
1661 tail_append
(new_penalty
(cur_val
));
1662 if
(mode
== vmode
) {
1663 checked_page_filter
(penalty
);
1668 @ When |delete_last| is called
, |cur_chr| is the |type| of node that
1669 will be deleted
, if present.
1671 The |remove_item| command removes a penalty
, kern
, or glue node if it
1672 appears at the tail of the current list
, using a brute-force linear scan.
1673 Like \.
{\\lastbox
}, this command is not allowed in vertical mode
(except
1674 internal vertical mode
), since the current list in vertical mode is sent
1675 to the page builder. But if we happen to be able to implement it in
1676 vertical mode
, we do.
1679 void delete_last
(void
)
1681 halfword p
, q
; /* run through the current list
*/
1682 if
((mode
== vmode
) && (tail == head)) {
1683 /* Apologize for inability to do the operation now
,
1684 unless \.
{\\unskip
} follows non-glue
*/
1685 if
((cur_chr
!= glue_node
) ||
(last_glue
!= max_halfword
)) {
1687 if
(cur_chr
== kern_node
) {
1689 ("Sorry...I usually can't take things from the current page.",
1690 "Try `I\\kern-\\lastkern' instead.");
1691 } else if
(cur_chr
!= glue_node
) {
1693 ("Sorry...I usually can't take things from the current page.",
1694 "Perhaps you can make the output routine do it.");
1697 ("Sorry...I usually can't take things from the current page.",
1698 "Try `I\\vskip-\\lastskip' instead.");
1703 /* todo
: clean this up
*/
1704 if
(!is_char_node
(tail
)) {
1705 if
(type
(tail
) == cur_chr
) {
1709 if
(!is_char_node
(q
)) {
1710 if
(type
(q
) == disc_node
) {
1716 } while
(q
!= tail
);
1718 flush_node_list
(tail
);
1726 void unpackage
(void
)
1728 halfword p
; /* the box
*/
1729 halfword r
; /* to remove marginal kern nodes
*/
1730 int c
; /* should we copy?
*/
1731 halfword s
; /* for varmem assignment
*/
1732 if
(cur_chr
> copy_code
) {
1733 /* Handle saved items and |goto done|
*/
1734 try_couple_nodes
(tail
, disc_ptr
[cur_chr
]);
1735 disc_ptr
[cur_chr
] = null
;
1739 scan_register_num
();
1743 if
((abs
(mode
) == mmode
)
1744 ||
((abs
(mode
) == vmode
) && (type(p) != vlist_node))
1745 ||
((abs
(mode
) == hmode
) && (type(p) != hlist_node))) {
1746 print_err
("Incompatible list can't be unboxed");
1747 help3
("Sorry, Pandora. (You sneaky devil.)",
1748 "I refuse to unbox an \\hbox in vertical mode or vice versa.",
1749 "And I can't open any boxes in math mode.");
1753 if
(c
== copy_code
) {
1754 s
= copy_node_list
(list_ptr
(p
));
1755 try_couple_nodes
(tail
,s
);
1757 try_couple_nodes
(tail
,list_ptr
(p
));
1758 box
(cur_val
) = null
;
1763 while
(vlink
(tail
) != null
) {
1765 if
(!is_char_node
(r
) && (type(r) == margin_kern_node)) {
1766 try_couple_nodes
(tail
,vlink
(r
));
1774 Italic corrections are converted to kern nodes when the |ital_corr| command
1775 follows a character. In math mode the same effect is achieved by appending
1776 a kern of zero here
, since italic corrections are supplied later.
1779 void append_italic_correction
(void
)
1781 halfword p
; /* |char_node| at the tail of the current list
*/
1782 internal_font_number f
; /* the font in the |char_node|
*/
1784 if
(is_char_node
(tail
))
1789 tail_append
(new_kern
(char_italic
(f
, character
(p
))));
1790 subtype
(tail
) = italic_kern
;
1795 void append_local_box
(int kind
)
1798 set_saved_record
(-1, saved_boxtype
, 0, kind
);
1799 new_save_level
(local_box_group
);
1803 space_factor
= 1000;
1806 @ Discretionary nodes are easy in the common case `\.
{\\
-}'
, but in the
1807 general case we must process three braces full of items.
1809 The space factor does not change when we append a discretionary node
,
1810 but it starts out as
1000 in the subsidiary lists.
1813 void append_discretionary
(void
)
1816 tail_append
(new_disc
());
1817 subtype
(tail
) = (quarterword
) cur_chr
;
1818 if
(cur_chr
== explicit_disc
) {
1820 c
= get_pre_hyphen_char
(cur_lang
);
1822 vlink
(pre_break
(tail
)) = new_char
(equiv
(cur_font_loc
), c
);
1823 alink
(vlink
(pre_break
(tail
))) = pre_break
(tail
);
1824 tlink
(pre_break
(tail
)) = vlink
(pre_break
(tail
));
1826 c
= get_post_hyphen_char
(cur_lang
);
1828 vlink
(post_break
(tail
)) = new_char
(equiv
(cur_font_loc
), c
);
1829 alink
(vlink
(post_break
(tail
))) = post_break
(tail
);
1830 tlink
(post_break
(tail
)) = vlink
(post_break
(tail
));
1832 disc_penalty
(tail
) = int_par
(ex_hyphen_penalty_code
);
1834 /* \discretionary
*/
1835 if
(scan_keyword
("penalty")) {
1837 disc_penalty
(tail
) = cur_val
;
1840 set_saved_record
(-1, saved_disc
, 0, 0);
1841 new_save_level
(disc_group
);
1845 space_factor
= 1000;
1846 /* already preset
: disc_penalty
(tail
) = int_par
(hyphen_penalty_code
); */
1850 @ The test for |p
!= null| ensures that empty \.
{\\localleftbox
} and
1851 \.
{\\localrightbox
} commands are not applied.
1854 void build_local_box
(void
)
1859 assert
(saved_type
(-1) == saved_boxtype
);
1860 kind
= saved_value
(-1);
1865 p
= hpack
(p
, 0, additional
, -1);
1867 eq_define
(local_left_box_base
, box_ref_cmd
, p
);
1869 eq_define
(local_right_box_base
, box_ref_cmd
, p
);
1870 if
(abs
(mode
) == hmode
) {
1871 /* LOCAL
: Add local paragraph node
*/
1872 tail_append
(make_local_par_node
(1));
1874 eq_word_define
(int_base
+ no_local_whatsits_code
, no_local_whatsits
+ 1);
1877 @ The three discretionary lists are constructed somewhat as if they were
1878 hboxes. A~subroutine called |build_discretionary| handles the transitions.
1879 (This is sort of fun.
)
1882 void build_discretionary
(void
)
1884 halfword p
, q
; /* for link manipulation
*/
1885 int n
; /* length of discretionary list
*/
1887 /* Prune the current list
, if necessary
, until it contains only
1888 |char_node|
, |kern_node|
, |hlist_node|
, |vlist_node| and
1889 |rule_node| items
; set |n| to the length of the list
,
1890 and set |q| to the lists tail
*/
1891 /* During this loop
, |p
=vlink
(q
)| and there are |n| items preceding |p|.
*/
1896 if
(!is_char_node
(p
) && type(p) > rule_node && type(p) != kern_node) {
1897 print_err
("Improper discretionary list");
1898 help1
("Discretionary lists must contain only boxes and kerns.");
1901 tprint_nl
("The following discretionary sublist has been deleted:");
1903 end_diagnostic
(true
);
1916 assert
(saved_type
(-1) == saved_disc
);
1917 switch
(saved_value
(-1)) {
1920 vlink
(pre_break
(tail
)) = p
;
1921 alink
(p
) = pre_break
(tail
);
1922 tlink
(pre_break
(tail
)) = q
;
1927 vlink
(post_break
(tail
)) = p
;
1928 alink
(p
) = post_break
(tail
);
1929 tlink
(post_break
(tail
)) = q
;
1933 /* Attach list |p| to the current list
, and record its length
;
1934 then finish up and |return|
*/
1935 if
((n
> 0) && (abs(mode) == mmode)) {
1936 print_err
("Illegal math \\discretionary");
1937 help2
("Sorry: The third part of a discretionary break must be",
1938 "empty, in math formulas. I had to delete your third part.");
1943 vlink
(no_break
(tail
)) = p
;
1944 alink
(p
) = no_break
(tail
);
1945 tlink
(no_break
(tail
)) = q
;
1951 } /* there are no other cases
*/
1952 set_saved_record
(-1, saved_disc
, 0, (saved_value
(-1) + 1));
1953 new_save_level
(disc_group
);
1957 space_factor
= 1000;
1960 @ The positioning of accents is straightforward but tedious. Given an accent
1961 of width |a|
, designed for characters of height |x| and slant |s|
;
1962 and given a character of width |w|
, height |h|
, and slant |t|
: We will shift
1963 the accent down by |x-h|
, and we will insert kern nodes that have the effect of
1964 centering the accent over the character and shifting the accent to the
1965 right by $\delta
={1\over2
}(w-a
)+h\cdot t-x\cdot s$. If either character is
1966 absent from the font
, we will simply use the other
, without shifting.
1969 void make_accent
(void
)
1971 double s
, t
; /* amount of slant
*/
1972 halfword p
, q
, r
; /* character
, box
, and kern nodes
*/
1973 internal_font_number f
; /* relevant font
*/
1974 scaled a
, h
, x
, w
, delta
; /* heights and widths
, as explained above
*/
1976 f
= equiv
(cur_font_loc
);
1977 p
= new_glyph
(f
, cur_val
);
1980 s
= float_cast
(slant
(f
)) / float_constant
(65536); /* real division
*/
1983 /* Create a character node |q| for the next character
,
1984 but set |q
:=null| if problems arise
*/
1986 f
= equiv
(cur_font_loc
);
1987 if
((cur_cmd
== letter_cmd
) ||
1988 (cur_cmd
== other_char_cmd
) ||
(cur_cmd
== char_given_cmd
)) {
1989 q
= new_glyph
(f
, cur_chr
);
1990 } else if
(cur_cmd
== char_num_cmd
) {
1992 q
= new_glyph
(f
, cur_val
);
1998 /* Append the accent with appropriate kerns
, then set |p
:=q|
*/
1999 /* The kern nodes appended here must be distinguished from other kerns
, lest
2000 they be wiped away by the hyphenation algorithm or by a previous line break.
2002 The two kerns are computed with
(machine-dependent
) |real| arithmetic
, but
2003 their sum is machine-independent
; the net effect is machine-independent
,
2004 because the user cannot remove these nodes nor access them via \.
{\\lastkern
}.
2006 t
= float_cast
(slant
(f
)) / float_constant
(65536); /* real division
*/
2008 h
= glyph_height
(q
);
2009 if
(h
!= x
) { /* the accent must be shifted up or down
*/
2010 p
= hpack
(p
, 0, additional
, -1);
2011 shift_amount
(p
) = x
- h
;
2013 delta
= round
(float_cast
(w
- a
) / float_constant
(2) + h
* t
- x
* s
); /* real multiplication
*/
2014 r
= new_kern
(delta
);
2015 subtype
(r
) = accent_kern
;
2016 couple_nodes
(tail
, r
);
2018 tail
= new_kern
(-a
- delta
);
2019 subtype
(tail
) = accent_kern
;
2020 couple_nodes
(p
, tail
);
2024 couple_nodes
(tail
, p
);
2026 space_factor
= 1000;
2030 @ When `\.
{\\cr
}' or `\.
{\\span
}' or a tab mark comes through the scanner
2031 into |main_control|
, it might be that the user has foolishly inserted
2032 one of them into something that has nothing to do with alignment. But it is
2033 far more likely that a left brace or right brace has been omitted
, since
2034 |get_next| takes actions appropriate to alignment only when `\.
{\\cr
}'
2035 or `\.
{\\span
}' or tab marks occur with |align_state
=0|. The following
2036 program attempts to make an appropriate recovery.
2039 void align_error
(void
)
2041 if
(abs
(align_state
) > 2) {
2042 /* Express consternation over the fact that no alignment is in progress
*/
2043 print_err
("Misplaced ");
2044 print_cmd_chr
((quarterword
) cur_cmd
, cur_chr
);
2045 if
(cur_tok
== tab_token
+ '
&') {
2046 help6
("I can't figure out why you would want to use a tab mark",
2047 "here. If you just want an ampersand, the remedy is",
2048 "simple: Just type `I\\&' now. But if some right brace",
2049 "up above has ended a previous alignment prematurely,",
2050 "you're probably due for more error messages, and you",
2051 "might try typing `S' now just to see what is salvageable.");
2053 help5
("I can't figure out why you would want to use a tab mark",
2054 "or \\cr or \\span just now. If something like a right brace",
2055 "up above has ended a previous alignment prematurely,",
2056 "you're probably due for more error messages, and you",
2057 "might try typing `S' now just to see what is salvageable.");
2063 if
(align_state
< 0) {
2064 print_err
("Missing { inserted");
2066 cur_tok
= left_brace_token
+ '
{'
;
2068 print_err
("Missing } inserted");
2070 cur_tok
= right_brace_token
+ '
}'
;
2072 help3
("I've put in what seems to be necessary to fix",
2073 "the current column of the current alignment.",
2074 "Try to go on, since this might almost work.");
2079 @ The help messages here contain a little white lie
, since \.
{\\noalign
}
2080 and \.
{\\omit
} are allowed also after `\.
{\\noalign\
{...\
}}'.
2083 void no_align_error
(void
)
2085 print_err
("Misplaced \\noalign");
2086 help2
("I expect to see \\noalign only after the \\cr of",
2087 "an alignment. Proceed, and I'll ignore this case.");
2091 void omit_error
(void
)
2093 print_err
("Misplaced \\omit");
2094 help2
("I expect to see \\omit only after tab marks or the \\cr of",
2095 "an alignment. Proceed, and I'll ignore this case.");
2099 @ We've now covered most of the abuses of \.
{\\halign
} and \.
{\\valign
}.
2100 Let's take a look at what happens when they are used correctly.
2102 An |align_group| code is supposed to remain on the |save_stack|
2103 during an entire alignment
, until |fin_align| removes it.
2105 A devious user might force an |endv| command to occur just about anywhere
;
2106 we must defeat such hacks.
2111 base_ptr
= input_ptr
;
2112 input_stack
[base_ptr
] = cur_input
;
2113 while
((input_stack
[base_ptr
].index_field
!= v_template
) &&
2114 (input_stack
[base_ptr
].loc_field
== null
) &&
2115 (input_stack
[base_ptr
].state_field
== token_list
))
2117 if
((input_stack
[base_ptr
].index_field
!= v_template
) ||
2118 (input_stack
[base_ptr
].loc_field
!= null
) ||
2119 (input_stack
[base_ptr
].state_field
!= token_list
))
2120 fatal_error
("(interwoven alignment preambles are not allowed)");
2121 /*.interwoven alignment preambles...
*/
2122 if
(cur_group
== align_group
) {
2123 end_graf
(align_group
);
2131 @ Finally
, \.
{\\endcsname
} is not supposed to get through to |main_control|.
2136 print_err
("Extra \\endcsname");
2137 help1
("I'm ignoring this, since I wasn't doing a \\csname.");
2142 Assignments to values in |eqtb| can be global or local. Furthermore
, a
2143 control sequence can be defined to be `\.
{\\long
}'
, `\.
{\\protected
}'
,
2144 or `\.
{\\outer
}'
, and it might or might not be expanded. The prefixes
2145 `\.
{\\global
}'
, `\.
{\\long
}'
, `\.
{\\protected
}'
,
2146 and `\.
{\\outer
}' can occur in any order. Therefore we assign binary numeric
2147 codes
, making it possible to accumulate the union of all specified prefixes
2148 by adding the corresponding codes.
(PASCAL's |set| operations could also
2151 Every prefix
, and every command code that might or might not be prefixed
,
2152 calls the action procedure |prefixed_command|. This routine accumulates
2153 a sequence of prefixes until coming to a non-prefix
, then it carries out
2156 @ If the user says
, e.g.
, `\.
{\\global\\global
}'
, the redundancy is
2160 @ The different types of code values have different legal ranges
; the
2161 following program is careful to check each case properly.
2164 #define check_def_code
(A
) do
{ \
2165 if
(((cur_val
<0)&&(p<(A)))||(cur_val>n)) { \
2166 print_err
("Invalid code ("); \
2167 print_int
(cur_val
); \
2169 tprint
("), should be in the range 0.."); \
2171 tprint
("), should be at most "); \
2173 help1
("I'm going to use 0 instead of that illegal code value."); \
2180 void prefixed_command
(void
)
2182 int a
; /* accumulated prefix codes so far
*/
2183 internal_font_number f
; /* identifies a font
*/
2184 halfword j
; /* index into a \.
{\\parshape
} specification
*/
2185 halfword p
, q
; /* for temporary short-term use
*/
2187 boolean e
; /* should a definition be expanded? or was \.
{\\let
} not done?
*/
2188 mathcodeval mval
; /* for handling of \.
{\\mathchardef
}s
*/
2190 while
(cur_cmd
== prefix_cmd
) {
2191 if
(!odd
(a
/ cur_chr
))
2193 /* Get the next non-blank non-relax...
*/
2196 } while
((cur_cmd
== spacer_cmd
) ||
(cur_cmd
== relax_cmd
));
2198 if
(cur_cmd
<= max_non_prefixed_command
) {
2199 /* Discard erroneous prefixes and |return|
*/
2200 print_err
("You can't use a prefix with `");
2201 print_cmd_chr
((quarterword
) cur_cmd
, cur_chr
);
2204 ("I'll pretend you didn't say \\long or \\outer or \\global or",
2209 if
(int_par
(tracing_commands_code
) > 2)
2212 /* Discard the prefixes \.
{\\long
} and \.
{\\outer
} if they are irrelevant
*/
2214 j
= protected_token
;
2219 if
((cur_cmd
!= def_cmd
) && ((a % 4 != 0) || (j != 0))) {
2220 print_err
("You can't use `\\long' or `\\outer' or `\\protected' with `");
2221 print_cmd_chr
((quarterword
) cur_cmd
, cur_chr
);
2223 help1
("I'll pretend you didn't say \\long or \\outer or \\protected here.");
2226 /* Adjust for the setting of \.
{\\globaldefs
} */
2227 if
(global_defs
!= 0) {
2228 if
(global_defs
< 0) {
2238 /* Here's an example of the way many of the following routines operate.
2239 (Unfortunately
, they aren't all as simple as this.
) */
2240 define
(cur_font_loc
, data_cmd
, cur_chr
);
2243 /* When a |def| command has been scanned
,
2244 |cur_chr| is odd if the definition is supposed to be global
, and
2245 |cur_chr
>=2| if the definition is supposed to be expanded.
*/
2247 if
(odd
(cur_chr
) && !is_global(a) && (global_defs >= 0))
2252 q
= scan_toks
(true
, e
);
2255 set_token_info
(q
, j
);
2256 set_token_link
(q
, token_link
(def_ref
));
2257 set_token_link
(def_ref
, q
);
2259 define
(p
, call_cmd
+ (a
% 4), def_ref
);
2268 } while
(cur_cmd
== spacer_cmd
);
2269 if
(cur_tok
== other_token
+ '
='
) {
2271 if
(cur_cmd
== spacer_cmd
)
2274 } else if
(n
== normal
+ 1) {
2283 /* look ahead
, then back up
*/
2284 /* note that |back_input| doesn't affect |cur_cmd|
, |cur_chr|
*/
2290 cur_cs
= active_to_cs
(cur_val
, true
);
2291 set_token_info
(cur_cs
, cur_cs
+ cs_token_flag
);
2295 } while
(cur_cmd
== spacer_cmd
);
2296 if
(cur_tok
== other_token
+ '
='
) {
2298 if
(cur_cmd
== spacer_cmd
)
2303 tex_error
("invalid number for \\letcharcode",NULL);
2306 if
(cur_cmd
>= call_cmd
)
2307 add_token_ref
(cur_chr
);
2308 define
(p
, cur_cmd
, cur_chr
);
2310 case shorthand_def_cmd
:
2311 /* We temporarily define |p| to be |relax|
, so that an occurrence of |p|
2312 while scanning the definition will simply stop the scanning instead of
2313 producing an ``undefined control sequence'' error or expanding the
2314 previous meaning. This allows
, for instance
, `\.
{\\chardef\\foo
=123\\foo
}'.
2319 define
(p
, relax_cmd
, too_big_char
);
2320 scan_optional_equals
();
2324 define
(p
, char_given_cmd
, cur_val
);
2326 case math_char_def_code
:
2327 mval
= scan_mathchar
(tex_mathcode
);
2328 if
(mathoption_int_par
(c_mathoption_umathcode_meaning_code
) == 1) {
2329 cur_val
= (mval.class_value
+ (8 * mval.family_value
)) * (65536 * 32) + mval.character_value
;
2330 define
(p
, xmath_given_cmd
, cur_val
);
2332 cur_val
= (mval.class_value
* 16 + mval.family_value
) * 256 + mval.character_value
;
2333 define
(p
, math_given_cmd
, cur_val
);
2336 case xmath_char_def_code
:
2337 mval
= scan_mathchar
(umath_mathcode
);
2338 cur_val
= (mval.class_value
+ (8 * mval.family_value
)) * (65536 * 32) + mval.character_value
;
2339 define
(p
, xmath_given_cmd
, cur_val
);
2341 case umath_char_def_code
:
2342 mval
= scan_mathchar
(umathnum_mathcode
);
2343 cur_val
= (mval.class_value
+ (8 * mval.family_value
)) * (65536 * 32) + mval.character_value
;
2344 define
(p
, xmath_given_cmd
, cur_val
);
2347 scan_register_num
();
2349 case count_def_code
:
2350 define
(p
, assign_int_cmd
, count_base
+ cur_val
);
2352 case attribute_def_code
:
2353 define
(p
, assign_attr_cmd
, attribute_base
+ cur_val
);
2355 case dimen_def_code
:
2356 define
(p
, assign_dimen_cmd
, scaled_base
+ cur_val
);
2359 define
(p
, assign_glue_cmd
, skip_base
+ cur_val
);
2361 case mu_skip_def_code
:
2362 define
(p
, assign_mu_glue_cmd
, mu_skip_base
+ cur_val
);
2365 define
(p
, assign_toks_cmd
, toks_base
+ cur_val
);
2368 confusion
("shorthand_def");
2374 case read_to_cs_cmd
:
2378 if
(!scan_keyword
("to")) {
2379 print_err
("Missing `to' inserted");
2380 help2
("You should have said `\\read<number> to \\cs'.",
2381 "I'm going to look for the \\cs now.");
2387 define
(p
, call_cmd
, cur_val
);
2389 case toks_register_cmd
:
2390 case assign_toks_cmd
:
2391 /* The token-list parameters
, \.
{\\output
} and \.
{\\everypar
}, etc.
, receive
2392 their values in the following way.
(For safety's sake
, we place an
2393 enclosing pair of braces around an \.
{\\output
} list.
) */
2395 if
(cur_cmd
== toks_register_cmd
) {
2396 scan_register_num
();
2397 p
= toks_base
+ cur_val
;
2399 p
= cur_chr
; /* |p
=every_par_loc| or |output_routine_loc| or \dots
*/
2401 scan_optional_equals
();
2402 /* Get the next non-blank non-relax non-call token
*/
2405 } while
((cur_cmd
== spacer_cmd
) ||
(cur_cmd
== relax_cmd
));
2407 if
(cur_cmd
!= left_brace_cmd
) {
2408 /* If the right-hand side is a token parameter
2409 or token register
, finish the assignment and |goto done|
*/
2410 if
(cur_cmd
== toks_register_cmd
) {
2411 scan_register_num
();
2412 cur_cmd
= assign_toks_cmd
;
2413 cur_chr
= toks_base
+ cur_val
;
2415 if
(cur_cmd
== assign_toks_cmd
) {
2418 define
(p
, undefined_cs_cmd
, null
);
2421 define
(p
, call_cmd
, q
);
2428 q
= scan_toks
(false
, false
);
2429 if
(token_link
(def_ref
) == null
) { /* empty list
: revert to the default
*/
2430 define
(p
, undefined_cs_cmd
, null
);
2431 free_avail
(def_ref
);
2433 if
(p
== output_routine_loc
) { /* enclose in curlies
*/
2435 set_token_link
(q
, p
);
2436 p
= output_routine_loc
;
2438 set_token_info
(q
, right_brace_token
+ '
}'
);
2440 set_token_info
(q
, left_brace_token
+ '
{'
);
2441 set_token_link
(q
, token_link
(def_ref
));
2442 set_token_link
(def_ref
, q
);
2444 define
(p
, call_cmd
, def_ref
);
2447 case assign_int_cmd
:
2448 /* Similar routines are used to assign values to the numeric parameters.
*/
2450 scan_optional_equals
();
2452 assign_internal_value
(a
, p
, cur_val
);
2454 case assign_attr_cmd
:
2456 scan_optional_equals
();
2458 if
((p
- attribute_base
) > max_used_attr
)
2459 max_used_attr
= (p
- attribute_base
);
2460 attr_list_cache
= cache_disabled
;
2461 word_define
(p
, cur_val
);
2463 case assign_dir_cmd
:
2464 /* DIR: Assign direction codes
*/
2467 case int_base
+ page_direction_code
:
2468 eq_word_define
(int_base
+ page_direction_code
, cur_val
);
2470 case int_base
+ body_direction_code
:
2471 eq_word_define
(int_base
+ body_direction_code
, cur_val
);
2473 case int_base
+ par_direction_code
:
2474 eq_word_define
(int_base
+ par_direction_code
, cur_val
);
2476 case int_base
+ math_direction_code
:
2477 eq_word_define
(int_base
+ math_direction_code
, cur_val
);
2479 case int_base
+ text_direction_code
:
2481 /* various tests hint that this is unnecessary and
2482 * sometimes even produces weird results
, eg
2483 * (\hbox
{\textdir TRT ABC\textdir TLT
DEF})
2488 if
((no_local_dirs
> 0) && (abs(mode) == hmode)) {
2489 /* DIR: Add local dir node
*/
2490 tail_append
(new_dir
(text_direction
));
2493 update_text_dir_ptr
(cur_val
);
2494 if
(abs
(mode
) == hmode
) {
2495 /* DIR: Add local dir node
*/
2496 tail_append
(new_dir
(cur_val
));
2497 dir_level
(tail
) = cur_level
;
2499 eq_word_define
(int_base
+ text_direction_code
, cur_val
);
2500 eq_word_define
(int_base
+ no_local_dirs_code
, no_local_dirs
+ 1);
2504 case assign_dimen_cmd
:
2506 scan_optional_equals
();
2507 scan_normal_dimen
();
2508 assign_internal_value
(a
, p
, cur_val
);
2510 case assign_glue_cmd
:
2511 case assign_mu_glue_cmd
:
2514 scan_optional_equals
();
2515 if
(n
== assign_mu_glue_cmd
)
2516 scan_glue
(mu_val_level
);
2518 scan_glue
(glue_val_level
);
2519 define
(p
, glue_ref_cmd
, cur_val
);
2521 case def_char_code_cmd
:
2522 case def_del_code_cmd
:
2523 /* Let |n| be the largest legal code value
, based on |cur_chr|
*/
2524 if
(cur_chr
== cat_code_base
)
2526 else if
(cur_chr
== sf_code_base
)
2532 if
(cur_chr
== math_code_base
) {
2534 cur_val1
= level_one
;
2536 cur_val1
= cur_level
;
2537 scan_extdef_math_code
(cur_val1
, tex_mathcode
);
2538 } else if
(cur_chr
== lc_code_base
) {
2541 scan_optional_equals
();
2543 check_def_code
(lc_code_base
);
2544 define_lc_code
(p
, cur_val
);
2545 } else if
(cur_chr
== uc_code_base
) {
2548 scan_optional_equals
();
2550 check_def_code
(uc_code_base
);
2551 define_uc_code
(p
, cur_val
);
2552 } else if
(cur_chr
== sf_code_base
) {
2555 scan_optional_equals
();
2557 check_def_code
(sf_code_base
);
2558 define_sf_code
(p
, cur_val
);
2559 } else if
(cur_chr
== cat_code_base
) {
2562 scan_optional_equals
();
2564 check_def_code
(cat_code_base
);
2565 define_cat_code
(p
, cur_val
);
2566 } else if
(cur_chr
== del_code_base
) {
2568 cur_val1
= level_one
;
2570 cur_val1
= cur_level
;
2571 scan_extdef_del_code
(cur_val1
, tex_mathcode
);
2574 case extdef_math_code_cmd
:
2575 case extdef_del_code_cmd
:
2577 cur_val1
= level_one
;
2579 cur_val1
= cur_level
;
2580 if
(cur_chr
== math_code_base
)
2581 scan_extdef_math_code
(cur_val1
, umath_mathcode
);
2582 else if
(cur_chr
== math_code_base
+ 1)
2583 scan_extdef_math_code
(cur_val1
, umathnum_mathcode
);
2584 else if
(cur_chr
== del_code_base
)
2585 scan_extdef_del_code
(cur_val1
, umath_mathcode
);
2586 else if
(cur_chr
== del_code_base
+ 1)
2587 scan_extdef_del_code
(cur_val1
, umathnum_mathcode
);
2589 case def_family_cmd
:
2591 scan_math_family_int
();
2593 scan_optional_equals
();
2595 define_fam_fnt
(cur_val1
, p
, cur_val
);
2597 case set_math_param_cmd
:
2600 if
(cur_cmd
!= math_style_cmd
) {
2601 print_err
("Missing math style, treated as \\displaystyle");
2603 ("A style should have been here; I inserted `\\displaystyle'.");
2604 cur_val1
= display_style
;
2609 scan_optional_equals
();
2610 if
(p
< math_param_first_mu_glue
) {
2611 if
(p
== math_param_radical_degree_raise
)
2614 scan_dimen
(false
, false
, false
);
2616 scan_glue
(mu_val_level
);
2617 if
(cur_val
== glue_par
(thin_mu_skip_code
))
2618 cur_val
= thin_mu_skip_code
;
2619 else if
(cur_val
== glue_par
(med_mu_skip_code
))
2620 cur_val
= med_mu_skip_code
;
2621 else if
(cur_val
== glue_par
(thick_mu_skip_code
))
2622 cur_val
= thick_mu_skip_code
;
2624 define_math_param
(p
, cur_val1
, cur_val
);
2630 do_register_command
(a
);
2633 /* The processing of boxes is somewhat different
, because we may need
2634 to scan and create an entire box before we actually change the value
2636 scan_register_num
();
2638 n
= global_box_flag
+ cur_val
;
2640 n
= box_flag
+ cur_val
;
2641 scan_optional_equals
();
2642 if
(set_box_allowed
) {
2645 print_err
("Improper \\setbox");
2646 help2
("Sorry, \\setbox is not allowed after \\halign in a display,",
2647 "or between \\accent and an accented character.");
2652 /* The |space_factor| or |prev_depth| settings are changed when a |set_aux|
2653 command is sensed. Similarly
, |prev_graf| is changed in the presence of
2654 |set_prev_graf|
, and |dead_cycles| or |insert_penalties| in the presence of
2655 |set_page_int|. These definitions are always global.
*/
2658 case set_prev_graf_cmd
:
2661 case set_page_dimen_cmd
:
2662 alter_page_so_far
();
2664 case set_page_int_cmd
:
2667 case set_box_dimen_cmd
:
2668 /* When some dimension of a box register is changed
, the change isn't exactly
2669 global
; but \TeX\ does not look at the \.
{\\global
} switch.
*/
2672 case set_tex_shape_cmd
:
2674 scan_optional_equals
();
2680 p
= new_node
(shape_node
, 2 * (n
+ 1) + 1);
2682 for
(j
= 1; j
<= n
; j
++) {
2683 scan_normal_dimen
();
2684 varmem
[p
+ 2 * j
].cint
= cur_val
; /* indentation
*/
2685 scan_normal_dimen
();
2686 varmem
[p
+ 2 * j
+ 1].cint
= cur_val
; /* width
*/
2689 define
(q
, shape_ref_cmd
, p
);
2691 case set_etex_shape_cmd
:
2693 scan_optional_equals
();
2699 n
= (cur_val
/ 2) + 1;
2700 p
= new_node
(shape_node
, 2 * n
+ 1 + 1);
2703 varmem
[p
+ 2].cint
= n
; /* number of penalties
*/
2704 for
(j
= p
+ 3; j
<= p
+ n
+ 2; j
++) {
2706 varmem
[j
].cint
= cur_val
; /* penalty values
*/
2709 varmem
[p
+ n
+ 3].cint
= 0; /* unused
*/
2711 define
(q
, shape_ref_cmd
, p
);
2714 /* All of \TeX's parameters are kept in |eqtb| except the font information
,
2715 the interaction mode
, and the hyphenation tables
; these are strictly global.
2719 new_hyph_exceptions
();
2725 new_pre_hyphen_char
();
2728 new_post_hyphen_char
();
2731 new_pre_exhyphen_char
();
2734 new_post_exhyphen_char
();
2737 new_hyphenation_min
();
2744 case assign_font_dimen_cmd
:
2747 case assign_font_int_cmd
:
2751 if
(n
== no_lig_code
) {
2752 set_no_ligatures
(f
);
2753 } else if
(n
< lp_code_base
) {
2754 scan_optional_equals
();
2757 set_hyphen_char
(f
, cur_val
);
2759 set_skew_char
(f
, cur_val
);
2763 scan_optional_equals
();
2767 set_lp_code
(f
, p
, cur_val
);
2770 set_rp_code
(f
, p
, cur_val
);
2773 set_ef_code
(f
, p
, cur_val
);
2776 set_tag_code
(f
, p
, cur_val
);
2782 /* Here is where the information for a new font gets loaded.
*/
2783 tex_def_font
((small_number
) a
);
2785 case letterspace_font_cmd
:
2786 new_letterspaced_font
((small_number
) a
);
2789 make_font_copy
((small_number
) a
);
2791 case set_font_id_cmd
:
2793 if
(is_valid_font
(cur_val
))
2794 zset_cur_font
(cur_val
);
2796 case set_interaction_cmd
:
2800 confusion
("prefix");
2802 } /* end of Assignments cases
*/
2804 /* Insert a token saved by \.
{\\afterassignment
}, if any
*/
2805 if
(after_token
!= 0) {
2806 cur_tok
= after_token
;
2813 void fixup_directions
(void
)
2815 int temp_no_whatsits
= no_local_whatsits
;
2816 int temp_no_dirs
= no_local_dirs
;
2817 int temporary_dir
= text_direction
;
2818 if
(dir_level
(text_dir_ptr
) == cur_level
) {
2819 /* DIR: Remove from |text_dir_ptr|
*/
2820 halfword text_dir_tmp
= vlink
(text_dir_ptr
);
2821 flush_node
(text_dir_ptr
);
2822 text_dir_ptr
= text_dir_tmp
;
2825 if
(abs
(mode
) == hmode
) {
2826 if
(temp_no_dirs
!= 0) {
2827 /* DIR: Add local dir node
*/
2828 tail_append
(new_dir
(text_direction
));
2829 dir_dir
(tail
) = temporary_dir
- dir_swap
;
2831 if
(temp_no_whatsits
!= 0) {
2832 /* LOCAL
: Add local paragraph node
*/
2833 tail_append
(make_local_par_node
(2));
2838 @ When a control sequence is to be defined
, by \.
{\\def
} or \.
{\\let
} or
2839 something similar
, the |get_r_token| routine will substitute a special
2840 control sequence for a token that is not redefinable.
2843 void get_r_token
(void
)
2848 } while
(cur_tok
== space_token
);
2849 if
((cur_cs
== 0) ||
(cur_cs
> eqtb_top
) ||
2850 ((cur_cs
> frozen_control_sequence
) && (cur_cs <= eqtb_size))) {
2851 print_err
("Missing control sequence inserted");
2852 help5
("Please don't say `\\def cs{...}', say `\\def\\cs{...}'.",
2853 "I've inserted an inaccessible control sequence so that your",
2854 "definition will be completed without mixing me up too badly.",
2855 "You can recover graciously from this error, if you're",
2856 "careful; see exercise 27.2 in The TeXbook.");
2859 cur_tok
= cs_token_flag
+ frozen_protection
;
2866 void assign_internal_value
(int a
, halfword p
, int val
)
2869 if
((p
>= int_base
) && (p < attribute_base)) {
2870 switch
((p
- int_base
)) {
2871 case cat_code_table_code
:
2872 if
(valid_catcode_table
(val
)) {
2873 if
(val
!= int_par
(cat_code_table_code
))
2874 word_define
(p
, val
);
2876 print_err
("Invalid \\catcode table");
2878 ("You can only switch to a \\catcode table that is initialized",
2879 "using \\savecatcodetable or \\initcatcodetable, or to table 0");
2883 case output_box_code
:
2884 if
((val
> 65535) |
(val
< 0)) {
2885 print_err
("Invalid \\outputbox");
2887 ("The value for \\outputbox has to be between 0 and 65535.");
2890 word_define
(p
, val
);
2893 case new_line_char_code
:
2895 print_err
("Invalid \\newlinechar");
2897 ("The value for \\newlinechar has to be no higher than 127.",
2898 "Your invalid assignment will be ignored.");
2901 word_define
(p
, val
);
2904 case end_line_char_code
:
2906 print_err
("Invalid \\endlinechar");
2908 ("The value for \\endlinechar has to be no higher than 127.",
2909 "Your invalid assignment will be ignored.");
2912 word_define
(p
, val
);
2917 word_define
(int_base
+ cur_lang_code
, -1);
2919 } else if
(val
> 16383) {
2920 print_err
("Invalid \\language");
2922 ("The absolute value for \\language has to be no higher than 16383.",
2923 "Your invalid assignment will be ignored.");
2926 word_define
(int_base
+ cur_lang_code
, val
);
2927 word_define
(p
, val
);
2931 word_define
(p
, val
);
2934 /* If we are defining subparagraph penalty levels while we are
2935 in hmode
, then we put out a whatsit immediately
, otherwise
2936 we leave it alone. This mechanism might not be sufficiently
2937 powerful
, and some other algorithm
, searching down the stack
,
2938 might be necessary. Good first step.
*/
2939 if
((abs
(mode
) == hmode
) &&
2940 ((p
== (int_base
+ local_inter_line_penalty_code
)) ||
2941 (p
== (int_base
+ local_broken_penalty_code
)))) {
2942 /* LOCAL
: Add local paragraph node
*/
2943 tail_append
(make_local_par_node
(3));
2945 eq_word_define
(int_base
+ no_local_whatsits_code
,
2946 no_local_whatsits
+ 1);
2948 } else if
((p
>= dimen_base
) && (p <= eqtb_size)) {
2949 if
(p
== (dimen_base
+ page_left_offset_code
)) {
2950 n
= val
- one_true_inch
;
2951 word_define
(dimen_base
+ h_offset_code
, n
);
2952 } else if
(p
== (dimen_base
+ h_offset_code
)) {
2953 n
= val
+ one_true_inch
;
2954 word_define
(dimen_base
+ page_left_offset_code
, n
);
2955 } else if
(p
== (dimen_base
+ page_top_offset_code
)) {
2956 n
= val
- one_true_inch
;
2957 word_define
(dimen_base
+ v_offset_code
, n
);
2958 } else if
(p
== (dimen_base
+ v_offset_code
)) {
2959 n
= val
+ one_true_inch
;
2960 word_define
(dimen_base
+ page_top_offset_code
, n
);
2962 word_define
(p
, val
);
2963 } else if
((p
>= local_base
) && (p < toks_base)) { /* internal locals */
2964 define
(p
, call_cmd
, val
);
2966 confusion
("assign internal value");
2970 @ We use the fact that |register
<advance
<multiply
<divide|
2972 Compute the register location |l| and its type |p|
; but |return| if invalid
2973 Here we use the fact that the consecutive codes |int_val..mu_val| and
2974 |assign_int..assign_mu_glue| correspond to each other nicely.
2977 void do_register_command
(int a
)
2980 halfword q
= cur_cmd
;
2982 if
(q
!= register_cmd
) {
2984 if
((cur_cmd
>= assign_int_cmd
) && (cur_cmd <= assign_mu_glue_cmd)) {
2986 p
= cur_cmd
- assign_int_cmd
;
2989 if
(cur_cmd
!= register_cmd
) {
2990 print_err
("You can't use `");
2991 print_cmd_chr
((quarterword
) cur_cmd
, cur_chr
);
2993 print_cmd_chr
((quarterword
) q
, 0);
2994 help1
("I'm forgetting what you said and not changing anything.");
3000 scan_register_num
();
3001 if
(p
== int_val_level
)
3002 l
= cur_val
+ count_base
;
3003 else if
(p
== attr_val_level
)
3004 l
= cur_val
+ attribute_base
;
3005 else if
(p
== dimen_val_level
)
3006 l
= cur_val
+ scaled_base
;
3007 else if
(p
== glue_val_level
)
3008 l
= cur_val
+ skip_base
;
3009 else if
(p
== mu_val_level
)
3010 l
= cur_val
+ mu_skip_base
;
3012 if
(q
== register_cmd
) {
3013 scan_optional_equals
();
3014 } else if
(scan_keyword
("by")) {
3015 /* optional `\.
{by
}'
*/
3017 arith_error
= false
;
3018 if
(q
< multiply_cmd
) {
3019 /* Compute result of |register| or |advance|
, put it in |cur_val|
*/
3020 if
(p
< glue_val_level
) {
3021 if
((p
== int_val_level
) ||
(p
== attr_val_level
))
3024 scan_normal_dimen
();
3025 if
(q
== advance_cmd
)
3026 cur_val
= cur_val
+ eqtb
[l
].cint
;
3028 /* we can probably save a copy
*/
3030 if
(q
== advance_cmd
) {
3031 /* Compute the sum of two glue specs
*/
3032 halfword r
= equiv
(l
);
3033 q
= new_spec
(cur_val
);
3034 flush_node
(cur_val
);
3035 width
(q
) = width
(q
) + width
(r
);
3036 if
(stretch
(q
) == 0) {
3037 stretch_order
(q
) = normal
;
3039 if
(stretch_order
(q
) == stretch_order
(r
)) {
3040 stretch
(q
) = stretch
(q
) + stretch
(r
);
3041 } else if
((stretch_order
(q
) < stretch_order
(r
)) && (stretch(r) != 0)) {
3042 stretch
(q
) = stretch
(r
);
3043 stretch_order
(q
) = stretch_order
(r
);
3045 if
(shrink
(q
) == 0) {
3046 shrink_order
(q
) = normal
;
3048 if
(shrink_order
(q
) == shrink_order
(r
)) {
3049 shrink
(q
) = shrink
(q
) + shrink
(r
);
3050 } else if
((shrink_order
(q
) < shrink_order
(r
)) && (shrink(r) != 0)) {
3051 shrink
(q
) = shrink
(r
);
3052 shrink_order
(q
) = shrink_order
(r
);
3058 /* Compute result of |multiply| or |divide|
, put it in |cur_val|
*/
3060 if
(p
< glue_val_level
) {
3061 if
(q
== multiply_cmd
) {
3062 if
((p
== int_val_level
) ||
(p
== attr_val_level
)) {
3063 cur_val
= mult_integers
(eqtb
[l
].cint
, cur_val
);
3065 cur_val
= nx_plus_y
(eqtb
[l
].cint
, cur_val
, 0);
3068 cur_val
= x_over_n
(eqtb
[l
].cint
, cur_val
);
3071 halfword s
= equiv
(l
);
3072 halfword r
= new_spec
(s
);
3073 if
(q
== multiply_cmd
) {
3074 width
(r
) = nx_plus_y
(width
(s
), cur_val
, 0);
3075 stretch
(r
) = nx_plus_y
(stretch
(s
), cur_val
, 0);
3076 shrink
(r
) = nx_plus_y
(shrink
(s
), cur_val
, 0);
3078 width
(r
) = x_over_n
(width
(s
), cur_val
);
3079 stretch
(r
) = x_over_n
(stretch
(s
), cur_val
);
3080 shrink
(r
) = x_over_n
(shrink
(s
), cur_val
);
3086 print_err
("Arithmetic overflow");
3087 help2
("I can't carry out that multiplication or division,",
3088 "since the result is out of range.");
3089 if
(p
>= glue_val_level
)
3090 flush_node
(cur_val
);
3094 if
(p
< glue_val_level
) {
3095 if
(p
== attr_val_level
) {
3096 if
((l
- attribute_base
) > max_used_attr
)
3097 max_used_attr
= (l
- attribute_base
);
3098 attr_list_cache
= cache_disabled
;
3100 if
((p
== int_val_level
) ||
(p
== dimen_val_level
))
3101 assign_internal_value
(a
, l
, cur_val
);
3103 word_define
(l
, cur_val
);
3105 define
(l
, glue_ref_cmd
, cur_val
);
3110 void alter_aux
(void
)
3112 halfword c
; /* |hmode| or |vmode|
*/
3113 if
(cur_chr
!= abs
(mode
)) {
3114 report_illegal_case
();
3117 scan_optional_equals
();
3119 scan_normal_dimen
();
3120 prev_depth
= cur_val
;
3123 if
((cur_val
<= 0) ||
(cur_val
> 32767)) {
3124 print_err
("Bad space factor");
3125 help1
("I allow only values in the range 1..32767 here.");
3128 space_factor
= cur_val
;
3135 void alter_prev_graf
(void
)
3137 int p
; /* index into |nest|
*/
3139 while
(abs
(nest
[p
].mode_field
) != vmode
)
3141 scan_optional_equals
();
3144 print_err
("Bad \\prevgraf");
3145 help1
("I allow only nonnegative values here.");
3148 nest
[p
].pg_field
= cur_val
;
3153 void alter_page_so_far
(void
)
3155 int c
; /* index into |page_so_far|
*/
3157 scan_optional_equals
();
3158 scan_normal_dimen
();
3159 page_so_far
[c
] = cur_val
;
3163 void alter_integer
(void
)
3165 int c
; /* 0 for \.
{\\deadcycles
}, 1 for \.
{\\insertpenalties
}, etc.
*/
3167 scan_optional_equals
();
3170 dead_cycles
= cur_val
;
3171 } else if
(c
== 2) {
3172 if
((cur_val
< batch_mode
) ||
(cur_val
> error_stop_mode
)) {
3173 print_err
("Bad interaction mode");
3174 help2
("Modes are 0=batch, 1=nonstop, 2=scroll, and",
3175 "3=errorstop. Proceed, and I'll ignore this case.");
3182 insert_penalties
= cur_val
;
3187 void alter_box_dimen
(void
)
3189 int c
; /* |width_offset| or |height_offset| or |depth_offset|
*/
3190 int b
; /* box number
*/
3192 scan_register_num
();
3194 scan_optional_equals
();
3195 scan_normal_dimen
();
3197 varmem
[box
(b
) + c
].cint
= cur_val
;
3201 void new_interaction
(void
)
3204 interaction
= cur_chr
;
3205 if
(interaction
== batch_mode
)
3206 kpse_make_tex_discard_errors
= 1;
3208 kpse_make_tex_discard_errors
= 0;
3209 fixup_selector
(log_opened_global
);
3212 @ The \.
{\\afterassignment
} command puts a token into the global
3213 variable |after_token|. This global variable is examined just after
3214 every assignment has been performed.
3217 halfword after_token
; /* zero
, or a saved token
*/
3219 @ Here is a procedure that might be called `Get the next non-blank non-relax
3220 non-call non-assignment token'.
3223 void do_assignments
(void
)
3226 /* Get the next non-blank non-relax...
*/
3229 } while
((cur_cmd
== spacer_cmd
) ||
(cur_cmd
== relax_cmd
));
3230 if
(cur_cmd
<= max_non_prefixed_command
)
3232 set_box_allowed
= false
;
3234 set_box_allowed
= true
;
3239 void open_or_close_in
(void
)
3241 int c
; /* 1 for \.
{\\openin
}, 0 for \.
{\\closein
} */
3242 int n
; /* stream number
*/
3245 scan_four_bit_int
();
3247 if
(read_open
[n
] != closed
) {
3248 lua_a_close_in
(read_file
[n
], (n
+ 1));
3249 read_open
[n
] = closed
;
3252 scan_optional_equals
();
3255 } while
((cur_cmd
== spacer_cmd
) ||
(cur_cmd
== relax_cmd
));
3257 if
(cur_cmd
!= left_brace_cmd
) {
3258 scan_file_name
(); /* set |cur_name| to desired file name
*/
3259 if
(cur_ext
== get_nullstr
())
3260 cur_ext
= maketexstring
(".tex");
3262 scan_file_name_toks
();
3264 fn
= pack_file_name
(cur_name
, cur_area
, cur_ext
);
3265 if
(lua_a_open_in
(&(read_file[n]), fn, (n + 1))) {
3266 read_open
[n
] = just_open
;
3272 boolean long_help_seen
; /* has the long \.
{\\errmessage
} help been used?
*/
3274 void issue_message
(void
)
3276 int old_setting
; /* holds |selector| setting
*/
3277 int c
; /* identifies \.
{\\message
} and \.
{\\errmessage
} */
3278 str_number s
; /* the message
*/
3280 (void
) scan_toks
(false
, true
);
3281 old_setting
= selector
;
3282 selector
= new_string
;
3283 token_show
(def_ref
);
3284 selector
= old_setting
;
3285 flush_list
(def_ref
);
3289 /* Print string |s| on the terminal
*/
3290 if
(term_offset
+ (int
) str_length
(s
) > max_print_line
- 2)
3292 else if
((term_offset
> 0) ||
(file_offset
> 0))
3298 /* Print string |s| as an error message
*/
3299 /* If \.
{\\errmessage
} occurs often in |scroll_mode|
, without user-defined
3300 \.
{\\errhelp
}, we don't want to give a long help message each time. So we
3301 give a verbose explanation only once.
*/
3304 if
(err_help
!= null
) {
3305 use_err_help
= true
;
3306 } else if
(long_help_seen
) {
3307 help1
("(That was another \\errmessage.)");
3309 if
(interaction
< error_stop_mode
)
3310 long_help_seen
= true
;
3311 help4
("This error message was generated by an \\errmessage",
3312 "command, so I can't give any explicit help.",
3313 "Pretend that you're Hercule Poirot: Examine all clues,",
3314 "and deduce the truth by order and method.");
3317 use_err_help
= false
;
3323 @ The |error| routine calls on |give_err_help| if help is requested from
3324 the |err_help| parameter.
3327 void give_err_help
(void
)
3329 token_show
(err_help
);
3332 @ The \.
{\\uppercase
} and \.
{\\lowercase
} commands are implemented by
3333 building a token list and then changing the cases of the letters in it.
3336 void shift_case
(void
)
3338 halfword b
; /* |lc_code_base| or |uc_code_base|
*/
3339 halfword p
; /* runs through the token list
*/
3340 halfword t
; /* token
*/
3341 halfword c
; /* character code
*/
3342 halfword i
; /* inbetween
*/
3344 p
= scan_toks
(false
, false
);
3345 p
= token_link
(def_ref
);
3347 /* Change the case of the token in |p|
, if a change is appropriate
*/
3349 When the case of a |chr_code| changes
, we don't change the |cmd|.
3350 We also change active characters.
3353 if
(t
< cs_token_flag
) {
3354 c
= t
% STRING_OFFSET
;
3355 if
(b
== uc_code_base
)
3360 set_token_info
(p
, t
- c
+ i
);
3361 } else if
(is_active_cs
(cs_text
(t
- cs_token_flag
))) {
3362 c
= active_cs_value
(cs_text
(t
- cs_token_flag
));
3363 if
(b
== uc_code_base
)
3368 set_token_info
(p
, active_to_cs
(i
, true
) + cs_token_flag
);
3372 back_list
(token_link
(def_ref
));
3373 free_avail
(def_ref
); /* omit reference count
*/
3376 @ We come finally to the last pieces missing from |main_control|
, namely the
3377 `\.
{\\show
}' commands that are useful when debugging.
3380 void show_whatever
(void
)
3382 halfword p
; /* tail of a token list to show
*/
3383 int t
; /* type of conditional being shown
*/
3384 int m
; /* upper bound on |fi_or_else| codes
*/
3385 int l
; /* line where that conditional began
*/
3386 int n
; /* level of \.
{\\if...\\fi
} nesting
*/
3393 /* Show the current contents of a box
*/
3394 scan_register_num
();
3396 tprint_nl
("> \\box");
3399 if
(box
(cur_val
) == null
)
3402 show_box
(box
(cur_val
));
3405 /* Show the current meaning of a token
, then |goto common_ending|
*/
3407 if
(interaction
== error_stop_mode
)
3417 /* Cases for |show_whatever|
*/
3426 if
(cond_ptr
== null
) {
3428 tprint
("no active conditionals");
3435 } while
(p
!= null
);
3441 tprint_nl
("### level ");
3444 print_cmd_chr
(if_test_cmd
, t
);
3449 t
= if_limit_subtype
(p
);
3450 l
= if_line_field
(p
);
3451 m
= if_limit_type
(p
);
3453 } while
(p
!= null
);
3457 /* Show the current value of some parameter or register
,
3458 then |goto common_ending|
*/
3460 if
(interaction
== error_stop_mode
)
3463 token_show
(temp_token_head
);
3464 flush_list
(token_link
(temp_token_head
));
3468 /* Complete a potentially long \.
{\\show
} command
*/
3469 end_diagnostic
(true
);
3471 if
(selector
== term_and_log
) {
3472 if
(tracing_online
<= 0) {
3473 selector
= term_only
;
3474 tprint
(" (see the transcript file)");
3475 selector
= term_and_log
;
3479 if
(interaction
< error_stop_mode
) {
3482 } else if
(tracing_online
> 0) {
3483 help3
("This isn't an error message; I'm just \\showing something.",
3484 "Type `I\\show...' to show more (e.g., \\show\\cs,",
3485 "\\showthe\\count10, \\showbox255, \\showlists).");
3487 help5
("This isn't an error message; I'm just \\showing something.",
3488 "Type `I\\show...' to show more (e.g., \\show\\cs,",
3489 "\\showthe\\count10, \\showbox255, \\showlists).",
3490 "And type `I\\tracingonline=1\\show...' to show boxes and",
3491 "lists on your terminal as well as in the transcript file.");
3497 void initialize
(void
)
3498 { /* this procedure gets things started properly
*/
3499 int k
; /* index into |mem|
, |eqtb|
, etc.
*/
3500 /* Initialize whatever \TeX\ might access
*/
3501 /* Set initial values of key variables
*/
3502 initialize_errors
();
3503 initialize_arithmetic
();
3505 attr_list_cache
= cache_disabled
;
3506 initialize_nesting
();
3508 /* Start a new current page
*/
3509 page_contents
= empty
;
3510 page_tail
= page_head
;
3512 vlink
(page_head
) = null
;
3514 last_glue
= max_halfword
;
3517 last_node_type
= -1;
3521 initialize_equivalents
();
3522 no_new_control_sequence
= true
; /* new identifiers are usually forbidden
*/
3529 static_pdf
= init_pdf_struct
(static_pdf
); /* should be init_backend
() */
3532 format_name
= get_nullstr
();
3533 initialize_directions
();
3534 initialize_write_files
();
3535 seconds_and_micros
(epochseconds
, microseconds
);
3536 init_start_time
(static_pdf
);
3538 edit_name_start
= 0;
3539 stop_at_space
= true
;
3542 /* Initialize table entries
(done by \.
{INITEX
} only
) */
3545 initialize_tokens
();
3546 /* Initialize the special list heads and constant nodes
*/
3547 initialize_alignments
();
3548 initialize_buildpage
();
3550 initialize_active
();
3552 set_eq_type
(undefined_control_sequence
, undefined_cs_cmd
);
3553 set_equiv
(undefined_control_sequence
, null
);
3554 set_eq_level
(undefined_control_sequence
, level_zero
);
3555 for
(k
= null_cs
; k
<= (eqtb_top
- 1); k
++)
3556 eqtb
[k
] = eqtb
[undefined_control_sequence
];
3557 set_equiv
(glue_base
, zero_glue
);
3558 set_eq_level
(glue_base
, level_one
);
3559 set_eq_type
(glue_base
, glue_ref_cmd
);
3560 for
(k
= glue_base
+ 1; k
<= local_base
- 1; k
++) {
3561 eqtb
[k
] = eqtb
[glue_base
];
3563 par_shape_ptr
= null
;
3564 set_eq_type
(par_shape_loc
, shape_ref_cmd
);
3565 set_eq_level
(par_shape_loc
, level_one
);
3566 for
(k
= etex_pen_base
; k
<= (etex_pens
- 1); k
++)
3567 eqtb
[k
] = eqtb
[par_shape_loc
];
3568 for
(k
= output_routine_loc
; k
<= toks_base
+ biggest_reg
; k
++)
3569 eqtb
[k
] = eqtb
[undefined_control_sequence
];
3571 set_eq_type
(box_base
, box_ref_cmd
);
3572 set_eq_level
(box_base
, level_one
);
3573 for
(k
= box_base
+ 1; k
<= (box_base
+ biggest_reg
); k
++)
3574 eqtb
[k
] = eqtb
[box_base
];
3575 cur_font
= null_font
;
3576 set_eq_type
(cur_font_loc
, data_cmd
);
3577 set_eq_level
(cur_font_loc
, level_one
);
3578 set_equiv
(cat_code_base
, 0);
3579 set_eq_type
(cat_code_base
, data_cmd
);
3580 set_eq_level
(cat_code_base
, level_one
);
3581 eqtb
[internal_math_param_base
] = eqtb
[cat_code_base
];
3582 eqtb
[lc_code_base
] = eqtb
[cat_code_base
];
3583 eqtb
[uc_code_base
] = eqtb
[cat_code_base
];
3584 eqtb
[sf_code_base
] = eqtb
[cat_code_base
];
3585 eqtb
[math_code_base
] = eqtb
[cat_code_base
];
3587 initialize_math_codes
();
3588 initialize_text_codes
();
3589 initex_cat_codes
(0);
3590 for
(k
= '
0'
; k
<= '
9'
; k
++)
3591 set_math_code
(k
, var_code
, 0, k
, level_one
);
3592 for
(k
= 'A'
; k
<= 'Z'
; k
++) {
3593 set_math_code
(k
, var_code
, 1, k
, level_one
);
3594 set_math_code
((k
+ 32), var_code
, 1, (k
+ 32), level_one
);
3595 set_lc_code
(k
, k
+ 32, level_one
);
3596 set_lc_code
(k
+ 32, k
+ 32, level_one
);
3597 set_uc_code
(k
, k
, level_one
);
3598 set_uc_code
(k
+ 32, k
, level_one
);
3599 set_sf_code
(k
, 999, level_one
);
3601 for
(k
= int_base
; k
<= attribute_base
- 1; k
++)
3603 for
(k
= attribute_base
; k
<= del_code_base
- 1; k
++)
3604 eqtb
[k
].cint
= UNUSED_ATTRIBUTE
;
3608 max_dead_cycles
= 25;
3610 end_line_char
= carriage_return
;
3611 set_del_code
('.'
, 0, 0, 0, 0, level_one
); /* this null delimiter is used in error recovery
*/
3612 ex_hyphen_char
= '
-'
;
3614 for
(k
= dimen_base
; k
<= eqtb_size
; k
++)
3616 page_left_offset
= one_inch
;
3617 page_top_offset
= one_inch
;
3618 page_right_offset
= one_inch
;
3619 page_bottom_offset
= one_inch
;
3620 ini_init_primitives
();
3621 hash_used
= frozen_control_sequence
; /* nothing is used
*/
3624 set_eq_type
(frozen_dont_expand
, dont_expand_cmd
);
3625 cs_text
(frozen_dont_expand
) = maketexstring
("notexpanded:");
3626 set_eq_type
(frozen_primitive
, ignore_spaces_cmd
);
3627 set_equiv
(frozen_primitive
, 1);
3628 set_eq_level
(frozen_primitive
, level_one
);
3629 cs_text
(frozen_primitive
) = maketexstring
("primitive");
3633 math_eqno_gap_step
= 1000 ;
3634 cs_text
(frozen_protection
) = maketexstring
("inaccessible");
3635 format_ident
= maketexstring
(" (INITEX)");
3636 cs_text
(end_write
) = maketexstring
("endwrite");
3637 set_eq_level
(end_write
, level_one
);
3638 set_eq_type
(end_write
, outer_call_cmd
);
3639 set_equiv
(end_write
, null
);
3642 synctexoffset
= int_base
+ synctex_code
;