~ubuntu-branches/ubuntu/gutsy/inform/gutsy

« back to all changes in this revision

Viewing changes to src/inform.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Baker
  • Date: 2004-03-29 23:52:44 UTC
  • Revision ID: james.westby@ubuntu.com-20040329235244-fox1z1yv7d6vojoo
Tags: upstream-6.30
ImportĀ upstreamĀ versionĀ 6.30

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ------------------------------------------------------------------------- */
 
2
/*   "inform" :  The top level of Inform: switches, pathnames, filenaming    */
 
3
/*               conventions, ICL (Inform Command Line) files, main          */
 
4
/*                                                                           */
 
5
/*   Part of Inform 6.30                                                     */
 
6
/*   copyright (c) Graham Nelson 1993 - 2004                                 */
 
7
/*                                                                           */
 
8
/* ------------------------------------------------------------------------- */
 
9
 
 
10
#define MAIN_INFORM_FILE
 
11
#include "header.h"
 
12
 
 
13
/* ------------------------------------------------------------------------- */
 
14
/*   Compiler progress                                                       */
 
15
/* ------------------------------------------------------------------------- */
 
16
 
 
17
static int no_compilations;
 
18
 
 
19
int endofpass_flag;      /* set to TRUE when an "end" directive is reached
 
20
                            (the inputs routines insert one into the stream
 
21
                            if necessary)                                    */
 
22
 
 
23
/* ------------------------------------------------------------------------- */
 
24
/*   Version control                                                         */
 
25
/* ------------------------------------------------------------------------- */
 
26
 
 
27
/* This stuff is Z-code only, for now. It might handle multiple Glulx
 
28
   versions someday, if needed. */
 
29
 
 
30
int version_number,      /* 3 to 8                                           */
 
31
    instruction_set_number,
 
32
                         /* 3 to 6: versions 7 and 8 use instruction set of
 
33
                            version 5                                        */
 
34
    extend_memory_map;   /* extend using function- and string-offsets        */
 
35
int32 scale_factor,      /* packed address multiplier                        */
 
36
    length_scale_factor; /* length-in-header multiplier                      */
 
37
 
 
38
extern void select_version(int vn)
 
39
{   version_number = vn;
 
40
    extend_memory_map = FALSE;
 
41
    if ((version_number==6)||(version_number==7)) extend_memory_map = TRUE;
 
42
 
 
43
    scale_factor = 4;
 
44
    if (version_number==3) scale_factor = 2;
 
45
    if (version_number==8) scale_factor = 8;
 
46
 
 
47
    length_scale_factor = scale_factor;
 
48
    if ((version_number==6)||(version_number==7)) length_scale_factor = 8;
 
49
 
 
50
    instruction_set_number = version_number;
 
51
    if ((version_number==7)||(version_number==8)) instruction_set_number = 5;
 
52
}
 
53
 
 
54
/* ------------------------------------------------------------------------- */
 
55
/*   Target: variables which vary between the Z-machine and Glulx            */
 
56
/* ------------------------------------------------------------------------- */
 
57
 
 
58
int   WORDSIZE;            /* Size of a machine word: 2 or 4 */
 
59
int32 MAXINTWORD;          /* 0x7FFF or 0x7FFFFFFF */
 
60
 
 
61
/* The first property number which is an individual property. The
 
62
   eight class-system i-props (create, recreate, ... print_to_array)
 
63
   are numbered from INDIV_PROP_START to INDIV_PROP_START+7.
 
64
*/
 
65
int INDIV_PROP_START;
 
66
 
 
67
/* The length of an object, as written in tables.c. It's easier to define
 
68
   it here than to repeat the same expression all over the source code.
 
69
   Not used in Z-code. 
 
70
*/
 
71
int OBJECT_BYTE_LENGTH;
 
72
 
 
73
static void select_target(int targ)
 
74
{
 
75
  if (!targ) {
 
76
    /* Z-machine */
 
77
    WORDSIZE = 2;
 
78
    MAXINTWORD = 0x7FFF;
 
79
    INDIV_PROP_START = 64;
 
80
    OBJECT_BYTE_LENGTH = 0; /* not used */
 
81
 
 
82
    if (DICT_WORD_SIZE != 6) {
 
83
      DICT_WORD_SIZE = 6;
 
84
      warning("You cannot change DICT_WORD_SIZE in Z-code; resetting to 6");
 
85
    }
 
86
    if (NUM_ATTR_BYTES != 6) {
 
87
      NUM_ATTR_BYTES = 6;
 
88
      warning("You cannot change NUM_ATTR_BYTES in Z-code; resetting to 6");
 
89
    }
 
90
    if (MAX_LOCAL_VARIABLES != 16) {
 
91
      MAX_LOCAL_VARIABLES = 16;
 
92
      warning("You cannot change MAX_LOCAL_VARIABLES in Z-code; resetting to 16");
 
93
    }
 
94
    if (MAX_GLOBAL_VARIABLES != 240) {
 
95
      MAX_GLOBAL_VARIABLES = 240;
 
96
      warning("You cannot change MAX_GLOBAL_VARIABLES in Z-code; resetting to 240");
 
97
    }
 
98
  }
 
99
  else {
 
100
    /* Glulx */
 
101
    WORDSIZE = 4;
 
102
    MAXINTWORD = 0x7FFFFFFF;
 
103
    INDIV_PROP_START = 256; /* This could be a memory setting */
 
104
    scale_factor = 0; /* It should never even get used in Glulx */
 
105
 
 
106
    if (NUM_ATTR_BYTES % 4 != 3) {
 
107
      NUM_ATTR_BYTES += (3 - (NUM_ATTR_BYTES % 4)); 
 
108
      warning_numbered("NUM_ATTR_BYTES must be a multiple of four, plus three. Increasing to", NUM_ATTR_BYTES);
 
109
    }
 
110
 
 
111
    OBJECT_BYTE_LENGTH = (1 + (NUM_ATTR_BYTES) + 6*4);
 
112
  }
 
113
 
 
114
  if (MAX_LOCAL_VARIABLES >= 120) {
 
115
    MAX_LOCAL_VARIABLES = 119;
 
116
    warning("MAX_LOCAL_VARIABLES cannot exceed 119; resetting to 119");
 
117
    /* This is because the keyword table in the lexer only has 120
 
118
       entries. */
 
119
  }
 
120
  if (DICT_WORD_SIZE > MAX_DICT_WORD_SIZE) {
 
121
    DICT_WORD_SIZE = MAX_DICT_WORD_SIZE;
 
122
    warning_numbered(
 
123
      "DICT_WORD_SIZE cannot exceed MAX_DICT_WORD_SIZE; resetting", 
 
124
      MAX_DICT_WORD_SIZE);
 
125
    /* MAX_DICT_WORD_SIZE can be increased in header.h without fear. */
 
126
  }
 
127
  if (NUM_ATTR_BYTES > MAX_NUM_ATTR_BYTES) {
 
128
    NUM_ATTR_BYTES = MAX_NUM_ATTR_BYTES;
 
129
    warning_numbered(
 
130
      "NUM_ATTR_BYTES cannot exceed MAX_NUM_ATTR_BYTES; resetting",
 
131
      MAX_NUM_ATTR_BYTES);
 
132
    /* MAX_NUM_ATTR_BYTES can be increased in header.h without fear. */
 
133
  }
 
134
}
 
135
 
 
136
/* ------------------------------------------------------------------------- */
 
137
/*   Tracery: output control variables                                       */
 
138
/* ------------------------------------------------------------------------- */
 
139
 
 
140
int asm_trace_level,     /* trace assembly: 0 for off, 1 for assembly
 
141
                            only, 2 for full assembly tracing with hex dumps */
 
142
    line_trace_level,    /* line tracing: 0 off, 1 on                        */
 
143
    expr_trace_level,    /* expression tracing: 0 off, 1 full, 2 brief       */
 
144
    linker_trace_level,  /* set by -y: 0 to 4 levels of tracing              */
 
145
    tokens_trace_level;  /* lexer output tracing: 0 off, 1 on                */
 
146
 
 
147
/* ------------------------------------------------------------------------- */
 
148
/*   On/off switch variables (by default all FALSE); other switch settings   */
 
149
/* ------------------------------------------------------------------------- */
 
150
 
 
151
int bothpasses_switch,              /* -b */
 
152
    concise_switch,                 /* -c */
 
153
    economy_switch,                 /* -e */
 
154
    frequencies_switch,             /* -f */
 
155
    ignore_switches_switch,         /* -i */
 
156
    listobjects_switch,             /* -j */
 
157
    debugfile_switch,               /* -k */
 
158
    listing_switch,                 /* -l */
 
159
    memout_switch,                  /* -m */
 
160
    printprops_switch,              /* -n */
 
161
    offsets_switch,                 /* -o */
 
162
    percentages_switch,             /* -p */
 
163
    obsolete_switch,                /* -q */
 
164
    transcript_switch,              /* -r */
 
165
    statistics_switch,              /* -s */
 
166
    optimise_switch,                /* -u */
 
167
    version_set_switch,             /* -v */
 
168
    nowarnings_switch,              /* -w */
 
169
    hash_switch,                    /* -x */
 
170
    memory_map_switch,              /* -z */
 
171
    oddeven_packing_switch,         /* -B */
 
172
    define_DEBUG_switch,            /* -D */
 
173
    temporary_files_switch,         /* -F */
 
174
    module_switch,                  /* -M */
 
175
    runtime_error_checking_switch,  /* -S */
 
176
    define_USE_MODULES_switch,      /* -U */
 
177
    define_INFIX_switch;            /* -X */
 
178
#ifdef ARC_THROWBACK
 
179
int throwback_switch;               /* -T */
 
180
#endif
 
181
#ifdef ARCHIMEDES
 
182
int riscos_file_type_format;        /* set by -R */
 
183
#endif
 
184
int compression_switch;             /* set by -H */
 
185
int character_set_setting,          /* set by -C */
 
186
    error_format,                   /* set by -E */
 
187
    asm_trace_setting,              /* set by -a and -t: value of
 
188
                                       asm_trace_level to use when tracing */
 
189
    double_space_setting,           /* set by -d: 0, 1 or 2 */
 
190
    trace_fns_setting,              /* set by -g: 0, 1 or 2 */
 
191
    linker_trace_setting,           /* set by -y: ditto for linker_... */
 
192
    header_ext_setting,             /* set by -W */
 
193
    store_the_text;                 /* when set, record game text to a chunk
 
194
                                       of memory (used by both -r & -k) */
 
195
static int r_e_c_s_set;             /* has -S been explicitly set? */
 
196
 
 
197
int glulx_mode;                     /* -G */
 
198
 
 
199
static void reset_switch_settings(void)
 
200
{   asm_trace_setting=0;
 
201
    linker_trace_level=0;
 
202
    tokens_trace_level=0;
 
203
 
 
204
    store_the_text = FALSE;
 
205
 
 
206
    bothpasses_switch = FALSE;
 
207
    concise_switch = FALSE;
 
208
    double_space_setting = 0;
 
209
    economy_switch = FALSE;
 
210
    frequencies_switch = FALSE;
 
211
    trace_fns_setting = 0;
 
212
    ignore_switches_switch = FALSE;
 
213
    listobjects_switch = FALSE;
 
214
    debugfile_switch = FALSE;
 
215
    listing_switch = FALSE;
 
216
    memout_switch = FALSE;
 
217
    printprops_switch = FALSE;
 
218
    offsets_switch = FALSE;
 
219
    percentages_switch = FALSE;
 
220
    obsolete_switch = FALSE;
 
221
    transcript_switch = FALSE;
 
222
    statistics_switch = FALSE;
 
223
    optimise_switch = FALSE;
 
224
    version_set_switch = FALSE;
 
225
    nowarnings_switch = FALSE;
 
226
    hash_switch = FALSE;
 
227
    memory_map_switch = FALSE;
 
228
    oddeven_packing_switch = FALSE;
 
229
    define_DEBUG_switch = FALSE;
 
230
#ifdef USE_TEMPORARY_FILES
 
231
    temporary_files_switch = TRUE;
 
232
#else
 
233
    temporary_files_switch = FALSE;
 
234
#endif
 
235
    define_USE_MODULES_switch = FALSE;
 
236
    module_switch = FALSE;
 
237
#ifdef ARC_THROWBACK
 
238
    throwback_switch = FALSE;
 
239
#endif
 
240
    runtime_error_checking_switch = TRUE;
 
241
    r_e_c_s_set = FALSE;
 
242
    define_INFIX_switch = FALSE;
 
243
#ifdef ARCHIMEDES
 
244
    riscos_file_type_format = 0;
 
245
#endif
 
246
    error_format=DEFAULT_ERROR_FORMAT;
 
247
 
 
248
    character_set_setting = 1;                     /* Default is ISO Latin-1 */
 
249
    header_ext_setting = 0;
 
250
 
 
251
    compression_switch = TRUE;
 
252
    glulx_mode = FALSE;
 
253
}
 
254
 
 
255
/* ------------------------------------------------------------------------- */
 
256
/*   Number of files given as command line parameters (0, 1 or 2)            */
 
257
/* ------------------------------------------------------------------------- */
 
258
 
 
259
static int cli_files_specified,
 
260
           convert_filename_flag;
 
261
 
 
262
char Source_Name[100];                 /* Processed name of first input file */
 
263
char Code_Name[100];                   /* Processed name of output file      */
 
264
 
 
265
static char *cli_file1, *cli_file2;    /* Unprocessed (and unsafe to alter)  */
 
266
 
 
267
/* ========================================================================= */
 
268
/*   Data structure management routines                                      */
 
269
/* ------------------------------------------------------------------------- */
 
270
 
 
271
static void init_vars(void)
 
272
{
 
273
    init_arrays_vars();
 
274
    init_asm_vars();
 
275
    init_bpatch_vars();
 
276
    init_chars_vars();
 
277
    init_directs_vars();
 
278
    init_errors_vars();
 
279
    init_expressc_vars();
 
280
    init_expressp_vars();
 
281
    init_files_vars();
 
282
    init_lexer_vars();
 
283
    init_linker_vars();
 
284
    init_memory_vars();
 
285
    init_objects_vars();
 
286
    init_states_vars();
 
287
    init_symbols_vars();
 
288
    init_syntax_vars();
 
289
    init_tables_vars();
 
290
    init_text_vars();
 
291
    init_veneer_vars();
 
292
    init_verbs_vars();
 
293
}
 
294
 
 
295
static void begin_pass(void)
 
296
{
 
297
    arrays_begin_pass();
 
298
    asm_begin_pass();
 
299
    bpatch_begin_pass();
 
300
    chars_begin_pass();
 
301
    directs_begin_pass();
 
302
    errors_begin_pass();
 
303
    expressc_begin_pass();
 
304
    expressp_begin_pass();
 
305
    files_begin_pass();
 
306
 
 
307
    endofpass_flag = FALSE;
 
308
    line_trace_level = 0; expr_trace_level = 0;
 
309
    asm_trace_level = asm_trace_setting;
 
310
    linker_trace_level = linker_trace_setting;
 
311
    if (listing_switch) line_trace_level=1;
 
312
 
 
313
    lexer_begin_pass();
 
314
    linker_begin_pass();
 
315
    memory_begin_pass();
 
316
    objects_begin_pass();
 
317
    states_begin_pass();
 
318
    symbols_begin_pass();
 
319
    syntax_begin_pass();
 
320
    tables_begin_pass();
 
321
    text_begin_pass();
 
322
    veneer_begin_pass();
 
323
    verbs_begin_pass();
 
324
 
 
325
    if (!module_switch)
 
326
    {
 
327
        /*  Compile a Main__ routine (see "veneer.c")  */
 
328
 
 
329
        compile_initial_routine();
 
330
 
 
331
        /*  Make the four metaclasses: Class must be object number 1, so
 
332
            it must come first  */
 
333
 
 
334
        veneer_mode = TRUE;
 
335
 
 
336
        make_class("Class");
 
337
        make_class("Object");
 
338
        make_class("Routine");
 
339
        make_class("String");
 
340
 
 
341
        veneer_mode = FALSE;
 
342
    }
 
343
}
 
344
 
 
345
extern void allocate_arrays(void)
 
346
{
 
347
    arrays_allocate_arrays();
 
348
    asm_allocate_arrays();
 
349
    bpatch_allocate_arrays();
 
350
    chars_allocate_arrays();
 
351
    directs_allocate_arrays();
 
352
    errors_allocate_arrays();
 
353
    expressc_allocate_arrays();
 
354
    expressp_allocate_arrays();
 
355
    files_allocate_arrays();
 
356
 
 
357
    lexer_allocate_arrays();
 
358
    linker_allocate_arrays();
 
359
    memory_allocate_arrays();
 
360
    objects_allocate_arrays();
 
361
    states_allocate_arrays();
 
362
    symbols_allocate_arrays();
 
363
    syntax_allocate_arrays();
 
364
    tables_allocate_arrays();
 
365
    text_allocate_arrays();
 
366
    veneer_allocate_arrays();
 
367
    verbs_allocate_arrays();
 
368
}
 
369
 
 
370
extern void free_arrays(void)
 
371
{
 
372
    /*  One array may survive this routine, all_the_text (used to hold
 
373
        game text until the abbreviations optimiser begins work on it): this
 
374
        array (if it was ever allocated) is freed at the top level.          */
 
375
 
 
376
    arrays_free_arrays();
 
377
    asm_free_arrays();
 
378
    bpatch_free_arrays();
 
379
    chars_free_arrays();
 
380
    directs_free_arrays();
 
381
    errors_free_arrays();
 
382
    expressc_free_arrays();
 
383
    expressp_free_arrays();
 
384
    files_free_arrays();
 
385
 
 
386
    lexer_free_arrays();
 
387
    linker_free_arrays();
 
388
    memory_free_arrays();
 
389
    objects_free_arrays();
 
390
    states_free_arrays();
 
391
    symbols_free_arrays();
 
392
    syntax_free_arrays();
 
393
    tables_free_arrays();
 
394
    text_free_arrays();
 
395
    veneer_free_arrays();
 
396
    verbs_free_arrays();
 
397
}
 
398
 
 
399
/* ------------------------------------------------------------------------- */
 
400
/*    Name translation code for filenames                                    */
 
401
/* ------------------------------------------------------------------------- */
 
402
 
 
403
static char Source_Path[PATHLEN];
 
404
static char Include_Path[PATHLEN];
 
405
static char Code_Path[PATHLEN];
 
406
static char Module_Path[PATHLEN];
 
407
static char Temporary_Path[PATHLEN];
 
408
static char current_source_path[PATHLEN];
 
409
       char Debugging_Name[PATHLEN];
 
410
       char Transcript_Name[PATHLEN];
 
411
       char Language_Name[PATHLEN];
 
412
       char Charset_Map[PATHLEN];
 
413
static char ICL_Path[PATHLEN];
 
414
 
 
415
static void set_path_value(char *path, char *value)
 
416
{   int i, j;
 
417
 
 
418
    for (i=0, j=0;;)
 
419
    {   if ((value[j] == FN_ALT) || (value[j] == 0))
 
420
        {   if ((value[j] == FN_ALT)
 
421
                && (path != Source_Path) && (path != Include_Path)
 
422
                && (path != ICL_Path) && (path != Module_Path))
 
423
            {   printf("The character '%c' is used to divide entries in a list \
 
424
of possible locations, and can only be used in the Include_Path, Source_Path, \
 
425
Module_Path or ICL_Path variables. Other paths are for output only.", FN_ALT);
 
426
                exit(1);
 
427
            }
 
428
            if ((path != Debugging_Name) && (path != Transcript_Name)
 
429
                 && (path != Language_Name) && (path != Charset_Map)
 
430
                 && (i>0) && (isalnum(path[i-1]))) path[i++] = FN_SEP;
 
431
            path[i++] = value[j++];
 
432
            if (value[j-1] == 0) return;
 
433
        }
 
434
        else path[i++] = value[j++];
 
435
    }
 
436
}
 
437
 
 
438
static void set_default_paths(void)
 
439
{
 
440
    set_path_value(Source_Path,     Source_Directory);
 
441
    set_path_value(Include_Path,    Include_Directory);
 
442
    set_path_value(Code_Path,       Code_Directory);
 
443
    set_path_value(Module_Path,     Module_Directory);
 
444
    set_path_value(ICL_Path,        ICL_Directory);
 
445
    set_path_value(Temporary_Path,  Temporary_Directory);
 
446
    set_path_value(Debugging_Name,  Debugging_File);
 
447
    set_path_value(Transcript_Name, Transcript_File);
 
448
    set_path_value(Language_Name,   "English");
 
449
    set_path_value(Charset_Map,     "");
 
450
}
 
451
 
 
452
static void set_path_command(char *command)
 
453
{   int i, j; char *path_to_set = NULL, *new_value;
 
454
    for (i=0; (command[i]!=0) && (command[i]!='=');i++) ;
 
455
 
 
456
    if (command[i]==0) { new_value=command; path_to_set=Include_Path; }
 
457
    else
 
458
    {   char pathname[PATHLEN];
 
459
        if (i>=PATHLEN) i=PATHLEN-1;
 
460
        new_value = command+i+1;
 
461
        for (j=0;j<i;j++)
 
462
            if (isupper(command[j])) pathname[j]=tolower(command[j]);
 
463
            else pathname[j]=command[j];
 
464
        pathname[j]=0;
 
465
 
 
466
        if (strcmp(pathname, "source_path")==0)  path_to_set=Source_Path;
 
467
        if (strcmp(pathname, "include_path")==0) path_to_set=Include_Path;
 
468
        if (strcmp(pathname, "code_path")==0)    path_to_set=Code_Path;
 
469
        if (strcmp(pathname, "module_path")==0)  path_to_set=Module_Path;
 
470
        if (strcmp(pathname, "icl_path")==0)     path_to_set=ICL_Path;
 
471
        if (strcmp(pathname, "temporary_path")==0) path_to_set=Temporary_Path;
 
472
        if (strcmp(pathname, "debugging_name")==0) path_to_set=Debugging_Name;
 
473
        if (strcmp(pathname, "transcript_name")==0) path_to_set=Transcript_Name;
 
474
        if (strcmp(pathname, "language_name")==0) path_to_set=Language_Name;
 
475
        if (strcmp(pathname, "charset_map")==0) path_to_set=Charset_Map;
 
476
 
 
477
        if (path_to_set == NULL)
 
478
        {   printf("No such path setting as \"%s\"\n", pathname);
 
479
            exit(1);
 
480
        }
 
481
    }
 
482
 
 
483
    set_path_value(path_to_set, new_value);
 
484
}
 
485
 
 
486
static int contains_separator(char *name)
 
487
{   int i;
 
488
    for (i=0; name[i]!=0; i++)
 
489
        if (name[i] == FN_SEP) return 1;
 
490
    return 0;
 
491
}
 
492
 
 
493
static int write_translated_name(char *new_name, char *old_name,
 
494
                                 char *prefix_path, int start_pos,
 
495
                                 char *extension)
 
496
{   int x;
 
497
    if (prefix_path == NULL)
 
498
    {   sprintf(new_name,"%s%s", old_name, extension);
 
499
        return 0;
 
500
    }
 
501
    strcpy(new_name, prefix_path + start_pos);
 
502
    for (x=0; (new_name[x]!=0) && (new_name[x]!=FN_ALT); x++) ;
 
503
    if (new_name[x] == 0) start_pos = 0; else start_pos += x+1;
 
504
    sprintf(new_name + x, "%s%s", old_name, extension);
 
505
    return start_pos;
 
506
}
 
507
 
 
508
#ifdef FILE_EXTENSIONS
 
509
static char *check_extension(char *name, char *extension)
 
510
{   int i;
 
511
 
 
512
    /* If a filename ends in '.', remove the dot and add no file extension: */
 
513
    i = strlen(name)-1;
 
514
    if (name[i] == '.') { name[i]=0; return ""; }
 
515
 
 
516
    /* Remove the new extension if it's already got one: */
 
517
 
 
518
    for (; (i>=0) && (name[i]!=FN_SEP); i--)
 
519
        if (name[i] == '.') return "";
 
520
    return extension;
 
521
}
 
522
#endif
 
523
 
 
524
/* ------------------------------------------------------------------------- */
 
525
/*    Three translation routines have to deal with path variables which may  */
 
526
/*    contain alternative locations separated by the FN_ALT character.       */
 
527
/*    These have the protocol:                                               */
 
528
/*                                                                           */
 
529
/*        int translate_*_filename(int last_value, ...)                      */
 
530
/*                                                                           */
 
531
/*    and should first be called with last_value equal to 0.  If the         */
 
532
/*    translated filename works, fine.  Otherwise, if the returned integer   */
 
533
/*    was zero, the caller knows that no filename works and can issue an     */
 
534
/*    error message.  If it was non-zero, the caller should pass it on as    */
 
535
/*    the last_value again.                                                  */
 
536
/*                                                                           */
 
537
/*    As implemented below, last_value is the position in the path variable  */
 
538
/*    string at which the next directory name to try begins.                 */
 
539
/* ------------------------------------------------------------------------- */
 
540
 
 
541
extern int translate_in_filename(int last_value,
 
542
    char *new_name, char *old_name,
 
543
    int same_directory_flag, int command_line_flag)
 
544
{   char *prefix_path = NULL;
 
545
    char *extension;
 
546
    int add_path_flag = 1;
 
547
    int i;
 
548
 
 
549
    if ((same_directory_flag==0)
 
550
        && (contains_separator(old_name)==1)) add_path_flag=0;
 
551
 
 
552
    if (add_path_flag==1)
 
553
    {   if (command_line_flag == 0)
 
554
        {   /* File is opened as a result of an Include directive */
 
555
 
 
556
            if (same_directory_flag==1)
 
557
                prefix_path = current_source_path;
 
558
            else
 
559
                if (Include_Path[0]!=0) prefix_path = Include_Path;
 
560
        }
 
561
        /* Main file being opened from the command line */
 
562
 
 
563
        else if (Source_Path[0]!=0) prefix_path = Source_Path;
 
564
    }
 
565
 
 
566
#ifdef FILE_EXTENSIONS
 
567
    /* Which file extension is expected? */
 
568
 
 
569
    if ((command_line_flag==1)||(same_directory_flag==1))
 
570
        extension = Source_Extension;
 
571
    else
 
572
        extension = Include_Extension;
 
573
 
 
574
    extension = check_extension(old_name, extension);
 
575
#else
 
576
    extension = "";
 
577
#endif
 
578
 
 
579
    last_value = write_translated_name(new_name, old_name,
 
580
                     prefix_path, last_value, extension);
 
581
 
 
582
    /* Set the "current source path" (for use of Include ">...") */
 
583
 
 
584
    if (command_line_flag==1)
 
585
    {   strcpy(current_source_path, new_name);
 
586
        for (i=strlen(current_source_path)-1;
 
587
             ((i>0)&&(current_source_path[i]!=FN_SEP));i--) ;
 
588
 
 
589
        if (i!=0) current_source_path[i+1] = 0; /* Current file in subdir   */
 
590
        else current_source_path[0] = 0;        /* Current file at root dir */
 
591
    }
 
592
 
 
593
    return last_value;
 
594
}
 
595
 
 
596
extern int translate_link_filename(int last_value,
 
597
    char *new_name, char *old_name)
 
598
{   char *prefix_path = NULL;
 
599
    char *extension;
 
600
 
 
601
    if (contains_separator(old_name)==0)
 
602
        if (Module_Path[0]!=0)
 
603
            prefix_path = Module_Path;
 
604
 
 
605
#ifdef FILE_EXTENSIONS
 
606
    extension = check_extension(old_name, Module_Extension);
 
607
#else
 
608
    extension = "";
 
609
#endif
 
610
 
 
611
    return write_translated_name(new_name, old_name,
 
612
               prefix_path, last_value, extension);
 
613
}
 
614
 
 
615
static int translate_icl_filename(int last_value,
 
616
    char *new_name, char *old_name)
 
617
{   char *prefix_path = NULL;
 
618
    char *extension = "";
 
619
 
 
620
    if (contains_separator(old_name)==0)
 
621
        if (ICL_Path[0]!=0)
 
622
            prefix_path = ICL_Path;
 
623
 
 
624
#ifdef FILE_EXTENSIONS
 
625
    extension = check_extension(old_name, ICL_Extension);
 
626
#endif
 
627
 
 
628
    return write_translated_name(new_name, old_name,
 
629
               prefix_path, last_value, extension);
 
630
}
 
631
 
 
632
extern void translate_out_filename(char *new_name, char *old_name)
 
633
{   char *prefix_path;
 
634
    char *extension = "";
 
635
    int i;
 
636
 
 
637
    /* If !convert_filename_flag, then the old_name is just the <file2>
 
638
       parameter on the Inform command line, which we leave alone. */
 
639
 
 
640
    if (!convert_filename_flag)
 
641
    {   strcpy(new_name, old_name); return;
 
642
    }
 
643
 
 
644
    /* Remove any pathname or extension in <file1>. */
 
645
 
 
646
    if (contains_separator(old_name)==1)
 
647
    {   for (i=strlen(old_name)-1; (i>=0)&&(old_name[i]!=FN_SEP) ;i--) ;
 
648
            if (old_name[i]==FN_SEP) i++;
 
649
        old_name += i;
 
650
    }
 
651
#ifdef FILE_EXTENSIONS
 
652
    for (i=strlen(old_name)-1; (i>=0)&&(old_name[i]!='.') ;i--) ;
 
653
    if (old_name[i] == '.') old_name[i] = 0;
 
654
#endif
 
655
 
 
656
    prefix_path = NULL;
 
657
    if (module_switch)
 
658
    {   extension = Module_Extension;
 
659
        if (Module_Path[0]!=0) prefix_path = Module_Path;
 
660
    }
 
661
    else
 
662
    {
 
663
        if (!glulx_mode) {
 
664
            switch(version_number)
 
665
            {   case 3: extension = Code_Extension;   break;
 
666
                case 4: extension = V4Code_Extension; break;
 
667
                case 5: extension = V5Code_Extension; break;
 
668
                case 6: extension = V6Code_Extension; break;
 
669
                case 7: extension = V7Code_Extension; break;
 
670
                case 8: extension = V8Code_Extension; break;
 
671
            }
 
672
        }
 
673
        else {
 
674
            extension = GlulxCode_Extension;
 
675
        }
 
676
        if (Code_Path[0]!=0) prefix_path = Code_Path;
 
677
    }
 
678
 
 
679
#ifdef FILE_EXTENSIONS
 
680
    extension = check_extension(old_name, extension);
 
681
#endif
 
682
 
 
683
    write_translated_name(new_name, old_name, prefix_path, 0, extension);
 
684
}
 
685
 
 
686
static char *name_or_unset(char *p)
 
687
{   if (p[0]==0) return "(unset)";
 
688
    return p;
 
689
}
 
690
 
 
691
static void help_on_filenames(void)
 
692
{   char old_name[PATHLEN];
 
693
    char new_name[PATHLEN];
 
694
    int save_mm = module_switch, x;
 
695
 
 
696
    module_switch = FALSE;
 
697
 
 
698
    printf("Help information on filenames:\n\n");
 
699
 
 
700
    printf(
 
701
"The command line can take one of two forms:\n\n\
 
702
  inform [commands...] <file1>\n\
 
703
  inform [commands...] <file1> <file2>\n\n\
 
704
Inform translates <file1> into a source file name (see below) for its input.\n\
 
705
<file2> is usually omitted: if so, the output filename is made from <file1>\n\
 
706
by cutting out the name part and translating that (see below).\n\
 
707
If <file2> is given, however, the output filename is set to just <file2>\n\
 
708
(not altered in any way).\n\n");
 
709
 
 
710
    printf(
 
711
"Filenames given in the game source (with commands like Include \"name\" and\n\
 
712
Link \"name\") are also translated by the rules below.\n\n");
 
713
 
 
714
    printf(
 
715
"Rules of translation:\n\n\
 
716
Inform translates plain filenames (such as \"xyzzy\") into full pathnames\n\
 
717
(such as \"adventure%cgames%cxyzzy\") according to the following rules.\n\n\
 
718
1. If the name contains a '%c' character (so it's already a pathname), it\n\
 
719
   isn't changed.\n\n", FN_SEP, FN_SEP, FN_SEP);
 
720
 
 
721
    printf(
 
722
"   [Exception: when the name is given in an Include command using the >\n\
 
723
   form (such as Include \">prologue\"), the \">\" is replaced by the path\n\
 
724
   of the file doing the inclusion");
 
725
#ifdef FILE_EXTENSIONS
 
726
                          printf(" and a suitable file extension is added");
 
727
#endif
 
728
    printf(".]\n\n");
 
729
 
 
730
    printf(
 
731
"   Filenames must never contain double-quotation marks \".  To use filenames\n\
 
732
   which contain spaces, write them in double-quotes: for instance,\n\n\
 
733
   \"inform +code_path=\"Jigsaw Final Version\" jigsaw\".\n\n");
 
734
 
 
735
    printf(
 
736
"2. The file is looked for at a particular \"path\" (the filename of a\n\
 
737
   directory), depending on what kind of file it is.\n\n\
 
738
       File type              Name                Current setting\n\n\
 
739
       Source code (in)       source_path         %s\n\
 
740
       Include file (in)      include_path        %s\n\
 
741
       Story file (out)       code_path           %s\n",
 
742
   name_or_unset(Source_Path), name_or_unset(Include_Path),
 
743
   name_or_unset(Code_Path));
 
744
 
 
745
    printf(
 
746
"       Temporary file (out)   temporary_path      %s\n\
 
747
       ICL command file (in)  icl_path            %s\n\
 
748
       Module (in & out)      module_path         %s\n\n",
 
749
   name_or_unset(Temporary_Path),
 
750
   name_or_unset(ICL_Path), name_or_unset(Module_Path));
 
751
 
 
752
    printf(
 
753
"   If the path is unset, then the current working directory is used (so\n\
 
754
   the filename doesn't change): if, for instance, include_path is set to\n\
 
755
   \"backup%coldlib\" then when \"parser\" is included it is looked for at\n\
 
756
   \"backup%coldlib%cparser\".\n\n\
 
757
   The paths can be set or unset on the Inform command line by, eg,\n\
 
758
   \"inform +code_path=finished jigsaw\" or\n\
 
759
   \"inform +include_path= balances\" (which unsets include_path).\n\n",
 
760
        FN_SEP, FN_SEP, FN_SEP);
 
761
 
 
762
    printf(
 
763
"   The four input path variables can be set to lists of alternative paths\n\
 
764
   separated by '%c' characters: these alternatives are always tried in\n\
 
765
   the order they are specified in, that is, left to right through the text\n\
 
766
   in the path variable.\n\
 
767
   (Modules are written to the first alternative in the module_path list;\n\
 
768
   it is an error to give alternatives at all for purely output paths.)\n\n",
 
769
   FN_ALT);
 
770
 
 
771
#ifdef FILE_EXTENSIONS
 
772
    printf("3. The following file extensions are added:\n\n\
 
773
      Source code:     %s\n\
 
774
      Include files:   %s\n\
 
775
      Story files:     %s (Version 3), %s (v4), %s (v5, the default),\n\
 
776
                       %s (v6), %s (v7), %s (v8), %s (Glulx)\n\
 
777
      Temporary files: .tmp\n\
 
778
      Modules:         %s\n\n",
 
779
      Source_Extension, Include_Extension,
 
780
      Code_Extension, V4Code_Extension, V5Code_Extension, V6Code_Extension,
 
781
      V7Code_Extension, V8Code_Extension, GlulxCode_Extension, 
 
782
      Module_Extension);
 
783
    printf("\
 
784
   except that any extension you give (on the command line or in a filename\n\
 
785
   used in a program) will override these.  If you give the null extension\n\
 
786
   \".\" then Inform uses no file extension at all (removing the \".\").\n\n");
 
787
#endif
 
788
 
 
789
    printf("Names of four individual files can also be set using the same\n\
 
790
  + command notation (though they aren't really pathnames).  These are:\n\n\
 
791
      transcript_name  (text written by -r switch): now \"%s\"\n\
 
792
      debugging_name   (data written by -k switch): now \"%s\"\n\
 
793
      language_name    (library file defining natural language of game):\n\
 
794
                       now \"%s\"\n\
 
795
      charset_map      (file for character set mapping): now \"%s\"\n\n",
 
796
    Transcript_Name, Debugging_Name, Language_Name, Charset_Map);
 
797
 
 
798
    translate_in_filename(0, new_name, "rezrov", 0, 1);
 
799
    printf("Examples: 1. \"inform rezrov\"\n\
 
800
  the source code is read from \"%s\"\n",
 
801
        new_name);
 
802
    convert_filename_flag = TRUE;
 
803
    translate_out_filename(new_name, "rezrov");
 
804
    printf("  and a story file is compiled to \"%s\".\n\n", new_name);
 
805
 
 
806
    translate_in_filename(0, new_name, "frotz", 0, 1);
 
807
    printf("2. \"inform -M frotz\"\n\
 
808
  the source code is read from \"%s\"\n",
 
809
        new_name);
 
810
    module_switch = TRUE;
 
811
    convert_filename_flag = TRUE;
 
812
    translate_out_filename(new_name, "frotz");
 
813
    printf("  and a module is compiled to \"%s\".\n\n", new_name);
 
814
 
 
815
    module_switch = FALSE;
 
816
 
 
817
    sprintf(old_name, "demos%cplugh", FN_SEP);
 
818
    printf("3. \"inform %s\"\n", old_name);
 
819
    translate_in_filename(0, new_name, old_name, 0, 1);
 
820
    printf("  the source code is read from \"%s\"\n", new_name);
 
821
    sprintf(old_name, "demos%cplugh", FN_SEP);
 
822
    convert_filename_flag = TRUE;
 
823
    translate_out_filename(new_name, old_name);
 
824
    printf("  and a story file is compiled to \"%s\".\n\n", new_name);
 
825
 
 
826
    printf("4. \"inform plover my_demo\"\n");
 
827
    translate_in_filename(0, new_name, "plover", 0, 1);
 
828
    printf("  the source code is read from \"%s\"\n", new_name);
 
829
    convert_filename_flag = FALSE;
 
830
    translate_out_filename(new_name, "my_demo");
 
831
    printf("  and a story file is compiled to \"%s\".\n\n", new_name);
 
832
 
 
833
    strcpy(old_name, Source_Path);
 
834
    sprintf(new_name, "%cnew%cold%crecent%cold%cancient",
 
835
        FN_ALT, FN_ALT, FN_SEP, FN_ALT, FN_SEP);
 
836
    printf("5. \"inform +source_path=%s zooge\"\n", new_name);
 
837
    printf(
 
838
"   Note that four alternative paths are given, the first being the empty\n\
 
839
   path-name (meaning: where you are now).  Inform looks for the source code\n\
 
840
   by trying these four places in turn, stopping when it finds anything:\n\n");
 
841
 
 
842
    set_path_value(Source_Path, new_name);
 
843
    x = 0;
 
844
    do
 
845
    {   x = translate_in_filename(x, new_name, "zooge", 0, 1);
 
846
        printf("     \"%s\"\n", new_name);
 
847
    } while (x != 0);
 
848
    strcpy(Source_Path, old_name);
 
849
    module_switch = save_mm;
 
850
}
 
851
 
 
852
/* ------------------------------------------------------------------------- */
 
853
/*  Naming temporary files                                                   */
 
854
/*       (Arguably temporary files should be made using "tmpfile" in         */
 
855
/*        the ANSI C library, but many supposed ANSI libraries lack it.)     */
 
856
/* ------------------------------------------------------------------------- */
 
857
 
 
858
extern void translate_temp_filename(int i)
 
859
{   char *p;
 
860
    switch(i)
 
861
    {   case 1: p=Temp1_Name; break;
 
862
        case 2: p=Temp2_Name; break;
 
863
        case 3: p=Temp3_Name; break;
 
864
    }
 
865
    sprintf(p,"%s%s%d", Temporary_Path, Temporary_File, i);
 
866
#ifdef INCLUDE_TASK_ID
 
867
    sprintf(p+strlen(p), "_proc%08lx", (long int) unique_task_id());
 
868
#endif
 
869
#ifdef FILE_EXTENSIONS
 
870
    sprintf(p+strlen(p), ".tmp");
 
871
#endif
 
872
}
 
873
 
 
874
#ifdef ARCHIMEDES
 
875
static char riscos_ft_buffer[4];
 
876
 
 
877
extern char *riscos_file_type(void)
 
878
{
 
879
    if (riscos_file_type_format == 1)
 
880
    {   if (module_switch) return("data");
 
881
        return("11A");
 
882
    }
 
883
 
 
884
    if (module_switch) return("075");
 
885
 
 
886
    sprintf(riscos_ft_buffer, "%03x", 0x60 + version_number);
 
887
    return(riscos_ft_buffer);
 
888
}
 
889
#endif
 
890
 
 
891
/* ------------------------------------------------------------------------- */
 
892
/*   The compilation pass                                                    */
 
893
/* ------------------------------------------------------------------------- */
 
894
 
 
895
static void run_pass(void)
 
896
{
 
897
    lexer_begin_prepass();
 
898
    files_begin_prepass();
 
899
    load_sourcefile(Source_Name, 0);
 
900
 
 
901
    begin_pass();
 
902
 
 
903
    parse_program(NULL);
 
904
 
 
905
    find_the_actions();
 
906
    issue_unused_warnings();
 
907
    compile_veneer();
 
908
 
 
909
    lexer_endpass();
 
910
    if (module_switch) linker_endpass();
 
911
 
 
912
    close_all_source();
 
913
    if (hash_switch && hash_printed_since_newline) printf("\n");
 
914
 
 
915
    if (temporary_files_switch)
 
916
    {   if (module_switch) flush_link_data();
 
917
        check_temp_files();
 
918
    }
 
919
    sort_dictionary();
 
920
    construct_storyfile();
 
921
}
 
922
 
 
923
int output_has_occurred;
 
924
 
 
925
static void rennab(int32 time_taken)
 
926
{   /*  rennab = reverse of banner  */
 
927
 
 
928
    int t = no_warnings + no_suppressed_warnings;
 
929
 
 
930
    if (memout_switch) print_memory_usage();
 
931
 
 
932
    if ((no_errors + t)!=0)
 
933
    {   printf("Compiled with ");
 
934
        if (no_errors > 0)
 
935
        {   printf("%d error%s", no_errors,(no_errors==1)?"":"s");
 
936
            if (t > 0) printf(" and ");
 
937
        }
 
938
        if (no_warnings > 0)
 
939
            printf("%d warning%s", t, (t==1)?"":"s");
 
940
        if (no_suppressed_warnings > 0)
 
941
        {   if (no_warnings > 0)
 
942
                printf(" (%d suppressed)", no_suppressed_warnings);
 
943
            else
 
944
            printf("%d suppressed warning%s", no_suppressed_warnings,
 
945
                (no_suppressed_warnings==1)?"":"s");
 
946
        }
 
947
        if (output_has_occurred == FALSE) printf(" (no output)");
 
948
        printf("\n");
 
949
    }
 
950
 
 
951
    if (no_compiler_errors > 0) print_sorry_message();
 
952
 
 
953
    if (statistics_switch)
 
954
        printf("Completed in %ld seconds\n", (long int) time_taken);
 
955
}
 
956
 
 
957
/* ------------------------------------------------------------------------- */
 
958
/*   The compiler abstracted to a routine.                                   */
 
959
/* ------------------------------------------------------------------------- */
 
960
 
 
961
static int execute_icl_header(char *file1);
 
962
 
 
963
static int compile(int number_of_files_specified, char *file1, char *file2)
 
964
{   int32 time_start;
 
965
 
 
966
    if (execute_icl_header(file1))
 
967
      return 1;
 
968
 
 
969
    select_target(glulx_mode);
 
970
 
 
971
    if (define_INFIX_switch && glulx_mode) {
 
972
        printf("Infix (-X) facilities are not available in Glulx: \
 
973
disabling -X switch\n");
 
974
        define_INFIX_switch = FALSE;
 
975
    }
 
976
 
 
977
    if (module_switch && glulx_mode) {
 
978
        printf("Modules are not available in Glulx: \
 
979
disabling -M switch\n");
 
980
        module_switch = FALSE;
 
981
    }
 
982
 
 
983
    if (define_INFIX_switch && module_switch)
 
984
    {   printf("Infix (-X) facilities are not available when compiling \
 
985
modules: disabling -X switch\n");
 
986
        define_INFIX_switch = FALSE;
 
987
    }
 
988
    if (runtime_error_checking_switch && module_switch)
 
989
    {   printf("Strict checking (-S) facilities are not available when \
 
990
compiling modules: disabling -S switch\n");
 
991
        runtime_error_checking_switch = FALSE;
 
992
    }
 
993
 
 
994
    time_start=time(0); no_compilations++;
 
995
 
 
996
    strcpy(Source_Name, file1); convert_filename_flag = TRUE;
 
997
    strcpy(Code_Name, file1);
 
998
    if (number_of_files_specified == 2)
 
999
    {   strcpy(Code_Name, file2); convert_filename_flag = FALSE;
 
1000
    }
 
1001
 
 
1002
    init_vars();
 
1003
    allocate_arrays();
 
1004
 
 
1005
    if (debugfile_switch) begin_debug_file();
 
1006
    if (transcript_switch) open_transcript_file(Source_Name);
 
1007
 
 
1008
    run_pass();
 
1009
 
 
1010
    if (transcript_switch)
 
1011
    {   write_dictionary_to_transcript();
 
1012
        close_transcript_file();
 
1013
    }
 
1014
 
 
1015
    if (no_errors==0) { output_file(); output_has_occurred = TRUE; }
 
1016
    else { output_has_occurred = FALSE; }
 
1017
 
 
1018
    if (debugfile_switch) close_debug_file();
 
1019
 
 
1020
    if (temporary_files_switch && (no_errors>0)) remove_temp_files();
 
1021
 
 
1022
    free_arrays();
 
1023
 
 
1024
    rennab((int32) (time(0)-time_start));
 
1025
 
 
1026
    if (optimise_switch) optimise_abbreviations();
 
1027
 
 
1028
    if (store_the_text) my_free(&all_text,"transcription text");
 
1029
 
 
1030
    return (no_errors==0)?0:1;
 
1031
}
 
1032
 
 
1033
/* ------------------------------------------------------------------------- */
 
1034
/*   The command line interpreter                                            */
 
1035
/* ------------------------------------------------------------------------- */
 
1036
 
 
1037
static void cli_print_help(int help_level)
 
1038
{
 
1039
    printf(
 
1040
"\nThis program is a compiler of Infocom format (also called \"Z-machine\")\n\
 
1041
story files: copyright (c) Graham Nelson 1993 - 2004.\n\n");
 
1042
 
 
1043
   /* For people typing just "inform", a summary only: */
 
1044
 
 
1045
   if (help_level==0)
 
1046
   {
 
1047
 
 
1048
#ifndef PROMPT_INPUT
 
1049
  printf("Usage: \"inform [commands...] <file1> [<file2>]\"\n\n");
 
1050
#else
 
1051
  printf("When run, Inform prompts you for commands (and switches),\n\
 
1052
which are optional, then an input <file1> and an (optional) output\n\
 
1053
<file2>.\n\n");
 
1054
#endif
 
1055
 
 
1056
  printf(
 
1057
"<file1> is the Inform source file of the game to be compiled. <file2>,\n\
 
1058
if given, overrides the filename Inform would normally use for the\n\
 
1059
compiled output.  Try \"inform -h1\" for file-naming conventions.\n\n\
 
1060
One or more words can be supplied as \"commands\". These may be:\n\n\
 
1061
  -switches     a list of compiler switches, 1 or 2 letter\n\
 
1062
                (see \"inform -h2\" for the full range)\n\n\
 
1063
  +dir          set Include_Path to this directory\n\
 
1064
  +PATH=dir     change the PATH to this directory\n\n\
 
1065
  $...          one of the following memory commands:\n");
 
1066
  printf(
 
1067
"     $list            list current memory allocation settings\n\
 
1068
     $huge            make standard \"huge game\" settings %s\n\
 
1069
     $large           make standard \"large game\" settings %s\n\
 
1070
     $small           make standard \"small game\" settings %s\n\
 
1071
     $?SETTING        explain briefly what SETTING is for\n\
 
1072
     $SETTING=number  change SETTING to given number\n\n\
 
1073
  (filename)    read in a list of commands (in the format above)\n\
 
1074
                from this \"setup file\"\n\n",
 
1075
    (DEFAULT_MEMORY_SIZE==HUGE_SIZE)?"(default)":"",
 
1076
    (DEFAULT_MEMORY_SIZE==LARGE_SIZE)?"(default)":"",
 
1077
    (DEFAULT_MEMORY_SIZE==SMALL_SIZE)?"(default)":"");
 
1078
 
 
1079
#ifndef PROMPT_INPUT
 
1080
    printf("For example: \"inform -dexs $huge curses\".\n\n");
 
1081
#endif
 
1082
 
 
1083
    printf(
 
1084
"For fuller information, see the Inform Designer's Manual.\n");
 
1085
 
 
1086
       return;
 
1087
   }
 
1088
 
 
1089
   /* The -h1 (filenaming) help information: */
 
1090
 
 
1091
   if (help_level == 1) { help_on_filenames(); return; }
 
1092
 
 
1093
   /* The -h2 (switches) help information: */
 
1094
 
 
1095
   printf("Help on the full list of legal switch commands:\n\n\
 
1096
  a   trace assembly-language (without hex dumps; see -t)\n\
 
1097
  c   more concise error messages\n\
 
1098
  d   contract double spaces after full stops in text\n\
 
1099
  d2  contract double spaces after exclamation and question marks, too\n\
 
1100
  e   economy mode (slower): make use of declared abbreviations\n");
 
1101
 
 
1102
   printf("\
 
1103
  f   frequencies mode: show how useful abbreviations are\n\
 
1104
  g   traces calls to functions (except in the library)\n\
 
1105
  g2  traces calls to all functions\n\
 
1106
  h   print this information\n");
 
1107
 
 
1108
   printf("\
 
1109
  i   ignore default switches set within the file\n\
 
1110
  j   list objects as constructed\n\
 
1111
  k   output Infix debugging information to \"%s\" (and switch -D on)\n\
 
1112
  l   list every statement run through Inform\n\
 
1113
  m   say how much memory has been allocated\n\
 
1114
  n   print numbers of properties, attributes and actions\n",
 
1115
          Debugging_Name);
 
1116
   printf("\
 
1117
  o   print offset addresses\n\
 
1118
  p   give percentage breakdown of story file\n\
 
1119
  q   keep quiet about obsolete usages\n\
 
1120
  r   record all the text to \"%s\"\n\
 
1121
  s   give statistics\n\
 
1122
  t   trace assembly-language (with full hex dumps; see -a)\n",
 
1123
      Transcript_Name);
 
1124
 
 
1125
   printf("\
 
1126
  u   work out most useful abbreviations (very very slowly)\n\
 
1127
  v3  compile to version-3 (\"Standard\") story file\n\
 
1128
  v4  compile to version-4 (\"Plus\") story file\n\
 
1129
  v5  compile to version-5 (\"Advanced\") story file: the default\n\
 
1130
  v6  compile to version-6 (graphical) story file\n\
 
1131
  v8  compile to version-8 (expanded \"Advanced\") story file\n\
 
1132
  w   disable warning messages\n\
 
1133
  x   print # for every 100 lines compiled\n\
 
1134
  y   trace linking system\n\
 
1135
  z   print memory map of the Z-machine\n\n");
 
1136
 
 
1137
printf("\
 
1138
  B   use big memory model (for large V6/V7 files)\n\
 
1139
  C0  text character set is plain ASCII only\n\
 
1140
  Cn  text character set is ISO 8859-n (n = 1 to 9)\n\
 
1141
      (1 to 4, Latin1 to Latin4; 5, Cyrillic; 6, Arabic;\n\
 
1142
       7, Greek; 8, Hebrew; 9, Latin5.  Default is -C1.)\n");
 
1143
printf("  D   insert \"Constant DEBUG;\" automatically\n");
 
1144
printf("  E0  Archimedes-style error messages%s\n",
 
1145
      (error_format==0)?" (current setting)":"");
 
1146
printf("  E1  Microsoft-style error messages%s\n",
 
1147
      (error_format==1)?" (current setting)":"");
 
1148
printf("  E2  Macintosh MPW-style error messages%s\n",
 
1149
      (error_format==2)?" (current setting)":"");
 
1150
#ifdef USE_TEMPORARY_FILES
 
1151
printf("  F0  use extra memory rather than temporary files\n");
 
1152
#else
 
1153
printf("  F1  use temporary files to reduce memory consumption\n");
 
1154
#endif
 
1155
printf("  G   compile a Glulx game file\n");
 
1156
printf("  H   use Huffman encoding to compress Glulx strings\n");
 
1157
printf("  M   compile as a Module for future linking\n");
 
1158
 
 
1159
#ifdef ARCHIMEDES
 
1160
printf("\
 
1161
  R0  use filetype 060 + version number for games (default)\n\
 
1162
  R1  use official Acorn filetype 11A for all games\n");
 
1163
#endif
 
1164
printf("  S   compile strict error-checking at run-time (on by default)\n");
 
1165
#ifdef ARC_THROWBACK
 
1166
printf("  T   enable throwback of errors in the DDE\n");
 
1167
#endif
 
1168
printf("  U   insert \"Constant USE_MODULES;\" automatically\n");
 
1169
printf("  Wn  header extension table is at least n words (n = 3 to 99)\n");
 
1170
printf("  X   compile with INFIX debugging facilities present\n");
 
1171
  printf("\n");
 
1172
}
 
1173
 
 
1174
extern void switches(char *p, int cmode)
 
1175
{   int i, s=1, state;
 
1176
    /* Here cmode is 0 if switches list is from a "Switches" directive
 
1177
       and 1 if from a "-switches" command-line or ICL list */
 
1178
 
 
1179
    if (cmode==1)
 
1180
    {   if (p[0]!='-')
 
1181
        {   printf(
 
1182
                "Ignoring second word which should be a -list of switches.\n");
 
1183
            return;
 
1184
        }
 
1185
    }
 
1186
    for (i=cmode; p[i]!=0; i+=s, s=1)
 
1187
    {   state = TRUE;
 
1188
        if (p[i] == '~')
 
1189
        {   state = FALSE;
 
1190
            i++;
 
1191
        }
 
1192
        switch(p[i])
 
1193
        {
 
1194
        case 'a': asm_trace_setting = 1; break;
 
1195
        case 'b': bothpasses_switch = state; break;
 
1196
        case 'c': concise_switch = state; break;
 
1197
        case 'd': switch(p[i+1])
 
1198
                  {   case '1': double_space_setting=1; s=2; break;
 
1199
                      case '2': double_space_setting=2; s=2; break;
 
1200
                      default: double_space_setting=1; break;
 
1201
                  }
 
1202
                  break;
 
1203
        case 'e': economy_switch = state; break;
 
1204
        case 'f': frequencies_switch = state; break;
 
1205
        case 'g': switch(p[i+1])
 
1206
                  {   case '1': trace_fns_setting=1; s=2; break;
 
1207
                      case '2': trace_fns_setting=2; s=2; break;
 
1208
                      default: trace_fns_setting=1; break;
 
1209
                  }
 
1210
                  break;
 
1211
        case 'h': switch(p[i+1])
 
1212
                  {   case '1': cli_print_help(1); s=2; break;
 
1213
                      case '2': cli_print_help(2); s=2; break;
 
1214
                      case '0': s=2;
 
1215
                      default:  cli_print_help(0); break;
 
1216
                  }
 
1217
                  break;
 
1218
        case 'i': ignore_switches_switch = state; break;
 
1219
        case 'j': listobjects_switch = state; break;
 
1220
        case 'k': if (cmode == 0)
 
1221
                      error("The switch '-k' can't be set with 'Switches'");
 
1222
                  else
 
1223
                  {   debugfile_switch = state;
 
1224
                      if (state) define_DEBUG_switch = TRUE;
 
1225
                  }
 
1226
                  break;
 
1227
        case 'l': listing_switch = state; break;
 
1228
        case 'm': memout_switch = state; break;
 
1229
        case 'n': printprops_switch = state; break;
 
1230
        case 'o': offsets_switch = state; break;
 
1231
        case 'p': percentages_switch = state; break;
 
1232
        case 'q': obsolete_switch = state; break;
 
1233
        case 'r': if (cmode == 0)
 
1234
                      error("The switch '-r' can't be set with 'Switches'");
 
1235
                  else
 
1236
                      transcript_switch = state; break;
 
1237
        case 's': statistics_switch = state; break;
 
1238
        case 't': asm_trace_setting=2; break;
 
1239
        case 'u': optimise_switch = state; break;
 
1240
        case 'v': if ((cmode==0) && (version_set_switch)) { s=2; break; }
 
1241
                  version_set_switch = TRUE; s=2;
 
1242
                  switch(p[i+1])
 
1243
                  {   case '3': select_version(3); break;
 
1244
                      case '4': select_version(4); break;
 
1245
                      case '5': select_version(5); break;
 
1246
                      case '6': select_version(6); break;
 
1247
                      case '7': select_version(7); break;
 
1248
                      case '8': select_version(8); break;
 
1249
                      default:  printf("-v must be followed by 3 to 8\n");
 
1250
                                version_set_switch=0; s=1;
 
1251
                                break;
 
1252
                  }
 
1253
                  break;
 
1254
        case 'w': nowarnings_switch = state; break;
 
1255
        case 'x': hash_switch = state; break;
 
1256
        case 'y': s=2; linker_trace_setting=p[i+1]-'0'; break;
 
1257
        case 'z': memory_map_switch = state; break;
 
1258
        case 'B': oddeven_packing_switch = state; break;
 
1259
        case 'C': s=2; character_set_setting=p[i+1]-'0';
 
1260
                  if ((character_set_setting < 0)
 
1261
                      || (character_set_setting > 9))
 
1262
                  {   printf("-C must be followed by 0 to 9\n");
 
1263
                      character_set_setting = 1;
 
1264
                  }
 
1265
                  if (cmode == 0) change_character_set();
 
1266
                  break;
 
1267
        case 'D': define_DEBUG_switch = state; break;
 
1268
        case 'E': switch(p[i+1])
 
1269
                  {   case '0': s=2; error_format=0; break;
 
1270
                      case '1': s=2; error_format=1; break;
 
1271
                      case '2': s=2; error_format=2; break;
 
1272
                      default:  error_format=1; break;
 
1273
                  }
 
1274
                  break;
 
1275
        case 'F': switch(p[i+1])
 
1276
                  {   case '0': s=2; temporary_files_switch = FALSE; break;
 
1277
                      case '1': s=2; temporary_files_switch = TRUE; break;
 
1278
                      default:  temporary_files_switch = state; break;
 
1279
                  }
 
1280
                  break;
 
1281
        case 'M': module_switch = state;
 
1282
                  if (state && (r_e_c_s_set == FALSE))
 
1283
                      runtime_error_checking_switch = FALSE;
 
1284
                  break;
 
1285
#ifdef ARCHIMEDES
 
1286
        case 'R': switch(p[i+1])
 
1287
                  {   case '0': s=2; riscos_file_type_format=0; break;
 
1288
                      case '1': s=2; riscos_file_type_format=1; break;
 
1289
                      default:  riscos_file_type_format=1; break;
 
1290
                  }
 
1291
                  break;
 
1292
#endif
 
1293
#ifdef ARC_THROWBACK
 
1294
        case 'T': throwback_switch = state; break;
 
1295
#endif
 
1296
        case 'S': runtime_error_checking_switch = state;
 
1297
                  r_e_c_s_set = TRUE; break;
 
1298
        case 'G': if (cmode == 0)
 
1299
                      error("The switch '-G' can't be set with 'Switches'");
 
1300
                  else
 
1301
                  {   glulx_mode = state; /* ###- */
 
1302
                      adjust_memory_sizes();
 
1303
                  }
 
1304
                  break;
 
1305
        case 'H': compression_switch = state; break;
 
1306
        case 'U': define_USE_MODULES_switch = state; break;
 
1307
        case 'W': if ((p[i+1]>='0') && (p[i+1]<='9'))
 
1308
                  {   s=2; header_ext_setting = p[i+1]-'0';
 
1309
                      if ((p[i+2]>='0') && (p[i+2]<='9'))
 
1310
                      {   s=3; header_ext_setting *= 10;
 
1311
                          header_ext_setting += p[i+2]-'0';
 
1312
                      }
 
1313
                  }
 
1314
                  break;
 
1315
        case 'X': define_INFIX_switch = state; break;
 
1316
        default:
 
1317
          printf("Switch \"-%c\" unknown (try \"inform -h2\" for the list)\n",
 
1318
              p[i]);
 
1319
          break;
 
1320
        }
 
1321
    }
 
1322
 
 
1323
    if (optimise_switch && (!store_the_text))
 
1324
    {   store_the_text=TRUE;
 
1325
#ifdef PC_QUICKC
 
1326
        if (memout_switch)
 
1327
            printf("Allocation %ld bytes for transcription text\n",
 
1328
                (long) MAX_TRANSCRIPT_SIZE);
 
1329
        all_text = halloc(MAX_TRANSCRIPT_SIZE,1);
 
1330
        malloced_bytes += MAX_TRANSCRIPT_SIZE;
 
1331
        if (all_text==NULL)
 
1332
         fatalerror("Can't hallocate memory for transcription text.  Darn.");
 
1333
#else
 
1334
        all_text=my_malloc(MAX_TRANSCRIPT_SIZE,"transcription text");
 
1335
#endif
 
1336
    }
 
1337
}
 
1338
 
 
1339
static int icl_command(char *p)
 
1340
{   if ((p[0]=='+')||(p[0]=='-')||(p[0]=='$')
 
1341
        || ((p[0]=='(')&&(p[strlen(p)-1]==')')) ) return TRUE;
 
1342
    return FALSE;
 
1343
}
 
1344
 
 
1345
static void icl_error(char *filename, int line)
 
1346
{   printf("Error in ICL file '%s', line %d:\n", filename, line);
 
1347
}
 
1348
 
 
1349
static void icl_header_error(char *filename, int line)
 
1350
{   printf("Error in ICL header of file '%s', line %d:\n", filename, line);
 
1351
}
 
1352
 
 
1353
static int copy_icl_word(char *from, char *to)
 
1354
{
 
1355
    /*  Copies one token from 'from' to 'to', null-terminated:
 
1356
        returns the number of chars in 'from' read past (possibly 0).  */
 
1357
 
 
1358
    int i, j, quoted_mode;
 
1359
 
 
1360
    i = 0;
 
1361
    while ((from[i] == ' ') || (from[i] == TAB_CHARACTER)
 
1362
           || (from[i] == (char) 10) || (from[i] == (char) 13)) i++;
 
1363
 
 
1364
    if (from[i] == '!')
 
1365
    {   while (from[i] != 0) i++;
 
1366
        to[0] = 0; return i;
 
1367
    }
 
1368
 
 
1369
    for (quoted_mode = FALSE, j=0;;)
 
1370
    {   if (from[i] == 0) break;
 
1371
        if (from[i] == 10) break;
 
1372
        if (from[i] == 13) break;
 
1373
        if (from[i] == TAB_CHARACTER) break;
 
1374
        if ((from[i] == ' ') && (!quoted_mode)) break;
 
1375
        if (from[i] == '\"') { quoted_mode = !quoted_mode; i++; }
 
1376
        else to[j++] = from[i++];
 
1377
    }
 
1378
    to[j] = 0; return i;
 
1379
}
 
1380
 
 
1381
static void execute_icl_command(char *p);
 
1382
 
 
1383
static int execute_icl_header(char *argname)
 
1384
{
 
1385
  FILE *command_file;
 
1386
  char cli_buff[256], fw[256];
 
1387
  int line = 0;
 
1388
  int errcount = 0;
 
1389
  int i;
 
1390
  char filename[PATHLEN]; 
 
1391
  int x = 0;
 
1392
 
 
1393
  do
 
1394
    {   x = translate_in_filename(x, filename, argname, 0, 1);
 
1395
        command_file = fopen(filename,"r");
 
1396
    } while ((command_file == NULL) && (x != 0));
 
1397
  if (!command_file) {
 
1398
    /* Fail silently. The regular compiler will try to open the file
 
1399
       again, and report the problem. */
 
1400
    return 0;
 
1401
  }
 
1402
 
 
1403
  while (feof(command_file)==0) {
 
1404
    if (fgets(cli_buff,256,command_file)==0) break;
 
1405
    line++;
 
1406
    if (!(cli_buff[0] == '!' && cli_buff[1] == '%'))
 
1407
      break;
 
1408
    i = copy_icl_word(cli_buff+2, fw);
 
1409
    if (icl_command(fw)) {
 
1410
      execute_icl_command(fw);
 
1411
      copy_icl_word(cli_buff+2 + i, fw);
 
1412
      if ((fw[0] != 0) && (fw[0] != '!')) {
 
1413
        icl_header_error(filename, line);
 
1414
        errcount++;
 
1415
        printf("expected comment or nothing but found '%s'\n", fw);
 
1416
      }
 
1417
    }
 
1418
    else {
 
1419
      if (fw[0]!=0) {
 
1420
        icl_header_error(filename, line);
 
1421
        errcount++;
 
1422
        printf("Expected command or comment but found '%s'\n", fw);
 
1423
      }
 
1424
    }
 
1425
  }
 
1426
  fclose(command_file);
 
1427
 
 
1428
  return (errcount==0)?0:1;
 
1429
}
 
1430
 
 
1431
 
 
1432
static void run_icl_file(char *filename, FILE *command_file)
 
1433
{   char cli_buff[256], fw[256];
 
1434
    int i, x, line = 0;
 
1435
    printf("[Running ICL file '%s']\n", filename);
 
1436
 
 
1437
    while (feof(command_file)==0)
 
1438
    {   if (fgets(cli_buff,256,command_file)==0) break;
 
1439
        line++;
 
1440
        i = copy_icl_word(cli_buff, fw);
 
1441
        if (icl_command(fw))
 
1442
        {   execute_icl_command(fw);
 
1443
            copy_icl_word(cli_buff + i, fw);
 
1444
            if ((fw[0] != 0) && (fw[0] != '!'))
 
1445
            {   icl_error(filename, line);
 
1446
                printf("expected comment or nothing but found '%s'\n", fw);
 
1447
            }
 
1448
        }
 
1449
        else
 
1450
        {   if (strcmp(fw, "compile")==0)
 
1451
            {   char story_name[PATHLEN], code_name[PATHLEN];
 
1452
                i += copy_icl_word(cli_buff + i, story_name);
 
1453
                i += copy_icl_word(cli_buff + i, code_name);
 
1454
 
 
1455
                if (code_name[0] != 0) x=2;
 
1456
                else if (story_name[0] != 0) x=1;
 
1457
                else x=0;
 
1458
 
 
1459
                switch(x)
 
1460
                {   case 0: icl_error(filename, line);
 
1461
                            printf("No filename given to 'compile'\n");
 
1462
                            break;
 
1463
                    case 1: printf("[Compiling <%s>]\n", story_name);
 
1464
                            compile(x, story_name, code_name);
 
1465
                            break;
 
1466
                    case 2: printf("[Compiling <%s> to <%s>]\n",
 
1467
                                story_name, code_name);
 
1468
                            compile(x, story_name, code_name);
 
1469
                            copy_icl_word(cli_buff + i, fw);
 
1470
                            if (fw[0]!=0)
 
1471
                            {   icl_error(filename, line);
 
1472
                        printf("Expected comment or nothing but found '%s'\n",
 
1473
                                fw);
 
1474
                            }
 
1475
                            break;
 
1476
                }
 
1477
            }
 
1478
            else
 
1479
            if (fw[0]!=0)
 
1480
            {   icl_error(filename, line);
 
1481
                printf("Expected command or comment but found '%s'\n", fw);
 
1482
            }
 
1483
        }
 
1484
    }
 
1485
}
 
1486
 
 
1487
static void execute_icl_command(char *p)
 
1488
{   char filename[PATHLEN], cli_buff[256];
 
1489
    FILE *command_file;
 
1490
 
 
1491
    switch(p[0])
 
1492
    {   case '+': set_path_command(p+1); break;
 
1493
        case '-': switches(p,1); break;
 
1494
        case '$': memory_command(p+1); break;
 
1495
        case '(': strcpy(cli_buff,p+1); cli_buff[strlen(cli_buff)-1]=0;
 
1496
                  {   int x = 0;
 
1497
                      do
 
1498
                      {   x = translate_icl_filename(x, filename, cli_buff);
 
1499
                          command_file = fopen(filename,"r");
 
1500
                      } while ((command_file == NULL) && (x != 0));
 
1501
                  }
 
1502
                  if (command_file == NULL)
 
1503
                      printf("Error in ICL: Couldn't open command file '%s'\n",
 
1504
                          filename);
 
1505
                  else
 
1506
                  {   run_icl_file(filename, command_file);
 
1507
                      fclose(command_file);
 
1508
                  }
 
1509
                  break;
 
1510
    }
 
1511
}
 
1512
 
 
1513
/* ------------------------------------------------------------------------- */
 
1514
/*   Opening and closing banners                                             */
 
1515
/* ------------------------------------------------------------------------- */
 
1516
 
 
1517
char banner_line[80];
 
1518
 
 
1519
static void banner(void)
 
1520
{
 
1521
    sprintf(banner_line, "Inform %d.%d%d",
 
1522
        (VNUMBER/100)%10, (VNUMBER/10)%10, VNUMBER%10);
 
1523
    if (0) {
 
1524
        sprintf(banner_line+strlen(banner_line), " (biplatform, G%d.%d%d)",
 
1525
            (GLULX_RELEASE_NUMBER/100)%10, (GLULX_RELEASE_NUMBER/10)%10, 
 
1526
            GLULX_RELEASE_NUMBER%10);
 
1527
    }
 
1528
#ifdef MACHINE_STRING
 
1529
    sprintf(banner_line+strlen(banner_line), " for %s", MACHINE_STRING);
 
1530
#endif
 
1531
    sprintf(banner_line+strlen(banner_line), " (%s)",
 
1532
        RELEASE_DATE);
 
1533
    printf("%s\n", banner_line);
 
1534
}
 
1535
 
 
1536
/* ------------------------------------------------------------------------- */
 
1537
/*   Input from the outside world                                            */
 
1538
/* ------------------------------------------------------------------------- */
 
1539
 
 
1540
#ifdef PROMPT_INPUT
 
1541
static void read_command_line(int argc, char **argv)
 
1542
{   int i;
 
1543
    char buffer1[100], buffer2[100], buffer3[100];
 
1544
    i=0;
 
1545
    printf("Source filename?\n> ");
 
1546
    while (gets(buffer1)==NULL); cli_file1=buffer1;
 
1547
    printf("Output filename (RETURN for the same)?\n> ");
 
1548
    while (gets(buffer2)==NULL); cli_file2=buffer2;
 
1549
    cli_files_specified=1;
 
1550
    if (buffer2[0]!=0) cli_files_specified=2;
 
1551
    do
 
1552
    {   printf("List of commands (RETURN to finish; \"-h\" for help)?\n> ");
 
1553
        while (gets(buffer3)==NULL); execute_icl_command(buffer3);
 
1554
    } while (buffer3[0]!=0);
 
1555
}
 
1556
#else
 
1557
static void read_command_line(int argc, char **argv)
 
1558
{   int i;
 
1559
    if (argc==1) switches("-h",1);
 
1560
 
 
1561
    for (i=1, cli_files_specified=0; i<argc; i++)
 
1562
        if (icl_command(argv[i]))
 
1563
            execute_icl_command(argv[i]);
 
1564
        else
 
1565
            switch(++cli_files_specified)
 
1566
            {   case 1: cli_file1 = argv[i]; break;
 
1567
                case 2: cli_file2 = argv[i]; break;
 
1568
                default:
 
1569
                    printf("Command line error: unknown parameter '%s'\n",
 
1570
                        argv[i]); return;
 
1571
            }
 
1572
}
 
1573
#endif
 
1574
 
 
1575
/* ------------------------------------------------------------------------- */
 
1576
/*   M A I N : An outer shell for machine-specific quirks                    */
 
1577
/*   Omitted altogether if EXTERNAL_SHELL is defined, as for instance is     */
 
1578
/*   needed for the Macintosh front end.                                     */
 
1579
/* ------------------------------------------------------------------------- */
 
1580
 
 
1581
#ifdef EXTERNAL_SHELL
 
1582
extern int sub_main(int argc, char **argv);
 
1583
#else
 
1584
 
 
1585
static int sub_main(int argc, char **argv);
 
1586
#ifdef MAC_MPW
 
1587
int main(int argc, char **argv, char *envp[])
 
1588
#else
 
1589
int main(int argc, char **argv)
 
1590
#endif
 
1591
{   int rcode;
 
1592
#ifdef MAC_MPW
 
1593
    InitCursorCtl((acurHandle)NULL); Show_Cursor(WATCH_CURSOR);
 
1594
#endif
 
1595
    rcode = sub_main(argc, argv);
 
1596
#ifdef ARC_THROWBACK
 
1597
    throwback_end();
 
1598
#endif
 
1599
    return rcode;
 
1600
}
 
1601
 
 
1602
#endif
 
1603
 
 
1604
/* ------------------------------------------------------------------------- */
 
1605
/*   M A I N  II:  Starting up ICL with the command line                     */
 
1606
/* ------------------------------------------------------------------------- */
 
1607
 
 
1608
#ifdef EXTERNAL_SHELL
 
1609
extern int sub_main(int argc, char **argv)
 
1610
#else
 
1611
static int sub_main(int argc, char **argv)
 
1612
#endif
 
1613
{   int return_code;
 
1614
 
 
1615
#ifdef MAC_FACE
 
1616
    ProcessEvents (&g_proc);
 
1617
    if (g_proc != true)
 
1618
    {   free_arrays();
 
1619
        if (store_the_text) my_free(&all_text,"transcription text");
 
1620
        longjmp (g_fallback, 1);
 
1621
    }
 
1622
#endif
 
1623
 
 
1624
    banner();
 
1625
 
 
1626
    set_memory_sizes(DEFAULT_MEMORY_SIZE); set_default_paths();
 
1627
    reset_switch_settings(); select_version(5);
 
1628
 
 
1629
    cli_files_specified = 0; no_compilations = 0;
 
1630
    cli_file1 = "source"; cli_file2 = "output";
 
1631
 
 
1632
    read_command_line(argc, argv);
 
1633
 
 
1634
    if (cli_files_specified > 0)
 
1635
    {   return_code = compile(cli_files_specified, cli_file1, cli_file2);
 
1636
 
 
1637
        if (return_code != 0) return(return_code);
 
1638
    }
 
1639
 
 
1640
    if (no_compilations == 0)
 
1641
        printf("\n[No compilation requested]\n");
 
1642
    if (no_compilations > 1)
 
1643
        printf("[%d compilations completed]\n", no_compilations);
 
1644
 
 
1645
    return(0);
 
1646
}
 
1647
 
 
1648
/* ========================================================================= */