/*@z40.c:Filter Handler:FilterInit()@*****************************************/ /* */ /* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.27) */ /* COPYRIGHT (C) 1991, 2002 Jeffrey H. Kingston */ /* */ /* Jeffrey H. Kingston (jeff@it.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_FILE); 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; FULL_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_FILE); if( err_fp != NULL ) { while( ReadOneLine(err_fp, line, MAX_LINE) != 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 */ 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(); 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_FILE); 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); else StringFPuts(KW_LBR, fp); StringFPuts(STR_NEWLINE, fp); *linecount += 1; while( (ch = getc(in_fp)) != EOF ) { putc(ch, fp); if( ch == CH_CR ) { ch = getc(in_fp); if( ch != CH_LF ) ungetc(ch, in_fp); *linecount += 1; } else if( ch == CH_LF ) { ch = getc(in_fp); if( ch != CH_CR ) ungetc(ch, in_fp); *linecount += 1; } } if( filter_use_begin(y) ) { StringFPuts(KW_END, fp); StringFPuts(" ", fp); StringFPuts(SymName(filter_actual(y)), fp); } else StringFPuts(KW_RBR, fp); StringFPuts(STR_NEWLINE, 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 */