#include "assert.h"
#include "string.h"
#include "errno.h"
#include "stdlib.h"
#include "lp.h"
#include "filters.h"
#include "regex.h"
#define MATCH(PT, PM) (STREQU((PT)->pattern, PATT_STAR) || \
match((PT)->re, *((PM)->pvalue)))
typedef struct PARM {
char *keyword;
unsigned short flags;
char **pvalue;
} PARM;
#define X_MUST 0x0800
#define X_FIRST 0x1000
#define X_FIXED 0x2000
#define X_MANY 0x4000
#define X_USED 0x8000
static struct S {
TYPE input_type;
TYPE output_type;
TYPE printer_type;
char *printer;
PARM *parms;
} S;
#if defined(__STDC__)
static int searchlist_t(TYPE *, TYPE *);
static int instantiate(_FILTER **, TYPE *, TYPE *,
int (*)(), void *);
static int check_pipeline(_FILTER *, PARM *);
static char *build_pipe(_FILTER *, PARM *, unsigned short *);
#else
static int searchlist_t();
static int instantiate();
static int check_pipeline();
static char *build_pipe();
#endif
#define NFIXED 4
static PARM parmtable[] = {
PARM_INPUT, X_FIXED, &S.input_type.name,
PARM_OUTPUT, X_FIXED, &S.output_type.name,
PARM_TERM, X_FIXED, &S.printer_type.name,
PARM_PRINTER, X_FIXED, &S.printer,
PARM_CPI, FPARM_CPI, 0,
PARM_LPI, FPARM_LPI, 0,
PARM_LENGTH, FPARM_LENGTH, 0,
PARM_WIDTH, FPARM_WIDTH, 0,
PARM_PAGES, FPARM_PAGES | X_FIRST | X_MUST, 0,
PARM_CHARSET, FPARM_CHARSET, 0,
PARM_FORM, FPARM_FORM, 0,
PARM_COPIES, FPARM_COPIES | X_FIRST, 0,
PARM_MODES, FPARM_MODES | X_MANY | X_MUST, 0,
0, 0, 0,
};
FILTERTYPE
#if defined(__STDC__)
insfilter(
char **pipes,
char *input_type,
char *output_type,
char *printer_type,
char *printer,
char **parms,
unsigned short *flagsp
)
#else
insfilter(pipes, input_type, output_type, printer_type, printer, parms, flagsp)
char **pipes,
*input_type,
*output_type,
*printer_type,
*printer,
**parms;
unsigned short *flagsp;
#endif
{
_FILTER *pipeline;
FILTERTYPE ret;
S.input_type.name = input_type;
S.input_type.info = isterminfo(input_type);
S.output_type.name = output_type;
S.output_type.info = isterminfo(output_type);
S.printer_type.name = printer_type;
S.printer_type.info = isterminfo(printer_type);
S.printer = printer;
if (!filters && loadfilters((char *)0) == -1)
return (fl_none);
{
register int n;
register PARM * pp;
register PARM * ppt;
register char ** p;
for (n = 0, p = parms; *p; n++, p++)
;
n /= 2;
n += NFIXED;
if (!(S.parms = (PARM *)Malloc((n + 1) * sizeof (PARM)))) {
errno = ENOMEM;
return (fl_none);
}
for (ppt = parmtable; ppt->keyword; ppt++)
ppt->flags &= ~X_USED;
pp = S.parms;
for (ppt = parmtable; ppt < parmtable + NFIXED; ppt++) {
pp->keyword = ppt->keyword;
pp->flags = ppt->flags;
if (ppt->flags & X_FIXED)
pp->pvalue = ppt->pvalue;
else
pp->pvalue = parms + 1;
if (!(ppt->flags & X_MANY))
ppt->flags |= X_USED;
pp++;
}
for (p = parms; *p; p += 2)
for (ppt = parmtable; ppt->keyword; ppt++)
if (STREQU(*p, ppt->keyword) &&
!(ppt->flags & X_USED)) {
pp->keyword = ppt->keyword;
pp->flags = ppt->flags;
if (ppt->flags & X_FIXED)
pp->pvalue = ppt->pvalue;
else
pp->pvalue = p + 1;
if (!(ppt->flags & X_MANY))
ppt->flags |= X_USED;
pp++;
break;
}
pp->keyword = 0;
}
{
register _FILTER * pf;
for (pf = filters; pf->name; pf++) {
pf->mark = FL_CLEAR;
if (printer && !searchlist(printer, pf->printers))
pf->mark = FL_SKIP;
else if (printer_type &&
!searchlist_t(&(S.printer_type),
pf->printer_types))
pf->mark = FL_SKIP;
}
}
if (!instantiate(&pipeline, &S.input_type, &S.output_type,
check_pipeline, S.parms)) {
ret = fl_none;
goto Return;
}
if (!pipes) {
ret = fl_both;
goto Return;
} else {
register _FILTER * pf;
register _FILTER * pfastf;
register _FILTER * pslowf;
for (pf = pfastf = pipeline, pslowf = 0; pf; pf = pf->next)
if (pf->type == fl_slow) {
pslowf = pf;
pfastf = pf->next;
}
if (pslowf) {
assert(pslowf != pfastf);
pslowf->next = 0;
pipes[0] = build_pipe(pipeline, S.parms, flagsp);
ret = fl_slow;
} else
pipes[0] = 0;
if (pfastf) {
pipes[1] = build_pipe(pfastf, S.parms, flagsp);
ret = fl_fast;
} else
pipes[1] = 0;
if (pslowf && pfastf)
ret = fl_both;
if (pslowf && !pipes[0] || pfastf && !pipes[1])
ret = fl_none;
}
Return: Free((char *)S.parms);
return (ret);
}
static int
#if defined(__STDC__)
typematch(
TYPE *type1,
TYPE *type2
)
#else
typematch(type1, type2)
TYPE *type1, *type2;
#endif
{
if (STREQU(type1->name, NAME_ANY) || STREQU(type2->name, NAME_ANY) ||
STREQU(type1->name, type2->name) ||
(STREQU(type1->name, NAME_TERMINFO) && type2->info) ||
(STREQU(type2->name, NAME_TERMINFO) && type1->info))
return (1);
else
return (0);
}
static int
#if defined(__STDC__)
searchlist_t(
TYPE *itemp,
TYPE *list
)
#else
searchlist_t(itemp, list)
TYPE *itemp;
register TYPE *list;
#endif
{
if (!list || !list->name)
return (0);
while (list->name) {
if (typematch(itemp, list))
return (1);
list++;
}
return (0);
}
typedef struct PIPELIST {
_FILTER * lhead;
_FILTER * ltail;
_FILTER * rhead;
} PIPELIST;
#if defined(__STDC__)
static int _instantiate(PIPELIST *, TYPE *, TYPE *,
int (*)(_FILTER *, void *), void *);
#else
static int _instantiate();
#endif
static int peg;
static int
#if defined(__STDC__)
instantiate(
_FILTER **pline,
TYPE *input,
TYPE *output,
int (*verify)(_FILTER *, void *),
void *criteria
)
#else
instantiate(pline, input, output, verify, criteria)
_FILTER **pline;
TYPE *input,
*output;
int (*verify)();
char *criteria;
#endif
{
PIPELIST p;
int ret;
peg = 0;
p.lhead = p.ltail = p.rhead = 0;
ret = _instantiate(&p, input, output, verify, criteria);
*pline = p.lhead;
return (ret);
}
#define ENTER() int our_tag; our_tag = ++peg;
#define LEAVE(Y) if (!Y) { \
register _FILTER *f; \
for (f = filters; f->name; f++) \
CLEAR(f); \
return (0); \
} else \
return (1)
#define MARK(F, M) (((F)->mark |= M), (F)->level = our_tag)
#define CLEAR(F) if ((F)->level == our_tag) \
(F)->level = 0, (F)->mark = FL_CLEAR
#define CHECK(F, M) (((F)->mark & M) && (F)->level == our_tag)
#define USED(F) ((F)->mark)
static int
#if defined(__STDC__)
_instantiate(
PIPELIST *pp,
TYPE *inputp,
TYPE *outputp,
int (*verify)(_FILTER *, void *),
void *criteria
)
#else
_instantiate(pp, inputp, outputp, verify, criteria)
PIPELIST *pp;
TYPE *inputp,
*outputp;
int (*verify)();
char *criteria;
#endif
{
register _FILTER *prev_lhead;
register _FILTER *prev_ltail;
ENTER();
if (typematch(inputp, outputp) && pp->lhead) {
pp->ltail->next = pp->rhead;
if ((*verify)(pp->lhead, criteria))
LEAVE(1);
else
LEAVE(0);
}
{
register _FILTER * pf;
for (pf = filters; pf->name; pf++) {
if (USED(pf))
continue;
if (searchlist_t(inputp, pf->input_types)) {
MARK(pf, FL_LEFT);
pf->inputp = inputp;
}
if (searchlist_t(outputp, pf->output_types)) {
MARK(pf, FL_RIGHT);
pf->outputp = outputp;
}
if (CHECK(pf, FL_LEFT) && CHECK(pf, FL_RIGHT)) {
prev_lhead = pp->lhead;
prev_ltail = pp->ltail;
if (!pp->lhead)
pp->lhead = pf;
else
pp->ltail->next = pf;
(pp->ltail = pf)->next = pp->rhead;
if ((*verify)(pp->lhead, criteria))
LEAVE(1);
if ((pp->ltail = prev_ltail))
pp->ltail->next = 0;
pp->lhead = prev_lhead;
}
}
}
{
register _FILTER * pfl;
register _FILTER * pfr;
register TYPE * llist;
register TYPE * rlist;
for (pfl = filters; pfl->name; pfl++) {
if (!CHECK(pfl, FL_LEFT))
continue;
for (pfr = filters; pfr->name; pfr++) {
if (pfr == pfl || !CHECK(pfr, FL_RIGHT))
continue;
prev_lhead = pp->lhead;
prev_ltail = pp->ltail;
if (!pp->lhead)
pp->lhead = pfl;
else
pp->ltail->next = pfl;
(pp->ltail = pfl)->next = 0;
pfr->next = pp->rhead;
pp->rhead = pfr;
for (llist = pfl->output_types; llist->name;
llist++)
for (rlist = pfr->input_types;
rlist->name; rlist++)
if (_instantiate(pp, llist,
rlist, verify,
criteria)) {
pfl->outputp = llist;
pfr->inputp = rlist;
LEAVE(1);
}
pp->rhead = pfr->next;
if ((pp->ltail = prev_ltail))
pp->ltail->next = 0;
pp->lhead = prev_lhead;
}
}
}
LEAVE(0);
}
static int
#if defined(__STDC__)
check_pipeline(
_FILTER *pipeline,
PARM *parms
)
#else
check_pipeline(pipeline, parms)
_FILTER *pipeline;
PARM *parms;
#endif
{
register PARM *pm;
register _FILTER *pf;
register TEMPLATE *pt;
register int fail;
for (fail = 0, pm = parms; !fail && pm->keyword; pm++) {
if (!(pm->flags & X_MUST))
continue;
for (pf = pipeline; pf; pf = pf->next) {
if (!(pt = pf->templates))
continue;
for (; pt->keyword; pt++)
if (STREQU(pt->keyword, pm->keyword) &&
pt->result && MATCH(pt, pm))
goto Okay;
}
fail = 1;
continue;
Okay:;
}
return (fail? 0 : 1);
}
#if defined(__STDC__)
static size_t build_simple_cmd(char **, _FILTER *, PARM *,
unsigned short *);
#else
static size_t build_simple_cmd();
#endif
static char *
#if defined(__STDC__)
build_pipe(
_FILTER *pipeline,
PARM *parms,
unsigned short *fp
)
#else
build_pipe(pipeline, parms, fp)
_FILTER *pipeline;
PARM *parms;
unsigned short *fp;
#endif
{
register _FILTER *pf;
register size_t nchars;
register size_t n;
char *p;
char *ret;
for (nchars = 0, pf = pipeline; pf; pf = pf->next)
if ((n = build_simple_cmd((char **)0, pf, parms, fp)) > 0)
nchars += n + 1;
if (!(ret = p = Malloc(nchars))) {
errno = ENOMEM;
return (0);
}
for (pf = pipeline; pf; pf = pf->next, *p++ = (pf? '|' : 0))
(void) build_simple_cmd(&p, pf, parms, fp);
return (ret);
}
static size_t
#if defined(__STDC__)
build_simple_cmd(
char **pp,
_FILTER *pf,
PARM *parms,
unsigned short *flagsp
)
#else
build_simple_cmd(pp, pf, parms, flagsp)
char **pp;
_FILTER *pf;
PARM *parms;
unsigned short *flagsp;
#endif
{
register size_t ncount;
register TEMPLATE *pt;
register PARM *pm;
if (pf->command) {
ncount = strlen(pf->command);
if (pp) {
strcpy (*pp, pf->command);
*pp += ncount;
}
} else
ncount = 0;
if (!pf->templates)
return (ncount);
for (pm = parms; pm->keyword; pm++) {
if ((pm->flags & X_USED) || !*(pm->pvalue))
continue;
for (pt = pf->templates; pt->keyword; pt++) {
if (!STREQU(pt->keyword, pm->keyword) || !pt->result)
continue;
if (STREQU(pt->keyword, PARM_INPUT))
pm->pvalue = &(pf->inputp->name);
else if (STREQU(pt->keyword, PARM_OUTPUT))
pm->pvalue = &(pf->outputp->name);
if (MATCH(pt, pm)) {
if (pp)
*(*pp)++ = ' ';
ncount++;
ncount += replace(pp, pt->result,
*(pm->pvalue), pt->nbra);
if (pp && pm->flags & X_FIRST)
pm->flags |= X_USED;
*flagsp |= pm->flags;
}
}
}
return (ncount);
}