a patch for an off-by-one error when print on terminal
[luatex.git] / source / texk / web2c / luatexdir / tex / printing.w
blob8dc24f320f2521e16bccf93954217b5563e0dbe9
1 % printing.w
3 % Copyright 2009-2013 Taco Hoekwater <taco@@luatex.org>
5 % This file is part of LuaTeX.
7 % LuaTeX is free software; you can redistribute it and/or modify it under
8 % the terms of the GNU General Public License as published by the Free
9 % Software Foundation; either version 2 of the License, or (at your
10 % option) any later version.
12 % LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13 % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 % FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 % License for more details.
17 % You should have received a copy of the GNU General Public License along
18 % with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
20 @ @c
23 #include "ptexlib.h"
24 #include "lua/luatex-api.h" /* for luatex_banner */
26 @ @c
27 #define font_id_text(A) cs_text(font_id_base+(A))
29 #define wlog(A) fputc(A,log_file)
30 #define wterm(A) fputc(A,term_out)
33 @ Messages that are sent to a user's terminal and to the transcript-log file
34 are produced by several `|print|' procedures. These procedures will
35 direct their output to a variety of places, based on the setting of
36 the global variable |selector|, which has the following possible
37 values:
39 \yskip
40 \hang |term_and_log|, the normal setting, prints on the terminal and on the
41 transcript file.
43 \hang |log_only|, prints only on the transcript file.
45 \hang |term_only|, prints only on the terminal.
47 \hang |no_print|, doesn't print at all. This is used only in rare cases
48 before the transcript file is open.
50 \hang |pseudo|, puts output into a cyclic buffer that is used
51 by the |show_context| routine; when we get to that routine we shall discuss
52 the reasoning behind this curious mode.
54 \hang |new_string|, appends the output to the current string in the
55 string pool.
57 \hang 0 to 15, prints on one of the sixteen files for \.{\\write} output.
59 \yskip
60 \noindent The symbolic names `|term_and_log|', etc., have been assigned
61 numeric codes that satisfy the convenient relations |no_print+1=term_only|,
62 |no_print+2=log_only|, |term_only+2=log_only+1=term_and_log|.
64 Three additional global variables, |tally| and |term_offset| and
65 |file_offset|, record the number of characters that have been printed
66 since they were most recently cleared to zero. We use |tally| to record
67 the length of (possibly very long) stretches of printing; |term_offset|
68 and |file_offset|, on the other hand, keep track of how many characters
69 have appeared so far on the current line that has been output to the
70 terminal or to the transcript file, respectively.
73 alpha_file log_file; /* transcript of \TeX\ session */
74 int selector = term_only; /* where to print a message */
75 int dig[23]; /* digits in a number being output */
76 int tally = 0; /* the number of characters recently printed */
77 int term_offset = 0; /* the number of characters on the current terminal line */
78 int file_offset = 0; /* the number of characters on the current file line */
79 packed_ASCII_code trick_buf[(ssup_error_line + 1)]; /* circular buffer for pseudoprinting */
80 int trick_count; /* threshold for pseudoprinting, explained later */
81 int first_count; /* another variable for pseudoprinting */
82 boolean inhibit_par_tokens = false; /* for minor adjustments to |show_token_list| */
84 @ To end a line of text output, we call |print_ln|
86 void print_ln(void)
87 { /* prints an end-of-line */
88 switch (selector) {
89 case term_and_log:
90 wterm_cr();
91 wlog_cr();
92 term_offset = 0;
93 file_offset = 0;
94 break;
95 case log_only:
96 wlog_cr();
97 file_offset = 0;
98 break;
99 case term_only:
100 wterm_cr();
101 term_offset = 0;
102 break;
103 case no_print:
104 case pseudo:
105 case new_string:
106 break;
107 default:
108 fprintf(write_file[selector], "\n");
109 break;
111 } /* |tally| is not affected */
114 @ The |print_char| procedure sends one byte to the desired destination.
115 All printing comes through |print_ln| or |print_char|, except for the
116 case of |tprint| (see below).
119 #define wterm_char(A) do { \
120 if ((A>=0x20)||(A==0x0A)||(A==0x0D)||(A==0x09)) { \
121 wterm(A); \
122 } else { \
123 if (term_offset+2>=max_print_line) { \
124 wterm_cr(); term_offset=0; \
126 incr(term_offset); wterm('^'); \
127 incr(term_offset); wterm('^'); \
128 wterm(A+64); \
130 } while (0)
132 #define needs_wrapping(A,B) \
133 (((A>=0xF0)&&(B+4>=max_print_line))|| \
134 ((A>=0xE0)&&(B+3>=max_print_line))|| \
135 ((A>=0xC0)&&(B+2>=max_print_line)))
137 #define fix_term_offset(A) do { \
138 if (needs_wrapping(A,term_offset)){ \
139 wterm_cr(); term_offset=0; \
141 } while (0)
143 #define fix_log_offset(A) do { \
144 if (needs_wrapping(A,file_offset)){ \
145 wlog_cr(); file_offset=0; \
147 } while (0)
149 void print_char(int s)
150 { /* prints a single byte */
151 assert(s >= 0 && s < 256);
152 if (s == int_par(new_line_char_code)) {
153 if (selector < pseudo) {
154 print_ln();
155 return;
158 switch (selector) {
159 case term_and_log:
160 fix_term_offset(s);
161 fix_log_offset(s);
162 wterm_char(s);
163 wlog(s);
164 incr(term_offset);
165 incr(file_offset);
166 if (term_offset == max_print_line) {
167 wterm_cr();
168 term_offset = 0;
170 if (file_offset == max_print_line) {
171 wlog_cr();
172 file_offset = 0;
174 break;
175 case log_only:
176 fix_log_offset(s);
177 wlog(s);
178 incr(file_offset);
179 if (file_offset == max_print_line) {
180 wlog_cr();
181 file_offset = 0;
183 break;
184 case term_only:
185 fix_term_offset(s);
186 wterm_char(s);
187 incr(term_offset);
188 if (term_offset == max_print_line) {
189 wterm_cr();
190 term_offset = 0;
192 break;
193 case no_print:
194 break;
195 case pseudo:
196 if (tally < trick_count)
197 trick_buf[tally % error_line] = (packed_ASCII_code) s;
198 break;
199 case new_string:
200 append_char(s);
201 break; /* we drop characters if the string space is full */
202 default:
203 fprintf(write_file[selector], "%c", s);
205 incr(tally);
209 @ An entire string is output by calling |print|. Note that if we are outputting
210 the single standard ASCII character \.c, we could call |print("c")|, since
211 |"c"=99| is the number of a single-character string, as explained above. But
212 |print_char("c")| is quicker, so \TeX\ goes directly to the |print_char|
213 routine when it knows that this is safe. (The present implementation
214 assumes that it is always safe to print a visible ASCII character.)
215 @^system dependencies@>
217 The first 256 entries above the 17th unicode plane are used for a
218 special trick: when \TeX\ has to print items in that range, it will
219 instead print the character that results from substracting 0x110000
220 from that value. This allows byte-oriented output to things like
221 \.{\\specials} and \.{\\pdfliterals}. Todo: Perhaps it would be useful
222 to do the same substraction while typesetting.
225 void print(int s)
226 { /* prints string |s| */
227 if (s >= str_ptr) {
228 /* this can't happen */
229 print_char('?');
230 print_char('?');
231 print_char('?');
232 return;
233 } else if (s < STRING_OFFSET) {
234 if (s < 0) {
235 /* can't happen */
236 print_char('?');
237 print_char('?');
238 print_char('?');
239 } else {
240 /* TH not sure about this, disabled for now! */
241 if ((false) && (selector > pseudo)) {
242 print_char(s);
243 return; /* internal strings are not expanded */
245 if (s == int_par(new_line_char_code)) {
246 if (selector < pseudo) {
247 print_ln();
248 return;
251 if (s <= 0x7F) {
252 print_char(s);
253 } else if (s <= 0x7FF) {
254 print_char(0xC0 + (s / 0x40));
255 print_char(0x80 + (s % 0x40));
256 } else if (s <= 0xFFFF) {
257 print_char(0xE0 + (s / 0x1000));
258 print_char(0x80 + ((s % 0x1000) / 0x40));
259 print_char(0x80 + ((s % 0x1000) % 0x40));
260 } else if (s >= 0x110000) {
261 int c = s - 0x110000;
262 if (c >= 256) {
263 pdf_warning("print", "bad raw byte to print (c=",
264 true, false);
265 print_int(c);
266 tprint("), skipped.");
267 print_ln();
268 } else {
269 print_char(c);
271 } else {
272 print_char(0xF0 + (s / 0x40000));
273 print_char(0x80 + ((s % 0x40000) / 0x1000));
274 print_char(0x80 + (((s % 0x40000) % 0x1000) / 0x40));
275 print_char(0x80 + (((s % 0x40000) % 0x1000) % 0x40));
278 return;
280 if (selector == new_string) {
281 append_string(str_string(s), (unsigned) str_length(s));
282 return;
284 lprint(&str_lstring(s));
287 void lprint (lstring *ss) {
288 unsigned char *j, *l; /* current character code position */
289 j = ss->s;
290 l = j + ss->l;
291 while (j < l) {
292 /* 0x110000 in utf=8: 0xF4 0x90 0x80 0x80 */
293 /* I don't bother checking the last two bytes explicitly */
294 if ((j < l - 4) && (*j == 0xF4) && (*(j + 1) == 0x90)) {
295 int c = (*(j + 2) - 128) * 64 + (*(j + 3) - 128);
296 assert(c >= 0 && c < 256);
297 print_char(c);
298 j = j + 4;
299 } else {
300 print_char(*j);
301 incr(j);
306 @ The procedure |print_nl| is like |print|, but it makes sure that the
307 string appears at the beginning of a new line.
310 void print_nlp(void)
311 { /* move to beginning of a line */
312 if (((term_offset > 0) && (odd(selector))) ||
313 ((file_offset > 0) && (selector >= log_only)))
314 print_ln();
317 void print_nl(str_number s)
318 { /* prints string |s| at beginning of line */
319 print_nlp();
320 print(s);
323 @ |char *| versions of the same procedures. |tprint| is
324 different because it uses buffering, which works well because
325 most of the output actually comes through |tprint|.
328 void tprint(const char *sss)
330 char *buffer = NULL;
331 int i = 0; /* buffer index */
332 int newlinechar = int_par(new_line_char_code);
333 int dolog = 0;
334 int doterm = 0;
335 switch (selector) {
336 case new_string:
337 append_string((const unsigned char *)sss, (unsigned) strlen(sss));
338 return;
339 break;
340 case pseudo:
341 while (*sss) {
342 if (tally < trick_count) {
343 trick_buf[tally % error_line] = (packed_ASCII_code) *sss++;
344 tally++;
345 } else {
346 return;
349 return;
350 break;
351 case no_print:
352 return;
353 break;
354 case term_and_log:
355 dolog = 1;
356 doterm = 1;
357 break;
358 case log_only:
359 dolog = 1;
360 break;
361 case term_only:
362 doterm = 1;
363 break;
364 default:
366 char *newstr = xstrdup(sss);
367 char *s;
368 for (s=newstr;*s;s++) {
369 if (*s == newlinechar) {
370 *s = '\n';
373 fputs(newstr, write_file[selector]);
374 free(newstr);
375 return;
377 break;
379 /* what is left is the 3 term/log settings */
380 buffer = xmalloc(strlen(sss)*3);
381 if (dolog) {
382 const unsigned char *ss = (const unsigned char *) sss;
383 while (*ss) {
384 int s = *ss++;
385 if (needs_wrapping(s,file_offset) || s == newlinechar) {
386 buffer[i++] = '\n';
387 buffer[i++] = '\0';
388 fputs(buffer, log_file);
389 i = 0; buffer[0] = '\0';
390 file_offset=0;
392 if (s != newlinechar) {
393 buffer[i++] = s;
394 if (file_offset++ == max_print_line) {
395 buffer[i++] = '\n';
396 buffer[i++] = '\0';
397 fputs(buffer, log_file);
398 i = 0; buffer[0] = '\0';
399 file_offset = 0;
403 if (*buffer) {
404 buffer[i++] = '\0';
405 fputs(buffer, log_file);
406 buffer[0] = '\0';
408 i = 0;
410 if (doterm) {
411 const unsigned char *ss = (const unsigned char *) sss;
412 while (*ss) {
413 int s = *ss++;
414 if (needs_wrapping(s,term_offset) || s == newlinechar) {
415 buffer[i++] = '\n';
416 buffer[i++] = '\0';
417 fputs(buffer, term_out);
418 i = 0; buffer[0] = '\0';
419 term_offset=0;
421 if (s != newlinechar) {
422 if ((s>=0x20)||(s==0x0A)||(s==0x0D)||(s==0x09)) {
423 buffer[i++] = s;
424 } else {
425 buffer[i++] = '^';
426 buffer[i++] = '^';
427 buffer[i++] = s+64;
428 term_offset += 2;
430 if (++term_offset == max_print_line) {
431 buffer[i++] = '\n';
432 buffer[i++] = '\0';
433 fputs(buffer, term_out);
434 i = 0; buffer[0] = '\0';
435 term_offset = 0;
439 if (*buffer) {
440 buffer[i++] = '\0';
441 fputs(buffer, term_out);
444 free(buffer);
447 void tprint_nl(const char *s)
449 print_nlp();
450 tprint(s);
453 @ Here is the very first thing that \TeX\ prints: a headline that identifies
454 the version number and format package. The |term_offset| variable is temporarily
455 incorrect, but the discrepancy is not serious since we assume that the banner
456 and format identifier together will occupy at most |max_print_line|
457 character positions.
460 void print_banner(const char *v, int ver)
462 int callback_id;
463 callback_id = callback_defined(start_run_callback);
464 if (callback_id == 0) {
465 if (ver < 0)
466 fprintf(term_out, "This is " MyName ", Version %s ", v);
467 else
468 fprintf(term_out, "This is " MyName ", Version %s%s (rev %d) ", v,
469 WEB2CVERSION, ver);
470 if (format_ident > 0)
471 print(format_ident);
472 print_ln();
473 if (show_luahashchars){
474 wterm(' ');
475 fprintf(term_out,"Number of bits used by the hash function (" my_name "): %d",LUAI_HASHLIMIT);
476 print_ln();
478 if (shellenabledp) {
479 wterm(' ');
480 if (restrictedshell)
481 fprintf(term_out, "restricted ");
482 fprintf(term_out, "\\write18 enabled.\n");
484 } else if (callback_id > 0) {
485 run_callback(callback_id, "->");
489 @ @c
490 void log_banner(const char *v, int ver)
492 const char *months[] = { " ",
493 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
494 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
496 unsigned month = (unsigned) int_par(month_code);
497 if (month > 12)
498 month = 0;
499 if (ver < 0)
500 fprintf(log_file, "This is " MyName ", Version %s ", v);
501 else
502 fprintf(log_file, "This is " MyName ", Version %s%s (rev %d) ", v,
503 WEB2CVERSION, ver);
504 print(format_ident);
505 print_char(' ');
506 print_char(' ');
507 print_int(int_par(day_code));
508 print_char(' ');
509 fprintf(log_file, "%s", months[month]);
510 print_char(' ');
511 print_int(int_par(year_code));
512 print_char(' ');
513 print_two(int_par(time_code) / 60);
514 print_char(':');
515 print_two(int_par(time_code) % 60);
516 if (shellenabledp) {
517 wlog_cr();
518 wlog(' ');
519 if (restrictedshell)
520 fprintf(log_file, "restricted ");
521 fprintf(log_file, "\\write18 enabled.");
523 if (filelineerrorstylep) {
524 wlog_cr();
525 fprintf(log_file, " file:line:error style messages enabled.");
527 if (parsefirstlinep) {
528 wlog_cr();
529 fprintf(log_file, " %%&-line parsing enabled.");
533 @ @c
534 void print_version_banner(void)
536 fprintf(term_out, "%s", luatex_banner);
539 @ The procedure |print_esc| prints a string that is preceded by
540 the user's escape character (which is usually a backslash).
543 void print_esc(str_number s)
544 { /* prints escape character, then |s| */
545 int c; /* the escape character code */
546 /* Set variable |c| to the current escape character */
547 c = int_par(escape_char_code);
548 if (c >= 0 && c < STRING_OFFSET)
549 print(c);
550 print(s);
553 @ @c
554 void tprint_esc(const char *s)
555 { /* prints escape character, then |s| */
556 int c; /* the escape character code */
557 /* Set variable |c| to the current escape character */
558 c = int_par(escape_char_code);
559 if (c >= 0 && c < STRING_OFFSET)
560 print(c);
561 tprint(s);
564 @ An array of digits in the range |0..15| is printed by |print_the_digs|.
567 void print_the_digs(eight_bits k)
569 /* prints |dig[k-1]|$\,\ldots\,$|dig[0]| */
570 while (k-- > 0) {
571 if (dig[k] < 10)
572 print_char('0' + dig[k]);
573 else
574 print_char('A' - 10 + dig[k]);
578 @ The following procedure, which prints out the decimal representation of a
579 given integer |n|, has been written carefully so that it works properly
580 if |n=0| or if |(-n)| would cause overflow. It does not apply |mod| or |div|
581 to negative arguments, since such operations are not implemented consistently
582 by all PASCAL compilers.
585 void print_int(longinteger n)
586 { /* prints an integer in decimal form */
587 int k; /* index to current digit; we assume that $|n|<10^{23}$ */
588 longinteger m; /* used to negate |n| in possibly dangerous cases */
589 k = 0;
590 if (n < 0) {
591 print_char('-');
592 if (n > -100000000) {
593 n = -n;
594 } else {
595 m = -1 - n;
596 n = m / 10;
597 m = (m % 10) + 1;
598 k = 1;
599 if (m < 10)
600 dig[0] = (int) m;
601 else {
602 dig[0] = 0;
603 incr(n);
607 do {
608 dig[k] = (int) (n % 10);
609 n = n / 10;
610 incr(k);
611 } while (n != 0);
612 print_the_digs((eight_bits) k);
616 @ Here is a trivial procedure to print two digits; it is usually called with
617 a parameter in the range |0<=n<=99|.
620 void print_two(int n)
621 { /* prints two least significant digits */
622 n = abs(n) % 100;
623 print_char('0' + (n / 10));
624 print_char('0' + (n % 10));
628 @ Hexadecimal printing of nonnegative integers is accomplished by |print_hex|.
631 void print_hex(int n)
632 { /* prints a positive integer in hexadecimal form */
633 int k; /* index to current digit; we assume that $0\L n<16^{22}$ */
634 k = 0;
635 print_char('"');
636 do {
637 dig[k] = n % 16;
638 n = n / 16;
639 incr(k);
640 } while (n != 0);
641 print_the_digs((eight_bits) k);
645 @ Roman numerals are produced by the |print_roman_int| routine. Readers
646 who like puzzles might enjoy trying to figure out how this tricky code
647 works; therefore no explanation will be given. Notice that 1990 yields
648 \.{mcmxc}, not \.{mxm}.
651 void print_roman_int(int n)
653 char *j, *k; /* mysterious indices */
654 int u, v; /* mysterious numbers */
655 char mystery[] = "m2d5c2l5x2v5i";
656 j = (char *) mystery;
657 v = 1000;
658 while (1) {
659 while (n >= v) {
660 print_char(*j);
661 n = n - v;
663 if (n <= 0)
664 return; /* nonpositive input produces no output */
665 k = j + 2;
666 u = v / (*(k - 1) - '0');
667 if (*(k - 1) == '2') {
668 k = k + 2;
669 u = u / (*(k - 1) - '0');
671 if (n + u >= v) {
672 print_char(*k);
673 n = n + u;
674 } else {
675 j = j + 2;
676 v = v / (*(j - 1) - '0');
682 @ The |print| subroutine will not print a string that is still being
683 created. The following procedure will.
686 void print_current_string(void)
687 { /* prints a yet-unmade string */
688 unsigned j = 0; /* points to current character code */
689 while (j < cur_length)
690 print_char(cur_string[j++]);
693 @ The procedure |print_cs| prints the name of a control sequence, given
694 a pointer to its address in |eqtb|. A space is printed after the name
695 unless it is a single nonletter or an active character. This procedure
696 might be invoked with invalid data, so it is ``extra robust.'' The
697 individual characters must be printed one at a time using |print|, since
698 they may be unprintable.
701 void print_cs(int p)
702 { /* prints a purported control sequence */
703 str_number t = cs_text(p);
704 if (p < hash_base) { /* nullcs */
705 if (p == null_cs) {
706 tprint_esc("csname");
707 tprint_esc("endcsname");
708 print_char(' ');
709 } else {
710 tprint_esc("IMPOSSIBLE.");
712 } else if ((p >= undefined_control_sequence) &&
713 ((p <= eqtb_size) || p > eqtb_size + hash_extra)) {
714 tprint_esc("IMPOSSIBLE.");
715 } else if (t >= str_ptr) {
716 tprint_esc("NONEXISTENT.");
717 } else {
718 if (is_active_cs(t)) {
719 print(active_cs_value(t));
720 } else {
721 print_esc(t);
722 if (single_letter(t)) {
723 if (get_cat_code(int_par(cat_code_table_code),
724 pool_to_unichar(str_string(t))) == letter_cmd)
725 print_char(' ');
726 } else {
727 print_char(' ');
734 @ Here is a similar procedure; it avoids the error checks, and it never
735 prints a space after the control sequence.
738 void sprint_cs(pointer p)
739 { /* prints a control sequence */
740 str_number t;
741 if (p == null_cs) {
742 tprint_esc("csname");
743 tprint_esc("endcsname");
744 } else {
745 t = cs_text(p);
746 if (is_active_cs(t))
747 print(active_cs_value(t));
748 else
749 print_esc(t);
754 @ This procedure is never called when |interaction<scroll_mode|.
756 void prompt_input(const char *s)
758 wake_up_terminal();
759 tprint(s);
760 term_input();
764 @ Then there is a subroutine that prints glue stretch and shrink, possibly
765 followed by the name of finite units:
768 void print_glue(scaled d, int order, const char *s)
769 { /* prints a glue component */
770 print_scaled(d);
771 if ((order < normal) || (order > filll)) {
772 tprint("foul");
773 } else if (order > normal) {
774 tprint("fi");
775 while (order > sfi) {
776 print_char('l');
777 decr(order);
779 } else if (s != NULL) {
780 tprint(s);
784 @ The next subroutine prints a whole glue specification
786 void print_spec(int p, const char *s)
787 { /* prints a glue specification */
788 if (p < 0) {
789 print_char('*');
790 } else {
791 print_scaled(width(p));
792 if (s != NULL)
793 tprint(s);
794 if (stretch(p) != 0) {
795 tprint(" plus ");
796 print_glue(stretch(p), stretch_order(p), s);
798 if (shrink(p) != 0) {
799 tprint(" minus ");
800 print_glue(shrink(p), shrink_order(p), s);
806 @ We can reinforce our knowledge of the data structures just introduced
807 by considering two procedures that display a list in symbolic form.
808 The first of these, called |short_display|, is used in ``overfull box''
809 messages to give the top-level description of a list. The other one,
810 called |show_node_list|, prints a detailed description of exactly what
811 is in the data structure.
813 The philosophy of |short_display| is to ignore the fine points about exactly
814 what is inside boxes, except that ligatures and discretionary breaks are
815 expanded. As a result, |short_display| is a recursive procedure, but the
816 recursion is never more than one level deep.
817 @^recursion@>
819 A global variable |font_in_short_display| keeps track of the font code that
820 is assumed to be present when |short_display| begins; deviations from this
821 font will be printed.
824 int font_in_short_display; /* an internal font number */
827 @ Boxes, rules, inserts, whatsits, marks, and things in general that are
828 sort of ``complicated'' are indicated only by printing `\.{[]}'.
831 void print_font_identifier(internal_font_number f)
833 str_number fonttext;
834 fonttext = font_id_text(f);
835 if (fonttext > 0) {
836 print_esc(fonttext);
837 } else {
838 tprint_esc("FONT");
839 print_int(f);
841 if (int_par(pdf_tracing_fonts_code) > 0) {
842 tprint(" (");
843 print_font_name(f);
844 if (font_size(f) != font_dsize(f)) {
845 tprint("@@");
846 print_scaled(font_size(f));
847 tprint("pt");
849 print_char(')');
853 @ @c
854 void short_display(int p)
855 { /* prints highlights of list |p| */
856 while (p != null) {
857 if (is_char_node(p)) {
858 if (lig_ptr(p) != null) {
859 short_display(lig_ptr(p));
860 } else {
861 if (font(p) != font_in_short_display) {
862 if (!is_valid_font(font(p)))
863 print_char('*');
864 else
865 print_font_identifier(font(p));
866 print_char(' ');
867 font_in_short_display = font(p);
869 print(character(p));
871 } else {
872 /* Print a short indication of the contents of node |p| */
873 print_short_node_contents(p);
875 p = vlink(p);
880 @ The |show_node_list| routine requires some auxiliary subroutines: one to
881 print a font-and-character combination, one to print a token list without
882 its reference count, and one to print a rule dimension.
885 void print_font_and_char(int p)
886 { /* prints |char_node| data */
887 if (!is_valid_font(font(p)))
888 print_char('*');
889 else
890 print_font_identifier(font(p));
891 print_char(' ');
892 print(character(p));
895 @ @c
896 void print_mark(int p)
897 { /* prints token list data in braces */
898 print_char('{');
899 if ((p < (int) fix_mem_min) || (p > (int) fix_mem_end))
900 tprint_esc("CLOBBERED.");
901 else
902 show_token_list(token_link(p), null, max_print_line - 10);
903 print_char('}');
906 @ @c
907 void print_rule_dimen(scaled d)
908 { /* prints dimension in rule node */
909 if (is_running(d))
910 print_char('*');
911 else
912 print_scaled(d);
916 @ Since boxes can be inside of boxes, |show_node_list| is inherently recursive,
917 @^recursion@>
918 up to a given maximum number of levels. The history of nesting is indicated
919 by the current string, which will be printed at the beginning of each line;
920 the length of this string, namely |cur_length|, is the depth of nesting.
922 A global variable called |depth_threshold| is used to record the maximum
923 depth of nesting for which |show_node_list| will show information. If we
924 have |depth_threshold=0|, for example, only the top level information will
925 be given and no sublists will be traversed. Another global variable, called
926 |breadth_max|, tells the maximum number of items to show at each level;
927 |breadth_max| had better be positive, or you won't see anything.
930 int depth_threshold; /* maximum nesting depth in box displays */
931 int breadth_max; /* maximum number of items shown at the same list level */
934 @ The recursive machinery is started by calling |show_box|.
937 void show_box(halfword p)
939 /* Assign the values |depth_threshold:=show_box_depth| and
940 |breadth_max:=show_box_breadth| */
941 depth_threshold = int_par(show_box_depth_code);
942 breadth_max = int_par(show_box_breadth_code);
944 if (breadth_max <= 0)
945 breadth_max = 5;
946 show_node_list(p); /* the show starts at |p| */
947 print_ln();
951 @ Helper for debugging purposes
954 void short_display_n(int p, int m)
955 { /* prints highlights of list |p| */
956 int i = 0;
957 font_in_short_display = null_font;
958 if (p == null)
959 return;
960 while (p != null) {
961 if (is_char_node(p)) {
962 if (p <= max_halfword) {
963 if (font(p) != font_in_short_display) {
964 if (!is_valid_font(font(p)))
965 print_char('*');
966 else
967 print_font_identifier(font(p));
968 print_char(' ');
969 font_in_short_display = font(p);
971 print(character(p));
973 } else {
974 if ((type(p) == glue_node) ||
975 (type(p) == disc_node) ||
976 (type(p) == penalty_node) ||
977 ((type(p) == kern_node) && (subtype(p) == explicit)))
978 incr(i);
979 if (i >= m)
980 return;
981 if (type(p) == disc_node) {
982 print_char('|');
983 short_display(vlink(pre_break(p)));
984 print_char('|');
985 short_display(vlink(post_break(p)));
986 print_char('|');
987 } else {
988 /* Print a short indication of the contents of node |p| */
989 print_short_node_contents(p);
992 p = vlink(p);
993 if (p == null)
994 return;
996 update_terminal();
1000 @ When debugging a macro package, it can be useful to see the exact
1001 control sequence names in the format file. For example, if ten new
1002 csnames appear, it's nice to know what they are, to help pinpoint where
1003 they came from. (This isn't a truly ``basic'' printing procedure, but
1004 that's a convenient module in which to put it.)
1007 void print_csnames(int hstart, int hfinish)
1009 int h;
1010 unsigned char *c, *l;
1011 fprintf(stderr, "fmtdebug:csnames from %d to %d:", (int) hstart,
1012 (int) hfinish);
1013 for (h = hstart; h <= hfinish; h++) {
1014 if (cs_text(h) > 0) { /* if have anything at this position */
1015 c = str_string(cs_text(h));
1016 l = c + str_length(cs_text(h));
1017 while (c < l) {
1018 fputc(*c++, stderr); /* print the characters */
1020 fprintf(stderr, "|");
1026 @ A helper for printing file:line:error style messages. Look for a
1027 filename in |full_source_filename_stack|, and if we fail to find
1028 one fall back on the non-file:line:error style.
1031 void print_file_line(void)
1033 int level;
1034 level = in_open;
1035 while ((level > 0) && (full_source_filename_stack[level] == 0))
1036 decr(level);
1037 if (level == 0) {
1038 tprint_nl("! ");
1039 } else {
1040 tprint_nl("");
1041 tprint(full_source_filename_stack[level]);
1042 print_char(':');
1043 if (level == in_open)
1044 print_int(line);
1045 else
1046 print_int(line_stack[level + 1]);
1047 tprint(": ");
1052 @ \TeX\ is occasionally supposed to print diagnostic information that
1053 goes only into the transcript file, unless |tracing_online| is positive.
1054 Here are two routines that adjust the destination of print commands:
1057 void begin_diagnostic(void)
1058 { /* prepare to do some tracing */
1059 global_old_setting = selector;
1060 if ((int_par(tracing_online_code) <= 0) && (selector == term_and_log)) {
1061 decr(selector);
1062 if (history == spotless)
1063 history = warning_issued;
1067 @ @c
1068 void end_diagnostic(boolean blank_line)
1069 { /* restore proper conditions after tracing */
1070 tprint_nl("");
1071 if (blank_line)
1072 print_ln();
1073 selector = global_old_setting;
1077 @ Of course we had better declare another global variable, if the previous
1078 routines are going to work.
1081 int global_old_setting;