/*
* Copyright (c) 2002, The Tendra Project <http://www.ten15.org/>
* 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/tld/library.c,v 1.12 2005/10/18 15:31:06 stefanf Exp $
*/
/*** library.c --- TDF library ADT.
*
** Author: Steve Folkes <smf@hermes.mod.uk>
*
*** Commentary:
*
* This file implements the TDF library routines used by the TDF linker.
*
*** Change Log:*/
/****************************************************************************/
#include "library.h"
#include "capsule.h"
#include "debug.h"
#include "exception.h"
#include "file-name.h"
#include "msgcat.h"
#include "tdf.h"
#include "tdf-write.h"
#include "solve-cycles.h"
/*--------------------------------------------------------------------------*/
static ExceptionP XX_library_error = EXCEPTION ("error in TDF library");
/*--------------------------------------------------------------------------*/
static TDFReaderP
library_reader(LibraryP library)
{
ASSERT (library->type == LT_INPUT);
return (&(library->u.reader));
}
static TDFWriterP
library_writer(LibraryP library)
{
ASSERT (library->type == LT_OUTPUT);
return (&(library->u.writer));
}
/*--------------------------------------------------------------------------*/
static void
library_check_index_entry(LibraryP library, ShapeEntryP entry, BoolT need_dec,
BoolT no_mult, NStringP shape_key, NameKeyP key, unsigned use,
LibCapsuleP lib_capsule, NameTableP table)
{
NameEntryP name_entry = name_table_add (table, key, entry);
unsigned name_use = name_entry_get_use (name_entry);
if (use & ~(U_USED | U_DECD | U_DEFD | U_MULT)) {
MSG_lib_bad_usage (library, shape_key, key, use);
THROW (XX_library_error);
UNREACHED;
} else if (no_mult && (use & U_MULT)) {
MSG_lib_illegally_mult_defined (library, shape_key, key);
THROW (XX_library_error);
UNREACHED;
} else if (need_dec &&
(((use & (U_DEFD | U_DECD)) == U_DEFD) ||
((use & (U_MULT | U_DECD)) == U_MULT))) {
MSG_lib_defined_but_not_declared (library, shape_key, key);
THROW (XX_library_error);
UNREACHED;
}
if ((use & U_DEFD) && (name_use & U_DEFD)) {
LibCapsuleP definition = name_entry_get_lib_definition (name_entry);
MSG_lib_multiply_defined (library, shape_key, key, definition);
} else if ((use & U_MULT) && (name_use & U_MULT) &&
(!(use & U_DEFD)) && (!(name_use & U_DEFD))) {
name_entry_set_lib_definition (name_entry, NIL (LibCapsuleP));
} else if ((use & U_DEFD) ||
((use & U_MULT) && (!(name_use & (U_MULT | U_DEFD))))) {
name_entry_set_lib_definition (name_entry, lib_capsule);
}
debug_info_r_index_entry (key, use, name_use, name_entry_key (name_entry),
lib_capsule_name (lib_capsule));
name_entry_merge_use (name_entry, use);
}
static unsigned
library_read_version_0_capsules(LibraryP library)
{
TDFReaderP reader = library_reader (library);
unsigned num_capsules = tdf_read_int (reader);
unsigned i;
debug_info_r_start_capsules (num_capsules);
library->num_capsules = num_capsules;
library->capsules = ALLOCATE_VECTOR (LibCapsuleT, num_capsules);
for (i = 0; i < num_capsules; i ++) {
NStringP contents = &(library->capsules [i].contents);
NStringT nstring;
unsigned length;
tdf_read_string (reader, &nstring);
if (nstring_contains (&nstring, '\0')) {
MSG_null_in_file_name (library, &nstring);
THROW (XX_library_error);
UNREACHED;
}
library->capsules [i].name = nstring_to_cstring (&nstring);
library->capsules [i].library = library;
library->capsules [i].loaded = FALSE;
length = tdf_read_int (reader);
nstring_init_length (contents, length);
tdf_read_bytes (reader, contents);
debug_info_r_capsule (&nstring, length);
nstring_destroy (&nstring);
}
return (num_capsules);
}
static void
library_read_version_0(LibraryP library, ShapeTableP shapes)
{
TDFReaderP reader = library_reader (library);
unsigned num_capsules = library_read_version_0_capsules (library);
ShapeEntryP token_entry = shape_table_get_token_entry (shapes);
ShapeEntryP tag_entry = shape_table_get_tag_entry (shapes);
unsigned num_shapes = tdf_read_int (reader);
unsigned i;
debug_info_r_start_index (num_shapes);
for (i = 0; i < num_shapes; i ++) {
NStringT name;
ShapeEntryP entry;
BoolT need_dec;
BoolT no_mult;
NameTableP table;
unsigned num_names;
unsigned j;
tdf_read_string (reader, &name);
entry = shape_table_add (shapes, &name);
need_dec = (entry == tag_entry);
no_mult = (entry == token_entry);
table = shape_entry_name_table (entry);
num_names = tdf_read_int (reader);
debug_info_r_start_shape_index (&name, num_names);
for (j = 0; j < num_names; j ++) {
NameKeyT external_name;
unsigned use;
unsigned capsule_index;
LibCapsuleP lib_capsule;
tdf_read_name (reader, &external_name);
use = tdf_read_int (reader);
capsule_index = tdf_read_int (reader);
if (capsule_index >= num_capsules) {
MSG_capsule_index_too_big (library, &name, &external_name,
capsule_index, num_capsules);
THROW (XX_library_error);
UNREACHED;
}
lib_capsule = &(library->capsules [capsule_index]);
library_check_index_entry (library, entry, need_dec, no_mult,
&name, &external_name, use, lib_capsule,
table);
name_key_destroy (&external_name);
}
nstring_destroy (&name);
}
tdf_read_eof (reader);
}
static void
library_extract_1(LibCapsuleP capsule, BoolT use_basename)
{
char *old_name = lib_capsule_name (capsule);
char *name = old_name;
NStringP contents = lib_capsule_contents (capsule);
TDFWriterT writer;
if (use_basename) {
name = file_name_basename (name);
}
file_name_populate (name);
if (tdf_writer_open (&writer, name)) {
MSG_extracting_capsule (old_name, name);
tdf_write_bytes (&writer, contents);
tdf_writer_close (&writer);
} else {
MSG_cant_open_output_file (name);
}
if (use_basename) {
DEALLOCATE (name);
}
}
/*--------------------------------------------------------------------------*/
typedef void (*LibTypeProcP)(LibraryP, ShapeTableP);
static LibTypeProcP library_type_jump_table [] = {
library_read_version_0
};
#define LIBRARY_TYPE_JUMP_TABLE_SIZE \
((unsigned) (sizeof (library_type_jump_table) / sizeof (LibTypeProcP)))
/*--------------------------------------------------------------------------*/
static NStringP
library_magic(void)
{
static NStringT const_magic;
static BoolT inited = FALSE;
if (!inited) {
nstring_copy_cstring (&const_magic, "TDFL");
inited = TRUE;
}
return (&const_magic);
}
/*--------------------------------------------------------------------------*/
static void
library_read_header(LibraryP library)
{
TDFReaderP reader = library_reader (library);
NStringP const_magic = library_magic ();
unsigned capsule_major = capsule_get_major_version ();
NStringT magic;
unsigned major;
unsigned minor;
nstring_init_length (&magic, (unsigned) 4);
tdf_read_bytes (reader, &magic);
if (!nstring_equal (&magic, const_magic)) {
MSG_library_bad_magic (library, &magic, const_magic);
THROW (XX_library_error);
UNREACHED;
}
nstring_destroy (&magic);
major = tdf_read_int (reader);
minor = tdf_read_int (reader);
debug_info_r_lib_versions (major, minor);
if (major < 4) {
MSG_library_bad_version (library, major);
THROW (XX_library_error);
UNREACHED;
} else if (capsule_major == 0) {
capsule_set_major_version (major);
} else if (capsule_major != major) {
MSG_library_version_mismatch (library, capsule_major, major);
THROW (XX_library_error);
UNREACHED;
}
library->major = major;
library->minor = minor;
tdf_read_align (reader);
}
/*--------------------------------------------------------------------------*/
static void
library_write_header(LibraryP library)
{
TDFWriterP writer = library_writer (library);
NStringP const_magic = library_magic ();
unsigned major = capsule_get_major_version ();
unsigned minor = capsule_get_minor_version ();
tdf_write_bytes (writer, const_magic);
ASSERT (major >= 4);
tdf_write_int (writer, major);
tdf_write_int (writer, minor);
debug_info_w_lib_versions (major, minor);
tdf_write_align (writer);
}
/*--------------------------------------------------------------------------*/
char *
lib_capsule_name(LibCapsuleP capsule)
{
return (capsule->name);
}
char *
lib_capsule_full_name(LibCapsuleP capsule)
{
char *lib_name = library_name (capsule->library);
unsigned lib_length = strlen (lib_name);
char *name = lib_capsule_name (capsule);
unsigned length = strlen (name);
char *full_name = ALLOCATE_VECTOR (char, lib_length + length + 3);
char *tmp = full_name;
(void) memcpy (tmp, lib_name, (size_t) lib_length);
tmp += lib_length;
*tmp = '(';
tmp ++;
(void) memcpy (tmp, name, (size_t) length);
tmp += length;
*tmp = ')';
tmp ++;
*tmp = '\0';
return (full_name);
}
NStringP
lib_capsule_contents(LibCapsuleP capsule)
{
return (&(capsule->contents));
}
BoolT
lib_capsule_is_loaded(LibCapsuleP capsule)
{
return (capsule->loaded);
}
void
lib_capsule_loaded(LibCapsuleP capsule)
{
capsule->loaded = TRUE;
}
/*--------------------------------------------------------------------------*/
void
write_lib_capsule_full_name(OStreamP ostream, LibCapsuleP capsule)
{
write_cstring (ostream, library_name (capsule->library));
write_char (ostream, '(');
write_cstring (ostream, lib_capsule_name (capsule));
write_char (ostream, ')');
}
/*--------------------------------------------------------------------------*/
LibraryP
library_create_stream_input(char *name)
{
LibraryP library = ALLOCATE (LibraryT);
library->type = LT_INPUT;
if (!tdf_reader_open (library_reader (library), name)) {
DEALLOCATE (library);
return (NIL (LibraryP));
}
library->name = name;
library->complete = FALSE;
return (library);
}
LibraryP
library_create_stream_output(char *name)
{
LibraryP library = ALLOCATE (LibraryT);
library->type = LT_OUTPUT;
if (!tdf_writer_open (library_writer (library), name)) {
DEALLOCATE (library);
return (NIL (LibraryP));
}
library->name = name;
library->complete = FALSE;
return (library);
}
char *
library_name(LibraryP library)
{
return (library->name);
}
unsigned
library_num_capsules(LibraryP library)
{
return (library->num_capsules);
}
LibCapsuleP
library_get_capsule(LibraryP library, unsigned capsule_index)
{
ASSERT (capsule_index < library->num_capsules);
return (&(library->capsules [capsule_index]));
}
unsigned
library_byte(LibraryP library)
{
return (tdf_reader_byte (library_reader (library)));
}
void
library_content(LibraryP library, BoolT want_index, BoolT want_size,
BoolT want_version)
{
ShapeTableP shapes = shape_table_create ();
library_read (library, shapes);
if (library->complete) {
unsigned i;
if (want_version) {
write_char (ostream_output, '[');
write_unsigned (ostream_output, library->major);
write_cstring (ostream_output, ", ");
write_unsigned (ostream_output, library->minor);
write_char (ostream_output, ']');
write_newline (ostream_output);
}
for (i = 0; i < library->num_capsules; i ++) {
LibCapsuleP capsule = &(library->capsules [i]);
write_cstring (ostream_output, lib_capsule_name (capsule));
if (want_size) {
NStringP body = lib_capsule_contents (capsule);
write_cstring (ostream_output, " (");
write_unsigned (ostream_output, nstring_length (body));
write_char (ostream_output, ')');
}
write_newline (ostream_output);
}
if (want_index) {
shape_table_iter (shapes, shape_entry_show_content,
NULL);
}
}
}
void
library_extract_all(LibraryP library, BoolT use_basename)
{
ShapeTableP shapes = shape_table_create ();
library_read (library, shapes);
if (library->complete) {
unsigned i;
for (i = 0; i < library->num_capsules; i ++) {
LibCapsuleP capsule = &(library->capsules [i]);
library_extract_1 (capsule, use_basename);
}
}
}
void
library_extract(LibraryP library, BoolT use_basename, BoolT match_basename,
unsigned num_files, char **files)
{
ShapeTableP shapes = shape_table_create ();
library_read (library, shapes);
if (library->complete) {
unsigned i;
for (i = 0; i < num_files; i ++) {
BoolT matched = FALSE;
unsigned j;
for (j = 0; j < library->num_capsules; j ++) {
LibCapsuleP capsule = &(library->capsules [j]);
char *file_name = (files [i]);
char *lib_name = lib_capsule_name (capsule);
char *base_name = NULL;
if (match_basename) {
base_name = file_name_basename (lib_name);
}
if ((cstring_equal (file_name, lib_name)) ||
(match_basename && cstring_equal (file_name, base_name))) {
library_extract_1 (capsule, use_basename);
matched = TRUE;
}
if (match_basename) {
DEALLOCATE (base_name);
}
}
if (!matched) {
MSG_capsule_not_found (files [i], library_name (library));
}
}
}
}
void
library_read(LibraryP library, ShapeTableP shapes)
{
HANDLE {
TDFReaderP reader = library_reader (library);
unsigned library_type;
debug_info_r_start_library (library_name (library));
library_read_header (library);
library_type = tdf_read_int (reader);
if (library_type >= LIBRARY_TYPE_JUMP_TABLE_SIZE) {
MSG_lib_unknown_type (library, library_type);
THROW (XX_library_error);
UNREACHED;
}
debug_info_r_library_version (library_type);
(*(library_type_jump_table [library_type])) (library, shapes);
debug_info_r_end_library ();
library->complete = TRUE;
} WITH {
ExceptionP exception = EXCEPTION_EXCEPTION ();
debug_info_r_abort_library ();
if ((exception != XX_tdf_read_error) &&
(exception != XX_library_error)) {
RETHROW ();
}
} END_HANDLE
}
void
library_write(LibraryP library, ShapeTableP shapes, unsigned num_capsules,
CapsuleP *capsules)
{
TDFWriterP writer = library_writer (library);
unsigned num_shapes = 0;
unsigned i;
debug_info_w_start_library (library_name (library));
library_write_header (library);
debug_info_w_library_version ((unsigned) 0);
tdf_write_int (writer, (unsigned) 0);
debug_info_w_start_capsules (num_capsules);
tdf_write_int (writer, num_capsules);
for (i = 0; i < num_capsules; i ++) {
CapsuleP capsule = capsules [i];
char *name = capsule_name (capsule);
NStringP contents = capsule_contents (capsule);
unsigned length = nstring_length (contents);
NStringT nstring;
debug_info_w_capsule (name, length);
nstring_copy_cstring (&nstring, name);
tdf_write_string (writer, &nstring);
nstring_destroy (&nstring);
tdf_write_int (writer, length);
tdf_write_bytes (writer, contents);
}
shape_table_iter (shapes, shape_entry_do_lib_count,
(void *) &num_shapes);
debug_info_w_start_index (num_shapes);
tdf_write_int (writer, num_shapes);
shape_table_iter (shapes, shape_entry_do_lib_write, (void *) writer);
debug_info_w_end_library ();
}
void
library_close(LibraryP library)
{
switch (library->type) EXHAUSTIVE {
case CT_INPUT:
tdf_reader_close (library_reader (library));
break;
case CT_OUTPUT:
tdf_writer_close (library_writer (library));
break;
}
}
syntax highlighted by Code2HTML, v. 0.9.1