| /*@z40.c:Filter Handler:FilterInit()@*****************************************/ |
| /* */ |
| /* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.24) */ |
| /* 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 */ |
| fprintf(stderr, "Cannot execute system calls!\n"); |
| abort(); |
| status = 0; |
| // 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 */ |