/*@z40.c:Filter Handler:FilterInit()@*****************************************/
/* */
/* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.23) */
/* COPYRIGHT (C) 1991, 2000 Jeffrey H. Kingston */
/* */
/* Jeffrey H. Kingston (jeff@cs.usyd.edu.au) */
/* Basser Department of Computer Science */
/* The University of Sydney 2006 */
/* AUSTRALIA */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either Version 2, or (at your option) */
/* any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA */
/* */
/* FILE: z40.c */
/* MODULE: Filter Handler */
/* EXTERNS: FilterInit(), FilterCreate(), FilterSetFileNames(), */
/* FilterExecute(), FilterWrite(), FilterScavenge() */
/* */
/*****************************************************************************/
#include "externs.h"
static int filter_count; /* number of filter files */
static OBJECT filter_active; /* the active filter file records */
static OBJECT filter_in_filename; /* initial name of filter input file */
static OBJECT filter_out_filename; /* initial name of filter ouput file */
/*****************************************************************************/
/* */
/* FilterInit() */
/* */
/* Initialize this module. */
/* */
/*****************************************************************************/
void FilterInit(void)
{ filter_count = 0;
New(filter_active, ACAT);
sym_body(FilterInSym) = MakeWord(WORD, FILTER_IN, no_fpos);
sym_body(FilterOutSym) = MakeWord(WORD, FILTER_OUT, no_fpos);
sym_body(FilterErrSym) = MakeWord(WORD, FILTER_ERR, no_fpos);
filter_in_filename = sym_body(FilterInSym);
filter_out_filename = sym_body(FilterOutSym);
} /* end FilterInit */
/*@::FilterCreate(), FilterSetFileNames()@************************************/
/* */
/* OBJECT FilterCreate(use_begin, act, xfpos) */
/* */
/* Create and return a new FILTERED object. Open the corresponding file */
/* for writing and dump the parameter text to be filtered into it. */
/* */
/*****************************************************************************/
OBJECT FilterCreate(BOOLEAN use_begin, OBJECT act, FILE_POS *xfpos)
{ FULL_CHAR buff[MAX_LINE]; FILE *fp; OBJECT x, res, junk;
debug3(DFH, D, "FilterCreate(%s, %s, %s)", bool(use_begin),
SymName(act), EchoFilePos(xfpos));
New(res, FILTERED);
FposCopy(fpos(res), *xfpos);
++filter_count;
sprintf( (char *) buff, "%s%d", FILTER_IN, filter_count);
fp = StringFOpen(buff, WRITE_TEXT);
if( fp == NULL )
Error(40, 1, "cannot open temporary filter file %s", FATAL, xfpos, buff);
x = MakeWord(WORD, buff, xfpos);
filter_use_begin(x) = use_begin;
filter_actual(x) = act;
Link(res, x);
Link(filter_active, x);
junk = LexScanVerbatim(fp, use_begin, xfpos, FALSE);
fclose(fp);
sprintf( (char *) buff, "%s%d", FILTER_OUT, filter_count);
x = MakeWord(WORD, buff, xfpos);
Link(res, x);
if( has_body(act) ) PushScope(act, FALSE, TRUE);
x = GetScopeSnapshot();
if( has_body(act) ) PopScope();
Link(res, x);
debug2(DFH, D, "FilterCreate returning %d %s", (int) res, EchoObject(res));
return res;
} /* end FilterCreate */
/*****************************************************************************/
/* */
/* FilterSetFileNames(x) */
/* */
/* Set @FilterIn, @FilterOut, and @FilterErr to suitable values for the */
/* manifesting of the command which runs filter x. */
/* */
/*****************************************************************************/
void FilterSetFileNames(OBJECT x)
{ OBJECT y;
assert( type(x) == FILTERED, "FilterSetFileNames: type(x)!" );
assert( Down(x) != x, "FilterSetFileNames: x has no children!" );
debug2(DFH, D, "FilterSetFileNames(%d %s)", (int) x, EchoObject(x));
Child(y, Down(x));
assert( type(y) == WORD, "FilterSetFileNames: type(y)!" );
sym_body(FilterInSym) = y;
Child(y, NextDown(Down(x)));
assert( type(y) == WORD, "FilterSetFileNames: type(y) (2)!" );
sym_body(FilterOutSym) = y;
debug0(DFH, D, "FilterSetFileNames returning.");
} /* end FilterSetFileNames */
/*@::FilterExecute()@*********************************************************/
/* */
/* OBJECT FilterExecute(x, command, env) */
/* */
/* Execute the filter command on FILTERED object x, and return the result. */
/* */
/*****************************************************************************/
OBJECT FilterExecute(OBJECT x, FULL_CHAR *command, OBJECT env)
{ int status; OBJECT t, res, scope_snapshot; char line[MAX_LINE];
FILE *err_fp; FILE_NUM filter_out_file;
assert( type(x) == FILTERED, "FilterExecute: type(x)!" );
assert( type(env) == ENV, "FilterExecute: type(env)!" );
debug4(DFH, D, "FilterExecute(%d %s, \"%s\", %s)", (int) x, EchoObject(x),
command, EchoObject(env));
/* reset FilterInSym since Manifest of @Filter is now complete */
sym_body(FilterInSym) = filter_in_filename;
if( SafeExecution )
{
/* if safe execution, print error message and return empty object */
Error(40, 2, "safe execution prohibiting command: %s", WARN, &fpos(x),
command);
res = MakeWord(WORD, STR_EMPTY, &fpos(x));
}
else
{
/* execute the command, echo error messages, and exit if status problem */
status = system( (char *) command);
err_fp = StringFOpen(FILTER_ERR, READ_TEXT);
if( err_fp != NULL )
{ while( fgets(line, MAX_LINE, err_fp) != NULL )
{ if( line[strlen(line)-1] == '\n' )
line[strlen(line)-1] = '\0';
Error(40, 3, "%s", WARN, &fpos(x), line);
}
fclose(err_fp);
StringRemove(FILTER_ERR);
}
if( status != 0 )
Error(40, 4, "failure (non-zero status) of filter: %s",
FATAL, &fpos(x), command);
/* read in output of system command as a Lout object */
/* *** using scope snapshot now
SwitchScope(nilobj);
count = 0;
SetScope(env, &count, TRUE);
*** */
Child(scope_snapshot, LastDown(x));
LoadScopeSnapshot(scope_snapshot);
debug0(DFS, D, " calling DefineFile from FilterExecute");
filter_out_file =
DefineFile(string(sym_body(FilterOutSym)), STR_EMPTY, &fpos(x),
FILTER_FILE, SOURCE_PATH);
LexPush(filter_out_file, 0, FILTER_FILE, 1, FALSE);
t = NewToken(BEGIN, &fpos(x), 0, 0, BEGIN_PREC, FilterOutSym);
res = Parse(&t, nilobj, FALSE, FALSE);
LexPop();
/* *** using scope snapshot now
for( i = 1; i <= count; i++ ) PopScope();
UnSwitchScope(nilobj);
*** */
ClearScopeSnapshot(scope_snapshot);
StringRemove(string(sym_body(FilterOutSym)));
sym_body(FilterOutSym) = filter_out_filename;
}
debug1(DFH, D, "FilterExecute returning %s", EchoObject(res));
return res;
} /* end FilterExecute */
/*@::FilterWrite(), FilterScavenge()@*****************************************/
/* */
/* FilterWrite(x, fp, linecount) */
/* */
/* Write out the active FILTERED object x by copying the file. */
/* Increment *linecount by the number of lines written. */
/* */
/*****************************************************************************/
void FilterWrite(OBJECT x, FILE *fp, int *linecount)
{ FILE *in_fp; OBJECT y; int ch;
assert( type(x) == FILTERED, "FilterWrite: type(x)!" );
debug2(DFH, D, "[ FilterWrite(%d %s, fp)", (int) x, EchoObject(x));
Child(y, Down(x));
in_fp = StringFOpen(string(y), READ_TEXT);
if( in_fp == NULL )
Error(40, 5, "cannot read filter temporary file %s",
FATAL, &fpos(x), string(y));
if( filter_use_begin(y) )
{ StringFPuts(KW_BEGIN, fp);
StringFPuts("\n", fp);
*linecount += 1;
while( (ch = getc(in_fp)) != EOF )
{ putc(ch, fp);
if( ch == '\n' ) *linecount += 1;
}
StringFPuts(KW_END, fp);
StringFPuts(" ", fp);
StringFPuts(SymName(filter_actual(y)), fp);
}
else
{ StringFPuts(KW_LBR, fp);
StringFPuts("\n", fp);
*linecount += 1;
while( (ch = getc(in_fp)) != EOF )
{ putc(ch, fp);
ifdebug(DFH, D, putc(ch, stderr));
if( ch == '\n' ) *linecount += 1;
}
StringFPuts(KW_RBR, fp);
}
StringFPuts("\n", fp);
*linecount += 1;
fclose(in_fp);
debug0(DFH, D, "] FilterWrite returning.");
} /* end FilterWrite */
/*****************************************************************************/
/* */
/* FilterScavenge(all) */
/* */
/* Unlink unneeded filter files, or all remaining filter files if all. */
/* */
/*****************************************************************************/
void FilterScavenge(BOOLEAN all)
{ OBJECT y, link, nextlink;
ifdebug(DFH, D, return);
debug1(DFH, D, "FilterScavenge(%s)", bool(all));
for( link = Down(filter_active); link != filter_active; link = nextlink )
{ Child(y, link);
nextlink = NextDown(link);
if( all || Up(y) == LastUp(y) )
{ debug1(DFH, D, "FilterScavenge scavenging %s", string(y));
StringRemove(string(y));
DisposeChild(link);
}
}
debug0(DFH, D, "FilterScavenge returning.");
} /* end FilterScavenge */