/*
* 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/rename-file.c,v 1.11 2005/10/18 15:31:06 stefanf Exp $
*/
/**** rename-file.c --- Routines for parsing rename file.
*
** Author: Steve Folkes <smf@hermes.mod.uk>
*
**** Commentary:
*
* This file provides the routines that parse the rename file. The rename
* file has the following format.
*
* 'shape'
* "name1" "name2";
* "name3" [unique.4];
*
* Where shape names are enclosed in single quotes, string names are enclosed
* in double quotes, and uniques are written using the normal unique syntax.
* A single shape name may be followed by any number of name pairs, each of
* which is terminated by a semi-colon.
*
**** Change Log:*/
/****************************************************************************/
#include "rename-file.h"
#include "dstring.h"
#include "msgcat.h"
#include "istream.h"
#include "nstring-list.h"
#include "syntax.h"
#include "tenapp.h"
#include "solve-cycles.h"
/*--------------------------------------------------------------------------*/
#ifdef FS_NO_ENUM
typedef int RenameTagT, *RenameTagP;
#define RTOK_SHAPE (0)
#define RTOK_NAME (1)
#define RTOK_SEMI (2)
#define RTOK_EOF (3)
#else
typedef enum {
RTOK_SHAPE,
RTOK_NAME,
RTOK_SEMI,
RTOK_EOF
} RenameTagT, *RenameTagP;
#endif /* defined (FS_NO_ENUM) */
typedef struct RenameTokenT {
RenameTagT tag;
union {
NStringT shape;
NameKeyT name;
} u;
} RenameTokenT, *RenameTokenP;
/*--------------------------------------------------------------------------*/
static BoolT
rename_file_skip_white_space(IStreamP istream, char *c_ref)
{
BoolT comment = FALSE;
for (;;) {
char c;
redo:
switch (c = ISTREAM_READ_CHAR (istream)) {
case '\0':
ISTREAM_HANDLE_NULL (istream, redo, eof);
break;
case '\n':
istream_inc_line (istream);
comment = FALSE;
break;
case '#':
comment = TRUE;
break;
default:
if ((!comment) && (!syntax_is_white_space (c))) {
*c_ref = c;
return (TRUE);
}
break;
}
}
eof:
return (FALSE);
}
static void
rename_file_read_unique(IStreamP istream, RenameTokenP token)
{
NameKeyP name = &(token->u.name);
unsigned length = 1;
DStringT dstring;
NStringT nstring;
NStringListT list;
NStringListEntryP entry;
unsigned i;
dstring_init (&dstring);
nstring_list_init (&list);
for (;;) {
char c;
redo:
switch (c = ISTREAM_READ_CHAR (istream)) {
case '\0':
ISTREAM_HANDLE_NULL (istream, redo, eof);
dstring_append_char (&dstring, '\0');
break;
case '\n':
istream_inc_line (istream);
MSG_rename_unexpected_newline (istream);
break;
case ']':
dstring_to_nstring (&dstring, &nstring);
nstring_list_append (&list, &nstring);
dstring_destroy (&dstring);
name_key_init_unique (name, length);
for (i = 0, entry = nstring_list_head (&list); entry;
i ++, entry = nstring_list_entry_deallocate (entry)) {
NStringP component = nstring_list_entry_string (entry);
name_key_set_component (name, i, component);
}
token->tag = RTOK_NAME;
return;
case '[':
MSG_rename_illegal_char (istream, c);
break;
case '.':
dstring_to_nstring (&dstring, &nstring);
nstring_list_append (&list, &nstring);
dstring_destroy (&dstring);
dstring_init (&dstring);
length ++;
break;
case '\\':
switch (istream_read_escaped_char (istream, &c)) EXHAUSTIVE {
case ISTREAM_STAT_READ_CHAR:
dstring_append_char (&dstring, c);
break;
case ISTREAM_STAT_SYNTAX_ERROR:
MSG_rename_illegal_escape (istream);
break;
case ISTREAM_STAT_NO_CHAR:
/*NOTHING*/
break;
}
break;
default:
dstring_append_char (&dstring, c);
break;
}
}
eof:
MSG_rename_unexpected_eof (istream);
dstring_destroy (&dstring);
for (entry = nstring_list_head (&list); entry;
entry = nstring_list_entry_deallocate (entry)) {
nstring_destroy (nstring_list_entry_string (entry));
}
token->tag = RTOK_EOF;
}
static void
rename_file_read_shape(IStreamP istream, RenameTokenP token)
{
DStringT dstring;
dstring_init (&dstring);
for (;;) {
char c;
redo:
switch (c = ISTREAM_READ_CHAR (istream)) {
case '\0':
ISTREAM_HANDLE_NULL (istream, redo, eof);
dstring_append_char (&dstring, '\0');
break;
case '\n':
istream_inc_line (istream);
MSG_rename_unexpected_newline (istream);
break;
case '\'':
dstring_to_nstring (&dstring, &(token->u.shape));
dstring_destroy (&dstring);
token->tag = RTOK_SHAPE;
return;
case '\\':
switch (istream_read_escaped_char (istream, &c)) EXHAUSTIVE {
case ISTREAM_STAT_READ_CHAR:
dstring_append_char (&dstring, c);
break;
case ISTREAM_STAT_SYNTAX_ERROR:
MSG_rename_illegal_escape (istream);
break;
case ISTREAM_STAT_NO_CHAR:
/*NOTHING*/
break;
}
break;
default:
dstring_append_char (&dstring, c);
break;
}
}
eof:
MSG_rename_unexpected_eof (istream);
dstring_destroy (&dstring);
token->tag = RTOK_EOF;
}
static void
rename_file_read_string(IStreamP istream, RenameTokenP token)
{
DStringT dstring;
NStringT nstring;
dstring_init (&dstring);
for (;;) {
char c;
redo:
switch (c = ISTREAM_READ_CHAR (istream)) {
case '\0':
ISTREAM_HANDLE_NULL (istream, redo, eof);
dstring_append_char (&dstring, '\0');
break;
case '\n':
istream_inc_line (istream);
MSG_rename_unexpected_newline (istream);
break;
case '"':
dstring_to_nstring (&dstring, &nstring);
dstring_destroy (&dstring);
name_key_init_string (&(token->u.name), &nstring);
token->tag = RTOK_NAME;
return;
case '[': case ']': case '.':
MSG_rename_illegal_char (istream, c);
break;
case '\\':
switch (istream_read_escaped_char (istream, &c)) EXHAUSTIVE {
case ISTREAM_STAT_READ_CHAR:
dstring_append_char (&dstring, c);
break;
case ISTREAM_STAT_SYNTAX_ERROR:
MSG_rename_illegal_escape (istream);
break;
case ISTREAM_STAT_NO_CHAR:
/*NOTHING*/
break;
}
break;
default:
dstring_append_char (&dstring, c);
break;
}
}
eof:
MSG_rename_unexpected_eof (istream);
dstring_destroy (&dstring);
token->tag = RTOK_EOF;
}
static void
rename_file_next_token(IStreamP istream, RenameTokenP token)
{
char c;
again:
if (rename_file_skip_white_space (istream, &c)) {
switch (c) {
case '[':
rename_file_read_unique (istream, token);
break;
case '\'':
rename_file_read_shape (istream, token);
break;
case '"':
rename_file_read_string (istream, token);
break;
case ';':
token->tag = RTOK_SEMI;
break;
default:
MSG_rename_illegal_char (istream, c);
goto again;
}
} else {
token->tag = RTOK_EOF;
}
}
static void
rename_file_parse_names(IStreamP istream, NStringP shape, ArgDataP arg_data,
RenameTokenP token)
{
rename_file_next_token (istream, token);
while (token->tag == RTOK_NAME) {
NameKeyT name;
name_key_assign (&name, &(token->u.name));
rename_file_next_token (istream, token);
if (token->tag != RTOK_NAME) {
MSG_rename_expected_name (istream);
name_key_destroy (&name);
if (token->tag != RTOK_SEMI) {
return;
}
rename_file_next_token (istream, token);
} else {
NameKeyT to_name;
name_key_assign (&to_name, &(token->u.name));
arg_data_add_rename (arg_data, shape, &name, &to_name);
rename_file_next_token (istream, token);
if (token->tag != RTOK_SEMI) {
MSG_rename_expected_semi (istream);
} else {
rename_file_next_token (istream, token);
}
}
}
}
static void
rename_file_parse_1(IStreamP istream, ArgDataP arg_data)
{
BoolT need_error = TRUE;
RenameTokenT token;
NStringT shape;
rename_file_next_token (istream, &token);
while (token.tag != RTOK_EOF) {
switch (token.tag) {
case RTOK_SHAPE:
nstring_assign (&shape, &(token.u.shape));
rename_file_parse_names (istream, &shape, arg_data, &token);
nstring_destroy (&shape);
need_error = TRUE;
break;
case RTOK_NAME:
name_key_destroy (&(token.u.name));
FALL_THROUGH;
default:
if (need_error) {
MSG_rename_expected_shape (istream);
need_error = FALSE;
}
rename_file_next_token (istream, &token);
break;
}
}
}
/*--------------------------------------------------------------------------*/
void
rename_file_parse(char *name, ArgDataP arg_data)
{
IStreamT istream;
if (istream_open (&istream, name)) {
rename_file_parse_1 (&istream, arg_data);
istream_close (&istream);
} else {
MSG_cant_open_rename_file (name);
}
tenapp_checkerrors(MSG_SEV_ERROR);
}
syntax highlighted by Code2HTML, v. 0.9.1