1 /* -*- c -*- */
2 
3 /*
4  * filler.c
5  *
6  * chpp
7  *
8  * Copyright (C) 1997-1998 Heinz Deinhart
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24 
25 /*****************************************************************************
26  *  Command parse ,,black box'' (named by Schani)
27  *
28  * Created by a fluctuation of void *
29  */
30 
31 #define _FILLER_C_
32 
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <assert.h>
38 
39 #include "memory.h"
40 #include "dynstring.h"
41 #include "chash.h"
42 #include "error.h"
43 #include "depends.h"
44 
45 #include "filler.h"
46 #include "commands.h"
47 #include "recorder.h"
48 
49 /* #undef MERD */
50 /* define MERD(x) ; */
51 
52 /* include paths */
53 dynstring *defDirs = 0;
54 int nrOfDefDirs = 0;
55 
56 /* used by filler & commands */
57 int bufPosAtCommandBegin;
58 
59 char filler_cmdChar;
60 int flowsExtern = 0;
61 dynstring externFlow;
62 
63 FlowStack *flowStack;
64 int flowDepth = 1;
65 
66 int incFiles;
67 int zeilenNummer = 0;
68 dynstring currentFileName;
69 dynstring currentFilePath;
70 
71 InputFileStack *ifStack = 0;
72 /* ------------------------- */
73 
74 static FILE* inFile;
75 static int activeNL, bufOverflow;
76 static dynstring tmpStr, overflowStr;
77 /* static int commandWantsFlush = 0; */
78 static dynstring nextCmdCommand;
79 static dynstring nextCmdArgument;
80 static void *nextCmdFun = 0;
81 
82 static hash cmdHash;
83 
84 int warningAlert = 0;
85 
86 void
cutExtern(int i)87 cutExtern( int i ) {
88   dsShrinkRear( &externFlow, i );
89 }
90 
91 void
goExtern(char ch)92 goExtern( char ch ) {
93   dsAppendChar( &externFlow, ch );
94 }
95 
96 void
goExternDS(dynstring * ds)97 goExternDS( dynstring *ds ) {
98   dsAppendString( &externFlow, ds->data, ds->length );
99 }
100 
101 void
flowDepthCeck()102 flowDepthCeck() {
103   if( flowDepth == 1 ) {
104     fprintf( stderr,
105 	    "chmop: flowDepth should be greater than 1, but is 1.\n" );
106    exit( 1 );
107   }
108 }
109 
getPathFromFileName(const char * name)110 dynstring getPathFromFileName( const char *name ) {
111   char *tmp = memXAllocAtomic( strlen( name ) + 1 );
112   char *p;
113   dynstring ds;
114 
115   strcpy( tmp, name );
116   p = strrchr( tmp, '/' );
117   if( !p ) return dsNewFrom( "" );
118   *(p+1)=0;
119 
120   ds = dsNewFrom( tmp );
121   memFree( tmp );
122 
123   return ds;
124 }
125 
getLastPathComponent(const char * path)126 dynstring getLastPathComponent( const char *path ) {
127   char *p;
128   int i = strlen( path );
129 
130   if( !i || path[i-1] == '/' ) return dsNewFrom( "" );
131   p = strrchr( path, '/' );
132   return dsNewFrom( p ? (p+1) : path );
133 }
134 
135 /* returns 0 if file not found */
136 int
includeFile(const char * name)137 includeFile( const char *name ) {
138   InputFileStack *tmpIFS;
139   FILE *ifi = 0;
140   dynstring tmpDy, path;
141   int strlen_name = strlen( name );
142 
143 
144   path.data = 0;
145 
146   /* filenames starting with "./" are always local */
147   if( nrOfDefDirs && name[0] != '.' && name[1] != '/' ) {
148     int i;
149 
150     for( i = (nrOfDefDirs-1); i>=0; i-- ) {
151       tmpDy = dsCopy( &defDirs[i] );
152       dsAppendString( &tmpDy, name, strlen_name );
153       if( (ifi = fopen( tmpDy.data, "r" )) != 0 ) {
154 	i = 0;
155 	path = getPathFromFileName( tmpDy.data );
156       }
157     }
158   }
159 
160   if( !ifi ) { /* try to open file relativ to old file */
161     tmpDy = dsCopy( &currentFilePath );
162     dsAppendString( &tmpDy, name, strlen_name );
163     if( !(ifi = fopen( tmpDy.data, "r" ))) { /* try working dir */
164       if( !(ifi = fopen( name, "r" ))) {
165 	return 0;
166       } else {
167 	path = dsNewFrom( "./" );
168 	//	return 1;  *** warum steht das hier ?
169       }
170     } else {
171       path = getPathFromFileName( tmpDy.data );
172     }
173   }
174 
175   if( !ifi ) { /* file not found */
176     // issueError(ERRCMD_NO_INCLUDE, name, 0, 0);
177     return 0;
178   }
179 
180   tmpIFS = ifStack;
181   ifStack = (InputFileStack *)memXAlloc(sizeof(InputFileStack));
182   ifStack->next = tmpIFS;
183   ifStack->f = inFile;
184   ifStack->zeilenNummer = zeilenNummer;
185   ifStack->name = currentFileName;
186   ifStack->path = currentFilePath;
187   currentFileName = getLastPathComponent( name );
188 
189   currentFilePath = path;
190   zeilenNummer = 0;
191   inFile = ifi;
192   activeNL = 1;
193 
194   recordNewFile( bufPosAtCommandBegin, name );
195 
196   if( currentFilePath.length >= 2 && !strncmp( currentFilePath.data, "./",2 ))
197     dsShrinkFront( &currentFilePath, 2 );
198 
199   incFiles++;
200 
201   if( generateDependencies ) {
202     dynstring tmpDynni = dsNewFrom( currentFilePath.data );
203     dsAppendString( &tmpDynni, currentFileName.data,
204                     strlen( currentFileName.data ));
205     dsAppendChar( &tmpDynni, ' ' );
206     addDependency( 0, &tmpDynni );
207   }
208 
209   return 1;
210 }
211 
212 void
finishFile()213 finishFile() {
214   InputFileStack *tmpIFS ;
215 
216   if( ifStack ) { /* not with last file */
217     fclose( inFile );
218     tmpIFS = ifStack;
219     inFile = ifStack->f;
220     zeilenNummer = ifStack->zeilenNummer;
221     /*
222     fprintf( stderr, "i wipe di aus du sau (%p).\n",
223              currentFilePath.data );
224              */
225     currentFileName = ifStack->name;
226     currentFilePath = ifStack->path;
227     ifStack = tmpIFS->next;
228     recordNewFile( bufPosAtCommandBegin, currentFileName.data );
229   }
230   incFiles--;
231 }
232 
233 static void
generateCommands()234 generateCommands() {
235   cmdHash = hash_new( 100 );
236 
237   hash_insert( cmdHash, "include", cmd_include );
238 
239   hash_insert( cmdHash, "define", cmd_define );
240   hash_insert( cmdHash, "def", cmd_define );
241   hash_insert( cmdHash, "ende", cmd_ende );
242 
243   hash_insert( cmdHash, "edefine", cmd_edefine );
244   hash_insert( cmdHash, "edef", cmd_edefine );
245 
246   hash_insert( cmdHash, "discard", cmd_discard );
247   hash_insert( cmdHash, "disc", cmd_discard );
248   hash_insert( cmdHash, "endd", cmd_endd );
249 
250   hash_insert( cmdHash, "ifdefined", cmd_ifdef );
251   hash_insert( cmdHash, "ifdef", cmd_ifdef );
252   hash_insert( cmdHash, "ifnotdefined", cmd_ifndef );
253   hash_insert( cmdHash, "ifndef", cmd_ifndef );
254   hash_insert( cmdHash, "if", cmd_if );
255   hash_insert( cmdHash, "else", cmd_else );
256   hash_insert( cmdHash, "endif", cmd_endif );
257   hash_insert( cmdHash, "elseif", cmd_elseif );
258   hash_insert( cmdHash, "elif", cmd_elseif );
259 
260   hash_insert( cmdHash, "end", cmd_end );
261 
262   hash_insert( cmdHash, "!", cmd_rem );
263   hash_insert( cmdHash, "rem", cmd_rem );
264   hash_insert( cmdHash, "error", cmd_error );
265 }
266 
267 void
initCommands(FILE * inputFile,char commandChar,const char * filename,const char * filepath)268 initCommands( FILE *inputFile, char commandChar, const char *filename, const char *filepath) {
269   inFile = inputFile;
270   incFiles = 1;
271   filler_cmdChar = commandChar;
272   activeNL = 1;
273   tmpStr = dsNew();
274   ifStack = 0;
275   bufOverflow = 0;
276   generateCommands();
277 
278   /* init flowStack */
279   flowStack = (FlowStack *)memXAlloc( sizeof( FlowStack ));
280   flowStack->next = 0;
281   flowStack->flowLevel = 1;
282   flowStack->openCmd = 0;
283 
284   currentFileName = dsNewFrom(filename);
285   currentFilePath = dsNewFrom(filepath);
286 }
287 
288 /* processActiveNL
289  * Starts to copy a line to tmp buffer till
290  * 1) it knows that line is no command -> tmp buf is copied to output buf
291  *     and processText is called
292  * 2) it knows that line is a command .. command is execd
293  */
294 int
processActiveNL(char * buf,int max,int akt)295 processActiveNL( char *buf, int max, int akt ) {
296   int bufp;
297   char ch;
298 
299   zeilenNummer++;
300 
301   recordNewLine( akt, zeilenNummer );
302 
303   if( !tmpStr.data ) tmpStr = dsNew();
304 
305   /* MERD( "processActiveNL" ); */
306   bufp = akt;
307   ch = (char)fgetc( inFile );
308   /*fprintf( stderr, "-%c-", ch ); */
309   /*  fprintf( stderr, "<<processActiveNL - %i - %i - ch = '%c'>>\n", max, akt, ch ); */
310   /*fprintf( stderr, "-%c-", ch ); */
311   while( (ch == ' ' || ch == '\t') && !feof( inFile )) {
312       /*   fprintf( stderr, "kurding '%c'\n", ch ); */
313     dsAppendChar( &tmpStr, ch );
314     ch = (char)fgetc( inFile );
315     /* fprintf( stderr, "-%c-", ch ); */
316   }
317 
318   if( feof( inFile )) {
319     ch = 0;
320   }
321 
322   if( ch ) {
323     if( flowStack->flowLevel ) { /* HACK, but i weiss net warum der char */
324 	/* durchrutscht wenn i des net mach .... */
325       dsAppendChar( &tmpStr, ch );
326     }/* dont miss the ch who killed command */
327     /*    fprintf( stderr, "kurding II '%c'\n", ch ); */
328   }
329 
330   if( ch == filler_cmdChar ) { /* oh yes, it is a command */
331     nextCmdCommand = dsNew();
332     nextCmdArgument = dsNew();
333 
334     do { /* read rest of line */
335       ch = (char)fgetc( inFile );
336       dsAppendChar( &nextCmdCommand, ch );
337     } while( ch != '\n' && !feof( inFile));
338 
339     dsShrinkRear( &nextCmdCommand, 1 );
340     dsRemoveOuterWS( &nextCmdCommand );
341     nextCmdArgument = dsSplitWS( &nextCmdCommand );
342 
343     dsRemoveOuterWS( &nextCmdArgument );
344 
345     /*    fprintf( stderr, "[COMMAND FOUND: '%s' '%s']\n",  */
346     /*	    nextCmdCommand.data, nextCmdArgument.data ); */
347 
348     {
349       nextCmdFun = hash_lookup( cmdHash, nextCmdCommand.data );
350       if( !nextCmdFun ) {
351 	issueWarning(WARNCMD_UNKNOWN_COMMAND, nextCmdCommand.data, 0, 0);
352       } else {
353 	  /*	((void(*)(const char*))fun)( nextCmdArgument.data ); */
354 	return bufp; /* return now, next time go to processCommand */
355 
356       }
357     }
358 
359     tmpStr = dsNew();
360 
361     /* aktiveNL stays 1 cause command may follow in next line */
362   } else { /* no command, pass tmpStr to schani */
363       /*MERD( "reingfalln, is doch kein command" ); */
364     if( flowsExtern ) { /* in externen buffa eine */
365       goExternDS( &tmpStr );
366       /*      fprintf( stderr, "activeNL: '%s'\n", tmpStr.data ); */
367       if( ch != '\n' ) {
368 	activeNL = 0;
369       } else {
370 	tmpStr = dsNew();
371       }
372     } else {
373 
374       if( !flowStack->flowLevel || tmpStr.length <= (max-akt-1)) {
375 	  /* super, buffer gross genug, oder eh kein output */
376 	if( flowStack->flowLevel ) {
377 	  memcpy( &buf[bufp], tmpStr.data, tmpStr.length );
378 	  bufp += tmpStr.length;
379 	}
380 
381 	if( ch != '\n' ) {
382 	  activeNL = 0;
383 	} else {
384 	  tmpStr = dsNew();
385 	}
386       } else { /* mega scheisse, buffer to short */
387 	  /* fprintf( stderr, "*#*#*#*#*#*#*#*#*quake\n" ); */
388 	memcpy( &buf[bufp], tmpStr.data, max - akt - 1 ); /* fully fill buffer */
389 	bufp += max - akt - 1;
390 	/* store rest of tmpStr in overflowStr */
391 	overflowStr = dsCopy( &tmpStr );
392 	dsShrinkFront( &overflowStr, max - akt - 1 );
393 	bufOverflow = 1;
394       }
395     }
396   }
397 
398   if( feof( inFile )) { /* Change files */
399       /* go down 1 include level */
400       bufPosAtCommandBegin = bufp; /* hack: end of file is no command */
401     finishFile();
402     activeNL = 1;
403     return bufp;
404   }
405 
406   return bufp;
407 }
408 
409 /* BUG: may loose a character if buffer is full */
410 
411 /* processText
412  * reads chars, and wipes them into buffer
413  * if newline is encounterd, processActiveNL is called
414  */
415 int
processText(char * buf,int max,int akt)416 processText( char *buf, int max, int akt ) {
417   int bufp;
418   char ch;
419 
420   /* fprintf( stderr, "<<processText - %i - %i ->>\n", max, akt ); */
421 
422   bufp = akt;
423 
424   ch = (char)fgetc( inFile );
425   /* fprintf( stderr, "-%c-", ch ); */
426   while( ch != '\n' && bufp < (max - 1) && !feof( inFile )) {
427       /* add chars */
428     if( flowStack->flowLevel ) {  /* if flowLevel write to buf */
429       if( flowsExtern ) {
430 	goExtern( ch );
431 	/*	fprintf( stderr, "processText: '%c'\n", ch ); */
432       } else {
433         buf[bufp++] = ch;
434       }
435     }
436     ch = (char)fgetc( inFile );
437     /* fprintf( stderr, "-%c-", ch ); */
438   }
439 
440   if( feof( inFile )) {
441     finishFile();
442     return bufp;
443   } else {
444     if( ch == '\n' && bufp < max) { /* add newline if possible */
445        if( flowStack->flowLevel ) {
446 	 if( flowsExtern ) {
447 	   goExtern( ch );
448 	   /*   fprintf( stderr, "processText: '%c'\n", ch ); */
449 	 } else {
450 	   buf[bufp++] = ch;
451 	 }
452        }
453     }
454 
455     if( bufp == (max - 1)) {
456       overflowStr = dsNew();
457       if( ch != '\n' ) dsAppendChar( &overflowStr, ch );
458       /* fprintf( stderr, "+> %i\n", unRecordLineNumber( bufp )); */
459       bufOverflow = 1;
460     }
461   }
462 
463   if( ch == '\n' ) {
464     activeNL = 1;
465     tmpStr = dsNew();
466     return bufp;
467   }
468   return bufp;
469 }
470 
471 /* processOverflow
472  * 1) handles the last char that did not fit into the output buffer
473  * 2) splits the buffer created by processActiveNL into output buffer
474  */
475 int
processOverflow(char * buf,int max,int akt)476 processOverflow( char *buf, int max, int akt) {
477   int bufp = akt;
478   char ch;
479 
480   /*  fprintf( stderr, "PROCESS OVERFLOW\n" );*/
481 
482   if( overflowStr.length <= (max-akt-1)) {  /* super, buffer gross genug */
483     memcpy( &buf[bufp], overflowStr.data, overflowStr.length );
484     bufp += overflowStr.length;
485 
486     ch = buf[bufp-1]; /* needed to check if last char was newline */
487 
488     if( ch != '\n' ) {
489       activeNL = 0;
490     } else {
491       activeNL = 1;
492       overflowStr = dsNew();
493     }
494     bufOverflow = 0;
495   } else { /* mega scheisse, buffer to short */
496     memcpy( &buf[bufp], overflowStr.data, max - akt - 1 ); /* fully fill buffer */
497     /* store rest of tmpStr in overflowStr */
498     dsShrinkFront( &overflowStr, max - akt - 1 );
499     /* lets do it again */
500   }
501 
502   return bufp;
503 }
504 
505 int
processCommand(char * buf,int max,int akt)506 processCommand( char *buf, int max, int akt ) {
507 
508     /* Hack to access the bufPos inside of commands (used in include) */
509   bufPosAtCommandBegin = akt;
510 
511   if( nextCmdArgument.data[0] ) {
512     ((void(*)(const char*))nextCmdFun)( nextCmdArgument.data );
513   } else {
514     ((void(*)(const char*))nextCmdFun)( 0 );
515   }
516   tmpStr = dsNew();
517 
518   nextCmdFun = 0;
519 
520   /*  fprintf( stderr, "processCommand: tmpStr = '%s'\n", tmpStr.data ); */
521 
522   activeNL = 1;
523 
524   return akt;
525 }
526 
527 int /* returnd anzahl or -1 if all done */
fillBuffer(char * buf,int max)528 fillBuffer( char *buf, int max ) { /* max is anzahl */
529     /* scan 4 cmd */
530   int bufp = 0;
531 
532   recordChangeTape();
533   recordNewFile( 0, currentFileName.data );
534 
535   if( !incFiles ) return -1;
536   if( nextCmdFun ) bufp = processCommand( buf, max, bufp );
537   do {
538     if( bufOverflow ) bufp = processOverflow( buf, max, bufp );
539     if( activeNL ) { /* tmpStr muss allociert sein */
540       bufp = processActiveNL( buf, max, bufp );
541       if( nextCmdFun ) return bufp; /* aha, command wants flush */
542     } else {
543       bufp = processText( buf, max, bufp );
544     }
545   } while( bufp < (max - 1) && incFiles );
546   return bufp;
547 }
548 
549 /*
550 int
551 fillBuffer( char *buf, int max ) {
552   int xxx;
553 
554   xxx= fillBuffer2( buf, max );
555   fprintf( stderr, "-> %i (bufoverflow=%i activeNL=%i)\n",
556 	   unRecordLineNumber( xxx ), bufOverflow, activeNL );
557   return xxx;
558 }
559 */
560