~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to tads/tads3/tcmakecl.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifdef RCSID
 
2
static char RCSid[] =
 
3
"$Header$";
 
4
#endif
 
5
 
 
6
/* 
 
7
 *   Copyright (c) 1999, 2002 Michael J. Roberts.  All Rights Reserved.
 
8
 *   
 
9
 *   Please see the accompanying license file, LICENSE.TXT, for information
 
10
 *   on using and copying this software.  
 
11
 */
 
12
/*
 
13
Name
 
14
  tcmakecl.cpp - TADS Compiler "Make" command line tool
 
15
Function
 
16
  Command-line interface to "make" program build utility
 
17
Notes
 
18
  
 
19
Modified
 
20
  07/11/99 MJRoberts  - Creation
 
21
*/
 
22
 
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
 
 
27
#include "os.h"
 
28
#include "t3_os.h"
 
29
#include "t3std.h"
 
30
#include "tcmake.h"
 
31
#include "tchostsi.h"
 
32
#include "vmerr.h"
 
33
#include "tcvsn.h"
 
34
#include "resload.h"
 
35
#include "tcmain.h"
 
36
#include "tclibprs.h"
 
37
#include "t3test.h"
 
38
#include "tccmdutl.h"
 
39
#include "rcmain.h"
 
40
 
 
41
/*
 
42
 *   Library parser.  This is a specialized version of the library parser
 
43
 *   that we use to expand library arguments into their corresponding source
 
44
 *   file lists.  
 
45
 */
 
46
class CTcLibParserCmdline: public CTcLibParser
 
47
{
 
48
public:
 
49
    /*
 
50
     *   Process a command-line argument that refers to a library.  We'll
 
51
     *   read the library and add each file mentioned in the library to the
 
52
     *   source module list.
 
53
     *   
 
54
     *   Returns zero on success, non-zero if any errors occur.  Fills in
 
55
     *   '*nodef' on return to indicate whether or not a "nodef" flag
 
56
     *   appeared in the library.  
 
57
     */
 
58
    static int process_lib_arg(CTcHostIfc *hostifc, CTcMake *mk,
 
59
                               CRcResList *res_list,
 
60
                               const char *lib_name, const char *lib_url,
 
61
                               int *nodef)
 
62
    {
 
63
        char path[OSFNMAX];
 
64
        char full_name[OSFNMAX];
 
65
 
 
66
        /* add a default "tl" extension to the library name */
 
67
        strcpy(full_name, lib_name);
 
68
        os_defext(full_name, "tl");
 
69
 
 
70
        /* extract the path name from the library's name */
 
71
        os_get_path_name(path, sizeof(path), lib_name);
 
72
 
 
73
        /* 
 
74
         *   add the directory containing the library to the include path,
 
75
         *   if it's not already there 
 
76
         */
 
77
        mk->maybe_add_include_path(path);
 
78
 
 
79
        /* set up our library parser object */
 
80
        CTcLibParserCmdline parser(hostifc, mk, res_list, full_name, lib_url);
 
81
 
 
82
        /* scan the library and add its files to the command line */
 
83
        parser.parse_lib();
 
84
 
 
85
        /* set the 'nodef' indication for the caller */
 
86
        *nodef = parser.nodef_;
 
87
 
 
88
        /* if there are any errors, return non-zero */
 
89
        return parser.get_err_cnt();
 
90
    }
 
91
 
 
92
protected:
 
93
    /* instantiate */
 
94
    CTcLibParserCmdline(CTcHostIfc *hostifc, CTcMake *mk,
 
95
                        CRcResList *res_list,
 
96
                        const char *lib_name, const char *lib_url)
 
97
        : CTcLibParser(lib_name)
 
98
    {
 
99
        /* remember our host interface */
 
100
        hostifc_ = hostifc;
 
101
 
 
102
        /* remember our 'make' control object */
 
103
        mk_ = mk;
 
104
 
 
105
        /* remember our resource list container */
 
106
        res_list_ = res_list;
 
107
 
 
108
        /* remember the URL to the library */
 
109
        lib_name_ = lib_copy_str(lib_name);
 
110
        lib_url_ = lib_copy_str(lib_url);
 
111
 
 
112
        /* no "nodef" flag yet */
 
113
        nodef_ = FALSE;
 
114
    }
 
115
 
 
116
    ~CTcLibParserCmdline()
 
117
    {
 
118
        /* delete the library name and URL strings */
 
119
        lib_free_str(lib_name_);
 
120
        lib_free_str(lib_url_);
 
121
    }
 
122
 
 
123
    /* process a source file entry in the library */
 
124
    void scan_full_source(const char *val, const char *fname)
 
125
    {
 
126
        char url[OSFNMAX*2 + 20];
 
127
        CTcMakeModule *mod;
 
128
        
 
129
        /* add the source module to our module list */
 
130
        mod = mk_->add_module(fname, 0, 0);
 
131
 
 
132
        /* 
 
133
         *   build the full URL for the module - this is the library URL
 
134
         *   prefix plus the "source:" value (not the full filename - simply
 
135
         *   the original unretouched value of the "source:" variable) 
 
136
         */
 
137
        sprintf(url, "%.*s%.*s", (int)OSFNMAX, lib_url_, (int)OSFNMAX, val);
 
138
 
 
139
        /* set the module's URL */
 
140
        mod->set_url(url);
 
141
 
 
142
        /* set the module's original name and library name */
 
143
        mod->set_orig_name(val);
 
144
        mod->set_from_lib(lib_name_, lib_url_);
 
145
    }
 
146
 
 
147
    /* process a sub-library entry in the library */
 
148
    void scan_full_library(const char *val, const char *fname)
 
149
    {
 
150
        char url[OSFNMAX*2 + 20];
 
151
        int nodef;
 
152
        
 
153
        /* 
 
154
         *   build the library URL prefix - this is the parent library URL
 
155
         *   prefix, plus our "library:" value (not the full filename -
 
156
         *   simply the original unretouched "library:" variable value),
 
157
         *   plus a slash 
 
158
         */
 
159
        sprintf(url, "%.*s%.*s/", (int)OSFNMAX, lib_url_, (int)OSFNMAX, val);
 
160
 
 
161
        /* parse the sub-library */
 
162
        if (process_lib_arg(hostifc_, mk_, res_list_, fname, url, &nodef))
 
163
        {
 
164
            /* 
 
165
             *   error parsing the sub-library - count it in our own error
 
166
             *   count, so we know the parsing failed 
 
167
             */
 
168
            ++err_cnt_;
 
169
        }
 
170
 
 
171
        /* 
 
172
         *   if the sub-library had a 'nodef' flag, count it as a 'nodef'
 
173
         *   flag in this library 
 
174
         */
 
175
        if (nodef)
 
176
            nodef_ = TRUE;
 
177
    }
 
178
 
 
179
    /* process a resource entry in the library */
 
180
    void scan_full_resource(const char *val, const char *fname)
 
181
    {
 
182
        /* add the resource to the list */
 
183
        res_list_->add_file(fname, val, TRUE);
 
184
    }
 
185
 
 
186
    /* display an error */
 
187
    void err_msg(const char *msg, ...)
 
188
    {
 
189
        va_list args;
 
190
 
 
191
        /* display the error */
 
192
        va_start(args, msg);
 
193
        hostifc_->v_print_err(msg, args);
 
194
        hostifc_->print_err("\n");
 
195
        va_end(args);
 
196
    }
 
197
 
 
198
    /* look up a preprocessor symbol */
 
199
    int get_pp_symbol(char *dst, size_t dst_len,
 
200
                      const char *sym_name, size_t sym_len)
 
201
    {
 
202
        const char *val;
 
203
        size_t val_len;
 
204
 
 
205
        /* ask the 'make' control object for the expansion */
 
206
        val = mk_->look_up_pp_sym(sym_name, sym_len);
 
207
 
 
208
        /* if we didn't find a value, return undefined */
 
209
        if (val == 0)
 
210
            return -1;
 
211
 
 
212
        /* if it fits in the caller's result buffer, copy it */
 
213
        val_len = strlen(val);
 
214
        if (val_len <= dst_len)
 
215
            memcpy(dst, val, val_len);
 
216
 
 
217
        /* return the value length */
 
218
        return val_len;
 
219
    }
 
220
 
 
221
    /* scan a "nodef" flag */
 
222
    void scan_nodef() { nodef_ = TRUE; }
 
223
 
 
224
    /* our 'make' control object */
 
225
    CTcMake *mk_;
 
226
 
 
227
    /* our resource list container */
 
228
    CRcResList *res_list_;
 
229
 
 
230
    /* host system interface */
 
231
    CTcHostIfc *hostifc_;
 
232
 
 
233
    /* the library name */
 
234
    char *lib_name_;
 
235
 
 
236
    /* 
 
237
     *   the library URL - this is the common prefix for the URL of every
 
238
     *   member of the library 
 
239
     */
 
240
    char *lib_url_;
 
241
 
 
242
    /* flag: we've seen a "nodef" flag */
 
243
    int nodef_;
 
244
};
 
245
 
 
246
 
 
247
/* ------------------------------------------------------------------------ */
 
248
/*
 
249
 *   Helper object for CTcCommandUtil::parse_opt_file 
 
250
 */
 
251
class CMainOptHelper: public CTcOptFileHelper
 
252
{
 
253
public:
 
254
    /* allocate an option string */
 
255
    char *alloc_opt_file_str(size_t len) { return lib_alloc_str(len); }
 
256
 
 
257
    /* free an option string previously allocated */
 
258
    void free_opt_file_str(char *str) { lib_free_str(str); }
 
259
 
 
260
    /* process a comment (we ignore comments) */
 
261
    void process_comment_line(const char *) { }
 
262
 
 
263
    /* process a non-comment line (ignore it) */
 
264
    void process_non_comment_line(const char *) { }
 
265
 
 
266
    /* process a configuration section line (ignore it) */
 
267
    void process_config_line(const char *, const char *, int) { }
 
268
};
 
269
 
 
270
/* ------------------------------------------------------------------------ */
 
271
/*
 
272
 *   Make a file path relative to the option file path, if we indeed have an
 
273
 *   option file path.  'buf' is a buffer the caller provides where we can
 
274
 *   build the full path, if necessary.  We'll return a pointer either to the
 
275
 *   buffer containing the combined path, or to the original filename if we
 
276
 *   decided not to use the relative path.  
 
277
 */
 
278
static char *make_opt_file_relative(char *buf, size_t buflen,
 
279
                                    int read_opt_file,
 
280
                                    const char *opt_file_path,
 
281
                                    char *fname)
 
282
{
 
283
    char lcl[OSFNMAX];
 
284
    
 
285
    /* 
 
286
     *   if we haven't read an option file, we don't have an option file path
 
287
     *   to use as the relative root, so use the original filename unchanged 
 
288
     */
 
289
    if (!read_opt_file)
 
290
        return fname;
 
291
 
 
292
    /* convert the name to local conventions */
 
293
    os_cvt_url_dir(buf, buflen < sizeof(lcl) ? buflen : sizeof(lcl),
 
294
                   fname, FALSE);
 
295
 
 
296
    /* if the filename is absolute, use it as given */
 
297
    if (os_is_file_absolute(buf))
 
298
        return buf;
 
299
 
 
300
    /* 
 
301
     *   we have a relative filename and an option file, so build the given
 
302
     *   name relative to the option file path, using the version that we
 
303
     *   converted to local conventions 
 
304
     */
 
305
    strcpy(lcl, buf);
 
306
    os_build_full_path(buf, buflen, opt_file_path, lcl);
 
307
 
 
308
    /* return the caller's buffer where we built the full path */
 
309
    return buf;
 
310
}
 
311
                                    
 
312
 
 
313
 
 
314
/* ------------------------------------------------------------------------ */
 
315
/*
 
316
 *   Program main entrypoint 
 
317
 */
 
318
int main(int argc, char **argv)
 
319
{
 
320
    CTcHostIfcStdio *hostifc = new CTcHostIfcStdio();
 
321
    int curarg;
 
322
    char *p;
 
323
    int force_build = FALSE;
 
324
    int force_link = FALSE;
 
325
    CTcMake *mk;
 
326
    int err_cnt, warn_cnt;
 
327
    int image_specified = FALSE;
 
328
    char dirbuf[OSFNMAX + 4096];
 
329
    int show_banner;
 
330
    const char *opt_file = 0;
 
331
    char opt_file_path[OSFNMAX];
 
332
    int read_opt_file = FALSE;
 
333
    int usage_err = FALSE;
 
334
    int add_def_mod = TRUE;
 
335
    int compile_only = FALSE;
 
336
    int pp_only = FALSE;
 
337
    osfildef *string_fp = 0;
 
338
    osfildef *assembly_fp = 0;
 
339
    int sym_dir_set = FALSE;
 
340
    int obj_dir_set = FALSE;
 
341
    int lib_err = FALSE;
 
342
    CMainOptHelper opt_helper;
 
343
    int opt_file_path_warning = FALSE;
 
344
    int need_opt_file_path_warning;
 
345
    const size_t SUPPRESS_LIST_MAX = 100;
 
346
    int suppress_list[SUPPRESS_LIST_MAX];
 
347
    size_t suppress_cnt;
 
348
    CTcMakePath *sys_inc_entry;
 
349
    CTcMakePath *sys_lib_entry;
 
350
    int verbose = FALSE;
 
351
    int pedantic = FALSE;
 
352
    int res_recurse = TRUE;
 
353
    CRcResList *res_list;
 
354
    int warnings_as_errors = FALSE;
 
355
 
 
356
    /* we don't have any warning codes to suppress yet */
 
357
    suppress_cnt = 0;
 
358
 
 
359
    /* no errors or warnings yet */
 
360
    err_cnt = warn_cnt = 0;
 
361
 
 
362
    /* create a resource list, in case we have resource options */
 
363
    res_list = new CRcResList();
 
364
 
 
365
    /* initialize the error subsystem */
 
366
    {
 
367
        CResLoader *res_loader;
 
368
        char buf[OSFNMAX];
 
369
 
 
370
        /* create a resource loader */
 
371
        os_get_special_path(buf, sizeof(buf), argv[0], OS_GSP_T3_RES);
 
372
        res_loader = new CResLoader(buf);
 
373
 
 
374
        /* tell the resource loader the executable filename, if possible */
 
375
        if (os_get_exe_filename(buf, sizeof(buf), argv[0]))
 
376
            res_loader->set_exe_filename(buf);
 
377
 
 
378
        /* initialize the error subsystem */
 
379
        CTcMain::tc_err_init(1024, res_loader);
 
380
 
 
381
        /* done with the resource loader */
 
382
        delete res_loader;
 
383
    }
 
384
 
 
385
    /* create the 'make' object */
 
386
    mk = new CTcMake();
 
387
 
 
388
    /* presume we'll show the banner and progress messages */
 
389
    show_banner = TRUE;
 
390
 
 
391
    /* 
 
392
     *   Add the default system header directory to the system include path.
 
393
     *   System include paths always follow any user-specified paths in the
 
394
     *   search order.  
 
395
     */
 
396
    os_get_special_path(dirbuf, sizeof(dirbuf), argv[0], OS_GSP_T3_INC);
 
397
    sys_inc_entry = mk->add_sys_include_path(dirbuf);
 
398
 
 
399
    /*
 
400
     *   Add the user library search path list to the source search path.
 
401
     *   This list comes from platform-specific global configuration data
 
402
     *   (such as a environment variable on Unix), so we want it to come
 
403
     *   after any search list specified in the command-line options; ensure
 
404
     *   that we search these locations last by making them "system" paths,
 
405
     *   since system paths follow all command-line paths.  
 
406
     */
 
407
    os_get_special_path(dirbuf, sizeof(dirbuf), argv[0], OS_GSP_T3_USER_LIBS);
 
408
    for (p = dirbuf ; *p != '\0' ; )
 
409
    {
 
410
        char *start;
 
411
        char *nxt;
 
412
 
 
413
        /* remember where this list element starts */
 
414
        start = p;
 
415
 
 
416
        /* find the next path separator character */
 
417
        for ( ; *p != '\0' && *p != OSPATHSEP ; ++p) ;
 
418
 
 
419
        /* if there's another path element, note its start */
 
420
        nxt = p;
 
421
        if (*nxt == OSPATHSEP)
 
422
            ++nxt;
 
423
 
 
424
        /* null-terminate the path at the separator */
 
425
        *p = '\0';
 
426
 
 
427
        /* add this path */
 
428
        mk->add_sys_source_path(start);
 
429
 
 
430
        /* continue scanning at the next list element */
 
431
        p = nxt;
 
432
    }
 
433
 
 
434
    /*
 
435
     *   Add the default system library directory to the source path.
 
436
     *   System source paths always follow user-specified paths in the
 
437
     *   search order.  
 
438
     */
 
439
    os_get_special_path(dirbuf, sizeof(dirbuf), argv[0], OS_GSP_T3_LIB);
 
440
    sys_lib_entry = mk->add_sys_source_path(dirbuf);
 
441
 
 
442
parse_options:
 
443
    /* read the options */
 
444
    for (curarg = 1 ; curarg < argc && argv[curarg][0] == '-' ; ++curarg)
 
445
    {
 
446
        char subopt;
 
447
        char relbuf[OSFNMAX];
 
448
 
 
449
        /* 
 
450
         *   if we have a "-source" or "-lib" argument, we're done with
 
451
         *   options, and we're on to the module list 
 
452
         */
 
453
        if (strcmp(argv[curarg], "-source") == 0
 
454
            || strcmp(argv[curarg], "-lib") == 0
 
455
            || strcmp(argv[curarg], "-res") == 0)
 
456
            break;
 
457
 
 
458
        /* 
 
459
         *   figure out which option we have, starting with the first letter
 
460
         *   after the '-' 
 
461
         */
 
462
        switch(argv[curarg][1])
 
463
        {
 
464
        case 'f':
 
465
            /* read an options file - make sure we don't have one already */
 
466
            if (opt_file != 0)
 
467
            {
 
468
                /* can't read a file from a file */
 
469
                printf("error: only one option file (-f) is allowed\n");
 
470
                err_cnt = 1;
 
471
                goto done;
 
472
            }
 
473
 
 
474
            /* 
 
475
             *   remember the options file name - we'll get around to the
 
476
             *   actual reading of the file after we finish with the
 
477
             *   command line options 
 
478
             */
 
479
            opt_file = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 1);
 
480
            if (opt_file == 0)
 
481
                goto missing_option_arg;
 
482
            break;
 
483
            
 
484
        case 'd':
 
485
            /* set debug mode */
 
486
            mk->set_debug(TRUE);
 
487
            break;
 
488
 
 
489
        case 'D':
 
490
            /* add preprocessor symbol definition */
 
491
            p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 1);
 
492
            if (p != 0)
 
493
            {
 
494
                char *eq;
 
495
 
 
496
                /* see if there's an '=' in the string */
 
497
                for (eq = p ; *eq != '\0' && *eq != '=' ; ++eq) ;
 
498
 
 
499
                /* if the '=' is present, replace it with a null byte */
 
500
                if (*eq == '=')
 
501
                {
 
502
                    /* replace it */
 
503
                    *eq = '\0';
 
504
 
 
505
                    /* skip to the start of the replacement text */
 
506
                    ++eq;
 
507
                }
 
508
 
 
509
                /* add the symbol definition */
 
510
                mk->def_pp_sym(p, eq);
 
511
            }
 
512
            else
 
513
                goto missing_option_arg;
 
514
            break;
 
515
 
 
516
        case 'e':
 
517
            /* check for longer option names */
 
518
            if (strlen(argv[curarg]) >= 7
 
519
                && memcmp(argv[curarg], "-errnum", 7) == 0)
 
520
            {
 
521
                /* check for "+" or "-" suffixes */
 
522
                if (strcmp(argv[curarg] + 7, "+") == 0
 
523
                    || argv[curarg][7] == '\0')
 
524
                {
 
525
                    /* turn on error number display */
 
526
                    mk->set_show_err_numbers(TRUE);
 
527
                }
 
528
                else if (strcmp(argv[curarg] + 7, "-") == 0)
 
529
                {
 
530
                    /* turn off error number display */
 
531
                    mk->set_show_err_numbers(FALSE);
 
532
                }
 
533
                else
 
534
                {
 
535
                    /* invalid option */
 
536
                    goto bad_option;
 
537
                }
 
538
            }
 
539
            else
 
540
            {
 
541
                /* invalid option */
 
542
                goto bad_option;
 
543
            }
 
544
            break;
 
545
 
 
546
        case 'U':
 
547
            /* add preprocess symbol un-definition */
 
548
            p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 1);
 
549
            if (p != 0)
 
550
                mk->undef_pp_sym(p);
 
551
            else
 
552
                goto missing_option_arg;
 
553
            break;
 
554
 
 
555
        case 'c':
 
556
            /* see what follows */
 
557
            switch (argv[curarg][2])
 
558
            {
 
559
            case 's':
 
560
                /* it's a character set specification */
 
561
                p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 2);
 
562
                if (p != 0)
 
563
                    mk->set_source_charset(p);
 
564
                else
 
565
                    goto missing_option_arg;
 
566
                break;
 
567
 
 
568
            case 'l':
 
569
                /* check for "-clean" */
 
570
                if (strcmp(argv[curarg], "-clean") == 0)
 
571
                {
 
572
                    /* set "clean" mode */
 
573
                    mk->set_clean_mode(TRUE);
 
574
                }
 
575
                else
 
576
                {
 
577
                    /* invalid option */
 
578
                    goto bad_option;
 
579
                }
 
580
                break;
 
581
 
 
582
            case '\0':
 
583
                /* set compile-only (no link) mode */
 
584
                mk->set_do_link(FALSE);
 
585
                compile_only = TRUE;
 
586
                break;
 
587
 
 
588
            default:
 
589
                /* invalid option */
 
590
                goto bad_option;
 
591
            }
 
592
            break;
 
593
 
 
594
        case 'a':
 
595
            /* see what follows */
 
596
            switch(argv[curarg][2])
 
597
            {
 
598
            case 'l':
 
599
                /* force only the link phase */
 
600
                force_link = TRUE;
 
601
                break;
 
602
 
 
603
            case '\0':
 
604
                force_build = TRUE;
 
605
                break;
 
606
 
 
607
            default:
 
608
                /* invalid option */
 
609
                goto bad_option;
 
610
            }
 
611
            break;
 
612
            
 
613
        case 'v':
 
614
            /* set verbose mode */
 
615
            mk->set_verbose(TRUE);
 
616
            verbose = TRUE;
 
617
            break;
 
618
            
 
619
        case 'I':
 
620
            /* add a #include path */
 
621
            p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 1);
 
622
            if (p != 0)
 
623
            {
 
624
                /* make it relative to the option file path if appropriate */
 
625
                p = make_opt_file_relative(relbuf, sizeof(relbuf),
 
626
                                           read_opt_file, opt_file_path, p);
 
627
                
 
628
                /* add the path */
 
629
                mk->add_include_path(p);
 
630
            }
 
631
            else
 
632
                goto missing_option_arg;
 
633
            break;
 
634
            
 
635
        case 'o':
 
636
            /* set the image file name */
 
637
            p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 1);
 
638
            if (p != 0)
 
639
            {
 
640
                /* make it relative to the option file path if appropriate */
 
641
                p = make_opt_file_relative(relbuf, sizeof(relbuf),
 
642
                                           read_opt_file, opt_file_path, p);
 
643
 
 
644
                /* set the image file name */
 
645
                mk->set_image_file(p);
 
646
 
 
647
                /* note that we have an explicit image file name */
 
648
                image_specified = TRUE;
 
649
            }
 
650
            else
 
651
                goto missing_option_arg;
 
652
            break;
 
653
 
 
654
        case 'O':
 
655
            switch(argv[curarg][2])
 
656
            {
 
657
            case 's':
 
658
                /* 
 
659
                 *   if we already have a string capture file, close the
 
660
                 *   old one 
 
661
                 */
 
662
                if (string_fp != 0)
 
663
                {
 
664
                    osfcls(string_fp);
 
665
                    string_fp = 0;
 
666
                }
 
667
                
 
668
                /* set the string file */
 
669
                p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 2);
 
670
                if (p == 0)
 
671
                    goto missing_option_arg;
 
672
 
 
673
                /* make it relative to the option file path if appropriate */
 
674
                p = make_opt_file_relative(relbuf, sizeof(relbuf),
 
675
                                           read_opt_file, opt_file_path, p);
 
676
 
 
677
                /* open the string file */
 
678
                string_fp = osfopwt(p, OSFTTEXT);
 
679
                if (string_fp == 0)
 
680
                {
 
681
                    printf("error: unable to create string capture file "
 
682
                           "\"%s\"\n", p);
 
683
                    goto done;
 
684
                }
 
685
 
 
686
                /* set the string capture file in the build object */
 
687
                mk->set_string_capture(string_fp);
 
688
 
 
689
                /* done */
 
690
                break;
 
691
 
 
692
            default:
 
693
                /* invalid suboption */
 
694
                goto bad_option;
 
695
            }
 
696
            break;
 
697
 
 
698
        case 'F':
 
699
            /* presume we won't need an option file path warning */
 
700
            need_opt_file_path_warning = FALSE;
 
701
 
 
702
            /* note the sub-option letter */
 
703
            subopt = argv[curarg][2];
 
704
 
 
705
            /* get the filename/path argument */
 
706
            p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 2);
 
707
            if (p == 0)
 
708
                goto missing_option_arg;
 
709
 
 
710
            /* make it relative to the option file path */
 
711
            p = make_opt_file_relative(relbuf, sizeof(relbuf),
 
712
                                       read_opt_file, opt_file_path, p);
 
713
 
 
714
            /* 
 
715
             *   if this is an absolute path, note it so we can warn about it
 
716
             *   if this is in an option file 
 
717
             */
 
718
            need_opt_file_path_warning = os_is_file_absolute(p);
 
719
 
 
720
            /* check the suboption */
 
721
            switch(subopt)
 
722
            {
 
723
            case 'L':
 
724
                /* override the system library path */
 
725
                sys_lib_entry->set_path(p);
 
726
                break;
 
727
 
 
728
            case 'I':
 
729
                /* override the system include path */
 
730
                sys_inc_entry->set_path(p);
 
731
                break;
 
732
 
 
733
            case 's':
 
734
                /* add the source path */
 
735
                mk->add_source_path(p);
 
736
                break;
 
737
                
 
738
            case 'y':
 
739
                /* set the symbol path */
 
740
                mk->set_symbol_dir(p);
 
741
 
 
742
                /* remember that we have a symbol directory */
 
743
                sym_dir_set = TRUE;
 
744
                break;
 
745
            
 
746
            case 'o':
 
747
                /* set the object file directory */
 
748
                mk->set_object_dir(p);
 
749
 
 
750
                /* remember that we've set this path */
 
751
                obj_dir_set = TRUE;
 
752
                break;
 
753
 
 
754
            case 'a':
 
755
                /* 
 
756
                 *   Set the assembly listing file.  Note that this is an
 
757
                 *   undocumented option - at the moment, the assembly
 
758
                 *   listing is a bit rough, and is meant for internal TADS 3
 
759
                 *   development use, to facilitate analysis of the
 
760
                 *   compiler's code generation.  
 
761
                 */
 
762
 
 
763
                /* close any previous assembly listing file */
 
764
                if (assembly_fp != 0)
 
765
                {
 
766
                    osfcls(assembly_fp);
 
767
                    assembly_fp = 0;
 
768
                }
 
769
 
 
770
                /* open the listing file */
 
771
                assembly_fp = osfopwt(p, OSFTTEXT);
 
772
                if (assembly_fp == 0)
 
773
                {
 
774
                    printf("error: unable to create assembly listing file "
 
775
                           "\"%s\"\n", p);
 
776
                    goto done;
 
777
                }
 
778
 
 
779
                /* set the listing file */
 
780
                mk->set_assembly_listing(assembly_fp);
 
781
 
 
782
                /* done */
 
783
                break;
 
784
 
 
785
            default:
 
786
                /* invalid option */
 
787
                goto bad_option;
 
788
            }
 
789
 
 
790
            /* 
 
791
             *   if we're reading from a command file, and we haven't already
 
792
             *   found reason to warn about absolute paths, note that we need
 
793
             *   to warn now 
 
794
             */
 
795
            if (read_opt_file
 
796
                && need_opt_file_path_warning)
 
797
                opt_file_path_warning = TRUE;
 
798
 
 
799
            /* done */
 
800
            break;
 
801
 
 
802
        case 'G':
 
803
            /* code generation options */
 
804
            if (strcmp(argv[curarg], "-Gstg") == 0)
 
805
            {
 
806
                /* turn on sourceTextGroup mode */
 
807
                mk->set_source_text_group_mode(TRUE);
 
808
            }
 
809
            else
 
810
                goto bad_option;
 
811
            break;
 
812
 
 
813
        case 'n':
 
814
            /* check what we have */
 
815
            if (strcmp(argv[curarg], "-nopre") == 0)
 
816
            {
 
817
                /* explicitly turn off preinit mode */
 
818
                mk->set_preinit(FALSE);
 
819
            }
 
820
            else if (strcmp(argv[curarg], "-nobanner") == 0)
 
821
            {
 
822
                /* turn off the banner */
 
823
                show_banner = FALSE;
 
824
            }
 
825
            else if (strcmp(argv[curarg], "-nodef") == 0)
 
826
            {
 
827
                /* don't add the default modules */
 
828
                add_def_mod = FALSE;
 
829
            }
 
830
            else
 
831
                goto bad_option;
 
832
            break;
 
833
 
 
834
        case 'p':
 
835
            /* check what we have */
 
836
            if (strcmp(argv[curarg], "-pre") == 0)
 
837
            {
 
838
                /* explicitly turn on preinit mode */
 
839
                mk->set_preinit(TRUE);
 
840
            }
 
841
            else
 
842
                goto bad_option;
 
843
            break;
 
844
 
 
845
        case 'P':
 
846
            /* 
 
847
             *   A preprocess-only mode.  The plain -P generates
 
848
             *   preprocessed source to standard output; -Pi generates only
 
849
             *   a list of names of #included files to standard output.  
 
850
             */
 
851
            if (strcmp(argv[curarg], "-P") == 0)
 
852
            {
 
853
                /* set preprocess-only mode */
 
854
                mk->set_pp_only(TRUE);
 
855
                pp_only = TRUE;
 
856
            }
 
857
            else if (strcmp(argv[curarg], "-Pi") == 0)
 
858
            {
 
859
                /* set list-includes mode */
 
860
                mk->set_list_includes(TRUE);
 
861
                pp_only = TRUE;
 
862
            }
 
863
            break;
 
864
 
 
865
        case 'q':
 
866
            /* check the full option name */
 
867
            if (strcmp(argv[curarg], "-quotefname") == 0)
 
868
            {
 
869
                /* they want quoted filenames in error messages */
 
870
                mk->set_err_quoted_fnames(TRUE);
 
871
            }
 
872
            else if (strcmp(argv[curarg], "-q") == 0)
 
873
            {
 
874
                /* quiet mode - turn off banner and progress messages */
 
875
                show_banner = FALSE;
 
876
                hostifc->set_show_progress(FALSE);
 
877
            }
 
878
            else
 
879
                goto bad_option;
 
880
            break;
 
881
 
 
882
        case 's':
 
883
            /* check the full option name */
 
884
            if (strcmp(argv[curarg], "-statprefix") == 0)
 
885
            {
 
886
                /* get the argument */
 
887
                p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 10);
 
888
                
 
889
                /* set the status message prefix text */
 
890
                if (p != 0)
 
891
                    hostifc->set_status_prefix(p);
 
892
                else
 
893
                    goto missing_option_arg;
 
894
            }
 
895
            else
 
896
            {
 
897
                /* unknown option - report usage error */
 
898
                goto bad_option;
 
899
            }
 
900
            break;
 
901
 
 
902
        case 't':
 
903
            /* check the full option name */
 
904
            if (strcmp(argv[curarg], "-test") == 0)
 
905
            {
 
906
                /* 
 
907
                 *   it's the secret test-mode option - the test scripts use
 
908
                 *   this to set the reporting mode so that we suppress path
 
909
                 *   names in progress reports, so that the test logs can be
 
910
                 *   insensitive to local path name conventions 
 
911
                 */
 
912
                mk->set_test_report_mode(TRUE);
 
913
 
 
914
                /* perform any necessary test initialization */
 
915
                test_init();
 
916
            }
 
917
            else
 
918
            {
 
919
                /* unknown option - report usage error */
 
920
                goto bad_option;
 
921
            }
 
922
            break;
 
923
 
 
924
        case 'w':
 
925
            /* warning level/mode - see what level they're setting */
 
926
            switch(argv[curarg][2])
 
927
            {
 
928
                int num;
 
929
                int enable;
 
930
 
 
931
            case '0':
 
932
                /* no warnings */
 
933
                mk->set_warnings(FALSE);
 
934
                mk->set_pedantic(FALSE);
 
935
                break;
 
936
 
 
937
            case '1':
 
938
                /* normal warnings, but not pedantic warnings */
 
939
                mk->set_warnings(TRUE);
 
940
                mk->set_pedantic(FALSE);
 
941
                break;
 
942
 
 
943
            case '2':
 
944
                /* show all warnings, even pedantic ones */
 
945
                mk->set_warnings(TRUE);
 
946
                mk->set_pedantic(TRUE);
 
947
                pedantic = TRUE;
 
948
                break;
 
949
 
 
950
            case '+':
 
951
            case '-':
 
952
                /* 
 
953
                 *   Add/remove a warning to/from the list of warnings to
 
954
                 *   suppress.  First, note whether we're enabling or
 
955
                 *   disabling the warning.  
 
956
                 */
 
957
                enable = (argv[curarg][2] == '+');
 
958
 
 
959
                /* get the warning number */
 
960
                p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 2);
 
961
                if (p == 0)
 
962
                    goto missing_option_arg;
 
963
 
 
964
                /* convert it to a number */
 
965
                num = atoi(p);
 
966
 
 
967
                /* 
 
968
                 *   add it to the list if we're disabling it, otherwise
 
969
                 *   remove it from the list (since every warning is enabled
 
970
                 *   by default) 
 
971
                 */
 
972
                if (!enable)
 
973
                {
 
974
                    /* if we don't have room, we can't add it */
 
975
                    if (suppress_cnt >= SUPPRESS_LIST_MAX)
 
976
                    {
 
977
                        /* tell them what's wrong */
 
978
                        printf("Too many -w-# options - maximum %d.\n",
 
979
                               (int)SUPPRESS_LIST_MAX);
 
980
 
 
981
                        /* abort */
 
982
                        goto done;
 
983
                    }
 
984
 
 
985
                    /* add the new list entry */
 
986
                    suppress_list[suppress_cnt++] = num;
 
987
                }
 
988
                else
 
989
                {
 
990
                    size_t rem;
 
991
                    int *src;
 
992
                    int *dst;
 
993
 
 
994
                    /* 
 
995
                     *   scan the list for an existing instance of this
 
996
                     *   number, and remove any we find 
 
997
                     */
 
998
                    for (rem = suppress_cnt, src = dst = suppress_list ;
 
999
                         rem != 0 ; ++src, --rem)
 
1000
                    {
 
1001
                        /* if this one isn't to be suppressed, keep it */
 
1002
                        if (*src != num)
 
1003
                            *dst++ = *src;
 
1004
                    }
 
1005
 
 
1006
                    /* calculate the new count */
 
1007
                    suppress_cnt = dst - suppress_list;
 
1008
                }
 
1009
 
 
1010
                /* remember the updated list */
 
1011
                mk->set_suppress_list(suppress_list, suppress_cnt);
 
1012
 
 
1013
                /* done */
 
1014
                break;
 
1015
 
 
1016
            case 'e':
 
1017
                /* turn "warnings as errors" mode on or off */
 
1018
                switch (argv[curarg][3])
 
1019
                {
 
1020
                case '\0':
 
1021
                case '+':
 
1022
                    warnings_as_errors = TRUE;
 
1023
                    mk->set_warnings_as_errors(TRUE);
 
1024
                    break;
 
1025
 
 
1026
                case '-':
 
1027
                    warnings_as_errors = FALSE;
 
1028
                    mk->set_warnings_as_errors(FALSE);
 
1029
                    break;
 
1030
 
 
1031
                default:
 
1032
                    goto bad_option;
 
1033
                }
 
1034
                break;
 
1035
 
 
1036
            default:
 
1037
                /* invalid option */
 
1038
                goto bad_option;
 
1039
            }
 
1040
            break;
 
1041
 
 
1042
        case '?':
 
1043
            /* take '?' as an explicit request to show the usage message */
 
1044
            goto show_usage;
 
1045
 
 
1046
        case 'h':
 
1047
            /* check for "-help" */
 
1048
            if (strcmp(argv[curarg], "-help") == 0)
 
1049
                goto show_usage;
 
1050
 
 
1051
            /* other '-h*' options are unrecognized */
 
1052
            goto bad_option;
 
1053
            
 
1054
        default:
 
1055
        bad_option:
 
1056
            /* invalid - describe the problem */
 
1057
            printf("Error: Invalid option: \"%s\"\n"
 
1058
                   "(Type \"t3make -help\" for a summary of the "
 
1059
                   "command syntax)\n", argv[curarg]);
 
1060
 
 
1061
            /* abort */
 
1062
            goto done;
 
1063
 
 
1064
        missing_option_arg:
 
1065
            /* missing option argument */
 
1066
            printf("Error: Missing argument for option \"%s\"\n"
 
1067
                   "(Type \"t3make -help\" for a summary of the "
 
1068
                   "command syntax)\n", argv[curarg]);
 
1069
 
 
1070
            /* abort */
 
1071
            goto done;
 
1072
        }
 
1073
    }
 
1074
 
 
1075
    /* 
 
1076
     *   if there are no module arguments, and no project file was
 
1077
     *   specified, look for a default project file 
 
1078
     */
 
1079
    if (curarg >= argc && !usage_err && opt_file == 0)
 
1080
    {
 
1081
        /* 
 
1082
         *   if the default project file exists, try reading it; otherwise,
 
1083
         *   show a usage error 
 
1084
         */
 
1085
        if (!osfacc(T3_DEFAULT_PROJ_FILE))
 
1086
            opt_file = T3_DEFAULT_PROJ_FILE;
 
1087
        else
 
1088
        {
 
1089
            /* 
 
1090
             *   if there are no arguments at all, just show the usage
 
1091
             *   message; otherwise, explain that we need some source files 
 
1092
             */
 
1093
            if (argc == 1)
 
1094
            {
 
1095
                /* just fall through to the usage message */
 
1096
                usage_err = TRUE;
 
1097
            }
 
1098
            else
 
1099
            {
 
1100
                /* explain that we need source files */
 
1101
                printf("Error: No source file(s) specified.\n"
 
1102
                       "(Type \"t3make -help\" for help with the "
 
1103
                       "command syntax.\n");
 
1104
                goto done;
 
1105
            }
 
1106
        }
 
1107
    }
 
1108
 
 
1109
    /* 
 
1110
     *   Show the banner, unless they explicitly asked us not to (and even
 
1111
     *   then, show it anyway if we're going to show the "usage" message).
 
1112
     */
 
1113
    if ((show_banner || usage_err) && (opt_file == 0 || read_opt_file))
 
1114
    {
 
1115
        char patch_id[10];
 
1116
        
 
1117
        /* 
 
1118
         *   Generate the patch number or development build iteration number,
 
1119
         *   if appropriate.  If there's a patch number, give it precedence,
 
1120
         *   appending it as an extra dot-number suffix; if there's a build
 
1121
         *   number, show it as an alphabetic suffix.  If neither is defined,
 
1122
         *   add nothing, so we'll just have a three-part dotted version
 
1123
         *   number.  
 
1124
         */
 
1125
        if (TC_VSN_PATCH != 0)
 
1126
            sprintf(patch_id, ".%d", TC_VSN_PATCH);
 
1127
        else if (TC_VSN_DEVBUILD != 0)
 
1128
            sprintf(patch_id, "%c", TC_VSN_DEVBUILD + 'a' - 1);
 
1129
        else
 
1130
            patch_id[0] = '\0';
 
1131
 
 
1132
        /* show the banner */
 
1133
        /* copyright-date-string */
 
1134
        printf("TADS Compiler %d.%d.%d%s  "
 
1135
               "Copyright 1999, 2007 Michael J. Roberts\n",
 
1136
               TC_VSN_MAJOR, TC_VSN_MINOR, TC_VSN_REV, patch_id);
 
1137
    }
 
1138
 
 
1139
    /* 
 
1140
     *   warn about absolute paths in the options file, if necessary; do this
 
1141
     *   only in pedantic mode, though, since it's only a usage suggestion 
 
1142
     */
 
1143
    if (opt_file_path_warning && pedantic)
 
1144
    {
 
1145
        /* show the warning */
 
1146
        printf("Warning: absolute path found in -Fs/-Fo/-Fy option "
 
1147
               "in options (-f) file.\n");
 
1148
 
 
1149
        /* add more explanation if in verbose mode */
 
1150
        if (verbose)
 
1151
            printf("It's better not to use absolute paths in the "
 
1152
                   "options file, because this\n"
 
1153
                   "ties the options file to the particular "
 
1154
                   "directory layout of your machine.  \n"
 
1155
                   "If possible, refer only to subfolders of the "
 
1156
                   "folder containing the options\n"
 
1157
                   "file, and refer to the subfolders using "
 
1158
                   "relative path notation.\n");
 
1159
    }
 
1160
 
 
1161
    /* if a usage error occurred, display the usage message */
 
1162
    if (usage_err)
 
1163
    {
 
1164
    show_usage:
 
1165
        printf("usage: t3make [options] module ... [-res resources]\n"
 
1166
               "Options:\n"
 
1167
               "  -a      - rebuild all files, "
 
1168
               "even if up to date\n"
 
1169
               "  -al     - relink, even if image file is up to date\n"
 
1170
               "  -c      - compile only (do not create image file)\n"
 
1171
               "  -clean  - delete all derived (symbol, object, image) "
 
1172
               "files\n"
 
1173
               "  -cs xxx - source file character set is 'xxx'\n"
 
1174
               "  -d      - compile for debugging (include symbols)\n"
 
1175
               "  -D x=y  - define preprocessor symbol 'x' with value 'y'\n"
 
1176
               "  -errnum - show numeric error codes with error messages\n"
 
1177
               "  -f file - read command line options from 'file'\n"
 
1178
               "  -I dir  - add 'dir' to #include search path\n"
 
1179
               "  -Fs dir - add 'dir' to source file search path\n"
 
1180
               "  -Fy dir - put symbol files in directory 'dir'\n"
 
1181
               "  -Fo dir - put object files in directory 'dir'\n"
 
1182
               "  -FI dir - override the standard system include path\n"
 
1183
               "  -FL dir - override the standard system library path\n"
 
1184
               "  -Gstg   - generate sourceTextGroup properties\n"
 
1185
               "  -nobanner - suppress version/copyright banner\n"
 
1186
               "  -nodef  - do not include default library modules in build\n"
 
1187
               "  -nopre  - do not run pre-initialization, regardless of "
 
1188
               "debug mode\n"
 
1189
               "  -o img  - set image file name to 'img'\n"
 
1190
               "  -Os str - write all strings found in compiled files to "
 
1191
               "text file 'str'\n"
 
1192
               "  -P      - preprocess only; write preprocessed source "
 
1193
               "to console\n"
 
1194
               "  -Pi     - preprocess only; write only list of #include "
 
1195
               "files to console\n"
 
1196
               "  -pre    - run pre-initialization, regardless of "
 
1197
               "debug mode\n"
 
1198
               "  -q      - quiet mode: suppress banner and "
 
1199
               "progress reports\n"
 
1200
               "  -quotefname - quote filenames in error messages\n"
 
1201
               "  -statprefix txt - set status-message prefix text\n"
 
1202
               "  -U x    - un-define preprocessor symbol 'x'\n"
 
1203
               "  -v      - display verbose error messages\n"
 
1204
               "  -w#     - warning level: 0=none, 1=standard "
 
1205
               "(default), 2=pedantic\n"
 
1206
               "  -w-#    - suppress the given warning number\n"
 
1207
               "  -w+#    - enable the given warning number\n"
 
1208
               "  -we     - treat warnings as errors (-we- to disable)\n"
 
1209
               "\n"
 
1210
               "Modules: Each entry in the module list can have one "
 
1211
               "of these forms:\n"
 
1212
               "\n"
 
1213
               "  filename           - specify the name of a source or "
 
1214
               "library file; the\n"
 
1215
               "                       file's type is inferred from its "
 
1216
               "filename suffix\n"
 
1217
               "  -source filename   - specify the name of a source file\n"
 
1218
               "  -lib filename      - specify the name of a library\n"
 
1219
               "\n"
 
1220
               "The default filename suffix for a source file is \".t\", "
 
1221
               "and the default for a\n"
 
1222
               "library is \".tl\".  You can omit the \"-source\" or "
 
1223
               "\"-lib\" specifier for any\n"
 
1224
               "file if its name includes the correct default suffix for "
 
1225
               "its type, and its\n"
 
1226
               "name doesn't begin with a \"-\".\n"
 
1227
               "Immediately following each library, you can add one or more "
 
1228
               "\"-x filename\"\n"
 
1229
               "options to exclude library members.  Each \"-x\" excludes "
 
1230
               "one library member.\n"
 
1231
               "The filename specified in a \"-x\" option must exactly "
 
1232
               "match the filename as it\n"
 
1233
               "appears in the library \"source:\" line.\n"
 
1234
               "\n"
 
1235
               "If no modules are specified, the compiler will attempt to "
 
1236
               "find '" T3_DEFAULT_PROJ_FILE "'\n"
 
1237
               "in the current directory, and will read it to obtain build "
 
1238
               "instructions.\n"
 
1239
               "\n"
 
1240
               "Resources: Multi-media resources can be bundled into the "
 
1241
               "image file using the\n"
 
1242
               "-res option.  After the -res option, specify any desired "
 
1243
               "resource options:\n"
 
1244
               "\n"
 
1245
               "  -recurse   - recurse into subdirectories for subsequent "
 
1246
               "items (default)\n"
 
1247
               "  -norecurse - do not recurse into subdirectories for "
 
1248
               "subsequent items\n"
 
1249
               "  file       - add 'file' as a multimedia resource\n"
 
1250
               "  file=alias - add 'file', using 'alias' as the resource "
 
1251
               "name\n"
 
1252
               "  dir        - add all files within directory 'dir' (and all "
 
1253
               "files in all\n"
 
1254
               "               subdirectories of 'dir', if -recurse option "
 
1255
               "is in effect)\n"
 
1256
               "\n"
 
1257
               "When a file is specified without an '=alias' name, the "
 
1258
               "stored resource name is\n"
 
1259
               "the original filename converted to URL-style notation.  If "
 
1260
               "an '=alias' name is\n"
 
1261
               "specified, then the stored resource will be named with the "
 
1262
               "alias name.\n"
 
1263
               "\n"
 
1264
               "Note that resource options are ignored when compiling "
 
1265
               "for debugging.\n");
 
1266
 
 
1267
        /* terminate */
 
1268
        goto done;
 
1269
    }
 
1270
 
 
1271
    /* add the modules */
 
1272
    for ( ; curarg < argc ; ++curarg)
 
1273
    {
 
1274
        int is_source;
 
1275
        int is_lib;
 
1276
        char relbuf[OSFNMAX];
 
1277
 
 
1278
        /* we don't know the file type yet */
 
1279
        is_source = FALSE;
 
1280
        is_lib = FALSE;
 
1281
 
 
1282
        /* check to see if we have a module type option */
 
1283
        if (argv[curarg][0] == '-')
 
1284
        {
 
1285
            if (strcmp(argv[curarg], "-source") == 0)
 
1286
            {
 
1287
                /* note that we have a source file, and skip the option */
 
1288
                is_source = TRUE;
 
1289
                ++curarg;
 
1290
            }
 
1291
            else if (strcmp(argv[curarg], "-lib") == 0)
 
1292
            {
 
1293
                /* note that we have a library, and skip the option */
 
1294
                is_lib = TRUE;
 
1295
                ++curarg;
 
1296
            }
 
1297
            else if (strcmp(argv[curarg], "-res") == 0)
 
1298
            {
 
1299
                /* 
 
1300
                 *   Resource arguments follow - we're done with modules.
 
1301
                 *   Skip the "-res" argument and exit the module loop.  
 
1302
                 */
 
1303
                ++curarg;
 
1304
                break;
 
1305
            }
 
1306
            else
 
1307
            {
 
1308
                /* invalid option in the module list */
 
1309
                goto bad_option;
 
1310
            }
 
1311
 
 
1312
            /* 
 
1313
             *   if we have no filename argument following the type
 
1314
             *   specifier, it's an error 
 
1315
             */
 
1316
            if (curarg == argc)
 
1317
            {
 
1318
                --curarg;
 
1319
                goto missing_option_arg;
 
1320
            }
 
1321
        }
 
1322
 
 
1323
        /* 
 
1324
         *   if we didn't find an explicit type specifier, infer the type
 
1325
         *   from the filename suffix 
 
1326
         */
 
1327
        if (!is_source && !is_lib)
 
1328
        {
 
1329
            size_t len;
 
1330
 
 
1331
            /* 
 
1332
             *   if we have a ".tl" suffix, assume it's a library file;
 
1333
             *   otherwise, assume it's a source file 
 
1334
             */
 
1335
            if ((len = strlen(argv[curarg])) > 3
 
1336
                && stricmp(argv[curarg] + len - 3, ".tl") == 0)
 
1337
            {
 
1338
                /* ".tl" - it's a library file */
 
1339
                is_lib = TRUE;
 
1340
            }
 
1341
            else
 
1342
            {
 
1343
                /* something else - assume it's a source file */
 
1344
                is_source = TRUE;
 
1345
            }
 
1346
        }
 
1347
 
 
1348
        /* make the filename relative to the option file path */
 
1349
        p = make_opt_file_relative(relbuf, sizeof(relbuf),
 
1350
                                   read_opt_file, opt_file_path,
 
1351
                                   argv[curarg]);
 
1352
 
 
1353
        /* process the file according to its type */
 
1354
        if (is_source)
 
1355
        {
 
1356
            CTcMakeModule *mod;
 
1357
 
 
1358
            /* add this file to the module list */
 
1359
            mod = mk->add_module(p, 0, 0);
 
1360
 
 
1361
            /* set the module's original name to the name as given */
 
1362
            mod->set_orig_name(argv[curarg]);
 
1363
 
 
1364
            /* 
 
1365
             *   if no image has been specified yet already, use this
 
1366
             *   module's name as the image name, with the suffix ".t3" 
 
1367
             */
 
1368
            if (!image_specified)
 
1369
            {
 
1370
                char buf[OSFNMAX];
 
1371
 
 
1372
                /* 
 
1373
                 *   build the default image filename by changing the
 
1374
                 *   module's extension to "t3" (or adding the "t3"
 
1375
                 *   extension if the module didn't have one to begin with) 
 
1376
                 */
 
1377
                strcpy(buf, p);
 
1378
                os_remext(buf);
 
1379
                os_addext(buf, "t3");
 
1380
 
 
1381
                /* set the filename */
 
1382
                mk->set_image_file(buf);
 
1383
 
 
1384
                /* note that we know the image file's name now */
 
1385
                image_specified = TRUE;
 
1386
            }
 
1387
        }
 
1388
        else
 
1389
        {
 
1390
            CTcMakeModule lib_mod;
 
1391
            CTcMakeModule *last_pre_lib_mod;
 
1392
            char fname[OSFNMAX];
 
1393
            char orig_fname[OSFNMAX];
 
1394
            int nodef;
 
1395
 
 
1396
            /* add a default "tl" extension */
 
1397
            strcpy(fname, p);
 
1398
            os_defext(fname, "tl");
 
1399
 
 
1400
            /* likewise, add a default "tl" extension to the original name */
 
1401
            strcpy(orig_fname, argv[curarg]);
 
1402
            os_defext(orig_fname, "tl");
 
1403
 
 
1404
            /* 
 
1405
             *   set up a module for the library, so we can easily search
 
1406
             *   the source path for the module 
 
1407
             */
 
1408
            lib_mod.set_module_name(fname);
 
1409
            lib_mod.set_search_source_name(orig_fname);
 
1410
 
 
1411
            /* get the module name by searching the path if necessary */
 
1412
            mk->get_srcfile(fname, &lib_mod);
 
1413
 
 
1414
            /* remember the last module before this library's modules */
 
1415
            last_pre_lib_mod = mk->get_last_module();
 
1416
                
 
1417
            /* 
 
1418
             *   Process the library.  Since this is a top-level library
 
1419
             *   (rather than a sub-library included from within another
 
1420
             *   library), there is no prefix to the URL's of the member
 
1421
             *   items. 
 
1422
             */
 
1423
            if (CTcLibParserCmdline::process_lib_arg(
 
1424
                hostifc, mk, res_list, fname, "", &nodef))
 
1425
                lib_err = TRUE;
 
1426
 
 
1427
            /* if there was a 'nodef' flag, note it */
 
1428
            if (nodef)
 
1429
                add_def_mod = FALSE;
 
1430
 
 
1431
            /* process any exclusion options */
 
1432
            while (curarg + 1 < argc && strcmp(argv[curarg+1], "-x") == 0)
 
1433
            {
 
1434
                CTcMakeModule *mod;
 
1435
                const char *url;
 
1436
 
 
1437
                /* skip to the "-x" */
 
1438
                ++curarg;
 
1439
                
 
1440
                /* if the filename is missing, report a usage error */
 
1441
                if (curarg + 1 >= argc)
 
1442
                    goto missing_option_arg;
 
1443
 
 
1444
                /* skip to the -x's argument and retrieve it */
 
1445
                url = argv[++curarg];
 
1446
 
 
1447
                /* 
 
1448
                 *   Start with the next module after the last module before
 
1449
                 *   this library.  If there was nothing before this library,
 
1450
                 *   then this library's first module is the first module in
 
1451
                 *   the entire program,.  
 
1452
                 */
 
1453
                if ((mod = last_pre_lib_mod) != 0)
 
1454
                    mod = mod->get_next();
 
1455
                else
 
1456
                    mod = mk->get_first_module();
 
1457
 
 
1458
                /* scan the list of library modules for a match */
 
1459
                for ( ; mod != 0 ; mod = mod->get_next())
 
1460
                {
 
1461
                    /* if this module has the excluded URL, exclude it */
 
1462
                    if (stricmp(mod->get_url(), argv[curarg]) == 0)
 
1463
                    {
 
1464
                        /* mark this module as excluded */
 
1465
                        mod->set_excluded(TRUE);
 
1466
 
 
1467
                        /* 
 
1468
                         *   no need to look any further - assume each URL
 
1469
                         *   is unique 
 
1470
                         */
 
1471
                        break;
 
1472
                    }
 
1473
                }
 
1474
            }
 
1475
        }
 
1476
    }
 
1477
 
 
1478
    /* if we have any more arguments, they're for resource files */
 
1479
    for ( ; curarg < argc ; ++curarg)
 
1480
    {
 
1481
        char relbuf[OSFNMAX];
 
1482
 
 
1483
        /* check for a resource bundler option */
 
1484
        if (argv[curarg][0] == '-')
 
1485
        {
 
1486
            /* check the argument */
 
1487
            switch(argv[curarg][1])
 
1488
            {
 
1489
            case 'n':
 
1490
                /* check for '-norecurse' */
 
1491
                if (strcmp(argv[curarg], "-norecurse") == 0)
 
1492
                    res_recurse = FALSE;
 
1493
                else
 
1494
                    goto bad_option;
 
1495
                break;
 
1496
 
 
1497
            case 'r':
 
1498
                /* check for '-recurse' */
 
1499
                if (strcmp(argv[curarg], "-recurse") == 0)
 
1500
                    res_recurse = TRUE;
 
1501
                else
 
1502
                    goto bad_option;
 
1503
                break;
 
1504
 
 
1505
            default:
 
1506
                /* unknown option */
 
1507
                goto bad_option;
 
1508
            }
 
1509
        }
 
1510
        else
 
1511
        {
 
1512
            char *p;
 
1513
            char *fname;
 
1514
            char *alias;
 
1515
 
 
1516
            /* 
 
1517
             *   It's not an option, so it must be a file.  Scan for an
 
1518
             *   alias, which is introduced with an '=' character.  
 
1519
             */
 
1520
            for (p = fname = argv[curarg] ; *p != '\0' && *p != '=' ; ++p) ;
 
1521
            if (*p == '=')
 
1522
            {
 
1523
                /* 
 
1524
                 *   overwrite the '=' with a null byte, so that the filename
 
1525
                 *   ends here 
 
1526
                 */
 
1527
                *p = '\0';
 
1528
 
 
1529
                /* the alias starts after the '=' */
 
1530
                alias = p + 1;
 
1531
            }
 
1532
            else
 
1533
            {
 
1534
                /* there's no alias */
 
1535
                alias = 0;
 
1536
            }
 
1537
 
 
1538
            /* make the filename relative to the option file path */
 
1539
            fname = make_opt_file_relative(relbuf, sizeof(relbuf),
 
1540
                                           read_opt_file, opt_file_path,
 
1541
                                           fname);
 
1542
 
 
1543
            /* add this file to the resource list*/
 
1544
            res_list->add_file(fname, alias, res_recurse);
 
1545
        }
 
1546
    }
 
1547
 
 
1548
    /*
 
1549
     *   If an option file was specified or implied, and we haven't read
 
1550
     *   it yet, read it now.  
 
1551
     */
 
1552
    if (opt_file != 0 && !read_opt_file)
 
1553
    {
 
1554
        osfildef *fp;
 
1555
        int new_argc;
 
1556
        char **new_argv;
 
1557
        char new_opt_file[OSFNMAX];
 
1558
 
 
1559
        /* if the options file doesn't exist, try adding the suffix 't3m' */
 
1560
        if (osfacc(opt_file))
 
1561
        {
 
1562
            strcpy(new_opt_file, opt_file);
 
1563
            os_defext(new_opt_file, "t3m");
 
1564
            opt_file = new_opt_file;
 
1565
        }
 
1566
 
 
1567
        /* open the options file */
 
1568
        fp = osfoprt(opt_file, OSFTTEXT);
 
1569
        if (fp == 0)
 
1570
        {
 
1571
            printf("error: unable to read option file \"%s\"\n", opt_file);
 
1572
            err_cnt = 1;
 
1573
            goto done;
 
1574
        }
 
1575
 
 
1576
        /* 
 
1577
         *   First, parse the file simply to count the arguments.  Add in one
 
1578
         *   extra argument to make room for making a copy of argv[0].  
 
1579
         */
 
1580
        new_argc = CTcCommandUtil::parse_opt_file(fp, 0, &opt_helper) + 1;
 
1581
 
 
1582
        /* rewind the file to parse it again */
 
1583
        osfseek(fp, 0, OSFSK_SET);
 
1584
 
 
1585
        /* allocate a new argument list */
 
1586
        new_argv = (char **)t3malloc(new_argc * sizeof(new_argv[0]));
 
1587
 
 
1588
        /* copy the program name from argv[0] */
 
1589
        new_argv[0] = argv[0];
 
1590
 
 
1591
        /* 
 
1592
         *   Re-read the file, saving the arguments.  Note that we want to
 
1593
         *   start saving the arguments from the file at index 1 in the new
 
1594
         *   argv array, because we reserve argv[0] to hold the original
 
1595
         *   program name argument.  
 
1596
         */
 
1597
        CTcCommandUtil::parse_opt_file(fp, new_argv + 1, &opt_helper);
 
1598
 
 
1599
        /* done with the file - close it */
 
1600
        osfcls(fp);
 
1601
 
 
1602
        /* start over with the new argument vector */
 
1603
        argv = new_argv;
 
1604
        argc = new_argc;
 
1605
        
 
1606
        /* 
 
1607
         *   note that we've read the options file - we can only do this
 
1608
         *   once per run 
 
1609
         */
 
1610
        read_opt_file = TRUE;
 
1611
 
 
1612
        /* 
 
1613
         *   Note the option file's path prefix.  We'll assume that any
 
1614
         *   relative filename paths mentioned in the option file are meant
 
1615
         *   to be relative to the folder containing the option file itself. 
 
1616
         */
 
1617
        os_get_path_name(opt_file_path, sizeof(opt_file_path), opt_file);
 
1618
 
 
1619
        /* go add the new command options */
 
1620
        goto parse_options;
 
1621
    }
 
1622
 
 
1623
    /* 
 
1624
     *   Add the default object modules, if appropriate.  Do not add the
 
1625
     *   default modules unless we're linking. 
 
1626
     */
 
1627
    if (add_def_mod && !compile_only && !pp_only)
 
1628
    {
 
1629
        char srcname[OSFNMAX];
 
1630
        CTcMakeModule *mod;
 
1631
 
 
1632
        /* build the full path to the "_main" library module */
 
1633
        os_build_full_path(srcname, sizeof(srcname),
 
1634
                           sys_lib_entry->get_path(), "_main");
 
1635
 
 
1636
        /* add this as the first module of our compilation */
 
1637
        mod = mk->add_module_first(srcname, 0, 0);
 
1638
 
 
1639
        /* set its original name, and note it's from the system library */
 
1640
        mod->set_orig_name("_main");
 
1641
        mod->set_from_syslib();
 
1642
    }
 
1643
 
 
1644
    /*
 
1645
     *   If the symbol file and object file directory paths weren't
 
1646
     *   explicitly set, set these to the same path used by the image file.
 
1647
     *   This will put all of the output files in the same place, if they
 
1648
     *   didn't explicitly tell us where to put the different kinds of
 
1649
     *   generated files.  
 
1650
     */
 
1651
    os_get_path_name(dirbuf, sizeof(dirbuf), mk->get_image_file());
 
1652
    if (!sym_dir_set)
 
1653
        mk->set_symbol_dir(dirbuf);
 
1654
    if (!obj_dir_set)
 
1655
        mk->set_object_dir(dirbuf);
 
1656
 
 
1657
    /* if we encountered any errors parsing a library, we can't proceed */
 
1658
    if (lib_err)
 
1659
        goto done;
 
1660
 
 
1661
    /* build the program */
 
1662
    mk->build(hostifc, &err_cnt, &warn_cnt,
 
1663
              force_build, force_link, res_list, argv[0]);
 
1664
 
 
1665
done:
 
1666
    /* terminate the error subsystem */
 
1667
    CTcMain::tc_err_term();
 
1668
 
 
1669
    /* delete our 'make' object */
 
1670
    delete mk;
 
1671
 
 
1672
    /* show the error and warning counts if non-zero */
 
1673
    if (err_cnt != 0 || warn_cnt != 0)
 
1674
        printf("Errors:   %d\n"
 
1675
               "Warnings: %d\n", err_cnt, warn_cnt);
 
1676
 
 
1677
    /* if we read an options file, delete the memory used for the options */
 
1678
    if (read_opt_file)
 
1679
    {
 
1680
        int i;
 
1681
        
 
1682
        /* 
 
1683
         *   delete the argv strings (except for argv[0], which came from
 
1684
         *   the caller)
 
1685
         */
 
1686
        for (i = 1 ; i < argc ; ++i)
 
1687
            opt_helper.free_opt_file_str(argv[i]);
 
1688
 
 
1689
        /* delete the argv vector itself */
 
1690
        t3free(argv);
 
1691
    }
 
1692
 
 
1693
    /* if we have a string capture file, close it */
 
1694
    if (string_fp != 0)
 
1695
        osfcls(string_fp);
 
1696
 
 
1697
    /* if we have an aassembly listing file, close it */
 
1698
    if (assembly_fp != 0)
 
1699
        osfcls(assembly_fp);
 
1700
 
 
1701
    /* delete the host interface */
 
1702
    delete hostifc;
 
1703
 
 
1704
    /* delete the resource list */
 
1705
    delete res_list;
 
1706
 
 
1707
    /* show any unfreed memory (if we're in a debug build) */
 
1708
    t3_list_memory_blocks(0);
 
1709
 
 
1710
    /* 
 
1711
     *   exit with an appropriate exit code, depending on whether we had
 
1712
     *   any errors or not 
 
1713
     */
 
1714
    return (err_cnt != 0 || (warnings_as_errors && warn_cnt != 0)
 
1715
            ? OSEXFAIL : OSEXSUCC);
 
1716
}
 
1717