Imported Upstream version 6.33.1~b2+dfsg.1
[debian_inform6.git] / src / files.c
blobce34787b37528d0eabab9d7e035573258b7432d1
1 /* ------------------------------------------------------------------------- */
2 /* "files" : File handling for source code, the transcript file and the */
3 /* debugging information file; file handling and splicing of */
4 /* the output file. */
5 /* */
6 /* Note that filenaming conventions are left to the top-level */
7 /* routines in "inform.c", since they are tied up with ICL */
8 /* settings and are very host OS-dependent. */
9 /* */
10 /* Part of Inform 6.33 */
11 /* copyright (c) Graham Nelson 1993 - 2014 */
12 /* */
13 /* ------------------------------------------------------------------------- */
15 #include "header.h"
17 int input_file; /* Number of source files so far */
19 int32 total_chars_read; /* Characters read in (from all
20 source files put together) */
22 static int checksum_low_byte, /* For calculating the Z-machine's */
23 checksum_high_byte; /* "verify" checksum */
25 static int32 checksum_long; /* For the Glulx checksum, */
26 static int checksum_count; /* similarly */
28 /* ------------------------------------------------------------------------- */
29 /* Most of the information about source files is kept by "lexer.c"; this */
30 /* level is only concerned with file names and handles. */
31 /* ------------------------------------------------------------------------- */
33 FileId *InputFiles=NULL; /* Ids for all the source files */
34 static char *filename_storage, /* Translated filenames */
35 *filename_storage_p;
36 static int filename_storage_left;
38 /* ------------------------------------------------------------------------- */
39 /* When emitting debug information, we won't have addresses of routines, */
40 /* sequence points, Glulx objects (addresses of Z-machine objects aren't */
41 /* needed), globals, arrays, or grammar lines. We only have their */
42 /* offsets from base addresses, which won't be known until the end of */
43 /* compilation. Since everything else in the relevant debug records is */
44 /* known much earlier and is less convenient to store up, we emit the */
45 /* debug records with a placeholder value and then backpatch these */
46 /* placeholders. The following structs each store either an offset or a */
47 /* symbol index and the point in the debug information file where the */
48 /* corresponding address should be written once the base address is known. */
49 /* ------------------------------------------------------------------------- */
51 #define INITIAL_DEBUG_INFORMATION_BACKPATCH_ALLOCATION 65536
53 typedef struct value_and_backpatch_position_struct
54 { int32 value;
55 fpos_t backpatch_position;
56 } value_and_backpatch_position;
58 typedef struct debug_backpatch_accumulator_struct
59 { int32 number_of_values_to_backpatch;
60 int32 number_of_available_backpatches;
61 value_and_backpatch_position *values_and_backpatch_positions;
62 int32 (* backpatching_function)(int32);
63 } debug_backpatch_accumulator;
65 static debug_backpatch_accumulator object_backpatch_accumulator;
66 static debug_backpatch_accumulator packed_code_backpatch_accumulator;
67 static debug_backpatch_accumulator code_backpatch_accumulator;
68 static debug_backpatch_accumulator global_backpatch_accumulator;
69 static debug_backpatch_accumulator array_backpatch_accumulator;
70 static debug_backpatch_accumulator grammar_backpatch_accumulator;
72 /* ------------------------------------------------------------------------- */
73 /* File handles and names for temporary files. */
74 /* ------------------------------------------------------------------------- */
76 FILE *Temp1_fp=NULL, *Temp2_fp=NULL, *Temp3_fp=NULL;
77 char Temp1_Name[PATHLEN], Temp2_Name[PATHLEN], Temp3_Name[PATHLEN];
79 /* ------------------------------------------------------------------------- */
80 /* Opening and closing source code files */
81 /* ------------------------------------------------------------------------- */
83 #if defined(PC_WIN32) && defined(HAS_REALPATH)
84 #include <windows.h>
85 char *realpath(const char *path, char *resolved_path)
87 return GetFullPathNameA(path,PATHLEN,resolved_path,NULL) != 0 ? resolved_path : 0;
89 #endif
91 extern void load_sourcefile(char *filename_given, int same_directory_flag)
93 /* Meaning: open a new file of Inform source. (The lexer picks up on
94 this by noticing that input_file has increased.) */
96 char name[PATHLEN];
97 #ifdef HAS_REALPATH
98 char absolute_name[PATHLEN];
99 #endif
100 int x = 0;
101 FILE *handle;
103 if (input_file == MAX_SOURCE_FILES)
104 memoryerror("MAX_SOURCE_FILES", MAX_SOURCE_FILES);
107 { x = translate_in_filename(x, name, filename_given, same_directory_flag,
108 (input_file==0)?1:0);
109 handle = fopen(name,"r");
110 } while ((handle == NULL) && (x != 0));
112 if (filename_storage_left <= (int)strlen(name))
113 memoryerror("MAX_SOURCE_FILES", MAX_SOURCE_FILES);
115 filename_storage_left -= strlen(name)+1;
116 strcpy(filename_storage_p, name);
117 InputFiles[input_file].filename = filename_storage_p;
119 filename_storage_p += strlen(name)+1;
121 if (debugfile_switch)
122 { debug_file_printf("<source index=\"%d\">", input_file);
123 debug_file_printf("<given-path>");
124 debug_file_print_with_entities(filename_given);
125 debug_file_printf("</given-path>");
126 #ifdef HAS_REALPATH
127 if (realpath(name, absolute_name))
128 { debug_file_printf("<resolved-path>");
129 debug_file_print_with_entities(absolute_name);
130 debug_file_printf("</resolved-path>");
132 #endif
133 debug_file_printf("<language>Inform 6</language>");
134 debug_file_printf("</source>");
137 InputFiles[input_file].handle = handle;
138 if (InputFiles[input_file].handle==NULL)
139 fatalerror_named("Couldn't open source file", name);
141 if (line_trace_level > 0) printf("\nOpening file \"%s\"\n",name);
143 input_file++;
146 static void close_sourcefile(int file_number)
148 if (InputFiles[file_number-1].handle == NULL) return;
150 /* Close this file. */
152 if (ferror(InputFiles[file_number-1].handle))
153 fatalerror_named("I/O failure: couldn't read from source file",
154 InputFiles[file_number-1].filename);
156 fclose(InputFiles[file_number-1].handle);
158 InputFiles[file_number-1].handle = NULL;
160 if (line_trace_level > 0) printf("\nClosing file\n");
163 extern void close_all_source(void)
164 { int i;
165 for (i=0; i<input_file; i++) close_sourcefile(i+1);
168 /* ------------------------------------------------------------------------- */
169 /* Feeding source code up into the lexical analyser's buffer */
170 /* (see "lexer.c" for its specification) */
171 /* ------------------------------------------------------------------------- */
173 extern int file_load_chars(int file_number, char *buffer, int length)
175 int read_in; FILE *handle;
177 if (file_number-1 > input_file)
178 { buffer[0] = 0; return 1; }
180 handle = InputFiles[file_number-1].handle;
181 if (handle == NULL)
182 { buffer[0] = 0; return 1; }
184 read_in = fread(buffer, 1, length, handle);
185 total_chars_read += read_in;
187 if (read_in == length) return length;
189 close_sourcefile(file_number);
191 if (file_number == 1)
192 { buffer[read_in] = 0;
193 buffer[read_in+1] = 0;
194 buffer[read_in+2] = 0;
195 buffer[read_in+3] = 0;
197 else
198 { buffer[read_in] = '\n';
199 buffer[read_in+1] = ' ';
200 buffer[read_in+2] = ' ';
201 buffer[read_in+3] = ' ';
204 return(-(read_in+4));
207 /* ------------------------------------------------------------------------- */
208 /* Final assembly and output of the story file/module. */
209 /* ------------------------------------------------------------------------- */
211 FILE *sf_handle;
213 static void sf_put(int c)
215 if (!glulx_mode) {
217 /* The checksum is the unsigned sum mod 65536 of the bytes in the
218 story file from 0x0040 (first byte after header) to the end.
220 The link data does not contribute to the checksum of a module. */
222 checksum_low_byte += c;
223 if (checksum_low_byte>=256)
224 { checksum_low_byte-=256;
225 if (++checksum_high_byte==256) checksum_high_byte=0;
229 else {
231 /* The checksum is the unsigned 32-bit sum of the entire story file,
232 considered as a list of 32-bit words, with the checksum field
233 being zero. */
235 switch (checksum_count) {
236 case 0:
237 checksum_long += (((int32)(c & 0xFF)) << 24);
238 break;
239 case 1:
240 checksum_long += (((int32)(c & 0xFF)) << 16);
241 break;
242 case 2:
243 checksum_long += (((int32)(c & 0xFF)) << 8);
244 break;
245 case 3:
246 checksum_long += ((int32)(c & 0xFF));
247 break;
250 checksum_count = (checksum_count+1) & 3;
254 fputc(c, sf_handle);
257 /* Recursive procedure to generate the Glulx compression table. */
259 static void output_compression(int entnum, int32 *size, int *count)
261 huffentity_t *ent = &(huff_entities[entnum]);
262 int32 val;
263 char *cx;
265 sf_put(ent->type);
266 (*size)++;
267 (*count)++;
269 switch (ent->type) {
270 case 0:
271 val = Write_Strings_At + huff_entities[ent->u.branch[0]].addr;
272 sf_put((val >> 24) & 0xFF);
273 sf_put((val >> 16) & 0xFF);
274 sf_put((val >> 8) & 0xFF);
275 sf_put((val) & 0xFF);
276 (*size) += 4;
277 val = Write_Strings_At + huff_entities[ent->u.branch[1]].addr;
278 sf_put((val >> 24) & 0xFF);
279 sf_put((val >> 16) & 0xFF);
280 sf_put((val >> 8) & 0xFF);
281 sf_put((val) & 0xFF);
282 (*size) += 4;
283 output_compression(ent->u.branch[0], size, count);
284 output_compression(ent->u.branch[1], size, count);
285 break;
286 case 1:
287 /* no data */
288 break;
289 case 2:
290 sf_put(ent->u.ch);
291 (*size) += 1;
292 break;
293 case 3:
294 cx = (char *)abbreviations_at + ent->u.val*MAX_ABBREV_LENGTH;
295 while (*cx) {
296 sf_put(*cx);
297 cx++;
298 (*size) += 1;
300 sf_put('\0');
301 (*size) += 1;
302 break;
303 case 4:
304 val = unicode_usage_entries[ent->u.val].ch;
305 sf_put((val >> 24) & 0xFF);
306 sf_put((val >> 16) & 0xFF);
307 sf_put((val >> 8) & 0xFF);
308 sf_put((val) & 0xFF);
309 (*size) += 4;
310 break;
311 case 9:
312 val = abbreviations_offset + 4 + ent->u.val*4;
313 sf_put((val >> 24) & 0xFF);
314 sf_put((val >> 16) & 0xFF);
315 sf_put((val >> 8) & 0xFF);
316 sf_put((val) & 0xFF);
317 (*size) += 4;
318 break;
322 static void output_file_z(void)
323 { FILE *fin; char new_name[PATHLEN];
324 int32 length, blanks=0, size, i, j, offset;
325 uint32 code_length, size_before_code, next_cons_check;
326 int use_function;
328 ASSERT_ZCODE();
330 /* At this point, construct_storyfile() has just been called. */
332 /* Enter the length information into the header. */
334 length=((int32) Write_Strings_At) + static_strings_extent;
335 if (module_switch) length += link_data_size +
336 zcode_backpatch_size +
337 zmachine_backpatch_size;
339 while ((length%length_scale_factor)!=0) { length++; blanks++; }
340 length=length/length_scale_factor;
341 zmachine_paged_memory[26]=(length & 0xff00)/0x100;
342 zmachine_paged_memory[27]=(length & 0xff);
344 /* To assist interpreters running a paged virtual memory system, Inform
345 writes files which are padded with zeros to the next multiple of
346 0.5K. This calculates the number of bytes of padding needed: */
348 while (((length_scale_factor*length)+blanks-1)%512 != 511) blanks++;
350 translate_out_filename(new_name, Code_Name);
352 sf_handle = fopen(new_name,"wb");
353 if (sf_handle == NULL)
354 fatalerror_named("Couldn't open output file", new_name);
356 #ifdef MAC_MPW
357 /* Set the type and creator to Andrew Plotkin's MaxZip, a popular
358 Z-code interpreter on the Macintosh */
360 if (!module_switch) fsetfileinfo(new_name, 'mxZR', 'ZCOD');
361 #endif
363 /* (1) Output the paged memory. */
365 for (i=0;i<64;i++)
366 fputc(zmachine_paged_memory[i], sf_handle);
367 size = 64;
368 checksum_low_byte = 0;
369 checksum_high_byte = 0;
371 for (i=64; i<Write_Code_At; i++)
372 { sf_put(zmachine_paged_memory[i]); size++;
375 /* (2) Output the compiled code area. */
377 if (temporary_files_switch)
378 { fclose(Temp2_fp);
379 fin=fopen(Temp2_Name,"rb");
380 if (fin==NULL)
381 fatalerror("I/O failure: couldn't reopen temporary file 2");
384 if (!OMIT_UNUSED_ROUTINES) {
385 /* This is the old-fashioned case, which is easy. All of zcode_area
386 (zmachine_pc bytes) will be output. next_cons_check will be
387 ignored, because j will never reach it. */
388 code_length = zmachine_pc;
389 use_function = TRUE;
390 next_cons_check = code_length+1;
392 else {
393 /* With dead function stripping, life is more complicated.
394 j will run from 0 to zmachine_pc, but only code_length of
395 those should be output. next_cons_check is the location of
396 the next function break; that's where we check whether
397 we're in a live function or a dead one.
398 (This logic is simplified by the assumption that a backpatch
399 marker will never straddle a function break.) */
400 if (zmachine_pc != df_total_size_before_stripping)
401 compiler_error("Code size does not match (zmachine_pc and df_total_size).");
402 code_length = df_total_size_after_stripping;
403 use_function = TRUE;
404 next_cons_check = 0;
405 df_prepare_function_iterate();
407 size_before_code = size;
409 j=0;
410 if (!module_switch)
411 for (i=0; i<zcode_backpatch_size; i=i+3)
412 { int long_flag = TRUE;
413 offset
414 = 256*read_byte_from_memory_block(&zcode_backpatch_table, i+1)
415 + read_byte_from_memory_block(&zcode_backpatch_table, i+2);
416 backpatch_error_flag = FALSE;
417 backpatch_marker
418 = read_byte_from_memory_block(&zcode_backpatch_table, i);
419 if (backpatch_marker >= 0x80) long_flag = FALSE;
420 backpatch_marker &= 0x7f;
421 offset = offset + (backpatch_marker/32)*0x10000;
422 while (offset+0x30000 < j) {
423 offset += 0x40000;
424 long_flag = !long_flag;
426 backpatch_marker &= 0x1f;
428 /* All code up until the next backpatch marker gets flushed out
429 as-is. (Unless we're in a stripped-out function.) */
430 while (j<offset) {
431 if (!use_function) {
432 while (j<offset && j<next_cons_check) {
433 /* get dummy value */
434 ((temporary_files_switch)?fgetc(fin):
435 read_byte_from_memory_block(&zcode_area, j));
436 j++;
439 else {
440 while (j<offset && j<next_cons_check) {
441 size++;
442 sf_put((temporary_files_switch)?fgetc(fin):
443 read_byte_from_memory_block(&zcode_area, j));
444 j++;
447 if (j == next_cons_check)
448 next_cons_check = df_next_function_iterate(&use_function);
451 if (long_flag)
452 { int32 v = (temporary_files_switch)?fgetc(fin):
453 read_byte_from_memory_block(&zcode_area, j);
454 v = 256*v + ((temporary_files_switch)?fgetc(fin):
455 read_byte_from_memory_block(&zcode_area, j+1));
456 j += 2;
457 if (use_function) {
458 v = backpatch_value(v);
459 sf_put(v/256); sf_put(v%256);
460 size += 2;
463 else
464 { int32 v = (temporary_files_switch)?fgetc(fin):
465 read_byte_from_memory_block(&zcode_area, j);
466 j++;
467 if (use_function) {
468 v = backpatch_value(v);
469 sf_put(v);
470 size++;
474 if (j > next_cons_check)
475 compiler_error("Backpatch appears to straddle function break");
477 if (backpatch_error_flag)
478 { printf("*** %s zcode offset=%08lx backpatch offset=%08lx ***\n",
479 (long_flag)?"long":"short", (long int) j, (long int) i);
483 /* Flush out the last bit of zcode_area, after the last backpatch
484 marker. */
485 offset = zmachine_pc;
486 while (j<offset) {
487 if (!use_function) {
488 while (j<offset && j<next_cons_check) {
489 /* get dummy value */
490 ((temporary_files_switch)?fgetc(fin):
491 read_byte_from_memory_block(&zcode_area, j));
492 j++;
495 else {
496 while (j<offset && j<next_cons_check) {
497 size++;
498 sf_put((temporary_files_switch)?fgetc(fin):
499 read_byte_from_memory_block(&zcode_area, j));
500 j++;
503 if (j == next_cons_check)
504 next_cons_check = df_next_function_iterate(&use_function);
507 if (temporary_files_switch)
508 { if (ferror(fin))
509 fatalerror("I/O failure: couldn't read from temporary file 2");
510 fclose(fin);
513 if (size_before_code + code_length != size)
514 compiler_error("Code output length did not match");
516 /* (3) Output any null bytes (required to reach a packed address)
517 before the strings area. */
519 while (size<Write_Strings_At) { sf_put(0); size++; }
521 /* (4) Output the static strings area. */
523 if (temporary_files_switch)
524 { fclose(Temp1_fp);
525 fin=fopen(Temp1_Name,"rb");
526 if (fin==NULL)
527 fatalerror("I/O failure: couldn't reopen temporary file 1");
528 for (i=0; i<static_strings_extent; i++) sf_put(fgetc(fin));
529 if (ferror(fin))
530 fatalerror("I/O failure: couldn't read from temporary file 1");
531 fclose(fin);
532 remove(Temp1_Name); remove(Temp2_Name);
534 else
535 for (i=0; i<static_strings_extent; i++) {
536 sf_put(read_byte_from_memory_block(&static_strings_area,i));
537 size++;
540 /* (5) Output the linking data table (in the case of a module). */
542 if (temporary_files_switch)
543 { if (module_switch)
544 { fclose(Temp3_fp);
545 fin=fopen(Temp3_Name,"rb");
546 if (fin==NULL)
547 fatalerror("I/O failure: couldn't reopen temporary file 3");
548 for (j=0; j<link_data_size; j++) sf_put(fgetc(fin));
549 if (ferror(fin))
550 fatalerror("I/O failure: couldn't read from temporary file 3");
551 fclose(fin);
552 remove(Temp3_Name);
555 else
556 if (module_switch)
557 for (i=0; i<link_data_size; i++)
558 sf_put(read_byte_from_memory_block(&link_data_area,i));
560 if (module_switch)
561 { for (i=0; i<zcode_backpatch_size; i++)
562 sf_put(read_byte_from_memory_block(&zcode_backpatch_table, i));
563 for (i=0; i<zmachine_backpatch_size; i++)
564 sf_put(read_byte_from_memory_block(&zmachine_backpatch_table, i));
567 /* (6) Output null bytes to reach a multiple of 0.5K. */
569 while (blanks>0) { sf_put(0); blanks--; }
571 if (ferror(sf_handle))
572 fatalerror("I/O failure: couldn't write to story file");
574 fseek(sf_handle, 28, SEEK_SET);
575 fputc(checksum_high_byte, sf_handle);
576 fputc(checksum_low_byte, sf_handle);
578 if (ferror(sf_handle))
579 fatalerror("I/O failure: couldn't backtrack on story file for checksum");
581 fclose(sf_handle);
583 /* Write a copy of the header into the debugging information file
584 (mainly so that it can be used to identify which story file matches
585 with which debugging info file). */
587 if (debugfile_switch)
588 { debug_file_printf("<story-file-prefix>");
589 for (i = 0; i < 63; i += 3)
590 { if (i == 27)
591 { debug_file_print_base_64_triple
592 (zmachine_paged_memory[27],
593 checksum_high_byte,
594 checksum_low_byte);
595 } else
596 { debug_file_print_base_64_triple
597 (zmachine_paged_memory[i],
598 zmachine_paged_memory[i + 1],
599 zmachine_paged_memory[i + 2]);
602 debug_file_print_base_64_single(zmachine_paged_memory[63]);
603 debug_file_printf("</story-file-prefix>");
606 #ifdef ARCHIMEDES
607 { char settype_command[PATHLEN];
608 sprintf(settype_command, "settype %s %s",
609 new_name, riscos_file_type());
610 system(settype_command);
612 #endif
613 #ifdef MAC_FACE
614 if (module_switch)
615 InformFiletypes (new_name, INF_MODULE_TYPE);
616 else
617 InformFiletypes (new_name, INF_ZCODE_TYPE);
618 #endif
621 static void output_file_g(void)
622 { FILE *fin; char new_name[PATHLEN];
623 int32 size, i, j, offset;
624 int32 VersionNum;
625 uint32 code_length, size_before_code, next_cons_check;
626 int use_function;
627 int first_byte_of_triple, second_byte_of_triple, third_byte_of_triple;
629 ASSERT_GLULX();
631 /* At this point, construct_storyfile() has just been called. */
633 translate_out_filename(new_name, Code_Name);
635 sf_handle = fopen(new_name,"wb+");
636 if (sf_handle == NULL)
637 fatalerror_named("Couldn't open output file", new_name);
639 #ifdef MAC_MPW
640 /* Set the type and creator to Andrew Plotkin's MaxZip, a popular
641 Z-code interpreter on the Macintosh */
643 if (!module_switch) fsetfileinfo(new_name, 'mxZR', 'ZCOD');
644 #endif
646 checksum_long = 0;
647 checksum_count = 0;
649 /* Determine the version number. */
651 VersionNum = 0x00020000;
653 /* Increase for various features the game may have used. */
654 if (no_unicode_chars != 0 || (uses_unicode_features)) {
655 VersionNum = 0x00030000;
657 if (uses_memheap_features) {
658 VersionNum = 0x00030100;
660 if (uses_acceleration_features) {
661 VersionNum = 0x00030101;
663 if (uses_float_features) {
664 VersionNum = 0x00030102;
667 /* And check if the user has requested a specific version. */
668 if (requested_glulx_version) {
669 if (requested_glulx_version < VersionNum) {
670 static char error_message_buff[256];
671 sprintf(error_message_buff, "Version 0x%08lx requested, but \
672 game features require version 0x%08lx", (long)requested_glulx_version, (long)VersionNum);
673 warning(error_message_buff);
675 else {
676 VersionNum = requested_glulx_version;
680 /* (1) Output the header. We use sf_put here, instead of fputc,
681 because the header is included in the checksum. */
683 /* Magic number */
684 sf_put('G');
685 sf_put('l');
686 sf_put('u');
687 sf_put('l');
688 /* Version number. */
689 sf_put((VersionNum >> 24));
690 sf_put((VersionNum >> 16));
691 sf_put((VersionNum >> 8));
692 sf_put((VersionNum));
693 /* RAMSTART */
694 sf_put((Write_RAM_At >> 24));
695 sf_put((Write_RAM_At >> 16));
696 sf_put((Write_RAM_At >> 8));
697 sf_put((Write_RAM_At));
698 /* EXTSTART, or game file size */
699 sf_put((Out_Size >> 24));
700 sf_put((Out_Size >> 16));
701 sf_put((Out_Size >> 8));
702 sf_put((Out_Size));
703 /* ENDMEM, which the game file size plus MEMORY_MAP_EXTENSION */
704 i = Out_Size + MEMORY_MAP_EXTENSION;
705 sf_put((i >> 24));
706 sf_put((i >> 16));
707 sf_put((i >> 8));
708 sf_put((i));
709 /* STACKSIZE */
710 sf_put((MAX_STACK_SIZE >> 24));
711 sf_put((MAX_STACK_SIZE >> 16));
712 sf_put((MAX_STACK_SIZE >> 8));
713 sf_put((MAX_STACK_SIZE));
714 /* Initial function to call. Inform sets things up so that this
715 is the start of the executable-code area. */
716 sf_put((Write_Code_At >> 24));
717 sf_put((Write_Code_At >> 16));
718 sf_put((Write_Code_At >> 8));
719 sf_put((Write_Code_At));
720 /* String-encoding table. */
721 sf_put((Write_Strings_At >> 24));
722 sf_put((Write_Strings_At >> 16));
723 sf_put((Write_Strings_At >> 8));
724 sf_put((Write_Strings_At));
725 /* Checksum -- zero for the moment. */
726 sf_put(0x00);
727 sf_put(0x00);
728 sf_put(0x00);
729 sf_put(0x00);
731 size = GLULX_HEADER_SIZE;
733 /* (1a) Output the eight-byte memory layout identifier. */
735 sf_put('I'); sf_put('n'); sf_put('f'); sf_put('o');
736 sf_put(0); sf_put(1); sf_put(0); sf_put(0);
738 /* (1b) Output the rest of the Inform-specific data. */
740 /* Inform version number */
741 sf_put('0' + ((RELEASE_NUMBER/100)%10));
742 sf_put('.');
743 sf_put('0' + ((RELEASE_NUMBER/10)%10));
744 sf_put('0' + RELEASE_NUMBER%10);
745 /* Glulx back-end version number */
746 sf_put('0' + ((GLULX_RELEASE_NUMBER/100)%10));
747 sf_put('.');
748 sf_put('0' + ((GLULX_RELEASE_NUMBER/10)%10));
749 sf_put('0' + GLULX_RELEASE_NUMBER%10);
750 /* Game release number */
751 sf_put((release_number>>8) & 0xFF);
752 sf_put(release_number & 0xFF);
753 /* Game serial number */
755 char serialnum[8];
756 write_serial_number(serialnum);
757 for (i=0; i<6; i++)
758 sf_put(serialnum[i]);
760 size += GLULX_STATIC_ROM_SIZE;
762 /* (2) Output the compiled code area. */
764 if (temporary_files_switch)
765 { fclose(Temp2_fp);
766 fin=fopen(Temp2_Name,"rb");
767 if (fin==NULL)
768 fatalerror("I/O failure: couldn't reopen temporary file 2");
771 if (!OMIT_UNUSED_ROUTINES) {
772 /* This is the old-fashioned case, which is easy. All of zcode_area
773 (zmachine_pc bytes) will be output. next_cons_check will be
774 ignored, because j will never reach it. */
775 code_length = zmachine_pc;
776 use_function = TRUE;
777 next_cons_check = code_length+1;
779 else {
780 /* With dead function stripping, life is more complicated.
781 j will run from 0 to zmachine_pc, but only code_length of
782 those should be output. next_cons_check is the location of
783 the next function break; that's where we check whether
784 we're in a live function or a dead one.
785 (This logic is simplified by the assumption that a backpatch
786 marker will never straddle a function break.) */
787 if (zmachine_pc != df_total_size_before_stripping)
788 compiler_error("Code size does not match (zmachine_pc and df_total_size).");
789 code_length = df_total_size_after_stripping;
790 use_function = TRUE;
791 next_cons_check = 0;
792 df_prepare_function_iterate();
794 size_before_code = size;
796 j=0;
797 if (!module_switch)
798 for (i=0; i<zcode_backpatch_size; i=i+6) {
799 int data_len;
800 int32 v;
801 offset =
802 (read_byte_from_memory_block(&zcode_backpatch_table, i+2) << 24)
803 | (read_byte_from_memory_block(&zcode_backpatch_table, i+3) << 16)
804 | (read_byte_from_memory_block(&zcode_backpatch_table, i+4) << 8)
805 | (read_byte_from_memory_block(&zcode_backpatch_table, i+5));
806 backpatch_error_flag = FALSE;
807 backpatch_marker =
808 read_byte_from_memory_block(&zcode_backpatch_table, i);
809 data_len =
810 read_byte_from_memory_block(&zcode_backpatch_table, i+1);
812 /* All code up until the next backpatch marker gets flushed out
813 as-is. (Unless we're in a stripped-out function.) */
814 while (j<offset) {
815 if (!use_function) {
816 while (j<offset && j<next_cons_check) {
817 /* get dummy value */
818 ((temporary_files_switch)?fgetc(fin):
819 read_byte_from_memory_block(&zcode_area, j));
820 j++;
823 else {
824 while (j<offset && j<next_cons_check) {
825 size++;
826 sf_put((temporary_files_switch)?fgetc(fin):
827 read_byte_from_memory_block(&zcode_area, j));
828 j++;
831 if (j == next_cons_check)
832 next_cons_check = df_next_function_iterate(&use_function);
835 /* Write out the converted value of the backpatch marker.
836 (Unless we're in a stripped-out function.) */
837 switch (data_len) {
839 case 4:
840 v = ((temporary_files_switch)?fgetc(fin):
841 read_byte_from_memory_block(&zcode_area, j));
842 v = (v << 8) | ((temporary_files_switch)?fgetc(fin):
843 read_byte_from_memory_block(&zcode_area, j+1));
844 v = (v << 8) | ((temporary_files_switch)?fgetc(fin):
845 read_byte_from_memory_block(&zcode_area, j+2));
846 v = (v << 8) | ((temporary_files_switch)?fgetc(fin):
847 read_byte_from_memory_block(&zcode_area, j+3));
848 j += 4;
849 if (!use_function)
850 break;
851 v = backpatch_value(v);
852 sf_put((v >> 24) & 0xFF);
853 sf_put((v >> 16) & 0xFF);
854 sf_put((v >> 8) & 0xFF);
855 sf_put((v) & 0xFF);
856 size += 4;
857 break;
859 case 2:
860 v = ((temporary_files_switch)?fgetc(fin):
861 read_byte_from_memory_block(&zcode_area, j));
862 v = (v << 8) | ((temporary_files_switch)?fgetc(fin):
863 read_byte_from_memory_block(&zcode_area, j+1));
864 j += 2;
865 if (!use_function)
866 break;
867 v = backpatch_value(v);
868 if (v >= 0x10000) {
869 printf("*** backpatch value does not fit ***\n");
870 backpatch_error_flag = TRUE;
872 sf_put((v >> 8) & 0xFF);
873 sf_put((v) & 0xFF);
874 size += 2;
875 break;
877 case 1:
878 v = ((temporary_files_switch)?fgetc(fin):
879 read_byte_from_memory_block(&zcode_area, j));
880 j += 1;
881 if (!use_function)
882 break;
883 v = backpatch_value(v);
884 if (v >= 0x100) {
885 printf("*** backpatch value does not fit ***\n");
886 backpatch_error_flag = TRUE;
888 sf_put((v) & 0xFF);
889 size += 1;
890 break;
892 default:
893 printf("*** unknown backpatch data len = %d ***\n",
894 data_len);
895 backpatch_error_flag = TRUE;
898 if (j > next_cons_check)
899 compiler_error("Backpatch appears to straddle function break");
901 if (backpatch_error_flag) {
902 printf("*** %d bytes zcode offset=%08lx backpatch offset=%08lx ***\n",
903 data_len, (long int) j, (long int) i);
907 /* Flush out the last bit of zcode_area, after the last backpatch
908 marker. */
909 offset = zmachine_pc;
910 while (j<offset) {
911 if (!use_function) {
912 while (j<offset && j<next_cons_check) {
913 /* get dummy value */
914 ((temporary_files_switch)?fgetc(fin):
915 read_byte_from_memory_block(&zcode_area, j));
916 j++;
919 else {
920 while (j<offset && j<next_cons_check) {
921 size++;
922 sf_put((temporary_files_switch)?fgetc(fin):
923 read_byte_from_memory_block(&zcode_area, j));
924 j++;
927 if (j == next_cons_check)
928 next_cons_check = df_next_function_iterate(&use_function);
931 if (temporary_files_switch)
932 { if (ferror(fin))
933 fatalerror("I/O failure: couldn't read from temporary file 2");
934 fclose(fin);
937 if (size_before_code + code_length != size)
938 compiler_error("Code output length did not match");
940 /* (4) Output the static strings area. */
942 if (temporary_files_switch) {
943 fseek(Temp1_fp, 0, SEEK_SET);
946 int32 ix, lx;
947 int ch, jx, curbyte, bx;
948 int depth, checkcount;
949 huffbitlist_t *bits;
950 int32 origsize;
952 origsize = size;
954 if (compression_switch) {
956 /* The 12-byte table header. */
957 lx = compression_table_size;
958 sf_put((lx >> 24) & 0xFF);
959 sf_put((lx >> 16) & 0xFF);
960 sf_put((lx >> 8) & 0xFF);
961 sf_put((lx) & 0xFF);
962 size += 4;
963 sf_put((no_huff_entities >> 24) & 0xFF);
964 sf_put((no_huff_entities >> 16) & 0xFF);
965 sf_put((no_huff_entities >> 8) & 0xFF);
966 sf_put((no_huff_entities) & 0xFF);
967 size += 4;
968 lx = Write_Strings_At + 12;
969 sf_put((lx >> 24) & 0xFF);
970 sf_put((lx >> 16) & 0xFF);
971 sf_put((lx >> 8) & 0xFF);
972 sf_put((lx) & 0xFF);
973 size += 4;
975 checkcount = 0;
976 output_compression(huff_entity_root, &size, &checkcount);
977 if (checkcount != no_huff_entities)
978 compiler_error("Compression table count mismatch.");
981 if (size - origsize != compression_table_size)
982 compiler_error("Compression table size mismatch.");
984 origsize = size;
986 for (lx=0, ix=0; lx<no_strings; lx++) {
987 int escapelen=0, escapetype=0;
988 int done=FALSE;
989 int32 escapeval;
990 if (compression_switch)
991 sf_put(0xE1); /* type byte -- compressed string */
992 else
993 sf_put(0xE0); /* type byte -- non-compressed string */
994 size++;
995 jx = 0;
996 curbyte = 0;
997 while (!done) {
998 if (temporary_files_switch)
999 ch = fgetc(Temp1_fp);
1000 else
1001 ch = read_byte_from_memory_block(&static_strings_area, ix);
1002 ix++;
1003 if (ix > static_strings_extent || ch < 0)
1004 compiler_error("Read too much not-yet-compressed text.");
1006 if (escapelen == -1) {
1007 escapelen = 0;
1008 if (ch == '@') {
1009 ch = '@';
1011 else if (ch == '0') {
1012 ch = '\0';
1014 else if (ch == 'A' || ch == 'D' || ch == 'U') {
1015 escapelen = 4;
1016 escapetype = ch;
1017 escapeval = 0;
1018 continue;
1020 else {
1021 compiler_error("Strange @ escape in processed text.");
1024 else if (escapelen) {
1025 escapeval = (escapeval << 4) | ((ch-'A') & 0x0F);
1026 escapelen--;
1027 if (escapelen == 0) {
1028 if (escapetype == 'A') {
1029 ch = huff_abbrev_start+escapeval;
1031 else if (escapetype == 'D') {
1032 ch = huff_dynam_start+escapeval;
1034 else if (escapetype == 'U') {
1035 ch = huff_unicode_start+escapeval;
1037 else {
1038 compiler_error("Strange @ escape in processed text.");
1041 else
1042 continue;
1044 else {
1045 if (ch == '@') {
1046 escapelen = -1;
1047 continue;
1049 if (ch == 0) {
1050 ch = 256;
1051 done = TRUE;
1055 if (compression_switch) {
1056 bits = &(huff_entities[ch].bits);
1057 depth = huff_entities[ch].depth;
1058 for (bx=0; bx<depth; bx++) {
1059 if (bits->b[bx / 8] & (1 << (bx % 8)))
1060 curbyte |= (1 << jx);
1061 jx++;
1062 if (jx == 8) {
1063 sf_put(curbyte);
1064 size++;
1065 curbyte = 0;
1066 jx = 0;
1070 else {
1071 if (ch >= huff_dynam_start) {
1072 sf_put(' '); sf_put(' '); sf_put(' ');
1073 size += 3;
1075 else if (ch >= huff_abbrev_start) {
1076 /* nothing */
1078 else {
1079 /* 256, the string terminator, comes out as zero */
1080 sf_put(ch & 0xFF);
1081 size++;
1085 if (compression_switch && jx) {
1086 sf_put(curbyte);
1087 size++;
1091 if (size - origsize != compression_string_size)
1092 compiler_error("Compression string size mismatch.");
1096 /* (4.5) Output any null bytes (required to reach a GPAGESIZE address)
1097 before RAMSTART. */
1099 while (size % GPAGESIZE) { sf_put(0); size++; }
1101 /* (5) Output RAM. */
1103 for (i=0; i<RAM_Size; i++)
1104 { sf_put(zmachine_paged_memory[i]); size++;
1107 if (ferror(sf_handle))
1108 fatalerror("I/O failure: couldn't write to story file");
1110 fseek(sf_handle, 32, SEEK_SET);
1111 fputc((checksum_long >> 24) & 0xFF, sf_handle);
1112 fputc((checksum_long >> 16) & 0xFF, sf_handle);
1113 fputc((checksum_long >> 8) & 0xFF, sf_handle);
1114 fputc((checksum_long) & 0xFF, sf_handle);
1116 if (ferror(sf_handle))
1117 fatalerror("I/O failure: couldn't backtrack on story file for checksum");
1119 /* Write a copy of the first 64 bytes into the debugging information file
1120 (mainly so that it can be used to identify which story file matches with
1121 which debugging info file). */
1123 if (debugfile_switch)
1124 { fseek(sf_handle, 0L, SEEK_SET);
1125 debug_file_printf("<story-file-prefix>");
1126 for (i = 0; i < 63; i += 3)
1127 { first_byte_of_triple = fgetc(sf_handle);
1128 second_byte_of_triple = fgetc(sf_handle);
1129 third_byte_of_triple = fgetc(sf_handle);
1130 debug_file_print_base_64_triple
1131 (first_byte_of_triple,
1132 second_byte_of_triple,
1133 third_byte_of_triple);
1135 debug_file_print_base_64_single(fgetc(sf_handle));
1136 debug_file_printf("</story-file-prefix>");
1139 fclose(sf_handle);
1141 #ifdef ARCHIMEDES
1142 { char settype_command[PATHLEN];
1143 sprintf(settype_command, "settype %s %s",
1144 new_name, riscos_file_type());
1145 system(settype_command);
1147 #endif
1148 #ifdef MAC_FACE
1149 if (module_switch)
1150 InformFiletypes (new_name, INF_MODULE_TYPE);
1151 else
1152 InformFiletypes (new_name, INF_ZCODE_TYPE);
1153 #endif
1156 extern void output_file(void)
1158 if (!glulx_mode)
1159 output_file_z();
1160 else
1161 output_file_g();
1164 /* ------------------------------------------------------------------------- */
1165 /* Output the text transcript file (only called if there is to be one). */
1166 /* ------------------------------------------------------------------------- */
1168 FILE *transcript_file_handle; int transcript_open;
1170 extern void write_to_transcript_file(char *text)
1171 { fputs(text, transcript_file_handle);
1172 fputc('\n', transcript_file_handle);
1175 extern void open_transcript_file(char *what_of)
1176 { char topline_buffer[256];
1178 transcript_file_handle = fopen(Transcript_Name,"w");
1179 if (transcript_file_handle==NULL)
1180 fatalerror_named("Couldn't open transcript file",
1181 Transcript_Name);
1183 transcript_open = TRUE;
1185 sprintf(topline_buffer, "Transcript of the text of \"%s\"\n\
1186 [From %s]\n", what_of, banner_line);
1187 write_to_transcript_file(topline_buffer);
1190 extern void abort_transcript_file(void)
1191 { if (transcript_switch && transcript_open)
1192 fclose(transcript_file_handle);
1193 transcript_open = FALSE;
1196 extern void close_transcript_file(void)
1197 { char botline_buffer[256];
1198 char sn_buffer[7];
1200 write_serial_number(sn_buffer);
1201 sprintf(botline_buffer, "\n[End of transcript: release %d.%s]\n",
1202 release_number, sn_buffer);
1203 write_to_transcript_file(botline_buffer);
1205 if (ferror(transcript_file_handle))
1206 fatalerror("I/O failure: couldn't write to transcript file");
1207 fclose(transcript_file_handle);
1208 transcript_open = FALSE;
1210 #ifdef ARCHIMEDES
1211 { char settype_command[PATHLEN];
1212 sprintf(settype_command, "settype %s text",
1213 Transcript_Name);
1214 system(settype_command);
1216 #endif
1217 #ifdef MAC_FACE
1218 InformFiletypes (Transcript_Name, INF_TEXT_TYPE);
1219 #endif
1222 /* ------------------------------------------------------------------------- */
1223 /* Access to the debugging information file. */
1224 /* ------------------------------------------------------------------------- */
1226 static FILE *Debug_fp; /* Handle of debugging info file */
1228 static void open_debug_file(void)
1229 { Debug_fp=fopen(Debugging_Name,"wb");
1230 if (Debug_fp==NULL)
1231 fatalerror_named("Couldn't open debugging information file",
1232 Debugging_Name);
1235 extern void nullify_debug_file_position(maybe_file_position *position) {
1236 position->valid = 0;
1239 static void close_debug_file(void)
1240 { fclose(Debug_fp);
1241 #ifdef MAC_FACE
1242 InformFiletypes (Debugging_Name, INF_DEBUG_TYPE);
1243 #endif
1246 extern void begin_debug_file(void)
1247 { open_debug_file();
1249 debug_file_printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
1250 debug_file_printf("<inform-story-file version=\"1.0\" ");
1251 debug_file_printf("content-creator=\"Inform\" ");
1252 debug_file_printf
1253 ("content-creator-version=\"%d.%d%d\">",
1254 (VNUMBER / 100) % 10,
1255 (VNUMBER / 10) % 10,
1256 VNUMBER % 10);
1259 extern void debug_file_printf(const char*format, ...)
1260 { va_list argument_pointer;
1261 va_start(argument_pointer, format);
1262 vfprintf(Debug_fp, format, argument_pointer);
1263 va_end(argument_pointer);
1264 if (ferror(Debug_fp))
1265 { fatalerror("I/O failure: can't write to debugging information file");
1269 extern void debug_file_print_with_entities(const char*string)
1270 { int index = 0;
1271 char character;
1272 for (character = string[index]; character; character = string[++index])
1273 { switch(character)
1274 { case '"':
1275 debug_file_printf("&quot;");
1276 break;
1277 case '&':
1278 debug_file_printf("&amp;");
1279 break;
1280 case '\'':
1281 debug_file_printf("&apos;");
1282 break;
1283 case '<':
1284 debug_file_printf("&lt;");
1285 break;
1286 case '>':
1287 debug_file_printf("&gt;");
1288 break;
1289 default:
1290 debug_file_printf("%c", character);
1291 break;
1296 static char base_64_digits[] =
1297 { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
1298 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
1299 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
1300 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
1301 '8', '9', '+', '/' };
1303 extern void debug_file_print_base_64_triple
1304 (uchar first, uchar second, uchar third)
1305 { debug_file_printf
1306 ("%c%c%c%c",
1307 base_64_digits[first >> 2],
1308 base_64_digits[((first & 3) << 4) | (second >> 4)],
1309 base_64_digits[((second & 15) << 2) | (third >> 6)],
1310 base_64_digits[third & 63]);
1313 extern void debug_file_print_base_64_pair(uchar first, uchar second)
1314 { debug_file_printf
1315 ("%c%c%c=",
1316 base_64_digits[first >> 2],
1317 base_64_digits[((first & 3) << 4) | (second >> 4)],
1318 base_64_digits[(second & 15) << 2]);
1321 extern void debug_file_print_base_64_single(uchar first)
1322 { debug_file_printf
1323 ("%c%c==",
1324 base_64_digits[first >> 2],
1325 base_64_digits[(first & 3) << 4]);
1328 static void write_debug_location_internals(debug_location location)
1329 { debug_file_printf("<file-index>%d</file-index>", location.file_index - 1);
1330 debug_file_printf
1331 ("<file-position>%d</file-position>", location.beginning_byte_index);
1332 debug_file_printf
1333 ("<line>%d</line>", location.beginning_line_number);
1334 debug_file_printf
1335 ("<character>%d</character>", location.beginning_character_number);
1336 if (location.beginning_byte_index != location.end_byte_index ||
1337 location.beginning_line_number != location.end_line_number ||
1338 location.beginning_character_number != location.end_character_number)
1339 { debug_file_printf
1340 ("<end-file-position>%d</end-file-position>",
1341 location.end_byte_index);
1342 debug_file_printf
1343 ("<end-line>%d</end-line>", location.end_line_number);
1344 debug_file_printf
1345 ("<end-character>%d</end-character>",
1346 location.end_character_number);
1350 extern void write_debug_location(debug_location location)
1351 { if (location.file_index && location.file_index != 255)
1352 { debug_file_printf("<source-code-location>");
1353 write_debug_location_internals(location);
1354 debug_file_printf("</source-code-location>");
1358 extern void write_debug_locations(debug_locations locations)
1359 { if (locations.next)
1360 { const debug_locations*current = &locations;
1361 unsigned int index = 0;
1362 for (; current; current = current->next, ++index)
1363 { debug_file_printf("<source-code-location index=\"%d\">", index);
1364 write_debug_location_internals(current->location);
1365 debug_file_printf("</source-code-location>");
1368 else
1369 { write_debug_location(locations.location);
1373 extern void write_debug_optional_identifier(int32 symbol_index)
1374 { if (stypes[symbol_index] != ROUTINE_T)
1375 { compiler_error
1376 ("Attempt to write a replaceable identifier for a non-routine");
1378 if (replacement_debug_backpatch_positions[symbol_index].valid)
1379 { if (fsetpos
1380 (Debug_fp,
1381 &replacement_debug_backpatch_positions[symbol_index].position))
1382 { fatalerror("I/O failure: can't seek in debugging information file");
1384 debug_file_printf
1385 ("<identifier artificial=\"true\">%s "
1386 "(superseded replacement)</identifier>",
1387 symbs[symbol_index]);
1388 if (fseek(Debug_fp, 0L, SEEK_END))
1389 { fatalerror("I/O failure: can't seek in debugging information file");
1392 fgetpos
1393 (Debug_fp, &replacement_debug_backpatch_positions[symbol_index].position);
1394 replacement_debug_backpatch_positions[symbol_index].valid = TRUE;
1395 debug_file_printf("<identifier>%s</identifier>", symbs[symbol_index]);
1396 /* Space for: artificial="true" (superseded replacement) */
1397 debug_file_printf(" ");
1400 extern void write_debug_symbol_backpatch(int32 symbol_index)
1401 { if (symbol_debug_backpatch_positions[symbol_index].valid) {
1402 compiler_error("Symbol entry incorrectly reused in debug information "
1403 "file backpatching");
1405 fgetpos(Debug_fp, &symbol_debug_backpatch_positions[symbol_index].position);
1406 symbol_debug_backpatch_positions[symbol_index].valid = TRUE;
1407 /* Reserve space for up to 10 digits plus a negative sign. */
1408 debug_file_printf("*BACKPATCH*");
1411 extern void write_debug_symbol_optional_backpatch(int32 symbol_index)
1412 { if (symbol_debug_backpatch_positions[symbol_index].valid) {
1413 compiler_error("Symbol entry incorrectly reused in debug information "
1414 "file backpatching");
1416 /* Reserve space for open and close value tags and up to 10 digits plus a
1417 negative sign, but take the backpatch position just inside the element,
1418 so that we'll be in the same case as above if the symbol is eventually
1419 defined. */
1420 debug_file_printf("<value>");
1421 fgetpos(Debug_fp, &symbol_debug_backpatch_positions[symbol_index].position);
1422 symbol_debug_backpatch_positions[symbol_index].valid = TRUE;
1423 debug_file_printf("*BACKPATCH*</value>");
1426 static void write_debug_backpatch
1427 (debug_backpatch_accumulator *accumulator, int32 value)
1428 { if (accumulator->number_of_values_to_backpatch ==
1429 accumulator->number_of_available_backpatches)
1430 { my_realloc(&accumulator->values_and_backpatch_positions,
1431 sizeof(value_and_backpatch_position) *
1432 accumulator->number_of_available_backpatches,
1433 2 * sizeof(value_and_backpatch_position) *
1434 accumulator->number_of_available_backpatches,
1435 "values and debug information backpatch positions");
1436 accumulator->number_of_available_backpatches *= 2;
1438 accumulator->values_and_backpatch_positions
1439 [accumulator->number_of_values_to_backpatch].value = value;
1440 fgetpos
1441 (Debug_fp,
1442 &accumulator->values_and_backpatch_positions
1443 [accumulator->number_of_values_to_backpatch].backpatch_position);
1444 ++(accumulator->number_of_values_to_backpatch);
1445 /* Reserve space for up to 10 digits plus a negative sign. */
1446 debug_file_printf("*BACKPATCH*");
1449 extern void write_debug_object_backpatch(int32 object_number)
1450 { if (glulx_mode)
1451 { write_debug_backpatch(&object_backpatch_accumulator, object_number - 1);
1453 else
1454 { debug_file_printf("%d", object_number);
1458 static int32 backpatch_object_address(int32 index)
1459 { return object_tree_offset + OBJECT_BYTE_LENGTH * index;
1462 extern void write_debug_packed_code_backpatch(int32 offset)
1463 { write_debug_backpatch(&packed_code_backpatch_accumulator, offset);
1466 static int32 backpatch_packed_code_address(int32 offset)
1467 { return (code_offset + offset) / scale_factor;
1470 extern void write_debug_code_backpatch(int32 offset)
1471 { write_debug_backpatch(&code_backpatch_accumulator, offset);
1474 static int32 backpatch_code_address(int32 offset)
1475 { return code_offset + offset;
1478 extern void write_debug_global_backpatch(int32 offset)
1479 { write_debug_backpatch(&global_backpatch_accumulator, offset);
1482 static int32 backpatch_global_address(int32 offset)
1483 { return variables_offset + WORDSIZE * (offset - MAX_LOCAL_VARIABLES);
1486 extern void write_debug_array_backpatch(int32 offset)
1487 { write_debug_backpatch(&array_backpatch_accumulator, offset);
1490 static int32 backpatch_array_address(int32 offset)
1491 { return (glulx_mode ? arrays_offset : variables_offset) + offset;
1494 extern void write_debug_grammar_backpatch(int32 offset)
1495 { write_debug_backpatch(&grammar_backpatch_accumulator, offset);
1498 static int32 backpatch_grammar_address(int32 offset)
1499 { return grammar_table_offset + offset;
1502 extern void begin_writing_debug_sections()
1503 { debug_file_printf("<story-file-section>");
1504 debug_file_printf("<type>header</type>");
1505 debug_file_printf("<address>0</address>");
1508 extern void write_debug_section(const char*name, int32 beginning_address)
1509 { debug_file_printf("<end-address>%d</end-address>", beginning_address);
1510 debug_file_printf("</story-file-section>");
1511 debug_file_printf("<story-file-section>");
1512 debug_file_printf("<type>");
1513 debug_file_print_with_entities(name);
1514 debug_file_printf("</type>");
1515 debug_file_printf("<address>%d</address>", beginning_address);
1518 extern void end_writing_debug_sections(int32 end_address)
1519 { debug_file_printf("<end-address>%d</end-address>", end_address);
1520 debug_file_printf("</story-file-section>");
1523 extern void write_debug_undef(int32 symbol_index)
1524 { if (!symbol_debug_backpatch_positions[symbol_index].valid)
1525 { compiler_error
1526 ("Attempt to erase debugging information never written or since "
1527 "erased");
1529 if (stypes[symbol_index] != CONSTANT_T)
1530 { compiler_error
1531 ("Attempt to erase debugging information for a non-constant "
1532 "because of an #undef");
1534 if (fsetpos
1535 (Debug_fp, &symbol_debug_backpatch_positions[symbol_index].position))
1536 { fatalerror("I/O failure: can't seek in debugging information file");
1538 /* There are 7 characters in ``<value>''. */
1539 if (fseek(Debug_fp, -7L, SEEK_CUR))
1540 { fatalerror("I/O failure: can't seek in debugging information file");
1542 /* Overwrite: <value>*BACKPATCH*</value> */
1543 debug_file_printf(" ");
1544 nullify_debug_file_position
1545 (&symbol_debug_backpatch_positions[symbol_index]);
1546 if (fseek(Debug_fp, 0L, SEEK_END))
1547 { fatalerror("I/O failure: can't seek in debugging information file");
1551 static void apply_debug_information_backpatches
1552 (debug_backpatch_accumulator *accumulator)
1553 { int32 backpatch_index, backpatch_value;
1554 for (backpatch_index = accumulator->number_of_values_to_backpatch;
1555 backpatch_index--;)
1556 { if (fsetpos
1557 (Debug_fp,
1558 &accumulator->values_and_backpatch_positions
1559 [backpatch_index].backpatch_position))
1560 { fatalerror
1561 ("I/O failure: can't seek in debugging information file");
1563 backpatch_value =
1564 (*accumulator->backpatching_function)
1565 (accumulator->values_and_backpatch_positions
1566 [backpatch_index].value);
1567 debug_file_printf
1568 ("%11d", /* Space for up to 10 digits plus a negative sign. */
1569 backpatch_value);
1573 static void apply_debug_information_symbol_backpatches()
1574 { int backpatch_symbol;
1575 for (backpatch_symbol = no_symbols; backpatch_symbol--;)
1576 { if (symbol_debug_backpatch_positions[backpatch_symbol].valid)
1577 { if (fsetpos(Debug_fp,
1578 &symbol_debug_backpatch_positions
1579 [backpatch_symbol].position))
1580 { fatalerror
1581 ("I/O failure: can't seek in debugging information file");
1583 debug_file_printf("%11d", svals[backpatch_symbol]);
1588 static void write_debug_system_constants()
1589 { int *system_constant_list =
1590 glulx_mode ? glulx_system_constant_list : z_system_constant_list;
1591 int system_constant_index = 0;
1593 /* Store system constants. */
1594 for (; system_constant_list[system_constant_index] != -1;
1595 ++system_constant_index)
1596 { int system_constant = system_constant_list[system_constant_index];
1597 debug_file_printf("<constant>");
1598 debug_file_printf
1599 ("<identifier>#%s</identifier>",
1600 system_constants.keywords[system_constant]);
1601 debug_file_printf
1602 ("<value>%d</value>",
1603 value_of_system_constant(system_constant));
1604 debug_file_printf("</constant>");
1608 extern void end_debug_file()
1609 { write_debug_system_constants();
1610 debug_file_printf("</inform-story-file>\n");
1612 if (glulx_mode)
1613 { apply_debug_information_backpatches(&object_backpatch_accumulator);
1614 } else
1615 { apply_debug_information_backpatches(&packed_code_backpatch_accumulator);
1617 apply_debug_information_backpatches(&code_backpatch_accumulator);
1618 apply_debug_information_backpatches(&global_backpatch_accumulator);
1619 apply_debug_information_backpatches(&array_backpatch_accumulator);
1620 apply_debug_information_backpatches(&grammar_backpatch_accumulator);
1622 apply_debug_information_symbol_backpatches();
1624 close_debug_file();
1627 /* ------------------------------------------------------------------------- */
1628 /* Temporary storage files: */
1629 /* */
1630 /* Temp file 1 is used to hold the static strings area, as compiled */
1631 /* 2 to hold compiled routines of Z-code */
1632 /* 3 to hold the link data table (but only for modules) */
1633 /* */
1634 /* (Though annoying, this procedure typically saves about 200K of memory, */
1635 /* an important point for Amiga and sub-386 PC users of Inform) */
1636 /* ------------------------------------------------------------------------- */
1638 extern void open_temporary_files(void)
1639 { translate_temp_filename(1);
1640 Temp1_fp=fopen(Temp1_Name,"wb");
1641 if (Temp1_fp==NULL) fatalerror_named("Couldn't open temporary file 1",
1642 Temp1_Name);
1643 translate_temp_filename(2);
1644 Temp2_fp=fopen(Temp2_Name,"wb");
1645 if (Temp2_fp==NULL) fatalerror_named("Couldn't open temporary file 2",
1646 Temp2_Name);
1648 if (!module_switch) return;
1649 translate_temp_filename(3);
1650 Temp3_fp=fopen(Temp3_Name,"wb");
1651 if (Temp3_fp==NULL) fatalerror_named("Couldn't open temporary file 3",
1652 Temp3_Name);
1655 extern void check_temp_files(void)
1657 if (ferror(Temp1_fp))
1658 fatalerror("I/O failure: couldn't write to temporary file 1");
1659 if (ferror(Temp2_fp))
1660 fatalerror("I/O failure: couldn't write to temporary file 2");
1661 if (module_switch && ferror(Temp3_fp))
1662 fatalerror("I/O failure: couldn't write to temporary file 3");
1665 extern void remove_temp_files(void)
1666 { if (Temp1_fp != NULL) fclose(Temp1_fp);
1667 if (Temp2_fp != NULL) fclose(Temp2_fp);
1668 remove(Temp1_Name); remove(Temp2_Name);
1669 if (module_switch)
1670 { if (Temp3_fp != NULL) fclose(Temp3_fp);
1671 remove(Temp3_Name);
1675 /* ========================================================================= */
1676 /* Data structure management routines */
1677 /* ------------------------------------------------------------------------- */
1679 extern void init_files_vars(void)
1680 { malloced_bytes = 0;
1681 checksum_low_byte = 0; /* Z-code */
1682 checksum_high_byte = 0;
1683 checksum_long = 0; /* Glulx */
1684 checksum_count = 0;
1685 transcript_open = FALSE;
1688 extern void files_begin_prepass(void)
1689 { input_file = 0;
1692 extern void files_begin_pass(void)
1693 { total_chars_read=0;
1694 if (temporary_files_switch)
1695 open_temporary_files();
1698 static void initialise_accumulator
1699 (debug_backpatch_accumulator *accumulator,
1700 int32 (* backpatching_function)(int32))
1701 { accumulator->number_of_values_to_backpatch = 0;
1702 accumulator->number_of_available_backpatches =
1703 INITIAL_DEBUG_INFORMATION_BACKPATCH_ALLOCATION;
1704 accumulator->values_and_backpatch_positions =
1705 my_malloc
1706 (sizeof(value_and_backpatch_position) *
1707 accumulator->number_of_available_backpatches,
1708 "values and debug information backpatch positions");
1709 accumulator->backpatching_function = backpatching_function;
1712 extern void files_allocate_arrays(void)
1713 { filename_storage = my_malloc(MAX_SOURCE_FILES*64, "filename storage");
1714 filename_storage_p = filename_storage;
1715 filename_storage_left = MAX_SOURCE_FILES*64;
1716 InputFiles = my_malloc(MAX_SOURCE_FILES*sizeof(FileId),
1717 "input file storage");
1718 if (debugfile_switch)
1719 { if (glulx_mode)
1720 { initialise_accumulator
1721 (&object_backpatch_accumulator, &backpatch_object_address);
1722 } else
1723 { initialise_accumulator
1724 (&packed_code_backpatch_accumulator,
1725 &backpatch_packed_code_address);
1727 initialise_accumulator
1728 (&code_backpatch_accumulator, &backpatch_code_address);
1729 initialise_accumulator
1730 (&global_backpatch_accumulator, &backpatch_global_address);
1731 initialise_accumulator
1732 (&array_backpatch_accumulator, &backpatch_array_address);
1733 initialise_accumulator
1734 (&grammar_backpatch_accumulator, &backpatch_grammar_address);
1738 static void tear_down_accumulator(debug_backpatch_accumulator *accumulator)
1739 { my_free
1740 (&(accumulator->values_and_backpatch_positions),
1741 "values and debug information backpatch positions");
1744 extern void files_free_arrays(void)
1745 { my_free(&filename_storage, "filename storage");
1746 my_free(&InputFiles, "input file storage");
1747 if (debugfile_switch)
1748 { if (!glulx_mode)
1749 { tear_down_accumulator(&object_backpatch_accumulator);
1750 } else
1751 { tear_down_accumulator(&packed_code_backpatch_accumulator);
1753 tear_down_accumulator(&code_backpatch_accumulator);
1754 tear_down_accumulator(&global_backpatch_accumulator);
1755 tear_down_accumulator(&array_backpatch_accumulator);
1756 tear_down_accumulator(&grammar_backpatch_accumulator);
1760 /* ========================================================================= */