Exemple #1
0
static void
set_and_increment(
    Trans_t	*t
)
{
    Mapping_t	*m;
    int		i, inc, n;
    char	*cp, buf[50];

    /* set/reset variables */
    if (t->set_var) {
	for (m=t->set_var->maps,i=0; i<t->set_var->n_used; i++)
	    SetMappingNV(Variables, m[i].name, m[i].sval);
    }

    /* 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);
		}
	    }
	}
    }
}
Exemple #2
0
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;
    }
}
Exemple #3
0
Trans_t *
FindTrans(
    Element_t	*e
)
{
    char	context[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)) 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 (! tpt_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 (!tpt_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]);
		if ( !p || strcmp(p, tok[1]) )
		    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 content */
	if (t->content) {		/* no att specified -> a match */
	    for (match=0,i=0; i<e->ndcont; i++) {
		if (tpt_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)
	fprintf(stderr, "Warning: transpec not found for %s\n", e->gi);

    /* default spec - pass character data and descend node */
    return &NullTrans;
}
Exemple #4
0
/*  Copy a buffer/string into another, expanding regular 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
)
{
    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 == VDELIM && *(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;

	    /* 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 (!s) {
		modifier = 0; /* assume user gave us the exact string  */
		s = def_val;  /* may be null if no default value given */
	    }

	    /* 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++;
	    }
	}
	*op++ = *ip++;
    }
    *op = EOS;		/* terminate string */
}
Exemple #5
0
void
ExpandSpecialVar(
    char	*name,
    Element_t	*e,
    FILE	*fp,
    int		track_pos
)
{
    FILE	*infile;
    char	buf[LINESIZE], *cp, *cp2, *atval;
    char	**tok;
    int		ntok, n, i, actioni;
    char	*action, *action1;
    Element_t	*ep;
    Trans_t	*t, *tt;
    Entity_t	*entp;

    /* 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 ( ntok >= 2 )	{
	    cp2 = FindAttValByName(e, tok[1]);
	    if ( ! (entp = FindEntity(cp2)) )	{
	    	fprintf(stderr, "Can't find entity named %s (via _filename expression):\n", tok[1]);
	    	PrintLocation(e, stderr);
	    	return;
	    }
	    OutputString(entp->sysid, fp, track_pos);
	} else	{
	    if (!e->entity) {
	    	fprintf(stderr, "Expected ext entity (element %s) - no ->entity (internal error? bug?):\n", e->gi);
	    	PrintLocation(e, stderr);
	    	return;
	    }
	    if (!e->entity->fname) {
	    	fprintf(stderr, "Expected filename (element %s) - no ->entity->fname (internal error? bug?):\n", e->gi);
	    	PrintLocation(e, stderr);
	    	return;
	    }
	    OutputString(e->entity->sysid, 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 
     * Format: _issete varname [value] action  --  expands value */
    else if (StrEq(tok[0], "isset") || StrEq(tok[0], "issete")) {
	if ((cp = FindMappingVal(Variables, tok[1]))) {
	    if (ntok == 3) TranTByAction(e, tok[2], fp);
	    else
	    if (ntok > 3)	{
	    	if ( StrEq(tok[0], "issete") )	{
			ExpandVariables(tok[2], buf, e);
			cp2 = buf;
		} else
			cp2 = tok[2];
	    	if ( !strcmp(cp, cp2))
			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);
	}
    }

    /* 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;
}