/* * 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/tnc/de_capsule.c,v 1.9 2005/09/21 20:30:00 stefanf Exp $ */ #include "config.h" #include "fmm.h" #include "msgcat.h" #include "tdf_types.h" #include "tdf_stream.h" #include "types.h" #include "de_types.h" #include "de_capsule.h" #include "de_unit.h" #include "decode.h" #include "file.h" #include "names.h" #include "node.h" #include "table.h" #include "tdf.h" #include "utility.h" /* * FLAG : DECODE STATUS * * A value of 0 indicates that we are decoding the names at the start * of the capsule, 1 that we are decoding the linkage information, and * 2 that we are decoding a main equation body. */ int decode_status = -1; /* * FLAG : ONLY DECODE TOKEN DECLARATIONS * * This flag is true if we are only interested in the token * declarations in a capsule. */ boolean extract_tokdecs = 0; /* * THE ARRAY OF ALL VARIABLE SORTS * * The array vars of size no_var gives all variable sorts. The * indexes in this array of the alignment tags, tags and tokens are * given by al_tag_var, tag_var, tok_var respectively. */ static unsigned long no_var; static var_sort *vars; long al_tag_var, tag_var, tok_var; /* * LIST OF UNUSED CONSTRUCTS * * All unused constructs in a capsule are formed into a list for * later reuse. */ static construct *garbage = null; /* * CURRENT BINDINGS * * The current bindings are held in crt_binding. spare_binding, if not * null, contains a binding suitable for reuse. */ binding *crt_binding; static binding *spare_binding = null; /* * CREATE A NEW BINDING * * A new binding with space for no_var variable sorts is created and * cleared. */ static binding * new_binding(void) { binding *b; unsigned long i, n = no_var; if (n == 0) return (null); if (spare_binding) { b = spare_binding; spare_binding = null; for (i = 0 ; i < n ; i++) b [i].max_no = 0; return (b); } b = xalloc (sizeof (*b) * n); for (i = 0 ; i < n ; i++) { b [i].max_no = 0; b [i].sz = 0; b [i].table = null; } return (b); } /* * FREE A BINDING * * The binding b is returned to free. */ static void free_binding(binding *b) { spare_binding = b; return; } /* * SET THE SIZE OF AN ENTRY IN A BINDING * * The size of the table of the vth variable sort in the binding bt * is set to n. */ static void set_binding_size(binding *bt, unsigned long v, long n) { binding *b; construct **p; long i, m = n + 10; if (v >= no_var) MSG_FATAL_illegal_binding_sort (); b = bt + v; b->max_no = n; if (b->sz < m) { p = xrealloc (b->table, sizeof (construct *) * m); b->sz = m; b->table = p; } else { p = b->table; } for (i = 0 ; i < b->sz ; i++) p [i] = null; return; } /* * COMPLETE A BINDING * * The unused entries in the binding b are filled in. */ static void complete_binding(binding *b) { unsigned long v; for (v = 0 ; v < no_var ; v++) { unsigned long i; binding *bv = b + v; sortname s = vars [v].sortnum; for (i = 0 ; i < bv->max_no ; i++) { if (bv->table [i] == null) { construct *p = make_construct (s); if (extract_tokdecs) { /* This construct is unused - free it */ (sort_count [s])--; p->next = garbage; garbage = p; } else { /* Make up an internal name */ long n = p->encoding; char *nm = xalloc (32); IGNORE sprintf (nm, "~~%s_%ld", vars [v].name, n); p->name = nm; if (add_to_var_hash (p, s)) MSG_FATAL_var_already_defined (nm); } bv->table [i] = p; } } } return; } /* * SET AN ENTRY IN A BINDING * * The nth entry of the vth variable sort of the binding bt is set to * the construct p. */ static void set_binding(binding *bt, unsigned long v, unsigned long n, construct *p) { binding *b; if (v >= no_var) MSG_FATAL_illegal_binding_sort (); b = bt + v; if (n >= b->max_no) MSG_FATAL_object_number_too_big (n, vars [v].name); if (b->table [n]) MSG_FATAL_object_already_bound (n, vars [v].name); b->table [n] = p; return; } /* * FIND AN ENTRY IN A BINDING * * The nth entry of the vth variable sort of the binding bt is returned. */ construct * find_binding(binding *bt, unsigned long v, unsigned long n) { binding *b; if (v >= no_var) MSG_FATAL_illegal_binding_sort (); b = bt + v; if (n >= b->max_no) MSG_FATAL_object_number_too_big (n, vars [v].name); return (b->table [n]); } /* * DECODE AN ALIGNED STRING * * An aligned string (in an external name) is decoded and returned * as an array of characters. */ static char * de_aligned_string(void) { TDFIDENT ts; tdf_de_tdfident (tdfr, &ts); if (ts.size != 8) MSG_FATAL_only_8bit_strings_allowed (); return (ts.ints.chars); } /* * FLAG INDICATING SKIP PASS * * This flag is true if we are in the skip pass of a set of equations * (primarily token definitions). */ boolean in_skip_pass = 0; /* * DECODE A SET OF EQUATIONS * * A set of equations with decoding routine f is decoded. If f is null * the equations are stepped over, otherwise they are decoded. */ typedef void (*equation_func)(void) ; static void de_equation(equation_func f) { unsigned long i, n; binding *old_binding = null; /* Read new bindings */ n = tdf_de_tdfintl (tdfr); if (n) { if (n != no_var) MSG_FATAL_number_of_local_variables_wrong (); old_binding = crt_binding; crt_binding = new_binding (); for (i = 0 ; i < n ; i++) { long sz = tdf_int (); set_binding_size (crt_binding, i, sz); } n = tdf_de_tdfintl (tdfr); if (n != no_var) MSG_FATAL_number_of_linkage_units_wrong (); for (i = 0 ; i < n ; i++) { long j, no_links = tdf_int (); for (j = 0 ; j < no_links ; j++) { unsigned long inner = tdf_de_tdfintl (tdfr); unsigned long outer = tdf_de_tdfintl (tdfr); construct *p = find_binding (old_binding, i, outer); set_binding (crt_binding, i, inner, p); } } complete_binding (crt_binding); } else { n = tdf_de_tdfintl (tdfr); if (n) MSG_FATAL_number_of_linkage_units_wrong (); } /* Read the actual equation */ n = BYTESIZE * tdf_de_tdfintl (tdfr); tdf_de_align (tdfr); if (f == null) { tdf_skip_bits (tdfr, n); } else { tdf_pos end_posn = tdf_stream_tell (tdfr) + n; decode_status = 2; (*f) (); tdf_de_align (tdfr); decode_status = 1; if (tdf_stream_tell (tdfr) != end_posn) MSG_FATAL_unit_length_wrong (); } /* Restore the old bindings */ if (old_binding) { free_binding (crt_binding); crt_binding = old_binding; } return; } /* * DECODE A CAPSULE * * An entire TDF capsule is decoded. */ void de_capsule(void) { unsigned long i, n; unsigned long no_eqn; char **eqns; /* Reset variables */ al_tag_var = -1; tag_var = -2; tok_var = -3; spare_binding = null; have_version = 0; decode_status = 0; /* Read magic number */ de_magic (tdf_cap_magic); /* Read equation names */ no_eqn = tdf_de_tdfintl (tdfr); eqns = xalloc (sizeof (char *) * no_eqn); for (i = 0 ; i < no_eqn ; i++) eqns [i] = de_aligned_string (); /* Read variable sort names */ no_var = tdf_de_tdfintl (tdfr); vars = xalloc (sizeof (var_sort) * no_var); crt_binding = new_binding (); for (i = 0 ; i < no_var ; i++) { char *s = de_aligned_string (); long sz = tdf_int (); vars [i].name = s; if (streq (s, LINK_al_tag)) { vars [i].sortnum = SORT_al_tag; al_tag_var = i; } else if (streq (s, LINK_tag)) { vars [i].sortnum = SORT_tag; tag_var = i; } else if (streq (s, LINK_token)) { vars [i].sortnum = SORT_token; tok_var = i; } else { vars [i].sortnum = SORT_unknown; } set_binding_size (crt_binding, i, sz); } /* Read external names */ decode_status = 1; n = tdf_int (); if (n != no_var) MSG_FATAL_number_of_variable_sorts_wrong (); for (i = 0 ; i < no_var ; i++) { static int un = 0; sortname si = vars [i].sortnum; long j, no_links = tdf_int (); boolean reject = 0; if (extract_tokdecs && i != tok_var) reject = 1; for (j = 0 ; j < no_links ; j++) { construct *p, *q; unsigned long id = tdf_de_tdfintl (tdfr); n = de_external_bits (); tdf_de_align (tdfr); p = make_construct (si); if (extract_tokdecs) { (sort_count [ si ])--; p->encoding = -1; } if (n == ENC_string_extern) { /* Simple external name */ boolean name_ok = 1; node *ns = de_node ("="); if (reject) { free_node (ns); } else { /* Check that name is a valid identifier */ char *nm = ns->cons->name; if (alpha (*nm)) { long k; for (k = 1 ; k < ns->cons->encoding ; k++) { char c = nm [k]; if (!alphanum (c)) name_ok = 0; } } else { name_ok = 0; } if (name_ok) { /* Use external name as internal name */ p->name = nm; if (!is_local_name (nm)) { p->ename = new_node (); p->ename->cons = &false_cons; } } else { /* Make up internal name */ p->name = xalloc (32); IGNORE sprintf (p->name, "~~extern_%d", un++); if (!is_local_name (nm)) { p->ename = new_node (); p->ename->cons = &true_cons; p->ename->son = ns; } } } } else if (n == ENC_unique_extern) { /* Unique external name */ node *nu = de_node ("%[=]"); if (reject) { free_node (nu); } else { /* Make up internal name */ p->name = xalloc (32); IGNORE sprintf (p->name, "~~extern_%d", un++); p->ename = new_node (); p->ename->cons = &true_cons; p->ename->son = nu; } } else if (n == ENC_chain_extern) { /* Chain external name */ node *nc = de_node ("=i"); if (reject) { free_node (nc); } else { /* Make up internal name */ p->name = xalloc (32); IGNORE sprintf (p->name, "~~extern_%d", un++); p->ename = new_node (); p->ename->cons = &true_cons; p->ename->son = nc; } } else { MSG_FATAL_illegal_EXTERN_value (n); } /* Add construct to tables */ if (reject) { set_binding (crt_binding, i, id, p); p->next = garbage; garbage = p; } else { q = add_to_var_hash (p, si); if (q) { if (!extract_tokdecs) { (sort_count [ si ])--; if (q->encoding == -1) { q->encoding = (sort_count [ si ])++; } } set_binding (crt_binding, i, id, q); p->next = garbage; garbage = p; } else { set_binding (crt_binding, i, id, p); } } } } /* Complete the bindings */ complete_binding (crt_binding); /* Read the equations */ n = tdf_int (); if (n != no_eqn) MSG_FATAL_number_of_equations_wrong (); for (i = 0 ; i < no_eqn ; i++) { char *eq = eqns [i]; long j, no_units = tdf_int (); if (no_units) { boolean skip_pass = 0; equation_func f = null; /* Find equation decoding routine */ if (extract_tokdecs) { if (streq (eq, LINK_tokdec_props)) { f = de_tokdec; } else if (streq (eq, LINK_tokdef_props)) { f = de_tokdef; in_skip_pass = 1; } } else { if (streq (eq, LINK_al_tagdef_props)) { f = de_aldef; } else if (streq (eq, LINK_tagdec_props)) { f = de_tagdec; } else if (streq (eq, LINK_tagdef_props)) { f = de_tagdef; } else if (streq (eq, LINK_tokdec_props)) { f = de_tokdec; } else if (streq (eq, LINK_tokdef_props)) { f = de_tokdef; skip_pass = 1; } else if (streq (eq, LINK_version_props)) { f = de_version; } } /* Skip pass */ if (skip_pass) { tdf_pos old_posn = tdf_stream_tell (tdfr); in_skip_pass = 1; for (j = 0 ; j < no_units ; j++) de_equation (f); in_skip_pass = 0; tdf_stream_seek (tdfr, old_posn); } /* Main pass */ for (j = 0 ; j < no_units ; j++) de_equation (f); in_skip_pass = 0; } } /* Free unused constructs */ free_construct (&garbage); return; } /* * NAME OF CURRENT CAPSULE * * The current capsule of a library is recorded to use in error messages. */ char *capname = null; /* * DECODE A TDF LIBRARY */ void de_library(void) { tdf_pos old_posn; long i, no_cap; boolean old_extract = extract_tokdecs; de_magic (tdf_lib_magic); IGNORE tdf_int (); no_cap = tdf_int (); old_posn = tdf_stream_tell (tdfr); /* First pass - extract all token declaration */ extract_tokdecs = 1; for (i = 0 ; i < no_cap ; i++) { tdf_pos end_posn; long n; decode_status = 0; capname = de_aligned_string (); n = BYTESIZE * tdf_int (); tdf_de_align (tdfr); end_posn = tdf_stream_tell (tdfr) + n; de_capsule (); tdf_de_align (tdfr); if (tdf_stream_tell (tdfr) != end_posn) MSG_FATAL_capsule_length_wrong (); capname = null; } /* Second pass - if the first pass didn't do everything */ extract_tokdecs = old_extract; if (extract_tokdecs) return; tdf_stream_seek (tdfr, old_posn); for (i = 0 ; i < no_cap ; i++) { tdf_pos end_posn; long n; decode_status = 0; capname = de_aligned_string (); n = BYTESIZE * tdf_int (); tdf_de_align (tdfr); end_posn = tdf_stream_tell (tdfr) + n; de_capsule (); tdf_de_align (tdfr); if (tdf_stream_tell (tdfr) != end_posn) MSG_FATAL_capsule_length_wrong (); capname = null; } return; }