/* tectonic/output.c -- functions related to outputting messages * Copyright 2016 the Tectonic Project * Licensed under the MIT License. */ #include "xetex-core.h" #include "xetex-xetexd.h" #include "xetex-synctex.h" #include "tectonic_bridge_core.h" static ttbc_diagnostic_t *current_diagnostic = 0; void capture_to_diagnostic(ttbc_diagnostic_t *diagnostic) { if (current_diagnostic) { ttstub_diag_finish(current_diagnostic); } current_diagnostic = diagnostic; } static void diagnostic_print_file_line(ttbc_diagnostic_t *diagnostic) { // Add file/line number information // This duplicates logic from print_file_line int32_t level = in_open; while (level > 0 && full_source_filename_stack[level] == 0) level--; if (level == 0) { ttbc_diag_append(diagnostic, "!"); } else { int32_t source_line = line; if (level != in_open) { source_line = line_stack[level + 1]; } char* filename = gettexstring(full_source_filename_stack[level]); ttstub_diag_printf(diagnostic, "%s:%d: ", filename, source_line); free(filename); } } ttbc_diagnostic_t * diagnostic_begin_capture_warning_here(void) { ttbc_diagnostic_t *warning = ttbc_diag_begin_warning(); diagnostic_print_file_line(warning); capture_to_diagnostic(warning); return warning; } // This replaces the "print file+line number" block at the start of errors ttbc_diagnostic_t * error_here_with_diagnostic(const char* message) { ttbc_diagnostic_t *error = ttbc_diag_begin_error(); diagnostic_print_file_line(error); ttstub_diag_printf(error, "%s", message); if (file_line_error_style_p) print_file_line(); else print_nl_cstr("! "); print_cstr(message); capture_to_diagnostic(error); return error; } static void warn_char(int c) { if (current_diagnostic) { char bytes[2] = { c, 0 }; ttbc_diag_append(current_diagnostic, bytes); } } void print_ln(void) { switch (selector) { case SELECTOR_TERM_AND_LOG: warn_char('\n'); ttstub_output_putc(rust_stdout, '\n'); ttstub_output_putc(log_file, '\n'); term_offset = 0; file_offset = 0; break; case SELECTOR_LOG_ONLY: warn_char('\n'); ttstub_output_putc(log_file, '\n'); file_offset = 0; break; case SELECTOR_TERM_ONLY: warn_char('\n'); ttstub_output_putc(rust_stdout, '\n'); term_offset = 0; break; case SELECTOR_NO_PRINT: case SELECTOR_PSEUDO: case SELECTOR_NEW_STRING: break; default: ttstub_output_putc(write_file[selector], '\n'); break; } } void print_raw_char(UTF16_code s, bool incr_offset) { switch (selector) { case SELECTOR_TERM_AND_LOG: warn_char(s); ttstub_output_putc(rust_stdout, s); ttstub_output_putc(log_file, s); if (incr_offset) { term_offset++; file_offset++; } if (term_offset == max_print_line) { ttstub_output_putc(rust_stdout, '\n'); term_offset = 0; } if (file_offset == max_print_line) { ttstub_output_putc(log_file, '\n'); file_offset = 0; } break; case SELECTOR_LOG_ONLY: warn_char(s); ttstub_output_putc(log_file, s); if (incr_offset) file_offset++; if (file_offset == max_print_line) { ttstub_output_putc(log_file, '\n'); file_offset = 0; } break; case SELECTOR_TERM_ONLY: warn_char(s); ttstub_output_putc(rust_stdout, s); if (incr_offset) term_offset++; if (term_offset == max_print_line) { ttstub_output_putc(rust_stdout, '\n'); term_offset = 0; } break; case SELECTOR_NO_PRINT: break; case SELECTOR_PSEUDO: if (tally < trick_count) trick_buf[tally % error_line] = s; break; case SELECTOR_NEW_STRING: if (pool_ptr < pool_size) { str_pool[pool_ptr] = s; pool_ptr++; } break; default: ttstub_output_putc(write_file[selector], s); break; } tally++; } void print_char(int32_t s) { small_number l; if ((selector > SELECTOR_PSEUDO) && (!doing_special)) { if (s >= 0x10000) { print_raw_char(0xD800 + (s - 0x10000) / 1024, true); print_raw_char(0xDC00 + (s - 0x10000) % 1024, true); } else print_raw_char(s, true); return; } if ( /*252: */ s == INTPAR(new_line_char) /*:252 */ ) { if (selector < SELECTOR_PSEUDO) { print_ln(); return; } } if (s < 32 && !doing_special) { print_raw_char('^' , true); print_raw_char('^' , true); print_raw_char(s + 64, true); } else if (s < 127) { print_raw_char(s, true); } else if (s == 127) { if (!doing_special) { print_raw_char('^' , true); print_raw_char('^' , true); print_raw_char('?' , true); } else { print_raw_char(s, true); } } else if (s < 160 && !doing_special) { print_raw_char('^' , true); print_raw_char('^' , true); l = (s % 256) / 16; if (l < 10) print_raw_char('0' + l, true); else print_raw_char('a' + l - 10, true); l = s % 16; if (l < 10) print_raw_char('0' + l, true); else print_raw_char('a' + l - 10, true); } else if (selector == SELECTOR_PSEUDO) { print_raw_char(s, true); } else { if (s < 2048) { print_raw_char(192 + s / 64, false); print_raw_char(128 + s % 64, true); } else if (s < 0x10000) { print_raw_char(224 + (s / 4096), false); print_raw_char(128 + (s % 4096) / 64, false); print_raw_char(128 + (s % 64), true); } else { print_raw_char(240 + (s / 0x40000), false); print_raw_char(128 + (s % 0x40000) / 4096, false); print_raw_char(128 + (s % 4096) / 64, false); print_raw_char(128 + (s % 64), true); } } } void print(int32_t s) { int32_t nl; if (s >= str_ptr) return print_cstr("???"); else if (s <= BIGGEST_CHAR) { if (s < 0) return print_cstr("???"); else { if (selector > SELECTOR_PSEUDO) { print_char(s); return; } if ( /*252: */ s == INTPAR(new_line_char) /*:252 */ ) { if (selector < SELECTOR_PSEUDO) { print_ln(); return; } } nl = INTPAR(new_line_char); INTPAR(new_line_char) = -1; print_char(s); INTPAR(new_line_char) = nl; return; } } int32_t pool_idx = s - 0x10000; for (pool_pointer i = str_start[pool_idx]; i < str_start[pool_idx + 1]; i++) { if ( (str_pool[i] >= 0xD800) && (str_pool[i] < 0xDC00) && (i + 1 < str_start[pool_idx + 1]) && (str_pool[i + 1] >= 0xDC00) && (str_pool[i + 1] < 0xE000) ) { print_char( 0x10000 + (str_pool[i] - 0xD800) * 1024 + str_pool[i + 1] - 0xDC00 ); i++; } else { print_char(str_pool[i]); } } } void print_cstr(const char* str) { for (unsigned int i = 0; i < strlen(str); i++) { print_char(str[i]); } } void print_nl(str_number s) { if (((term_offset > 0) && (odd(selector))) || ((file_offset > 0) && (selector >= SELECTOR_LOG_ONLY))) print_ln(); print(s); } void print_nl_cstr(const char* str) { if (((term_offset > 0) && (odd(selector))) || ((file_offset > 0) && (selector >= SELECTOR_LOG_ONLY))) print_ln(); print_cstr(str); } void print_esc(str_number s) { int32_t c = INTPAR(escape_char) /*:251 */ ; if (c >= 0 && c <= BIGGEST_USV) print_char(c); print(s); } void print_esc_cstr(const char* s) { int32_t c = INTPAR(escape_char) /*:251 */ ; if (c >= 0 && c <= BIGGEST_USV) print_char(c); print_cstr(s); } static void print_the_digs(eight_bits k) { while (k > 0) { k--; if (dig[k] < 10) print_char('0' + dig[k]); else print_char(55 /*"A" -10 */ + dig[k]); } } void print_int(int32_t n) { unsigned char k = 0; int32_t m; if (n < 0) { print_char('-'); if (n > -100000000L) n = -(int32_t) n; else { m = -1 - n; n = m / 10; m = (m % 10) + 1; k = 1; if (m < 10) dig[0] = m; else { dig[0] = 0; n++; } } } do { dig[k] = n % 10; n = n / 10; k++; } while (!(n == 0)); print_the_digs(k); } void print_cs(int32_t p) { if (p < HASH_BASE) { if (p >= SINGLE_BASE) { if (p == NULL_CS) { print_esc_cstr("csname"); print_esc_cstr("endcsname"); print_char(' '); } else { print_esc(p - SINGLE_BASE); if (CAT_CODE(p - SINGLE_BASE) == LETTER) print_char(' '); } } else if (p < ACTIVE_BASE) print_esc_cstr("IMPOSSIBLE."); else print_char(p - 1); } else if (((p >= UNDEFINED_CONTROL_SEQUENCE) && (p <= EQTB_SIZE)) || (p > eqtb_top)) { print_esc_cstr("IMPOSSIBLE."); } else if (hash[p].s1 >= str_ptr) { print_esc_cstr("NONEXISTENT."); } else { if (p >= PRIM_EQTB_BASE && p < FROZEN_NULL_FONT) print_esc(prim[p - PRIM_EQTB_BASE].s1 - 1); else print_esc(hash[p].s1); print_char(' '); } } void sprint_cs(int32_t p) { if (p < HASH_BASE) { if (p < SINGLE_BASE) print_char(p - 1); else if (p < NULL_CS) print_esc(p - SINGLE_BASE); else { print_esc_cstr("csname"); print_esc_cstr("endcsname"); } } else if (p >= PRIM_EQTB_BASE && p < FROZEN_NULL_FONT) { print_esc(prim[p - PRIM_EQTB_BASE].s1 - 1); } else { print_esc(hash[p].s1); } } void print_file_name(int32_t n, int32_t a, int32_t e) { bool must_quote = false; int32_t quote_char = 0; pool_pointer j; if (a != 0) { j = str_start[(a) - 0x10000]; while (((!must_quote) || (quote_char == 0)) && (j < str_start[(a + 1) - 0x10000])) { if (str_pool[j] == ' ' ) must_quote = true; else if ((str_pool[j] == '"' ) || (str_pool[j] == '\'' )) { must_quote = true; quote_char = 73 /*""" 39 */ - str_pool[j]; } j++; } } if (n != 0) { j = str_start[(n) - 0x10000]; while (((!must_quote) || (quote_char == 0)) && (j < str_start[(n + 1) - 0x10000])) { if (str_pool[j] == ' ' ) must_quote = true; else if ((str_pool[j] == '"' ) || (str_pool[j] == '\'' )) { must_quote = true; quote_char = 73 /*""" 39 */ - str_pool[j]; } j++; } } if (e != 0) { j = str_start[(e) - 0x10000]; while (((!must_quote) || (quote_char == 0)) && (j < str_start[(e + 1) - 0x10000])) { if (str_pool[j] == ' ' ) must_quote = true; else if ((str_pool[j] == '"' ) || (str_pool[j] == '\'' )) { must_quote = true; quote_char = 73 /*""" 39 */ - str_pool[j]; } j++; } } if (must_quote) { if (quote_char == 0) quote_char = '"' ; print_char(quote_char); } if (a != 0) { register int32_t for_end; j = str_start[(a) - 0x10000]; for_end = str_start[(a + 1) - 0x10000] - 1; if (j <= for_end) do { if (str_pool[j] == quote_char) { print(quote_char); quote_char = 73 /*""" 39 */ - quote_char; print(quote_char); } print(str_pool[j]); } while (j++ < for_end); } if (n != 0) { register int32_t for_end; j = str_start[(n) - 0x10000]; for_end = str_start[(n + 1) - 0x10000] - 1; if (j <= for_end) do { if (str_pool[j] == quote_char) { print(quote_char); quote_char = 73 /*""" 39 */ - quote_char; print(quote_char); } print(str_pool[j]); } while (j++ < for_end); } if (e != 0) { register int32_t for_end; j = str_start[(e) - 0x10000]; for_end = str_start[(e + 1) - 0x10000] - 1; if (j <= for_end) do { if (str_pool[j] == quote_char) { print(quote_char); quote_char = 73 /*""" 39 */ - quote_char; print(quote_char); } print(str_pool[j]); } while (j++ < for_end); } if (quote_char != 0) print_char(quote_char); } void print_size(int32_t s) { if (s == TEXT_SIZE) print_esc_cstr("textfont"); else if (s == SCRIPT_SIZE) print_esc_cstr("scriptfont"); else print_esc_cstr("scriptscriptfont"); } void print_write_whatsit(const char* s, int32_t p) { print_esc_cstr(s); if (mem[p + 1].b32.s0 < 16) print_int(mem[p + 1].b32.s0); else if (mem[p + 1].b32.s0 == 16) print_char('*'); else print_char('-'); } void print_native_word(int32_t p) { int32_t i, c, cc; int32_t for_end = mem[p + 4].b16.s1 - 1; for (i = 0; i <= for_end; i++) { c = NATIVE_NODE_text(p)[i]; if ((c >= 0xD800) && (c < 0xDC00)) { if (i < mem[p + 4].b16.s1 - 1) { cc = NATIVE_NODE_text(p)[i + 1]; if ((cc >= 0xDC00) && (cc < 0xE000)) { c = 0x10000 + (c - 0xD800) * 1024 + (cc - 0xDC00); print_char(c); i++; } else print('.'); } else print('.'); } else print_char(c); } } void print_sa_num(int32_t q) { int32_t n; if (mem[q].b16.s1 < DIMEN_VAL_LIMIT) n = mem[q + 1].b32.s1; else { n = mem[q].b16.s1 % 64; q = LLIST_link(q); n = n + 64 * mem[q].b16.s1; q = LLIST_link(q); n = n + 64 * 64 * (mem[q].b16.s1 + 64 * mem[mem[q].b32.s1].b16.s1); } print_int(n); } void print_file_line(void) { int32_t level = in_open; while ((level > 0) && (full_source_filename_stack[level] == 0)) level--; if (level == 0) print_nl_cstr("! "); else { print_nl_cstr(""); print(full_source_filename_stack[level]); print(':'); if (level == in_open) print_int(line); else print_int(line_stack[level + 1]); print_cstr(": "); } } /*:1660*/ void print_two(int32_t n) { n = abs(n) % 100; print_char('0' + (n / 10)); print_char('0' + (n % 10)); } void print_hex(int32_t n) { unsigned char k = 0; print_char('"'); do { dig[k] = n % 16; n = n / 16; k++; } while (n != 0); print_the_digs(k); } void print_roman_int(int32_t n) { int32_t u, v; const char* roman_data = "m2d5c2l5x2v5i"; unsigned char j = 0; unsigned char k = 0; v = 1000; while (true) { while (n >= v) { print_char(roman_data[j]); n = n - v; } if (n <= 0) return; k = j + 2; u = v / (roman_data[k - 1] - '0'); if (roman_data[k - 1] == '2' ) { k = k + 2; u = u / (roman_data[k - 1] - '0'); } if (n + u >= v) { print_char(roman_data[k]); n = n + u; } else { j = j + 2; v = v / (roman_data[j - 1] - '0'); } } } void print_current_string(void) { pool_pointer j = str_start[str_ptr - 0x10000]; while (j < pool_ptr) { print_char(str_pool[j]); j++; } } void print_scaled(scaled_t s) { scaled_t delta; if (s < 0) { print_char('-'); s = -(int32_t) s; } print_int(s / 0x10000); print_char('.'); s = 10 * (s % 0x10000) + 5; delta = 10; do { if (delta > 0x10000) s = s + 0x8000 - 50000; print_char('0' + (s / 0x10000)); s = 10 * (s % 0x10000); delta = delta * 10; } while (s > delta); } void print_ucs_code(UnicodeScalar n) { unsigned char k = 0; print_cstr("U+"); do { dig[k] = n % 16; n = n / 16; k++; } while (n != 0); while (k < 4) { dig[k] = 0; k++; } print_the_digs(k); }