/* 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); } } } } /* if the pointers didn't lead to the GI, give error */ if (!s) fprintf(stderr, "Error: Could not find '%s'\n", gi); }
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); }
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; }
/* 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 */ }
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; }