/* * Copyright (c) 2002, The Tendra Project * 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 unmodified, 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * * Crown Copyright (c) 1997 * * This TenDRA(r) Computer Program is subject to Copyright * owned by the United Kingdom Secretary of State for Defence * acting through the Defence Evaluation and Research Agency * (DERA). It is made available to Recipients with a * royalty-free licence for its use, reproduction, transfer * to other parties and amendment for any purpose not excluding * product development provided that any such use et cetera * shall be deemed to be acceptance of the following conditions:- * * (1) Its Recipients shall ensure that this Notice is * reproduced upon any copies or amended versions of it; * * (2) Any amended version of it shall be clearly marked to * show both the nature of and the organisation responsible * for the relevant amendment or amendments; * * (3) Its onward transfer from a recipient to another * party shall be deemed to be that party's acceptance of * these conditions; * * (4) DERA gives no warranty or assurance as to its * quality or suitability for any purpose and DERA accepts * no liability whatsoever in relation to any use to which * it may be put. * * $TenDRA: tendra/src/tools/tspec/main.c,v 1.15 2004/08/08 10:55:54 stefanf Exp $ */ #include "config.h" #include "argparse.h" #include "catstdn.h" #include "cstring.h" #include "msgcat.h" #include "ostream.h" #include "tenapp.h" #include #include "release.h" #include "object.h" #include "hash.h" #include "index.h" #include "lex.h" #include "makefile.h" #include "name.h" #include "syntax.h" #include "type.h" #include "print.h" #include "utility.h" extern void tspec_on_message(MSG_DATA *); static BoolT check_only = 0; static BoolT preproc_input = 0; static BoolT separate_files = 0; static FILE *preproc_file = NULL; static int show_index = 0; static char *dir = "."; static char *progfile; /* * SIGNAL HANDLER * * This routine handles caught signals. */ static void exit_handler(void) { hash_elem *e; if (exit_status == 0) return; e = sort_hash (files); while (e) { object *p = e->obj; FILE *f = p->u.u_file; if (f) { char *nm = p->name; if (verbose) IGNORE printf ("Removing %s ...\n", nm); IGNORE fclose (f); IGNORE remove (nm); } e = e->next; } } /* * SEPARATE COMPILATION ROUTINE * * This routine performs the separate compilation of the set object p. */ static void separate(object *p) { info *i = p->u.u_info; static char *exec = null; if (i->subset || i->file == null) return; if (exec == null) exec = buffer + strlen (buffer); IGNORE sprintf (exec, "%s %s", i->api, i->file); if (verbose > 1) IGNORE printf ("Executing '%s' ...\n", buffer); if (system (buffer)) { MSG_separate_compilation_failed (p->name); } return; } /* * MARK A SET AS IMPLEMENTED * * This routine recursively marks all implemented subsets of p. */ static void implement(object *p, int depth) { object *q; info *i = p->u.u_info; if (i == null || i->implemented >= depth) return; i->implemented = depth; for (q = i->elements; q != null; q = q->next) { if (q->objtype == OBJ_IMPLEMENT) { implement (q->u.u_obj, depth + 1); } } return; } static void opt_include(char *option, void *closure, char *value) { UNUSED(option); UNUSED(closure); dir = string_printf ("%s:%s", dir, value); } static void opt_nowarns(char *option, void *closure) { UNUSED(option); UNUSED(closure); msg_sev_set (MSG_SEV_WARNING, 0); } static void opt_outidir(char *option, void *closure, char *value) { UNUSED(option); UNUSED(closure); output_incl_dir = value; output_incl_len = (int) strlen (value) + 1; } static void opt_outsdir(char *option, void *closure, char *value) { UNUSED(option); UNUSED(closure); output_src_dir = value; output_src_len = (int) strlen (value) + 1; } static void opt_preprocess(char *option, void *closure) { UNUSED(option); UNUSED(closure); preproc_file = stdout; } static void opt_progtstamp(char *option, void *closure) { UNUSED(option); UNUSED(closure); progdate = date_stamp (progfile); } static void opt_show_index(char *option, void *closure) { UNUSED(closure); switch (option[0]) { case 'i': show_index = 1; break; case 'm': show_index = 2; break; } } static void opt_verbose(char *option, void *closure) { UNUSED(option); UNUSED(closure); verbose++; } static void opt_help(char *option, void *closure); static ArgListT cmdl_opts[] = { AP_OPT_EITHER (include, 'I', NULL, opt_include), AP_OPT_EITHER (outidir, 'O', NULL, opt_outidir), AP_OPT_EITHER (outsdir, 'S', NULL, opt_outsdir), AP_OPT_EMPTY (version, 'V', NULL, arg_std_version), AP_OPT_RESET (atonce, 'a', NULL, &separate_files), AP_OPT_SET (separate, 's', NULL, &separate_files), AP_OPT_SET (check_only, 'c', NULL, &check_only), AP_OPT_RESET (restrict_depth,'d', NULL, &restrict_depth), AP_OPT_EMPTY (preprocess, 'e', NULL, opt_preprocess), AP_OPT_SET (force_output, 'f', NULL, &force_output), AP_OPT_EMPTY (help, 'h', "help", opt_help), AP_OPT_EMPTY (docindex, 'i', NULL, opt_show_index), AP_OPT_SET (local_input, 'l', NULL, &local_input), AP_OPT_EMPTY (machindex, 'm', NULL, opt_show_index), AP_OPT_EMPTY (progtstamp, 'n', NULL, opt_progtstamp), AP_OPT_SET (preproc_input, 'p', NULL, &preproc_input), AP_OPT_SET (restrict_use, 'r', NULL, &restrict_use), AP_OPT_SET (allow_longlong,'t', NULL, &allow_long_long), AP_OPT_SET (unique_names, 'u', NULL, &unique_names), AP_OPT_EMPTY (verbose, 'v', NULL, opt_verbose), AP_OPT_EMPTY (nowarns, 'w', NULL, opt_nowarns), AP_OPT_EOL }; static void opt_help(char *option, void *closure) { UNUSED(option); UNUSED(closure); MSG_usage (); arg_print_usage (cmdl_opts); msg_append_newline (); } static void msg_uh_fileline(char ch, void *pp) { UNUSED(ch); UNUSED(pp); if (filename) write_fmt(msg_stream, "%s: %d: ", filename, line_no); } /* * MAIN ROUTINE * * This is the main routine which interprets the command-line options * and calls the appropriate routines. */ int main(int argc, char **argv) { int optcnt, targc; char *env, **targv; char *api = null; char *file = null; char *subset = null; object *commands = null; /* Initialisation */ tenapp_init (argc, argv, "An API specification tool", "2.10"); tenapp_add_eh (exit_handler); msg_uh_add(MSG_GLOB_fileline, msg_uh_fileline); msg_on_message = tspec_on_message; targc = argc; targv = argv; line_no = 1; filename = "built-in definitions"; init_hash (); init_keywords (); init_types (); filename = "command line"; /* Read system variables */ env = getenv (INPUT_ENV); if (env) input_dir = string_copy (env); env = getenv (OUTPUT_ENV); if (env) { output_incl_dir = string_printf ("%s/include", env); output_incl_len = (int) strlen (output_incl_dir) + 1; output_src_dir = string_printf ("%s/src", env); output_src_len = (int) strlen (output_src_dir) + 1; } env = getenv (INCLUDE_ENV); if (env) { output_incl_dir = string_copy (env); output_incl_len = (int) strlen (output_incl_dir) + 1; } env = getenv (SRC_ENV); if (env) { output_src_dir = string_copy (env); output_src_len = (int) strlen (output_src_dir) + 1; } progfile = argv[0]; optcnt = arg_parse_arguments (cmdl_opts, --argc, ++argv); argc -= optcnt; argv += optcnt; if (argc < 1) MSG_getopt_not_enough_arguments (); if (argc > 3) MSG_getopt_too_many_arguments (); api = *argv++; if (argc > 1) { file = *argv++; if (argc > 2) subset = *argv; } if (local_input) { if (subset) MSG_getopt_too_many_arguments (); subset = file; file = api; api = LOCAL_API; } if (api == null) MSG_getopt_not_enough_arguments (); input_dir = string_printf ("%s:%s", dir, input_dir); if (preproc_input) { /* Open preprocessed input */ if (file != null) MSG_getopt_not_enough_arguments (); preproc_file = fopen (api, "r"); filename = api; line_no = 1; if (preproc_file == null) { MSG_cant_open_input_file (api); } } else { /* Find the temporary file */ int n; if (preproc_file == null) { preproc_file = tmpfile (); if (preproc_file == null) { MSG_cant_open_temporary_file (); } } /* Do the preprocessing */ preproc (preproc_file, api, file, subset); n = no_errors; if (n) { filename = null; MSG_errors_in_preprocessor_phase (n); } if (preproc_file == stdout) exit (exit_status); filename = "temporary file"; line_no = 1; } /* Deal with separate compilation */ if (separate_files) { int n; hash_elem *e; char *s = buffer; IGNORE sprintf (s, "%s ", targv [0]); for (optcnt = 1; optcnt < targc; optcnt++) { char *arg = targv [optcnt]; if (arg [0] == '-') { s = s + strlen (s); IGNORE sprintf (s, "%s ", arg); } } s = s + strlen (s); IGNORE strcpy (s, "-ac "); filename = null; e = sort_hash (subsets); while (e) { separate (e->obj); e = e->next; } n = no_errors; if (n) { MSG_errors_in_separate_compilation (n); } exit (exit_status); } /* Process the input */ input_file = preproc_file; input_pending = LEX_EOF; rewind (input_file); ADVANCE_LEXER; read_spec (&commands); if (no_errors) { filename = null; MSG_errors_in_analyser_phase (no_errors); } /* Perform the output */ if (!check_only) { filename = null; if (commands && commands->objtype == OBJ_SET) { implement (commands->u.u_obj, 1); if (show_index == 0) { print_set (commands, 0); print_set (commands, 1); if (file == null) { hash_elem *e = sort_hash (subsets); print_makefile (api, e); } } else { if (show_index == 1) { print_index (commands); } else { print_machine_index (commands); } } } } return (exit_status); }