1 /*@z40.c:Filter Handler:FilterInit()@*****************************************/
2 /* */
3 /* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.39) */
4 /* COPYRIGHT (C) 1991, 2008 Jeffrey H. Kingston */
5 /* */
6 /* Jeffrey H. Kingston (jeff@it.usyd.edu.au) */
7 /* School of Information Technologies */
8 /* The University of Sydney 2006 */
9 /* AUSTRALIA */
10 /* */
11 /* This program is free software; you can redistribute it and/or modify */
12 /* it under the terms of the GNU General Public License as published by */
13 /* the Free Software Foundation; either Version 3, or (at your option) */
14 /* any later version. */
15 /* */
16 /* This program is distributed in the hope that it will be useful, */
17 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
18 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
19 /* GNU General Public License for more details. */
20 /* */
21 /* You should have received a copy of the GNU General Public License */
22 /* along with this program; if not, write to the Free Software */
23 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA */
24 /* */
25 /* FILE: z40.c */
26 /* MODULE: Filter Handler */
27 /* EXTERNS: FilterInit(), FilterCreate(), FilterSetFileNames(), */
28 /* FilterExecute(), FilterWrite(), FilterScavenge() */
29 /* */
30 /*****************************************************************************/
31 #include "externs.h"
32
33
34 static int filter_count; /* number of filter files */
35 static OBJECT filter_active; /* the active filter file records */
36 static OBJECT filter_in_filename; /* initial name of filter input file */
37 static OBJECT filter_out_filename; /* initial name of filter ouput file */
38
39
40 /*****************************************************************************/
41 /* */
42 /* FilterInit() */
43 /* */
44 /* Initialize this module. */
45 /* */
46 /*****************************************************************************/
47
FilterInit(void)48 void FilterInit(void)
49 { filter_count = 0;
50 New(filter_active, ACAT);
51 sym_body(FilterInSym) = MakeWord(WORD, FILTER_IN, no_fpos);
52 sym_body(FilterOutSym) = MakeWord(WORD, FILTER_OUT, no_fpos);
53 sym_body(FilterErrSym) = MakeWord(WORD, FILTER_ERR, no_fpos);
54 filter_in_filename = sym_body(FilterInSym);
55 filter_out_filename = sym_body(FilterOutSym);
56 } /* end FilterInit */
57
58
59 /*@::FilterCreate(), FilterSetFileNames()@************************************/
60 /* */
61 /* OBJECT FilterCreate(use_begin, act, xfpos) */
62 /* */
63 /* Create and return a new FILTERED object. Open the corresponding file */
64 /* for writing and dump the parameter text to be filtered into it. */
65 /* */
66 /*****************************************************************************/
67
FilterCreate(BOOLEAN use_begin,OBJECT act,FILE_POS * xfpos)68 OBJECT FilterCreate(BOOLEAN use_begin, OBJECT act, FILE_POS *xfpos)
69 { FULL_CHAR buff[MAX_LINE]; FILE *fp; OBJECT x, res, junk;
70 debug3(DFH, D, "FilterCreate(%s, %s, %s)", bool(use_begin),
71 SymName(act), EchoFilePos(xfpos));
72 New(res, FILTERED);
73 FposCopy(fpos(res), *xfpos);
74 ++filter_count;
75 sprintf( (char *) buff, "%s%d", FILTER_IN, filter_count);
76 fp = StringFOpen(buff, WRITE_FILE);
77 if( fp == NULL )
78 Error(40, 1, "cannot open temporary filter file %s", FATAL, xfpos, buff);
79 x = MakeWord(WORD, buff, xfpos);
80 filter_use_begin(x) = use_begin;
81 filter_actual(x) = act;
82 Link(res, x);
83 Link(filter_active, x);
84 junk = LexScanVerbatim(fp, use_begin, xfpos, FALSE);
85 fclose(fp);
86 sprintf( (char *) buff, "%s%d", FILTER_OUT, filter_count);
87 x = MakeWord(WORD, buff, xfpos);
88 Link(res, x);
89 if( has_body(act) ) PushScope(act, FALSE, TRUE);
90 x = GetScopeSnapshot();
91 if( has_body(act) ) PopScope();
92 Link(res, x);
93 debug2(DFH, D, "FilterCreate returning %d %s", (int) res, EchoObject(res));
94 return res;
95 } /* end FilterCreate */
96
97
98 /*****************************************************************************/
99 /* */
100 /* FilterSetFileNames(x) */
101 /* */
102 /* Set @FilterIn, @FilterOut, and @FilterErr to suitable values for the */
103 /* manifesting of the command which runs filter x. */
104 /* */
105 /*****************************************************************************/
106
FilterSetFileNames(OBJECT x)107 void FilterSetFileNames(OBJECT x)
108 { OBJECT y;
109 assert( type(x) == FILTERED, "FilterSetFileNames: type(x)!" );
110 assert( Down(x) != x, "FilterSetFileNames: x has no children!" );
111 debug2(DFH, D, "FilterSetFileNames(%d %s)", (int) x, EchoObject(x));
112 Child(y, Down(x));
113 assert( type(y) == WORD, "FilterSetFileNames: type(y)!" );
114 sym_body(FilterInSym) = y;
115 Child(y, NextDown(Down(x)));
116 assert( type(y) == WORD, "FilterSetFileNames: type(y) (2)!" );
117 sym_body(FilterOutSym) = y;
118 debug0(DFH, D, "FilterSetFileNames returning.");
119 } /* end FilterSetFileNames */
120
121
122 /*@::FilterExecute()@*********************************************************/
123 /* */
124 /* OBJECT FilterExecute(x, command, env) */
125 /* */
126 /* Execute the filter command on FILTERED object x, and return the result. */
127 /* */
128 /*****************************************************************************/
129
FilterExecute(OBJECT x,FULL_CHAR * command,OBJECT env)130 OBJECT FilterExecute(OBJECT x, FULL_CHAR *command, OBJECT env)
131 { int status; OBJECT t, res, scope_snapshot; FULL_CHAR line[MAX_LINE];
132 FILE *err_fp; FILE_NUM filter_out_file;
133
134 assert( type(x) == FILTERED, "FilterExecute: type(x)!" );
135 assert( type(env) == ENV, "FilterExecute: type(env)!" );
136 debug4(DFH, D, "FilterExecute(%d %s, \"%s\", %s)", (int) x, EchoObject(x),
137 command, EchoObject(env));
138
139 /* reset FilterInSym since Manifest of @Filter is now complete */
140 sym_body(FilterInSym) = filter_in_filename;
141
142 if( SafeExecution )
143 {
144 /* if safe execution, print error message and return empty object */
145 Error(40, 2, "safe execution prohibiting command: %s", WARN, &fpos(x),
146 command);
147 res = MakeWord(WORD, STR_EMPTY, &fpos(x));
148 }
149 else
150 {
151 /* execute the command, echo error messages, and check status */
152 status = system( (char *) command);
153 err_fp = StringFOpen(FILTER_ERR, READ_FILE);
154 if( err_fp != NULL )
155 { while( ReadOneLine(err_fp, line, MAX_LINE) != 0 )
156 Error(40, 3, "%s", WARN, &fpos(x), line);
157 fclose(err_fp);
158 StringRemove(FILTER_ERR);
159 }
160 if( status == 0 )
161 {
162 /* system command succeeded; read in its output as a Lout object */
163 Child(scope_snapshot, LastDown(x));
164 LoadScopeSnapshot(scope_snapshot);
165 debug0(DFS, D, " calling DefineFile from FilterExecute");
166 filter_out_file =
167 DefineFile(string(sym_body(FilterOutSym)), STR_EMPTY, &fpos(x),
168 FILTER_FILE, SOURCE_PATH);
169 LexPush(filter_out_file, 0, FILTER_FILE, 1, FALSE);
170 t = NewToken(BEGIN, &fpos(x), 0, 0, BEGIN_PREC, FilterOutSym);
171 res = Parse(&t, nilobj, FALSE, FALSE);
172 LexPop();
173 ClearScopeSnapshot(scope_snapshot);
174 StringRemove(string(sym_body(FilterOutSym)));
175 sym_body(FilterOutSym) = filter_out_filename;
176 }
177 else
178 {
179 /* system command failed; print warning message and substitute "??" */
180 Error(40, 4, "failure (status %d) of filter: %s", WARN, &fpos(x),
181 status, command);
182 res = MakeWord(WORD, STR_NOCROSS, &fpos(x)); /* i.e. "??" */
183 }
184 }
185
186 debug1(DFH, D, "FilterExecute returning %s", EchoObject(res));
187 return res;
188 } /* end FilterExecute */
189
190
191 /*@::FilterWrite(), FilterScavenge()@*****************************************/
192 /* */
193 /* FilterWrite(x, fp, linecount) */
194 /* */
195 /* Write out the active FILTERED object x by copying the file. */
196 /* Increment *linecount by the number of lines written. */
197 /* */
198 /*****************************************************************************/
199
FilterWrite(OBJECT x,FILE * fp,int * linecount)200 void FilterWrite(OBJECT x, FILE *fp, int *linecount)
201 { FILE *in_fp; OBJECT y; int ch;
202 assert( type(x) == FILTERED, "FilterWrite: type(x)!" );
203 debug2(DFH, D, "[ FilterWrite(%d %s, fp)", (int) x, EchoObject(x));
204 Child(y, Down(x));
205 in_fp = StringFOpen(string(y), READ_FILE);
206 if( in_fp == NULL )
207 Error(40, 5, "cannot read filter temporary file %s",
208 FATAL, &fpos(x), string(y));
209 if( filter_use_begin(y) )
210 StringFPuts(KW_BEGIN, fp);
211 else
212 StringFPuts(KW_LBR, fp);
213 StringFPuts(STR_NEWLINE, fp);
214 *linecount += 1;
215 while( (ch = getc(in_fp)) != EOF )
216 { putc(ch, fp);
217 if( ch == CH_CR )
218 {
219 ch = getc(in_fp);
220 if( ch != CH_LF )
221 ungetc(ch, in_fp);
222 *linecount += 1;
223 }
224 else if( ch == CH_LF )
225 {
226 ch = getc(in_fp);
227 if( ch != CH_CR )
228 ungetc(ch, in_fp);
229 *linecount += 1;
230 }
231 }
232 if( filter_use_begin(y) )
233 {
234 StringFPuts(KW_END, fp);
235 StringFPuts(" ", fp);
236 StringFPuts(SymName(filter_actual(y)), fp);
237 }
238 else
239 StringFPuts(KW_RBR, fp);
240 /* *** a line too far! JeffK 8/3/07
241 StringFPuts(STR_NEWLINE, fp);
242 *linecount += 1;
243 *** */
244 fclose(in_fp);
245 debug0(DFH, D, "] FilterWrite returning.");
246 } /* end FilterWrite */
247
248
249 /*****************************************************************************/
250 /* */
251 /* FilterScavenge(all) */
252 /* */
253 /* Unlink unneeded filter files, or all remaining filter files if all. */
254 /* */
255 /*****************************************************************************/
256
FilterScavenge(BOOLEAN all)257 void FilterScavenge(BOOLEAN all)
258 { OBJECT y, link, nextlink;
259 ifdebug(DFH, D, return);
260 debug1(DFH, D, "FilterScavenge(%s)", bool(all));
261 for( link = Down(filter_active); link != filter_active; link = nextlink )
262 { Child(y, link);
263 nextlink = NextDown(link);
264 if( all || Up(y) == LastUp(y) )
265 { debug1(DFH, D, "FilterScavenge scavenging %s", string(y));
266 StringRemove(string(y));
267 DisposeChild(link);
268 }
269 }
270 debug0(DFH, D, "FilterScavenge returning.");
271 } /* end FilterScavenge */
272