Tool for manipulating SGML document instances. Replaces sgmlsasp.

This commit is contained in:
John Fieber 1996-09-08 01:55:10 +00:00
parent 60b522b0a6
commit 8053f55001
15 changed files with 8265 additions and 0 deletions

View File

@ -0,0 +1,15 @@
# $Id: Makefile,v 1.1.1.1 1996/01/16 05:14:09 jfieber Exp $
PROG= instant
SRCS= browse.c info.c main.c tables.c traninit.c translate.c
SRCS+= tranvar.c util.c
CFLAGS+= -I${.CURDIR}/../libsgmls -I${.CURDIR}/../sgmls
LDADD= ${LIBSGMLS} -lcompat
DPADD= ${LIBSGMLS}
MAN1= instant.1
MAN5= transpec.5
.include <bsd.prog.mk>

View File

@ -0,0 +1,150 @@
#
# Copyright (c) 1994
# Open Software Foundation, Inc.
#
# Permission is hereby granted to use, copy, modify and freely distribute
# the software in this file and its documentation for any purpose without
# fee, provided that the above copyright notice appears in all copies and
# that both the copyright notice and this permission notice appear in
# supporting documentation. Further, provided that the name of Open
# Software Foundation, Inc. ("OSF") not be used in advertising or
# publicity pertaining to distribution of the software without prior
# written permission from OSF. OSF makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
instant - a formatting application for OSF SGML instances
____________________________________________________________________________
Requirements
ANSI C compiler (gcc is one)
sgmls 1.1 -- sgml parser from James Clark. Based on Goldfarb's ARC parser.
Vanilla unix make
POSIX C libraries
Files for instant program
Module Function
------ --------
browse.c interactive browser
general.h general definitions
info.c print information about the instances
main.c main entry, arg parsing, instance reading
tables.c table-specific formatting routines (TeX and tbl)
traninit.c translator initialization (read spec, etc.)
translate.c main translator
translate.h structure definitions for translation code
tranvar.c routines for handling "special variables"
util.c general utilities
Also required
1. Translation spec (transpec) files. (../transpecs/*.ts)
2. SDATA mapping files for mapping sdata entities. (../transpecs/*.sdata)
3. Character mapping files for mapping characters. (../transpecs/*.cmap)
Platforms tried on
OSF1 1.3 (i486)
Ultrix 4.2 (mips)
HP-UX 9.01 (hp 9000/700)
AIX 3.2 (rs6000)
SunOS [missing strerror()]
____________________________________________________________________________
General outline of program
------- ------- -- -------
To summarize in a sentence, instant reads the output of sgmls, builds a tree
of the instnace in memory, then traverses the tree in in-order, processing
the nodes according to a translation spec.
Element tree storage
------- ---- -------
The first thing instant must do is read the ESIS (output of sgmls) from the
specified file or stdin, forming a tree in memory. (Nothing makes sense
without an instance...) Each element of the instance is a node in the tree,
stored as a structure called Element_t. Elements contain content (what
else?), which is a mixture of data (#PCDATA, #CDATA, #RCDATA - all the same
in the ESIS), child elements, and PIs. Each 'chunk' of content is referred
to by a Content_t structure. A Content_t contains an enum that can point to
a string (data or PI), another Element_t. For example, if a <p> element
contains some characters, an <emphasis> element, some more characters,
a <function> element, then some more characters, it has 5 Content_t children
as an array.
Element_t's have pointers to their parents, and a next element in a linked
list (they're stored as a linked list, for cases when you'd want to quickly
travers all the nodes, in no particular order).
For convenience, Element_t's have an array of pointers to it's child
Element_t's. These are just pointers to the same thing contained in the
Content_t array, without the intervening data or PIs. This makes it easier
for the program to traverse the elements of the tree (it does not have to
be concerned with skipping data, etc.). There is an analagous array of
pointers for the data content, an array of (char *)'s. This makes it easier
to consider the immediate character content of an element.
Attributes are kept as an array of name-value mappings (using the typedef
Mapping_t). ID attributes are also stored in a separate list of ID value -
element pointer pairs so that it is quick to find an element by ID.
Other information kept about each element (in the Element_t struct) includes
the line number in the EISI where the element occurs, the input filename.
(These depend on sgmls being run with the "-l" option.) Also stored is
an element's order in its parent's collection of children and an element's
depth in the tree.
Translation specs
----------- -----
A translation spec is read into a linked list in memory. As the instance
tree is traversed, the transpecs are searched in order for a match. As a
rule, one should position the less specific transpecs later in the file.
Also, specs for seldom-used element are best placed later in the file, since
it takes cpu cycles to skip over them for each of the more-used elements.
During translation of a particular element, the list of Content_t structures
are processed in order. If a content 'chunk' is data, it is printed to
the output stream. If it is an element, the translation routine is called
for that elemen, recursively. Hence, in-order traversal.
Miscellaneous information displays
------------- ----------- --------
There are several informational display options available. They include:
- a list of element usage (-u) -- lists each element in the instance,
it's attributes, number of children, parent, data content 'nodes'.
- statistics about elements (-S) -- lists elements, number of times
each is used, percent of elements that this is, total char content
in that element, average number of characters in they element.
- show context of each element (-x) -- lists each element and its
context, looking up the tree (this is the same context that
would match the Context field of a transpec).
- show the hierarchy of the instance (-h) -- show an ascii 'tree' of
the instance, where elements deeper in the tree are indented more.
Numbers after the element name in parentheses are the number of
element content nodes and the number of data content nodes.
Interactive browser
----------- -------
Originally, the interactive browser was intended as a debugging aid for
the code developer. It was a way to examine a particular node of the
instance tree or process a subtree without being distracted by the rest
of the instance. Many of the commands test functionality of the query
and search code (such as testing whether a certain element has a given
relationship to the current position in the tree).
____________________________________________________________________________

View File

@ -0,0 +1,462 @@
/*
* Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
* All rights reserved.
*/
/*
* Copyright (c) 1994
* Open Software Foundation, Inc.
*
* Permission is hereby granted to use, copy, modify and freely distribute
* the software in this file and its documentation for any purpose without
* fee, provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation. Further, provided that the name of Open
* Software Foundation, Inc. ("OSF") not be used in advertising or
* publicity pertaining to distribution of the software without prior
* written permission from OSF. OSF makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
/*
* Copyright (c) 1996 X Consortium
* Copyright (c) 1995, 1996 Dalrymple Consulting
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the X Consortium and
* Dalrymple Consulting shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without prior
* written authorization.
*/
/* ________________________________________________________________________
*
* Module for interactive browsing.
*
* Entry points for this module:
* Browse() interactive browser
* ________________________________________________________________________
*/
#ifndef lint
static char *RCSid =
"$Header: /usr/src/docbook-to-man/Instant/RCS/browse.c,v 1.2 1996/06/02 21:46:10 fld Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "general.h"
static void PrElemPlusID(Element_t *);
static void ls_node(Element_t *, int, char **);
static void do_query(Element_t *, char *, char *);
static void do_find(Element_t *, char **);
/* ______________________________________________________________________ */
static char *br_help_msg[] = {
" ls List info about current element in tree",
" (context, children, attributes, etc.)",
" cd N ... Change to Nth elememt child, where N is shown by 'ls'.",
" N may also be '/' (top) or '..' (up).",
" cd id I Change to elememt whose ID is I",
" data N Show data of Nth data node",
" where Show current position in the tree",
" id I Show path to element with id I",
" (using '?' for I will lists all IDs and their paths)",
" find S Find elements matching spec S. Recognized syntaxes:",
" find attr <name> <value>",
" find cont <string>",
" find parent <gi-name>",
" find child <gi-name>",
" find gi <gi-name>",
" q rel gi Query: report if elem 'gi' has relation to current elem",
" ('rel' is one of 'child parent ancestor descendant",
" sibling sibling+ sibling+1 sibling- sibling-1 cousin')",
"",
" tran [outfile]",
" Translate into 'outfile' (stdout)",
" stat Print statistics (how often elements occur, etc.)",
" sum Print elem usage summary (# of children, depth, etc.)",
" tree Print document hierarchy as a tree",
" cont Print context of each element",
NULL
};
/* ______________________________________________________________________ */
void
Browse()
{
char buf[256], *cmd, **av, **sv;
char *Prompt;
Element_t *ce; /* current element */
Element_t *e;
int i, n, ac;
if (slave) Prompt = "=>\n";
else Prompt = "=> ";
ce = DocTree;
while (fputs(Prompt, stdout)) {
if (!fgets(buf, 256, stdin)) break;
stripNL(buf);
if (buf[0] == EOS) {
fputs(Prompt, stdout);
continue;
}
ac = 20;
av = Split(buf, &ac, S_ALVEC);
if (ac > 0) cmd = av[0];
if (!cmd || !(*cmd)) continue;
if (!strcmp(cmd, "ls")) ls_node(ce, ac, av);
else if (!strcmp(cmd, "cd")) {
if (av[1]) {
if (ac == 3 && !strcmp(av[1], "id")) {
if ((e = FindElemByID(av[2]))) ce = e;
else printf("Element with ID '%s' not found.\n", av[2]);
continue;
}
for (i=1; i<ac; i++) {
if (!strcmp(av[i], "..")) {
if (ce->parent) ce = ce->parent;
continue;
}
if (!strcmp(av[i], "/")) {
if (ce->parent) ce = DocTree;
continue;
}
if (!isdigit(*av[i])) {
printf("Expecting digit, '..', or '/', got '%s'.\n",
av[i]);
break;
}
n = atoi(av[i]);
if (n < ce->necont) ce = ce->econt[n];
else {
printf("Must be in range 0 - %d.\n", ce->necont);
break;
}
}
}
}
else if (!strcmp(cmd, "data")) {
if (av[1] && isdigit(*av[1])) {
n = atoi(av[1]);
if (n < ce->ndcont) {
printf(ce->dcont[n]);
fputs("\n", stdout);
}
else if (ce->ndcont == 0)
printf("No data at this node.\n");
else printf("Must be in range 0 - %d.\n", ce->ndcont);
}
}
/* show where we are in the tree */
else if (!strcmp(cmd, "where")) PrintLocation(ce, stdout);
/* show where we are in the tree */
else if (!strcmp(cmd, "pwd")) PrElemPlusID(ce);
/* perform query with yes/no answer */
else if (!strcmp(cmd, "q") && av[1] && av[2])
do_query(ce, av[1], av[2]);
/* perform query printing paths to matching elements */
else if (!strcmp(cmd, "find") && av[1] && av[2])
do_find(ce, av);
/* list locations where specified ID(s) occur */
else if (!strcmp(cmd, "id")) {
if (ac <= 1) continue;
if (*av[1] == '?') PrintIDList();
else {
/* short: "id i1 i2 ...", long: "id -l i1 i2 ..." */
if (!strcmp(av[1], "-l")) n = 2;
else n = 1;
for (i=n; i<ac; i++) {
if ((e = FindElemByID(av[i]))) {
if (n == 2) { /* long (multiline) format */
if (n != i) putchar('\n');
PrintLocation(e, stdout);
}
else PrElemPlusID(e);
}
else printf("Element with ID '%s' not found.\n", av[i]);
}
}
}
/* show and set variables */
else if (!strcmp(cmd, "show") && av[1]) {
printf("%s\n", FindMappingVal(Variables, av[1]));
}
else if (!strcmp(cmd, "set") && av[1] && av[2]) {
SetMappingNV(Variables, av[1], av[2]);
}
/* print summary of tag usage */
else if (!strcmp(cmd, "sum")) {
if (ac > 1) PrintElemSummary(ce);
else PrintElemSummary(DocTree);
}
/* print element tree */
else if (!strcmp(cmd, "tree")) {
if (ac > 1) PrintElemTree(ce);
else PrintElemTree(DocTree);
}
/* print statistics */
else if (!strcmp(cmd, "stat")) {
if (ac > 1) PrintStats(ce);
else PrintStats(DocTree);
}
/* print context of each element of tree */
else if (!strcmp(cmd, "cont")) {
if (ac > 1) PrintContext(ce);
else PrintContext(DocTree);
}
/* print translation, given transpec */
else if (!strcmp(cmd, "tran")) {
FILE *fp;
if (ac > 1){
if (!(fp = fopen(av[1], "w"))) {
perror("Can not open output file");
continue;
}
}
else fp = stdout;
DoTranslate(ce, fp);
if (ac > 1) fclose(fp);
}
else if (!strcmp(cmd, "help") || *cmd == '?') {
sv = br_help_msg;
while (*sv) puts(*sv++);
}
/* quit (control-D also works) */
else if (!strcmp(cmd, "quit")) break;
else
fprintf(stderr, "Unknown command '%s' - ingored.\n", cmd);
}
putc(NL, stdout);
}
/* ______________________________________________________________________ */
/* Do the "ls" command.
* Arguments:
* Pointer to element under consideration.
* Arg count from command line (this command, not the shell command).
* Arg vector.
*/
static void
ls_node(
Element_t *e,
int ac,
char **av
)
{
int i;
char buf[LINESIZE];
if (ac > 1 && !strcmp(av[1], "-n")) {
for(i=0; i<e->ncont; i++) {
if (IsContElem(e,i)) printf("%s\n", ContElem(e,i)->gi);
else if (IsContData(e,i)) printf("#data %s\n", ContData(e,i));
else if (IsContPI(e,i)) printf("#pi %s\n", ContData(e,i));
}
return;
}
printf("Element: %s\tLineNumber: %d\n", e->gi, e->lineno);
if (e->parent)
printf("Context: %s\n", FindContext(e, 20, buf));
if (e->natts) {
printf("%d attributes:\n", e->natts);
for (i=0; i<e->natts; i++)
printf("\t%2d: %s = '%s'\n", i, e->atts[i].name, e->atts[i].sval);
}
if (e->entity) {
printf("Entity & notation information:\n");
if (e->entity->ename)
printf("Entity name: %s\n", e->entity->ename);
if (e->entity->nname)
printf("Notation name: %s\n", e->entity->nname);
if (e->entity->sysid)
printf("Sys id: %s\n", e->entity->sysid);
if (e->entity->pubid)
printf("Pub id: %s\n", e->entity->pubid);
if (e->entity->fname)
printf("Filename: %s\n", e->entity->fname);
}
if (e->my_eorder >= 0)
printf("My order among my siblings: %d\n", e->my_eorder);
if (e->necont) {
printf("%d child element nodes:\n", e->necont);
for(i=0; i<e->necont; i++) printf("\t%2d: %s\n", i, e->econt[i]->gi);
}
if (e->ndcont) {
printf("%d child data nodes:\n", e->ndcont);
for(i=0; i<e->ndcont; i++) {
if (strlen(e->dcont[i]) < 40)
printf("\t%2d: %s\n", i, e->dcont[i]);
else
printf("\t%2d: %-40.40s...\n", i, e->dcont[i]);
}
}
}
/* ______________________________________________________________________ */
/* Perform query. Syntax: find relationship gi. Tells whether gi has
* given relationship to current element. Result (message) sent to stdout.
* Args:
* Pointer to element under consideration.
* Pointer to name of relationship. (see FindRelByName() for names)
* Pointer to GI to look for.
*/
static void
do_query(
Element_t *e,
char *rel,
char *gi
)
{
char *cp;
Relation_t r;
Element_t *ep;
for (cp=gi; *cp; cp++) if (islower(*cp)) *cp = toupper(*cp);
if ((r = FindRelByName(rel)) == REL_Unknown) {
return;
}
ep = QRelation(e, gi, r);
printf("%s, '%s' is%s %s of '%s'.\n", (ep ? "Yes" : "No"), gi,
(ep ? "" : " not"), rel, e->gi);
}
/* ______________________________________________________________________ */
/* Print path to the element and its ID (if it has one) on a single line.
* Arguments:
* Pointer to element under consideration.
*/
static void
PrElemPlusID(
Element_t *e
)
{
char buf[LINESIZE];
if (e->id) printf("%s -- ID=%s\n", FindElementPath(e, buf), e->id);
else printf("%s\n", FindElementPath(e, buf));
}
/* ______________________________________________________________________ */
/* Print path to the element and its ID (if it has one) on a single line.
* Arguments:
* Pointer to element under consideration.
*/
static void
match_gi(
Element_t *e,
char **av
)
{
if (!strcmp(av[1], e->gi)) PrElemPlusID(e);
}
/* Shorthand for defining simple finctions, which are just interfaces to
* calling QRelation(). DescendTree() only passes ptr to element. */
#define MATCH(Fun,Rel) \
static void Fun(Element_t *e, char **av) \
{ if (QRelation(e, av[1], Rel)) PrElemPlusID(e); }
MATCH(match_parent, REL_Parent)
MATCH(match_child, REL_Child)
MATCH(match_anc, REL_Ancestor)
MATCH(match_desc, REL_Descendant)
MATCH(match_sib, REL_Sibling)
static void
match_attr(
Element_t *e,
char **av
)
{
char *atval;
if ((atval = FindAttValByName(e, av[1])) && !strcmp(av[2], atval))
PrElemPlusID(e);
}
static void
match_cont(
Element_t *e,
char **av
)
{
int i;
for (i=0; i<e->ncont; i++) {
if (IsContData(e,i) && strstr(ContData(e,i), av[1])) {
PrElemPlusID(e);
return;
}
}
}
/* Find an element, given the criteria on its command line.
* Arguments:
* Pointer to element under consideration.
*/
static void
do_find(
Element_t *e,
char **av
)
{
av++;
if (!strcmp(av[0], ".")) av++;
else e = DocTree;
if (!strcmp(av[0], "gi")) DescendTree(e, match_gi, 0, 0, av);
else if (!strcmp(av[0], "attr")) DescendTree(e, match_attr, 0, 0, av);
else if (!strcmp(av[0], "parent")) DescendTree(e, match_parent, 0, 0, av);
else if (!strcmp(av[0], "child")) DescendTree(e, match_child, 0, 0, av);
else if (!strcmp(av[0], "cont")) DescendTree(e, match_cont, 0, 0, av);
else if (!strcmp(av[0], "sib")) DescendTree(e, match_sib, 0, 0, av);
else if (!strcmp(av[0], "desc")) DescendTree(e, match_desc, 0, 0, av);
else if (!strcmp(av[0], "anc")) DescendTree(e, match_anc, 0, 0, av);
else fprintf(stderr, "Unknown find command: %s.\n", av[0]);
}
/* ______________________________________________________________________ */

View File

@ -0,0 +1,329 @@
/*
* Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
* All rights reserved.
*/
/*
* Copyright (c) 1994
* Open Software Foundation, Inc.
*
* Permission is hereby granted to use, copy, modify and freely distribute
* the software in this file and its documentation for any purpose without
* fee, provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation. Further, provided that the name of Open
* Software Foundation, Inc. ("OSF") not be used in advertising or
* publicity pertaining to distribution of the software without prior
* written permission from OSF. OSF makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
/*
* Copyright (c) 1996 X Consortium
* Copyright (c) 1995, 1996 Dalrymple Consulting
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the X Consortium and
* Dalrymple Consulting shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without prior
* written authorization.
*/
/* ________________________________________________________________________
*
* Common definitions for "instant" program.
* ________________________________________________________________________
*/
#ifdef STORAGE
#ifndef lint
static char *gen_h_RCSid =
"$Header: /usr/src/docbook-to-man/Instant/RCS/general.h,v 1.5 1996/06/11 20:25:03 fld Exp $";
#endif
#endif
/* string/numeric/character definitions */
#define EOS '\0'
#define NL '\n'
#define TAB '\t'
#define CR '\r'
#define ANCHOR '^'
/* bigmask/flags for the Split() function */
#define S_STRDUP 0x01
#define S_ALVEC 0x02
/* Command codes (1st char of esis lines) from sgmls. See its manpage. */
#define CMD_DATA '-'
#define CMD_OPEN '('
#define CMD_CLOSE ')'
#define CMD_ATT 'A'
#define CMD_D_ATT 'D'
#define CMD_NOTATION 'N'
#define CMD_EXT_ENT 'E'
#define CMD_INT_ENT 'I'
#define CMD_SYSID 's'
#define CMD_PUBID 'p'
#define CMD_FILENAME 'f'
#define CMD_LINE 'L'
#define CMD_PI '?'
#define CMD_SUBDOC 'S'
#define CMD_SUBDOC_S '{'
#define CMD_SUBDOC_E '}'
#define CMD_EXT_REF '&'
#define CMD_APPINFO '#'
#define CMD_CONFORM 'C'
/* Some sizes */
#define MAX_DEPTH 40
#define LINESIZE 60000
/* Name of library env variable, and default value. */
#ifndef TPT_LIB
#define TPT_LIB "TPT_LIB"
#endif
#ifndef DEF_TPT_LIB
#define DEF_TPT_LIB "/usr/share/sgml/transpec"
#endif
/* Relationships - for querying */
typedef enum {
REL_None, REL_Parent, REL_Child, REL_Ancestor, REL_Descendant,
REL_Sibling, REL_Preceding, REL_ImmPreceding, REL_Following,
REL_ImmFollowing, REL_Cousin, REL_Unknown
} Relation_t;
/* Initial map sizes (IMS) */
#define IMS_relations 3
#define IMS_setvar 3
#define IMS_incvar 3
#define IMS_sdata 50
#define IMS_sdatacache 30
#define IMS_variables 20
#define IMS_attnames 50
#define IMS_elemnames 50
/* ----- typedef and other misc definitions ----- */
#ifndef TRUE
#define TRUE (1 == 1)
#endif
#ifndef FALSE
#define FALSE (1 == 0)
#endif
typedef short bool;
/* ----- structure definitions ----- */
/* We use this for variables, attributes, etc., so the caller only needs an
* opaque handle to the thing below, not worrying about array management. */
typedef struct {
char *name; /* name of the thing */
char *sval; /* string value */
} Mapping_t;
typedef struct {
int n_alloc; /* number of elements allocated */
int n_used; /* number of elements used */
int slot_incr; /* increment for allocating slots */
int flags; /* info about this set of mappings */
Mapping_t *maps; /* array of mappings */
} Map_t;
/* ______________________________________________________________________ */
/* Information about an entity reference. Not all fields will be used
* at once. */
typedef struct _ent {
char *type; /* entity type */
char *ename; /* entity name */
char *nname; /* notation name */
char *sysid; /* sys id */
char *pubid; /* pub id */
char *fname; /* filename */
struct _ent *next; /* next in linked list */
} Entity_t;
/* Content (child nodes) of an element (node in the tree) -- both data
* and other elements. */
typedef struct {
char type; /* element, data, or pi? */
union {
struct _elem *elem; /* direct children of this elem */
char *data; /* character data of this elem */
} ch;
} Content_t;
/* An element (node in the tree) */
typedef struct _elem {
char *gi; /* element GI */
Content_t *cont; /* content - element & data children */
int ncont; /* # of content/children */
struct _elem **econt; /* element children */
int necont; /* # of element children */
char **dcont; /* character data children */
int ndcont; /* # of data children */
Mapping_t *atts; /* array of attributes */
int natts; /* # of attributes */
Entity_t *entity; /* ext entity & notation info */
char *id; /* for linking */
int index; /* an internal bookkeeping mechanism */
int depth; /* how deep in tree */
int lineno; /* line number */
char *infile; /* input filename */
int my_eorder; /* order of this elem of its parent */
struct _elem *parent; /* this elem's direct parent */
struct _elem *next; /* kept in linked list */
void *trans; /* pointer to translation spec */
/* I'm not crazy about this, but it works */
int gen_trans[2]; /* refs to generated trans specs */
int processed; /* was this node processed? */
} Element_t;
/* For mapping of element IDs to elements themselves. */
typedef struct id_s {
char *id; /* ID of the element */
Element_t *elem; /* pointer to it */
struct id_s *next;
} ID_t;
/* ----- global variable declarations ----- */
#ifdef STORAGE
# define def
#else
# define def extern
#endif
def Element_t *DocTree; /* root of document tree */
def char **UsedElem; /* a unique list of used elem names */
def int nUsedElem; /* number of used elem names */
def char **UsedAtt; /* a unique list of used attrib names */
def int nUsedAtt; /* number of used attrib names */
def ID_t *IDList; /* list of IDs used in the doc */
def Map_t *Variables; /* general, global variables */
def Map_t *SDATAmap; /* SDATA mappings */
def Map_t *PImap; /* Processing Instruction mappings */
def Entity_t *Entities; /* list of entities */
def FILE *outfp; /* where output is written */
def char *tpt_lib; /* TPT library directory */
def int verbose; /* flag - verbose output? */
def int warnings; /* flag - show warnings? */
def int interactive; /* flag - interactive browsing? */
def int slave; /* are we slave to another process? */
def int fold_case; /* flag - fold case of GIs? */
/* ----- some macros for convenience and ease of code reading ----- */
#define stripNL(s) { char *_cp; if ((_cp=strchr(s, NL))) *_cp = EOS; }
/* Similar to calloc(), malloc(), and realloc(), but check for success.
* Args to all:
* (1) number of 'elements' to allocate
* (2) variable to point at allocated space
* (3) type of 'element'
* Eg: Calloc(5, e, Element_t) replaces
* if (!(e = (Element_t *)calloc(5, sizeof(Element_t))) {
* ... handle error ... ;
* }
*/
#define Calloc(N,V,T) \
{ if (!((V) = (T *)calloc((size_t)N, sizeof(T)))) { \
perror("Calloc failed -- out of memory. Bailing out."); exit(1); \
}; memset((void *) (V), 0, (size_t) sizeof(T)); }
#define Malloc(N,V,T) \
{ if (!((V) = (T *)malloc((size_t)N*sizeof(T)))) { \
perror("Malloc failed -- out of memory. Bailing out."); exit(1); \
}; memset((void *) (V), 0, (size_t) sizeof(T)); }
#define Realloc(N,V,T) \
{ if (!((V) = (T *)realloc(V,(size_t)N*sizeof(T)))) { \
perror("Realloc failed -- out of memory. Bailing out."); exit(1); \
} }
/* similar to strcmp(), but check first chars first, for efficiency */
#define StrEq(s1,s2) (s1[0] == s2[0] && !strcmp(s1,s2))
/* similar to isspace(), but check for blank or tab - without overhead
* of procedure call */
#define IsWhite(c) (c == ' ' || c == TAB || c == NL)
#define ContType(e,i) (e->cont[i].type)
#define ContData(e,i) (e->cont[i].ch.data)
#define ContElem(e,i) (e->cont[i].ch.elem)
#define IsContData(e,i) (e->cont[i].type == CMD_DATA)
#define IsContElem(e,i) (e->cont[i].type == CMD_OPEN)
#define IsContPI(e,i) (e->cont[i].type == CMD_PI)
/* ----- function prototypes ----- */
/* things defined in util.c */
Element_t *QRelation(Element_t *, char *, Relation_t);
Relation_t FindRelByName(char *);
char *FindAttValByName(Element_t *, char *);
char *FindContext(Element_t *, int, char *);
char *AddElemName(char *);
char *AddAttName(char *);
char *ExpandString(char *);
void OutputString(char *, FILE *, int);
char *LookupSDATA(char *);
FILE *OpenFile(char *);
char *FilePath(char *);
char *FindElementPath(Element_t *, char *);
char *NearestOlderElem(Element_t *, char *);
void PrintLocation(Element_t *, FILE *);
char **Split(char *, int *, int);
void DescendTree(Element_t *, void(*)(), void(*)(), void(*)(), void *);
Map_t *NewMap(int);
Mapping_t *FindMapping(Map_t *, const char *);
char *FindMappingVal(Map_t *, const char *);
void SetMapping(Map_t *, const char *);
void SetMappingNV(Map_t *, const char *, const char *);
void AddID(Element_t *, char *);
Element_t *FindElemByID(char *);
/* things defined in translate.c */
void DoTranslate(Element_t*, FILE *);
void ExpandVariables(char*, char*, Element_t*);
/* things defined in traninit.c */
void ReadTransSpec(char *);
/* things defined in tranvar.c */
char *Get_A_C_value(const char *);
/* things defined in info.c */
void PrintContext(Element_t *e);
void PrintElemSummary(Element_t *);
void PrintElemTree(Element_t *);
void PrintStats(Element_t *);
void PrintIDList();
/* things defined in table.c */
void CALStable(Element_t *, FILE *, char **, int);
/* ----- other declarations ----- */
#ifdef ultrix
#define strdup(s) strcpy((char *)malloc(strlen(s)+1), s)
#endif

View File

@ -0,0 +1,100 @@
/*
* Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
* All rights reserved.
*/
/*
* Copyright (c) 1994
* Open Software Foundation, Inc.
*
* Permission is hereby granted to use, copy, modify and freely distribute
* the software in this file and its documentation for any purpose without
* fee, provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation. Further, provided that the name of Open
* Software Foundation, Inc. ("OSF") not be used in advertising or
* publicity pertaining to distribution of the software without prior
* written permission from OSF. OSF makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
/*
* Copyright (c) 1996 X Consortium
* Copyright (c) 1995, 1996 Dalrymple Consulting
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the X Consortium and
* Dalrymple Consulting shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without prior
* written authorization.
*/
/* ________________________________________________________________________
*
* Hypermedia-related facilities.
*
* Entry points for this module:
* AddID(elem, idval) add elem-id pair to list of known ids
* FindElemByID(idval) find elem by id
* ________________________________________________________________________
*/
#ifndef lint
static char *RCSid =
"$Header: /usr/src/docbook-to-man/Instant/RCS/hyper.c,v 1.2 1996/06/02 21:46:10 fld Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <memory.h>
#include <sys/types.h>
#include "general.h"
/* ______________________________________________________________________ */
void
AddID(Element *e, char *idval)
{
static ID *id_last;
if (!IDList) {
Calloc(1, id_last, ID);
IDList = id_last;
}
else {
Calloc(1, id_last->next, ID);
id_last = id_last->next;
}
id_last->elem = e;
id_last->id = idval;
}
Element *
FindElemByID(char *idval)
{
ID *id;
for (id=IDList; id; id=id->next)
if (!strcmp(id->id, idval)) return id->elem;
return 0;
}
/* ______________________________________________________________________ */

View File

@ -0,0 +1,300 @@
/*
* Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
* All rights reserved.
*/
/*
* Copyright (c) 1994
* Open Software Foundation, Inc.
*
* Permission is hereby granted to use, copy, modify and freely distribute
* the software in this file and its documentation for any purpose without
* fee, provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation. Further, provided that the name of Open
* Software Foundation, Inc. ("OSF") not be used in advertising or
* publicity pertaining to distribution of the software without prior
* written permission from OSF. OSF makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
/*
* Copyright (c) 1996 X Consortium
* Copyright (c) 1995, 1996 Dalrymple Consulting
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the X Consortium and
* Dalrymple Consulting shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without prior
* written authorization.
*/
/* ________________________________________________________________________
*
* Functions for printing information about an instance in the 'instant'
* program. Most of these are fairly short and simple.
*
* Entry points for this module:
* PrintElemSummary(elem) print summary info of each element
* PrintContext(elem) print context of each element
* PrintElemTree(elem) print tree of document
* PrintStats(elem) print statistics about doc tree
* PrintIDList(elem) print list of IDs and element context
* Most Print*() functions start at subtree pointed to by 'elem'.
* ________________________________________________________________________
*/
#ifndef lint
static char *RCSid =
"$Header: /usr/src/docbook-to-man/Instant/RCS/info.c,v 1.2 1996/06/02 21:46:10 fld Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "general.h"
/* ______________________________________________________________________ */
/* Print a summary of each tag use in the instance. Things like depth in
* the tree, number of children, parent, attributes.
*/
/* Do the actual printing. Print the info about the node. If null,
* print a header for the columns.
* Arguments:
* Pointer to element structure of the node to print.
*/
static void
print_summ(
Element_t *e
)
{
int i, n, dsize;
char *hfmt="%-18.18s %4s %5s %4s %4s %s\n";
char *fmt ="%-18.18s %4d %5d %4d %4d %s\n";
if (e == NULL) {
fprintf(outfp, hfmt, "Element", "Att", "Data", "Chd", "Dep", "Parent");
return;
}
for (i=0,n=0; i<e->ncont; i++) if (IsContElem(e,i)) n++;
for (i=0,dsize=0; i<e->ncont; i++)
if (IsContElem(e,i)) dsize += strlen(e->cont[i].ch.data);
fprintf(outfp, fmt, e->gi, e->natts, dsize, n, e->depth,
e->parent ? e->parent->gi : "-");
for (i=0; i<e->natts; i++) {
fprintf(outfp, "%45d: %s = %s\n", i, e->atts[i].name,
e->atts[i].sval ? e->atts[i].sval : "empty");
}
}
/* Descend the tree, calling processing routine.
* Arguments:
* Pointer to element structure at top of tree to traverse.
*/
void
PrintElemSummary(
Element_t *e
)
{
print_summ(0);
DescendTree(e, print_summ, 0, 0, 0);
}
/* ______________________________________________________________________ */
/* Print the context of each tag in the instance (i.e. the tag with its
* ancestors).
*/
/* Do the actual printing. Print the context of the node.
* Arguments:
* Pointer to element structure of the node to print.
*/
static void
print_context(
Element_t *e
)
{
char buf[LINESIZE];
fprintf(outfp, "%-22s %s\n", e->gi, FindContext(e, 10, buf));
}
/* Descend the tree, calling processing routine.
* Arguments:
* Pointer to element structure at top of tree to traverse.
*/
void
PrintContext(
Element_t *e
)
{
fprintf(outfp, "%-22s %s\n", "Element", "Context");
fprintf(outfp, "%-22s %s\n", "---------------", "-----------");
DescendTree(e, print_context, 0, 0, 0);
putc(NL, outfp);
}
/* ______________________________________________________________________ */
/* Print tree of the instance. GI's are printed indented by their depth
* in the tree.
*/
/* Do the actual printing. Print the element name, indented the right amount.
* Arguments:
* Pointer to element structure of the node to print.
*/
static void
print_indent(
Element_t *e
)
{
int i, ne, nd;
for(i=0; i<e->depth; i++) fputs(". ", outfp);
for(i=0,ne=0; i<e->ncont; i++) if (IsContElem(e,i)) ne++;
for(i=0,nd=0; i<e->ncont; i++) if IsContData(e,i) nd++;
fprintf(outfp, "%s (%d,%d)\n", e->gi, ne, nd);
}
/* Descend the tree, calling processing routine.
* Arguments:
* Pointer to element structure at top of tree to traverse.
*/
void
PrintElemTree(
Element_t *e
)
{
DescendTree(e, print_indent, 0, 0, 0);
putc(NL, outfp);
}
/* ______________________________________________________________________ */
/* Print some statistics about the instance.
*/
/* Accumulate the totals for the statistics.
* Arguments:
* Pointer to element structure of the node to print.
* Pointer to the total number of elements.
* Pointer to the total amount of content data.
* Pointer to the maximum depth of tree.
*/
static void
acc_tots(
Element_t *e,
int *tot_el,
int *tot_data,
int *max_depth
)
{
int i;
for(i=0; i<e->necont; i++)
acc_tots(e->econt[i], tot_el, tot_data, max_depth);
for (i=0; i<e->necont; i++) (*tot_el)++;
for (i=0; i<e->ndcont; i++) (*tot_data) += strlen(e->dcont[i]);
if (e->depth > (*max_depth)) *max_depth = e->depth;
}
/* Descend the tree (recursively), collecting the statistics.
* Arguments:
* Pointer to element structure of the node to print.
* Pointer to the total number of elements.
* Pointer to the total amount of content data.
* Pointer to the maximum depth of tree.
*/
static void
elem_usage(
Element_t *e,
char *name,
int *n_used,
int *nchars
)
{
int i;
if (!strcmp(name, e->gi)) {
(*n_used)++;
for (i=0; i<e->ncont; i++)
if (IsContData(e,i)) (*nchars) += strlen(ContData(e,i));
}
for(i=0; i<e->necont; i++)
elem_usage(e->econt[i], name, n_used, nchars);
}
/* Descend the tree, calling processing routine.
* Arguments:
* Pointer to element structure at top of tree to traverse.
*/
void
PrintStats(
Element_t *top
)
{
int i, n;
int dif_el=0, tot_el=0, tot_data=0, nchars, max_depth=0;
float pct;
fprintf(outfp, "%-22s %s %s\n", "Element name", "Occurrances", "Character Content");
fprintf(outfp, "%-22s %s %s\n", "---------------", "-----------", "-----------------");
acc_tots(top, &tot_el, &tot_data, &max_depth);
for (i=0; i<nUsedElem; i++) {
n = 0;
nchars = 0;
elem_usage(top, UsedElem[i], &n, &nchars);
if (n > 0) {
pct = 100.0 * (float)n / (float)tot_el;
fprintf(outfp, "%-22s %4d %4.1f%% %6d %4d\n", UsedElem[i],
n, pct, nchars, (nchars/n));
dif_el++;
}
}
fprintf(outfp, "\nTotal of %d elements used, %d different ones.\n",
tot_el, dif_el);
fprintf(outfp, "Total character data: %d.\n", tot_data);
fprintf(outfp, "Maximum element depth: %d.\n", max_depth);
putc(NL, outfp);
}
/* ______________________________________________________________________ */
/* Print list of: ID, GI, input file, line number, separated by colons.
* This is better for other programs to manipulate (like for keeping a
* database of IDs in documents) than humans to read.
*/
void
PrintIDList()
{
ID_t *id;
Element_t *ep;
for (id=IDList; id; id=id->next) {
ep = id->elem;
fprintf(outfp, "%s:%s:%s:%d\n", id->id, ep->gi,
ep->infile?ep->infile:"-", ep->lineno);
}
}
/* ______________________________________________________________________ */

View File

@ -0,0 +1,183 @@
...\"
...\" Copyright (c) 1994
...\" Open Software Foundation, Inc.
...\"
...\" Permission is hereby granted to use, copy, modify and freely distribute
...\" the software in this file and its documentation for any purpose without
...\" fee, provided that the above copyright notice appears in all copies and
...\" that both the copyright notice and this permission notice appear in
...\" supporting documentation. Further, provided that the name of Open
...\" Software Foundation, Inc. ("OSF") not be used in advertising or
...\" publicity pertaining to distribution of the software without prior
...\" written permission from OSF. OSF makes no representations about the
...\" suitability of this software for any purpose. It is provided "as is"
...\" without express or implied warranty.
...\"
...\" Copyright (c) 1996 X Consortium
...\" Copyright (c) 1996 Dalrymple Consulting
...\"
...\" Permission is hereby granted, free of charge, to any person obtaining a copy
...\" of this software and associated documentation files (the "Software"), to deal
...\" in the Software without restriction, including without limitation the rights
...\" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
...\" copies of the Software, and to permit persons to whom the Software is
...\" furnished to do so, subject to the following conditions:
...\"
...\" The above copyright notice and this permission notice shall be included in
...\" all copies or substantial portions of the Software.
...\"
...\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
...\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
...\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
...\" X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
...\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
...\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
...\" OTHER DEALINGS IN THE SOFTWARE.
...\"
...\" Except as contained in this notice, the names of the X Consortium and
...\" Dalrymple Consulting shall not be used in advertising or otherwise to
...\" promote the sale, use or other dealings in this Software without prior
...\" written authorization.
...\"
...\" Translated with /usr/local/lib/tpt/ref-man.ts by fld on cord, Wed 07 Feb 1996, 21:59
.Dd September 5, 1996
.Os FreeBSD 2.2
.Dt SGMLFMT 1
.Sh "NAME"
instant - manipulates ESIS from parsed SGML instance
.Sh "Synopsis"
.na
.Pp
\fBinstant\fP [ \fB-bhuvxHISW\fP ] [ \fB-t\fP \fIfile\fP] [ \fB-o\fP \fIfile\fP] [ \fB-D\fP \fIvariable\fP\fB=\fP\fIvalue\fP ...] [ \fB-i\fP \fIid\fP] [ \fB-l\fP \fIdirectory\fP] [\fIfile\fP]
.ad
.Sh "DESCRIPTION"
.Pp
The \fBinstant\fP program manipulates an SGML document instance in a variety of ways,
including translating into a form suitable for a formatting application and printing information about this instance.
Input to \fBinstant\fP is the output of \fBsgmls\fP, whose format is called Element Structure Information Set (ESIS).
.Sh "FLAGS"
.Pp
The following are the possible command line options to \fBinstant\fP. Output is sent to the standard output, except where otherwise noted.
.\"'br\" labeled list
.Bl -tag -width Ds
.It "\fB-t\fP \fIfile\fP"
Translate the SGML instance to another form, usually suitable for a formatting application.
The \fIfile\fP is called a translation spec, which specifies how the tags are to be translated. See \fBtranspec\fP(4).
By convention, names for \fIfile\fP use the suffix \fB.ts\fP, for \fItranslation spec\fP.
.It "\fB-d\fP"
"Data hack" \(em strip newline at the beginning of data records
.It "\fB-f \fIlength\fR"
Set the threshold for the length, in characters,
of an <Entry>, over which it is called a block of filled text, to \fIlength\fR.
.It "\fB-o\fP \fIfile\fP "
Write all output (except error and warning messages) to file \fIfile\fP. By default, output goes to stdout.
.It "\fB-h\fP"
Print a text representation of the hierarchy of the instance elements.
The deeper an element is in the tree, the more it is indented. The data content is not printed.
.It "\fB-u\fP"
Print a summary of the usage of each element in the instance.
Information given includes attributes, number of children, and depth in the hierarchy.
.It "\fB-S\fP"
Print some statistics about element usage in the instance, including how often each element is used
and how much PCDATA is contained.
.It "\fB-x\fP"
Print the context of each element in the instance, from each element to the root of the document tree.
.It "\fB-v\fP"
Validate the SGML instance based on the set of constraints or descriptions in the transpec file.
This flags tells \fBinstant\fP to turn off normal output, leaving only diagnostics.
.It "\fB-l\fP \fIdirectory\fP"
Try to read the translation specs or other files from in the directory \fIdirectory\fP
if not found in the current directory.
This is called the library directory.
The environment variable \fITPT_LIB\fP may also be used to specify this.
.It "\fB-b\fP"
Interactive browser mode. The user is prompted for actions,
which include moving among and examining the various nodes in the hierarchy of the instance, displaying information about them, etc.
.It "\fB-I\fP"
List the IDs of all elements in the instance that have an ID. The format is more suitable for other programs than humans.
Lines show the ID, element GI, filename, and line, separated by colons.
(This depends on the \fB-l\fP option to \fBsgmls\fP which provide filenames and line numbers.)
.It "\fB-i\fP \fIid\fP"
When translating the instance, begin processing at the element whose ID is \fIid\fP instead of the topmost element.
.It "\fB-D\fP \fIvariable\fP\fB=\fP\fIvalue\fP"
Define the variable \fIvariable\fP with value \fIvalue\fP.
.It "\fB-W\fP"
Do not print warning messages.
.It "\fB-H\fP"
Print a help message briefly describing the options.
.It "\fIfile\fP"
Read the instance from the file \fIfile\fP.
This is expected to be the output of the program \fBsgmls\fP.
If not specified, \fBinstant\fP reads the instance from its standard input.
.El
.\"'br\" labeled list end
.Pp
In some cases it makes no sense to combine options.
This is especially true if one of the options is to perform a translation. No checking is done for this.
.Sh "INTERACTIVE BROWSER"
.Pp
These are the commands to the interactive browser:
.Bl -tag -width Ds
.\"'br\" labeled list
.It "\fBcd\fP \fIargs ...\fP"
Change to a different element in the hierarchy.
\fBcd\fP \fBid\fP \fIid\fP will change to the element whose ID is \fIid\fP.
\fBcd\fP \fIN\fP will change to the \fIN\fPth child element of the current element.
Several values of \fIN\fP may be specified, so the program will change to successively descending elements in the hierarchy.
The string \fB..\fP may appear for \fIN\fP to move up a level in the hierarchy (like in a unix file system).
A \fB/\fP may be specified for \fIN\fP to change to the top of the hierarchy.
.It "\fBcont\fP"
Print the context of each element.
.It "\fBdata\fP \fIN\fP"
Show the data content (PCDATA, RCDATA, and DATA) of child node N.
.It "\fBfind\fP \fIspec\fP"
Find paths to elements matching \fIspec\fP, where \fIspec\fP may be one of:
.Bl -tag -width Ds
.\".RS +\n(INu
.It "\fBparent\fP \fIgi\fP"
Find all elements whose parent element is \fIgi\fP.
.It "\fBchild\fP \fIgi\fP"
Find all elements which have a child element \fIgi\fP.
.It "\fBgi\fP \fIgi\fP"
Find all elements whose name is \fIgi\fP.
.It "\fBattr\fP \fIname\fP \fIvalue\fP"
Find all elements that have a attribute \fIname\fP that have a value \fIvalue\fP.
.\".RE
.El
.It "\fBid\fP \fIID\fP"
Show location of element whose ID is \fIID\fP.
If \fIID\fP is \fB?\fP, it will list all IDs with the paths to them.
.It "\fBls\fP"
List information about the current element in the hierarchy.
This includes element name, line number in instance, context, attributes and their values, child elements, data directly within this element,
and the order of the current element among its siblings.
.It "\fBq\fP \fIrelation\fP \fIelement\fP"
Report whether or not the current element has the relation \fIrelation\fP to the named element \fIelement\fP.
Values of \fIrelation\fP are the same as for \fB_followrel\fP in \fBtranspec\fP reference page.
.It "\fBstat\fP"
Show statistics about the hierarchy.
.It "\fBsum\fP"
Show a tag usage summary about the hierarchy.
.It "\fBtran\fP \fIoutfile\fP"
Write translated output to file \fIoutfile\fP.
If \fIoutfile\fP is not specified, output is sent to stdout.
.It "\fBtree\fP"
Print a textual representation of the hierarchy of the instance, where deeper elements are indented more.
.It "\fBwhere\fP"
Show current position in the hierarchy.
.It "<\fBcontrol-D\fP>"
Exits the program.
.El
.Pp
The \fBstat\fP, \fBsum\fP, \fBtree\fP, \fBcont\fP commands take an optional first argument (of any value),
which means to only consider the entire instance instead of the hierarchy from the current element.
.Sh "FILES"
.Bl -tag -width Ds
.It "\fIfile\fP\fB.ts\fP"
Translation specification file.
.El
.Sh "SEE ALSO"
.Pp
.Xr transpec 5 ,
.Xr sgmls 1 ,
Standard Generalized Markup Language (SGML), ISO 8879.

View File

@ -0,0 +1,710 @@
/*
* Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
* All rights reserved.
*/
/*
* Copyright (c) 1994
* Open Software Foundation, Inc.
*
* Permission is hereby granted to use, copy, modify and freely distribute
* the software in this file and its documentation for any purpose without
* fee, provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation. Further, provided that the name of Open
* Software Foundation, Inc. ("OSF") not be used in advertising or
* publicity pertaining to distribution of the software without prior
* written permission from OSF. OSF makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
/*
* Copyright (c) 1996 X Consortium
* Copyright (c) 1995, 1996 Dalrymple Consulting
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the X Consortium and
* Dalrymple Consulting shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without prior
* written authorization.
*/
/* ________________________________________________________________________
*
* Program to read an SGML document instance, creating any of several things:
*
* "translated" output for formatting applications (given a trans. spec)
* validation report (given a appropriate trans spec)
* tree of the document's structure
* statistics about the element usage
* summary of the elements used
* context of each element used
* IDs of each element
*
* A C structure is created for each element, which includes:
* name, attributes, parent, children, content
* The tree is descended, and the desired actions performed.
*
* Takes input from James Clark's "sgmls" program (v. 1.1).
* ________________________________________________________________________
*/
#ifndef lint
static char *RCSid =
"$Header: /usr/src/docbook-to-man/Instant/RCS/main.c,v 1.8 1996/06/12 03:32:48 fld Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <time.h>
#include <locale.h>
#define STORAGE
#include "general.h"
static int do_context, do_tree, do_summ, do_stats, do_validate, do_idlist;
static int do_DATAhack = 0;
static char *this_prog;
static char *in_file, *out_file;
static char *tranfile;
static char *start_id;
static char *last_file;
static int last_lineno;
extern int BOFTTextThresh;
/* forward references */
static void HandleArgs(int, char *[]);
static void Initialize1();
static void Initialize2();
static void ReadInstance(char *);
static void DoHelpMessage();
extern void Browse();
/* external reference to version number */
char _HeadVeRsIoN_[] = "1.0 (FreeBSD)";
/* ______________________________________________________________________ */
/* Program entry point. Look at args, read instance, dispatch to the
* correct routines to do the work, and finish.
*/
int
main(
int ac,
char *av[]
)
{
setlocale(LC_ALL, "");
Initialize1(av[0]);
HandleArgs(ac, av);
Initialize2();
if (tranfile) ReadTransSpec(tranfile);
ReadInstance(in_file);
if (interactive) {
Browse(); /* this will handle interactive commands */
}
else {
/* Perform tasks based on command line flags... */
if (tranfile) {
Element_t *e;
/* If user wants to start at a particular ID, point to that
* element. Else, point to the top of the tree. */
if (start_id) {
if (!(e=FindElemByID(start_id))) {
fprintf(stderr, "Error: Can not find element with ID %s\n",
start_id);
exit(1);
}
}
else e = DocTree;
/* If we're doing validation, make output file pointer null.
* This means that we generate no output, except error messages. */
if (do_validate) outfp = NULL;
if (tranfile)
DoTranslate(e, outfp);
else
fprintf(stderr, "Translation spec file not specified. Skipping translation.\n");
}
if (do_summ) PrintElemSummary(DocTree);
if (do_tree) PrintElemTree(DocTree);
if (do_stats) PrintStats(DocTree);
if (do_context) PrintContext(DocTree);
if (do_idlist) PrintIDList();
}
if (out_file && outfp) fclose(outfp);
return 0;
}
/* ______________________________________________________________________ */
/* Initialization stuff done before dealing with args.
* Arguments:
* Name of program (string).
*/
static void
Initialize1(
char *myname
)
{
time_t tnow;
struct tm *nowtm;
char *cp, buf[100];
extern int gethostname(char *, int); /* not in a system .h file... */
/* where we try to find data/library files */
if (!(tpt_lib=getenv(TPT_LIB))) tpt_lib = DEF_TPT_LIB;
/* set some global variables */
warnings = 1;
fold_case = 1;
this_prog = myname;
/* setup global variable mapping */
Variables = NewMap(IMS_variables);
/* set some pre-defined variables */
SetMappingNV(Variables, "user", (cp=getenv("USER")) ? cp : "UnknownUser" );
time(&tnow);
nowtm = localtime(&tnow);
strftime(buf, 100, "%a %d %b %Y, %R", nowtm);
SetMappingNV(Variables, "date", buf);
if (gethostname(buf, 100) < 0) strcpy(buf, "unknown-host");
SetMappingNV(Variables, "host", buf);
SetMappingNV(Variables, "transpec", tranfile ? tranfile : "??");
}
/* Initialization stuff done after dealing with args. */
static void
Initialize2()
{
SetMappingNV(Variables, "transpec", tranfile ? tranfile : "??");
/* If user wants to send output to a file, open the file, and set
* the file pointer. Else we send output to standard out. */
if (out_file) {
if (!(outfp = fopen(out_file, "w"))) {
fprintf(stderr, "Could not open output '%s' file for writing.\n%s",
out_file, strerror(errno));
exit(1);
}
}
else outfp = stdout;
}
/* ______________________________________________________________________ */
/* Set a variable. If it is one of the "known" variables, set the
* variable in the C code (this program).
* Arguments:
* Variable name/value string - separated by an '=' (eg, "myname=Sally").
*/
static void
CmdLineSetVariable(
char *var
)
{
char *cp, buf[100], **tok;
int n;
/* Turn '=' into a space, to isolate the name. Then set variable. */
strcpy(buf, var);
if ((cp=strchr(buf, '='))) {
/* we have "var=value" */
*cp = ' ';
n = 2;
tok = Split(buf, &n, 0);
/* see if variable name matches one of our internal ones */
if (!strcmp(tok[0], "verbose")) verbose = atoi(tok[1]);
else if (!strcmp(tok[0], "warnings")) warnings = atoi(tok[1]);
else if (!strcmp(tok[0], "foldcase")) fold_case = atoi(tok[1]);
else SetMappingNV(Variables, tok[0], tok[1]);
}
else {
fprintf(stderr, "Expected an '=' in variable assignment: %s. Ignored\n",
var);
}
}
/* ______________________________________________________________________ */
/* Bounce through arguments, setting variables and flags.
* Arguments:
* Argc and Argv, as passed to main().
*/
static void
HandleArgs(
int ac,
char *av[]
)
{
int c, errflag=0;
extern char *optarg;
extern int optind;
while ((c=getopt(ac, av, "df:t:v:o:huSxIl:bHVWi:D:Z")) != EOF) {
switch (c) {
case 't': tranfile = optarg; break;
case 'v': do_validate = 1; break;
case 'h': do_tree = 1; break;
case 'u': do_summ = 1; break;
case 'S': do_stats = 1; break;
case 'x': do_context = 1; break;
case 'I': do_idlist = 1; break;
case 'l': tpt_lib = optarg; break;
case 'i': start_id = optarg; break;
case 'o': out_file = optarg; break;
case 'd': do_DATAhack = 1; break;
case 'f': BOFTTextThresh = atoi(optarg); break;
case 'b': interactive = 1; break;
case 'W': warnings = 0; break;
case 'V': verbose = 1; break;
case 'Z': slave = 1; break;
case 'H': DoHelpMessage(); exit(0); break;
case 'D': CmdLineSetVariable(optarg); break;
case '?': errflag = 1; break;
}
if (errflag) {
fprintf(stderr, "Try '%s -H' for help.\n", this_prog);
exit(1);
}
}
/* input (ESIS) file name */
if (optind < ac) in_file = av[optind];
/* If doing interactive/browsing, we can't take ESIS from stdin. */
if (interactive && !in_file) {
fprintf(stderr,
"You must specify ESIS file on cmd line for browser mode.\n");
exit(1);
}
}
/* ______________________________________________________________________ */
/* Simply print out a help/usage message.
*/
static char *help_msg[] = {
"",
" -t file Print translated output using translation spec in <file>",
" -v Validate using translation spec specified with -t",
" -i id Consider only subtree starting at element with ID <id>",
" -b Interactive browser",
" -S Print statistics (how often elements occur, etc.)",
" -u Print element usage summary (# of children, depth, etc.)",
" -x Print context of each element",
" -h Print document hierarchy as a tree",
" -o file Write output to <file>. Default is standard output.",
" -l dir Set library directory to <dir>. (or env. variable TPT_LIB)",
" -I List all IDs used in the instance",
" -W Do not print warning messages",
" -H Print this help message",
" -Dvar=val Set variable 'var' to value 'val'",
" file Take input from named file. If not specified, assume stdin.",
" File should be output from the 'sgmls' program (ESIS).",
NULL
};
static void
DoHelpMessage()
{
char **s = help_msg;
printf("usage: %s [option ...] [file]", this_prog);
while (*s) puts(*s++);
printf("\nVersion: %s\n", _HeadVeRsIoN_);
}
/* ______________________________________________________________________ */
/* Remember an external entity for future reference.
* Arguments:
* Pointer to entity structure to remember.
*/
static void
AddEntity(
Entity_t *ent
)
{
static Entity_t *last_ent;
if (!Entities) {
Malloc(1, Entities, Entity_t);
last_ent = Entities;
}
else {
Malloc(1, last_ent->next, Entity_t);
last_ent = last_ent->next;
}
*last_ent = *ent;
}
/* Find an entity, given its entity name.
* Arguments:
* Name of entity to retrieve.
*/
static Entity_t *
FindEntity(
char *ename
)
{
Entity_t *n;
for (n=Entities; n; n=n->next)
if (StrEq(ename, n->ename)) return n;
return 0;
}
/* Accumulate lines up to the open tag. Attributes, line number,
* entity info, notation info, etc., all come before the open tag.
*/
static Element_t *
AccumElemInfo(
FILE *fp
)
{
char buf[LINESIZE+1];
int c;
int i, na;
char *cp, *atval;
Mapping_t a[100];
Element_t *e;
Entity_t ent, *ent2;
char **tok;
static int Index=0;
static Element_t *last_e;
Calloc(1, e, Element_t);
memset(&ent, 0, sizeof ent); /* clean space for entity info */
/* Also, keep a linked list of elements, so we can easily scan through */
if (last_e) last_e->next = e;
last_e = e;
e->index = Index++; /* just a unique number for identification */
/* in case these are not set for this element in the ESIS */
e->lineno = last_lineno;
e->infile = last_file;
na = 0;
while (1) {
if ((c = getc(fp)) == EOF) break;
fgets(buf, LINESIZE, fp);
stripNL(buf);
switch (c) {
case EOF: /* End of input */
fprintf(stderr, "Error: Unexpectedly reached end of ESIS.\n");
exit(1);
break;
case CMD_OPEN: /* (gi */
e->gi = AddElemName(buf);
if (na > 0) {
Malloc(na, e->atts, Mapping_t);
memcpy(e->atts, a, na*sizeof(Mapping_t));
e->natts = na;
na = 0;
}
/* Check if this elem has a notation attr. If yes, and there
is no notation specified, recall the previous one. (feature
of sgmls - it does not repeat notation stuff if we the same
is used twice in a row) */
if (((atval=FindAttValByName(e, "NAME")) ||
(atval=FindAttValByName(e, "ENTITYREF")) ||
(atval=FindAttValByName(e, "EXTERNAL"))) && /* HACK */
(ent2=FindEntity(atval))) {
e->entity = ent2;
}
return e;
break;
case CMD_ATT: /* Aname val */
i = 3;
tok = Split(buf, &i, 0);
if (!strcmp(tok[1], "IMPLIED"))
break; /* skip IMPLIED atts. */
else if (!strcmp(tok[1], "CDATA"))
{
/* CDATA attributes must have ESIS escape
sequences and SDATA entities expanded. */
char *val = ExpandString(tok[2]);
a[na].name = AddAttName(tok[0]);
a[na].sval = AddAttName(val);
free(val);
na++;
}
else if (!strcmp(tok[1], "TOKEN") ||
!strcmp(tok[1], "ENTITY") ||!strcmp(tok[1], "NOTATION"))
{
a[na].name = AddAttName(tok[0]);
a[na].sval = AddAttName(tok[2]);
na++;
}
else {
fprintf(stderr, "Error: Bad attr line (%d): A%s %s...\n",
e->lineno, tok[0], tok[1]);
}
break;
case CMD_LINE: /* Llineno */
/* These lines come in 2 forms: "L123" and "L123 file.sgml".
* Filename is given only at 1st occurance. Remember it.
*/
if ((cp = strchr(buf, ' '))) {
cp++;
last_file = strdup(cp);
}
last_lineno = e->lineno = atoi(buf);
e->infile = last_file;
break;
case CMD_DATA: /* -data */
fprintf(stderr, "Error: Data in AccumElemInfo, line %d:\n%c%s\n",
e->lineno, c,buf);
/*return e;*/
exit(1);
break;
case CMD_D_ATT: /* Dename name val */
case CMD_NOTATION: /* Nnname */
case CMD_PI: /* ?pi */
/* This should be reworked soon, as it
forces all PI's before the first GI
to be ignored. -CSS */
break;
case CMD_EXT_ENT: /* Eename typ nname */
i = 3;
tok = Split(buf, &i, 0);
ent.ename = strdup(tok[0]);
ent.type = strdup(tok[1]);
ent.nname = strdup(tok[2]);
AddEntity(&ent);
break;
case CMD_INT_ENT: /* Iename typ text */
fprintf(stderr, "Error: Got CMD_INT_ENT in AccumElemInfo: %s\n", buf);
break;
case CMD_SYSID: /* ssysid */
ent.sysid = strdup(buf);
break;
case CMD_PUBID: /* ppubid */
ent.pubid = strdup(buf);
break;
case CMD_FILENAME: /* ffilename */
ent.fname = strdup(buf);
break;
case CMD_CLOSE: /* )gi */
case CMD_SUBDOC: /* Sename */
case CMD_SUBDOC_S: /* {ename */
case CMD_SUBDOC_E: /* }ename */
case CMD_EXT_REF: /* &name */
case CMD_APPINFO: /* #text */
case CMD_CONFORM: /* C */
default:
fprintf(stderr, "Error: Unexpected input in AccumElemInfo, %d:\n%c%s\n",
e->lineno, c,buf);
exit(1);
break;
}
}
fprintf(stderr, "Error: End of AccumElemInfo - should not be here: %s\n",
e->gi);
/* return e;*/
exit(1);
}
/* Read ESIS lines.
* Limitation? Max 5000 children per node. (done for efficiency --
* should do some malloc and bookkeeping games later).
*/
static Element_t *
ReadESIS(
FILE *fp,
int depth
)
{
char *buf;
int i, c, ncont;
Element_t *e;
Content_t cont[5000];
Malloc( LINESIZE+1, buf, char );
/* Read input stream - the output of "sgmls", called "ESIS". */
e = AccumElemInfo(fp);
e->depth = depth;
ncont = 0;
while (1) {
if ((c = getc(fp)) == EOF) break;
switch (c) {
case EOF: /* End of input */
break;
case CMD_DATA: /* -data */
fgets(buf, LINESIZE, fp);
stripNL(buf);
if (do_DATAhack && (buf[0] == '\\') && (buf[1] == 'n')) {
if ( ! buf[2] )
break;
buf[0] = ' ';
memcpy(&buf[1], &buf[2], strlen(buf)-1);
}
cont[ncont].ch.data = ExpandString(buf);
cont[ncont].type = CMD_DATA;
ncont++;
break;
case CMD_PI: /* ?pi */
fgets(buf, LINESIZE, fp);
stripNL(buf);
cont[ncont].type = CMD_PI;
cont[ncont].ch.data = strdup(buf);
ncont++;
break;
case CMD_CLOSE: /* )gi */
fgets(buf, LINESIZE, fp);
stripNL(buf);
if (ncont) {
e->ncont = ncont;
Malloc(ncont, e->cont, Content_t);
for (i=0; i<ncont; i++) e->cont[i] = cont[i];
}
free(buf);
return e;
break;
case CMD_OPEN: /* (gi */
/*fprintf(stderr, "+++++ OPEN +++\n");*/
/* break;*/
case CMD_ATT: /* Aname val */
case CMD_D_ATT: /* Dename name val */
case CMD_NOTATION: /* Nnname */
case CMD_EXT_ENT: /* Eename typ nname */
case CMD_INT_ENT: /* Iename typ text */
case CMD_SYSID: /* ssysid */
case CMD_PUBID: /* ppubid */
case CMD_FILENAME: /* ffilename */
ungetc(c, fp);
cont[ncont].ch.elem = ReadESIS(fp, depth+1);
cont[ncont].type = CMD_OPEN;
cont[ncont].ch.elem->parent = e;
ncont++;
break;
case CMD_LINE: /* Llineno */
fgets(buf, LINESIZE, fp);
break; /* ignore these here */
case CMD_SUBDOC: /* Sename */
case CMD_SUBDOC_S: /* {ename */
case CMD_SUBDOC_E: /* }ename */
case CMD_EXT_REF: /* &name */
case CMD_APPINFO: /* #text */
case CMD_CONFORM: /* C */
default:
fgets(buf, LINESIZE, fp);
fprintf(stderr, "Error: Unexpected input at %d: '%c%s'\n",
e->lineno, c, buf);
exit(1);
break;
}
}
fprintf(stderr, "Error: End of ReadESIS - should not be here: %s\n", e->gi);
free(buf);
return NULL;
}
/* ______________________________________________________________________ */
/* Read input stream, creating a tree in memory of the elements and data.
* Arguments:
* Filename where instance's ESIS is.
*/
static void
ReadInstance(
char *filename
)
{
int i, n;
FILE *fp;
Element_t *e;
char *idatt;
if (filename) { /* if we specified input file. else stdin */
if ((fp=fopen(filename, "r")) == NULL) {
perror(filename);
exit(1);
}
}
else fp = stdin;
last_file = filename;
DocTree = ReadESIS(fp, 0);
if (filename) fclose(fp);
/* Traverse tree, filling in econt and figuring out which child
* (ie. what birth order) each element is. */
DocTree->my_eorder = -1;
for (e=DocTree; e; e=e->next) {
/* count element children */
for (i=0,n=0; i<e->ncont; i++) if (IsContElem(e,i)) n++;
if (n > 0) Calloc(n, e->econt, Element_t *);
for (i=0; i<e->ncont; i++)
if (IsContElem(e,i)) e->econt[e->necont++] = ContElem(e,i);
/* count data children */
for (i=0,n=0; i<e->ncont; i++) if (IsContData(e,i)) n++;
if (n > 0) Calloc(n, e->dcont, char *);
for (i=0; i<e->ncont; i++)
if (IsContData(e,i)) e->dcont[e->ndcont++] = ContData(e,i);
/* where in child order order */
for (i=0; i<e->necont; i++)
e->econt[i]->my_eorder = i;
/* Does this element have an ID? */
for (i=0; i<e->natts; i++) {
if ((idatt=FindAttValByName(e, "ID"))) {
AddID(e, idatt);
/* remember ID value for quick reference */
e->id = idatt;
break;
}
}
}
return;
}
/* ______________________________________________________________________ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,577 @@
/*
* Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
* All rights reserved.
*/
/*
* Copyright (c) 1994
* Open Software Foundation, Inc.
*
* Permission is hereby granted to use, copy, modify and freely distribute
* the software in this file and its documentation for any purpose without
* fee, provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation. Further, provided that the name of Open
* Software Foundation, Inc. ("OSF") not be used in advertising or
* publicity pertaining to distribution of the software without prior
* written permission from OSF. OSF makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
/*
* Copyright (c) 1996 X Consortium
* Copyright (c) 1995, 1996 Dalrymple Consulting
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the X Consortium and
* Dalrymple Consulting shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without prior
* written authorization.
*/
/* ________________________________________________________________________
*
* Program to manipulate SGML instances.
*
* This module contains the initialization routines for translation module.
* They mostly deal with reading data files (translation specs, SDATA
* mappings, character mappings).
*
* Entry points:
* ReadTransSpec(transfile) read/store translation spec from file
* ________________________________________________________________________
*/
#ifndef lint
static char *RCSid =
"$Header: /usr/local/home/jfieber/src/cvsroot/nsgmlfmt/traninit.c,v 1.1.1.1 1996/01/16 05:14:10 jfieber Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <memory.h>
#include <sys/types.h>
#include <errno.h>
#include <regexp.h>
#include "general.h"
#include "translate.h"
#include "sgmls.h"
#include "config.h"
#include "std.h"
#ifndef TRUE
#define TRUE (1 == 1)
#endif
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
/* forward references */
void RememberTransSpec(Trans_t *, int);
static void do_data(char *gi, struct sgmls_data *v, int n);
static void build_ts(char *gi, char* cp);
void AddCharMap(const char *from, const char* to);
void AddSDATA(const char *from, const char *to);
/* ______________________________________________________________________ */
/* Read the translation specs from the input file, storing in memory.
* Arguments:
* Name of translation spec file.
*/
static Trans_t T;
static
void input_error(num, str, lineno)
int num;
char *str;
unsigned long lineno;
{
fprintf(stderr, "Error at input line %lu: %s\n", lineno, str);
}
void
ReadTransSpec(
char *transfile
)
{
FILE *fp;
struct sgmls *sp;
struct sgmls_event e;
char gi[LINESIZE];
char buf[LINESIZE];
char buf2[LINESIZE];
char *command;
char *sgmls = "sgmls ";
char maptype = '\0';
(void)sgmls_set_errhandler(input_error);
transfile = FilePath(transfile);
if (!transfile)
{
fprintf(stderr, "Error: Could not locate specified transfile\n");
exit(1);
}
/* XXX this is a quick, gross hack. Should write a parse() function. */
Malloc(strlen(sgmls) + strlen(transfile) + 2, command, char);
sprintf(command, "%s %s", sgmls, transfile);
fp = popen(command, "r");
sp = sgmls_create(fp);
while (sgmls_next(sp, &e))
switch (e.type) {
case SGMLS_EVENT_DATA:
do_data(gi, e.u.data.v, e.u.data.n);
break;
case SGMLS_EVENT_ENTITY:
fprintf(stderr, "Hm... got an entity\n");
break;
case SGMLS_EVENT_PI:
break;
case SGMLS_EVENT_START:
if (strncmp("RULE", e.u.start.gi, 4) == 0) {
/* A new transpec, so clear the data structure
* and look for an ID attribute.
*/
struct sgmls_attribute *attr = e.u.start.attributes;
memset(&T, 0, sizeof T);
while (attr) {
if (attr->type == SGMLS_ATTR_CDATA
&& strncmp("ID", attr->name, 2) == 0) {
strncpy(buf, attr->value.data.v->s,
MIN(attr->value.data.v->len, LINESIZE));
buf[MIN(attr->value.data.v->len, LINESIZE - 1)] = '\0';
T.my_id = atoi(buf);
}
attr = attr->next;
}
}
else if (strncmp("CMAP", e.u.start.gi, 4) == 0)
maptype = 'c';
else if (strncmp("SMAP", e.u.start.gi, 4) == 0)
maptype = 's';
else if (strncmp("MAP", e.u.start.gi, 3) == 0) {
struct sgmls_attribute *attr = e.u.start.attributes;
char *from = 0;
char *to = 0;
while (attr) {
if (attr->value.data.v && strncmp("FROM", attr->name, 4) == 0) {
strncpy(buf, attr->value.data.v->s,
MIN(attr->value.data.v->len, LINESIZE - 1));
buf[MIN(attr->value.data.v->len, LINESIZE - 1)] = '\0';
}
if (attr->value.data.v && strncmp("TO", attr->name, 2) == 0) {
strncpy(buf2, attr->value.data.v->s,
MIN(attr->value.data.v->len, LINESIZE - 1));
buf2[MIN(attr->value.data.v->len, LINESIZE - 1)] = '\0';
}
attr = attr->next;
}
if (maptype == 'c')
AddCharMap(buf, buf2);
else if (maptype == 's')
AddSDATA(buf, buf2);
else
fprintf(stderr, "Unknown map type!\n");
}
else {
strncpy(gi, e.u.start.gi, 512);
sgmls_free_attributes(e.u.start.attributes);
}
break;
case SGMLS_EVENT_END:
if (strncmp("RULE", e.u.start.gi, 4) == 0)
RememberTransSpec(&T, e.lineno);
break;
case SGMLS_EVENT_SUBSTART:
break;
case SGMLS_EVENT_SUBEND:
break;
case SGMLS_EVENT_APPINFO:
break;
case SGMLS_EVENT_CONFORMING:
break;
default:
abort();
}
sgmls_free(sp);
pclose(fp);
free(command);
}
static void do_data(char *gi, struct sgmls_data *v, int n)
{
int i;
char *cp;
static char *buf = 0;
static int buf_size = 0;
int buf_pos = 0;
/* figure out how much space this element will really
take, inculding expanded sdata entities. */
if (!buf)
{
buf_size = 1024;
Malloc(buf_size, buf, char);
}
for (i = 0; i < n; i++)
{
char *s;
int len;
/* Mark the current position. If this is SDATA
we will have to return here. */
int tmp_buf_pos = buf_pos;
/* Make sure the buffer is big enough. */
if (buf_size - buf_pos <= v[i].len)
{
buf_size += v[i].len * (n - i);
Realloc(buf_size, buf, char);
}
s = v[i].s;
len = v[i].len;
for (; len > 0; len--, s++)
{
if (*s != RSCHAR) {
if (*s == RECHAR)
buf[buf_pos] = '\n';
else
buf[buf_pos] = *s;
buf_pos++;
}
}
if (v[i].is_sdata)
{
char *p;
buf[buf_pos] = '\0';
p = LookupSDATA(buf + tmp_buf_pos);
if (p)
{
if (buf_size - tmp_buf_pos <= strlen(p))
{
buf_size += strlen(p) * (n - i);
Realloc(buf_size, buf, char);
}
strcpy(buf + tmp_buf_pos, p);
buf_pos = tmp_buf_pos + strlen(p);
}
}
}
/* Clean up the trailing end of the data. */
buf[buf_pos] = '\0';
buf_pos--;
while (buf_pos > 0 && isspace(buf[buf_pos]) && buf[buf_pos] != '\n')
buf_pos--;
if (buf[buf_pos] == '\n')
buf[buf_pos] = '\0';
/* Skip over whitespace at the beginning of the data. */
cp = buf;
while (*cp && isspace(*cp))
cp++;
build_ts(gi, cp);
}
/* ______________________________________________________________________ */
/* Set a transpec parameter
* Arguments:
* gi - the parameter to set
* cp - the value of the parameter
*/
static void build_ts(char *gi, char* cp)
{
if (strcmp("GI", gi) == 0)
{
char *cp2;
/* if we are folding the case of GIs, make all upper (unless
it's an internal pseudo-GI name, which starts with '_') */
if (fold_case && cp[0] != '_' && cp[0] != '#')
{
for (cp2=cp; *cp2; cp2++)
if (islower(*cp2)) *cp2 = toupper(*cp2);
}
T.gi = AddElemName(cp);
}
else if (strcmp("START", gi) == 0)
T.starttext = strdup(cp);
else if (strcmp("END", gi) == 0)
T.endtext = strdup(cp);
else if (strcmp("RELATION", gi) == 0)
{
if (!T.relations)
T.relations = NewMap(IMS_relations);
SetMapping(T.relations, cp);
}
else if (strcmp("REPLACE", gi) == 0)
T.replace = strdup(cp);
else if (strcmp("ATTVAL", gi) == 0)
{
if (!T.nattpairs)
{
Malloc(1, T.attpair, AttPair_t);
}
else
Realloc((T.nattpairs+1), T.attpair, AttPair_t);
/* we'll split name/value pairs later */
T.attpair[T.nattpairs].name = strdup(cp);
T.nattpairs++;
}
else if (strcmp("CONTEXT", gi) == 0)
T.context = strdup(cp);
else if (strcmp("MESSAGE", gi) == 0)
T.message = strdup(cp);
else if (strcmp("DO", gi) == 0)
T.use_id = atoi(cp);
else if (strcmp("CONTENT", gi) == 0)
T.content = strdup(cp);
else if (strcmp("PATTSET", gi) == 0)
T.pattrset = strdup(cp);
else if (strcmp("VERBATIM", gi) == 0)
T.verbatim = TRUE;
else if (strcmp("IGNORE", gi) == 0)
{
if (!strcmp(cp, "all"))
T.ignore = IGN_ALL;
else if (!strcmp(cp, "data"))
T.ignore = IGN_DATA;
else if (!strcmp(cp, "children"))
T.ignore = IGN_CHILDREN;
else
fprintf(stderr, "Bad 'Ignore:' arg in transpec %s: %s\n",
gi, cp);
}
else if (strcmp("VARVAL", gi) == 0)
{
char **tok;
int i = 2;
tok = Split(cp, &i, S_STRDUP);
T.var_name = tok[0];
T.var_value = tok[1];
}
else if (strcmp("VARREVAL", gi) == 0)
{
char buf[1000];
char **tok;
int i = 2;
tok = Split(cp, &i, S_STRDUP);
T.var_RE_name = tok[0];
ExpandVariables(tok[1], buf, 0);
if (!(T.var_RE_value=regcomp(buf))) {
fprintf(stderr, "Regex error in VarREValue Content: %s\n",
tok[1]);
}
}
else if (strcmp("SET", gi) == 0)
{
if (!T.set_var)
T.set_var = NewMap(IMS_setvar);
SetMapping(T.set_var, cp);
}
else if (strcmp("INCR", gi) == 0)
{
if (!T.incr_var)
T.incr_var = NewMap(IMS_incvar);
SetMapping(T.incr_var, cp);
}
else if (strcmp("NTHCHILD", gi) == 0)
T.nth_child = atoi(cp);
else if (strcmp("VAR", gi) == 0)
SetMapping(Variables, cp);
else if (strcmp("QUIT", gi) == 0)
T.quit = strdup(cp);
else
fprintf(stderr, "Unknown translation spec (skipping it): %s\n", gi);
}
/* ______________________________________________________________________ */
/* Store translation spec 't' in memory.
* Arguments:
* Pointer to translation spec to remember.
* Line number where translation spec ends.
*/
void
RememberTransSpec(
Trans_t *t,
int lineno
)
{
char *cp;
int i, do_regex;
static Trans_t *last_t;
char buf[1000];
/* If context testing, check some details and set things up for later. */
if (t->context) {
/* See if the context specified is a regular expression.
* If so, compile the reg expr. It is assumed to be a regex if
* it contains a character other than what's allowed for GIs in the
* OSF sgml declaration (alphas, nums, '-', and '.').
*/
for (do_regex=0,cp=t->context; *cp; cp++) {
if (!isalnum(*cp) && *cp != '-' && *cp != '.' && *cp != ' ') {
do_regex = 1;
break;
}
}
if (do_regex) {
t->depth = MAX_DEPTH;
if (!(t->context_re=regcomp(t->context))) {
fprintf(stderr, "Regex error in Context: %s\n", t->context);
}
}
else {
/* If there's only one item in context, it's the parent. Treat
* it specially, since it's faster to just check parent gi.
*/
cp = t->context;
if (!strchr(cp, ' ')) {
t->parent = t->context;
t->context = NULL;
}
else {
/* Figure out depth of context string */
t->depth = 0;
while (*cp) {
if (*cp) t->depth++;
while (*cp && !IsWhite(*cp)) cp++; /* find end of gi */
while (*cp && IsWhite(*cp)) cp++; /* skip space */
}
}
}
}
/* Compile regular expressions for each attribute */
for (i=0; i<t->nattpairs; i++) {
/* Initially, name points to "name value". Split them... */
cp = t->attpair[i].name;
while (*cp && !IsWhite(*cp)) cp++; /* point past end of name */
if (*cp) { /* value found */
*cp++ = EOS; /* terminate name */
while (*cp && IsWhite(*cp)) cp++; /* point to value */
ExpandVariables(cp, buf, 0); /* expand any variables */
t->attpair[i].val = strdup(buf);
}
else { /* value not found */
t->attpair[i].val = ".";
}
if (!(t->attpair[i].rex=regcomp(t->attpair[i].val))) {
fprintf(stderr, "Regex error in AttValue: %s %s\n",
t->attpair[i].name, t->attpair[i].val);
}
}
/* Compile regular expression for content */
t->content_re = 0;
if (t->content) {
ExpandVariables(t->content, buf, 0);
if (!(t->content_re=regcomp(buf)))
fprintf(stderr, "Regex error in Content: %s\n",
t->content);
}
/* If multiple GIs, break up into a vector, then remember it. We either
* sture the individual, or the list - not both. */
if (t->gi && strchr(t->gi, ' ')) {
t->gilist = Split(t->gi, 0, S_ALVEC);
t->gi = NULL;
}
/* Now, store structure in linked list. */
if (!TrSpecs) {
Malloc(1, TrSpecs, Trans_t);
last_t = TrSpecs;
}
else {
Malloc(1, last_t->next, Trans_t);
last_t = last_t->next;
}
*last_t = *t;
}
/* ______________________________________________________________________ */
/* Add an entry to the character mapping table, allocating or
* expanding the table if necessary.
* Arguments:
* Character to map
* String to map the character to
* A 'c' or an 's' for character or sdata map
*/
void
AddCharMap(
const char *from,
const char* to
)
{
static int n_alloc = 0;
if (from && to) {
if (nCharMap >= n_alloc) {
n_alloc += 32;
if (!CharMap) {
Malloc(n_alloc, CharMap, Mapping_t);
}
else {
Realloc(n_alloc, CharMap, Mapping_t);
}
}
CharMap[nCharMap].name = strdup(from);
CharMap[nCharMap].sval = strdup(to);
nCharMap++;
}
}
/* ______________________________________________________________________ */
/* Add an entry to the SDATA mapping table.
* Arguments:
* String to map
* String to map to
*/
void
AddSDATA(
const char *from,
const char *to
)
{
if (from && to) {
if (!SDATAmap)
SDATAmap = NewMap(IMS_sdata);
SetMappingNV(SDATAmap, from, to);
}
}
/* ______________________________________________________________________ */

View File

@ -0,0 +1,881 @@
/*
* Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
* All rights reserved.
*/
/*
* Copyright (c) 1994
* Open Software Foundation, Inc.
*
* Permission is hereby granted to use, copy, modify and freely distribute
* the software in this file and its documentation for any purpose without
* fee, provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation. Further, provided that the name of Open
* Software Foundation, Inc. ("OSF") not be used in advertising or
* publicity pertaining to distribution of the software without prior
* written permission from OSF. OSF makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
/*
* Copyright (c) 1996 X Consortium
* Copyright (c) 1995, 1996 Dalrymple Consulting
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the X Consortium and
* Dalrymple Consulting shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without prior
* written authorization.
*/
/* ________________________________________________________________________
*
* Program to manipulate SGML instances.
*
* This module is for "translating" an instance to another form, usually
* suitable for a formatting application.
*
* Entry points for this module:
* DoTranslate(elem, fp)
* ExpandVariables(in, out, e)
* ________________________________________________________________________
*/
#ifndef lint
static char *RCSid =
"$Header: /usr/src/docbook-to-man/Instant/RCS/translate.c,v 1.11 1996/06/15 22:49:00 fld Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <memory.h>
#include <sys/types.h>
#include <errno.h>
#include <regexp.h>
#include "general.h"
#define STORAGE
#include "translate.h"
static Trans_t NullTrans; /* an empty one */
/* forward references */
void ProcesOutputSpec(char *, Element_t *, FILE *, int);
static void WasProcessed(Element_t *);
/* ______________________________________________________________________ */
/* Translate the subtree starting at 'e'. Output goes to 'fp'.
* This is the entry point for translating an instance.
* Arguments:
* Pointer to element under consideration.
* FILE pointer to where to write output.
*/
void
DoTranslate(
Element_t *e,
FILE *fp
)
{
Trans_t *t, *tn;
/* Find transpec for each node. */
DescendTree(e, PrepTranspecs, 0, 0, 0);
/* Stuff to do at start of processing */
if ((t = FindTransByName("_Start"))) {
if (t->starttext) ProcesOutputSpec(t->starttext, 0, fp, 1);
if (t->replace) ProcesOutputSpec(t->replace, 0, fp, 1);
if (t->message) ProcesOutputSpec(t->message, 0, stderr, 0);
if (t->endtext) ProcesOutputSpec(t->endtext, 0, fp, 1);
}
/* Translate topmost/first element. This is recursive. */
TransElement(e, fp, NULL);
/* Stuff to do at end of processing */
if ((t = FindTransByName("_End"))) {
if (t->starttext) ProcesOutputSpec(t->starttext, 0, fp, 1);
if (t->replace) ProcesOutputSpec(t->replace, 0, fp, 1);
if (t->message) ProcesOutputSpec(t->message, 0, stderr, 0);
if (t->endtext) ProcesOutputSpec(t->endtext, 0, fp, 1);
}
/* Warn about unprocessed elements in this doc tree, if verbose mode. */
if (verbose)
DescendTree(e, WasProcessed, 0, 0, 0);
/* Clean up. This is not yet complete, which is no big deal (since the
* program is normally done at this point anyway. */
for (t=TrSpecs; t; ) {
tn = t->next;
/* free the contents of t here ... */
(void)free((void* )t);
t = tn;
}
TrSpecs = 0;
}
/* ______________________________________________________________________ */
/* Print warning about unprocessed elements in this doc tree (if they
* were not explicitely ignored).
* Arguments:
* Pointer to element under consideration.
*/
static void
WasProcessed(
Element_t *e
)
{
Trans_t *t;
t = e->trans;
if (!e->processed && (t && !t->ignore)) {
fprintf(stderr, "Warning: element '%s' was not processed:\n", e->gi);
PrintLocation(e, stderr);
}
}
/* ______________________________________________________________________ */
/* For each element find transpec.
* Arguments:
* Pointer to element under consideration.
*/
void
PrepTranspecs(
Element_t *e
)
{
Trans_t *t;
t = FindTrans(e, 0);
e->trans = t;
}
/* ______________________________________________________________________ */
/* Copy a buffer/string into another, expanding regular variables and immediate
* variables. (Special variables are done later.)
* Arguments:
* Pointer to string to expand.
* Pointer to expanded string. (return)
* Pointer to element under consideration.
*/
void
ExpandVariables(
char *in,
char *out,
Element_t *e
)
{
register int i, j;
char *ip, *vp, *op;
char *def_val, *s, *atval, *modifier;
char vbuf[500];
int lev;
ip = in;
op = out;
while (*ip) {
/* start of regular variable? */
if (*ip == '$' && *(ip+1) == L_CURLY && *(ip+2) != '_') {
ip++;
ip++; /* point at variable name */
vp = vbuf;
/* Look for matching (closing) curly. (watch for nesting)
* We store the variable content in a tmp buffer, so we don't
* clobber the input buffer.
*/
lev = 0;
while (*ip) {
if (*ip == L_CURLY) lev++;
if (*ip == R_CURLY) {
if (lev == 0) {
ip++;
break;
}
else lev--;
}
*vp++ = *ip++; /* copy to variable buffer */
}
*vp = EOS;
/* vbuf now contains the variable name (stuff between curlys). */
if (lev != 0) {
fprintf(stderr, "Botched variable use: %s\n", in);
/* copy rest of string if we can't recover ?? */
return;
}
/* Now, expand variable. */
vp = vbuf;
/* Check for immediate variables -- like _special variables but
* interpreted right now. These start with a "+" */
if ( *vp == '+' ) {
if ( ! strcmp(vp, "+content") ) {
for ( i=0; i<e->ncont; i++ ) {
if ( IsContData(e, i) ) {
j = strlen(ContData(e,i));
memcpy(op, ContData(e,i), j);
op += j;
} else {
fprintf(stderr, "warning: ${+current} skipped element content\n");
}
}
} else {
fprintf(stderr, "unknown immediate variable: %s\n", vp);
}
} else {
/* See if this variable has a default [ format: ${varname def} ] */
def_val = vp;
while (*def_val && *def_val != ' ') def_val++;
if (*def_val) *def_val++ = EOS;
else def_val = 0;
/* def_val now points to default, if it exists, null if not. */
modifier = vp;
while (*modifier && *modifier != ':') modifier++;
if (*modifier) *modifier++ = EOS;
else modifier = 0;
/* modifier now points to modifier if it exists, null if not. */
s = 0;
/* if attribute of current elem with this name found, use value */
if (e && (atval = FindAttValByName(e, vp)))
s = atval;
else /* else try for (global) variable with this name */
s = FindMappingVal(Variables, vp);
/* If we found a value, copy it to the output buffer. */
if (s) {
if ( modifier && *modifier == 'l' ) {
while (*s) {
*op = tolower(*s);
op++, *s++;
}
} else
while (*s) *op++ = *s++;
} else
if (def_val) {
while (*def_val) *op++ = *def_val++;
}
}
continue;
}
*op++ = *ip++;
}
*op = EOS; /* terminate string */
}
/* ______________________________________________________________________ */
/* Process an "output" translation spec - one of StartText, EndText,
* Replace, Message. (These are the ones that produce output.)
* Steps done:
* Expand attributes and regular varaibles in input string.
* Pass thru string, accumulating chars to be sent to output stream.
* If we find the start of a special variable, output what we've
* accumulated, then find the special variable's "bounds" (ie, the
* stuff between the curly brackets), and expand that by passing to
* ExpandSpecialVar(). Continue until done the input string.
* Arguments:
* Input buffer (string) to be expanded and output.
* Pointer to element under consideration.
* FILE pointer to where to write output.
* Flag saying whether to track the character position we're on
* (passed to OutputString).
*/
void
ProcesOutputSpec(
char *ib,
Element_t *e,
FILE *fp,
int track_pos
)
{
char obuf[LINESIZE];
char vbuf[LINESIZE];
char *dest, vname[LINESIZE], *cp;
int esc;
obuf[0] = EOS; /* start with empty output buffer */
ExpandVariables(ib, vbuf, e); /* expand regular variables */
ib = vbuf;
dest = obuf;
esc = 0;
while (*ib) {
/* If not a $, it's a regular char. Just copy it and go to next. */
if (*ib != '$') { /* look for att/variable marker */
*dest++ = *ib++; /* it's not. just copy character */
continue;
}
/* We have a $. What we have must be a "special variable" since
* regular variables have already been expanded, or just a lone $. */
if (ib[1] != L_CURLY) { /* just a stray dollar sign (no variable) */
*dest++ = *ib++;
continue;
}
ib++; /* point past $ */
/* Output what we have in buffer so far. */
*dest = EOS; /* terminate string */
if (obuf[0]) OutputString(obuf, fp, track_pos);
dest = obuf; /* ready for new stuff in buffer */
if (!strchr(ib, R_CURLY)) {
fprintf(stderr, "Mismatched braces in TranSpec: %s\n", ib);
/* how do we recover from this? */
}
ib++;
cp = vname;
while (*ib && *ib != R_CURLY) *cp++ = *ib++;
*cp = EOS; /* terminate att/var name */
ib++; /* point past closing curly */
/* we now have special variable name (stuff in curly {}'s) in vname */
ExpandSpecialVar(&vname[1], e, fp, track_pos);
}
*dest = EOS; /* terminate string in output buffer */
if (obuf[0]) OutputString(obuf, fp, track_pos);
}
/* ______________________________________________________________________ */
/* Find the translation spec for the given tag.
* Returns pointer to first spec that matches (name, depth, etc., of tag).
* Arguments:
* e -- Pointer to element under consideration.
* specID -- name of specid that we're looking for
* Return:
* Pointer to translation spec that matches given element's context.
*/
Trans_t *
FindTrans(
Element_t *e,
int specID
)
{
char context[LINESIZE], buf[LINESIZE], *cp, **vec, *atval;
int i, a, match;
Trans_t *t, *tt;
/* loop through all transpecs */
for (t=TrSpecs; t; t=t->next)
{
/* Only one of gi or gilist will be set. */
/* Check if elem name matches */
if (t->gi && !StrEq(t->gi, e->gi) && !specID) continue;
/* test if we're looking for a specific specID and then if
* this is it.. */
if (specID)
if (!t->my_id || (specID != t->my_id))
continue;
/* Match one in the list of GIs? */
if (t->gilist) {
for (match=0,vec=t->gilist; *vec; vec++) {
if (StrEq(*vec, e->gi)) {
match = 1;
break;
}
}
if (!match) continue;
}
/* Check context */
/* Special case of context */
if (t->parent)
if (!QRelation(e, t->parent, REL_Parent)) continue;
if (t->context) { /* no context specified -> a match */
FindContext(e, t->depth, context);
/* If reg expr set, do regex compare; else just string compare. */
if (t->context_re) {
if (! regexec(t->context_re, context)) continue;
}
else {
/* Is depth of spec deeper than element's depth? */
if (t->depth > e->depth) continue;
/* See if context of element matches "context" of transpec */
match = ( (t->context[0] == context[0]) &&
!strcmp(t->context, context) );
if (!match) continue;
}
}
/* Check attributes. Loop through list, comparing each. */
if (t->nattpairs) { /* no att specified -> a match */
for (match=1,a=0; a<t->nattpairs; a++) {
if (!(atval = FindAttValByName(e, t->attpair[a].name))) {
match = 0;
break;
}
if (!regexec(t->attpair[a].rex, atval)) match = 0;
}
if (!match) continue;
}
/* Check relationships: child, parent, ancestor, sib, ... */
if (t->relations) {
Mapping_t *r;
match = 1;
for (r=t->relations->maps,i=0; i<t->relations->n_used; i++) {
if (!CheckRelation(e, r[i].name, r[i].sval, 0, 0, RA_Current)) {
match = 0;
break;
}
}
if (!match) continue;
}
/* check this element's parent's attribute */
if (t->pattrset && e->parent) {
char *p, **tok;
i = 2;
match = 1;
tok = Split(t->pattrset, &i, S_STRDUP);
if ( i == 2 ) {
p = FindAttValByName(e->parent, tok[0]);
ExpandVariables(tok[1], buf, 0);
if ( !p || strcmp(p, buf) )
match = 0;
} else {
if (!FindAttValByName(e->parent, t->pattrset))
match = 0;
}
free(tok[0]);
if (!match) continue;
}
/* check this element's "birth order" */
if (t->nth_child) {
/* First one is called "1" by the user. Internally called "0". */
i = t->nth_child;
if (i > 0) { /* positive # -- count from beginning */
if (e->my_eorder != (i-1)) continue;
}
else { /* negative # -- count from end */
i = e->parent->necont - i;
if (e->my_eorder != i) continue;
}
}
/* check that variables match */
if (t->var_name) {
cp = FindMappingVal(Variables, t->var_name);
if (!cp || strcmp(cp, t->var_value)) continue;
}
/* check for variable regular expression match */
if ( t->var_RE_name ) {
cp = FindMappingVal(Variables, t->var_RE_name);
if (!cp || !regexec(t->var_RE_value, cp)) continue;
}
/* check content */
if (t->content) { /* no att specified -> a match */
for (match=0,i=0; i<e->ndcont; i++) {
if (regexec(t->content_re, e->dcont[i])) {
match = 1;
break;
}
}
if (!match) continue;
}
/* -------- at this point we've passed all criteria -------- */
/* See if we should be using another transpec's actions. */
if (t->use_id) {
if (t->use_id < 0) return &NullTrans; /* missing? */
/* see if we have a pointer to that transpec */
if (t->use_trans) return t->use_trans;
for (tt=TrSpecs; tt; tt=tt->next) {
if (t->use_id == tt->my_id) {
/* remember pointer for next time */
t->use_trans = tt;
return t->use_trans;
}
}
t->use_id = -1; /* flag it as missing */
fprintf(stderr, "Warning: transpec ID (%d) not found for %s.\n",
t->use_id, e->gi);
return &NullTrans;
}
return t;
}
/* At this point, we have not found a matching spec. See if there
* is a wildcard, and if so, use it. (Wildcard GI is named "*".) */
if ((t = FindTransByName("*"))) return t;
if (warnings && !specID)
fprintf(stderr, "Warning: transpec not found for %s\n", e->gi);
/* default spec - pass character data and descend node */
return &NullTrans;
}
/* ______________________________________________________________________ */
/* Find translation spec by (GI) name. Returns the first one that matches.
* Arguments:
* Pointer to name of transpec (the "gi" field of the Trans structure).
* Return:
* Pointer to translation spec that matches name.
*/
Trans_t *
FindTransByName(
char *s
)
{
Trans_t *t;
for (t=TrSpecs; t; t=t->next) {
/* check if tag name matches (first check 1st char, for efficiency) */
if (t->gi) {
if (*(t->gi) != *s) continue; /* check 1st character */
if (!strcmp(t->gi, s)) return t;
}
}
return NULL;
}
/* Find translation spec by its ID (SpecID).
* Arguments:
* Spec ID (an int).
* Return:
* Pointer to translation spec that matches name.
*/
Trans_t *
FindTranByID(int n)
{
Trans_t *t;
for (t=TrSpecs; t; t=t->next)
if (n == t->my_id) return t;
return NULL;
}
/* ______________________________________________________________________ */
/* Process a "chunk" of content data of an element.
* Arguments:
* Pointer to data content to process
* FILE pointer to where to write output.
*/
void
DoData(
char *data,
FILE *fp,
int verbatim
)
{
if (!fp) return;
OutputString(data, fp, 1);
}
/* ______________________________________________________________________ */
/* Handle a processing instruction. This is done similarly to elements,
* where we find a transpec, then do what it says. Differences: PI names
* start with '_' in the spec file (if a GI does not start with '_', it
* may be forced to upper case, sgmls keeps PIs as mixed case); the args
* to the PI are treated as the data of an element. Note that a PI wildcard
* is "_*"
* Arguments:
* Pointer to the PI.
* FILE pointer to where to write output.
*/
void
DoPI(
char *pi,
FILE *fp
)
{
char buf[250], **tok;
int n;
Trans_t *t;
buf[0] = '_';
strcpy(&buf[1], pi);
n = 2;
tok = Split(buf, &n, 0);
if ((t = FindTransByName(tok[0])) ||
(t = FindTransByName("_*"))) {
if (t->replace) ProcesOutputSpec(t->replace, 0, fp, 1);
else {
if (t->starttext) ProcesOutputSpec(t->starttext, 0, fp, 1);
if (t->ignore != IGN_DATA) /* skip data nodes? */
if (n > 1) OutputString(tok[1], fp, 1);
if (t->endtext) ProcesOutputSpec(t->endtext, 0, fp, 1);
}
if (t->message) ProcesOutputSpec(t->message, 0, stderr, 0);
}
else {
/* If not found, just print the PI in square brackets, along
* with a warning message. */
fprintf(fp, "[%s]", pi);
if (warnings) fprintf(stderr, "Warning: Unrecognized PI: [%s]\n", pi);
}
}
/* ______________________________________________________________________ */
/* Set and increment variables, as appropriate, if the transpec says to.
* Arguments:
* Pointer to translation spec for current element.
*/
static void
set_and_increment(
Trans_t *t,
Element_t *e
)
{
Mapping_t *m;
int i, inc, n;
char *cp, buf[50];
char ebuf[500];
/* set/reset variables */
if (t->set_var) {
for (m=t->set_var->maps,i=0; i<t->set_var->n_used; i++) {
ExpandVariables(m[i].sval, ebuf, e); /* do some expansion */
SetMappingNV(Variables, m[i].name, ebuf);
}
}
/* increment counters */
if (t->incr_var) {
for (m=t->incr_var->maps,i=0; i<t->incr_var->n_used; i++) {
cp = FindMappingVal(Variables, m[i].name);
/* if not set at all, set to 1 */
if (!cp) SetMappingNV(Variables, m[i].name, "1");
else {
if (isdigit(*cp) || (*cp == '-' && isdigit(cp[1]))) {
n = atoi(cp);
if (m[i].sval && isdigit(*m[i].sval)) inc = atoi(m[i].sval);
else inc = 1;
sprintf(buf, "%d", (n + inc));
SetMappingNV(Variables, m[i].name, buf);
} else
if (!*(cp+1) && isalpha(*cp)) {
buf[0] = *cp + 1;
buf[1] = 0;
SetMappingNV(Variables, m[i].name, buf);
}
}
}
}
}
/* ______________________________________________________________________ */
/* Translate one element.
* Arguments:
* Pointer to element under consideration.
* FILE pointer to where to write output.
* Pointer to translation spec for current element, or null.
*/
void
TransElement(
Element_t *e,
FILE *fp,
Trans_t *t
)
{
int i;
if (!t) t = ((e && e->trans) ? e->trans : &NullTrans);
/* see if we should quit. */
if (t->quit) {
fprintf(stderr, "Quitting at location:\n");
PrintLocation(e, fp);
fprintf(stderr, "%s\n", t->quit);
exit(1);
}
/* See if we want to replace subtree (do text, don't descend subtree) */
if (t->replace) {
ProcesOutputSpec(t->replace, e, fp, 1);
if (t->message) ProcesOutputSpec(t->message, e, stderr, 0);
set_and_increment(t, e); /* adjust variables, if appropriate */
return;
}
if (t->starttext) ProcesOutputSpec(t->starttext, e, fp, 1);
if (t->message) ProcesOutputSpec(t->message, e, stderr, 0);
/* Process data for this node and descend child elements/nodes. */
if (t->ignore != IGN_ALL) {
/* Is there a "generated" node at the front of this one? */
if (e->gen_trans[0]) {
Trans_t *tp;
if ((tp = FindTranByID(e->gen_trans[0]))) {
if (tp->starttext) ProcesOutputSpec(tp->starttext, e, fp, 1);
if (tp->message) ProcesOutputSpec(tp->message, e, stderr, 0);
if (tp->endtext) ProcesOutputSpec(tp->endtext, e, fp, 1);
}
}
/* Loop thruthe "nodes", whether data, child element, or PI. */
for (i=0; i<e->ncont; i++) {
if (IsContElem(e,i)) {
if (t->ignore != IGN_CHILDREN) /* skip child nodes? */
TransElement(ContElem(e,i), fp, NULL);
}
else if (IsContData(e,i)) {
if (t->ignore != IGN_DATA) /* skip data nodes? */
DoData(ContData(e,i), fp, t->verbatim);
}
else if (IsContPI(e,i))
DoPI(e->cont[i].ch.data, fp);
}
/* Is there a "generated" node at the end of this one? */
if (e->gen_trans[1]) {
Trans_t *tp;
if ((tp = FindTranByID(e->gen_trans[1]))) {
if (tp->starttext) ProcesOutputSpec(tp->starttext, e, fp, 1);
if (tp->message) ProcesOutputSpec(tp->message, e, stderr, 0);
if (tp->endtext) ProcesOutputSpec(tp->endtext, e, fp, 1);
}
}
}
set_and_increment(t, e); /* adjust variables, if appropriate */
if (t->endtext) ProcesOutputSpec(t->endtext, e, fp, 1);
e->processed = 1;
}
/* ______________________________________________________________________ */
/* Check if element matches specified relationship, and, if it does, perform
* action on either current element or matching element (depends on flag).
* Arguments:
* Pointer to element under consideration.
* Pointer to relationship name.
* Pointer to related element name (GI).
* Pointer to action to take (string - turned into an int).
* FILE pointer to where to write output.
* Flag saying whether to do action on related element (RA_Related)
* or on current element (RA_Current).
* Return:
* Bool, saying whether (1) or not (0) relationship matches.
*/
int
CheckRelation(
Element_t *e,
char *relname, /* relationship name */
char *related, /* related element */
char *actname, /* action to take */
FILE *fp,
RelAction_t flag
)
{
Element_t *ep;
Relation_t r;
if ((r = FindRelByName(relname)) == REL_Unknown) return 0;
if (!(ep=QRelation(e, related, r))) return 0;
if (!actname) return 1; /* no action - return what we found */
switch (flag) {
case RA_Related: TranTByAction(ep, actname, fp); break;
case RA_Current: TranTByAction(e, actname, fp); break;
}
return 1;
}
/* ______________________________________________________________________ */
/* Perform action given by a SpecID on the given element.
* Arguments:
* Pointer to element under consideration.
* SpecID of action to perform.
* FILE pointer to where to write output.
*
*/
void
TranByAction(
Element_t *e,
int n,
FILE *fp
)
{
Trans_t *t;
t = FindTranByID(n);
if (!t) {
fprintf(stderr, "Could not find named action for %d.\n", n);
return;
}
TransElement(e, fp, t);
}
/* ______________________________________________________________________ */
/* Perhaps perform action given by a SpecID on the given element.
* Arguments:
* Pointer to element under consideration.
* SpecID of action to perform. Unlike TranByAction, this is the argument
* as it occurred in the transpec (ASCII) and may end with the letter
* "t" which means that the transpec mustpass criteria selection.
* FILE pointer to where to write output.
*/
void
TranTByAction(
Element_t *e,
char *strn,
FILE *fp
)
{
int n;
Trans_t *t;
n = atoi(strn);
if ( strn[strlen(strn)-1] != 't' ) {
t = FindTranByID(n);
if (!t) {
fprintf(stderr, "Could not find named action for %d.\n", n);
return;
}
} else {
t = FindTrans(e, n);
if ( !t || !t->my_id )
return;
}
TransElement(e, fp, t);
}
/* ______________________________________________________________________ */

View File

@ -0,0 +1,153 @@
/*
* Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
* All rights reserved.
*/
/*
* Copyright (c) 1994
* Open Software Foundation, Inc.
*
* Permission is hereby granted to use, copy, modify and freely distribute
* the software in this file and its documentation for any purpose without
* fee, provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation. Further, provided that the name of Open
* Software Foundation, Inc. ("OSF") not be used in advertising or
* publicity pertaining to distribution of the software without prior
* written permission from OSF. OSF makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
/*
* Copyright (c) 1996 X Consortium
* Copyright (c) 1995, 1996 Dalrymple Consulting
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the X Consortium and
* Dalrymple Consulting shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without prior
* written authorization.
*/
/* ________________________________________________________________________
*
* Program to manipulate SGML instances.
*
* These are data definitions for the "translating" portion of the program.
*
* ________________________________________________________________________
*/
#ifdef STORAGE
#ifndef lint
static char *tr_h_RCSid =
"$Header: /usr/src/docbook-to-man/Instant/RCS/translate.h,v 1.3 1996/06/02 21:47:32 fld Exp $";
#endif
#endif
#define L_CURLY '{'
#define R_CURLY '}'
/* things to ignore when processing an element */
#define IGN_NONE 0
#define IGN_ALL 1
#define IGN_DATA 2
#define IGN_CHILDREN 3
/* for CheckRelation() */
typedef enum { RA_Current, RA_Related } RelAction_t;
typedef struct {
char *name; /* attribute name string */
char *val; /* attribute value string */
regexp *rex; /* attribute value reg expr (compiled) */
} AttPair_t;
typedef struct _Trans {
/* criteria */
char *gi; /* element name of tag under consideration */
char **gilist; /* list of element names (multiple gi's) */
char *context; /* context in tree - looking depth levels up */
regexp *context_re; /* tree heirarchy looking depth levels up */
int depth; /* number of levels to look up the tree */
AttPair_t *attpair; /* attr name-value pairs */
int nattpairs; /* number of name-value pairs */
char *parent; /* GI has this element as parent */
int nth_child; /* GI is Nth child of this of parent element */
char *content; /* element has this string in content */
regexp *content_re; /* content reg expr (compiled) */
char *pattrset; /* is this attr set (any value) in parent? */
char *var_name; /* variable name */
char *var_value; /* variable value */
char *var_RE_name; /* variable name (for VarREValue) */
regexp *var_RE_value; /* variable value (compiled, for VarREValue) */
Map_t *relations; /* various relations to check */
/* actions */
char *starttext; /* string to output at the start tag */
char *endtext; /* string to output at the end tag */
char *replace; /* string to replace this subtree with */
char *message; /* message for stderr, if element encountered */
int ignore; /* flag - ignore content or data of element? */
int verbatim; /* flag - pass content verbatim or do cmap? */
char *var_reset;
char *increment; /* increment these variables */
Map_t *set_var; /* set these variables */
Map_t *incr_var; /* increment these variables */
char *quit; /* print message and exit */
/* pointers and bookkeeping */
int my_id; /* unique (hopefully) ID of this transpec */
int use_id; /* use transpec whose ID is this */
struct _Trans *use_trans; /* pointer to other transpec */
struct _Trans *next; /* linked list */
int lineno; /* line number of end of transpec */
} Trans_t;
#ifdef def
#undef def
#endif
#ifdef STORAGE
# define def
#else
# define def extern
#endif
def Trans_t *TrSpecs;
def Mapping_t *CharMap;
def int nCharMap;
/* prototypes for things defined in translate.c */
int CheckRelation(Element_t *, char *, char *, char *, FILE*, RelAction_t);
Trans_t *FindTrans(Element_t *, int);
Trans_t *FindTransByName(char *);
Trans_t *FindTransByID(int);
void PrepTranspecs(Element_t *);
void ProcessOneSpec(char *, Element_t *, FILE *, int);
void TransElement(Element_t *, FILE *, Trans_t *);
void TranByAction(Element_t *, int, FILE *);
void TranTByAction(Element_t *, char *, FILE *);
/* prototypes for things defined in tranvar.c */
void ExpandSpecialVar(char *, Element_t *, FILE *, int);
/* prototypes for things defined in tables.c */
void OSFtable(Element_t *, FILE *, char **, int);
/* ______________________________________________________________________ */

View File

@ -0,0 +1,526 @@
...\"
...\"
...\" Copyright (c) 1994
...\" Open Software Foundation, Inc.
...\"
...\" Permission is hereby granted to use, copy, modify and freely distribute
...\" the software in this file and its documentation for any purpose without
...\" fee, provided that the above copyright notice appears in all copies and
...\" that both the copyright notice and this permission notice appear in
...\" supporting documentation. Further, provided that the name of Open
...\" Software Foundation, Inc. ("OSF") not be used in advertising or
...\" publicity pertaining to distribution of the software without prior
...\" written permission from OSF. OSF makes no representations about the
...\" suitability of this software for any purpose. It is provided "as is"
...\" without express or implied warranty.
...\"
...\" Copyright (c) 1996 X Consortium
...\" Copyright (c) 1996 Dalrymple Consulting
...\"
...\" Permission is hereby granted, free of charge, to any person obtaining a copy
...\" of this software and associated documentation files (the "Software"), to deal
...\" in the Software without restriction, including without limitation the rights
...\" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
...\" copies of the Software, and to permit persons to whom the Software is
...\" furnished to do so, subject to the following conditions:
...\"
...\" The above copyright notice and this permission notice shall be included in
...\" all copies or substantial portions of the Software.
...\"
...\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
...\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
...\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
...\" X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
...\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
...\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
...\" OTHER DEALINGS IN THE SOFTWARE.
...\"
...\" Except as contained in this notice, the names of the X Consortium and
...\" Dalrymple Consulting shall not be used in advertising or otherwise to
...\" promote the sale, use or other dealings in this Software without prior
...\" written authorization.
...\"
...\" Translated with /usr/local/lib/tpt/ref-man.ts by fld on cord, Wed 07 Feb 1996, 22:00
.TH "\fBtranspec\fP" "file format"
.SH "Name"
\fBtranspec\fP - translation specification for \fBinstant\fP
.SH "Synopsis"
.na
.PP
\fBfile.ts\fP
.ad
.SH "Description"
.PP
The \fBtranspec\fP file is used by the \fBinstant\fP program to translate an SGML document instance to a format suitable for a formatting application.
The convention is to name the file with the suffix \fB.ts\fP.
.PP
A \fBtranspec\fP file is composed of a number of individual translation specs.
Each translation spec (transpec) is made up of a number of fields, one per line.
Translation specs are separated by a line with a leading dash. Text after the dash is ignored.
Fields are composed of two parts, a name and a value, separated by a colon.
The colon must immediately follow the name, and any amount of whitespace (blanks and tabs) may be present between the colon and value.
Values should not be quoted, and you should be careful of trailing spaces.
(Trailing space will be considered part of the value.)
Quotes, if they appear, will be considered part of the value of the fields.
Lines that begin with whitespace (blanks and tabs) are a continuation of the previous line; the leading space is ignored.
These characteristics are very similar to those of e-mail headers.
Lines beginning with a \fB#\fP (number sign) are comments and blank lines are ignored.
.SH "Field Descriptions"
.PP
Some fields are for identifying criteria that determines if a particular spec matches an element in the instance.
Others specify what action is to take place when a match happens, such as sending text to the output stream.
.SS "Criteria fields"
.PP
Criteria fields restrict the conditions under which a single translation spec will apply.
If each field specified in a particular transpec matches an element under consideration in the document instance,
then that translation spec is said to match. The appropriate actions, as specified in that spec, are then taken.
The program, \fBinstant\fP, searches the list of transpecs in the order given in the file.
Therefore, the more restrictive specs (those with more criteria) should appear before less restrictive ones.
.PP
For quick reference, this is a brief summary of the possible criteria fields for translation. A complete discussion of each follows.
.P
.TS
tab(@);
l l l.
\fBField Label\fR@\fBField Value\fR@\fBDescription\fR
GI@gi ...@name of this GI
AttValue@attname reg-expr@current element has attribute with value
Content@reg-expr@is reg-expr in char content>
Context@context@element context, up the tree
NthChild@number@current element is Nth child of its parent
PAttSet@attname (val)@parent has this attribute set (optional to value val)
Relation@relationship gi@gi has relationship to current element
VarREValue@var REvalue@variable is set to regular expression value
VarValue@var value@variable is set to value
.TE
'br\" labeled list
.IP "\fBGI:\fP \fIgi\fP [...]"
\fIgi\fP is the name of the generic identifier, or element name, to consider.
More than one GI may appear in this field.
.IP "\fBAttValue:\fP \fIattname\fP \fIregular-expression\fP"
This is an attribute name-value pair, where \fIattname\fP is an attribute if the GI.
The \fIregular-expression\fP is of the form accepted by the unix program \fBegrep\fP.
This pair is compared to the corresponding attribute name-value pairs of the GI under consideration.
To simply test if an attribute us set, use \fB.\fP (a dot) for \fIregular-expression\fP.
There may be more than one of these lines for each transpec.
.IP "\fBContent:\fP \fIregular-expression\fP"
This specifies that the character content of GI contains a string matching the \fIregular-expression\fP.
.IP "\fBContext:\fP \fIcontext\fP"
This specifies the \fIcontext\fP in which to apply this translation spec.
It is either a list of generic identifiers or a regular expression describing a list of generic identifiers, looking up the hierarchy.
The first is the parent of the GI.
.IP "\fBNthChild:\fP \fInumber\fP"
This specifies that the GI is the \fInumber\fPth child element of its parent.
Children are numbered starting with \fB1\fP.
Negative numbers may be used to indicate order counting backwards.
For example, -1 denotes the last child.
.IP "\fBPAttSet:\fP \fIattname\fP"
This specifies that the parent has this attribute, \fIattname\fP, set to any value (not IMPLIED). A value to match may optionally
be specified after attname.
.IP "\fBRelation:\fP \fIrelationship\fP \fIgi\fP"
This specifies that the current element has the \fIrelationship\fP to the named \fIgi\fP.
The acceptable relationships are: \fBancestor\fP (anywhere up the tree), \fBchild\fP (immediate child),
\fBdescendant\fP (anywhere down the tree), \fBparent\fP (immediate ancestor), \fBsibling\fP (share same parent element),
\fBsibling+\fP (any later sibling), \fBsibling+1\fP (the immediately following sibling), \fBsibling-\fP (any earlier sibling),
\fBsibling-1\fP (the immediately following sibling).
.IP "\fBVarREValue:\fP \fIvarname\fP \fIREvalue\fP"
This specifies that the global variable \fIvarname\fP has the value \fIREvalue\fP,
where \fIREvalue\fP is a regular expression
(see the \fBVarValue\fP statement).
.IP "\fBVarValue:\fP \fIvarname\fP \fIvalue\fP"
This specifies that the global variable \fIvarname\fP has the (literal)
value \fIvalue\fP (see the \fBVarREValue\fP statement).
'br\" labeled list end
.PP
There are two special GIs.
If specified, \fB_Start\fP and \fB_End\fP are processed as if they were GIs in the instance at the start and end of the translation, respectively.
Their criteria are never checked. Only their actions are performed.
.SS "Action fields"
.PP
For quick reference, this is a brief summary of the action fields for translation. They are only performed if all the criteria are satisfied.
A complete discussion of each follows.
.P
.TS
tab(@);
l l l.
\fBField Label\fR@\fBField Value\fR@\fBDescription\fR
Action@spec-id@use transpec whose spec ID is `spec-id'
EndText@text@text for end of element
Increment@name@increment variable `name'
Ignore@key@flag for ignoring element's children and/or data
Message@text@text to send to stderr
Quit@text@print text and quit program
Replace@text@replace this subtree with text
Set@name value@set variable \fIname\fP to \fIvalue\fP
SpecID@spec-id@unique Spec ID (int) of this spec
StartText@text@text for start of element
.TE
'br\" labeled list
.IP "\fBAction:\fP \fIspec-id\fP"
Use the actions of the spec identified by the \fBSpecID\fP with matching identifier \fIspec-id\fP.
.IP "\fBEndText:\fP \fItext\fP"
This specifies text to be output when the end tag is processed.
.IP "\fBIgnore:\fP \fIkey\fP"
This specifies that the data or children for this element are to be ignored.
Set \fIkey\fP to \fBall\fP to ignore the element (data and child elements),
to \fBdata\fP to ignore the immediate character data content (child elements are still descended into),
and to \fBchildren\fP to process the immediate character data content but not descended into child elements.
Other actions specified in this transpec are still performed, however.
.IP "\fBIncrement:\fP \fIname\fP"
This is used to increment a variable whose value is a number.
If the variable is not a number, no action will be taken.
The variable must have been previously defined. This action is done immediately before \fBEndText\fP.
There may be more than one of these lines for each transpec.
.IP "\fBMessage:\fP \fItext\fP"
This specifies a string to be printed to the standard error when the matching element is processed.
It is intended for informing the user of the progress of the translation.
It is also used for validation of instances (see the \fB-v\fP flag of \fBinstant\fP(1));
a spec would be written to recognize a construct that is not allowed.
This action is done immediately after \fBStartText\fP.
Messages are also useful for debugging spec files; one is able to easily tell when a matching spec is processed,
without looking at the actual output of the translation.
Note that the spec writer is responsible for putting newlines (\fB\en\fP) in the message text.
.IP "\fBReplace:\fP \fItext\fP"
This specifies text to replace the current subtree with.
This is equivalent to \fBStartText\fP and \fBIgnore\fP.
.IP "\fBQuit:\fP \fItext\fP"
This specifies text to be printed to the standard error. The program then terminates with exit status 1.
This is intended for bailing out when an undesirable instance is encountered
(such as when it is known that the formatting application can never handle a class of components, like tables).
.IP "\fBSet:\fP \fIname\fP \fIvalue\fP"
This is used to set a variable whose name is \fIname\fP and value is \fIvalue\fP.
Names that would be valid for GIs in the document instance are valid for variable names.
\fIvalue\fP is the rest of the line and may be any string. This action is done immediately before \fBEndText\fP.
There may be more than one of these lines for each transpec.
See the discussion on variables below.
.IP "\fBSpecID:\fP \fIspec-id\fP"
This names the spec with the number \fIspec-id\fP. Other specs may refer to this one by this number by an \fBAction\fP field or an \fB_action\fP special variable.
This is used for cases where several specs to perform the exact same action.
.IP "\fBStartText:\fP \fItext\fP"
This specifies text to be output when the start tag is processed.
'br\" labeled list end
.SS "Other Fields"
.PP
These fields may appear anywhere. The action occurs when the translation spec file is read, before any elements are translated.
Theses are independent of any element processing.
'br\" labeled list
.IP "\fBVar:\fP \fIname\fP \fIvalue\fP"
This is used to define a variable whose name is \fIname\fP and value is \fIvalue\fP.
It is similar to \fBSet\fP, but it may occur anywhere in the file and takes effect when the spec file is read.
'br\" labeled list end
.SS "Text Strings"
.PP
The \fItext\fP referred to in the \fBStartText\fP, \fBEndText\fP, \fBReplace\fP,
and \fBMessage\fP actions is more than simple character strings.
Special sequences allow more complex output.
.PP
One type of special sequence is for C-style string processing.
Most special characters are escaped with a \e (backslash). Like in C or shell programs, to print a \e (backslash), you must escape it with another backslash. These special character strings are:
'br\" labeled list
.IP "\fB\en (backslash-n)\fP"
This specifies that a newline character is to be printed to the output stream.
.IP "\fB\er (backslash-r)\fP"
This specifies that a carriage return character is to be printed to the output stream.
.IP "\fB\et (backslash-t)\fP"
This specifies that a tab character is to be printed to the output stream.
.IP "\fB\es (backslash-s)\fP"
This specifies that a space is to be printed to the output stream.
This is useful for the end of a transpec line, where it can be difficult to tell if a blank is present at the end.
.IP "\fB\e007 (backslash-007)\fP"
This specifies that the character whose octal value is 007 is to be printed to the output stream.
This works for any octal character value.
.IP "\fB^ (caret)\fP"
This specifies the that position in the string will be at the start of a line in the output stream.
'br\" labeled list end
.PP
If the first token of the text string is \fB#include\fP, then the second token is taken to be a file name and that file is included.
If the file is not found, the library directory, as mentioned above, is searched.
If the text string starts with a \fB!\fP (exclamation point), the rest of the line is taken to be a command and the output of that command is inserted.
.PP
An element's attributes may also be used in the text of output fields.
To use an attribute value, precede its name with a \fB${\fP (dollar sign-left curly bracket) and follow it with a \fB}\fP (right curly bracket).
(This style is followed by the Bourne shell.) For example, \fB${TYPE}\fP.
If the attribute is not set (not IMPLIED), nothing will be printed to the output stream.
To specify a value to use if the attribute is not set, place the value after the attribute name, separated by a space.
To return the attribute value in lower-case, add a colon followed by
lower-case l (\fB${TYPE:l}\fP.
.SH "Variables"
.PP
Variables in \fBinstant\fP are similar to those in many other string-oriented programming languages, such as \fBsh\fP and \fBawk\fP.
They are set by: \fBVar:\fP \fIname\fP \fIvalue\fP and \fBSet:\fP \fIname\fP \fIvalue\fP.
Values may be set and reset to any string.
In a \fBVar\fP line, if the value begins with a \fB!\fP,
then the rest of the line is executed as a command, and its output is taken as the \fIvalue\fP.
.PP
A reference to the value of a variable follows the same syntax as
a reference to the value of an attribute: \fB${\fIname\fB}\fR.
If that variable has not been defined, a null value will be returned.
A default value can be returned instead of null for an undefined variable
by using the form: \fB${\fIname default\fB}\fR.
.PP
Variables may be used as attributes are, that is in any of the text strings mentioned above.
In fact, if an attribute name is referred to and it is not set for a given element,
\fBinstant\fP looks for a variable with the same name. This way global defaults can be set.
If you want to be sure that you are accessing a local variable value, not an attribute value, you can use lower or mixed case names.
Attribute names, as passed by \fBsgmls\fP, are in upper case.
.PP
Any number of \fBVar\fP actions may appear in the spec file. These set the values of the variables before any translation takes place.
The \fBSet\fP actions within transpecs are performed when that spec is processed when an element matches the given criteria.
.SS "Preset Variables"
.PP
Several variables are preset by \fBinstant\fP upon start of the program.
Their values may be overridden in transpec files or on the command line.
'br\" labeled list
.IP "\fBdate\fP"
This is the date and time that the program started. The format is: \f(CWTue 10 Aug 1993, 16:52\fP.
.IP "\fBhost\fP"
This is the name of the host where the program is run. It is what is returned by the \fBgethostname\fP library call.
.IP "\fBtranspec\fP"
This is the translation spec filename.
.IP "\fBuser\fP"
This is the login name of the user running the program.
'br\" labeled list end
.SS "Special Variables"
.PP
There is a collection of special variables called \fIspecial variables\fP.
These are identified by starting the names with a \fB_\fP (underscore).
This is a summary of the special variables. A complete discussion of each special variable follows.
\fBspec-id\fP refers to a number specified in a \fBSpecID\fP field.
When used in a special variable, it means to perform the action in that translation spec.
.PP
Note that when a \fIspec-id\fR is given in a special variable,
the default is to perform the translation spec named by the \fIspec-id\fR ignoring
of any criteria statements found there.
For most special variables that use a \fIspec-id\fP, postpending a "\fBt\fR" to
the \fIspec-id\fR (with no spaces between them, eg,
"\fB${_followrel child TITLE 15t}\fR"), will cause the criteria statements
in the named translation spec to evaluate successfully before that translation
spec will be processed.
.P
.TS
tab(@);
l l.
\fBVariable Usage\fR@\fBDescription\fR
\fB_action\fP \fIspec-id\fP@do spec with id spec-id
\fB_allatts\fP@print all attribute/value pairs
\fB_attval\fP \fIatt\fP [\fIvalue\fP] \fIspec-id\fP@use spec-id if attribute matches
\fB_chasetogi\fP \fIgi\fP \fIspec-id\fP@follow IDREFs until gi found
\fB_eachatt\fP \fIatt\fP \fIspec-id\fP [\fIspec-id\fP]@do spec-id for each word of attribute value
\fB_eachcon\fP \fIspec-id\fP [\fIspec-id\fP]@do spec-id for each word of content
\fB_env\fP \fIenv-variable\fP@return value of env variable
\fB_filename\fP@filename of notation
\fB_find\fP \fIrel\fP \fIgi\fP \fIspec-id\fP@find gi based on relationship
\fB_followlink\fP [\fIattname\fP] \fIspec-id\fP@follow IDREFs [attname] and use spec-id
\fB_followrel\fP \fIrel\fP \fIgi\fP \fIspec-id\fP@do spec-id on rel if it matches
\fB_gi\fP [\fBM|L|U\fP]@return GI name; M, L, U case
\fB_id\fP \fIid [\fP\fIspec-id\fP]@find element with ID and use spec-id
\fB_include\fP \fIfilename\fP@insert file here
\fB_infile\fP [\fBline\fP]@instance filename [and line number]
\fB_insertnode\fP S|E \fIspec-id\fP@do spec-id when element is traversed
\fB_isset\fP \fIvar\fP [\fIvalue\fP] \fIspec-id\fP@do spec-id if variable matches
\fB_location\fP@print location of current element
\fB_namelist\fP \fIspec-id\fP [\fIspec-id\fP]@content is namelist, do spec-id for each
\fB_nchild\fP [\fIgi\fP]@number of child elements [named \fIattname\fP]
\fB_osftable\fP \fIformat\fP [\fIflag\fP]@print table format specification
\fB_path\fP@print path to current element
\fB_pattr\fP \fIattname\fP@value of parent's attribute
\fB_pfind\fP \fIargs ...\fP@same as \fB_find\fP, but start at parent
\fB_relation\fP \fIrel\fP \fIgi\fP \fIspec-id\fP [\fIspec-id\fP]@do spec-id if relation matches
\fB_set\fP \fIvar\fP \fIvalue\fP@set variable to value
\fB_!\fP\fIcommand\fP@command to run
.TE
'br\" labeled list
.IP "\fB_action\fP \fIspec-id\fP"
Use the actions of the spec identified by the \fBSpecID\fP with matching identifier \fIspec-id\fP.
This behaves similarly to the \fBAction\fP action, but is in addition to the present translation spec.
.IP "\fB_allatts\fP"
Print all attribute name-value pairs of the current element to the output stream.
The name and value are separated by a \fB=\fP (equals sign), and the value is surrounded by quotes.
This can be useful for creating a normalized version of the instance.
.IP "\fB_attval\fP \fIattname\fP [\fIvalue\fP] \fIspec-id\fP"
If the current element has an attribute named \fIattname\fP, optionally whose value matches \fIvalue\fP,
use the actions of the transpec identified by \fIspec-id\fP.
.IP "\fB_chasetogi\fP \fIgi\fP \fIspec-id\fP"
Follow IDREF attributes until if finds an element whose GI is \fIgi\fP or which has a child element with that GI.
It will apply the transpec \fIspec-id\fP to that element.
By default, \fBinstant\fP assumes the attributes named \fBLINKEND\fP, \fBLINKENDS\fP, and \fBIDREF\fP are of type IDREF or IDREFS.
(This corresponds with the OSF DTDs.)
You can change this by setting the variable \fBlink_atts\fP to a space-separated list of attribute names.
.IP "\fB_eachatt\fP \fIatt\fP \fIspec-id\fP [\fIspec-id2\fP]"
The transpec named by \fIspec-id\fR is invoked once per each word
found in the value of the attribute \fIatt\fR.
Inside the target transpec, the current word being processed
is available in the variable named \fBeach_A\fR (\fB${each_A}\fR).
If \fIspec-id2\fP is specified, it will use \fIspec-id\fP for the first word
in the attribute and \fIspec-id2\fP for the others.
.IP "\fB_eachcon\fP \fIspec-id\fP [\fIspec-id2\fP]"
The transpec named by \fIspec-id\fR is invoked once per each word
found in the content of the current element.
Inside the target transpec, the current word being processed
is available in the variable named \fBeach_C\fR (\fB${each_C}\fR).
If \fIspec-id2\fP is specified, it will use \fIspec-id\fP for the first word
in the content and \fIspec-id2\fP for the others.
.IP "\fB_env\fP \fIenv-variable\fP"
Print the value of the environment variable \fIenv-variable\fP to the output stream.
.IP "\fB_filename\fP"
Print the filename of the notation associated with this element, if any.
This is used to get the filename of an external notation entity reference.
For example, to print the filename in the latex macro from the epsf macro package, use \f(CW\e\eepsfboxi{${_filename}}\fP.
.IP "\fB_find\fP [\fBtop\fP] \fIrelationship\fP \fIargs ...\fP \fIspec-id\fP"
Descend the document hierarchy finding elements that match one of several criteria.
When one is found, the action specified by \fIspec-id\fP is performed.
If \fBtop\fP is specified, the search starts at the top of the document hierarchy, rather than at the current element.
The possible values for \fIrelationship\fP are \fBgi\fP, \fBgi-parent\fP, \fBparent\fP, and \fBattr\fP,
and take different arguments.
Explanations may be best done by example:
\fB_find gi CHAPTER 123\fP means to find elements whose GI is CHAPTER, and perform action 123;
\fB_find gi-parent TITLE CHAPTER 124\fP means to find elements whose GI is TITLE and whose parent is CHAPTER, and perform action 124;
\fB_find parent BODY 125\fP means to find elements whose parent's GI is BODY, and perform action 125;
\fB_find attr TYPE UGLY 125\fP means to find elements whose attribute named TYPE is set to UGLY, and perform action 126.
.IP "\fB_followlink\fP [\fIattname\fP] \fIspec-id\fP"
When processing an element, \fBinstant\fP will follow the IDREF attributes until an element with no IDREF attributes is found.
It will then apply the transpec specified by \fIspec-id\fP to that element.
If specified, it will follow the link pointed to by \fIattname\fP.
By default, \fBinstant\fP assumes the attributes named \fBLINKEND\fP and \fBLINKENDS\fP are if type IDREF or IDREFS.
You can change this by setting the variable \fBlink_atts\fP to a space-separated list of attribute names.
.IP "\fB_followrel\fP \fIrelationship\fP \fIgi\fP \fIspec-id\fP"
If the \fIgi\fP has the specified \fIrelationship\fP to the current element,
perform the action specified by \fIspec-id\fP on the related element.
See the discussion of the criteria field \fBRelation\fP for acceptable relationship names.
.IP "\fB_gi\fP [\fBM|L|U\fP]"
Print the name of the current GI to the output stream.
If specified, \fBM\fP, \fBL\fP, or \fBU\fP will ensure the GI name is printed in mixed, lower, or upper case, respectively.
.IP "\fB_id\fP \fIid\fP [\fIspec-id\fP]"
Find the element with \fIid\fP and use \fIspec-id\fP, if set. If not set, use the spec for that element's context.
.IP "\fB_include\fP \fIfilename\fP"
Insert the file \fIfilename\fP into the output stream.
.IP "\fB_infile\fP [\fBline\fP]"
Print the name of the sgml instance file to the output stream. If \fBline\fP is specified, also print the line number.
This depends on \fBsgmls\fP being called with the \fB-l\fP option.
.IP "\fB_insertnode\fP \fBS\fP|\fBE\fP \fIspec-id\fP"
Do \fIspec-id\fP when the current element is traversed at a later pass.
This can be considered inserting a node, without content, into the hierarchy.
This is only useful if done to elements \fIbefore\fP they are processed.
Typically \fB_chasetogi\fP or \fB_followlink\fP is specified early in an instance's processing,
so that when the elements found by one of these actions are processed in their turn, the added actions are performed.
\fB_insertnode\fP would be specified as the action of a \fIspec-id\fP pointed to in a \fB_chasetogi\fP or \fB_followlink\fP usage.
.IP "\fB_location\fP"
The location of the current element is printed to the output stream in several ways: the path to the element (see \fB_path\fP),
a position hint, which is the nearest title, the line number, if the ESIS (output from \fBsgmls\fP) contains line numbers,
and the ID of the element, if it has one.
This is especially useful when using the \fBMessage\fP action to validate an instance.
.IP "\fB_namelist\fP \fIspec-id\fP [\fIspec-id2\fP]"
This assumes that the content of the current element is a namelist (a list of element IDs),
and applies the action based on \fIspec-id\fP for each element pointed to.
If \fIspec-id2\fP is specified, it will use \fIspec-id\fP for the first ID in the namelist and \fIspec-id2\fP for the others.
.IP "\fB_nchild\fP [\fIgi\fP]"
Print the number of child elements of the element to the output stream.
If \fIgi\fP is specified, print the number of child element with that name.
.IP "\fB_osftable\fP \fBtex\fP|\fBtbl\fP|\fBcheck\fP [\fIflag\fP]"
Print table markup into the output stream. The format depends on whether \fBtex\fP or \fBtbl\fP is specified.
The \fIflag\fP may be one of \fBcellstart\fP, \fBcellend\fP, \fBrowstart\fP, \fBrowend\fP, \fBtop\fP, or \fBbottom\fP.
The value determines what markup or text will be generated.
If \fBcellstart\fP is specified, the correct markup for the beginning of a cell is output.
If \fBtop\fP, \fBbottom\fP, or \fBrowend\fP are specified,
the correct markup for the end of the appropriate position is printed to the output stream.
If \fBcheck\fP is specified, the attributes and child elements are checked for errors and consistency.
.IP "\fB_path\fP"
Print the path to current GI to the output stream. A path is each element, going down the tree from the topmost element.
A number in parentheses after each element name shows which child element the next one is in the order of children for that element.
Ordering starts at 0.
For example: \f(CWOSF-BOOK(3) BODY(0) CHAPTER(4) SECTION\fP.
This says the path is \fB<OSF-BOOK>\fP's third child, \fB<BODY>\fP's zeroth,
and \fB<CHAPTER>\fP's fourth, which is named \fB<SECTION>\fP.
.IP "\fB_pattr\fP \fIname\fP"
Print the value of parent's attribute whose name is \fIname\fP to the output stream.
.IP "\fB_pfind\fP \fIrel\fP \fIgi\fP \fIspec-id\fP"
This is exactly the same as \fB_find\fP except that the search starts at the current element's parent.
.IP "\fB_relation\fP \fIrelationship\fP \fIgi\fP \fIspec-id\fP [\fIspec-id2\fP]"
If the \fIgi\fP has the specified \fIrelationship\fP to the current element,
perform the action specified by \fIspec-id\fP on the current element.
If the relationship test fails and \fIspec-id2\fP is specified, perform that action.
See the discussion of the criteria field \fBRelation\fP for acceptable relationship names.
.IP "\fB_set\fP \fIvarname\fP \fIvalue\fP"
Set the value of the variable \fIvarname\fP to \fIvalue\fP.
.IP "\fB_isset\fP \fIvarname\fP [\fIvalue\fP] \fIspec-id\fP"
If the value of the variable \fIvarname\fP is set to \fIvalue\fP, then perform action referred to by \fIspec-id\fP.
If \fIvalue\fP is not specified, action will be performed if \fIvarname\fP is set to any value.
.IP "\fB_!\fP \fIcommand\fP"
Run the command \fIcommand\fP, directing its standard output into the output stream.
'br\" labeled list end
.SS "Immediate Variables"
.PP
\fIImmediate variables\fR are like special variables, except that they
are expanded when the transpec is originally processed (special
variables are processed later, near when the final output is being generated).
The general syntax of immediate variables is \fB${+\fIimmediate_variable\ ...\fB}\fR.
.PP
There is currently only one immediate variable defined:
.IP "\fB+content\fP"
This special variable is replaced by the data content of the current element.
.SH "Examples"
.PP
The following will output the given string for elements whose generic identifier is \fBP\fP (for paragraph).
At the start of processing this element, the program ensures that the output starts on a new line,
the \fBtroff\fP macro \fB<.P>\fP is output, then a newline.
At the end of this element processing, the program ensures that the output starts on a new line.
.DS
.nf
.ft CW
GI: P
StartText: ^.P^
EndText: ^
-
.ft R
.fi
.DE
.PP
The following will output the given string for elements whose generic identifier is \fBCMD-ARGUMENT\fP and which have an
attribute \fBPRESENCE\fP set to the value \fBOPTIONAL\fP.
.DS
.nf
.ft CW
GI: CMD-ARGUMENT
AttValue: PRESENCE OPTIONAL
StartText: $\e\e[
EndText: $\e\e]
-
.ft R
.fi
.DE
.PP
The following prints the section number, title, and page number of the target of a cross reference.
Assume the cross reference points to a section element, which contains a title element.
The criteria for this spec to match is that the attribute \fBOSFROLE\fP is set to the value \fBgetfull\fP.
The action is to replace the content of the \fB<XREF>\fP element with the given string.
When processing the string, \fBinstant\fP will follow the IDREF attributes of \fB<XREF>\fP
until an element with no IDREF attributes is found. It will then apply the transpec numbered \fB87\fP to that element,
which will print the name of the GI in mixed case into the output stream.
It will then print the LaTeX reference instruction with the value of the \fBLINKEND\fP attribute as an argument.
(This will become the section number after processing by LaTeX.)
It will then follow IDREFs until if finds an element whose GI is \fBTITLE\fP or which has a child element with that GI.
It will apply the transpec numbered \fB1\fP to that element, which copies the title into the output stream where the cross reference occurs.
Finally, it will print the word \fBpage\fP followed by the LaTeX instruction to obtain the page number of a reference.
.DS
.nf
.ft CW
GI: XREF
AttValue: OSFROLE getfull
Replace: ${_followlink 87} \e\eref{${LINKEND}},\es
{\e\ebf ${_chasetogi TITLE 1}}, page \e\epageref{${LINKEND}}
-
# Print GI name, in mixed case
GI: _pr_gi_name
SpecID: 87
Ignore: 1
EndText: ${_gi M}
-
GI: _pass-text
SpecID: 1
-
.ft R
.fi
.DE
.SH "Related Information"
.PP
\fBinstant\fP(1), \fBsgmls\fP(1), \fBegrep\fP(1).

View File

@ -0,0 +1,757 @@
/*
* Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
* All rights reserved.
*/
/*
* Copyright (c) 1994
* Open Software Foundation, Inc.
*
* Permission is hereby granted to use, copy, modify and freely distribute
* the software in this file and its documentation for any purpose without
* fee, provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation. Further, provided that the name of Open
* Software Foundation, Inc. ("OSF") not be used in advertising or
* publicity pertaining to distribution of the software without prior
* written permission from OSF. OSF makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
/*
* Copyright (c) 1996 X Consortium
* Copyright (c) 1995, 1996 Dalrymple Consulting
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the X Consortium and
* Dalrymple Consulting shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without prior
* written authorization.
*/
/* ________________________________________________________________________
*
* instant - a program to manipulate SGML instances.
*
* This module is for handling "special variables". These act a lot like
* procedure calls
* ________________________________________________________________________
*/
#ifndef lint
static char *RCSid =
"$Header: /usr/src/docbook-to-man/Instant/RCS/tranvar.c,v 1.5 1996/06/11 22:43:15 fld Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <memory.h>
#include <sys/types.h>
#include <errno.h>
#include <regexp.h>
#include "general.h"
#include "translate.h"
static char **idrefs; /* list of IDREF att names to follow */
static char *def_idrefs[] = { "LINKEND", "LINKENDS", "IDREF", 0 };
static char *each_A = 0; /* last seen _eachatt */
static char *each_C = 0; /* last seen _eachcon */
/* forward references */
void ChaseIDRefs(Element_t *, char *, char *, FILE *);
void Find(Element_t *, int, char **, FILE *);
void GetIDREFnames();
/* ______________________________________________________________________ */
/* Handle "special" variable - read file, run command, do action, etc.
* Arguments:
* Name of special variable to expand.
* Pointer to element under consideration.
* FILE pointer to where to write output.
* Flag saying whether to track the character position we're on
* (passed to OutputString).
*/
void
ExpandSpecialVar(
char *name,
Element_t *e,
FILE *fp,
int track_pos
)
{
FILE *infile;
char buf[LINESIZE], *cp, *atval;
char **tok;
int ntok, n, i, actioni;
char *action, *action1;
Element_t *ep;
Trans_t *t, *tt;
/* Run a command.
* Format: _! command args ... */
if (*name == '!') {
name++;
if ((infile = popen(name, "r"))) {
while (fgets(buf, LINESIZE, infile)) fputs(buf, fp);
pclose(infile);
fflush(fp);
}
else {
fprintf(stderr, "Could not start program '%s': %s",
name, strerror(errno));
}
return;
}
/* See if caller wants one of the tokens from _eachatt or _eachcon.
* If so, output it and return. (Yes, I admit that this is a hack.)
*/
if (*name == 'A' && name[1] == EOS && each_A) {
OutputString(each_A, fp, track_pos);
return;
}
if (*name == 'C' && name[1] == EOS && each_C) {
OutputString(each_C, fp, track_pos);
return;
}
ntok = 0;
tok = Split(name, &ntok, 0);
/* Include another file.
* Format: _include filename */
if (StrEq(tok[0], "include")) {
name = tok[1];
if (ntok > 1 ) {
if ((infile=OpenFile(name)) == NULL) {
sprintf(buf, "Can not open included file '%s'", name);
perror(buf);
return;
}
while (fgets(buf, LINESIZE, infile)) fputs(buf, fp);
fclose(infile);
}
else fprintf(stderr, "No file name specified for include\n");
return;
}
/* Print location (nearest title, line no, path).
* Format: _location */
else if (StrEq(tok[0], "location")) {
PrintLocation(e, fp);
}
/* Print path to this element.
* Format: _path */
else if (StrEq(tok[0], "path")) {
(void)FindElementPath(e, buf);
OutputString(buf, fp, track_pos);
}
/* Print name of this element (gi).
* Format: _gi [M|L|U] */
else if (StrEq(tok[0], "gi")) {
strcpy(buf, e->gi);
if (ntok >= 2) {
if (*tok[1] == 'L' || *tok[1] == 'l' ||
*tok[1] == 'M' || *tok[1] == 'm') {
for (cp=buf; *cp; cp++)
if (isupper(*cp)) *cp = tolower(*cp);
}
if (*tok[1] == 'M' || *tok[1] == 'm')
if (islower(buf[0])) buf[0] = toupper(buf[0]);
}
OutputString(buf, fp, track_pos);
}
/* Print filename of this element's associated external entity.
* Format: _filename */
else if (StrEq(tok[0], "filename")) {
if (!e->entity) {
fprintf(stderr, "Expected ext entity (internal error? bug?):\n");
PrintLocation(e, stderr);
return;
}
if (!e->entity->fname) {
fprintf(stderr, "Expected filename (internal error? bug?):\n");
PrintLocation(e, stderr);
return;
}
OutputString(e->entity->fname, fp, track_pos);
}
/* Value of parent's attribute, by attr name.
* Format: _pattr attname */
else if (StrEq(tok[0], "pattr")) {
ep = e->parent;
if (!ep) {
fprintf(stderr, "Element does not have a parent:\n");
PrintLocation(ep, stderr);
return;
}
if ((atval = FindAttValByName(ep, tok[1]))) {
OutputString(atval, fp, track_pos);
}
}
/* Use an action, given transpec's SID.
* Format: _action action */
else if (StrEq(tok[0], "action")) {
TranTByAction(e, tok[1], fp);
}
/* Number of child elements of this element.
* Format: _nchild */
else if (StrEq(tok[0], "nchild")) {
if (ntok > 1) {
for (n=0,i=0; i<e->necont; i++)
if (StrEq(e->econt[i]->gi, tok[1])) n++;
}
else n = e->necont;
sprintf(buf, "%d", n);
OutputString(buf, fp, track_pos);
}
/* number of 1st child's child elements (grandchildren from first child).
* Format: _n1gchild */
else if (StrEq(tok[0], "n1gchild")) {
if (e->necont) {
sprintf(buf, "%d", e->econt[0]->necont);
OutputString(buf, fp, track_pos);
}
}
/* Chase this element's pointers until we hit the named GI.
* Do the action if it matches.
* Format: _chasetogi gi action */
else if (StrEq(tok[0], "chasetogi")) {
if (ntok < 3) {
fprintf(stderr, "Error: Not enough args for _chasetogi.\n");
return;
}
actioni = atoi(tok[2]);
if (actioni) ChaseIDRefs(e, tok[1], tok[2], fp);
}
/* Follow link to element pointed to, then do action.
* Format: _followlink [attname] action. */
else if (StrEq(tok[0], "followlink")) {
char **s;
if (ntok > 2) {
if ((atval = FindAttValByName(e, tok[1]))) {
if ((ep = FindElemByID(atval))) {
TranTByAction(ep, tok[2], fp);
return;
}
}
else fprintf(stderr, "Error: Did not find attr: %s.\n", tok[1]);
return;
}
GetIDREFnames();
for (s=idrefs; *s; s++) {
/* is this IDREF attr set? */
if ((atval = FindAttValByName(e, *s))) {
ntok = 0;
tok = Split(atval, &ntok, S_STRDUP);
/* we'll follow the first one... */
if ((ep = FindElemByID(tok[0]))) {
TranTByAction(ep, tok[1], fp);
return;
}
else fprintf(stderr, "Error: Can not find elem for ID: %s.\n",
tok[0]);
}
}
fprintf(stderr, "Error: Element does not have IDREF attribute set:\n");
PrintLocation(e, stderr);
return;
}
/* Starting at this element, decend tree (in-order), finding GI.
* Do the action if it matches.
* Format: _find args ... */
else if (StrEq(tok[0], "find")) {
Find(e, ntok, tok, fp);
}
/* Starting at this element's parent, decend tree (in-order), finding GI.
* Do the action if it matches.
* Format: _pfind args ... */
else if (StrEq(tok[0], "pfind")) {
Find(e->parent ? e->parent : e, ntok, tok, fp);
}
/* Content is supposed to be a list of IDREFs. Follow each, doing action.
* If 2 actions are specified, use 1st for the 1st ID, 2nd for the rest.
* Format: _namelist action [action2] */
else if (StrEq(tok[0], "namelist")) {
int id;
action1 = tok[1];
if (ntok > 2) action = tok[2];
else action = action1;
for (i=0; i<e->ndcont; i++) {
n = 0;
tok = Split(e->dcont[i], &n, S_STRDUP);
for (id=0; id<n; id++) {
if (fold_case)
for (cp=tok[id]; *cp; cp++)
if (islower(*cp)) *cp = toupper(*cp);
if ((e = FindElemByID(tok[id]))) {
if (id) TranTByAction(e, action, fp);
else TranTByAction(e, action1, fp); /* first one */
}
else fprintf(stderr, "Error: Can not find ID: %s.\n", tok[id]);
}
}
}
/* For each word in the element's content, do action.
* Format: _eachcon action [action] */
else if (StrEq(tok[0], "eachcon")) {
int id;
action1 = tok[1];
if (ntok > 3) action = tok[2];
else action = action1;
for (i=0; i<e->ndcont; i++) {
n = 0;
tok = Split(e->dcont[i], &n, S_STRDUP|S_ALVEC);
for (id=0; id<n; id++) {
each_C = tok[id];
TranTByAction(e, action, fp);
}
free(*tok);
}
}
/* For each word in the given attribute's value, do action.
* Format: _eachatt attname action [action] */
else if (StrEq(tok[0], "eachatt")) {
int id;
action1 = tok[2];
if (ntok > 3) action = tok[3];
else action = action1;
if ((atval = FindAttValByName(e, tok[1]))) {
n = 0;
tok = Split(atval, &n, S_STRDUP|S_ALVEC);
for (id=0; id<n; id++) {
each_A = tok[id];
if (id) TranTByAction(e, action, fp);
else TranTByAction(e, action1, fp); /* first one */
}
free(*tok);
}
}
/* Do action on this element if element has [relationship] with gi.
* Format: _relation relationship gi action [action] */
else if (StrEq(tok[0], "relation")) {
if (ntok >= 4) {
if (!CheckRelation(e, tok[1], tok[2], tok[3], fp, RA_Current)) {
/* action not done, see if alt action specified */
if (ntok >= 5)
TranTByAction(e, tok[4], fp);
}
}
}
/* Do action on followed element if element has [relationship] with gi.
* Format: _followrel relationship gi action */
else if (StrEq(tok[0], "followrel")) {
if (ntok >= 4)
(void)CheckRelation(e, tok[1], tok[2], tok[3], fp, RA_Related);
}
/* Find element with matching ID and do action. If action not specified,
* choose the right one appropriate for its context.
* Format: _id id [action] */
else if (StrEq(tok[0], "id")) {
if ((ep = FindElemByID(tok[1]))) {
if (ntok > 2) TranTByAction(ep, tok[2], fp);
else {
t = FindTrans(ep, 0);
TransElement(ep, fp, t);
}
}
}
/* Set variable to value.
* Format: _set name value */
else if (StrEq(tok[0], "set")) {
SetMappingNV(Variables, tok[1], tok[2]);
}
/* Do action if variable is set, optionally to value.
* If not set, do nothing.
* Format: _isset varname [value] action */
else if (StrEq(tok[0], "isset")) {
if ((cp = FindMappingVal(Variables, tok[1]))) {
if (ntok == 3) TranTByAction(e, tok[2], fp);
else if (ntok > 3 && !strcmp(cp, tok[2]))
TranTByAction(e, tok[3], fp);
}
}
/* Insert a node into the tree at start/end, pointing to action to perform.
* Format: _insertnode S|E action */
else if (StrEq(tok[0], "insertnode")) {
actioni = atoi(tok[2]);
if (*tok[1] == 'S') e->gen_trans[0] = actioni;
else if (*tok[1] == 'E') e->gen_trans[1] = actioni;
}
/* Do an CALS DTD table spec for TeX or troff. Looks through attributes
* and determines what to output. "check" means to check consistency,
* and print error messages.
* This is (hopefully) the only hard-coded part of instant.
*
* This was originally written for the OSF DTDs and recoded by FLD for
* CALS tables (since no one will ever use the OSF tables). Although
* TeX was addressed first, it seems that a fresh approach was required,
* and so, tbl is the first to be really *fixed*. Once tbl is stable,
* and there is a need for TeX again, that part will be recoded.
*
* *Obsolete* form (viz, for TeX):
* Format: _calstable [clear|check|tex]
* [cellstart|cellend|rowstart|rowend|top|bottom]
*
* New, good form:
*
* Format: _calstable [tbl]
* [tablestart|tableend|tablegroup|tablefoot|rowstart|
* rowend|entrystart|entryend]
*/
else if (StrEq(tok[0], "calstable")) {
CALStable(e, fp, tok, ntok);
}
/* Do action if element's attr is set, optionally to value.
* If not set, do nothing.
* Format: _attval att [value] action */
else if (StrEq(tok[0], "attval")) {
if ((atval = FindAttValByName(e, tok[1]))) {
if (ntok == 3) TranTByAction(e, tok[2], fp);
else if (ntok > 3 && !strcmp(atval, tok[2]))
TranTByAction(e, tok[3], fp);
}
}
/* Same thing, but look at parent */
else if (StrEq(tok[0], "pattval")) {
if ((atval = FindAttValByName(e->parent, tok[1]))) {
if (ntok == 3) {
TranTByAction(e, tok[2], fp);
}
if (ntok > 3 && !strcmp(atval, tok[2]))
TranTByAction(e, tok[3], fp);
}
}
/* Print each attribute and value for the current element, hopefully
* in a legal sgml form: <elem-name att1="value1" att2="value2:> .
* Format: _allatts */
else if (StrEq(tok[0], "allatts")) {
for (i=0; i<e->natts; i++) {
if (i != 0) putc(' ', fp);
fputs(e->atts[i].name, fp);
fputs("=\"", fp);
fputs(e->atts[i].sval, fp);
putc('"', fp);
}
}
/* Print the element's input filename, and optionally, the line number.
* Format: _infile [line] */
else if (StrEq(tok[0], "infile")) {
if (e->infile) {
if (ntok > 1 && !strcmp(tok[1], "root")) {
strcpy(buf, e->infile);
if ((cp = strrchr(buf, '.'))) *cp = EOS;
fputs(buf, fp);
}
else {
fputs(e->infile, fp);
if (ntok > 1 && !strcmp(tok[1], "line"))
fprintf(fp, " %d", e->lineno);
}
return;
}
else fputs("input-file??", fp);
}
/* Get value of an environement variable */
else if (StrEq(tok[0], "env")) {
if (ntok > 1 && (cp = getenv(tok[1]))) {
OutputString(cp, fp, track_pos);
}
}
/* If the element is not empty do specid.
* Format: _notempty spec-id */
else if (StrEq(tok[0], "notempty")) {
if (ntok > 1 && e->ncont) {
TranTByAction(e, tok[1], fp);
}
}
/* Something unknown */
else {
fprintf(stderr, "Unknown special variable: %s\n", tok[0]);
tt = e->trans;
if (tt && tt->lineno)
fprintf(stderr, "Used in transpec, line %d\n", tt->lineno);
}
return;
}
/* ______________________________________________________________________ */
/* return the value for the special variables _A (last processed _eachatt)
* and _C (last processed _eachcon)
*/
char *
Get_A_C_value(const char * name)
{
if ( !strcmp(name, "each_A") ) {
if ( each_A ) {
return each_A;
} else {
fprintf(stderr, "Requested value for unset _A variable\n");
}
} else
if ( !strcmp(name, "each_C") ) {
if ( each_C ) {
return each_C;
} else {
fprintf(stderr, "Requested value for unset _C variable\n");
}
} else {
fprintf(stderr, "Requested value for unknown special variable '%s'\n",
name);
}
return "";
}
/* ______________________________________________________________________ */
/* Chase IDs until we find an element whose GI matches. We also check
* child element names, not just the names of elements directly pointed
* at (by IDREF attributes).
*/
void
GetIDREFnames()
{
char *cp;
if (!idrefs) {
/* did user or transpec set the variable */
if ((cp = FindMappingVal(Variables, "link_atts")))
idrefs = Split(cp, 0, S_STRDUP|S_ALVEC);
else
idrefs = def_idrefs;
}
}
/* ______________________________________________________________________ */
/* Chase ID references - follow IDREF(s) attributes until we find
* a GI named 'gi', then perform given action on that GI.
* Arguments:
* Pointer to element under consideration.
* Name of GI we're looking for.
* Spec ID of action to take.
* FILE pointer to where to write output.
*/
void
ChaseIDRefs(
Element_t *e,
char *gi,
char * action,
FILE *fp
)
{
int ntok, i, ei;
char **tok, **s, *atval;
/* First, see if we got what we came for with this element */
if (StrEq(e->gi, gi)) {
TranTByAction(e, action, fp);
return;
}
GetIDREFnames();
/* loop for each attribute of type IDREF(s) */
for (s=idrefs; *s; s++) {
/* is this IDREF attr set? */
if ((atval = FindAttValByName(e, *s))) {
ntok = 0;
tok = Split(atval, &ntok, 0);
for (i=0; i<ntok; i++) {
/* get element pointed to */
if ((e = FindElemByID(tok[i]))) {
/* OK, we found a matching GI name */
if (StrEq(e->gi, gi)) {
/* process using named action */
TranTByAction(e, action, fp);
return;
}
else {
/* this elem itself did not match, try its children */
for (ei=0; ei<e->necont; ei++) {
if (StrEq(e->econt[ei]->gi, gi)) {
TranTByAction(e->econt[ei], action, fp);
return;
}
}
/* try this elem's IDREF attributes */
ChaseIDRefs(e, gi, action, fp);
return;
}
}
else {
/* should not happen, since parser checks ID/IDREFs */
fprintf(stderr, "Error: Could not find ID %s\n", atval);
return;
}
}
}
}
/* if the pointers didn't lead to the GI, give error */
if (!s)
fprintf(stderr, "Error: Could not find '%s'\n", gi);
}
/* ______________________________________________________________________ */
/* state to pass to recursive routines - so we don't have to use
* global variables. */
typedef struct {
char *gi;
char *gi2;
char action[10];
Element_t *elem;
FILE *fp;
} Descent_t;
static void
tr_find_gi(
Element_t *e,
Descent_t *ds
)
{
if (StrEq(ds->gi, e->gi))
if (ds->action[0]) TranTByAction(e, ds->action, ds->fp);
}
static void
tr_find_gipar(
Element_t *e,
Descent_t *ds
)
{
if (StrEq(ds->gi, e->gi) && e->parent &&
StrEq(ds->gi2, e->parent->gi))
if (ds->action[0]) TranTByAction(e, ds->action, ds->fp);
}
static void
tr_find_attr(
Element_t *e,
Descent_t *ds
)
{
char *atval;
if ((atval = FindAttValByName(e, ds->gi)) && StrEq(ds->gi2, atval))
TranTByAction(e, ds->action, ds->fp);
}
static void
tr_find_parent(
Element_t *e,
Descent_t *ds
)
{
if (QRelation(e, ds->gi, REL_Parent)) {
if (ds->action[0]) TranTByAction(e, ds->action, ds->fp);
}
}
/* ______________________________________________________________________ */
/* Descend tree, finding elements that match criteria, then perform
* given action.
* Arguments:
* Pointer to element under consideration.
* Number of tokens in special variable.
* Vector of tokens in special variable (eg, "find" "gi" "TITLE")
* FILE pointer to where to write output.
*/
void
Find(
Element_t *e,
int ac,
char **av,
FILE *fp
)
{
Descent_t DS; /* state passed to recursive routine */
memset(&DS, 0, sizeof(Descent_t));
DS.elem = e;
DS.fp = fp;
/* see if we should start at the top of instance tree */
if (StrEq(av[1], "top")) {
av++;
ac--;
e = DocTree;
}
if (ac < 4) {
fprintf(stderr, "Bad '_find' specification - missing args.\n");
return;
}
/* Find elem whose GI is av[2] */
if (StrEq(av[1], "gi")) {
DS.gi = av[2];
strcpy(DS.action, av[3]);
DescendTree(e, tr_find_gi, 0, 0, &DS);
}
/* Find elem whose GI is av[2] and whose parent GI is av[3] */
else if (StrEq(av[1], "gi-parent")) {
DS.gi = av[2];
DS.gi2 = av[3];
strcpy(DS.action, av[4]);
DescendTree(e, tr_find_gipar, 0, 0, &DS);
}
/* Find elem whose parent GI is av[2] */
else if (StrEq(av[0], "parent")) {
DS.gi = av[2];
strcpy(DS.action, av[3]);
DescendTree(e, tr_find_parent, 0, 0, &DS);
}
/* Find elem whose attribute av[2] has value av[3] */
else if (StrEq(av[0], "attr")) {
DS.gi = av[2];
DS.gi2 = av[3];
strcpy(DS.action, av[4]);
DescendTree(e, tr_find_attr, 0, 0, &DS);
}
}
/* ______________________________________________________________________ */

1109
usr.bin/sgmls/instant/util.c Normal file

File diff suppressed because it is too large Load Diff