diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/tex/dumpdata.c')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/tex/dumpdata.c | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/tex/dumpdata.c b/Build/source/texk/web2c/luatexdir/tex/dumpdata.c new file mode 100644 index 00000000000..0091685fb74 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/tex/dumpdata.c @@ -0,0 +1,539 @@ +/* + +dumpdata.w + +Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +This file is part of LuaTeX. + +LuaTeX is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your +option) any later version. + +LuaTeX is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. + +You should have received a copy of the GNU General Public License along +with LuaTeX; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "ptexlib.h" + +/*tex + + We use a magic number to register the version of the format. Normally this + number only increments when we add a new primitive of change command codes. + We start with 907 which is the sum of the values of the bytes of \quote + {don knuth}. + +*/ + +#define FORMAT_ID (907+48) +#if ((FORMAT_ID>=0) && (FORMAT_ID<=256)) +#error Wrong value for FORMAT_ID. +#endif + +/*tex + +After \.{INITEX} has seen a collection of fonts and macros, it can write all the +necessary information on an auxiliary file so that production versions of \TeX\ +are able to initialize their memory at high speed. The present section of the +program takes care of such output and input. We shall consider simultaneously the +processes of storing and restoring, so that the inverse relation between them is +clear. @.INITEX@> + +The global variable |format_ident| is a string that is printed right after the +|banner| line when \TeX\ is ready to start. For \.{INITEX} this string says +simply `\.{(INITEX)}'; for other versions of \TeX\ it says, for example, +`\.{(preloaded format=plain 1982.11.19)}', showing the year, month, and day that +the format file was created. We have |format_ident=0| before \TeX's tables are +loaded. |FORMAT_ID| is a new field of type int suitable for the identification of +a format: values between 0 and 256 (included) can not be used because in the +previous format they are used for the length of the name of the engine. + +*/ + +str_number format_ident; +str_number format_name; + + +/*tex + +Format files consist of |memory_word| items, and we use the following macros to +dump words of different types: + +*/ + +FILE *fmt_file; + +void store_fmt_file(void) +{ + int j, k, l, x; + halfword p; + char *format_engine; + int callback_id; + char *fmtname = NULL; + /*tex + If dumping is not allowed, abort. The user is not allowed to dump a + format file unless |save_ptr=0|. This condition implies that + |cur_level=level_one|, hence the |xeq_level| array is constant and it + need not be dumped. + */ + if (save_ptr != 0) { + print_err("You can't dump inside a group"); + help1("`{...\\dump}' is a no-no."); + succumb(); + } + /*tex + Create the |format_ident|, open the format file, and inform the user that + dumping has begun. + */ + callback_id = callback_defined(pre_dump_callback); + if (callback_id > 0) { + (void) run_callback(callback_id, "->"); + } + selector = new_string; + tprint(" (format="); + print(job_name); + print_char(' '); + print_int(year_par); + print_char('.'); + print_int(month_par); + print_char('.'); + print_int(day_par); + print_char(')'); + str_room(2); + format_ident = make_string(); + print(job_name); + format_name = make_string(); + if (interaction == batch_mode) { + selector = log_only; + } else { + selector = term_and_log; + } + fmtname = pack_job_name(format_extension); + while (!zopen_w_output(&fmt_file, fmtname, FOPEN_WBIN_MODE)) { + fmtname = prompt_file_name("format file name", format_extension); + } + tprint_nl("Beginning to dump on file "); + tprint(fmtname); + free(fmtname); + tprint_nl(""); + print(format_ident); + /*tex + Dump constants for consistency check. The next few sections of the + program should make it clear how we use the dump/undump macros. First + comes Web2C \TeX's magic constant: "W2TX" + */ + dump_int(0x57325458); + dump_int(FORMAT_ID); + /*tex + We align |engine_name| to 4 bytes with one or more trailing |NUL|. + */ + x = (int) strlen(engine_name); + format_engine = xmalloc((unsigned) (x + 4)); + strcpy(format_engine, engine_name); + for (k = x; k <= x + 3; k++) + format_engine[k] = 0; + x = x + 4 - (x % 4); + dump_int(x); + dump_things(format_engine[0], x); + xfree(format_engine); + dump_int(0x57325458); + dump_int(max_halfword); + dump_int(hash_high); + dump_int(eqtb_size); + dump_int(hash_prime); + /*tex Dump the string pool. */ + k = dump_string_pool(); + print_ln(); + print_int(k); + tprint(" strings using "); + print_int((longinteger) pool_size); + tprint(" bytes"); + /*tex + Dump the dynamic memory. By sorting the list of available spaces in the + variable-size portion of |mem|, we are usually able to get by without + having to dump very much of the dynamic memory. + + We recompute |var_used| and |dyn_used|, so that \.{INITEX} dumps valid + information even when it has not been gathering statistics. + */ + dump_node_mem(); + dump_int(temp_token_head); + dump_int(hold_token_head); + dump_int(omit_template); + dump_int(null_list); + dump_int(backup_head); + dump_int(garbage); + x = (int) fix_mem_min; + dump_int(x); + x = (int) fix_mem_max; + dump_int(x); + x = (int) fix_mem_end; + dump_int(x); + dump_int(avail); + dyn_used = (int) fix_mem_end + 1; + dump_things(fixmem[fix_mem_min], fix_mem_end - fix_mem_min + 1); + x = x + (int) (fix_mem_end + 1 - fix_mem_min); + p = avail; + while (p != null) { + decr(dyn_used); + p = token_link(p); + } + dump_int(dyn_used); + print_ln(); + print_int(x); + tprint(" memory locations dumped; current usage is "); + print_int(var_used); + print_char('&'); + print_int(dyn_used); + /*tex + Dump regions 1 to 4 of |eqtb|, the table of equivalents. The table of + equivalents usually contains repeated information, so we dump it in + compressed form: The sequence of $n+2$ values $(n,x_1,\ldots,x_n,m)$ in + the format file represents $n+m$ consecutive entries of |eqtb|, with |m| + extra copies of $x_n$, namely $(x_1,\ldots,x_n,x_n,\ldots,x_n)$. + */ + k = null_cs; + do { + j = k; + while (j < int_base - 1) { + if ((equiv(j) == equiv(j + 1)) && (eq_type(j) == eq_type(j + 1)) && + (eq_level(j) == eq_level(j + 1))) + goto FOUND1; + incr(j); + } + l = int_base; + /*tex |j=int_base-1| */ + goto DONE1; + FOUND1: + incr(j); + l = j; + while (j < int_base - 1) { + if ((equiv(j) != equiv(j + 1)) || (eq_type(j) != eq_type(j + 1)) || + (eq_level(j) != eq_level(j + 1))) + goto DONE1; + incr(j); + } + DONE1: + dump_int(l - k); + dump_things(eqtb[k], l - k); + k = j + 1; + dump_int(k - l); + } while (k != int_base); + /*tex Dump regions 5 and 6 of |eqtb|. */ + do { + j = k; + while (j < eqtb_size) { + if (eqtb[j].cint == eqtb[j + 1].cint) + goto FOUND2; + incr(j); + } + l = eqtb_size + 1; + /*tex |j=eqtb_size| */ + goto DONE2; + FOUND2: + incr(j); + l = j; + while (j < eqtb_size) { + if (eqtb[j].cint != eqtb[j + 1].cint) + goto DONE2; + incr(j); + } + DONE2: + dump_int(l - k); + dump_things(eqtb[k], l - k); + k = j + 1; + dump_int(k - l); + } while (k <= eqtb_size); + if (hash_high > 0) { + /*tex Dump the |hash_extra| part: */ + dump_things(eqtb[eqtb_size + 1], hash_high); + } + dump_int(par_loc); + dump_int(write_loc); + dump_math_codes(); + dump_text_codes(); + /*tex + Dump the hash table, A different scheme is used to compress the hash + table, since its lower region is usually sparse. When |text(p)<>0| for + |p<=hash_used|, we output two words, |p| and |hash[p]|. The hash table + is, of course, densely packed for |p>=hash_used|, so the remaining + entries are output in a~block. + */ + dump_primitives(); + dump_int(hash_used); + cs_count = frozen_control_sequence - 1 - hash_used + hash_high; + for (p = hash_base; p <= hash_used; p++) { + if (cs_text(p) != 0) { + dump_int(p); + dump_hh(hash[p]); + incr(cs_count); + } + } + dump_things(hash[hash_used + 1],undefined_control_sequence - 1 - hash_used); + if (hash_high > 0) { + dump_things(hash[eqtb_size + 1], hash_high); + } + dump_int(cs_count); + print_ln(); + print_int(cs_count); + tprint(" multiletter control sequences"); + /*tex Dump the font information. */ + dump_int(max_font_id()); + for (k = 0; k <= max_font_id(); k++) { + /*tex Dump the array info for internal font number |k|. */ + dump_font(k); + tprint_nl("\\font"); + print_esc(font_id_text(k)); + print_char('='); + tprint_file_name((unsigned char *) font_name(k), + (unsigned char *) font_area(k), NULL); + if (font_size(k) != font_dsize(k)) { + tprint(" at "); + print_scaled(font_size(k)); + tprint("pt"); + } + } + print_ln(); + print_int(max_font_id()); + tprint(" preloaded font"); + if (max_font_id() != 1) + print_char('s'); + dump_math_data(); + /*tex Dump the hyphenation tables. */ + dump_language_data(); + /*tex Dump a couple more things and the closing check word. */ + dump_int(interaction); + dump_int(format_ident); + dump_int(format_name); + dump_int(69069); + /*tex + We have already printed a lot of statistics, so we set |tracing_stats:=0| + to prevent them from appearing again. + */ + tracing_stats_par = 0; + /*tex Dump the \LUA\ bytecodes. */ + dump_luac_registers(); + /*tex Close the format file. */ + zwclose(fmt_file); +} + +/*tex + +Corresponding to the procedure that dumps a format file, we have a function that +reads one in. The function returns |false| if the dumped format is incompatible +with the present \TeX\ table sizes, etc. + +*/ + +#define too_small(A) do { \ + wake_up_terminal(); \ + wterm_cr(); \ + fprintf(term_out,"---! Must increase the %s",(A)); \ + goto BAD_FMT; \ +} while (0) + +/*tex + + The inverse macros are slightly more complicated, since we need to check the + range of the values we are reading in. We say `|undump(a)(b)(x)|' to read an + integer value |x| that is supposed to be in the range |a<=x<=b|. + +*/ + +#define undump(A,B,C) do { \ + undump_int(x); \ + if (x<(A) || x>(B)) \ + goto BAD_FMT; \ + else \ + (C) = x; \ +} while (0) + +#define format_debug(A,B) do { \ + if (debug_format_file) { \ + fprintf (stderr, "fmtdebug: %s=%d", (A), (int)(B)); \ + } \ +} while (0) + +#define undump_size(A,B,C,D) do { \ + undump_int(x); \ + if (x<(A)) \ + goto BAD_FMT; \ + if (x>(B)) \ + too_small(C); \ + else \ + format_debug (C,x); \ + (D) = x; \ +} while (0) + +boolean load_fmt_file(const char *fmtname) +{ + int j, k, x; + halfword p; + char *format_engine; + /*tex Undump constants for consistency check .*/ + if (ini_version) { + libcfree(hash); + libcfree(eqtb); + libcfree(fixmem); + libcfree(varmem); + } + undump_int(x); + format_debug("format magic number", x); + if (x != 0x57325458) { + /*tex it's not a format file. */ + goto BAD_FMT; + } + undump_int(x); + format_debug("format id", x); + if (x != FORMAT_ID) { + /*tex We have a |FORMAT_ID| mismatch. */ + goto BAD_FMT; + } + undump_int(x); + format_debug("engine name size", x); + if ((x < 0) || (x > 256)) { + /*tex The format file is corrupt. */ + goto BAD_FMT; + } + format_engine = xmalloc((unsigned) x); + undump_things(format_engine[0], x); + format_engine[x - 1] = 0; + if (strcmp(engine_name, format_engine)) { + wake_up_terminal(); + wterm_cr(); + fprintf(term_out, "---! %s was written by %s", fmtname, format_engine); + xfree(format_engine); + goto BAD_FMT; + } + xfree(format_engine); + undump_int(x); + format_debug("string pool checksum", x); + if (x != 0x57325458) { + wake_up_terminal(); + wterm_cr(); + fprintf(term_out, "---! %s was written by a different version", + fmtname); + goto BAD_FMT; + } + undump_int(x); + if (x != max_halfword) + goto BAD_FMT; + undump_int(hash_high); + if ((hash_high < 0) || (hash_high > sup_hash_extra)) + goto BAD_FMT; + if (hash_extra < hash_high) + hash_extra = hash_high; + eqtb_top = eqtb_size + hash_extra; + if (hash_extra == 0) + hash_top = undefined_control_sequence; + else + hash_top = eqtb_top; + hash = xmallocarray(two_halves, (unsigned) (1 + hash_top)); + memset(hash, 0, sizeof(two_halves) * (unsigned) (hash_top + 1)); + eqtb = xmallocarray(memory_word, (unsigned) (eqtb_top + 1)); + set_eq_type(undefined_control_sequence, undefined_cs_cmd); + set_equiv(undefined_control_sequence, null); + set_eq_level(undefined_control_sequence, level_zero); + for (x = eqtb_size + 1; x <= eqtb_top; x++) + eqtb[x] = eqtb[undefined_control_sequence]; + undump_int(x); + if (x != eqtb_size) + goto BAD_FMT; + undump_int(x); + if (x != hash_prime) + goto BAD_FMT; + /*tex Undump the string pool */ + str_ptr = undump_string_pool(); + /*tex Undump the dynamic memory */ + undump_node_mem(); + undump_int(temp_token_head); + undump_int(hold_token_head); + undump_int(omit_template); + undump_int(null_list); + undump_int(backup_head); + undump_int(garbage); + undump_int(fix_mem_min); + undump_int(fix_mem_max); + fixmem = xmallocarray(smemory_word, fix_mem_max + 1); + memset(voidcast(fixmem), 0, (fix_mem_max + 1) * sizeof(smemory_word)); + undump_int(fix_mem_end); + undump_int(avail); + undump_things(fixmem[fix_mem_min], fix_mem_end - fix_mem_min + 1); + undump_int(dyn_used); + /*tex Undump regions 1 to 6 of the table of equivalents |eqtb|. */ + k = null_cs; + do { + undump_int(x); + if ((x < 1) || (k + x > eqtb_size + 1)) + goto BAD_FMT; + undump_things(eqtb[k], x); + k = k + x; + undump_int(x); + if ((x < 0) || (k + x > eqtb_size + 1)) + goto BAD_FMT; + for (j = k; j <= k + x - 1; j++) + eqtb[j] = eqtb[k - 1]; + k = k + x; + } while (k <= eqtb_size); + if (hash_high > 0) { + /*tex undump |hash_extra| part */ + undump_things(eqtb[eqtb_size + 1], hash_high); + } + undump(hash_base, hash_top, par_loc); + par_token = cs_token_flag + par_loc; + undump(hash_base, hash_top, write_loc); + undump_math_codes(); + undump_text_codes(); + /*tex Undump the hash table */ + undump_primitives(); + undump(hash_base, frozen_control_sequence, hash_used); + p = hash_base - 1; + do { + undump(p + 1, hash_used, p); + undump_hh(hash[p]); + } while (p != hash_used); + undump_things(hash[hash_used + 1], undefined_control_sequence - 1 - hash_used); + if (debug_format_file) + print_csnames(hash_base, undefined_control_sequence - 1); + if (hash_high > 0) { + undump_things(hash[eqtb_size + 1], hash_high); + if (debug_format_file) + print_csnames(eqtb_size + 1, hash_high - (eqtb_size + 1)); + } + undump_int(cs_count); + /*tex Undump the font information */ + undump_int(x); + set_max_font_id(x); + for (k = 0; k <= max_font_id(); k++) { + /*tex Undump the array info for internal font number |k| */ + undump_font(k); + } + undump_math_data(); + /*tex Undump the hyphenation tables */ + undump_language_data(); + /*tex Undump a couple more things and the closing check word */ + undump(batch_mode, error_stop_mode, interaction); + if (interactionoption != unspecified_mode) + interaction = interactionoption; + undump(0, str_ptr, format_ident); + undump(0, str_ptr, format_name); + undump_int(x); + if (x != 69069) + goto BAD_FMT; + /*tex Undump the lua bytecodes. */ + undump_luac_registers(); + prev_depth_par = ignore_depth; + return true; + BAD_FMT: + wake_up_terminal(); + wterm_cr(); + fprintf(term_out, "(Fatal format file error; I'm stymied)"); + return false; +} |