1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
16 *     contributors may be used to endorse or promote products derived from
17 *     this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Portions of this software have been released under the following terms:
31 *
32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
35 *
36 * To anyone who acknowledges that this file is provided "AS IS"
37 * without any express or implied warranty:
38 * permission to use, copy, modify, and distribute this file for any
39 * purpose is hereby granted without fee, provided that the above
40 * copyright notices and this notice appears in all source code copies,
41 * and that none of the names of Open Software Foundation, Inc., Hewlett-
42 * Packard Company or Digital Equipment Corporation be used
43 * in advertising or publicity pertaining to distribution of the software
44 * without specific, written prior permission.  Neither Open Software
45 * Foundation, Inc., Hewlett-Packard Company nor Digital
46 * Equipment Corporation makes any representations about the suitability
47 * of this software for any purpose.
48 *
49 * Copyright (c) 2007, Novell, Inc. All rights reserved.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1.  Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 * 2.  Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in the
58 *     documentation and/or other materials provided with the distribution.
59 * 3.  Neither the name of Novell Inc. nor the names of its contributors
60 *     may be used to endorse or promote products derived from this
61 *     this software without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 * @APPLE_LICENSE_HEADER_END@
75 */
76
77/*
78**
79**  NAME:
80**
81**      command.c
82**
83**  FACILITY:
84**
85**      Interface Definition Language (IDL) Compiler
86**
87**  ABSTRACT:
88**
89**  IDL command line parsing.
90**
91**  VERSION: DCE 1.0
92**
93*/
94
95#include <nidl.h>       /* IDL common defs */
96#include <command.h>
97
98#include <files.h>      /* File handling defs */
99#include <getflags.h>   /* Command line parsing defs */
100#include <message.h>    /* reporting functions */
101
102#ifndef MAX_DEF_STRINGS
103# define MAX_DEF_STRINGS 10
104#endif
105
106#ifndef MAX_DUMP_STRINGS
107# define MAX_DUMP_STRINGS 10
108#endif
109
110#ifndef MAX_IMPORT_DIRECTORIES
111# define MAX_IMPORT_DIRECTORIES 50
112#endif
113
114extern boolean  ERR_no_warnings;    /* Global copy of -no_warn cmd option */
115extern char     *last_string;       /* Last string parsed from cmd line */
116
117static boolean  cmd_opt[NUM_OPTS];  /* True/False values for command options */
118static void     *cmd_val[NUM_OPTS]; /* Values associated w/ options (if any) */
119
120/* Global versions of the command options */
121       boolean *CMD_opts = (boolean*)cmd_opt;
122       void    **CMD_vals = (void**)cmd_val;
123
124static const char *UNSPECIFIED = "";
125static const char *nidl_library = NULL;
126
127static int      do_bug[NUM_BUGS];
128static int      do_not_do_bug[NUM_BUGS];
129static boolean  support_bug[NUM_BUGS + 1];
130
131static const char *caux_suffix    = CAUX_SUFFIX,
132                *caux_file;
133
134static const char *cc_cmd;
135static const char *cc_opt;
136
137static const char *client;
138#define client_none 0
139#define client_stub 1
140#define client_aux  2
141#define client_all  3
142static const char *client_vals[]    = { "none", "stub", "aux", "all", NULL };
143
144const char      *CMD_def_cpp_cmd;
145static const char *cpp_cmd;
146static const char *cpp_opt;
147
148static const char *cstub_suffix   = CSTUB_SUFFIX,
149                *cstub_file;
150
151static char     *(def_strings[MAX_DEF_STRINGS + 1]);
152static char     *(undef_strings[MAX_DEF_STRINGS + 1]);
153
154#ifdef DUMPERS
155static char     *dump_strings[MAX_DUMP_STRINGS+1];
156#define dump_acf        0
157#define dump_ast        1
158#define dump_ast_after  2
159#define dump_cmd        3
160#define dump_debug      4
161#define dump_flat       5
162#define dump_mnode      6
163#define dump_mool       7
164#define dump_nametbl    8
165#define dump_recs       9
166#define dump_sends     10
167#define dump_unode     11
168#define dump_uool      12
169#define dump_yy        13
170static const char *dump_vals[]    = { "acf", "ast", "ast_after", "cmd", "debug",
171                                    "flat", "mnode", "mool", "nametbl", "recs",
172                                    "sends", "unode", "uool", "yy", NULL };
173#endif
174
175static const char *header_suffix  = HEADER_SUFFIX,
176                *header_file;
177
178/*  List of import directories - allow two extra slots for the implicit
179 *  -I CD_DIR -I DEFAULT_IDIR and one for the sentinel.
180 */
181static const char *(import_directories[MAX_IMPORT_DIRECTORIES + 2 + 1]);
182
183static const char *keep;
184#define keep_none       0
185#define keep_c_source   1
186#define keep_object     2
187#define keep_both       3
188#define keep_all        4
189static const char *keep_vals[]    = { "none", "c_source", "object", "both",
190                                    "all", NULL  };
191
192static const char *out_dir;
193
194static const char *saux_suffix    = SAUX_SUFFIX,
195                *saux_file;
196
197static const char *server;
198#define server_none 0
199#define server_stub 1
200#define server_aux  2
201#define server_all  3
202static const char *server_vals[]    = { "none", "stub", "aux", "all", NULL };
203
204static const char *sstub_suffix   = SSTUB_SUFFIX,
205             *sstub_file;
206
207boolean CMD_DCL_interface = FALSE;
208static const char *standard = "extended";
209static int      standard_opt;
210static const char *standard_vals[] = {
211                "portable", "dce_v10", "dce_v11", "extended", NULL };
212static const int standard_ivals[] = {
213                opt_standard_dce_1_0, opt_standard_dce_1_0,
214                opt_standard_dce_1_1, opt_standard_dce_1_1 };
215
216#define FD(x)   (FLAGDEST)&x
217#define FDV(x)  (FLAGDEST)x
218
219static const
220OPTIONS option_table[]={
221	{"bug",          VINTARG(NUM_BUGS),              FDV(do_bug)},
222	{"caux",         STRARG,                         FD(caux_file)},
223	{"cc_cmd",       STRARG,                         FD(cc_cmd)},
224	{"cc_opt",       STRARG,                         FD(cc_opt)},
225	{"cepv",         ASSERTARG,                      FD(cmd_opt[opt_cepv])},
226	{"client",       STRARG,                         FD(client)},
227	{"confirm",      ASSERTARG|HIDARG,               FD(cmd_opt[opt_confirm])},
228        {"cpp_cmd",      OSTRARG,                        FD(cpp_cmd)},
229        {"cpp_opt",      STRARG,                         FD(cpp_opt)},
230	{"cstub",        STRARG,                         FD(cstub_file)},
231	{"D",            VSTRARG(MAX_DEF_STRINGS),       FDV(def_strings)},
232#ifdef DUMPERS
233	{"dump",         VSTRARG(MAX_DUMP_STRINGS)|HIDARG,FDV(dump_strings)},
234#endif
235	{"header",       OSTRARG,                        FD(header_file)},
236	{"I",            VSTRARG(MAX_IMPORT_DIRECTORIES),FDV(import_directories)},
237	{"keep",         STRARG,                         FD(keep)},
238	{"midl",         ASSERTARG|HIDARG,               FD(cmd_opt[opt_midl])},
239	{"no_bug",       VINTARG(NUM_BUGS),              FDV(do_not_do_bug)},
240	{"no_cpp",       DENYARG,                        FD(cmd_opt[opt_cpp])},
241	{"no_def_idir",  DENYARG,                        FD(cmd_opt[opt_def_idir])},
242	{"no_header",    DENYARG|HIDARG,                 FD(cmd_opt[opt_header])},
243	{"no_mepv",      DENYARG,                        FD(cmd_opt[opt_mepv])},
244	{"no_warn",      DENYARG,                        FD(cmd_opt[opt_warn])},
245#ifdef DUMPERS
246	{"ool",          ASSERTARG|HIDARG,               FD(cmd_opt[opt_ool])},
247#endif
248	{"out",          STRARG,                         FD(out_dir)},
249	{"saux",         STRARG,                         FD(saux_file)},
250	{"server",       STRARG,                         FD(server)},
251	{"space_opt",    ASSERTARG,                      FD(cmd_opt[opt_space_opt])},
252	{"sstub",        STRARG,                         FD(sstub_file)},
253	{"standard",     STRARG,                         FD(standard)},
254	{"stdin",        ASSERTARG,                      FD(cmd_opt[opt_stdin])},
255	{"syntax_only",  ASSERTARG,                      FD(cmd_opt[opt_syntax_check])},
256	{"U",            VSTRARG(MAX_DEF_STRINGS),       FDV(undef_strings)},
257	{"v",            ASSERTARG|HIDARG,               FD(cmd_opt[opt_verbose])},
258	{"version",      ASSERTARG|HIDARG,               FD(cmd_opt[opt_version])},
259	{0,              0,                              0}
260};
261
262/*
263**  C M D _ e x p l a i n _ a r g s
264**
265**  Explains command line arguments.
266*/
267
268void CMD_explain_args(void)
269{
270    message_print(NIDL_USAGE);
271
272    /*
273     * Don't print full list of command options here unless -confirm
274     * specified, but let user know there is a way to do it.
275     */
276    if (cmd_opt[opt_confirm])
277        printflags(option_table);
278    else
279        message_print(NIDL_CMDERR, "-confirm");
280}
281
282/*
283**  c h e c k _ s t r _ l i s t
284**
285**  Checks a string argument against a list of legal
286**  values.  Issues error and exits for illegal value.
287**
288**  Returns:    Index of match.  Returns -1 for null string.
289*/
290
291static int check_str_list
292(
293    const char        *opt,           /* [in] Name of command option */
294    const char        *val,           /* [in] Value assigned to command option */
295    const char        **list          /* [in] List of legal values for cmd option */
296)
297{
298    int i;      /* List index */
299
300    if (val[0] == '\0')
301        return -1;
302
303    for (i = 0 ; list[i] != NULL ; i++ )
304        if (strcmp(val, list[i]) == 0)
305            return i;
306
307    message_print(NIDL_INVOPTION, opt, val);
308    message_print(NIDL_LEGALVALS);
309
310    for ( ; *list != NULL ; list++ )
311        fprintf(stderr, " %s", *list);
312
313    fprintf(stderr, "\n");
314    exit(pgm_error);
315}
316
317/*
318**  c h e c k _ s t r _ i n t _ l i s t
319**
320**  Checks a string argument against a list of legal
321**  values.  Issues error and exits for illegal value.
322**
323**  Returns:    Integer corresponding to matched string.  Integer is
324**              obtained from array using index of matched string.
325**              Returns -1 for null string.
326*/
327
328static int check_str_int_list
329(
330    const char        *opt,           /* [in] Name of command option */
331    const char        *val,           /* [in] Value assigned to command option */
332    const char        **list,         /* [in] List of legal values for cmd option */
333    const int         *ilist          /* [in] List of corresponding integer values */
334)
335{
336    int i;      /* List index */
337
338    if (val[0] == '\0')
339        return -1;
340
341    for (i = 0 ; list[i] != NULL ; i++ )
342        if (strcmp(val, list[i]) == 0)
343            return ilist[i];
344
345    message_print(NIDL_INVOPTION, opt, val);
346    message_print(NIDL_LEGALVALS);
347
348    for ( ; *list != NULL ; list++ )
349        fprintf(stderr, " %s", *list);
350
351    fprintf(stderr, "\n");
352    exit(pgm_error);
353}
354
355/*
356**  d u m p _ c m d _ d a t a
357**
358**  Dump state of internal command vectors.
359*/
360
361#ifdef DUMPERS
362typedef enum {bit, string, string_list, int_list, number} opt_kind_t;
363typedef struct
364{
365    const char *opt_name;
366    opt_kind_t opt_kind;
367} opt_struct;
368
369/*
370 * Entries in this table must be consistent with definitions in command.h.
371 */
372static const opt_struct opt_info[NUM_OPTS] =
373{
374    { "caux",               string },
375    { "cc_cmd",             string },
376    { "cc_opt",             string },
377    { "cepv",               bit },
378    { "confirm",            bit },
379    { "cpp_cmd",            string },
380    { "cpp_def",            string_list },
381    { "cpp_opt",            string },
382    { "cpp_undef",          string_list },
383    { "cstub",              string },
384    { "def_idir",           bit },
385    { "do_bug",             int_list },
386    { "emit_cstub",         bit },
387    { "emit_sstub",         bit },
388    { "header",             string },
389    { "idir",               string_list },
390    { "keep_c",             bit },
391    { "keep_obj",           bit },
392    { "mepv",               bit },
393    { "out",                string },
394    { "saux",               string },
395    { "source",             string },
396    { "space_opt",          bit },
397    { "sstub",              string },
398    { "stdin",              bit },
399    { "syntax_only",        bit },
400    { "v",                  bit },
401    { "version",            bit },
402    { "warn",               bit },
403    { "standard",           number },
404    { "midl",               bit}
405#ifdef DUMPERS
406    ,
407    { "dump_acf",           bit },
408    { "dump_ast",           bit },
409    { "dump_ast_after",     bit },
410    { "dump_cmd",           bit },
411    { "dump_debug",         bit },
412    { "dump_flat",          bit },
413    { "dump_mnode",         bit },
414    { "dump_mool",          bit },
415    { "dump_nametbl",       bit },
416    { "dump_recs",          bit },
417    { "dump_sends",         bit },
418    { "dump_unode",         bit },
419    { "dump_uool",          bit },
420    { "dump_yy",            bit },
421    { "ool",                bit }
422#endif
423};
424
425static void dump_cmd_data(void)
426{
427    int     i;          /* Option index */
428    int     j;          /* Table index */
429    int     tbl_size;   /* Table size */
430    char    **pstr;     /* Ptr to string table entry */
431    int     *pint;      /* Ptr to integer table entry */
432
433    printf("\n");
434
435    for (i = 0 ; i < NUM_OPTS ; i++)
436    {
437        printf("%-20s", opt_info[i].opt_name);
438
439        if (cmd_opt[i])
440            printf("true    ");
441        else
442            printf("false   ");
443
444        switch (opt_info[i].opt_kind)
445        {
446        case bit:
447            printf("\n");
448            break;
449
450        case string:
451            if (cmd_val[i] != NULL)
452                printf(" %s\n", (char*)cmd_val[i]);
453            else
454                printf(" \n");
455            break;
456
457        case string_list:
458            pstr = (char **)cmd_val[i];
459            if (pstr != NULL)
460                while (*pstr != NULL)
461                    printf(" %s", *pstr++);
462            printf("\n");
463            break;
464
465        case int_list:
466            pint = (int *)cmd_val[i];
467            tbl_size = flags_option_count(option_table, opt_info[i].opt_name);
468            for (j = 0 ; j < tbl_size ; j++)
469                printf(" %d", *pint++);
470            printf("\n");
471            break;
472
473        case number:
474            pint = (int *)cmd_val[i];
475	    printf(" %d\n", *pint++);
476            break;
477
478        default:
479            printf("**Error**: Unsupported opt_kind in dump_cmd_data.\n");
480        }
481    }
482}
483#endif
484
485/*
486**  a l l o c _ a n d _ c o p y
487**
488**  Allocates memory for and copies a string to a return string.
489*/
490
491static char *alloc_and_copy     /* Returns address of new string */
492(
493    const char *orig_str           /* String to copy */
494)
495{
496    char    *new_str;           /* Local ptr to new string */
497
498    if (orig_str == NULL || orig_str[0] == '\0')
499        orig_str = UNSPECIFIED;     /* Empty string */
500
501    new_str = NEW_VEC (char, strlen(orig_str) + 1);
502
503    strlcpy(new_str, orig_str, strlen(orig_str) + 1);
504
505    return new_str;
506}
507
508/*
509** a d d _ d e f _ s t r i n g
510**
511** Adds specified string to the array of symbols defined for
512** preprocessor input.
513*/
514
515boolean add_def_string
516(
517    const char *def_string           /* [in] Additional #define string for preprocessor input */
518)
519{
520    char **defs = (char**) cmd_val[opt_cpp_def];
521    char *def;
522    int len, i = 0;
523
524    len = 1;       /* just to start the loop */
525    def = defs[i];
526
527    /* find the last def string */
528    while (i < MAX_DEF_STRINGS && (def != NULL && len > 0))
529    {
530	if (def != NULL)
531	{
532	    /* it makes no sense to define the same thing twice */
533	    if (!strcmp(def, def_string)) return true;
534	    len = strlen(def);
535	}
536	def = defs[++i];
537    }
538
539    /* add only if there's enough space */
540    if (i < MAX_DEF_STRINGS)
541    {
542        defs[i] = alloc_and_copy(def_string);
543	return true;
544    }
545
546    return false;
547}
548
549/*
550**  g e t _ s r c _ f i l e s p e c
551**
552**  Gets the source filespec from the command line, if any.  When it is
553**  ambiguous as to which parameter on the command line specifies the source
554**  IDL file, the rightmost parameter that can sensibly specify the source
555**  IDL file is chosen.
556**
557**  Returns:    TRUE if a source file was specified; FALSE otherwise
558*/
559
560static boolean get_src_filespec
561(
562    char    *src_filespec,       /* [out] Source filespec */
563	size_t	src_filespec_len
564)
565{
566    int     other_count;        /* Parameter cnt (excl. option cnt) */
567
568    other_count = flags_other_count();
569
570    /* Check for invalid extra arguments. */
571    if (other_count > 1)
572    {
573        int i;
574        CMD_explain_args();
575
576        message_print(NIDL_INVPARAMS);
577        for (i = 1; i < other_count ; i++)
578            fprintf(stderr, "  %s", flags_other(i));
579        fprintf(stderr, "\n");
580
581        return FALSE;
582    }
583
584    /*
585     * If one argument, it must be the source filespec if -stdin was not
586     * specified.  It -stdin was specified, it is an invalid extra argument.
587     */
588    if (other_count == 1)
589    {
590        if (cmd_opt[opt_stdin])
591        {
592            CMD_explain_args();
593            message_print(NIDL_INVPARAMS);
594            fprintf(stderr, "  %s\n", flags_other(0));
595            return FALSE;
596        }
597        else
598        {
599            strlcpy(src_filespec, flags_other(0), src_filespec_len);
600            return TRUE;
601        }
602    }
603
604    /* No arguments.  Fine if -stdin selected. */
605    if (cmd_opt[opt_stdin])
606    {
607        src_filespec[0] = '\0';
608        return TRUE;
609    }
610
611    /*
612     * We do not have an obvious source filespec on the command line as parsed.
613     * However, the command line format is ambiguous.  Any command option that
614     * takes an OPTIONAL string argument might have swallowed up what was
615     * really intended to be the source filespec.  The getflags function saves
616     * us the last such optional string that was parsed.  If we have one, that
617     * option becomes argument-less and what was parsed as its argument becomes
618     * the source filespec.
619     */
620    if (last_string == NULL || last_string[0] == '\0')
621    {
622        if (cmd_opt[opt_version])
623            exit(pgm_ok);
624
625        CMD_explain_args();
626
627        message_print(NIDL_SRCFILEREQ);
628#ifdef DUMPERS
629        if (cmd_opt[opt_dump_cmd])
630            dump_cmd_data();
631#endif
632        return FALSE;
633    }
634
635    strlcpy(src_filespec, last_string, src_filespec_len);
636    last_string[0] = '\0';
637    return TRUE;
638}
639
640/*
641**  C M D _ p a r s e _ a r g s
642**
643**  Parses command arguments.
644*/
645
646boolean CMD_parse_args          /* Returns TRUE on success */
647(
648    int         argc,           /* [in] Argument count */
649    char        **argv,         /* [in] Argument vector */
650    boolean     **p_cmd_opt,    /*[out] Ptr to array of cmd option arguments */
651    void        ***p_cmd_val,   /*[out] Ptr to array of cmd option values */
652    STRTAB_str_t *p_idl_sid     /*[out] Ptr to IDL filespec stringtable ID */
653                                /*      STRTAB_NULL_STR => stdin */
654)
655{
656    FILE_k_t out_dir_kind;              /* File kind of -out string */
657    int     i, j;
658    STRTAB_str_t src_file_str;          /* Source file stringtable ID */
659    char    src_filespec[PATH_MAX];     /* Source file specification */
660    char    src_filename[PATH_MAX];     /* Source file name portion */
661    char    l_cstub_file[PATH_MAX];     /* Work buf for full cstub filespec */
662    char    l_sstub_file[PATH_MAX];     /* Work buf for full sstub filespec */
663    char    l_header_file[PATH_MAX];    /* Work buf for full header filespec */
664    char    l_caux_file[PATH_MAX];      /* Work buf for full caux filespec */
665    char    l_saux_file[PATH_MAX];      /* Work buf for full saux filespec */
666    char    filespec[PATH_MAX];         /* Work buf for any filespec */
667
668    /*
669     * Set up default command line options.
670     */
671    cmd_opt[opt_do_bug]         = TRUE;
672    for (i = 0; i <= NUM_BUGS; i++)     /* 1-based index, thus extra elem */
673        support_bug[i] = FALSE;
674    /*
675     *  By default, -bug 4 is included in the code which causes
676     *  arrays of [ref] pointers contained in structures to not
677     *  be represented as a hole in NDR.
678     */
679    support_bug[bug_array_no_ref_hole] = TRUE;
680
681    cmd_opt[opt_caux]           = TRUE;
682    caux_file                   = "";
683
684    cmd_opt[opt_cc_cmd]         = TRUE;
685    cc_cmd                      = CC_DEF_CMD;
686
687    cmd_opt[opt_cc_opt]         = TRUE;
688#if defined(__alpha) && defined(__osf__)
689    cc_opt                      = "-std1";
690#else
691    cc_opt                      = "";
692#endif
693
694    cmd_opt[opt_cepv]           = FALSE;
695
696    cmd_opt[opt_emit_cstub]     = TRUE;
697    client                      = client_vals[client_all];
698
699    cmd_opt[opt_confirm]        = FALSE;
700
701    cpp_cmd                     = CPP;
702    cmd_opt[opt_cpp]            = TRUE;
703
704    CMD_def_cpp_cmd             = CPP;
705    cmd_opt[opt_cpp_opt]        = TRUE;
706    cpp_opt                     = "";
707
708    cmd_opt[opt_cstub]          = TRUE;
709    cstub_file                  = "";
710
711    cmd_opt[opt_header]         = TRUE;
712    header_file                 = "";
713
714    cmd_opt[opt_keep_c]         = FALSE;
715    cmd_opt[opt_keep_obj]       = TRUE;
716    keep                        = keep_vals[keep_object];
717
718    cmd_opt[opt_idir]           = TRUE;
719    cmd_opt[opt_def_idir]       = TRUE;
720
721    cmd_opt[opt_mepv]           = TRUE;
722    cmd_opt[opt_warn]           = TRUE;
723
724    cmd_opt[opt_out]            = FALSE;
725    out_dir                     = "";
726
727    cmd_opt[opt_saux]           = TRUE;
728    saux_file                   = "";
729
730    cmd_opt[opt_emit_sstub]     = TRUE;
731    server                      = server_vals[server_all];
732
733    cmd_opt[opt_source]         = TRUE;
734
735    cmd_opt[opt_space_opt]      = FALSE;
736
737    cmd_opt[opt_sstub]          = TRUE;
738    sstub_file                  = "";
739
740    cmd_opt[opt_stdin]          = FALSE;
741
742    cmd_opt[opt_syntax_check]   = FALSE;
743
744    cmd_opt[opt_verbose]        = FALSE;
745
746    cmd_opt[opt_version]        = FALSE;
747
748    standard_opt = opt_standard_dce_1_1;
749    cmd_val[opt_standard] = (void*)&standard_opt;
750
751    cmd_opt[opt_midl]           = FALSE;
752
753#ifdef DUMPERS
754    cmd_opt[opt_dump_acf]       = FALSE;
755    cmd_opt[opt_dump_ast]       = FALSE;
756    cmd_opt[opt_dump_ast_after] = FALSE;
757    cmd_opt[opt_dump_cmd]       = FALSE;
758    cmd_opt[opt_dump_debug]     = FALSE;
759    cmd_opt[opt_dump_flat]      = FALSE;
760    cmd_opt[opt_dump_mnode]     = FALSE;
761    cmd_opt[opt_dump_mool]      = FALSE;
762    cmd_opt[opt_dump_nametbl]   = FALSE;
763    cmd_opt[opt_dump_recs]      = FALSE;
764    cmd_opt[opt_dump_sends]     = FALSE;
765    cmd_opt[opt_dump_unode]     = FALSE;
766    cmd_opt[opt_dump_uool]      = FALSE;
767    cmd_opt[opt_dump_yy]        = FALSE;
768    cmd_opt[opt_ool]            = FALSE;
769#endif
770
771    /*
772     * Set up pointers to static storage and return parameters.
773     */
774    cmd_val[opt_cpp_def]    = (void *)def_strings;
775    cmd_val[opt_cpp_undef]  = (void *)undef_strings;
776    cmd_val[opt_do_bug]     = (void *)support_bug;
777    cmd_val[opt_idir]       = (void *)import_directories;
778    *p_cmd_opt = cmd_opt;
779    *p_cmd_val = cmd_val;
780
781    /*
782     * Check for no arguments.
783     */
784    if (argc == 0)
785    {
786        CMD_explain_args();
787        exit(pgm_error);
788    }
789
790    /*
791     * Parse command line options.
792     */
793    getflags(argc, argv, option_table);
794
795    if (cmd_opt[opt_version])
796    {
797        message_print(NIDL_VERSION, IDL_VERSION_TEXT);
798    }
799
800    /*
801     * Check -bug and -no_bug options.
802     */
803    for (i = flags_option_count(option_table, "bug") - 1; i >= 0; i--)
804        if ((do_bug[i] < 1) || (do_bug[i] > NUM_BUGS) ||
805            (do_bug[i] == bug_array_no_ref_hole))
806        {
807            message_print(NIDL_INVBUG, do_bug[i]);
808            exit(pgm_error);
809        }
810
811    for (i = flags_option_count(option_table, "no_bug") - 1; i >= 0; i--)
812        if ((do_not_do_bug[i] < 1) || (do_not_do_bug[i] > NUM_BUGS) ||
813            (do_not_do_bug[i] == bug_array_no_ref_hole))
814        {
815            message_print(NIDL_INVNOBUG, do_not_do_bug[i]);
816            exit(pgm_error);
817        }
818
819    for (i = flags_option_count(option_table, "bug") - 1; i >= 0; i--)
820        for (j = flags_option_count(option_table, "no_bug") - 1; j >= 0; j--)
821            if (do_bug[i] == do_not_do_bug[j])
822            {
823                message_print(NIDL_BUGNOBUG, do_bug[i], do_bug[i]);
824                exit(pgm_error);
825            }
826
827    for (i = flags_option_count(option_table, "bug") - 1; i >= 0; i--)
828    {
829        cmd_opt[opt_do_bug] = TRUE;
830        support_bug[do_bug[i]] = TRUE;
831    }
832
833    for (i = flags_option_count(option_table, "no_bug") - 1; i >= 0; i--)
834        support_bug[do_not_do_bug[i]] = FALSE;
835
836    /*
837     * Check the -client option.
838     */
839    i = check_str_list("client", client, client_vals);
840    switch (i)
841    {
842    case client_none:
843        cmd_opt[opt_emit_cstub] = FALSE;
844        cmd_opt[opt_caux]       = FALSE;
845        break;
846
847    case client_stub:
848        cmd_opt[opt_emit_cstub] = TRUE;
849        cmd_opt[opt_caux]       = FALSE;
850        break;
851
852    case client_aux:
853        cmd_opt[opt_emit_cstub] = FALSE;
854        cmd_opt[opt_caux]       = TRUE;
855        break;
856
857    case client_all:
858    default:
859        cmd_opt[opt_emit_cstub] = TRUE;
860        cmd_opt[opt_caux]       = TRUE;
861    }
862
863    /*
864     * Check the -dump options.
865     */
866#ifdef DUMPERS
867    for (j = 0; dump_strings[j] != NULL; j++)
868    {
869        i = check_str_list("dump", dump_strings[j], dump_vals);
870        switch (i)
871        {
872        case dump_acf:
873            cmd_opt[opt_dump_acf] = TRUE;
874            break;
875
876        case dump_ast:
877            cmd_opt[opt_dump_ast] = TRUE;
878            break;
879
880        case dump_ast_after:
881            cmd_opt[opt_dump_ast_after] = TRUE;
882            break;
883
884        case dump_cmd:
885            cmd_opt[opt_dump_cmd] = TRUE;
886            break;
887
888        case dump_debug:
889            cmd_opt[opt_dump_debug] = TRUE;
890            break;
891
892        case dump_flat:
893            cmd_opt[opt_dump_flat] = TRUE;
894            break;
895
896        case dump_mnode:
897            cmd_opt[opt_dump_mnode] = TRUE;
898            break;
899
900        case dump_mool:
901            cmd_opt[opt_dump_mool] = TRUE;
902            break;
903
904        case dump_nametbl:
905            cmd_opt[opt_dump_nametbl] = TRUE;
906            break;
907
908        case dump_recs:
909            cmd_opt[opt_dump_recs] = TRUE;
910            break;
911
912        case dump_sends:
913            cmd_opt[opt_dump_sends] = TRUE;
914            break;
915
916        case dump_unode:
917            cmd_opt[opt_dump_unode] = TRUE;
918            break;
919
920        case dump_uool:
921            cmd_opt[opt_dump_uool] = TRUE;
922            break;
923
924        case dump_yy:
925            {
926            extern int nidl_yydebug;
927            extern int acf_yydebug;
928            cmd_opt[opt_dump_yy] = TRUE;
929            nidl_yydebug = acf_yydebug = (int)TRUE;
930            break;
931            }
932        }
933    }
934#endif
935    standard_opt = check_str_int_list("standard", standard,
936                                      standard_vals, standard_ivals);
937    if (standard_opt == -1) standard_opt = opt_standard_dce_1_1;
938
939    /*
940     * Process the -I options for import directories.
941     */
942    if (cmd_opt[opt_def_idir])
943    {
944        for (i = 0; import_directories[i] != NULL
945                    && import_directories[i][0] != '\0' ; i++)
946            ;
947        import_directories[i+2] = NULL;
948
949#ifdef NIDL_LIBRARY_EV
950        nidl_library = getenv(NIDL_LIBRARY_EV);
951#endif
952        if (nidl_library == NULL)
953            nidl_library = DEFAULT_IDIR;
954        import_directories[i+1] = nidl_library;
955
956        for ( ; i > 0; i--)
957            import_directories[i] = import_directories[i-1];
958        import_directories[0] = CD_IDIR;
959        flags_incr_count(option_table, "I", 2);
960    }
961
962    if (!cmd_opt[opt_def_idir] &&
963        (import_directories[0] == NULL || import_directories[0][0] == '\0'))
964    {
965        import_directories[0] = CD_IDIR;
966        flags_incr_count(option_table, "I", 1);
967    }
968
969    /*
970     * Check the -keep option.
971     */
972    i = check_str_list("keep", keep, keep_vals);
973    switch (i)
974    {
975    case keep_none:
976        cmd_opt[opt_keep_c]     = FALSE;
977        cmd_opt[opt_keep_obj]   = FALSE;
978        break;
979
980    case keep_c_source:
981        cmd_opt[opt_keep_c]     = TRUE;
982        cmd_opt[opt_keep_obj]   = FALSE;
983        break;
984
985    case keep_object:
986    default:
987        cmd_opt[opt_keep_c]     = FALSE;
988        cmd_opt[opt_keep_obj]   = TRUE;
989        break;
990
991    case keep_both:
992    case keep_all:
993        cmd_opt[opt_keep_c]     = TRUE;
994        cmd_opt[opt_keep_obj]   = TRUE;
995        break;
996    }
997
998    /*
999     * Check for -out specification of output directory.
1000     */
1001    if (out_dir[0] != '\0')
1002        cmd_opt[opt_out] = TRUE;
1003
1004    /*
1005     * Make sure we have a source filespec before we use it to construct
1006     * other names.
1007     */
1008    if (!get_src_filespec(src_filespec, sizeof (src_filespec)))
1009        exit(pgm_error);
1010
1011    if (src_filespec[0] == '\0')    /* -stdin */
1012    {
1013        src_file_str = STRTAB_NULL_STR;
1014        src_filename[0] = 'a';      /* output filenames a.h, a_cstub.c, etc. */
1015        src_filename[1] = '\0';
1016    }
1017    else                            /* file */
1018    {
1019        if (!FILE_parse(src_filespec, (char *)NULL, 0, src_filename, sizeof (src_filename), (char *)NULL, 0))
1020        {
1021            /* Not a valid filespec so probably a bogus option. */
1022            error(NIDL_UNKFLAG, src_filespec);
1023            return FALSE;
1024        }
1025
1026        src_file_str = STRTAB_add_string(src_filespec);
1027    }
1028
1029    /*
1030     * Check the -server option.
1031     */
1032    i = check_str_list("server", server, server_vals);
1033    switch (i)
1034    {
1035    case server_none:
1036        cmd_opt[opt_emit_sstub] = FALSE;
1037        cmd_opt[opt_saux]       = FALSE;
1038        break;
1039
1040    case server_stub:
1041        cmd_opt[opt_emit_sstub] = TRUE;
1042        cmd_opt[opt_saux]       = FALSE;
1043        break;
1044
1045    case server_aux:
1046        cmd_opt[opt_emit_sstub] = FALSE;
1047        cmd_opt[opt_saux]       = TRUE;
1048        break;
1049
1050    case server_all:
1051    default:
1052        cmd_opt[opt_emit_sstub] = TRUE;
1053        cmd_opt[opt_saux]       = TRUE;
1054    }
1055
1056    /* If -syntax_only specified, disable all output file processing. */
1057    if (cmd_opt[opt_syntax_check])
1058    {
1059        cmd_opt[opt_out]    = FALSE;
1060        cmd_opt[opt_cstub]  = FALSE;
1061        cmd_opt[opt_sstub]  = FALSE;
1062        cmd_opt[opt_header] = FALSE;
1063        cmd_opt[opt_caux]   = FALSE;
1064        cmd_opt[opt_saux]   = FALSE;
1065    }
1066
1067    /*
1068     * If the -out option was selected, verify that the output-directory string
1069     * is a valid directory spec before prepending to any output filenames.
1070     */
1071    if (cmd_opt[opt_out])
1072    {
1073        if (!FILE_kind(out_dir, &out_dir_kind))
1074            error(NIDL_FILENOTFND, out_dir);
1075
1076        if (out_dir_kind != file_dir)
1077            error(NIDL_FILENOTDIR, out_dir);
1078    }
1079
1080    /*
1081     * Process -cstub option.
1082     */
1083    if (cmd_opt[opt_cstub])
1084    {
1085        sprintf(filespec, "%s%s", src_filename, cstub_suffix);
1086        if (!FILE_form_filespec(cstub_file, out_dir, (char *)NULL, filespec,
1087                                l_cstub_file, sizeof(l_cstub_file)))
1088        {
1089            message_print(NIDL_INVFILESPEC, cstub_file);
1090            return FALSE;
1091        }
1092        cstub_file = l_cstub_file;      /* Point at local buffer */
1093    }
1094
1095    /*
1096     * Process -sstub option.
1097     */
1098    if (cmd_opt[opt_sstub])
1099    {
1100        sprintf(filespec, "%s%s", src_filename, sstub_suffix);
1101        if (!FILE_form_filespec(sstub_file, out_dir, (char *)NULL, filespec,
1102                                l_sstub_file, sizeof(l_sstub_file)))
1103        {
1104            message_print(NIDL_INVFILESPEC, sstub_file);
1105            return FALSE;
1106        }
1107        sstub_file = l_sstub_file;      /* Point at local buffer */
1108    }
1109
1110    /*
1111     * Process -header option.
1112     */
1113    sprintf(filespec, "%s%s", src_filename, header_suffix);     /* =tbl */
1114    if (!FILE_form_filespec(header_file, out_dir, (char *)NULL, /* =tbl */
1115                            filespec, l_header_file, sizeof(l_header_file)))           /* =tbl */
1116    {
1117        message_print(NIDL_INVFILESPEC, header_file);
1118        return FALSE;
1119    }
1120    header_file = l_header_file;    /* Point at local buffer */
1121
1122    /*
1123     * Process -caux option.
1124     */
1125    if (cmd_opt[opt_caux])
1126    {
1127        sprintf(filespec, "%s%s", src_filename, caux_suffix);
1128        if (!FILE_form_filespec(caux_file, out_dir, (char *)NULL, filespec,
1129                                l_caux_file, sizeof(l_caux_file)))
1130        {
1131            message_print(NIDL_INVFILESPEC, caux_file);
1132            return FALSE;
1133        }
1134        caux_file = l_caux_file;        /* Point at local buffer */
1135    }
1136
1137    /*
1138     * Process -saux option.
1139     */
1140    if (cmd_opt[opt_saux])
1141    {
1142        sprintf(filespec, "%s%s", src_filename, saux_suffix);
1143        if (!FILE_form_filespec(saux_file, out_dir, (char *)NULL, filespec,
1144                                l_saux_file, sizeof(l_saux_file)))
1145        {
1146            message_print(NIDL_INVFILESPEC, saux_file);
1147            return FALSE;
1148        }
1149        saux_file = l_saux_file;        /* Point at local buffer */
1150    }
1151
1152    /*
1153     * All options are now loaded with default values if necessary.
1154     * Setup the cmd_val table to point to the parsed values.
1155     * Memory management assumptions: It is assumed that pointers to
1156     * unmodified command options reference memory that is valid for the
1157     * entire program.  Any modified command options, however, reference
1158     * local storage.  We must allocate permanent memory for those, via
1159     * the alloc_and_copy function.
1160     */
1161    cmd_val[opt_caux]       = (void *)alloc_and_copy(caux_file);
1162    cmd_val[opt_cc_cmd]     = (void *)cc_cmd;
1163    cmd_val[opt_cc_opt]     = (void *)cc_opt;
1164    cmd_val[opt_cpp]        = (void *)cpp_cmd;
1165    cmd_val[opt_cpp_opt]    = (void *)cpp_opt;
1166    cmd_val[opt_cstub]      = (void *)alloc_and_copy(cstub_file);
1167    cmd_val[opt_header]     = (void *)alloc_and_copy(header_file);
1168    cmd_val[opt_out]        = (void *)out_dir;
1169    cmd_val[opt_saux]       = (void *)alloc_and_copy(saux_file);
1170    cmd_val[opt_source]     = (void *)src_filespec;
1171    cmd_val[opt_sstub]      = (void *)alloc_and_copy(sstub_file);
1172
1173#ifdef DUMPERS
1174    if (cmd_opt[opt_dump_cmd])
1175        dump_cmd_data();
1176#endif
1177
1178    /*
1179     * Print list of options if requested.
1180     */
1181    if (cmd_opt[opt_confirm])
1182    {
1183        printflags(option_table);
1184        if (!cmd_opt[opt_verbose])
1185            exit(pgm_ok);
1186    }
1187
1188    ERR_no_warnings = !cmd_opt[opt_warn];
1189
1190    *p_idl_sid = src_file_str;
1191    return(TRUE);
1192}
1193