Tool for manipulating SGML document instances. Replaces sgmlsasp.
This commit is contained in:
parent
60b522b0a6
commit
8053f55001
15
usr.bin/sgmls/instant/Makefile
Normal file
15
usr.bin/sgmls/instant/Makefile
Normal 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>
|
150
usr.bin/sgmls/instant/README
Normal file
150
usr.bin/sgmls/instant/README
Normal 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).
|
||||
|
||||
|
||||
____________________________________________________________________________
|
||||
|
462
usr.bin/sgmls/instant/browse.c
Normal file
462
usr.bin/sgmls/instant/browse.c
Normal 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]);
|
||||
}
|
||||
|
||||
/* ______________________________________________________________________ */
|
329
usr.bin/sgmls/instant/general.h
Normal file
329
usr.bin/sgmls/instant/general.h
Normal 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
|
||||
|
100
usr.bin/sgmls/instant/hyper.c
Normal file
100
usr.bin/sgmls/instant/hyper.c
Normal 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;
|
||||
}
|
||||
|
||||
/* ______________________________________________________________________ */
|
||||
|
300
usr.bin/sgmls/instant/info.c
Normal file
300
usr.bin/sgmls/instant/info.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* ______________________________________________________________________ */
|
||||
|
183
usr.bin/sgmls/instant/instant.1
Normal file
183
usr.bin/sgmls/instant/instant.1
Normal 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.
|
710
usr.bin/sgmls/instant/main.c
Normal file
710
usr.bin/sgmls/instant/main.c
Normal 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;
|
||||
}
|
||||
|
||||
/* ______________________________________________________________________ */
|
2013
usr.bin/sgmls/instant/tables.c
Normal file
2013
usr.bin/sgmls/instant/tables.c
Normal file
File diff suppressed because it is too large
Load Diff
577
usr.bin/sgmls/instant/traninit.c
Normal file
577
usr.bin/sgmls/instant/traninit.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* ______________________________________________________________________ */
|
881
usr.bin/sgmls/instant/translate.c
Normal file
881
usr.bin/sgmls/instant/translate.c
Normal 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);
|
||||
}
|
||||
|
||||
/* ______________________________________________________________________ */
|
153
usr.bin/sgmls/instant/translate.h
Normal file
153
usr.bin/sgmls/instant/translate.h
Normal 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);
|
||||
|
||||
/* ______________________________________________________________________ */
|
||||
|
526
usr.bin/sgmls/instant/transpec.5
Normal file
526
usr.bin/sgmls/instant/transpec.5
Normal 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).
|
757
usr.bin/sgmls/instant/tranvar.c
Normal file
757
usr.bin/sgmls/instant/tranvar.c
Normal 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
1109
usr.bin/sgmls/instant/util.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user