/* * Write preprocessor state to a file */ void tok_write_defines(tokcxdef *ctx, osfildef *fp, errcxdef *ec) { int i; tokdfdef **dfp; tokdfdef *df; char buf[4]; /* write each element of the hash chains */ for (i = TOKDFHSHSIZ, dfp = ctx->tokcxdf ; i ; ++dfp, --i) { /* write each entry in this hash chain */ for (df = *dfp ; df ; df = df->nxt) { /* write this entry */ oswp2(buf, df->len); oswp2(buf + 2, df->explen); if (osfwb(fp, buf, 4) || osfwb(fp, df->nm, df->len) || (df->explen != 0 && osfwb(fp, df->expan, df->explen))) errsig(ec, ERR_WRTGAM); } /* write a zero-length entry to indicate the end of this chain */ oswp2(buf, 0); if (osfwb(fp, buf, 4)) errsig(ec, ERR_WRTGAM); } }
/* * Begin an object static data block */ void CVmImageWriter::begin_objs_block(uint metaclass_idx, int large_objects, int trans) { char buf[16]; uint flags; /* begin the block */ begin_block("OBJS", TRUE); /* prepare the flags */ flags = 0; if (large_objects) flags |= 1; if (trans) flags |= 2; /* remember where the prefix goes so we can fix it up later */ objs_prefix_ = fp_->get_pos(); /* * write a placeholder object count, the metaclass dependency table * index, and the OBJS flags */ oswp2(buf, 0); oswp2(buf + 2, metaclass_idx); oswp2(buf + 4, flags); /* write the prefix */ fp_->write_bytes(buf, 6); }
/* tell the line source the location of the current line being compiled */ void dbgclin(tokcxdef *tokctx, objnum objn, uint ofs) { uchar buf[4]; /* package the information and send it to the line source */ oswp2(buf, objn); oswp2(buf + 2, ofs); lincmpinf(tokctx->tokcxlin, buf); }
/* * store a vm_val_t value in a portable data holder */ void vmb_put_dh(char *buf, const vm_val_t *val) { /* store the type code */ buf[0] = (char)val->typ; /* store the value, in the appropriate type-dependent format */ switch(val->typ) { case VM_OBJ: case VM_OBJX: /* store the object ID as a UINT4 */ oswp4(buf+1, val->val.obj); break; case VM_PROP: /* store the property ID as a UINT2 */ oswp2(buf+1, val->val.prop); break; case VM_INT: oswp4(buf+1, val->val.intval); break; case VM_BIFPTR: case VM_BIFPTRX: /* store the integer as two UINT2s: function index, set index */ oswp2(buf+1, val->val.bifptr.func_idx); oswp2(buf+3, val->val.bifptr.set_idx); break; case VM_ENUM: /* store the enumerated constant value as a UINT4 */ oswp4(buf+1, val->val.enumval); break; case VM_SSTRING: case VM_DSTRING: case VM_LIST: case VM_CODEOFS: case VM_FUNCPTR: /* store the offset value as a UINT4 */ oswp4(buf+1, val->val.ofs); break; default: /* other types have no extra data or cannot be put into a DH */ break; } }
/* set a temporary label */ void emtslbl(emtcxdef *ctx, noreg uint *lblp, int release) { uint lbl = *lblp; emtldef *p = &ctx->emtcxlbl[lbl]; uint fwd; emtldef *fwdp; ushort nxt; short diff; ushort curpos = ctx->emtcxofs; p->emtlofs = curpos; p->emtlflg |= EMTLFSET; /* run through forward reference list, fixing up each reference */ for (fwd = p->emtllnk ; fwd != EMTLLNKEND ; fwd = nxt) { fwdp = &ctx->emtcxlbl[fwd]; /* get pointer to current record */ nxt = fwdp->emtllnk; /* remember the next record */ /* write the fixup, and release the forward reference */ diff = curpos - fwdp->emtlofs; oswp2(ctx->emtcxptr + fwdp->emtlofs, diff); fwdp->emtllnk = EMTLLNKEND; emtdlbl(ctx, &fwd); } p->emtllnk = EMTLLNKEND; /* there are no more forward refs for label */ if (release) emtdlbl(ctx, lblp); }
/* * Begin a block */ void CVmImageWriter::begin_block(const char *block_id, int mandatory) { char buf[10]; uint flags; /* if there's a block currently open, close it */ end_block(); /* remember the seek location of the start of the block */ block_start_ = fp_->get_pos(); /* store the type string */ memcpy(buf, block_id, 4); /* store four bytes of zeros as a placeholder for the size */ memset(buf+4, 0, 4); /* compute the flags */ flags = 0; if (mandatory) flags |= VMIMAGE_DBF_MANDATORY; /* store the flags */ oswp2(buf+8, flags); /* write the header */ fp_->write_bytes(buf, 10); }
/* write a required object (just an object number) */ static void fiowrq(errcxdef *ec, osfildef *fp, objnum objn) { uchar buf[2]; oswp2(buf, objn); if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM); }
/* * Write an entrypoint (ENTP) block */ void CVmImageWriter::write_entrypt(uint32 entry_ofs, size_t method_hdr_size, size_t exc_entry_size, size_t line_entry_size, size_t dbg_hdr_size, size_t dbg_lclsym_hdr_size, size_t dbg_frame_hdr_size, int dbg_vsn_id) { char buf[32]; /* prepare the block's contents */ oswp4(buf, entry_ofs); oswp2(buf+4, method_hdr_size); oswp2(buf+6, exc_entry_size); oswp2(buf+8, line_entry_size); oswp2(buf+10, dbg_hdr_size); oswp2(buf+12, dbg_lclsym_hdr_size); oswp2(buf+14, dbg_vsn_id); oswp2(buf+16, dbg_frame_hdr_size); /* open the block, write the data, and close the block */ begin_block("ENTP", TRUE); fp_->write_bytes(buf, 18); end_block(); }
/* * Begin a dependency block */ void CVmImageWriter::begin_dep_block(const char *block_id, int count) { char buf[4]; /* open the block */ begin_block(block_id, TRUE); /* write the number of entries */ oswp2(buf, count); fp_->write_bytes(buf, 2); }
/* write out a symbol table entry */ static void fiowrtsym(void *ctx0, toksdef *t) { fiowcxdef *ctx = (fiowcxdef *)ctx0; uchar buf[TOKNAMMAX + 50]; errcxdef *ec = ctx->fiowcxerr; osfildef *fp = ctx->fiowcxfp; buf[0] = t->tokslen; buf[1] = t->tokstyp; oswp2(buf + 2, t->toksval); memcpy(buf + 4, t->toksnam, (size_t)buf[0]); if (osfwb(fp, buf, 4 + t->tokslen)) errsig(ec, ERR_WRTGAM); }
/* * Write a constant pool definition block */ void CVmImageWriter::write_pool_def(uint pool_id, uint32 page_count, uint32 page_size, int mandatory) { char buf[16]; /* prepare the block's data */ oswp2(buf, pool_id); oswp4(buf+2, page_count); oswp4(buf+6, page_size); /* open the block, write the data, and end the block */ begin_block("CPDF", mandatory); fp_->write_bytes(buf, 10); end_block(); }
/* * Begin writing a constant pool page. This constructs the header and * prepares for writing the bytes making up the page. */ void CVmImageWriter::begin_pool_page(uint pool_id, uint32 page_index, int mandatory, uchar xor_mask) { char buf[16]; /* begin the block */ begin_block("CPPG", mandatory); /* prepare the prefix */ oswp2(buf, pool_id); oswp4(buf+2, page_index); buf[6] = xor_mask; /* write the prefix */ fp_->write_bytes(buf, 7); }
/* * Begin a symbolic names block */ void CVmImageWriter::begin_sym_block() { char buf[4]; /* begin the block */ begin_block("SYMD", FALSE); /* remember where our placeholder goes */ symd_prefix_ = fp_->get_pos(); /* prepare the placeholder prefix, using a zero count for now */ oswp2(buf, 0); /* write the prefix */ fp_->write_bytes(buf, 2); /* we haven't written any symbolic name items yet */ symd_cnt_ = 0; }
/* * Define the position of a label, resolving any fixups associated with * the label. */ void CTcCodeStream::def_label_pos(CTcCodeLabel *lbl) { /* set the label's position */ lbl->ofs = ofs_; lbl->is_known = TRUE; /* resolve each fixup */ while (lbl->fhead != 0) { CTcLabelFixup *fixup; long diff; char buf[4]; /* pull this fixup off of the active list */ fixup = lbl->fhead; lbl->fhead = lbl->fhead->nxt; /* * calculate the offset from the fixup position to the label * position, applying the bias to the fixup position */ diff = lbl->ofs - (fixup->ofs + fixup->bias); /* convert the offset to the correct format and write it out */ if (fixup->is_long) { /* write an INT4 offset value */ oswp4(buf, diff); write_at(fixup->ofs, buf, 4); } else { /* write an INT2 offset value */ oswp2(buf, diff); write_at(fixup->ofs, buf, 2); } /* add this fixup to the free list, since we're finished with it */ fixup->nxt = free_fixup_; free_fixup_ = fixup; } }
/* * end a symbolic names block */ void CVmImageWriter::end_sym_block() { long old_pos; char buf[4]; /* end the block */ end_block(); /* * Go back and fix the header with the number of items we wrote. * First, remember our current position, then seek back to the count * prefix. */ old_pos = fp_->get_pos(); fp_->set_pos(symd_prefix_); /* prepare the prefix, and write it out */ oswp2(buf, symd_cnt_); fp_->write_bytes(buf, 2); /* restore the file position */ fp_->set_pos(old_pos); }
/* * Write a constant pool page */ void CVmImageWriter::write_pool_page(uint pool_id, uint32 page_index, const char *page_data, uint32 page_data_size, int mandatory, uchar xor_mask) { char buf[16]; /* begin the block */ begin_block("CPPG", mandatory); /* prepare the prefix */ oswp2(buf, pool_id); oswp4(buf+2, page_index); buf[6] = xor_mask; /* write the prefix */ fp_->write_bytes(buf, 7); /* write the page data, XOR'ing the data with the mask byte */ xor_and_write_bytes(page_data, page_data_size, xor_mask); /* end the block */ end_block(); }
/* * Main entrypoint */ int main(int argc, char **argv) { int curarg; unsigned char input_map[256]; unsigned char output_map[256]; unsigned char input_map_set[256]; unsigned char output_map_set[256]; unsigned char *p; int i; osfildef *fp; char *infile; char *outfile; int linenum; static char sig[] = CMAP_SIG_S100; int strict_mode = FALSE; char id[5]; char ldesc[CMAP_LDESC_MAX_LEN + 1]; size_t len; unsigned char lenbuf[2]; char *sys_info; entity_map_t *entity_first; entity_map_t *entity_last; /* no parameters have been specified yet */ memset(id, 0, sizeof(id)); ldesc[0] = '\0'; sys_info = 0; /* we have no entities in our entity mapping list yet */ entity_first = entity_last = 0; /* scan options */ for (curarg = 1 ; curarg < argc && argv[curarg][0] == '-' ; ++curarg) { if (!stricmp(argv[curarg], "-strict")) { /* they want extra warnings */ strict_mode = TRUE; } else { /* consume all remaining options so we get a usage message */ curarg = argc; break; } } /* check for required arguments */ if (curarg + 1 >= argc) { printf("usage: mkchrtab [options] <source> <dest>\n" " <source> is the input file\n" " <dest> is the output file\n" "Options:\n" " -strict warn if any codes 128-255 are unassigned\n"); #if 0 /* * The information about what goes in the file made the message way too * long, so this has been removed. Users will want to the documentation * instead of the usage message for information this detailed, so it * didn't seem useful to keep it in here. */ printf("\n" "The source file contains one entry per line, as follows:\n" "\n" "Set the internal character set identifier, which can be up " "to four letters long\n" "(note that the mapping file MUST contain an ID entry):\n" " ID = id\n" "\n"); printf("Set the internal character set's full display name:\n" " LDESC = full name of character set\n" "\n" "Set system-dependent extra information (the meaning varies " "by system):\n" " EXTRA_SYSTEM_INFO = info-string\n" "\n" "Set the native default character:\n" " NATIVE_DEFAULT = charval\n" "Set the internal default character:\n" " INTERNAL_DEFAULT = charval\n"); printf("Load Unicode mapping files:\n" " UNICODE NATIVE=native-mapping INTERNAL=internal-mapping\n" "\n" "Reversibly map a native character code to an internal code:\n" " native <-> internal\n" "\n" "Map a native code to an internal code, and map the internal " "code back\nto a different native code:\n" " native -> internal -> native\n" "\n" "Map a native code to an internal code, where the internal " "code is already\nmapped to a native code by a previous line:\n" " native -> internal\n" "\n"); printf("Map an internal code to a native code, where the native " "code is already\nmapped to an internal code by a previous " "line:\n" " native <- internal\n" "\n" "Map an HTML entity name to a native code or string:\n" " &entity = internal-code [internal-code ...]\n" "\n" "Numbers can be specified in decimal (default), octal (by " "prefixing the number\nwith a zero, as in '037'), or hex (by " "prefixing the number with '0x', as in\n'0xb2'). A number " "can also be entered as a character by enclosing the\n" "character in single quotes.\n" "\n" "Blank lines and lines starting with a pound sign ('#') are " "ignored.\n"); #endif /* 0 */ os_term(OSEXFAIL); } /* get the input and output filenames */ infile = argv[curarg]; outfile = argv[curarg + 1]; /* * initialize the tables - by default, a character code in one * character set maps to the same code in the other character set */ for (p = input_map, i = 0 ; i < sizeof(input_map)/sizeof(input_map[0]) ; ++i, ++p) *p = (unsigned char)i; for (p = output_map, i = 0 ; i < sizeof(output_map)/sizeof(output_map[0]) ; ++i, ++p) *p = (unsigned char)i; /* * initialize the "set" flags all to false, since we haven't set any * of the values yet -- we'll use these flags to detect when the * user attempts to set the same value more than once, so that we * can issue a warning (multiple mappings are almost certainly in * error) */ for (i = 0 ; i < sizeof(input_map_set)/sizeof(input_map_set[0]) ; ++i) input_map_set[i] = output_map_set[i] = FALSE; /* open the input file */ fp = osfoprs(infile, OSFTTEXT); if (fp == 0) { printf("error: unable to open input file \"%s\"\n", infile); os_term(OSEXFAIL); } /* parse the input file */ for (linenum = 1 ; ; ++linenum) { char buf[256]; char *p; unsigned int n1, n2, n3; int set_input; int set_output; /* presume we're going to set both values */ set_input = set_output = TRUE; /* read the next line */ if (osfgets(buf, sizeof(buf), fp) == 0) break; /* scan off leading spaces */ for (p = buf ; isspace(*p) ; ++p) ; /* if this line is blank, or starts with a '#', ignore it */ if (*p == '\0' || *p == '\n' || *p == '\r' || *p == '#') continue; /* check for special directives */ if (isalpha(*p) || *p == '_') { char *sp; char *val; size_t vallen; size_t idlen; /* find the end of the directive name */ for (sp = p ; isalpha(*sp) || *sp == '_' ; ++sp) ; idlen = sp - p; /* find the equals sign, if present */ for (val = sp ; isspace(*val) ; ++val) ; if (*val == '=') { /* skip the '=' and any spaces that follow */ for (++val ; isspace(*val) ; ++val) ; /* find the end of the value */ for (sp = val ; *sp != '\n' && *sp != '\r' && *sp != '\0' ; ++sp) ; /* note its length */ vallen = sp - val; } else { /* there's no value */ val = 0; } /* see what we have */ if (id_matches(p, idlen, "id")) { /* this directive requires a value */ if (val == 0) goto val_required; /* ID's can never be more than four characters long */ if (vallen > 4) { printf("%s: line %d: ID too long - no more than four " "characters are allowed\n", infile, linenum); } else { /* remember the ID */ memcpy(id, val, vallen); id[vallen] = '\0'; } } else if (id_matches(p, idlen, "ldesc")) { /* this directive requires a value */ if (val == 0) goto val_required; /* make sure it fits */ if (vallen > sizeof(ldesc) - 1) { printf("%s: line %d: LDESC too long - no more than %u " "characters are allowed\n", infile, linenum, sizeof(ldesc) - 1); } else { /* remember the ldesc */ memcpy(ldesc, val, vallen); ldesc[vallen] = '\0'; } } else if (id_matches(p, idlen, "extra_system_info")) { /* this directive requires a value */ if (val == 0) goto val_required; /* allocate space for it */ sys_info = (char *)malloc(vallen + 1); memcpy(sys_info, val, vallen); sys_info[vallen] = '\0'; } else if (id_matches(p, idlen, "native_default")) { unsigned int nval; int i; /* this directive requires a value */ if (val == 0) goto val_required; /* parse the character value */ if (read_number(&nval, &val, infile, linenum, TRUE)) continue; /* apply the default */ for (i = 128 ; i < 256 ; ++i) { /* set the default only if we haven't mapped this one */ if (!output_map_set[i]) output_map[i] = nval; } } else if (id_matches(p, idlen, "internal_default")) { unsigned int nval; int i; /* this directive requires a value */ if (val == 0) goto val_required; /* parse the character value */ if (read_number(&nval, &val, infile, linenum, TRUE)) continue; /* apply the default */ for (i = 128 ; i < 256 ; ++i) { /* apply the default only if we haven't set this one */ if (!input_map_set[i]) input_map[i] = nval; } } else if (id_matches(p, idlen, "unicode")) { /* skip the 'unicode' string and any intervening spaces */ for (p += idlen ; isspace(*p) ; ++p) ; /* parse the unicode files */ parse_unicode_files(p, strlen(p), infile, linenum, input_map, input_map_set, output_map, output_map_set, &entity_first, &entity_last); } else { /* unknown directive */ printf("%s: line %d: invalid directive '%.*s'\n", infile, linenum, idlen, p); } /* done processing this line */ continue; /* come here if the directive needs a value and there isn't one */ val_required: printf("%s: line %d: '=' required with directive '%.*s'\n", infile, linenum, idlen, p); continue; } /* check for an entity name */ if (*p == '&') { entity_map_t *mapp; /* skip the '&' */ ++p; /* * parse the entity - if it succeeds, link the resulting * mapping entry into our list */ mapp = parse_entity(p, infile, linenum); if (mapp != 0) { if (entity_last == 0) entity_first = mapp; else entity_last->nxt = mapp; entity_last = mapp; } /* done */ continue; } /* read the first number */ if (read_number(&n1, &p, infile, linenum, TRUE)) continue; /* determine which operator we have */ if (*p == '<') { /* make sure it's "<->" or "<-" */ if (*(p+1) == '-' && *(p+2) != '>') { /* skip the operator */ p += 2; /* * This is a "from" translation - it only affects the * output mapping from the internal character set to the * native character set. Read the second number. There * is no third number, since we don't want to change the * input mapping. */ if (read_number(&n2, &p, infile, linenum, TRUE)) continue; /* * The forward translation is not affected; set only the * output translation. Note that the first number was * the output (native) value for the internal index in * the second number, so move the first value to n3. */ n3 = n1; set_input = FALSE; } else if (*(p+1) == '-' && *(p+2) == '>') { /* skip it */ p += 3; /* * this is a reversible translation, so we only need one * more number - the third number is implicitly the same * as the first */ n3 = n1; if (read_number(&n2, &p, infile, linenum, TRUE)) continue; } else { printf("%s: line %d: invalid operator - expected <->\n", infile, linenum); continue; } } else if (*p == '-') { /* make sure it's "->" */ if (*(p+1) != '>') { printf("%s: line %d: invalid operator - expected ->\n", infile, linenum); continue; } /* skip it */ p += 2; /* get the next number */ if (read_number(&n2, &p, infile, linenum, TRUE)) continue; /* * we may or may not have a third number - if we have * another -> operator, read the third number; if we don't, * the reverse translation is not affected by this entry */ if (*p == '-') { /* make sure it's "->" */ if (*(p+1) != '>') { printf("%s: line %d: invalid operator - expected ->\n", infile, linenum); continue; } /* skip it */ p += 2; /* read the third number */ if (read_number(&n3, &p, infile, linenum, TRUE)) continue; } else { /* * There's no third number - the reverse translation is * not affected by this line. */ set_output = FALSE; } } else { printf("%s: line %d: invalid operator - expected " "-> or <-> or <-\n", infile, linenum); continue; } /* make sure we're at the end of the line, and warn if not */ if (*p != '\0' && *p != '\n' && *p != '\r' && *p != '#') printf("%s: line %d: extra characters at end of line ignored\n", infile, linenum); /* set the input mapping, if necessary */ if (set_input) { /* warn the user if this value has already been set before */ if (input_map_set[n1]) printf("%s: line %d: warning - native character %u has " "already been\n mapped to internal value %u\n", infile, linenum, n1, input_map[n1]); /* set it */ input_map[n1] = n2; /* note that it's been set */ input_map_set[n1] = TRUE; } /* set the output mapping, if necessary */ if (set_output) { /* warn the user if this value has already been set before */ if (output_map_set[n2]) printf("%s: line %d: warning - internal character %u has " "already been\n mapped to native value %u\n", infile, linenum, n2, input_map[n2]); /* set it */ output_map[n2] = n3; /* note that it's been set */ output_map_set[n2] = TRUE; } } /* we're done with the input file */ osfcls(fp); /* * It's an error if we didn't get an ID or LDESC */ if (id[0] == '\0') { printf("Error: No ID was specified. An ID is required.\n"); os_term(OSEXFAIL); } else if (ldesc[0] == '\0') { printf("Error: No LDESC was specified. An LDESC is required.\n"); os_term(OSEXFAIL); } /* open the output file */ fp = osfopwb(outfile, OSFTCMAP); if (fp == 0) { printf("error: unable to open output file \"%s\"\n", outfile); os_term(OSEXFAIL); } /* write our signature */ if (osfwb(fp, sig, sizeof(sig))) printf("error writing signature to output file\n"); /* write the ID and LDESC */ len = strlen(ldesc) + 1; oswp2(lenbuf, len); if (osfwb(fp, id, 4) || osfwb(fp, lenbuf, 2) || osfwb(fp, ldesc, len)) printf("error writing ID information to output file\n"); /* write the mapping tables */ if (osfwb(fp, input_map, sizeof(input_map)) || osfwb(fp, output_map, sizeof(output_map))) printf("error writing character maps to output file\n"); /* write the extra system information if present */ if (sys_info != 0) { /* write it out, with the "SYSI" flag so we know it's there */ len = strlen(sys_info) + 1; oswp2(lenbuf, len); if (osfwb(fp, "SYSI", 4) || osfwb(fp, lenbuf, 2) || osfwb(fp, sys_info, len)) printf("error writing EXTRA_SYSTEM_INFO to output file\n"); /* we're done with the allocated buffer now */ free(sys_info); } /* * Write the entity mapping list, if we have any entities */ if (entity_first != 0) { entity_map_t *entp; entity_map_t *next_entity; char lenbuf[2]; char cvalbuf[2]; /* write out the entity list header */ if (osfwb(fp, "ENTY", 4)) printf("error writing entity marker to output file\n"); /* run through the list, writing out each entry */ for (entp = entity_first ; entp != 0 ; entp = next_entity) { /* write out this entity */ oswp2(lenbuf, entp->exp_len); oswp2(cvalbuf, entp->html_char); if (osfwb(fp, lenbuf, 2) || osfwb(fp, cvalbuf, 2) || osfwb(fp, entp->expansion, entp->exp_len)) { printf("error writing entity mapping to output file\n"); break; } /* remember the next entity before we delete this one */ next_entity = entp->nxt; /* we're done with this entity, so we can delete it now */ free(entp); } /* * write out the end marker, which is just a length marker and * character marker of zero */ oswp2(lenbuf, 0); oswp2(cvalbuf, 0); if (osfwb(fp, lenbuf, 2) || osfwb(fp, cvalbuf, 2)) printf("error writing entity list end marker to output file\n"); } /* write the end-of-file marker */ if (osfwb(fp, "$EOF", 4)) printf("error writing end-of-file marker to output file\n"); /* done with the output file */ osfcls(fp); /* if we're in strict mode, check for unassigned mappings */ if (strict_mode) { int in_cnt, out_cnt; int cnt; /* count unassigned characters */ for (i = 128, in_cnt = out_cnt = 0 ; i < 256 ; ++i) { if (!input_map_set[i]) ++in_cnt; if (!output_map_set[i]) ++out_cnt; } /* if we have any unassigned native characters, list them */ if (in_cnt != 0) { printf("\nUnassigned native -> internal mappings:\n "); for (i = 128, cnt = 0 ; i < 256 ; ++i) { if (!input_map_set[i]) { /* go to a new line if necessary */ if (cnt >= 16) { printf("\n "); cnt = 0; } /* display this item */ printf("%3d ", i); ++cnt; } } printf("\n"); } /* list unassigned internal characters */ if (out_cnt != 0) { printf("\nUnassigned internal -> native mappings:\n "); for (i = 128, cnt = 0 ; i < 256 ; ++i) { if (!output_map_set[i]) { /* go to a new line if necessary */ if (cnt >= 16) { printf("\n "); cnt = 0; } /* display this item */ printf("%3d ", i); ++cnt; } } printf("\n"); } } /* success */ os_term(OSEXSUCC); return OSEXSUCC; }
/* * Process an HTML resource list. If 'old_htmlres' is true, it * indicates that the input file is pointing to an old resource map; * otherwise, we need to construct a brand new one. */ static opdef *prochtmlres(osfildef *fp, osfildef *fpout, opdef *oplist, int *copyrsc, int *showed_heading, int old_htmlres) { opdef *op; opdef *add_list = 0; opdef *prev_op; opdef *next_op; int found; char buf[512]; ulong in_entry_cnt; ulong in_table_siz; ulong out_hdr_siz; ulong out_hdr_pos; ulong i; ulong out_res_cnt; ulong out_total_name_len; ulong rem; struct idx_t **in_list = 0, *out_list = 0, **p, *cur; ulong in_res_base, out_res_base; ulong out_endpos; /* * Scan the oplist for an HTML resource. If there aren't any, we * don't need to modify the HTMLRES list, so tell the caller to copy * this resource unchanged. */ for (op = oplist, found = FALSE ; op != 0 ; op = op->opnxt) { /* if this is an HTML resource, note it and stop looking */ if (op->oprestype == RESTYPE_HTML) { found = TRUE; break; } } /* * If we didn't find any operations on this resource, and we're not * simply listing resources or we don't have an old resource to * list, tell the caller to copy it unchanged. */ if (!found && (fpout != 0 || !old_htmlres)) { *copyrsc = TRUE; return oplist; } /* we'll be handling the resource - tell the caller not to copy it */ *copyrsc = FALSE; /* if there's an old HTMLRES resource, read it */ if (old_htmlres) { /* read the index entry count and size */ if (osfrb(fp, buf, 8)) listexit(fp, "unable to read HTMLRES header"); in_entry_cnt = osrp4(buf); in_table_siz = osrp4(buf + 4); /* allocate space for pointers to all of the entries */ if (in_entry_cnt != 0) { in_list = (struct idx_t **) malloc(in_entry_cnt * sizeof(struct idx_t *)); if (in_list == 0) listexit(fp, "unable to allocate space for HTMLRES entries"); } /* read the index table entries */ for (i = 0, p = in_list ; i < in_entry_cnt ; ++i, ++p) { ushort name_siz; ulong res_siz; ulong res_ofs; /* read the entry information */ if (osfrb(fp, buf, 10)) listexit(fp, "unable to read HTMLRES index table entry (prefix)"); /* get the resource size */ res_ofs = osrp4(buf); res_siz = osrp4(buf + 4); /* read the name */ name_siz = osrp2(buf + 8); if (name_siz > sizeof(buf)) listexit(fp, "name too large in HTMLRES index table entry"); if (osfrb(fp, buf, name_siz)) listexit(fp, "unable to read HTMLRES index table entry (name)"); /* build this entry */ *p = alloc_idx_entry(res_ofs, res_siz, buf, name_siz, 0, 0); } /* if we don't have an output file, list the HTMLRES contents */ if (fpout == 0) { /* display all of the entries */ for (i = 0, p = in_list ; i < in_entry_cnt ; ++i, ++p) show_list_item(showed_heading, "HTML", (*p)->siz, (*p)->nam, (*p)->namlen); /* there's no more processing to do */ goto done; } /* * The resources start at the end of the index table - note the * location of the end of the input table, since it's the base * address relative to which the resource offsets are stated. */ in_res_base = osfpos(fp); /* * Go through the resource table in the input file. Find each * one in the op list. If it's not in the op list, we'll copy * it to the output file. */ for (i = 0, p = in_list ; i < in_entry_cnt ; ++i, ++p) { int remove_res = FALSE; int add_res = FALSE; /* see if we can find this entry in the op list */ for (prev_op = 0, op = oplist ; op != 0 ; prev_op = op, op = op->opnxt) { /* if this one matches, note it */ if (op->oprestype == RESTYPE_HTML && strlen(op->opres) == (*p)->namlen && !memicmp(op->opres, (*p)->nam, (*p)->namlen)) { /* * if we're adding this resource (not replacing it), * warn that it's already in the file, and ignore * this op; if we're removing it or replacing it, * simply delete this entry from the input list so * it doesn't get copied to the output. */ if (!(op->opflag & OPFDEL)) { /* warn that the old one will stay */ rscptf("warning: HTML resource \"%s\" already " "present\n" " -- old version will be kept (use -replace " "to replace it)\n", op->opres); /* remove it from the processing list */ remove_res = TRUE; } else { /* we are deleting it; see if we're also adding it */ if (op->opflag & OPFADD) { /* * we're replacing this resource - take this * op out of the main list and put it into * the add list */ remove_res = TRUE; add_res = TRUE; /* note the addition */ show_op("replacing", op->opres, strlen(op->opres), op->oprestype); } else { /* note the deletion */ show_op("deleting", op->opres, strlen(op->opres), op->oprestype); /* just remove it */ remove_res = TRUE; } /* get rid of this item from the input list */ free(*p); *p = 0; } /* no need to look further in the operations list */ break; } } /* * If desired, remove this resource from the main list, and * add it into the list of resources to add. */ if (remove_res) { /* unlink it from the main list */ if (prev_op == 0) oplist = op->opnxt; else prev_op->opnxt = op->opnxt; /* if desired, add it to the additions list */ if (add_res) { /* we're adding it - put it in the additions list */ op->opnxt = add_list; add_list = op; } else { /* this item has been processed - delete it */ free(op); } } } } else { /* there are no entries in the input file */ in_entry_cnt = 0; in_table_siz = 0; } /* * Move all of the HTML resources marked as additions in the main * operations list into the additions list. */ for (prev_op = 0, op = oplist ; op != 0 ; op = next_op) { /* note the next op, in case we move this one to the other list */ next_op = op->opnxt; /* * if it's an HTML resource to be added, move it to the * additions list */ if (op->oprestype == RESTYPE_HTML && (op->opflag & OPFADD) != 0) { /* show what we're doing */ show_op("adding", op->opres, strlen(op->opres), op->oprestype); /* unlink it from the main list */ if (prev_op == 0) oplist = op->opnxt; else prev_op->opnxt = op->opnxt; /* add it to the additions list */ op->opnxt = add_list; add_list = op; /* * note that we don't want to advance the 'prev_op' pointer, * since we just removed this item - the previous item is * still the same as it was on the last iteration */ } else { /* * we're leaving this op in the original list - it's now the * previous op in the main list */ prev_op = op; } } /* * Figure out what we'll be putting in the HTMLRES list: we'll add * each surviving entry from the input file, plus all of the items * in the add list, plus all of the HTML items in the main list that * are marked for addition. */ out_res_cnt = 0; out_total_name_len = 0; /* count input file entries that we're going to copy */ for (i = 0, p = in_list ; i < in_entry_cnt ; ++i, ++p) { if (*p != 0) add_idx_entry(&out_list, &out_res_cnt, &out_total_name_len, 0, 0, (*p)->nam, (*p)->namlen, 0, *p); } /* * Count items in the additions list. Note that every HTML resource * marked for addition is in the additions list, since we moved all * such resources out of the main list and into the additions list * earlier. */ for (op = add_list ; op != 0 ; op = op->opnxt) add_idx_entry(&out_list, &out_res_cnt, &out_total_name_len, 0, 0, op->opres, (ushort)strlen(op->opres), op, 0); /* write the resource header */ if (osfwb(fpout, "\007HTMLRES\0\0\0\0", 12)) listexit(fp, "unable to write HTMLRES type header"); out_hdr_pos = osfpos(fpout); /* * Reserve space in the output file for the index table. We need * eight bytes for the index table prefix, then ten bytes per entry * plus the name sizes. */ out_hdr_siz = 8 + (10 * out_res_cnt) + out_total_name_len; /* write the index table prefix */ oswp4(buf, out_res_cnt); oswp4(buf + 4, out_hdr_siz); if (osfwb(fpout, buf, 8)) listexit(fp, "unable to write HTMLRES prefix"); /* * Reserve space for the headers. Don't actually write them yet, * since we don't know the actual locations and sizes of the * entries; for now, simply reserve the space, so that we can come * back here later and write the actual headers. Note that we * deduct the eight bytes we've already written from the amount of * filler to put in. */ for (rem = out_hdr_siz - 8 ; rem != 0 ; ) { ulong amt; /* write out a buffer full */ amt = (rem > sizeof(buf) ? sizeof(buf) : rem); if (osfwb(fpout, buf, amt)) listexit(fp, "unable to write HTMLRES header"); /* deduct the amount we wrote from the remainder */ rem -= amt; } /* * note the current position in the output file - this is the base * address of the resources */ out_res_base = osfpos(fpout); /* * Write the resources. */ for (cur = out_list ; cur != 0 ; cur = cur->nxt) { /* * note the current file position as an offset from the resource * base in the output file - this is the offset that we need to * store in the index entry for this object */ cur->ofs = osfpos(fpout) - out_res_base; /* * Copy the resource to the output. If it comes from the input * file, copy from there, otherwise go out and find the external * file and copy its contents. */ if (cur->src_op != 0) { osfildef *fpext; ulong fsiz; /* it comes from an external file - open the file */ fpext = osfoprb(cur->src_op->opfile, OSFTGAME); if (fpext == 0) { rscptf("%s: ", cur->src_op->opfile); errexit("unable to open file", 1); } /* figure the size of the file */ osfseek(fpext, 0L, OSFSK_END); fsiz = osfpos(fpext); osfseek(fpext, 0L, OSFSK_SET); /* copy the contents of the external file to the output */ copybytes(fpext, fpout, fsiz); /* the size is the same as the external file's size */ cur->siz = fsiz; /* done with the file */ osfcls(fpext); } else { /* * it comes from the input resource file - seek to the start * of the resource in the input file, and copy the data to * the output file */ osfseek(fp, in_res_base + cur->src_idx->ofs, OSFSK_SET); copybytes(fp, fpout, cur->src_idx->siz); /* the size is the same as in the input file */ cur->siz = cur->src_idx->siz; } } /* note the current output position - this is the end of the resource */ out_endpos = osfpos(fpout); /* * Now that we've written all of the resources and know their actual * layout in the file, we can go back and write the index table. */ osfseek(fpout, out_hdr_pos + 8, OSFSK_SET); for (cur = out_list ; cur != 0 ; cur = cur->nxt) { /* build this object's index table entry */ oswp4(buf, cur->ofs); oswp4(buf + 4, cur->siz); oswp2(buf + 8, cur->namlen); /* write the entry */ if (osfwb(fpout, buf, 10) || osfwb(fpout, cur->nam, cur->namlen)) listexit(fp, "unable to write HTML index table entry"); } /* * We're done building the resource; now all we need to do is go * back and write the ending position of the resource in the * resource header. */ osfseek(fpout, out_hdr_pos - 4, OSFSK_SET); oswp4(buf, out_endpos); if (osfwb(fpout, buf, 4)) errexit("error writing resource", 1); /* seek back to the end of the resource in the output file */ osfseek(fpout, out_endpos, OSFSK_SET); done: /* if we have an input list, free it */ if (in_list != 0) { /* delete all of the entries in the input table */ for (i = 0, p = in_list ; i < in_entry_cnt ; ++i, ++p) { /* delete this entry if we haven't already done so */ if (*p != 0) free(*p); } /* delete the input pointer list itself */ free(in_list); } /* * delete everything in the additions list, since we're done with * them now */ for (op = add_list ; op != 0 ; op = next_op) { /* note the next entry in the list */ next_op = op->opnxt; /* delete this entry */ free(op); } /* return the op list in its current form */ return oplist; }
/* process changes to resource file (or just list it) */ static opdef *rscproc(osfildef *fp, osfildef *fpout, opdef *oplist) { char buf[128]; ulong siz; char datebuf[27]; ulong endpos; uchar nambuf[40]; uint rsiz; opdef *op; int copyrsc; ulong startpos; uint endpos_ofs; ulong first_xfcn = 0; ulong extcnt_pos = 0; int found_user_rsc = FALSE; int showed_heading = FALSE; int found_htmlres = FALSE; char *file_type; /* * if we're reading an existing file, check it header; otherwise, * write out a brand new file header */ if (fp != 0) { /* * the input file exists -- check file and version headers, and * get flags and timestamp */ if (osfrb(fp, buf, (int)(sizeof(FIOFILHDR) + sizeof(FIOVSNHDR) + 2))) listexit(fp, "error reading file header"); /* check the file type */ if (memcmp(buf, FIOFILHDR, sizeof(FIOFILHDR)) == 0) file_type = "game"; else if (memcmp(buf, FIOFILHDRRSC, sizeof(FIOFILHDRRSC)) == 0) file_type = "resource"; else listexit(fp, "invalid resource file header"); /* check the version header */ if (memcmp(buf + sizeof(FIOFILHDR), FIOVSNHDR, sizeof(FIOVSNHDR)) && memcmp(buf + sizeof(FIOFILHDR), FIOVSNHDR2, sizeof(FIOVSNHDR2)) && memcmp(buf + sizeof(FIOFILHDR), FIOVSNHDR3, sizeof(FIOVSNHDR3))) listexit(fp, "incompatible resource file version"); /* get the timestamp */ if (osfrb(fp, datebuf, (size_t)26)) listexit(fp, "error reading file"); datebuf[26] = '\0'; } else { struct tm *tblock; time_t timer; /* construct a new file header */ memcpy(buf, FIOFILHDRRSC, sizeof(FIOFILHDRRSC)); memcpy(buf + sizeof(FIOFILHDR), FIOVSNHDR, sizeof(FIOVSNHDR)); /* clear the flags */ oswp2(buf + sizeof(FIOFILHDR) + sizeof(FIOVSNHDR), 0); /* construct the timestamp */ timer = time(0); tblock = localtime(&timer); strcpy(datebuf, asctime(tblock)); } if (fpout) { if (osfwb(fpout, buf, (int)(sizeof(FIOFILHDR) + sizeof(FIOVSNHDR) + 2)) || osfwb(fpout, datebuf, (size_t)26)) listexit(fp, "error writing header"); } /* if listing, show file creation timestamp */ if (fpout == 0) rscptf("\n" "File type: TADS %s file\n" "Date compiled: %s\n", file_type, datebuf); /* * Process the input file, if there is one */ for ( ; fp != 0 ; ) { /* assume this resource will be copied to the output */ copyrsc = TRUE; startpos = osfpos(fp); if (osfrb(fp, buf, 1) || osfrb(fp, buf + 1, (int)(buf[0] + 4))) listexit(fp, "error reading file"); memcpy(nambuf, buf + 1, (size_t)buf[0]); nambuf[buf[0]] = '\0'; endpos_ofs = 1 + buf[0]; endpos = osrp4(buf + endpos_ofs); siz = endpos - startpos; /* see what kind of resource we have, and do the right thing */ if (!strcmp((char *)nambuf, "$EOF")) { /* end of file marker - quit here */ break; } else if (!strcmp((char *)nambuf, "HTMLRES")) { /* if we've already found an HTMLRES list, it's an error */ if (found_htmlres) { rscptf("error: multiple HTMLRES maps found in file\n" " -- redundant entries have been deleted.\n"); copyrsc = FALSE; } else { /* go process it */ oplist = prochtmlres(fp, fpout, oplist, ©rsc, &showed_heading, TRUE); } /* note that we've found a resource */ found_user_rsc = TRUE; found_htmlres = TRUE; } else if (!strcmp((char *)nambuf, "EXTCNT")) { /* place to write start of XFCN's? */ if (siz >= 17 && fpout) extcnt_pos = osfpos(fpout); } else if (!strcmp((char *)nambuf, "XFCN")) { if (osfrb(fp, buf, 3) || osfrb(fp, buf + 3, (int)buf[2])) listexit(fp, "error reading file"); rsiz = osrp2(buf); buf[3 + buf[2]] = '\0'; if (fpout) { /* see if this resource is in the list */ for (op = oplist ; op ; op = op->opnxt) { if (!(op->opflag & OPFDONE) && op->oprestype == RESTYPE_XFCN && !stricmp((char *)buf + 3, op->opres)) { /* note that this resource has now been processed */ op->opflag |= OPFDONE; /* * if it's already here, and we're not deleting * it, warn that the old one will stay around */ if (!(op->opflag & OPFDEL)) { /* warn that we're going to ignore it */ rscptf("warning: XFCN resource \"%s\" already in " "file\n -- the old resource will be kept " "(use -replace to replace it)\n", op->opres); /* don't add it */ op->opflag &= ~OPFADD; } else { /* * we're deleting this resource; if adding * it back in (i.e., replacing it), process * the add operation now */ if (op->opflag & OPFADD) { /* show what we're doing */ show_op("replacing", op->opres, strlen(op->opres), op->oprestype); /* * add the external file, replacing the * one in the input file */ procop(fpout, op, &first_xfcn); } else { /* note that we're deleting it */ show_op("deleting", op->opres, strlen(op->opres), op->oprestype); } /* don't copy the one out of the file */ copyrsc = FALSE; } break; } } } else { /* no output file - just list the resource */ show_list_item(&showed_heading, "XFCN", (ulong)rsiz, buf + 3, (size_t)buf[2]); } /* note that we've found a user resource */ found_user_rsc = TRUE; } if (fpout != 0 && copyrsc) { osfseek(fp, startpos, OSFSK_SET); copyres(fp, fpout, siz, endpos_ofs); } /* skip to the next resource */ osfseek(fp, endpos, OSFSK_SET); } /* add the HTML resources if we haven't already */ if (!found_htmlres) oplist = prochtmlres(fp, fpout, oplist, ©rsc, &showed_heading, FALSE); /* now go through what's left, and add new non-HTML resources */ if (fpout != 0) { for (op = oplist ; op != 0 ; op = op->opnxt) { if (!(op->opflag & OPFDONE) && (op->opflag & OPFADD) && op->oprestype != RESTYPE_HTML) { /* show what we're doing */ show_op("adding", op->opres, strlen(op->opres), op->oprestype); /* add the file */ procop(fpout, op, &first_xfcn); /* mark the operation as completed */ op->opflag |= OPFDONE; } } } /* if just listing, and we didn't find anything, tell the user so */ if (fpout == 0 && !found_user_rsc) rscptf("No user resources found.\n"); /* done reading the file - finish it up */ if (fpout != 0) { /* write EOF resource */ if (osfwb(fpout, "\004$EOF\0\0\0\0", 9)) errexit("error writing resource", 1); /* write first_xfcn value to EXTCNT resource */ if (extcnt_pos) { osfseek(fpout, extcnt_pos + 13, OSFSK_SET); oswp4(buf, first_xfcn); osfwb(fpout, buf, 4); } } /* * return the final oplist (it may have been changed during * processing) */ return oplist; }
/* emit a list value */ void emtlst(emtcxdef *ctx, uint ofs, uchar *base) { uint initofs; ushort i; emtlidef *lst; emtledef *ele; initofs = ctx->emtcxofs; /* save starting offset */ emtint2(ctx, 2); /* emit placeholder length */ if (ofs == 0) return; /* nothing more to do for empty list */ lst = (emtlidef *)(base + ofs); for (i = lst->emtlicnt, ele = &lst->emtliele[i-1] ; i ; --ele, --i) { uchar dat; switch(ele->emtletyp) { case TOKTLIST: emtbyte(ctx, DAT_LIST); emtlst(ctx, (uint)ele->emtleval, base); continue; case TOKTSSTRING: { uint oplen = osrp2(base + ele->emtleval); emtbyte(ctx, DAT_SSTRING); emtmem(ctx, base + ele->emtleval, oplen); continue; } case TOKTNUMBER: dat = DAT_NUMBER; break; case TOKTNIL: dat = DAT_NIL; break; case TOKTTRUE: dat = DAT_TRUE; break; case TOKTPOUND: dat = DAT_PROPNUM; goto symbol; case TOKTFUNCTION: dat = DAT_FNADDR; goto symbol; case TOKTOBJECT: dat = DAT_OBJECT; goto symbol; case TOKTDOT: dat = DAT_PROPNUM; /* FALLTHROUGH */ symbol: emtbyte(ctx, dat); emtint2(ctx, (ushort)ele->emtleval); continue; default: assert(FALSE); break; } /* if we get here, emit datatype in dat, plus value */ emtbyte(ctx, dat); if (dat != DAT_TRUE && dat != DAT_NIL) emtint4(ctx, ele->emtleval); } oswp2(ctx->emtcxptr + initofs, ctx->emtcxofs - initofs); }
/* write an object given by a symbol table entry */ static void fiowrtobj(void *ctx0, toksdef *t) { fiowcxdef *ctx = (fiowcxdef *)ctx0; uchar buf[TOKNAMMAX + 50]; mcmon obj; mcmcxdef *mctx = ctx->fiowcxmem; errcxdef *ec = ctx->fiowcxerr; osfildef *fp = ctx->fiowcxfp; uint flags = ctx->fiowcxflg; uchar *p; uint siz; uint used; int err = 0; ulong startpos = osfpos(fp); /* set up start of buffer to write */ buf[0] = t->tokstyp; obj = t->toksval; oswp2(buf + 1, obj); switch(t->tokstyp) { case TOKSTOBJ: /* * Mark object as finished with compilation. Note that we must * do this even though tcdmain() does this as well, because * running preinit() might have updated properties since the * last time we marked objects. */ objcomp(mctx, (objnum)obj, ctx->fiowcxdebug); /* get the object's size information */ p = mcmlck(mctx, (mcmon)obj); siz = mcmobjsiz(mctx, (mcmon)obj); /* size in cache */ used = objfree(p); /* size actually used in object */ if (objflg(p) & OBJFINDEX) used += objnprop(p) * 4; goto write_func_or_obj; case TOKSTFUNC: /* size of function is entire object */ p = mcmlck(mctx, (mcmon)obj); siz = used = mcmobjsiz(mctx, (mcmon)obj); write_func_or_obj: /* write type(OBJ) + objnum + size + sizeused */ oswp2(buf+3, siz); oswp2(buf+5, used); if (osfwb(fp, buf, 7)) err = ERR_WRTGAM; /* write contents of object */ if (flags & FIOFCRYPT) fioxor(p, used, ctx->fiowcxseed, ctx->fiowcxinc); if (osfwb(fp, p, used)) err = ERR_WRTGAM; /* write fast-load record if applicable */ if (ctx->fiowcxffp) { oswp4(buf + 7, startpos); if (osfwb(ctx->fiowcxffp, buf, 11)) err = ERR_WRTGAM; } /* * We're done with the object - delete it so that * it doesn't have to be swapped out (which would * be pointless, since we'll never need it again). */ mcmunlck(mctx, (mcmon)obj); mcmfre(mctx, (mcmon)obj); break; case TOKSTEXTERN: /* all we must write is the name & number of ext func */ buf[3] = t->tokslen; memcpy(buf + 4, t->toksnam, (size_t)t->tokslen); if (osfwb(fp, buf, t->tokslen + 4)) err = ERR_WRTGAM; /* write fast-load record if applicable */ if (ctx->fiowcxffp && osfwb(ctx->fiowcxffp, buf, t->tokslen + 4)) err = ERR_WRTGAM; break; case TOKSTFWDOBJ: case TOKSTFWDFN: { int e = (t->tokstyp == TOKSTFWDFN ? ERR_UNDEFF : ERR_UNDEFO); if (flags & FIOFBIN) { /* write record for the forward reference */ p = mcmlck(mctx, (mcmon)obj); siz = mcmobjsiz(mctx, (mcmon)obj); oswp2(buf+3, siz); if (osfwb(fp, buf, 5) || osfwb(fp, p, siz)) err = ERR_WRTGAM; } else { /* log the undefined-object error */ sup_log_undefobj(mctx, ec, e, t->toksnam, (int)t->tokslen, obj); /* count the undefined object */ ++(ctx->fiowcxund); /* * we don't need this object any longer - delete it so * that we don't have to bother swapping it in or out */ mcmfre(mctx, (mcmon)obj); } } break; } /* if an error occurred, signal it */ if (err) errsig(ec, err); }
/* * Write the stream, its anchors, and its fixups to an object file. */ void CTcDataStream::write_to_object_file(CVmFile *fp) { ulong ofs; CTcStreamAnchor *anchor; long cnt; /* * First, write the data stream bytes. Write the length prefix * followed by the data. Just blast the whole thing out in one huge * byte stream, one page at a time. */ fp->write_int4(ofs_); /* write the data one page at a time */ for (ofs = 0 ; ofs < ofs_ ; ) { size_t cur; /* * write out one whole page, or the balance of the current page * if we have less than a whole page remaining */ cur = TCCS_PAGE_SIZE; if (ofs + cur > ofs_) cur = (size_t)(ofs_ - ofs); /* write out this chunk */ fp->write_bytes(calc_addr(ofs), cur); /* move to the next page's offset */ ofs += cur; } /* count the anchors */ for (cnt = 0, anchor = first_anchor_ ; anchor != 0 ; anchor = anchor->nxt_, ++cnt) ; /* write the count */ fp->write_int4(cnt); /* * Write all of the anchors, and all of their fixups. (We have the * code to write the anchor and fixup information in-line here for * efficiency - there will normally be a large number of these tiny * objects, so anything we can do to improve the speed of this loop * will help quite a lot in the overall write performance.) */ for (anchor = first_anchor_ ; anchor != 0 ; anchor = anchor->nxt_) { char buf[6]; /* write the stream offset */ oswp4(buf, anchor->get_ofs()); /* * If the anchor has an external fixup list, write the symbol's * name to the file; otherwise write a zero length to indicate * that we have an internal fixup list. */ if (anchor->get_fixup_owner_sym() == 0) { /* no external list - indicate with a zero symbol length */ oswp2(buf+4, 0); fp->write_bytes(buf, 6); } else { /* external list - write the symbol length and name */ oswp2(buf+4, anchor->get_fixup_owner_sym()->get_sym_len()); fp->write_bytes(buf, 6); fp->write_bytes(anchor->get_fixup_owner_sym()->get_sym(), anchor->get_fixup_owner_sym()->get_sym_len()); } /* write the fixup list */ CTcAbsFixup:: write_fixup_list_to_object_file(fp, *anchor->fixup_list_head_); } }
/* write game to binary file */ static void fiowrt1(mcmcxdef *mctx, voccxdef *vctx, tokcxdef *tokctx, tokthdef *tab, uchar *fmts, uint fmtl, osfildef *fp, uint flags, objnum preinit, int extc, uint prpcnt, char *filever) { int i; int j; int k; uchar buf[TOKNAMMAX + 50]; errcxdef *ec = vctx->voccxerr; ulong fpos; int obj; vocidef ***vpg; vocidef **v; objnum *sc; vocdef *voc; vocwdef *vw; vocdef **vhsh; struct tm *tblock; time_t timer; fiowcxdef cbctx; /* callback context for toktheach */ uint xor_seed = 63; uint xor_inc = 64; char *vsnhdr; uint vsnlen; char fastnamebuf[OSFNMAX]; /* fast-load record temp file name */ long flag_seek; /* generate appropriate file version */ switch(filever[0]) { case 'a': /* generate .GAM compatible with pre-2.0.15 runtimes */ vsnhdr = FIOVSNHDR2; vsnlen = sizeof(FIOVSNHDR2); xor_seed = 17; /* use old xor values */ xor_inc = 29; break; case 'b': /* generate 2.0.15+ format */ vsnhdr = FIOVSNHDR3; vsnlen = sizeof(FIOVSNHDR3); break; case 'c': case '*': /* current version */ vsnhdr = FIOVSNHDR; vsnlen = sizeof(FIOVSNHDR); break; default: errsig(ec, ERR_WRTVSN); } /* write file header and version header */ if (osfwb(fp, FIOFILHDR, sizeof(FIOFILHDR)) || osfwb(fp, vsnhdr, vsnlen)) errsig(ec, ERR_WRTGAM); /* * write the flags - remember where we wrote it in case we need to * change the flags later */ flag_seek = osfpos(fp); oswp2(buf, flags); if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM); /* write the timestamp */ timer = time(NULL); tblock = localtime(&timer); strcpy(vctx->voccxtim, asctime(tblock)); if (osfwb(fp, vctx->voccxtim, (size_t)26)) errsig(ec, ERR_WRTGAM); /* write xor parameters if generating post 2.0.15 .GAM file */ if (filever[0] != 'a') { fpos = fiowhd(fp, ec, "\003XSI"); buf[0] = xor_seed; buf[1] = xor_inc; if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM); fiowcls(fp, ec, fpos); } /* write count of external functions */ if (extc) { fpos = fiowhd(fp, ec, "\006EXTCNT"); oswp2(buf, extc); /* write the external function count */ if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM); /* write XFCN-seek-location header if post 2.0.15 file version */ if (filever[0] != 'a') { oswp4(buf, 0); /* placeholder - TADSRSC sets this up later */ if (osfwb(fp, buf, 4)) errsig(ec, ERR_WRTGAM); } /* close the resource */ fiowcls(fp, ec, fpos); } /* * write the character set information, if a character set was * specified */ if (G_cmap_id[0] != '\0') { size_t len; /* this is not allowed with explicit file versions a, b, or c */ if (filever[0] == 'a' || filever[0] == 'b' || filever[0] == 'c') errsig(ec, ERR_VNOCTAB); /* write out the CHRSET resource header */ fpos = fiowhd(fp, ec, "\006CHRSET"); /* write out the ID and LDESC of the internal character set */ len = strlen(G_cmap_ldesc) + 1; oswp2(buf, len); if (osfwb(fp, G_cmap_id, 4) || osfwb(fp, buf, 2) || osfwb(fp, G_cmap_ldesc, len)) errsig(ec, ERR_WRTGAM); /* close the resource */ fiowcls(fp, ec, fpos); } /* write OBJ resource header */ fpos = fiowhd(fp, ec, "\003OBJ"); /* set up the symbol table callback context for writing the objects */ cbctx.fiowcxmem = mctx; cbctx.fiowcxerr = ec; cbctx.fiowcxfp = fp; cbctx.fiowcxund = 0; cbctx.fiowcxseed = xor_seed; cbctx.fiowcxinc = xor_inc; cbctx.fiowcxdebug = (flags & FIOFSYM); if (flags & FIOFFAST) { /* try creating the temp file */ cbctx.fiowcxffp = os_create_tempfile(0, fastnamebuf); /* if that failed, we don't have a fast-load table after all */ if (cbctx.fiowcxffp == 0) { long curpos; char flag_buf[2]; /* clear the fast-load flag */ flags &= ~FIOFFAST; /* * go back to the flags we wrote to the .gam file header, and * re-write the new flags without the fast-load bit - since * we're not going to write a fast-load table, we don't want * readers thinking they're going to find one */ /* first, remember where we are right now */ curpos = osfpos(fp); /* seek back to the flags and re-write the new flags */ osfseek(fp, flag_seek, OSFSK_SET); oswp2(flag_buf, flags); if (osfwb(fp, flag_buf, 2)) errsig(ec, ERR_WRTGAM); /* seek back to where we started */ osfseek(fp, curpos, OSFSK_SET); } } else cbctx.fiowcxffp = (osfildef *)0; cbctx.fiowcxflg = flags; /* go through symbol table, and write each object */ toktheach((toktdef *)tab, fiowrtobj, &cbctx); /* also write all objects created with 'new' */ for (vpg = vctx->voccxinh, i = 0 ; i < VOCINHMAX ; ++vpg, ++i) { objnum obj; if (!*vpg) continue; for (v = *vpg, obj = (i << 8), j = 0 ; j < 256 ; ++v, ++obj, ++j) { /* if the object was dynamically allocated, write it out */ if (*v && (*v)->vociflg & VOCIFNEW) { toksdef t; /* clear the 'new' flag, as this is a static object now */ (*v)->vociflg &= ~VOCIFNEW; /* set up a toksdef, and write it out */ t.tokstyp = TOKSTOBJ; t.toksval = obj; fiowrtobj(&cbctx, &t); } } } /* close the resource */ fiowcls(fp, ec, fpos); /* copy fast-load records to output file if applicable */ if (cbctx.fiowcxffp) { osfildef *fp2 = cbctx.fiowcxffp; char copybuf[1024]; ulong len; ulong curlen; /* start with resource header for fast-load records */ fpos = fiowhd(fp, ec, "\003FST"); /* get length of temp file, then rewind it */ len = osfpos(fp2); osfseek(fp2, 0L, OSFSK_SET); /* copy the whole thing to the output file */ while (len) { curlen = (len > sizeof(copybuf) ? sizeof(copybuf) : len); if (osfrb(fp2, copybuf, (size_t)curlen) || osfwb(fp, copybuf, (size_t)curlen)) errsig(ec, ERR_WRTGAM); len -= curlen; } /* close the fast-load resource */ fiowcls(fp, ec, fpos); /* close and delete temp file */ osfcls(fp2); osfdel_temp(fastnamebuf); } /* write vocabulary inheritance records - start with header */ fpos = fiowhd(fp, ec, "\003INH"); /* go through inheritance records and write to file */ for (vpg = vctx->voccxinh, i = 0 ; i < VOCINHMAX ; ++vpg, ++i) { if (!*vpg) continue; for (v = *vpg, obj = (i << 8), j = 0 ; j < 256 ; ++v, ++obj, ++j) { if (*v) { buf[0] = (*v)->vociflg; oswp2(buf + 1, obj); oswp2(buf + 3, (*v)->vociloc); oswp2(buf + 5, (*v)->vociilc); oswp2(buf + 7, (*v)->vocinsc); for (k = 0, sc = (*v)->vocisc ; k < (*v)->vocinsc ; ++sc, ++k) { if (k + 9 >= sizeof(buf)) errsig(ec, ERR_FIOMSC); oswp2(buf + 9 + (k << 1), (*sc)); } if (osfwb(fp, buf, 9 + (2 * (*v)->vocinsc))) errsig(ec, ERR_WRTGAM); } } } /* close resource */ fiowcls(fp, ec, fpos); /* write format strings */ if (fmtl) { fpos = fiowhd(fp, ec, "\006FMTSTR"); oswp2(buf, fmtl); if (flags & FIOFCRYPT) fioxor(fmts, fmtl, xor_seed, xor_inc); if (osfwb(fp, buf, 2) || osfwb(fp, fmts, fmtl)) errsig(ec, ERR_WRTGAM); fiowcls(fp, ec, fpos); } /* write preinit if preinit object was specified */ if (flags & FIOFPRE) { fpos = fiowhd(fp, ec, "\007PREINIT"); oswp2(buf, preinit); if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM); fiowcls(fp, ec, fpos); } /* write required objects out of voccxdef */ fpos = fiowhd(fp, ec, "\003REQ"); fiowrq(ec, fp, vctx->voccxme); fiowrq(ec, fp, vctx->voccxvtk); fiowrq(ec, fp, vctx->voccxstr); fiowrq(ec, fp, vctx->voccxnum); fiowrq(ec, fp, vctx->voccxprd); fiowrq(ec, fp, vctx->voccxvag); fiowrq(ec, fp, vctx->voccxini); fiowrq(ec, fp, vctx->voccxpre); fiowrq(ec, fp, vctx->voccxper); fiowrq(ec, fp, vctx->voccxprom); fiowrq(ec, fp, vctx->voccxpdis); fiowrq(ec, fp, vctx->voccxper2); fiowrq(ec, fp, vctx->voccxpdef); fiowrq(ec, fp, vctx->voccxpask); fiowrq(ec, fp, vctx->voccxppc); fiowrq(ec, fp, vctx->voccxpask2); fiowrq(ec, fp, vctx->voccxperp); fiowrq(ec, fp, vctx->voccxpostprom); fiowrq(ec, fp, vctx->voccxinitrestore); fiowrq(ec, fp, vctx->voccxpuv); fiowrq(ec, fp, vctx->voccxpnp); fiowrq(ec, fp, vctx->voccxpostact); fiowrq(ec, fp, vctx->voccxendcmd); fiowrq(ec, fp, vctx->voccxprecmd); fiowrq(ec, fp, vctx->voccxpask3); fiowrq(ec, fp, vctx->voccxpre2); fiowrq(ec, fp, vctx->voccxpdef2); fiowcls(fp, ec, fpos); /* write compound words */ if (vctx->voccxcpl) { fpos = fiowhd(fp, ec, "\004CMPD"); oswp2(buf, vctx->voccxcpl); if (flags & FIOFCRYPT) fioxor((uchar *)vctx->voccxcpp, (uint)vctx->voccxcpl, xor_seed, xor_inc); if (osfwb(fp, buf, 2) || osfwb(fp, vctx->voccxcpp, (uint)vctx->voccxcpl)) errsig(ec, ERR_WRTGAM); fiowcls(fp, ec, fpos); } /* write special words */ if (vctx->voccxspl) { fpos = fiowhd(fp, ec, "\010SPECWORD"); oswp2(buf, vctx->voccxspl); if (flags & FIOFCRYPT) fioxor((uchar *)vctx->voccxspp, (uint)vctx->voccxspl, xor_seed, xor_inc); if (osfwb(fp, buf, 2) || osfwb(fp, vctx->voccxspp, (uint)vctx->voccxspl)) errsig(ec, ERR_WRTGAM); fiowcls(fp, ec, fpos); } /* write vocabulary */ fpos = fiowhd(fp, ec, "\003VOC"); /* go through each hash chain */ for (i = 0, vhsh = vctx->voccxhsh ; i < VOCHASHSIZ ; ++i, ++vhsh) { /* go through each word in this hash chain */ for (voc = *vhsh ; voc ; voc = voc->vocnxt) { /* encrypt the word if desired */ if (flags & FIOFCRYPT) fioxor(voc->voctxt, (uint)(voc->voclen + voc->vocln2), xor_seed, xor_inc); /* go through each object relation attached to the word */ for (vw = vocwget(vctx, voc->vocwlst) ; vw ; vw = vocwget(vctx, vw->vocwnxt)) { /* clear the 'new' flag, as this is a static object now */ vw->vocwflg &= ~VOCFNEW; /* write out this object relation */ oswp2(buf, voc->voclen); oswp2(buf+2, voc->vocln2); oswp2(buf+4, vw->vocwtyp); oswp2(buf+6, vw->vocwobj); oswp2(buf+8, vw->vocwflg); if (osfwb(fp, buf, 10) || osfwb(fp, voc->voctxt, voc->voclen + voc->vocln2)) errsig(ec, ERR_WRTGAM); } } } fiowcls(fp, ec, fpos); /* write the symbol table, if desired */ if (flags & FIOFSYM) { fpos = fiowhd(fp, ec, "\006SYMTAB"); toktheach((toktdef *)tab, fiowrtsym, &cbctx); /* indicate last symbol with a length of zero */ buf[0] = 0; if (osfwb(fp, buf, 4)) errsig(ec, ERR_WRTGAM); fiowcls(fp, ec, fpos); } /* write line source chain, if desired */ if ((flags & (FIOFLIN | FIOFLIN2)) != 0 && vctx->voccxrun->runcxdbg != 0) { lindef *lin; /* write the SRC header */ fpos = fiowhd(fp, ec, "\003SRC"); /* write the line records */ for (lin = vctx->voccxrun->runcxdbg->dbgcxlin ; lin ; lin = lin->linnxt) { /* write this record */ if (linwrt(lin, fp)) errsig(ec, ERR_WRTGAM); } /* done with this section */ fiowcls(fp, ec, fpos); /* * if we have new-style line records, put a SRC2 header (with no * block contents) in the file, so that the debugger realizes * that it has new-style line records (with line numbers rather * than seek offsets) */ if ((flags & FIOFLIN2) != 0) { fpos = fiowhd(fp, ec, "\004SRC2"); fiowcls(fp, ec, fpos); } } /* if writing a precompiled header, write some more information */ if (flags & FIOFBIN) { /* write property count */ fpos = fiowhd(fp, ec, "\006PRPCNT"); oswp2(buf, prpcnt); if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM); fiowcls(fp, ec, fpos); /* write preprocessor symbol table */ fpos = fiowhd(fp, ec, "\006TADSPP"); tok_write_defines(tokctx, fp, ec); fiowcls(fp, ec, fpos); } /* write end-of-file resource header */ (void)fiowhd(fp, ec, "\004$EOF"); osfcls(fp); /* if there are undefined functions/objects, signal an error */ if (cbctx.fiowcxund) errsig(ec, ERR_UNDEF); }
/* set up contents property for load-on-demand */ void supcont(void *ctx0, objnum obj, prpnum prp) { supcxdef *ctx = (supcxdef *)ctx0; vocidef ***vpg; vocidef **v; voccxdef *voc = ctx->supcxvoc; int i; int j; int len = 2; objnum chi; objnum loc; /* be sure the buffer is allocated */ if (!ctx->supcxbuf) { ctx->supcxlen = 512; ctx->supcxbuf = mchalo(ctx->supcxerr, ctx->supcxlen, "supcont"); } assert(prp == PRP_CONTENTS); /* the only thing that makes sense */ for (vpg = voc->voccxinh, i = 0 ; i < VOCINHMAX ; ++vpg, ++i) { if (!*vpg) continue; /* no entries on this page */ for (v = *vpg, chi = (i << 8), j = 0 ; j < 256 ; ++v, ++chi, ++j) { /* if there's no record at this location, skip it */ if (!*v) continue; /* inherit the location if it hasn't been set to any value */ if ((*v)->vociloc == MCMONINV && !((*v)->vociflg & VOCIFLOCNIL)) loc = (*v)->vociilc; else loc = (*v)->vociloc; /* if this object is in the indicated location, add it */ if (loc == obj && !((*v)->vociflg & VOCIFCLASS)) { /* see if we have room in list buffer; expand buffer if not */ if (len + 3 > ctx->supcxlen) { uchar *newbuf; /* allocate a new buffer */ newbuf = mchalo(ctx->supcxerr, (len + 512), "supcont"); /* copy the old buffer's contents into the new buffer */ memcpy(newbuf, ctx->supcxbuf, ctx->supcxlen); /* remember the new buffer length */ ctx->supcxlen = len + 512; /* free the old buffer */ mchfre(ctx->supcxbuf); /* remember the new buffer */ ctx->supcxbuf = newbuf; /* sanity check for integer overflow */ if (len + 3 > ctx->supcxlen) errsig(ctx->supcxmem->mcmcxgl->mcmcxerr, ERR_SUPOVF); } ctx->supcxbuf[len] = DAT_OBJECT; oswp2(ctx->supcxbuf + len + 1, chi); len += 3; } } } oswp2(ctx->supcxbuf, len); objsetp(ctx->supcxmem, obj, prp, DAT_LIST, ctx->supcxbuf, ctx->supcxrun->runcxundo); }
/* process an operation */ static void procop(osfildef *fpout, opdef *op, ulong *first_xfcn) { osfildef *fpin; char buf[128]; uint fsiz; ulong sizpos; ulong endpos; /* remember location of first resource if necessary */ if (fpout && *first_xfcn == 0) *first_xfcn = osfpos(fpout); fpin = osfoprb(op->opfile, OSFTGAME); if (fpin == 0) { rscptf("%s: ", op->opfile); errexit("unable to open file", 1); } /* get file size */ osfseek(fpin, 0L, OSFSK_END); fsiz = (uint)osfpos(fpin); osfseek(fpin, 0L, OSFSK_SET); /* set up the resource type part of the header */ switch(op->oprestype) { case RESTYPE_XFCN: buf[0] = 4; memcpy(buf + 1, "XFCN", 4); break; case RESTYPE_HTML: buf[0] = 4; memcpy(buf + 1, "HTML", 3); break; } /* set up the rest of the header */ if (osfwb(fpout, buf, buf[0] + 1)) errexit("error writing resource", 1); sizpos = osfpos(fpout); /* remember where size field goes */ oswp4(buf, 0); if (osfwb(fpout, buf, 4)) errexit("error writing resource", 1); /* set up the header */ oswp2(buf, fsiz); buf[2] = strlen(op->opres); strcpy(buf + 3, op->opres); if (osfwb(fpout, buf, (uint)(buf[2] + 3))) errexit("error writing resource", 1); /* copy the resource to the output */ copybytes(fpin, fpout, fsiz); /* write end position in the resource header */ endpos = osfpos(fpout); oswp4(buf, endpos); osfseek(fpout, sizpos, OSFSK_SET); if (osfwb(fpout, buf, 4)) errexit("error writing resource", 1); /* seek back to the end of the resource in the output file */ osfseek(fpout, endpos, OSFSK_SET); /* done with the input file */ osfcls(fpin); }