diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/tex/dumpdata.w')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/tex/dumpdata.w | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/tex/dumpdata.w b/Build/source/texk/web2c/luatexdir/tex/dumpdata.w new file mode 100644 index 00000000000..8b36e504182 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/tex/dumpdata.w @@ -0,0 +1,527 @@ +% 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/>. + +@ @c +#include "ptexlib.h" + +static const char _svn_version[] = + "$Id: dumpdata.w 3587 2010-04-03 14:32:25Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/tex/dumpdata.w $"; + +#define font_id_text(A) cs_text(font_id_base+(A)) +#define prev_depth cur_list.prev_depth_field + + +@ 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. + +@c +str_number format_ident; +str_number format_name; /* principal file name */ + + +@ Format files consist of |memory_word| items, and we use the following +macros to dump words of different types: + +@c +FILE *fmt_file; /* for input or output of format information */ + +@ @c +void store_fmt_file(void) +{ + int j, k, l; /* all-purpose indices */ + halfword p; /* all-purpose pointer */ + int x; /* something to dump */ + char *format_engine; + char *fmtname = NULL; + /* 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(); + } + + /* Create the |format_ident|, open the format file, and inform the user + that dumping has begun */ + selector = new_string; + tprint(" (format="); + print(job_name); + print_char(' '); + print_int(int_par(year_code)); + print_char('.'); + print_int(int_par(month_code)); + print_char('.'); + print_int(int_par(day_code)); + 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(""); + slow_print(format_ident); + + /* Dump constants for consistency check */ + /* The next few sections of the program should make it clear how we use the + dump/undump macros. */ + + dump_int(0x57325458); /* Web2C \TeX's magic constant: "W2TX" */ + /* Align engine 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); /* TODO HM, what checksum would make sense? */ + dump_int(max_halfword); + dump_int(hash_high); + dump_int(eqtb_size); + dump_int(hash_prime); + + /* Dump the string pool */ + k = dump_string_pool(); + print_ln(); + print_int(k); + tprint(" strings using "); + print_int((longinteger) pool_size); + tprint(" bytes"); + + /* 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); + + /* Dump the table of equivalents */ + /* Dump regions 1 to 4 of |eqtb| */ + /*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; + goto DONE1; /* |j=int_base-1| */ + 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); + + /* 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; + goto DONE2; /* |j=eqtb_size| */ + 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) + dump_things(eqtb[eqtb_size + 1], hash_high); /* dump |hash_extra| part */ + + dump_int(par_loc); + dump_int(write_loc); + dump_math_codes(); + dump_text_codes(); + /* 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"); + + /* Dump the font information */ + dump_int(max_font_id()); + for (k = 0; k <= max_font_id(); k++) { + /* 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(); + + /* Dump the ocp information */ + dump_active_ocp_info(); + dump_ocp_info(); + dump_ocplist_info(); + + /* Dump the hyphenation tables */ + dump_language_data(); + + /* Dump pdftex data */ + dump_pdftex_data(static_pdf); + + /* Dump a couple more things and the closing check word */ + dump_int(interaction); + dump_int(format_ident); + dump_int(format_name); + dump_int(69069); + /* We have already printed a lot of statistics, so we set |tracing_stats:=0| + to prevent them from appearing again. */ + int_par(tracing_stats_code) = 0; + + /* Dump the lua bytecodes */ + dump_luac_registers(); + + /* Close the format file */ + zwclose(fmt_file); +} + +@ 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. + +@c +#define too_small(A) do { \ + wake_up_terminal(); \ + wterm_cr(); \ + fprintf(term_out,"---! Must increase the %s",(A)); \ + goto BAD_FMT; \ + } while (0) + +@ 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|. + +@c +#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) + + +@ @c +boolean load_fmt_file(const char *fmtname) +{ + int j, k; /* all-purpose indices */ + halfword p; /* all-purpose pointer */ + int x; /* something undumped */ + char *format_engine; + /* 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) + goto BAD_FMT; /* not a format file */ + undump_int(x); + format_debug("engine name size", x); + if ((x < 0) || (x > 256)) + goto BAD_FMT; /* corrupted format file */ + + format_engine = xmalloc((unsigned) x); + undump_things(format_engine[0], x); + format_engine[x - 1] = 0; /* force string termination, just in case */ + 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) { /* todo: @@\$ *//* check that strings are the same */ + 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; /* check |max_halfword| */ + 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; + + /* Undump the string pool */ + str_ptr = undump_string_pool(); + /* 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); + + /* Undump the table of equivalents */ + /* Undump regions 1 to 6 of |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) /* 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(); + /* 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); + + /* Undump the font information */ + undump_int(x); + set_max_font_id(x); + for (k = 0; k <= max_font_id(); k++) { + /* Undump the array info for internal font number |k| */ + undump_font(k); + } + undump_math_data(); + make_pdftex_banner(); + + /* Undump the ocp information */ + undump_active_ocp_info(); + undump_ocp_info(); + undump_ocplist_info(); + + /* Undump the hyphenation tables */ + undump_language_data(); + + /* Undump pdftex data */ + undump_pdftex_data(static_pdf); + + /* 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; + + /* Undump the lua bytecodes */ + undump_luac_registers(); + + prev_depth = dimen_par(pdf_ignored_dimen_code); + return true; /* it worked! */ + BAD_FMT: + wake_up_terminal(); + wterm_cr(); + fprintf(term_out, "(Fatal format file error; I'm stymied)"); + return false; +} |