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