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( ¤tFilePath );
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( ¤tFilePath, 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