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**      FRONTEND.C
82**
83**  FACILITY:
84**
85**      Interface Definition Language (IDL) Compiler
86**
87**  ABSTRACT:
88**
89**      Mainline for IDL compilers.
90**
91**  VERSION: DCE 1.0
92**
93*/
94
95#include <signal.h>
96
97#ifdef vms
98#  include <types.h>
99#  include <stat.h>
100#  include <stsdef.h>
101#  include <descrip.h>
102#else
103#  include <sys/types.h>
104#  include <sys/stat.h>
105#  include <fcntl.h>
106#  include <stdio.h>
107#endif
108
109#include <frontend.h>
110#include <astp.h>
111#include <astp_dmp.h>
112#include <checker.h>
113#include <command.h>
114#include <errors.h>
115#include <files.h>
116#include <getflags.h>
117#include <propagat.h>
118#include <message.h>
119
120#define CONFIG_SUFFIX ".acf"
121
122/*
123 * Macro to "close" a pipe - don't actually call pclose since it can cause hangs
124 * in certain instances where a parent process opens and closes several pipes,
125 * apparently due to the underlying wait() call from pclose and the unpredict-
126 * ability of the order of child exits.
127 */
128#include <errno.h>
129#define PCLOSE(stream) \
130{ \
131    char buf[256]; \
132    /* Silently read to eof - extra lines should cause COMPABORT msg anyway */ \
133    while (fgets(buf, sizeof(buf), stream) != NULL) ; \
134}
135
136/* Globals */
137
138/* Local data definitions. */
139
140static boolean      *saved_cmd_opt;     /* Array of command option flags */
141static void         **saved_cmd_val;    /* Array of command option values */
142
143typedef struct FE_import_file_n_t {
144        struct FE_import_file_n_t * next;
145    STRTAB_str_t   imported_fn_id;
146    STRTAB_str_t   imported_full_fn_id;
147} FE_import_file_n_t;
148
149static FE_import_file_n_t * imported_file_list = NULL;
150
151extern boolean ASTP_parsing_main_idl;
152
153/*
154 * All the error reporting requires a parser location to access line
155 * numbers, etc. However, the APIs are structured such that they may
156 * invoke parser errors even when we are not in the middle of a parse.
157 * In that case, what's the correct line number? Who knows? Let's make
158 * a dummy location and hope we don't get any errors at the wrong time.
159 *	    -- jpeach
160 */
161
162const parser_location_t empty_parser_location;
163
164/*
165**  i n i t
166**
167**  Frontend-specific initialization.
168*/
169
170static void FE_init(void)
171{
172    saved_cmd_opt = NULL;
173    saved_cmd_val = NULL;
174
175    KEYWORDS_init();
176    NAMETABLE_init();
177    AST_init(null_parser_location);
178}
179
180/*
181**  c p p
182**
183**  Sends the source file through CPP before giving it to lex.
184**  The cpp_output argument is a file ID for the output from cpp.
185**      UNIX only:      cpp_output is connected to piped output from cpp.
186*/
187
188#if defined(CPP)
189static void cpp
190(
191    char        *cpp_cmd,       /* [in] Base command to invoke cpp */
192    char        *cpp_opt,       /* [in] Addtl command options for cpp */
193    char        *file_name,     /* [in] Source full filespec; "" => stdin */
194    char        *dst_file_name ATTRIBUTE_UNUSED, /* [in] Target filespec (VMS) */
195    char        **def_strings,  /* [in] List of #define's for preprocessor */
196    char        **undef_strings,/* [in] List of #undefine's for preprocessor */
197    char        **idir_list,    /* [in] List of -I directories */
198    FILE        **cpp_output    /*[out] File ID of cpp output */
199)
200
201{
202    char        cmd[max_string_len];    /* Command to spawn cpp */
203
204    cmd[0] = '\0';
205
206    assert(cpp_cmd && *cpp_cmd);
207
208    /* Put together beginning of command. */
209
210    strlcpy(cmd, cpp_cmd, sizeof(cmd));
211    strlcat(cmd, " ", sizeof(cmd));
212    strlcat(cmd, cpp_opt ? cpp_opt : "", sizeof(cmd));
213    strlcat(cmd, " ", sizeof(cmd));
214    strlcat(cmd, file_name ? file_name : "" , sizeof(cmd));
215
216    /* Append the -D strings. */
217
218    while (*def_strings)
219    {
220        strlcat(cmd, " -D", sizeof(cmd));
221        strlcat(cmd, *def_strings++, sizeof(cmd));
222    }
223
224    /* Append the -U strings. */
225    while (*undef_strings)
226    {
227        strlcat(cmd, " -U", sizeof(cmd));
228        strlcat(cmd, *undef_strings++, sizeof(cmd));
229    }
230
231    /* If cpp_cmd is the default, append the -I directories. */
232
233    if (strcmp(cpp_cmd, CMD_def_cpp_cmd) == 0)
234    {
235        while (*idir_list)
236        {
237            strlcat(cmd, " -I", sizeof(cmd));
238            strlcat(cmd, *idir_list++, sizeof(cmd));
239        }
240    }
241
242    /* Now execute the cpp command and open output file or pipe. */
243
244    if (saved_cmd_opt[opt_verbose])
245        message_print(NIDL_RUNCPP,cmd);
246
247#if 0
248    printf("CPP - %s\n", cmd);
249#endif
250
251    if ((*cpp_output = popen(cmd, "r")) == 0)
252        error(NIDL_INVOKECPP);
253}
254#endif
255
256/*
257**  p a r s e _ a c f
258**
259**  Invokes the ACF (Attribute Configuration File) parser on specified file.
260**
261**  Note:   If cmd_opt[opt_confirm], then no real work is done except to
262**          issue messages for the verbose option.
263**
264**  Returns:    == 0    => success
265**              != 0    => failure
266*/
267
268static boolean parse_acf        /* Returns true on success */
269(
270    boolean     *cmd_opt,       /* [in] Array of command option flags */
271    void        **cmd_val,      /* [in] Array of command option values */
272    char        *acf_file       /* [in] ACF full file name */
273)
274
275{
276    FILE *  acf_yyin = NULL;
277    char    temp_path_name[max_string_len]; /* Full temp file pathname */
278    void *  acf_parser;
279
280    if (cmd_opt[opt_verbose])
281        message_print(NIDL_PROCESSACF, acf_file);
282    if (cmd_opt[opt_confirm])
283        return true;
284
285    /*
286     * lex & yacc intializations
287     */
288
289    acf_parser = acf_parser_alloc(cmd_opt, cmd_val, acf_file);
290
291#if defined(CPP)
292    if (cmd_opt[opt_cpp])
293    {
294        temp_path_name[0] = '\0';
295
296        cpp((char *)cmd_val[opt_cpp],
297            (char *)cmd_val[opt_cpp_opt],
298            acf_file,
299            temp_path_name,
300            (char **)cmd_val[opt_cpp_def],
301            (char **)cmd_val[opt_cpp_undef],
302            (char **)cmd_val[opt_idir],
303            &acf_yyin);
304    }
305    else
306#endif
307        /* No cpp, just open source file */
308        FILE_open(acf_file, &acf_yyin);
309
310    acf_parser_input(acf_parser, acf_yyin);
311    if (acf_yyparse(acf_parser) != 0 && acf_errcount(acf_parser) == 0)
312    {
313        log_error(acf_yylineno(acf_parser), NIDL_COMPABORT, NULL);
314    }
315
316#if defined(CPP)
317    if (cmd_opt[opt_cpp])
318        PCLOSE(acf_yyin)
319    else
320#endif
321        fclose(acf_yyin);
322
323    if (acf_errcount(acf_parser) != 0)
324    {
325	acf_parser_destroy(acf_parser);
326        return false;
327    }
328
329    acf_parser_destroy(acf_parser);
330    return true;
331}
332
333/*
334** a l r e a d y _ i m p o r t e d
335**
336** Checks whether a file is already included in the parse or not.
337**
338** Returns TRUE if the import file has already been parsed.
339** Returns false otherwise  (Including can't find the file.)
340**
341*/
342
343static boolean already_imported
344(
345    STRTAB_str_t import_path_id      /* The name to check */
346)
347
348{
349    char                 new_import_full_fn[max_string_len];
350    STRTAB_str_t         new_import_full_fn_id;
351    STRTAB_str_t         new_import_fn_id;
352    char                 base_file_name[max_string_len];
353    char                 base_file_ext[max_string_len];
354    struct               stat stat_buf;
355    FE_import_file_n_t * imported_file;
356    char const * *       idir_list;
357    boolean              alr_imp;
358    char const        * file_name;
359
360    /*
361     * Get a string to lookup.
362     */
363    STRTAB_str_to_string (import_path_id, &file_name);
364    idir_list = (char const * *)saved_cmd_val[opt_idir];
365
366    /*
367     * Note that a lookup failure will not report a failure here;
368     * That will be reported when we actually try to import it.
369     */
370    if (!FILE_lookup(file_name, idir_list, &stat_buf, new_import_full_fn, sizeof (new_import_full_fn)))
371        return false;
372    new_import_full_fn_id = STRTAB_add_string(new_import_full_fn);
373
374    /*
375     * Make sure there is no partial path information.
376     */
377    if (!FILE_parse(new_import_full_fn, NULL, 0, base_file_name, sizeof(base_file_name), base_file_ext, sizeof(base_file_ext)))
378        return false;
379
380    strncat(base_file_name, base_file_ext, max_string_len);
381    new_import_fn_id = STRTAB_add_string(base_file_name);
382
383    /*
384     * Initialize the default return status.
385     */
386    alr_imp = false;
387
388    imported_file = imported_file_list;
389
390    while ((imported_file != NULL) && (!alr_imp))
391    {
392        if (new_import_fn_id == imported_file->imported_fn_id)
393        {
394            /*
395             * A match is found in the list. We are done.
396             */
397            alr_imp = true;
398        }
399        imported_file = imported_file -> next;
400    }
401
402    /*
403     * Record the import we are about to do if not imported already.
404     */
405    if (!alr_imp)
406    {
407        imported_file = NEW (FE_import_file_n_t);
408        imported_file -> imported_fn_id = new_import_fn_id;
409        imported_file -> imported_full_fn_id = new_import_full_fn_id;
410        imported_file -> next = imported_file_list;
411        imported_file_list = imported_file;
412    }
413
414    return alr_imp;
415}
416
417/*
418**  p a r s e
419**
420**  Invokes the parser on the specified IDL file.  If the IDL file is
421**  successfully parsed, and there is a related ACF file, then the ACF
422**  file is parsed also.
423**
424**  Returns:    a pointer to the interface binding if the IDL file was parsed
425**              successfully and the ACF file (if any) was parsed successfully;
426**              NULL otherwise.
427*/
428
429static boolean parse
430(
431    boolean     *cmd_opt,       /* [in] Array of command option flags */
432    void        **cmd_val,      /* [in] Array of command option values */
433    STRTAB_str_t idl_sid,       /* [in] IDL filespec stringtable ID */
434                                /*      STRTAB_NULL_STR => stdin */
435    boolean     idir_valid,     /* [in] true => use import directory list */
436    AST_interface_n_t **int_p   /*[out] Ptr to interface node */
437)
438{
439    FILE *nidl_yyin = NULL;
440
441    char const  *sf;                            /* Source filespec */
442    char        full_path_name[max_string_len]; /* Full source pathname */
443    char        temp_path_name[max_string_len]; /* Full temp file pathname */
444    STRTAB_str_t full_pn_id;                    /* Full src path string id */
445    char const * *idir_list;                    /* List of search directories */
446    char        file_dir[max_string_len];       /* Directory part of src file */
447    boolean     file_dir_is_cwd;                /* T => file_dir current dir */
448    char        file_name[max_string_len];      /* File name part of src file */
449    char        acf_file[max_string_len];       /* ACF file name w/o dir */
450    char        full_acf_name[max_string_len];  /* Full ACF pathname */
451    boolean     acf_exists;                     /* T => ACF file exists */
452    struct stat stat_buf;                       /* File lookup stats */
453    int         i=0;
454
455    void *	nidl_parser;
456
457    /* One-time saving of command array addresses to static storage. */
458    if (saved_cmd_opt == NULL)
459        saved_cmd_opt = cmd_opt;
460    if (saved_cmd_val == NULL)
461        saved_cmd_val = cmd_val;
462
463    /*
464     * If the idir_valid flag is set, look in the -I directories for the
465     * source file.  Otherwise, just use the filespec as is.
466     */
467    if (idir_valid)
468        idir_list = (char const * *)cmd_val[opt_idir];
469    else
470        idir_list = NULL;
471
472    if (idl_sid == STRTAB_NULL_STR)     /* stdin */
473        full_path_name[0] = '\0';
474    else
475    {
476        STRTAB_str_to_string(idl_sid, &sf);
477        if  (!FILE_lookup(sf, idir_list, &stat_buf, full_path_name, sizeof (full_path_name)))
478        {
479            error(NIDL_FILENOTFND, sf);
480            return false;
481        }
482    }
483
484    if (cmd_opt[opt_verbose] && !ASTP_parsing_main_idl)
485        message_print(NIDL_IMPORTIDL, full_path_name);
486
487#if defined(CPP)
488    if (cmd_opt[opt_cpp])
489    {
490        temp_path_name[0] = '\0';
491
492	/* define the macro describing dceidl compiler (for conditional
493	   constructions) */
494	if (!add_def_string(DCEIDL_DEF))
495        {
496            message_print(NIDL_INTERNAL_ERROR, "Warning: Couldn't define macro %s!\n", DCEIDL_DEF);
497        }
498
499        cpp((char *)cmd_val[opt_cpp],
500            (char *)cmd_val[opt_cpp_opt],
501            full_path_name,
502            temp_path_name,
503            (char **)cmd_val[opt_cpp_def],
504            (char **)cmd_val[opt_cpp_undef],
505            (char **)cmd_val[opt_idir],
506            &nidl_yyin);
507    }
508    else
509#endif
510        if (full_path_name[0] == '\0')  /* stdin */
511            nidl_yyin = stdin;
512        else
513            FILE_open(full_path_name, &nidl_yyin);
514
515    /*
516     * Setup file name for errors to the full file name
517     */
518    set_name_for_errors((full_path_name[0] == '\0') ? "stdin" : full_path_name);
519
520    nidl_parser = nidl_parser_alloc(cmd_opt, cmd_val, full_path_name);
521    nidl_parser_input(nidl_parser, nidl_yyin);
522
523#if YYDEBUG && 0
524	 {
525		  extern int nidl_yydebug;
526		  nidl_yydebug = 1;
527	 }
528#endif
529
530    if (nidl_yyparse(nidl_parser) != 0 && error_count == 0)
531        log_error(nidl_yylineno(nidl_parser), NIDL_COMPABORT, NULL);
532    *int_p = the_interface;
533
534    nidl_parser_destroy(nidl_parser);
535
536#if defined(CPP)
537    if (cmd_opt[opt_cpp])
538        PCLOSE(nidl_yyin)
539    else
540#endif
541        fclose(nidl_yyin);
542
543    if (error_count != 0)
544        return false;        /* Error parsing IDL */
545
546    /* Successful parse: save IDL filespec in interface node. */
547    if (the_interface != NULL)
548    {
549        full_pn_id = STRTAB_add_string(full_path_name);
550        the_interface->fe_info->file = full_pn_id;
551    }
552    else
553    {
554        if (ASTP_parsing_main_idl) return false;    /* Shouldn't happen */
555    }
556
557    /*
558     * Now see if there is an associated Attribute Configuration File (ACF).
559     * The ACF name is constructed from the IDL file name.  The ACF file can
560     * be in any of the -I directories.
561     */
562    if (!FILE_parse(full_path_name, file_dir, sizeof(file_dir), file_name, sizeof(file_name), (char *)NULL, 0))
563        return false;
564
565    if (!FILE_form_filespec(file_name, (char *)NULL, CONFIG_SUFFIX,
566                            (char *)NULL, acf_file, sizeof(acf_file)))
567        return false;
568#ifdef UNIX
569    /*
570     * If the created ACF filespec matches the file_name portion of the IDL
571     * filespec, it implies that the IDL filespec contains multiple '.'s - in
572     * this special case, append the ACF suffix to the filespec.
573     */
574    if (strcmp(file_name, acf_file) == 0)
575        strlcat(acf_file, CONFIG_SUFFIX, sizeof(acf_file));
576#endif
577
578    /*
579     * If the directory part of the source filespec is not the current dir,
580     * tack it on at the end of the include directory list.  Note: we assume
581     * that there is enough room for a temporary extra entry in the idir list.
582     */
583    idir_list = (char const **)cmd_val[opt_idir];
584    file_dir_is_cwd = FILE_is_cwd(file_dir);
585
586    if (!file_dir_is_cwd)
587    {
588        for (i = 0 ; idir_list[i] != NULL ; i++)
589            ;
590        idir_list[i] = file_dir;
591        idir_list[i+1] = NULL;
592    }
593
594    acf_exists = FILE_lookup(acf_file, idir_list, &stat_buf, full_acf_name, sizeof (full_acf_name));
595
596    if (!file_dir_is_cwd)
597        idir_list[i] = NULL;
598
599    if (!acf_exists)
600        return true;   /* No ACF; return success */
601
602    /* Parse the ACF. */
603    if (!parse_acf(cmd_opt, cmd_val, full_acf_name))
604        return false;            /* Error parsing ACF */
605
606    return true;       /* Both IDL and ACF parsed without errors */
607}
608
609/*
610 *  F E _ p a r s e _ i m p o r t
611 *
612 *  Parse an import file.
613 *  This involves pushing the state of the current parse, initing a few
614 *  cells, calling parse, and restoring the state of the current parse.
615 *
616 *  Parametric inputs: The string table id of the filename we wish to parse.
617 *  Global inputs: All the parse and lex static storage that maintains parse
618 *                 state.
619 *  Parametric outputs: None
620 *  Global outputs: The parse state is restored to its value on entry.
621 *
622 *  Routine value:  None.
623 */
624
625AST_interface_n_t *FE_parse_import
626(
627    STRTAB_str_t    new_input   /* [in] string table id of file to parse */
628)
629{
630
631	 /*
632	  * BISON/FLEX nester parser support
633	  *
634	  * FE_parse_import() is called by the import_file rule in
635	  * nidl.y. We can be called recursively, for each file requested
636	  * to be included. To support this with non-reentrant Flex
637	  * and Bison parsers, we save the current Flex/Bison state,
638	  * create a new, initialized state for the ACF & NIDL x Flex & BISON
639	  * state machines, and parse the import. When we are done,
640	  * we delete the temporary parsers states used to do the import,
641	  * and restore the parser state variables back to where they were.
642	  *
643	  * The support logic to do context switching of parser state machines
644	  * can be found at the end of nidl.l, nidl.y, acf.l, acf.y
645	  *
646	  * For any given import, we have to save and reset FOUR different
647	  * state machines:
648	  *
649	  *    ACF parser, ACF flexxer, NIDL parser, NIDL lexxer
650	  *
651	  */
652
653	 boolean saved_ASTP_parsing_main_idl;
654	 char saved_current_file[ PATH_MAX ];
655	 AST_interface_n_t *int_p;
656
657	 unsigned * saved_yylineno_p = yylineno_p;
658	 FILE * saved_yyin_p = yyin_p;
659
660	 /* Saved interface attributes */
661	 AST_interface_n_t *saved_interface;
662#if 0
663    int saved_op_count;
664#endif
665
666	 /*
667	  * Return now, if the file is already imported.
668	  */
669	 if (already_imported (new_input))
670		  return (AST_interface_n_t *)NULL;
671
672	 /* save the AST state */
673
674	 saved_ASTP_parsing_main_idl = ASTP_parsing_main_idl;
675	 inq_name_for_errors(saved_current_file, sizeof (saved_current_file));
676
677	 /*
678	  * Save interface information
679	  */
680
681	 saved_interface = the_interface;
682#if 0
683    saved_op_count = the_interface ? the_interface->op_count : 0;
684#endif
685
686	 /*
687	  * Initialize interface attributes
688	  */
689
690	 the_interface = NULL;
691
692	 /*
693	  * We have now saved away all the state of the current parse.
694	  * Initialize a few cells, open the imported file and recursively invoke the
695	  * parse.
696	  */
697
698	 if (saved_interface)
699		  ASTP_parsing_main_idl = false;
700
701	 /*
702	  * Create new, empty and initialized parser context to
703	  * do the import.
704	  */
705
706	 /* Now we can parse the import file....
707	  * Parse the file.  Routine parse normally returns a AST_interface_n_t,
708	  * but since we are not parsing the main IDL, we don't care about it.
709	  * The "true" argument says to search -I directories for the file.
710	  */
711
712	 parse(saved_cmd_opt, saved_cmd_val, new_input, true, &int_p);
713
714#if 0
715	 if (saved_interface && saved_interface->inherited_interface_name == the_interface->name)	{
716		  AST_export_n_t * ep = the_interface->exports;
717		  AST_export_n_t * op;
718
719		  if (AST_OBJECT_SET(the_interface))	{
720				/* ORPC inheritance by pulling in the base class interface's
721				 * operations */
722				saved_interface->op_count = the_interface->op_count;
723
724				for (; ep != NULL; ep = ep->next)	{
725					 if (ep->kind != AST_operation_k)
726						  continue;
727					 op = AST_export_node((ASTP_node_t*)ep->thing_p.exported_operation,
728								AST_operation_k);
729					 /* Assign the operation number to this operation relative to any
730					  * inherited operations */
731					 op->thing_p.exported_operation->op_number = saved_op_count++;
732					 saved_interface->exports = (AST_export_n_t*)AST_concat_element(
733								(ASTP_node_t*)saved_interface->exports,
734								(ASTP_node_t*)op
735								);
736				}
737				/* update the operation count to include base class operations */
738				saved_interface->op_count = saved_op_count;
739		  }
740	 }
741#endif
742
743	 /*
744	  * Restore interface information
745	  */
746	 the_interface = saved_interface;
747
748	 /*
749	  * The recursive parse is done (at this level).
750	  * Restore the state machines to the previous values before the import...
751	  */
752
753	 /*
754	  * Restore information used by error reporting routines.
755	  */
756	 ASTP_parsing_main_idl = saved_ASTP_parsing_main_idl;
757	 set_name_for_errors(saved_current_file);
758
759	 yylineno_p = saved_yylineno_p ;
760	 yyin_p = saved_yyin_p;
761
762	 return int_p;
763}
764/*
765**  p a r s e _ i d l
766**
767**  Parse the source IDL file.
768**
769**  Side Effects:   Returns the interface in the int_p parameters and
770**      a boolean status if any errors were encountered.
771*/
772
773static boolean parse_idl        /* Returns true on success */
774(
775    boolean     *cmd_opt,       /* [in] Array of command option flags */
776    void        **cmd_val,      /* [in] Array of command option values */
777    STRTAB_str_t idl_sid,       /* [in] IDL filespec stringtable ID */
778                                /*      STRTAB_NULL_STR => stdin */
779    AST_interface_n_t **int_p   /*[out] Ptr to interface node */
780)
781
782{
783    boolean status;                     /* Status to return */
784    FE_import_file_n_t *imported_file;  /* Main IDL file info */
785    char const *file_name;                 /* Main IDL file name */
786    char       imported_fn[max_string_len];/* Main IDL full file name */
787    struct stat stat_buf;               /* File lookup info */
788    char       file_name_part[max_string_len];/* Main IDL file name part */
789    char       file_type_part[max_string_len];/* Main IDL file type part */
790    boolean name_warning = false;       /* Warn on name used */
791
792    if (idl_sid != STRTAB_NULL_STR)
793    {
794        /*
795         * Record the main IDL as if it is an imported file.
796         * This preserves idempotency in case the main IDL is also imported.
797         */
798        STRTAB_str_to_string(idl_sid, &file_name);
799        FILE_parse(file_name, NULL, 0, file_name_part, sizeof(file_name_part), file_type_part, sizeof(file_type_part));
800        strlcat(file_name_part, file_type_part, sizeof(file_name_part));
801
802        /*
803         * Issue a warning on any system IDL files - a user might
804         * accidentally choose one of those name and get strange behavior.
805         */
806        if (!strcmp(file_name_part,"iovector.idl")) name_warning = true;
807        else if (!strcmp(file_name_part,"lbase.idl")) name_warning = true;
808        else if (!strcmp(file_name_part,"nbase.idl")) name_warning = true;
809        else if (!strcmp(file_name_part,"ncastat.idl")) name_warning = true;
810        else if (!strcmp(file_name_part,"ndrold.idl")) name_warning = true;
811        else if (!strcmp(file_name_part,"rpc.idl")) name_warning = true;
812        else if (!strcmp(file_name_part,"rpcsts.idl")) name_warning = true;
813        else if (!strcmp(file_name_part,"rpctypes.idl")) name_warning = true;
814        else if (!strcmp(file_name_part,"twr.idl")) name_warning = true;
815        else if (!strcmp(file_name_part,"uuid.idl")) name_warning = true;
816
817        if (name_warning)
818            message_print(NIDL_SYSIDLNAME,file_name);
819
820        /*
821         * Note that a lookup failure will not report a failure here;
822         * That will be reported when we actually try to parse it.
823         */
824        if (FILE_lookup(file_name, NULL, &stat_buf, imported_fn, sizeof (imported_fn)))
825        {
826            imported_file = NEW (FE_import_file_n_t);
827            imported_file->imported_fn_id = STRTAB_add_string(file_name_part);
828            imported_file->imported_full_fn_id = STRTAB_add_string(imported_fn);
829            imported_file->next = imported_file_list;
830            imported_file_list = imported_file;
831        }
832    }
833
834    /*
835     * Parse the top-level IDL file.  The "false" argument tells parse not
836     * to scan the import directories for the source IDL file.
837     */
838    *int_p = NULL;
839    status = parse(cmd_opt, cmd_val, idl_sid, false, int_p);
840
841    /* Terminate if there were any syntax errors in the top level IDL file. */
842    if (*int_p == NULL)
843        status = false;
844
845    return status;
846}
847
848/*
849**  F E _ m a i n
850**
851**  Main frontend routine.  Invokes each major frontend component.
852**
853**  Note:   If cmd_opt[opt_confirm], then no real work is done except to call
854**          the components that can issue messages for the verbose option.
855*/
856
857boolean FE_main                 /* Returns true on success */
858(
859    boolean     *cmd_opt,       /* [in] Array of command option flags */
860    void        **cmd_val,      /* [in] Array of command option values */
861    STRTAB_str_t idl_sid,       /* [in] IDL filespec stringtable ID */
862                                /*      STRTAB_NULL_STR => stdin */
863    AST_interface_n_t **int_p   /*[out] Ptr to interface node */
864)
865
866{
867    boolean status;
868
869    /* Frontend-specific initialization. */
870    FE_init();
871
872    /* Parse the source IDL file (and related ACF if applicable). */
873    status = parse_idl(cmd_opt, cmd_val, idl_sid, int_p);
874
875#ifdef DUMPERS
876    /* Dump the nametable if requested. */
877    if (cmd_opt[opt_dump_nametbl])
878        NAMETABLE_dump_tab();
879#endif
880
881#ifdef DUMPERS
882    /* Dump the AST (before checking) if requested. */
883    if (cmd_opt[opt_dump_ast])
884        AST_dump_interface(*int_p);
885#endif
886
887    /* Propagate attributes throughout the AST. */
888    if (status && !cmd_opt[opt_confirm])
889        status = PROP_main(cmd_opt, cmd_val, *int_p);
890
891    /* Do semantic checking of the interface. */
892    if (status)
893    {
894        if (!cmd_opt[opt_confirm])
895            status = CHECKER_main(cmd_opt, cmd_val, *int_p);
896    }
897    else
898        message_print(NIDL_NOSEMCHECK);
899
900#ifdef DUMPERS
901    /* Dump the AST (after other frontend components) if requested. */
902    if (cmd_opt[opt_dump_ast_after])
903        AST_dump_interface(*int_p);
904#endif
905
906    /* Cancel filename for error processing because we are done with source */
907    set_name_for_errors(NULL);
908    yylineno_p = NULL;
909    yyin_p = NULL;
910
911    return status;
912}
913
914/* preserve coding style vim: set tw=78 sw=4 : */
915