translate.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
* All rights reserved.
*/
/*
#pragma ident "%Z%%M% %I% %E% SMI"
* 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
* 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, transfile, mapfile, fp)
* ________________________________________________________________________
*/
#ifndef lint
static char *RCSid =
"$Header: /usr/src/docbook-to-man/Instant/RCS/translate.c,v 1.16 1998/06/29 04:13:40 fld Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <memory.h>
#include <errno.h>
#include <tptregexp.h>
#include "general.h"
#define STORAGE
#include "translate.h"
/* stack for nested Transpecs */
/* forward references */
static void WasProcessed(Element_t *);
/* ______________________________________________________________________ */
/* Translate the subtree starting at 'e'. Use 'transfile' for translation
* specs. Output goes to 'fp'. This is the entry point for translating
* an instance.
* Assumes you've read SDATA and CharMap files (optionally).
* Arguments:
* Pointer to element under consideration.
* Pointer to name of translation spec file.
* FILE pointer to where to write output.
*/
void
Element_t *e,
char *transfile,
)
{
if (!transfile) {
"Translation spec file not specified. Skipping translation.\n");
return;
}
/* Find transpec for each node. */
DescendTree(e, PrepTranspecs, 0, 0, 0);
/* Stuff to do at start of processing */
if ((t = FindTransByName("_Start"))) {
}
/* Stuff to do at end of processing */
if ((t = FindTransByName("_End"))) {
}
/* 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; ) {
/* 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
Element_t *e
)
{
Trans_t *t;
t = e->trans;
PrintLocation(e, stderr);
}
}
/* ______________________________________________________________________ */
/* For each element find transpec.
* Arguments:
* Pointer to element under consideration.
*/
void
Element_t *e
)
{
Trans_t *t;
t = FindTrans(e, 0);
e->trans = t;
}
/* ______________________________________________________________________ */
* variables. (Special variables are done later.)
* Arguments:
* Pointer to string to expand.
* Pointer to expanded string. (return)
* Pointer to element under consideration.
*/
void
char *in,
char *out,
Element_t *e
)
{
register int i, j, k;
char vbuf[500];
int lev;
while (*ip) {
/* start of regular variable? */
ip++;
ip++; /* point at variable name */
/* 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 (lev == 0) {
ip++;
break;
}
else lev--;
}
}
/* vbuf now contains the variable name (stuff between curlys). */
if (lev != 0) {
/* copy rest of string if we can't recover ?? */
return;
}
/* Now, expand variable. */
/* Check for immediate variables -- like _special variables but
* interpreted right now. These start with a "+" */
if ( *vp == '+' ) {
for ( i=0; i<e->ncont; i++ ) {
if ( IsContData(e, i) ) {
op += j;
} else {
if ( warnings )
if (! IsContPI(e, i) )
}
}
} else
for ( i=k=0; i<e->ncont; i++ ) {
if ( IsContData(e, i) ) {
for ( j=0; ContData(e, i)[j]; j++ ) {
}
} else {
#if FALSE
if ( warnings )
#endif
}
}
*op = 0;
} else {
}
} else {
/* See if this variable has a default [ format: ${varname def} ] */
else def_val = 0;
/* def_val now points to default, if it exists, null if not. */
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 */
s = atval;
else /* else try for (global) variable with this name */
/* If we found a value, copy it to the output buffer. */
if (s) {
while (*s) {
op++, *s++;
}
} else
while (*s) *op++ = *s++;
} else
if (def_val) {
}
}
continue;
}
}
}
/* ______________________________________________________________________ */
/* 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
char *ib,
Element_t *e,
int track_pos
)
{
int esc;
esc = 0;
while (*ib) {
/* Is esc-$ next? If so, just copy the '$'. */
ib++; /* skip esc */
continue;
}
/* If not a $, it's a regular char. Just copy it and go to next. */
continue;
}
/* We have a $. What we have must be a "special variable" since
* regular variables have already been expanded, or just a lone $. */
continue;
}
ib++; /* point past $ */
/* Output what we have in buffer so far. */
/* how do we recover from this? */
}
ib++;
ib++; /* point past closing curly */
/* we now have special variable name (stuff in curly {}'s) in vname */
}
}
/* ______________________________________________________________________ */
/* 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 *
Element_t *e,
int specID
)
{
int i, a, match;
/* loop through all transpecs */
{
/* Only one of gi or gilist will be set. */
/* Check if elem name matches */
/* test if we're looking for a specific specID and then if
* this is it.. */
if (specID)
continue;
/* Match one in the list of GIs? */
if (t->gilist) {
match = 1;
break;
}
}
if (!match) continue;
}
/* Check context */
/* Special case of context */
if (t->parent)
if (t->context) { /* no context specified -> a match */
/* If reg expr set, do regex compare; else just string compare. */
if (t->context_re) {
}
else {
/* Is depth of spec deeper than element's depth? */
/* See if context of element matches "context" of transpec */
if (!match) continue;
}
}
/* Check attributes. Loop through list, comparing each. */
if (t->nattpairs) { /* no att specified -> a match */
match = 0;
break;
}
}
if (!match) continue;
}
/* Check relationships: child, parent, ancestor, sib, ... */
if (t->relations) {
Mapping_t *r;
match = 1;
match = 0;
break;
}
}
if (!match) continue;
}
/* check this element's parent's attribute */
char *p, **tok;
i = 2;
match = 1;
if ( i == 2 ) {
match = 0;
} else {
match = 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 */
if (e->my_eorder != i) continue;
}
}
/* check that variables match */
if (t->var_name) {
}
/* check for variable regular expression match */
if ( t->var_RE_name ) {
}
/* check content */
if (t->content) { /* no att specified -> a match */
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) {
/* see if we have a pointer to that transpec */
/* remember pointer for next time */
return t->use_trans;
}
}
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;
/* 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 *
char *s
)
{
Trans_t *t;
/* check if tag name matches (first check 1st char, for efficiency) */
if (t->gi) {
if (*(t->gi) != *s) continue; /* check 1st character */
}
}
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;
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
char *data,
Trans_t *t
)
{
int i, j, mapped;
Mapping_t *m;
/* Worry about embedded newlines? */
if (!fp) return;
/* CLEANUP: this should really all be done in OutputString(). (I think) */
if (nCharMap) {
/* for each character, see if it's mapped to something else */
if (prev == '\\') {
continue;
}
continue;
if ( *cp == '\\' )
*cp++;
mapped = 1;
break;
}
for ( j=tsStacki; j >= 0; j-- ) {
if (tsStack[j]->substitute) {
while (*sub)
mapped = 2;
break;
}
}
if ( mapped == 2 )
break;
}
}
continue;
}
}
}
}
/* ______________________________________________________________________ */
/* 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,
)
{
int n;
Trans_t *t;
buf[0] = '_';
n = 2;
if ((t = FindTransByName(tok[0])) ||
(t = FindTransByName("_*"))) {
else {
}
}
else {
/* If not found, just print the PI in square brackets, along
* with a warning message. */
}
}
/* ______________________________________________________________________ */
/* Set and increment variables, as appropriate, if the transpec says to.
* Arguments:
* Pointer to translation spec for current element.
*/
static void
Trans_t *t,
Element_t *e
)
{
Mapping_t *m;
int i, inc, n;
char ebuf[5000];
if (t->set_var) {
}
}
/* increment counters */
if (t->incr_var) {
/* if not set at all, set to 1 */
else {
else inc = 1;
} else
buf[1] = 0;
}
}
}
}
}
/* ______________________________________________________________________ */
/* 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
Element_t *e,
Trans_t *t
)
{
int i;
/* see if we should quit. */
if (t->quit) {
PrintLocation(e, fp);
exit(1);
}
/* stack this element */
PushTranspecName(t);
/* See if we want to replace subtree (do text, don't descend subtree) */
if (t->replace) {
set_and_increment(t, e); /* adjust variables, if appropriate */
return;
}
/* Is there a "generated" node at the front of this one? */
if (e->gen_trans[0]) {
}
}
/* Loop thruthe "nodes", whether data, child element, or PI. */
for (i=0; i<e->ncont; i++) {
if (IsContElem(e,i)) {
}
else if (IsContData(e,i)) {
}
else if (IsContPI(e,i))
}
/* Is there a "generated" node at the end of this one? */
if (e->gen_trans[1]) {
}
}
}
set_and_increment(t, e); /* adjust variables, if appropriate */
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
Element_t *e,
char *relname, /* relationship name */
char *related, /* related element */
char *actname, /* action to take */
)
{
Relation_t r;
switch (flag) {
}
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
Element_t *e,
int n,
)
{
Trans_t *t;
t = FindTranByID(n);
if (!t) {
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
Element_t *e,
char *strn,
)
{
int n;
Trans_t *t;
t = FindTranByID(n);
if (!t) {
return;
}
} else {
t = FindTrans(e, n);
if ( !t || !t->my_id )
return;
}
TransElement(e, fp, t);
}
/* ______________________________________________________________________ */
/* push the name of a transpec (the new active one) onto the stack
* Arguments:
* transpec name
*/
void
Trans_t *t
)
{
if ( tsStacki >= MAXTRANSPECDEPTH ) {
exit(1);
}
}
/* ______________________________________________________________________ */
/* pop the top name of a transpec off the stack
*/
void
Trans_t *t
)
{
if ( tsStacki < 0 ) {
exit(1);
}
tsStacki--;
}