~ubuntu-branches/ubuntu/vivid/inform/vivid

« back to all changes in this revision

Viewing changes to inform-6.31.1/src/files.c

  • Committer: Bazaar Package Importer
  • Author(s): Jan Christoph Nordholz
  • Date: 2008-05-26 22:09:44 UTC
  • mfrom: (2.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080526220944-ba7phz0d1k4vo7wx
Tags: 6.31.1+dfsg-1
* Remove a considerable number of files from the package
  due to unacceptable licensing terms.
* Repair library symlinks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.31                                                     */
 
11
/*   copyright (c) Graham Nelson 1993 - 2006                                 */
 
12
/*                                                                           */
 
13
/* ------------------------------------------------------------------------- */
 
14
 
 
15
#include "header.h"
 
16
 
 
17
int input_file;                         /* Number of source files so far     */
 
18
 
 
19
int32 total_chars_read;                 /* Characters read in (from all
 
20
                                           source files put together)        */
 
21
 
 
22
static int checksum_low_byte,           /* For calculating the Z-machine's   */
 
23
           checksum_high_byte;          /* "verify" checksum                 */
 
24
 
 
25
static int32 checksum_long;             /* For the Glulx checksum,           */
 
26
static int checksum_count;              /* similarly                         */
 
27
 
 
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
/* ------------------------------------------------------------------------- */
 
32
 
 
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;
 
37
 
 
38
/* ------------------------------------------------------------------------- */
 
39
/*   File handles and names for temporary files.                             */
 
40
/* ------------------------------------------------------------------------- */
 
41
 
 
42
FILE *Temp1_fp=NULL, *Temp2_fp=NULL,  *Temp3_fp=NULL;
 
43
char Temp1_Name[PATHLEN], Temp2_Name[PATHLEN], Temp3_Name[PATHLEN];
 
44
 
 
45
/* ------------------------------------------------------------------------- */
 
46
/*   Opening and closing source code files                                   */
 
47
/* ------------------------------------------------------------------------- */
 
48
 
 
49
extern void load_sourcefile(char *filename_given, int same_directory_flag)
 
50
{
 
51
    /*  Meaning: open a new file of Inform source.  (The lexer picks up on
 
52
        this by noticing that input_file has increased.)                     */
 
53
 
 
54
    char name[PATHLEN]; int x = 0; FILE *handle;
 
55
 
 
56
    if (input_file == MAX_SOURCE_FILES)
 
57
        memoryerror("MAX_SOURCE_FILES", MAX_SOURCE_FILES);
 
58
 
 
59
    do
 
60
    {   x = translate_in_filename(x, name, filename_given, same_directory_flag,
 
61
                (input_file==0)?1:0);
 
62
        handle = fopen(name,"r");
 
63
    } while ((handle == NULL) && (x != 0));
 
64
 
 
65
    if (filename_storage_left <= (int)strlen(name))
 
66
        memoryerror("MAX_SOURCE_FILES", MAX_SOURCE_FILES);
 
67
 
 
68
    filename_storage_left -= strlen(name)+1;
 
69
    strcpy(filename_storage_p, name);
 
70
    InputFiles[input_file].filename = filename_storage_p;
 
71
 
 
72
    filename_storage_p += strlen(name)+1;
 
73
 
 
74
    if (debugfile_switch)
 
75
    {   write_debug_byte(FILE_DBR); write_debug_byte(input_file + 1);
 
76
        write_debug_string(filename_given);
 
77
        write_debug_string(name);
 
78
    }
 
79
 
 
80
    InputFiles[input_file].handle = handle;
 
81
    if (InputFiles[input_file].handle==NULL)
 
82
        fatalerror_named("Couldn't open source file", name);
 
83
 
 
84
    if (line_trace_level > 0) printf("\nOpening file \"%s\"\n",name);
 
85
 
 
86
    input_file++;
 
87
}
 
88
 
 
89
static void close_sourcefile(int file_number)
 
90
{
 
91
    if (InputFiles[file_number-1].handle == NULL) return;
 
92
 
 
93
    /*  Close this file.  */
 
94
 
 
95
    if (ferror(InputFiles[file_number-1].handle))
 
96
        fatalerror_named("I/O failure: couldn't read from source file",
 
97
            InputFiles[file_number-1].filename);
 
98
 
 
99
    fclose(InputFiles[file_number-1].handle);
 
100
 
 
101
    InputFiles[file_number-1].handle = NULL;
 
102
 
 
103
    if (line_trace_level > 0) printf("\nClosing file\n");
 
104
}
 
105
 
 
106
extern void close_all_source(void)
 
107
{   int i;
 
108
    for (i=0; i<input_file; i++) close_sourcefile(i+1);
 
109
}
 
110
 
 
111
/* ------------------------------------------------------------------------- */
 
112
/*   Feeding source code up into the lexical analyser's buffer               */
 
113
/*   (see "lexer.c" for its specification)                                   */
 
114
/* ------------------------------------------------------------------------- */
 
115
 
 
116
extern int file_load_chars(int file_number, char *buffer, int length)
 
117
{
 
118
    int read_in; FILE *handle;
 
119
 
 
120
    if (file_number-1 > input_file)
 
121
    {   buffer[0] = 0; return 1; }
 
122
 
 
123
    handle = InputFiles[file_number-1].handle;
 
124
    if (handle == NULL)
 
125
    {   buffer[0] = 0; return 1; }
 
126
 
 
127
    read_in = fread(buffer, 1, length, handle);
 
128
    total_chars_read += read_in;
 
129
 
 
130
    if (read_in == length) return length;
 
131
 
 
132
    close_sourcefile(file_number);
 
133
 
 
134
    if (file_number == 1)
 
135
    {   buffer[read_in]   = 0;
 
136
        buffer[read_in+1] = 0;
 
137
        buffer[read_in+2] = 0;
 
138
        buffer[read_in+3] = 0;
 
139
    }
 
140
    else
 
141
    {   buffer[read_in]   = '\n';
 
142
        buffer[read_in+1] = ' ';
 
143
        buffer[read_in+2] = ' ';
 
144
        buffer[read_in+3] = ' ';
 
145
    }
 
146
 
 
147
    return(-(read_in+4));
 
148
}
 
149
 
 
150
/* ------------------------------------------------------------------------- */
 
151
/*   Final assembly and output of the story file/module.                     */
 
152
/* ------------------------------------------------------------------------- */
 
153
 
 
154
FILE *sf_handle;
 
155
 
 
156
static void sf_put(int c)
 
157
{
 
158
    if (!glulx_mode) {
 
159
 
 
160
      /*  The checksum is the unsigned sum mod 65536 of the bytes in the
 
161
          story file from 0x0040 (first byte after header) to the end.
 
162
 
 
163
          The link data does not contribute to the checksum of a module.     */
 
164
 
 
165
      checksum_low_byte += c;
 
166
      if (checksum_low_byte>=256)
 
167
      {   checksum_low_byte-=256;
 
168
          if (++checksum_high_byte==256) checksum_high_byte=0;
 
169
      }
 
170
 
 
171
    }
 
172
    else {
 
173
 
 
174
      /*  The checksum is the unsigned 32-bit sum of the entire story file,
 
175
          considered as a list of 32-bit words, with the checksum field
 
176
          being zero. */
 
177
 
 
178
      switch (checksum_count) {
 
179
      case 0:
 
180
        checksum_long += (((int32)(c & 0xFF)) << 24);
 
181
        break;
 
182
      case 1:
 
183
        checksum_long += (((int32)(c & 0xFF)) << 16);
 
184
        break;
 
185
      case 2:
 
186
        checksum_long += (((int32)(c & 0xFF)) << 8);
 
187
        break;
 
188
      case 3:
 
189
        checksum_long += ((int32)(c & 0xFF));
 
190
        break;
 
191
      }
 
192
      
 
193
      checksum_count = (checksum_count+1) & 3;
 
194
      
 
195
    }
 
196
 
 
197
    fputc(c, sf_handle);
 
198
}
 
199
 
 
200
/* Recursive procedure to generate the Glulx compression table. */
 
201
 
 
202
static void output_compression(int entnum, int32 *size)
 
203
{
 
204
  huffentity_t *ent = &(huff_entities[entnum]);
 
205
  int32 val;
 
206
  char *cx;
 
207
 
 
208
  sf_put(ent->type);
 
209
  (*size)++;
 
210
 
 
211
  switch (ent->type) {
 
212
  case 0:
 
213
    val = Write_Strings_At + huff_entities[ent->u.branch[0]].addr;
 
214
    sf_put((val >> 24) & 0xFF);
 
215
    sf_put((val >> 16) & 0xFF);
 
216
    sf_put((val >> 8) & 0xFF);
 
217
    sf_put((val) & 0xFF);
 
218
    (*size) += 4;
 
219
    val = Write_Strings_At + huff_entities[ent->u.branch[1]].addr;
 
220
    sf_put((val >> 24) & 0xFF);
 
221
    sf_put((val >> 16) & 0xFF);
 
222
    sf_put((val >> 8) & 0xFF);
 
223
    sf_put((val) & 0xFF);
 
224
    (*size) += 4;
 
225
    output_compression(ent->u.branch[0], size);
 
226
    output_compression(ent->u.branch[1], size);
 
227
    break;
 
228
  case 1:
 
229
    /* no data */
 
230
    break;
 
231
  case 2:
 
232
    sf_put(ent->u.ch);
 
233
    (*size) += 1;
 
234
    break;
 
235
  case 3:
 
236
    cx = (char *)abbreviations_at + ent->u.val*MAX_ABBREV_LENGTH;
 
237
    while (*cx) {
 
238
      sf_put(*cx);
 
239
      cx++;
 
240
      (*size) += 1;  
 
241
    }
 
242
    sf_put('\0');
 
243
    (*size) += 1;  
 
244
    break;
 
245
  case 9:
 
246
    val = abbreviations_offset + 4 + ent->u.val*4;
 
247
    sf_put((val >> 24) & 0xFF);
 
248
    sf_put((val >> 16) & 0xFF);
 
249
    sf_put((val >> 8) & 0xFF);
 
250
    sf_put((val) & 0xFF);
 
251
    (*size) += 4;
 
252
    break;
 
253
  }
 
254
}
 
255
 
 
256
static void output_file_z(void)
 
257
{   FILE *fin; char new_name[PATHLEN];
 
258
    int32 length, blanks=0, size, i, j;
 
259
 
 
260
    ASSERT_ZCODE();
 
261
 
 
262
    /* At this point, construct_storyfile() has just been called. */
 
263
 
 
264
    /*  Enter the length information into the header.                        */
 
265
 
 
266
    length=((int32) Write_Strings_At) + static_strings_extent;
 
267
    if (module_switch) length += link_data_size +
 
268
                                 zcode_backpatch_size +
 
269
                                 zmachine_backpatch_size;
 
270
 
 
271
    while ((length%length_scale_factor)!=0) { length++; blanks++; }
 
272
    length=length/length_scale_factor;
 
273
    zmachine_paged_memory[26]=(length & 0xff00)/0x100;
 
274
    zmachine_paged_memory[27]=(length & 0xff);
 
275
 
 
276
    /*  To assist interpreters running a paged virtual memory system, Inform
 
277
        writes files which are padded with zeros to the next multiple of
 
278
        0.5K.  This calculates the number of bytes of padding needed:        */
 
279
 
 
280
    while (((length_scale_factor*length)+blanks-1)%512 != 511) blanks++;
 
281
 
 
282
    translate_out_filename(new_name, Code_Name);
 
283
 
 
284
    sf_handle = fopen(new_name,"wb");
 
285
    if (sf_handle == NULL)
 
286
        fatalerror_named("Couldn't open output file", new_name);
 
287
 
 
288
#ifdef MAC_MPW
 
289
    /*  Set the type and creator to Andrew Plotkin's MaxZip, a popular
 
290
        Z-code interpreter on the Macintosh  */
 
291
 
 
292
    if (!module_switch) fsetfileinfo(new_name, 'mxZR', 'ZCOD');
 
293
#endif
 
294
 
 
295
    /*  (1)  Output the paged memory.                                        */
 
296
 
 
297
    for (i=0;i<64;i++)
 
298
        fputc(zmachine_paged_memory[i], sf_handle);
 
299
    size = 64;
 
300
    checksum_low_byte = 0;
 
301
    checksum_high_byte = 0;
 
302
 
 
303
    for (i=64; i<Write_Code_At; i++)
 
304
    {   sf_put(zmachine_paged_memory[i]); size++;
 
305
    }
 
306
 
 
307
    /*  (2)  Output the compiled code area.                                  */
 
308
 
 
309
    if (temporary_files_switch)
 
310
    {   fclose(Temp2_fp);
 
311
        fin=fopen(Temp2_Name,"rb");
 
312
        if (fin==NULL)
 
313
            fatalerror("I/O failure: couldn't reopen temporary file 2");
 
314
    }
 
315
 
 
316
    j=0;
 
317
    if (!module_switch)
 
318
    for (i=0; i<zcode_backpatch_size; i=i+3)
 
319
    {   int long_flag = TRUE;
 
320
        int32 offset
 
321
            = 256*read_byte_from_memory_block(&zcode_backpatch_table, i+1)
 
322
              + read_byte_from_memory_block(&zcode_backpatch_table, i+2);
 
323
        backpatch_error_flag = FALSE;
 
324
        backpatch_marker
 
325
            = read_byte_from_memory_block(&zcode_backpatch_table, i);
 
326
        if (backpatch_marker >= 0x80) long_flag = FALSE;
 
327
        backpatch_marker &= 0x7f;
 
328
        offset = offset + (backpatch_marker/32)*0x10000;
 
329
        while (offset+0x30000 < j) {
 
330
            offset += 0x40000;
 
331
            long_flag = !long_flag;
 
332
        }
 
333
        backpatch_marker &= 0x1f;
 
334
        while (j<offset)
 
335
        {   size++;
 
336
            sf_put((temporary_files_switch)?fgetc(fin):
 
337
                  read_byte_from_memory_block(&zcode_area, j));
 
338
            j++;
 
339
        }
 
340
 
 
341
        if (long_flag)
 
342
        {   int32 v = (temporary_files_switch)?fgetc(fin):
 
343
                read_byte_from_memory_block(&zcode_area, j);
 
344
            v = 256*v + ((temporary_files_switch)?fgetc(fin):
 
345
                read_byte_from_memory_block(&zcode_area, j+1));
 
346
            v = backpatch_value(v);
 
347
            sf_put(v/256); sf_put(v%256);
 
348
            size += 2; j += 2;
 
349
        }
 
350
        else
 
351
        {   int32 v = (temporary_files_switch)?fgetc(fin):
 
352
                read_byte_from_memory_block(&zcode_area, j);
 
353
            v = backpatch_value(v);
 
354
            sf_put(v);
 
355
            size++; j++;
 
356
        }
 
357
 
 
358
        if (backpatch_error_flag)
 
359
        {   printf("*** %s  zcode offset=%08lx  backpatch offset=%08lx ***\n",
 
360
                (long_flag)?"long":"short", (long int) j, (long int) i);
 
361
        }
 
362
    }
 
363
 
 
364
    while (j<zmachine_pc)
 
365
    {   size++;
 
366
        sf_put((temporary_files_switch)?fgetc(fin):
 
367
            read_byte_from_memory_block(&zcode_area, j));
 
368
        j++;
 
369
    }
 
370
 
 
371
    if (temporary_files_switch)
 
372
    {   if (ferror(fin))
 
373
            fatalerror("I/O failure: couldn't read from temporary file 2");
 
374
        fclose(fin);
 
375
    }
 
376
 
 
377
    /*  (3)  Output any null bytes (required to reach a packed address)
 
378
             before the strings area.                                        */
 
379
 
 
380
    while (size<Write_Strings_At) { sf_put(0); size++; }
 
381
 
 
382
    /*  (4)  Output the static strings area.                                 */
 
383
 
 
384
    if (temporary_files_switch)
 
385
    {   fclose(Temp1_fp);
 
386
        fin=fopen(Temp1_Name,"rb");
 
387
        if (fin==NULL)
 
388
            fatalerror("I/O failure: couldn't reopen temporary file 1");
 
389
        for (i=0; i<static_strings_extent; i++) sf_put(fgetc(fin));
 
390
        if (ferror(fin))
 
391
            fatalerror("I/O failure: couldn't read from temporary file 1");
 
392
        fclose(fin);
 
393
        remove(Temp1_Name); remove(Temp2_Name);
 
394
    }
 
395
    else
 
396
      for (i=0; i<static_strings_extent; i++) {
 
397
        sf_put(read_byte_from_memory_block(&static_strings_area,i));
 
398
        size++;
 
399
      }
 
400
 
 
401
    /*  (5)  Output the linking data table (in the case of a module).        */
 
402
 
 
403
    if (temporary_files_switch)
 
404
    {   if (module_switch)
 
405
        {   fclose(Temp3_fp);
 
406
            fin=fopen(Temp3_Name,"rb");
 
407
            if (fin==NULL)
 
408
                fatalerror("I/O failure: couldn't reopen temporary file 3");
 
409
            for (j=0; j<link_data_size; j++) sf_put(fgetc(fin));
 
410
            if (ferror(fin))
 
411
                fatalerror("I/O failure: couldn't read from temporary file 3");
 
412
            fclose(fin);
 
413
            remove(Temp3_Name);
 
414
        }
 
415
    }
 
416
    else
 
417
        if (module_switch)
 
418
            for (i=0; i<link_data_size; i++)
 
419
                sf_put(read_byte_from_memory_block(&link_data_area,i));
 
420
 
 
421
    if (module_switch)
 
422
    {   for (i=0; i<zcode_backpatch_size; i++)
 
423
            sf_put(read_byte_from_memory_block(&zcode_backpatch_table, i));
 
424
        for (i=0; i<zmachine_backpatch_size; i++)
 
425
            sf_put(read_byte_from_memory_block(&zmachine_backpatch_table, i));
 
426
    }
 
427
 
 
428
    /*  (6)  Output null bytes to reach a multiple of 0.5K.                  */
 
429
 
 
430
    while (blanks>0) { sf_put(0); blanks--; }
 
431
 
 
432
    if (ferror(sf_handle))
 
433
        fatalerror("I/O failure: couldn't write to story file");
 
434
 
 
435
    fseek(sf_handle, 28, SEEK_SET);
 
436
    fputc(checksum_high_byte, sf_handle);
 
437
    fputc(checksum_low_byte, sf_handle);
 
438
 
 
439
    if (ferror(sf_handle))
 
440
      fatalerror("I/O failure: couldn't backtrack on story file for checksum");
 
441
 
 
442
    fclose(sf_handle);
 
443
 
 
444
    /*  Write a copy of the header into the debugging information file
 
445
        (mainly so that it can be used to identify which story file matches
 
446
        with which debugging info file)                                      */
 
447
 
 
448
    if (debugfile_switch)
 
449
    {   write_debug_byte(HEADER_DBR);
 
450
        for (i=0; i<64; i++)
 
451
        {   if (i==28) write_debug_byte(checksum_high_byte);
 
452
            else if (i==29) write_debug_byte(checksum_low_byte);
 
453
            else write_debug_byte((int) (zmachine_paged_memory[i]));
 
454
        }
 
455
    }
 
456
 
 
457
#ifdef ARCHIMEDES
 
458
    {   char settype_command[PATHLEN];
 
459
        sprintf(settype_command, "settype %s %s",
 
460
            new_name, riscos_file_type());
 
461
        system(settype_command);
 
462
    }
 
463
#endif
 
464
#ifdef MAC_FACE
 
465
     if (module_switch)
 
466
         InformFiletypes (new_name, INF_MODULE_TYPE);
 
467
     else
 
468
         InformFiletypes (new_name, INF_ZCODE_TYPE);
 
469
#endif
 
470
}
 
471
 
 
472
static void output_file_g(void)
 
473
{   FILE *fin; char new_name[PATHLEN];
 
474
    int32 size, i, j;
 
475
 
 
476
    ASSERT_GLULX();
 
477
 
 
478
    /* At this point, construct_storyfile() has just been called. */
 
479
 
 
480
    translate_out_filename(new_name, Code_Name);
 
481
 
 
482
    sf_handle = fopen(new_name,"wb");
 
483
    if (sf_handle == NULL)
 
484
        fatalerror_named("Couldn't open output file", new_name);
 
485
 
 
486
#ifdef MAC_MPW
 
487
    /*  Set the type and creator to Andrew Plotkin's MaxZip, a popular
 
488
        Z-code interpreter on the Macintosh  */
 
489
 
 
490
    if (!module_switch) fsetfileinfo(new_name, 'mxZR', 'ZCOD');
 
491
#endif
 
492
 
 
493
    checksum_long = 0;
 
494
    checksum_count = 0;
 
495
 
 
496
    /*  (1)  Output the header. We use sf_put here, instead of fputc,
 
497
        because the header is included in the checksum. */
 
498
 
 
499
    /* Magic number */
 
500
    sf_put('G');
 
501
    sf_put('l');
 
502
    sf_put('u');
 
503
    sf_put('l');
 
504
    /* Version number -- 0x00020000 for now. */
 
505
    sf_put(0x00);
 
506
    sf_put(0x02);
 
507
    sf_put(0x00);
 
508
    sf_put(0x00);
 
509
    /* RAMSTART */
 
510
    sf_put((Write_RAM_At >> 24));
 
511
    sf_put((Write_RAM_At >> 16));
 
512
    sf_put((Write_RAM_At >> 8));
 
513
    sf_put((Write_RAM_At));
 
514
    /* EXTSTART, or game file size */
 
515
    sf_put((Out_Size >> 24));
 
516
    sf_put((Out_Size >> 16));
 
517
    sf_put((Out_Size >> 8));
 
518
    sf_put((Out_Size));
 
519
    /* ENDMEM, which is also game file size */
 
520
    sf_put((Out_Size >> 24));
 
521
    sf_put((Out_Size >> 16));
 
522
    sf_put((Out_Size >> 8));
 
523
    sf_put((Out_Size));
 
524
    /* STACKSIZE, which we guess at 4096. That's about enough for 90
 
525
       nested function calls with 8 locals each -- the same capacity
 
526
       as the Z-Spec's suggestion for Z-machine stack size. */
 
527
    sf_put(0x00);
 
528
    sf_put(0x00);
 
529
    sf_put(0x10);
 
530
    sf_put(0x00);
 
531
    /* Initial function to call. Inform sets things up so that this
 
532
       is the start of the executable-code area. */
 
533
    sf_put((Write_Code_At >> 24));
 
534
    sf_put((Write_Code_At >> 16));
 
535
    sf_put((Write_Code_At >> 8));
 
536
    sf_put((Write_Code_At));
 
537
    /* String-encoding table. */
 
538
    sf_put((Write_Strings_At >> 24));
 
539
    sf_put((Write_Strings_At >> 16));
 
540
    sf_put((Write_Strings_At >> 8));
 
541
    sf_put((Write_Strings_At));
 
542
    /* Checksum -- zero for the moment. */
 
543
    sf_put(0x00);
 
544
    sf_put(0x00);
 
545
    sf_put(0x00);
 
546
    sf_put(0x00);
 
547
    
 
548
    size = GLULX_HEADER_SIZE;
 
549
 
 
550
    /*  (1a) Output the eight-byte memory layout identifier. */
 
551
 
 
552
    sf_put('I'); sf_put('n'); sf_put('f'); sf_put('o');
 
553
    sf_put(0); sf_put(1); sf_put(0); sf_put(0);
 
554
 
 
555
    /*  (1b) Output the rest of the Inform-specific data. */
 
556
 
 
557
    /* Inform version number */
 
558
    sf_put('0' + ((RELEASE_NUMBER/100)%10));
 
559
    sf_put('.');
 
560
    sf_put('0' + ((RELEASE_NUMBER/10)%10));
 
561
    sf_put('0' + RELEASE_NUMBER%10);
 
562
    /* Glulx back-end version number */
 
563
    sf_put('0' + ((GLULX_RELEASE_NUMBER/100)%10));
 
564
    sf_put('.');
 
565
    sf_put('0' + ((GLULX_RELEASE_NUMBER/10)%10));
 
566
    sf_put('0' + GLULX_RELEASE_NUMBER%10);
 
567
    /* Game release number */
 
568
    sf_put((release_number>>8) & 0xFF);
 
569
    sf_put(release_number & 0xFF);
 
570
    /* Game serial number */
 
571
    {
 
572
      char serialnum[8];
 
573
      write_serial_number(serialnum);
 
574
      for (i=0; i<6; i++)
 
575
        sf_put(serialnum[i]);
 
576
    }
 
577
    size += GLULX_STATIC_ROM_SIZE;
 
578
 
 
579
    /*  (2)  Output the compiled code area. */
 
580
 
 
581
    if (temporary_files_switch)
 
582
    {   fclose(Temp2_fp);
 
583
        fin=fopen(Temp2_Name,"rb");
 
584
        if (fin==NULL)
 
585
            fatalerror("I/O failure: couldn't reopen temporary file 2");
 
586
    }
 
587
 
 
588
    j=0;
 
589
    if (!module_switch)
 
590
      for (i=0; i<zcode_backpatch_size; i=i+6) {
 
591
        int data_len;
 
592
        int32 offset, v;
 
593
        offset = 
 
594
          (read_byte_from_memory_block(&zcode_backpatch_table, i+2) << 24)
 
595
          | (read_byte_from_memory_block(&zcode_backpatch_table, i+3) << 16)
 
596
          | (read_byte_from_memory_block(&zcode_backpatch_table, i+4) << 8)
 
597
          | (read_byte_from_memory_block(&zcode_backpatch_table, i+5));
 
598
        backpatch_error_flag = FALSE;
 
599
        backpatch_marker =
 
600
          read_byte_from_memory_block(&zcode_backpatch_table, i);
 
601
        data_len =
 
602
          read_byte_from_memory_block(&zcode_backpatch_table, i+1);
 
603
 
 
604
        while (j<offset) {
 
605
          size++;
 
606
          sf_put((temporary_files_switch)?fgetc(fin):
 
607
            read_byte_from_memory_block(&zcode_area, j));
 
608
          j++;
 
609
        }
 
610
 
 
611
        switch (data_len) {
 
612
 
 
613
        case 4:
 
614
          v = ((temporary_files_switch)?fgetc(fin):
 
615
            read_byte_from_memory_block(&zcode_area, j));
 
616
          v = (v << 8) | ((temporary_files_switch)?fgetc(fin):
 
617
            read_byte_from_memory_block(&zcode_area, j+1));
 
618
          v = (v << 8) | ((temporary_files_switch)?fgetc(fin):
 
619
            read_byte_from_memory_block(&zcode_area, j+2));
 
620
          v = (v << 8) | ((temporary_files_switch)?fgetc(fin):
 
621
            read_byte_from_memory_block(&zcode_area, j+3));
 
622
          v = backpatch_value(v);
 
623
          sf_put((v >> 24) & 0xFF);
 
624
          sf_put((v >> 16) & 0xFF);
 
625
          sf_put((v >> 8) & 0xFF);
 
626
          sf_put((v) & 0xFF);
 
627
          size += 4;
 
628
          j += 4;
 
629
          break;
 
630
 
 
631
        case 2:
 
632
          v = ((temporary_files_switch)?fgetc(fin):
 
633
            read_byte_from_memory_block(&zcode_area, j));
 
634
          v = (v << 8) | ((temporary_files_switch)?fgetc(fin):
 
635
            read_byte_from_memory_block(&zcode_area, j+1));
 
636
          v = backpatch_value(v);
 
637
          if (v >= 0x10000) {
 
638
            printf("*** backpatch value does not fit ***\n");
 
639
            backpatch_error_flag = TRUE;
 
640
          }
 
641
          sf_put((v >> 8) & 0xFF);
 
642
          sf_put((v) & 0xFF);
 
643
          size += 2;
 
644
          j += 2;
 
645
          break;
 
646
 
 
647
        case 1:
 
648
          v = ((temporary_files_switch)?fgetc(fin):
 
649
            read_byte_from_memory_block(&zcode_area, j));
 
650
          v = backpatch_value(v);
 
651
          if (v >= 0x100) {
 
652
            printf("*** backpatch value does not fit ***\n");
 
653
            backpatch_error_flag = TRUE;
 
654
          }
 
655
          sf_put((v) & 0xFF);
 
656
          size += 1;
 
657
          j += 1;
 
658
          break;
 
659
 
 
660
        default:
 
661
          printf("*** unknown backpatch data len = %d ***\n",
 
662
            data_len);
 
663
          backpatch_error_flag = TRUE;
 
664
        }
 
665
 
 
666
        if (backpatch_error_flag) {
 
667
          printf("*** %d bytes  zcode offset=%08lx  backpatch offset=%08lx ***\n",
 
668
            data_len, (long int) j, (long int) i);
 
669
        }
 
670
    }
 
671
 
 
672
    while (j<zmachine_pc)
 
673
    {   size++;
 
674
        sf_put((temporary_files_switch)?fgetc(fin):
 
675
            read_byte_from_memory_block(&zcode_area, j));
 
676
        j++;
 
677
    }
 
678
 
 
679
    if (temporary_files_switch)
 
680
    {   if (ferror(fin))
 
681
            fatalerror("I/O failure: couldn't read from temporary file 2");
 
682
        fclose(fin);
 
683
    }
 
684
 
 
685
    /*  (4)  Output the static strings area.                                 */
 
686
 
 
687
    if (temporary_files_switch) {
 
688
      fseek(Temp1_fp, 0, SEEK_SET);
 
689
    }
 
690
    {
 
691
      int32 ix, lx;
 
692
      int ch, jx, curbyte, bx;
 
693
      int depth;
 
694
      huffbitlist_t *bits;
 
695
      int32 origsize;
 
696
 
 
697
      origsize = size;
 
698
 
 
699
      if (compression_switch) {
 
700
 
 
701
        /* The 12-byte table header. */
 
702
        lx = compression_table_size;
 
703
        sf_put((lx >> 24) & 0xFF);
 
704
        sf_put((lx >> 16) & 0xFF);
 
705
        sf_put((lx >> 8) & 0xFF);
 
706
        sf_put((lx) & 0xFF);
 
707
        size += 4;
 
708
        sf_put((no_huff_entities >> 24) & 0xFF);
 
709
        sf_put((no_huff_entities >> 16) & 0xFF);
 
710
        sf_put((no_huff_entities >> 8) & 0xFF);
 
711
        sf_put((no_huff_entities) & 0xFF);
 
712
        size += 4;
 
713
        lx = Write_Strings_At + 12;
 
714
        sf_put((lx >> 24) & 0xFF);
 
715
        sf_put((lx >> 16) & 0xFF);
 
716
        sf_put((lx >> 8) & 0xFF);
 
717
        sf_put((lx) & 0xFF);
 
718
        size += 4;
 
719
 
 
720
        output_compression(huff_entity_root, &size);
 
721
      }
 
722
 
 
723
      if (size - origsize != compression_table_size)
 
724
        compiler_error("Compression table size mismatch.");
 
725
 
 
726
      origsize = size;
 
727
 
 
728
      for (lx=0, ix=0; lx<no_strings; lx++) {
 
729
        int escapelen=0, escapetype=0;
 
730
        int done=FALSE;
 
731
        int32 escapeval;
 
732
        if (compression_switch)
 
733
          sf_put(0xE1); /* type byte -- compressed string */
 
734
        else
 
735
          sf_put(0xE0); /* type byte -- non-compressed string */
 
736
        size++;
 
737
        jx = 0; 
 
738
        curbyte = 0;
 
739
        while (!done) {
 
740
          if (temporary_files_switch)
 
741
            ch = fgetc(Temp1_fp);
 
742
          else
 
743
            ch = read_byte_from_memory_block(&static_strings_area, ix);
 
744
          ix++;
 
745
          if (ix > static_strings_extent || ch < 0)
 
746
            compiler_error("Read too much not-yet-compressed text.");
 
747
 
 
748
          if (escapelen == -1) {
 
749
            escapelen = 0;
 
750
            if (ch == '@') {
 
751
              ch = '@';
 
752
            }
 
753
            else if (ch == '0') {
 
754
              ch = '\0';
 
755
            }
 
756
            else if (ch == 'A' || ch == 'D') {
 
757
              escapelen = 4;
 
758
              escapetype = ch;
 
759
              escapeval = 0;
 
760
              continue;
 
761
            }
 
762
            else {
 
763
              compiler_error("Strange @ escape in processed text.");
 
764
            }
 
765
          }
 
766
          else if (escapelen) {
 
767
            escapeval = (escapeval << 4) | ((ch-'A') & 0x0F);
 
768
            escapelen--;
 
769
            if (escapelen == 0) {
 
770
              if (escapetype == 'A') {
 
771
                ch = huff_abbrev_start+escapeval;
 
772
              }
 
773
              else if (escapetype == 'D') {
 
774
                ch = huff_dynam_start+escapeval;
 
775
              }
 
776
              else {
 
777
                compiler_error("Strange @ escape in processed text.");
 
778
              }
 
779
            }
 
780
            else 
 
781
              continue;
 
782
          }
 
783
          else {
 
784
            if (ch == '@') {
 
785
              escapelen = -1;
 
786
              continue;
 
787
            }
 
788
            if (ch == 0) {
 
789
              ch = 256;
 
790
              done = TRUE;
 
791
            }
 
792
          }
 
793
 
 
794
          if (compression_switch) {
 
795
            bits = &(huff_entities[ch].bits);
 
796
            depth = huff_entities[ch].depth;
 
797
            for (bx=0; bx<depth; bx++) {
 
798
              if (bits->b[bx / 8] & (1 << (bx % 8)))
 
799
                curbyte |= (1 << jx);
 
800
              jx++;
 
801
              if (jx == 8) {
 
802
                sf_put(curbyte);
 
803
                size++;
 
804
                curbyte = 0;
 
805
                jx = 0;
 
806
              }
 
807
            }
 
808
          }
 
809
          else {
 
810
            if (ch >= huff_dynam_start) {
 
811
              sf_put(' '); sf_put(' '); sf_put(' ');
 
812
              size += 3;
 
813
            }
 
814
            else if (ch >= huff_abbrev_start) {
 
815
              /* nothing */
 
816
            }
 
817
            else {
 
818
              /* 256, the string terminator, comes out as zero */
 
819
              sf_put(ch & 0xFF);
 
820
              size++;
 
821
            }
 
822
          }
 
823
        }
 
824
        if (compression_switch && jx) {
 
825
          sf_put(curbyte);
 
826
          size++;
 
827
        }
 
828
      }
 
829
      
 
830
      if (size - origsize != compression_string_size)
 
831
        compiler_error("Compression string size mismatch.");
 
832
 
 
833
    }
 
834
    
 
835
    /*  (4.5)  Output any null bytes (required to reach a GPAGESIZE address)
 
836
             before RAMSTART. */
 
837
 
 
838
    while (size % GPAGESIZE) { sf_put(0); size++; }
 
839
 
 
840
    /*  (5)  Output RAM. */
 
841
 
 
842
    for (i=0; i<RAM_Size; i++)
 
843
    {   sf_put(zmachine_paged_memory[i]); size++;
 
844
    }
 
845
 
 
846
    if (ferror(sf_handle))
 
847
        fatalerror("I/O failure: couldn't write to story file");
 
848
 
 
849
    fseek(sf_handle, 32, SEEK_SET);
 
850
    fputc((checksum_long >> 24) & 0xFF, sf_handle);
 
851
    fputc((checksum_long >> 16) & 0xFF, sf_handle);
 
852
    fputc((checksum_long >> 8) & 0xFF, sf_handle);
 
853
    fputc((checksum_long) & 0xFF, sf_handle);
 
854
 
 
855
    if (ferror(sf_handle))
 
856
      fatalerror("I/O failure: couldn't backtrack on story file for checksum");
 
857
 
 
858
    fclose(sf_handle);
 
859
 
 
860
#ifdef ARCHIMEDES
 
861
    {   char settype_command[PATHLEN];
 
862
        sprintf(settype_command, "settype %s %s",
 
863
            new_name, riscos_file_type());
 
864
        system(settype_command);
 
865
    }
 
866
#endif
 
867
#ifdef MAC_FACE
 
868
     if (module_switch)
 
869
         InformFiletypes (new_name, INF_MODULE_TYPE);
 
870
     else
 
871
         InformFiletypes (new_name, INF_ZCODE_TYPE);
 
872
#endif
 
873
}
 
874
 
 
875
extern void output_file(void)
 
876
{
 
877
  if (!glulx_mode)
 
878
    output_file_z();
 
879
  else
 
880
    output_file_g();
 
881
}
 
882
 
 
883
/* ------------------------------------------------------------------------- */
 
884
/*   Output the text transcript file (only called if there is to be one).    */
 
885
/* ------------------------------------------------------------------------- */
 
886
 
 
887
FILE *transcript_file_handle; int transcript_open;
 
888
 
 
889
extern void write_to_transcript_file(char *text)
 
890
{   fputs(text, transcript_file_handle);
 
891
    fputc('\n', transcript_file_handle);
 
892
}
 
893
 
 
894
extern void open_transcript_file(char *what_of)
 
895
{   char topline_buffer[256];
 
896
 
 
897
    transcript_file_handle = fopen(Transcript_Name,"w");
 
898
    if (transcript_file_handle==NULL)
 
899
        fatalerror_named("Couldn't open transcript file",
 
900
        Transcript_Name);
 
901
 
 
902
    transcript_open = TRUE;
 
903
 
 
904
    sprintf(topline_buffer, "Transcript of the text of \"%s\"\n\
 
905
[From %s]\n", what_of, banner_line);
 
906
    write_to_transcript_file(topline_buffer);
 
907
}
 
908
 
 
909
extern void abort_transcript_file(void)
 
910
{   if (transcript_switch && transcript_open)
 
911
        fclose(transcript_file_handle);
 
912
    transcript_open = FALSE;
 
913
}
 
914
 
 
915
extern void close_transcript_file(void)
 
916
{   char botline_buffer[256];
 
917
    char sn_buffer[7];
 
918
 
 
919
    write_serial_number(sn_buffer);
 
920
    sprintf(botline_buffer, "\n[End of transcript: release %d.%s]\n",
 
921
        release_number, sn_buffer);
 
922
    write_to_transcript_file(botline_buffer);
 
923
 
 
924
    if (ferror(transcript_file_handle))
 
925
        fatalerror("I/O failure: couldn't write to transcript file");
 
926
    fclose(transcript_file_handle);
 
927
    transcript_open = FALSE;
 
928
 
 
929
#ifdef ARCHIMEDES
 
930
    {   char settype_command[PATHLEN];
 
931
        sprintf(settype_command, "settype %s text",
 
932
            Transcript_Name);
 
933
        system(settype_command);
 
934
    }
 
935
#endif
 
936
#ifdef MAC_FACE
 
937
    InformFiletypes (Transcript_Name, INF_TEXT_TYPE);
 
938
#endif
 
939
}
 
940
 
 
941
/* ------------------------------------------------------------------------- */
 
942
/*   Access to the debugging information file.                               */
 
943
/* ------------------------------------------------------------------------- */
 
944
 
 
945
static FILE *Debug_fp;                 /* Handle of debugging info file      */
 
946
 
 
947
extern void open_debug_file(void)
 
948
{   Debug_fp=fopen(Debugging_Name,"wb");
 
949
    if (Debug_fp==NULL)
 
950
       fatalerror_named("Couldn't open debugging information file",
 
951
           Debugging_Name);
 
952
}
 
953
 
 
954
extern void close_debug_file(void)
 
955
{   fputc(EOF_DBR, Debug_fp);
 
956
    if (ferror(Debug_fp))
 
957
        fatalerror("I/O failure: can't write to debugging info file");
 
958
    fclose(Debug_fp);
 
959
#ifdef MAC_FACE
 
960
    InformFiletypes (Debugging_Name, INF_DEBUG_TYPE);
 
961
#endif
 
962
}
 
963
 
 
964
extern void write_debug_byte(int i)
 
965
{
 
966
    /*  All output to the debugging file is funneled through this routine    */
 
967
 
 
968
    fputc(i,Debug_fp);
 
969
    if (ferror(Debug_fp))
 
970
        fatalerror("I/O failure: can't write to debugging info file");
 
971
}
 
972
 
 
973
extern void write_debug_string(char *s)
 
974
{
 
975
    /*  Write a null-terminated string into the debugging file.              */
 
976
 
 
977
    int i;
 
978
    for (i=0; s[i]!=0; i++)
 
979
        write_debug_byte((int) s[i]);
 
980
    write_debug_byte(0);
 
981
}
 
982
 
 
983
extern void write_debug_address(int32 i)
 
984
{
 
985
    /*  Write a 3-byte address (capable of being a byte address in a story
 
986
        file whose size may be as much as 512K) into the debugging file.
 
987
        Also used for character positions in source files.                   */
 
988
 
 
989
    write_debug_byte((int)((i/256)/256));
 
990
    write_debug_byte((int)((i/256)%256));
 
991
    write_debug_byte((int)(i%256));
 
992
}
 
993
 
 
994
/* ------------------------------------------------------------------------- */
 
995
/*   There is a standard four-byte format to express code line refs in the   */
 
996
/*   debugging file: if X is a dbgl,                                         */
 
997
/*                                                                           */
 
998
/*       X.b1 = file number (input files to Inform are numbered from 1 in    */
 
999
/*              order of being opened)                                       */
 
1000
/*       X.b2, X.b3 = high byte, low byte of line in this file (numbered     */
 
1001
/*              from 1)                                                      */
 
1002
/*       X.cc = character position in current line                           */
 
1003
/* ------------------------------------------------------------------------- */
 
1004
 
 
1005
extern void write_dbgl(dbgl x)
 
1006
{   write_debug_byte(x.b1);
 
1007
    write_debug_byte(x.b2); write_debug_byte(x.b3);
 
1008
    write_debug_byte(x.cc);
 
1009
}
 
1010
 
 
1011
extern void begin_debug_file(void)
 
1012
{   open_debug_file();
 
1013
 
 
1014
    /* DEBF == Debugging File (sorry) */
 
1015
    write_debug_byte(0xDE); write_debug_byte(0xBF);
 
1016
 
 
1017
    /* Debugging file format version number */
 
1018
    write_debug_byte(0); write_debug_byte(0);
 
1019
 
 
1020
    /* Identify ourselves */
 
1021
    write_debug_byte(VNUMBER/256); write_debug_byte(VNUMBER%256);
 
1022
}
 
1023
 
 
1024
/* ------------------------------------------------------------------------- */
 
1025
/*  Temporary storage files:                                                 */
 
1026
/*                                                                           */
 
1027
/*      Temp file 1 is used to hold the static strings area, as compiled     */
 
1028
/*                2 to hold compiled routines of Z-code                      */
 
1029
/*                3 to hold the link data table (but only for modules)       */
 
1030
/*                                                                           */
 
1031
/*  (Though annoying, this procedure typically saves about 200K of memory,   */
 
1032
/*  an important point for Amiga and sub-386 PC users of Inform)             */
 
1033
/* ------------------------------------------------------------------------- */
 
1034
 
 
1035
extern void open_temporary_files(void)
 
1036
{   translate_temp_filename(1);
 
1037
    Temp1_fp=fopen(Temp1_Name,"wb");
 
1038
    if (Temp1_fp==NULL) fatalerror_named("Couldn't open temporary file 1",
 
1039
        Temp1_Name);
 
1040
    translate_temp_filename(2);
 
1041
    Temp2_fp=fopen(Temp2_Name,"wb");
 
1042
    if (Temp2_fp==NULL) fatalerror_named("Couldn't open temporary file 2",
 
1043
        Temp2_Name);
 
1044
 
 
1045
    if (!module_switch) return;
 
1046
    translate_temp_filename(3);
 
1047
    Temp3_fp=fopen(Temp3_Name,"wb");
 
1048
    if (Temp3_fp==NULL) fatalerror_named("Couldn't open temporary file 3",
 
1049
        Temp3_Name);
 
1050
}
 
1051
 
 
1052
extern void check_temp_files(void)
 
1053
{
 
1054
    if (ferror(Temp1_fp))
 
1055
        fatalerror("I/O failure: couldn't write to temporary file 1");
 
1056
    if (ferror(Temp2_fp))
 
1057
        fatalerror("I/O failure: couldn't write to temporary file 2");
 
1058
    if (module_switch && ferror(Temp3_fp))
 
1059
        fatalerror("I/O failure: couldn't write to temporary file 3");
 
1060
}
 
1061
 
 
1062
extern void remove_temp_files(void)
 
1063
{   if (Temp1_fp != NULL) fclose(Temp1_fp);
 
1064
    if (Temp2_fp != NULL) fclose(Temp2_fp);
 
1065
    remove(Temp1_Name); remove(Temp2_Name);
 
1066
    if (module_switch)
 
1067
    {   if (Temp3_fp != NULL) fclose(Temp3_fp);
 
1068
        remove(Temp3_Name);
 
1069
    }
 
1070
}
 
1071
 
 
1072
/* ========================================================================= */
 
1073
/*   Data structure management routines                                      */
 
1074
/* ------------------------------------------------------------------------- */
 
1075
 
 
1076
extern void init_files_vars(void)
 
1077
{   malloced_bytes = 0;
 
1078
    checksum_low_byte = 0; /* Z-code */
 
1079
    checksum_high_byte = 0;
 
1080
    checksum_long = 0; /* Glulx */
 
1081
    checksum_count = 0;
 
1082
    transcript_open = FALSE;
 
1083
}
 
1084
 
 
1085
extern void files_begin_prepass(void)
 
1086
{   input_file = 0;
 
1087
}
 
1088
 
 
1089
extern void files_begin_pass(void)
 
1090
{   total_chars_read=0;
 
1091
    if (temporary_files_switch)
 
1092
        open_temporary_files();
 
1093
}
 
1094
 
 
1095
extern void files_allocate_arrays(void)
 
1096
{   filename_storage = my_malloc(MAX_SOURCE_FILES*64, "filename storage");
 
1097
    filename_storage_p = filename_storage;
 
1098
    filename_storage_left = MAX_SOURCE_FILES*64;
 
1099
    InputFiles = my_malloc(MAX_SOURCE_FILES*sizeof(FileId), 
 
1100
        "input file storage");
 
1101
}
 
1102
 
 
1103
extern void files_free_arrays(void)
 
1104
{   my_free(&filename_storage, "filename storage");
 
1105
    my_free(&InputFiles, "input file storage");
 
1106
}
 
1107
 
 
1108
/* ========================================================================= */