/* * Copyright (c) 2010 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software have been released under the following terms: * * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION * * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this file for any * purpose is hereby granted without fee, provided that the above * copyright notices and this notice appears in all source code copies, * and that none of the names of Open Software Foundation, Inc., Hewlett- * Packard Company or Digital Equipment Corporation be used * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. Neither Open Software * Foundation, Inc., Hewlett-Packard Company nor Digital * Equipment Corporation makes any representations about the suitability * of this software for any purpose. * * Copyright (c) 2007, Novell, Inc. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Novell Inc. nor the names of its contributors * may be used to endorse or promote products derived from this * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @APPLE_LICENSE_HEADER_END@ */ /* ** ** NAME: ** ** driver.c ** ** FACILITY: ** ** Interface Definition Language (IDL) Compiler ** ** ABSTRACT: ** ** Main "driver" module - Invokes each major compiler component. ** ** VERSION: DCE 1.0 ** */ #include /* IDL common defs */ #include #include #include #include /* Abstract Syntax Tree defs */ #include /* Command Line defs */ #include #include /* File handling defs */ #include /* Decl. of BE_main() */ #include /* reporting functions */ #include /* Declaration of FE_main() */ #if defined(MIA) && defined(DUMPERS) static char *saved_header_file; /* Saved header filespec */ #endif /* Macro to call a function and return if boolean return status is FALSE */ #define CALL(rtn) \ { \ status = rtn; \ if (!status) \ {nidl_terminate();} \ } /* * setjmp/longjmp buffer to use for termination during fatal errors */ static jmp_buf nidl_termination_jmp_buf; /* ** n i d l _ t e r m i n a t e ** ** This routine utilizes setjmp/longjmp to perform an orderly termination ** of the idl compiler. */ void nidl_terminate ( void ) { extern void *errors; if (errors == NULL) { /* * No errors logged, yet we're terminating. Better issue a generic * "compilation aborted" message since this is probably an unhandled * internal compiler error. */ message_print(NIDL_COMPABORT); } longjmp(nidl_termination_jmp_buf,1); } /* ** a t t e m p t _ t o _ p r i n t _ e r r o r s ** ** This routine is established as an exception handler with the base system ** such that we always attempt to print out error messages even in the case of ** an error in the compiler. The print_errors routine, which we call is coded ** such that we cannot get into an infinite loop. */ static long attempt_to_print_errors(void) { signal(SIGBUS,SIG_DFL); signal(SIGSEGV,SIG_DFL); signal(SIGFPE,SIG_DFL); signal(SIGILL,SIG_DFL); /* * Try printing out the errors, if there are none, or it was * attempted before, this call will just return. */ print_errors(); return 0; } /* ** o p e n _ f e _ f i l e s ** ** Opens all output files that are processed by the frontend, and returns the ** file handles. Note that if an optional file was not selected by the user, ** the corresponding file handle will be NULL. ** ** Returns: FALSE if an error occurs opening any of the files. */ static boolean open_fe_files ( boolean *cmd_opt ATTRIBUTE_UNUSED, /* [in] Array of command option flags */ void **cmd_val ATTRIBUTE_UNUSED, /* [in] Array of command option values */ FILE **lis_fid /*[out] Listing file handle */ ) { /* Set up default return values. */ *lis_fid = NULL; /* Create listing file if specified. */ /* (add code when listing file supported) */ return TRUE; } /* ** o p e n _ b e _ f i l e s ** ** Opens all output files that are processed by the backend, and returns the ** file handles. Note that if an optional file was not selected by the user, ** the corresponding file handle will be NULL. ** ** Implicit Inputs: cmd_opt[opt_confirm] : If FALSE, normal processing. ** If TRUE, no files are actually created, but ** remaining processing remains intact. ** ** Implicit Outputs: cmd_opt flags for files are changed to reflect ** whether the files have been created or not. ** ** Returns: FALSE if an error occurs opening any of the files. ** FALSE if no files were opened (none selected by user). ** TRUE otherwise. */ static boolean open_be_files ( boolean *cmd_opt, /* [in] Array of command option flags */ void **cmd_val, /* [in] Array of command option values */ FILE **h_fid, /*[out] Header file handle */ FILE **caux_fid, /*[out] Client auxiliary file handle */ FILE **saux_fid, /*[out] Server auxiliary file handle */ FILE **cstub_fid, /*[out] Client stub file handle */ FILE **sstub_fid, /*[out] Server stub file handle */ AST_interface_n_t *int_p /* [in] Ptr to interface node */ ) { AST_export_n_t *export_p; /* Ptr to export node */ boolean stubs_required; /* TRUE if stub generation required */ boolean status; /* Modified by CALL macro */ boolean all_encode_decode; /* TRUE if all opers encode or decode */ /* Set up default return values. */ *caux_fid = NULL; *saux_fid = NULL; *h_fid = NULL; *cstub_fid = NULL; *sstub_fid = NULL; /* Create header file if specified. */ if (cmd_opt[opt_header]) { if (cmd_opt[opt_verbose]) message_print(NIDL_INCLCREATE, (char *)cmd_val[opt_header]); if (!cmd_opt[opt_confirm]) { CALL(FILE_create((char *)cmd_val[opt_header], h_fid)); fprintf(*h_fid, IDL_VERSION_TEMPLATE, IDL_VERSION_TEXT); } } /* * If there are no operations exported by the interface, or if the [local] * interface attribute is set, stub generation is not necessary. */ stubs_required = FALSE; all_encode_decode = TRUE; if (!AST_LOCAL_SET(int_p)) { for (export_p = int_p->exports; export_p != NULL; export_p = export_p->next) if (export_p->kind == AST_operation_k) { stubs_required = TRUE; if (!AST_ENCODE_SET(export_p->thing_p.exported_operation) && !AST_DECODE_SET(export_p->thing_p.exported_operation)) { all_encode_decode = FALSE; break; } } } /* Create client stub file if necessary. */ if (stubs_required && cmd_opt[opt_cstub] && cmd_opt[opt_emit_cstub]) { if (cmd_opt[opt_verbose]) message_print(NIDL_STUBCREATE, (char *)cmd_val[opt_cstub]); if (!cmd_opt[opt_confirm]) { CALL(FILE_create((char *)cmd_val[opt_cstub], cstub_fid)) fprintf(*cstub_fid, IDL_VERSION_TEMPLATE, IDL_VERSION_TEXT); } } else cmd_opt[opt_cstub] = FALSE; /* Create server stub file if necessary. */ if (stubs_required && !all_encode_decode && cmd_opt[opt_sstub] && cmd_opt[opt_emit_sstub]) { if (cmd_opt[opt_verbose]) message_print(NIDL_STUBCREATE, (char *)cmd_val[opt_sstub]); if (!cmd_opt[opt_confirm]) { CALL(FILE_create((char *)cmd_val[opt_sstub], sstub_fid)) fprintf(*sstub_fid, IDL_VERSION_TEMPLATE, IDL_VERSION_TEXT); } } else cmd_opt[opt_sstub] = FALSE; /* Create Client auxiliary file if it is necessary. */ #ifdef MIA if (getenv("IDL_GEN_AUX_FILES") != NULL) #endif { if (cmd_opt[opt_caux] && (int_p->sp_types != NULL || int_p->ool_types != NULL)) { if (cmd_opt[opt_verbose]) message_print(NIDL_STUBCREATE, (char *)cmd_val[opt_caux]); if (!cmd_opt[opt_confirm]) { CALL(FILE_create((char *)cmd_val[opt_caux], caux_fid)) fprintf(*caux_fid, IDL_VERSION_TEMPLATE, IDL_VERSION_TEXT); #ifdef MIA fprintf(*caux_fid,"static int idl_aux_stub = 0;\n"); #endif } } else cmd_opt[opt_caux] = FALSE; /* Create Server auxiliary file if it is necessary. */ if (cmd_opt[opt_saux] && (int_p->sp_types != NULL || int_p->ool_types != NULL || int_p->pipe_types != NULL)) { if (cmd_opt[opt_verbose]) message_print(NIDL_STUBCREATE, (char *)cmd_val[opt_saux]); if (!cmd_opt[opt_confirm]) { CALL(FILE_create((char *)cmd_val[opt_saux], saux_fid)) fprintf(*saux_fid, IDL_VERSION_TEMPLATE, IDL_VERSION_TEXT); #ifdef MIA fprintf(*saux_fid,"static int idl_aux_stub = 0;\n"); #endif } } else cmd_opt[opt_saux] = FALSE; } #ifdef MIA else { cmd_opt[opt_caux] = FALSE; cmd_opt[opt_saux] = FALSE; } #endif return (*caux_fid != NULL || *saux_fid != NULL || *h_fid != NULL || *cstub_fid != NULL || *sstub_fid != NULL); } /* ** s t u b _ c o m p i l e ** ** Conditionally invokes the C compiler to compile a generated stub file, ** directing the output file to the same directory as the source file. ** Conditionally outputs message that stub is being compiled. */ static int stub_compile ( boolean *cmd_opt, /* [in] Array of command option flags */ void **cmd_val, /* [in] Array of command option values */ int opt_file, /* [in] Index of stub file to process */ FILE *fid, /* [in] File handle of stub file */ char *compile_cmd /* [in] Base command to compile stub */ ) { char compile_opt[max_string_len]; char filespec[PATH_MAX]; /* If file was disabled, just return. */ if (!cmd_opt[opt_file]) return pgm_ok; /* Conditionally output "Compiling stub file" message. */ if (cmd_opt[opt_verbose] && error_count == 0 && cmd_opt[opt_confirm]) message_print(NIDL_STUBCOMPILE, (char *)cmd_val[opt_file]); /* If this is just a -confirm pass then return now. */ if (cmd_opt[opt_confirm] || fid == NULL) return pgm_ok; compile_opt[0] = '\0'; FILE_parse((char *)cmd_val[opt_file], filespec, sizeof (filespec), (char *)NULL, 0, (char *)NULL, 0); if (!FILE_is_cwd(filespec)) #ifdef CC_OPT_OBJECT /* * Make sure the object file ends up in the same directory as source * file by forming the object file name from the source file name and * constructing a command option to the C compiler. (This can't be * done, however, if the user has specified a -cc_cmd other than the * default, since we can't be sure of valid C compiler options.) */ if (strcmp((char *)cmd_val[opt_cc_cmd], CC_DEF_CMD) == 0) { FILE_form_filespec((char *)NULL, (char *)NULL, OBJ_FILETYPE, (char *)cmd_val[opt_file], filespec, sizeof(filespec)); sprintf(compile_opt, "%s%s", CC_OPT_OBJECT, filespec); } else #endif message_print(NIDL_OUTDIRIGN, (char *)cmd_val[opt_file]); return FILE_execute_cmd(compile_cmd, compile_opt, (char *)cmd_val[opt_file], ((cmd_opt[opt_verbose]) ? NIDL_STUBCOMPILE: 0) ); } /* ** c l o s e _ f i l e s ** ** Closes any output files that were opened during the compilation. */ static void close_files ( FILE *lis_fid, /* [in] Listing file handle */ FILE *h_fid, /* [in] Header file handle */ FILE *caux_fid, /* [in] Client auxiliary file handle */ FILE *saux_fid, /* [in] Server auxiliary file handle */ FILE *cstub_fid, /* [in] Client stub file handle */ FILE *sstub_fid /* [in] Server stub file handle */ ) { if (lis_fid != NULL) fclose(lis_fid); if (h_fid != NULL) fclose(h_fid); if (caux_fid != NULL) fclose(caux_fid); if (saux_fid != NULL) fclose(saux_fid); if (cstub_fid != NULL) fclose(cstub_fid); if (sstub_fid != NULL) fclose(sstub_fid); } /* ** i n i t ** ** Does any initializations that are global to the entire compiler. ** Component-specific initialization should be done by a separate ** initialization function for that component. */ static boolean init(char *image_name) /* Returns TRUE on success */ { /* Open error message database. */ message_open(image_name); return TRUE; } /* ** c l e a n u p ** ** Does any cleanup that is global to the entire compiler. ** Component-specific cleanup should be done by a separate ** cleanup function for that component. */ static boolean cleanup(void) /* Returns TRUE on success */ { /* Close error message database. */ message_close(); return TRUE; } /* ** D R I V E R _ m a i n ** ** Invokes each major compiler component. */ boolean DRIVER_main ( int argc, /* Command line argument count */ char **argv /* Array of command line arguments */ ) { boolean *cmd_opt; /* Array of command option flags */ void **cmd_val; /* Array of command option values */ STRTAB_str_t idl_sid; /* IDL filespec stringtable ID */ FILE *lis_fid; /* Listing file handle */ FILE *h_fid; /* Header file handle */ FILE *caux_fid; /* Client auxiliary file handle */ FILE *saux_fid; /* Server auxiliary file handle */ FILE *cstub_fid; /* Client stub file handle */ FILE *sstub_fid; /* Server stub file handle */ AST_interface_n_t *int_p; /* Ptr to interface node */ boolean status = TRUE; /* Assume we are successful */ int tmpsts; /* * Null out all file pointers in case we get an error we know which * have been opened. */ lis_fid = NULL; h_fid = NULL; caux_fid = NULL; saux_fid = NULL; cstub_fid = NULL; sstub_fid = NULL; cmd_opt = NULL; cmd_val = NULL; /* * Establish a handler such that we always try to output the * error messages, even when the compiler has an internal error. */ signal(SIGBUS, (void (*)(void))attempt_to_print_errors); signal(SIGSEGV, (void (*)(void))attempt_to_print_errors); signal(SIGFPE, (void (*)(void))attempt_to_print_errors); signal(SIGILL, (void (*)(void))attempt_to_print_errors); /* * This point is established for orderly termination of the compilation. * If a fatal error is detected, execution continues following this * if statement and the normal cleanup is performed. */ if (setjmp(nidl_termination_jmp_buf) == 0) { /* Global initialization (not specific to any one component). */ CALL(init(argv[0])); /* * Command line parsing. **NOTE**: If the combination of options * -confirm -v is selected, control *will* return back here; thus * make sure not to call any component if cmd_opt[opt_confirm] is true. */ CALL(CMD_parse_args(argc-1, &argv[1], &cmd_opt, &cmd_val, &idl_sid)); /* * Open output files that are processed by the frontend. Returned file * handles are null if not applicable. The source IDL files, any imported * IDL files, and any ACF files are opened by the parse routines. */ if (!cmd_opt[opt_confirm]) CALL(open_fe_files(cmd_opt, cmd_val, &lis_fid)); /* Frontend processing. */ CALL(FE_main(cmd_opt, cmd_val, idl_sid, &int_p)); /* Print accumulated errors and warnings generated by frontend. */ if (cmd_opt == NULL || !cmd_opt[opt_confirm]) print_errors(); /* Backend processing. */ if (open_be_files(cmd_opt, cmd_val, &h_fid, &caux_fid, &saux_fid, &cstub_fid, &sstub_fid, int_p)) { char filename[PATH_MAX]; char filetype[PATH_MAX]; char *saved_header; /* Prune the header filespec for BE so only the leafname remains. */ if (cmd_val[opt_header] != NULL) { FILE_parse((char *)cmd_val[opt_header], NULL, 0, filename, sizeof (filename), filetype, sizeof (filetype)); strlcat(filename, filetype, sizeof(filename)); } else filename[0] = '\0'; saved_header = (char *)cmd_val[opt_header]; #if defined(MIA) && defined(DUMPERS) saved_header_file = saved_header; /* Static copy for BE callback */ #endif cmd_val[opt_header] = (void *)filename; CALL(BE_main(cmd_opt, cmd_val, h_fid, caux_fid, saux_fid, cstub_fid, sstub_fid, int_p)); cmd_val[opt_header] = (void *)saved_header; } } else status = FALSE; /* Generation of listing file. */ /* (add call here) */ /* Statistics reporting. */ /* (add call here) */ /* Print accumulated errors and warnings generated by the backend, if any. */ if (cmd_opt == NULL || !cmd_opt[opt_confirm]) print_errors(); /* Close all output files. */ close_files(lis_fid, h_fid, caux_fid, saux_fid, cstub_fid, sstub_fid); /* Compile any generated files if objects were requested */ if (cmd_opt != NULL && cmd_opt[opt_keep_obj] && status) { char **idir_list; /* Array of include directories */ char idir_opt[max_string_len]; /* Cmd list of include directories */ char cc_cmd[max_string_len]; /* Base command line and options */ /* Paste together command line option for include directories. */ idir_list = (char **)cmd_val[opt_idir]; idir_opt[0] = '\0'; /* If an -out directory was specified, place it at front of idir list */ if (cmd_opt[opt_out]) { strlcat(idir_opt, " -I", sizeof(idir_opt)); strlcat(idir_opt, (char *)cmd_val[opt_out], sizeof(idir_opt)); } while (*idir_list) { strlcat(idir_opt, " -I", sizeof(idir_opt)); /* * If this include dir is the system IDL dir, then replace it * with the system H dir, which might be different. */ if (strcmp(*idir_list, DEFAULT_IDIR) == 0) strlcat(idir_opt, DEFAULT_H_IDIR, sizeof(idir_opt)); else strlcat(idir_opt, *idir_list, sizeof(idir_opt)); idir_list++; } /* Paste together base command line. */ #ifdef PASS_I_DIRS_TO_CC sprintf(cc_cmd, "%s %s %s", (char *)cmd_val[opt_cc_cmd], (char *)cmd_val[opt_cc_opt], idir_opt); #else sprintf(cc_cmd, "%s %s", (char *)cmd_val[opt_cc_cmd], (char *)cmd_val[opt_cc_opt]); #endif /* Now compile the stub modules. */ tmpsts = stub_compile(cmd_opt, cmd_val, opt_cstub, cstub_fid, cc_cmd); if (ERROR_STATUS(tmpsts)) status = FALSE; else tmpsts = stub_compile(cmd_opt, cmd_val, opt_sstub, sstub_fid, cc_cmd); if (ERROR_STATUS(tmpsts)) status = FALSE; else tmpsts = stub_compile(cmd_opt, cmd_val, opt_caux, caux_fid, cc_cmd); if (ERROR_STATUS(tmpsts)) status = FALSE; else tmpsts = stub_compile(cmd_opt, cmd_val, opt_saux, saux_fid, cc_cmd); if (ERROR_STATUS(tmpsts)) status = FALSE; } /* If no request to keep C files, delete each of them. */ if (cmd_opt != NULL && !cmd_opt[opt_keep_c] && status) { if (cmd_opt[opt_cstub]) { if (cmd_opt[opt_verbose] && error_count == 0) message_print(NIDL_STUBDELETE, (char *)cmd_val[opt_cstub]); if (!cmd_opt[opt_confirm] && cstub_fid) FILE_delete((char *)cmd_val[opt_cstub]); } if (cmd_opt[opt_sstub]) { if (cmd_opt[opt_verbose] && error_count == 0) message_print(NIDL_STUBDELETE, (char *)cmd_val[opt_sstub]); if (!cmd_opt[opt_confirm] && sstub_fid) FILE_delete((char *)cmd_val[opt_sstub]); } if (cmd_opt[opt_caux]) { if (cmd_opt[opt_verbose] && error_count == 0) message_print(NIDL_STUBDELETE, (char *)cmd_val[opt_caux]); if (!cmd_opt[opt_confirm] && caux_fid) FILE_delete((char *)cmd_val[opt_caux]); } if (cmd_opt[opt_saux]) { if (cmd_opt[opt_verbose] && error_count == 0) message_print(NIDL_STUBDELETE, (char *)cmd_val[opt_saux]); if (!cmd_opt[opt_confirm] && saux_fid) FILE_delete((char *)cmd_val[opt_saux]); } } /* Global cleanup. */ if (!cleanup()) status = FALSE; return status; }