[Inter::Binary::] Inter in Binary Files. To read or write inter between memory and binary files. @h Reading and writing inter to binary. The binary representation of Inter, saved out to a file, is portable and complete in itself. = void Inter::Binary::read(inter_tree *I, filename *F) { LOGIF(INTER_FILE_READ, "(Reading binary inter file %f)\n", F); long int max_offset = BinaryFiles::size(F); FILE *fh = BinaryFiles::open_for_reading(F); inter_error_location eloc = Inter::Errors::interb_location(F, 0); inter_bookmark at = Inter::Bookmarks::at_start_of_this_repository(I); inter_warehouse *warehouse = Inter::warehouse(I); unsigned int X = 0; @; @; @; @; @; BinaryFiles::close(fh); } @ Symmetrically: = void Inter::Binary::write(filename *F, inter_tree *I) { LOGIF(INTER_FILE_READ, "(Writing binary inter file %f)\n", F); FILE *fh = BinaryFiles::open_for_writing(F); inter_warehouse *warehouse = Inter::warehouse(I); @; @; @; @; @; BinaryFiles::close(fh); } @ The header is four bytes with a special value (equivalent to the ASCII for |intr|), then four zero bytes, so that we can tell this file from a text file coincidentally opening with those letters. @d INTER_SHIBBOLETH ((inter_t) 0x696E7472) @ = if ((BinaryFiles::read_int32(fh, &X) == FALSE) || ((inter_t) X != INTER_SHIBBOLETH) || (BinaryFiles::read_int32(fh, &X) == FALSE) || ((inter_t) X != 0)) Inter::Binary::read_error(&eloc, 0, I"not a binary inter file"); @ = BinaryFiles::write_int32(fh, (unsigned int) INTER_SHIBBOLETH); BinaryFiles::write_int32(fh, (unsigned int) 0); @ Next we have to describe the possible range of annotations. We need these now, because they will be referred to in the symbol definitions in the resource block later on. @ = inter_t ID = 0; while (BinaryFiles::read_int32(fh, &ID)) { if (ID == 0) break; TEMPORARY_TEXT(keyword); unsigned int L; if (BinaryFiles::read_int32(fh, &L) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); for (unsigned int i=0; i = inter_annotation_form *IAF; LOOP_OVER(IAF, inter_annotation_form) { if (IAF->annotation_ID == INVALID_IANN) continue; BinaryFiles::write_int32(fh, IAF->annotation_ID); BinaryFiles::write_int32(fh, (unsigned int) Str::len(IAF->annotation_keyword)); LOOP_THROUGH_TEXT(P, IAF->annotation_keyword) BinaryFiles::write_int32(fh, (unsigned int) Str::get(P)); } BinaryFiles::write_int32(fh, 0); @ There follows a block of resources, which is a list in which each entry opens with a word identifying which resource is meant; when |NO_IRSRC| is reached, that's the end of the list and therefore the block. @e NO_IRSRC from 0 @e STRING_IRSRC @e SYMBOLS_TABLE_IRSRC @e FRAME_LIST_IRSRC @e PACKAGE_IRSRC @ = int resource_counter = 0; while (BinaryFiles::read_int32(fh, &X)) { if (X == NO_IRSRC) break; resource_counter++; inter_t n = (inter_t) resource_counter; if (resource_counter >= 3) n = Inter::Warehouse::create_resource(warehouse); inter_resource_holder *res = &(warehouse->stored_resources[n]); switch (X) { case STRING_IRSRC: @; break; case SYMBOLS_TABLE_IRSRC: @; break; case FRAME_LIST_IRSRC: @; break; case PACKAGE_IRSRC: @; break; } } @ = for (int n = 1; n < warehouse->size; n++) { inter_resource_holder *res = &(warehouse->stored_resources[n]); if (res->stored_text_stream) { BinaryFiles::write_int32(fh, STRING_IRSRC); @; } else if (res->stored_symbols_table) { BinaryFiles::write_int32(fh, SYMBOLS_TABLE_IRSRC); @; } else if (res->stored_package) { BinaryFiles::write_int32(fh, PACKAGE_IRSRC); @; } else { BinaryFiles::write_int32(fh, FRAME_LIST_IRSRC); @; } } BinaryFiles::write_int32(fh, NO_IRSRC); @ = res->stored_text_stream = Str::new(); unsigned int L; if (BinaryFiles::read_int32(fh, &L) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); for (unsigned int i=0; istored_text_stream, (int) c); } @ = BinaryFiles::write_int32(fh, (unsigned int) Str::len(res->stored_text_stream)); LOOP_THROUGH_TEXT(P, res->stored_text_stream) BinaryFiles::write_int32(fh, (unsigned int) Str::get(P)); @ = if (res->stored_symbols_table == NULL) res->stored_symbols_table = Inter::SymbolsTables::new(); while (BinaryFiles::read_int32(fh, &X)) { if (X == 0) break; unsigned int st; if (BinaryFiles::read_int32(fh, &st) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); unsigned int sc; if (BinaryFiles::read_int32(fh, &sc) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); unsigned int L; if (BinaryFiles::read_int32(fh, &L) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); TEMPORARY_TEXT(name); for (unsigned int i=0; istored_symbols_table, name, X); S->symbol_type = (int) st; S->symbol_scope = (int) sc; if (Str::len(trans) > 0) Inter::Symbols::set_translate(S, trans); if (BinaryFiles::read_int32(fh, &L) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); for (unsigned int i=0; i= MAX_INTER_ANNOTATIONS_PER_SYMBOL) Inter::Binary::read_error(&eloc, ftell(fh), I"excessive annotation"); unsigned int c1, c2; if (BinaryFiles::read_int32(fh, &c1) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); if (BinaryFiles::read_int32(fh, &c2) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); inter_annotation IA = Inter::Defn::annotation_from_bytecode(c1, c2); if (Inter::Defn::is_invalid(IA)) Inter::Binary::read_error(&eloc, ftell(fh), I"invalid annotation"); Inter::Symbols::annotate(S, IA); } if (S->symbol_scope == LINK_ISYMS) { S->equated_name = Str::new(); while (TRUE) { unsigned int c; if (BinaryFiles::read_int32(fh, &c) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); if (c == 0) break; PUT_TO(S->equated_name, (wchar_t) c); } } LOGIF(INTER_BINARY, "Read symbol $3\n", S); DISCARD_TEXT(name); DISCARD_TEXT(trans); } @ = inter_symbols_table *T = res->stored_symbols_table; if (T) { for (int i=0; isize; i++) { inter_symbol *symb = T->symbol_array[i]; if (symb) { BinaryFiles::write_int32(fh, symb->symbol_ID); BinaryFiles::write_int32(fh, (unsigned int) symb->symbol_type); BinaryFiles::write_int32(fh, (unsigned int) symb->symbol_scope); BinaryFiles::write_int32(fh, (unsigned int) Str::len(symb->symbol_name)); LOOP_THROUGH_TEXT(P, symb->symbol_name) BinaryFiles::write_int32(fh, (unsigned int) Str::get(P)); BinaryFiles::write_int32(fh, (unsigned int) Str::len(symb->translate_text)); LOOP_THROUGH_TEXT(P, symb->translate_text) BinaryFiles::write_int32(fh, (unsigned int) Str::get(P)); BinaryFiles::write_int32(fh, (unsigned int) symb->no_symbol_annotations); for (int i=0; ino_symbol_annotations; i++) { inter_t c1 = 0, c2 = 0; Inter::Defn::annotation_to_bytecode(symb->symbol_annotations[i], &c1, &c2); BinaryFiles::write_int32(fh, (unsigned int) c1); BinaryFiles::write_int32(fh, (unsigned int) c2); } if (symb->symbol_scope == LINK_ISYMS) { LOOP_THROUGH_TEXT(pos, symb->equated_name) BinaryFiles::write_int32(fh, (unsigned int) Str::get(pos)); BinaryFiles::write_int32(fh, 0); } } } } BinaryFiles::write_int32(fh, 0); @ And similarly for packages. @ = unsigned int p; if (BinaryFiles::read_int32(fh, &p) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); unsigned int cl; if (BinaryFiles::read_int32(fh, &cl) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); unsigned int sc; if (BinaryFiles::read_int32(fh, &sc) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); unsigned int nid; if (BinaryFiles::read_int32(fh, &nid) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); inter_package *parent = NULL; if (p != 0) parent = Inter::get_package(I, p); if (res->stored_package == NULL) { res->stored_package = Inter::Packages::new(I, n); } if (cl) Inter::Packages::make_codelike(res->stored_package); if (nid == 0) Inter::Packages::make_rootlike(res->stored_package); if (sc != 0) Inter::Packages::set_scope(res->stored_package, Inter::get_symbols_table(I, sc)); if (nid != 0) { inter_symbol *pack_name = Inter::SymbolsTables::symbol_from_id(parent?(Inter::Packages::scope(parent)):Inter::get_global_symbols(I), nid); if (pack_name) Inter::Packages::set_name(res->stored_package, pack_name); else Inter::Binary::read_error(&eloc, ftell(fh), I"unable to retrieve package name"); } @ = inter_package *P = res->stored_package; if (P) { inter_package *par = Inter::Packages::parent(P); if (par == NULL) BinaryFiles::write_int32(fh, 0); else BinaryFiles::write_int32(fh, (unsigned int) par->index_n); BinaryFiles::write_int32(fh, (unsigned int) Inter::Packages::is_codelike(P)); BinaryFiles::write_int32(fh, (unsigned int) P->package_scope->n_index); if (P->package_name) BinaryFiles::write_int32(fh, (unsigned int) P->package_name->symbol_ID); else BinaryFiles::write_int32(fh, 0); } @ We do nothing here, because frame lists are built new on reading. It's enough that the slot exists for the eventual list to be stored in. @ = if (res->stored_frame_list == NULL) res->stored_frame_list = Inter::new_frame_list(); @ = ; @ = while (BinaryFiles::read_int32(fh, &X)) { if (X == 0) break; inter_symbols_table *from_T = Inter::get_symbols_table(I, X); if (from_T == NULL) { WRITE_TO(STDERR, "It's %d\n", X); internal_error("no from_T"); } unsigned int from_ID = 0; while (BinaryFiles::read_int32(fh, &from_ID)) { if (from_ID == 0) break; unsigned int to_T_id = 0; unsigned int to_ID = 0; if (BinaryFiles::read_int32(fh, &to_T_id) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); if (BinaryFiles::read_int32(fh, &to_ID) == FALSE) Inter::Binary::read_error(&eloc, ftell(fh), I"bytecode incomplete"); inter_symbols_table *to_T = Inter::get_symbols_table(I, to_T_id); if (from_T == NULL) internal_error("no to_T"); inter_symbol *from_S = Inter::SymbolsTables::symbol_from_id(from_T, from_ID); if (from_S == NULL) internal_error("no from_S"); inter_symbol *to_S = Inter::SymbolsTables::symbol_from_id(to_T, to_ID); if (to_S == NULL) internal_error("no to_S"); Inter::SymbolsTables::equate(from_S, to_S); } } @ = for (int n = 1; n < warehouse->size; n++) { inter_resource_holder *res = &(warehouse->stored_resources[n]); if (res->stored_symbols_table) { inter_symbols_table *from_T = res->stored_symbols_table; BinaryFiles::write_int32(fh, (unsigned int) n); for (int i=0; isize; i++) { inter_symbol *symb = from_T->symbol_array[i]; if ((symb) && (symb->equated_to)) { BinaryFiles::write_int32(fh, symb->symbol_ID); BinaryFiles::write_int32(fh, (unsigned int) symb->equated_to->owning_table->n_index); BinaryFiles::write_int32(fh, symb->equated_to->symbol_ID); } } BinaryFiles::write_int32(fh, 0); } } BinaryFiles::write_int32(fh, 0); @ = while (BinaryFiles::read_int32(fh, &X)) { eloc.error_offset = (size_t) ftell(fh) - PREFRAME_SIZE; int extent = (int) X; if ((extent < 2) || ((long int) extent >= max_offset)) Inter::Binary::read_error(&eloc, ftell(fh), I"overlarge line"); inter_package *owner = NULL; unsigned int PID = 0; if (BinaryFiles::read_int32(fh, &PID)) owner = Inter::Packages::from_PID(I, PID); inter_frame P = Inter::Warehouse::find_room(warehouse, Inter::get_global_symbols(I), extent-1, &eloc, owner); for (int i=0; i = Inter::traverse_global_list(I, Inter::Binary::visitor, fh, -PACKAGE_IST); Inter::traverse_tree(I, Inter::Binary::visitor, fh, NULL, 0); @ = void Inter::Binary::visitor(inter_tree *I, inter_frame P, void *state) { FILE *fh = (FILE *) state; BinaryFiles::write_int32(fh, (unsigned int) (P.extent + 1)); BinaryFiles::write_int32(fh, (unsigned int) (Inter::Frame::get_package(P))); for (int i=0; ierror_offset = (size_t) at; Inter::Errors::issue(Inter::Errors::plain(err, eloc)); exit(1); } @ This tests a file to see if it looks like Inter binary: = int Inter::Binary::test_file(filename *F) { int verdict = TRUE; FILE *fh = BinaryFiles::open_for_reading(F); unsigned int X = 0; if ((BinaryFiles::read_int32(fh, &X) == FALSE) || ((inter_t) X != INTER_SHIBBOLETH)) verdict = FALSE; if ((BinaryFiles::read_int32(fh, &X) == FALSE) || ((inter_t) X != 0)) verdict = FALSE; BinaryFiles::close(fh); return verdict; }