1 /****************************************************************************
2 *
3 *                            Open Watcom Project
4 *
5 *    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
6 *
7 *  ========================================================================
8 *
9 *    This file contains Original Code and/or Modifications of Original
10 *    Code as defined in and that are subject to the Sybase Open Watcom
11 *    Public License version 1.0 (the 'License'). You may not use this file
12 *    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
13 *    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
14 *    provided with the Original Code and Modifications, and is also
15 *    available at www.sybase.com/developer/opensource.
16 *
17 *    The Original Code and all software distributed under the License are
18 *    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
19 *    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
20 *    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
21 *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
22 *    NON-INFRINGEMENT. Please see the License for the specific language
23 *    governing rights and limitations under the License.
24 *
25 *  ========================================================================
26 *
27 * Description:  processing file/macro input data.
28 *
29 ****************************************************************************/
30 
31 #include <ctype.h>
32 //#include <stdarg.h> /* v2.12: removed - was necessary for _splitpath()/_makepath() */
33 
34 #include "globals.h"
35 #include "memalloc.h"
36 #include "parser.h"
37 #include "macro.h"
38 #include "input.h"
39 #include "lqueue.h"
40 #include "myassert.h"
41 
42 #define DETECTCTRLZ 1 /* 1=Ctrl-Z in input stream will skip rest of the file */
43 
44 /* FILESEQ: if 1, stores a linked list of source files, ordered
45  * by usage. Masm stores such a list in the COFF symbol table
46  * when -Zd/-Zi is set. It isn't necessary, however, and JWasm's
47  * COFF code currently will ignore the list.
48  */
49 
50 #define FILESEQ 0
51 
52 char   *commentbuffer;
53 
54 struct asym *FileCur; /* @FileCur symbol, created in SymInit() */
55 struct asym *LineCur; /* @Line symbol, created in SymInit()    */
56 
57 enum src_item_type {
58     SIT_FILE,
59     SIT_MACRO,
60 };
61 
62 /* item on src stack ( contains currently open source files & macros ) */
63 struct src_item {
64     struct src_item     *next;
65     uint_8              type;       /* item type ( see enum src_item_type ) */
66     uint_16             srcfile;    /* index of file in ModuleInfo.g.FNames */
67     union {
68         void            *content;   /* generic */
69         FILE            *file;      /* if item is a file */
70         struct macro_instance *mi;  /* if item is a macro */
71     };
72     uint_32             line_num;   /* current line # */
73     /* v2.11 field macro moved to struct macro_instance */
74     //struct asym         *macro;     /* the symbol if it is a macro */
75 };
76 
77 /* v2.11: introduced a list of unused src_items */
78 static struct src_item *SrcFree;
79 
80 #define src_stack  ModuleInfo.g.src_stack
81 
82 #if FILESEQ
83 struct qdesc            FileSeq;
84 #endif
85 
86 #ifdef DEBUG_OUT
87 struct asm_tok *end_tokenarray;
88 char           *end_stringbuf;
89 static int_32 cntflines;  /* count file lines ( read by fgets() ) */
90 static int_32 cntlines;   /* count lines read by GetTextLine() */
91 extern int_32 cnttok0;    /* count Tokenize() calls, index==0 */
92 extern int_32 cnttok1;    /* count Tokenize() calls, index!=0 */
93 extern int_32 cntppl0;    /* count preprocessed lines 1 */
94 extern int_32 cntppl1;    /* count preprocessed lines 2 */
95 extern int_32 cntppl2;    /* count lines NOT handled by preprocessor */
96 #endif
97 
98 /* buffer for source lines
99  * since the lines are sometimes concatenated
100  * the buffer must be a multiple of MAX_LINE_LEN
101  */
102 static char *srclinebuffer;
103 
104 /* string buffer - token strings and other stuff are stored here.
105  * must be a multiple of MAX_LINE_LEN since it is used for string expansion.
106  */
107 char *token_stringbuf;  /* start token string buffer */
108 
109 /* fixme: add '|| defined(__CYGWIN__)' ? */
110 #if defined(__UNIX__)
111 
112 #define INC_PATH_DELIM      ':'
113 #define INC_PATH_DELIM_STR  ":"
114 #define DIR_SEPARATOR       '/'
115 #define filecmp strcmp
116 #define ISPC( x ) ( x == '/' )
117 #define ISABS( x ) ( *x == '/' )
118 
119 #else
120 
121 #define INC_PATH_DELIM      ';'
122 #define INC_PATH_DELIM_STR  ";"
123 #define DIR_SEPARATOR       '\\'
124 #define filecmp _stricmp
125 #define ISPC( x ) ( x == '/' || x == '\\' || x == ':' )
126 #define ISABS( x ) ( *x == '/' || *x == '\\' || ( *x &&  *(x+1) == ':' && ( *(x+2) == '/' || *(x+2) == '\\' ) ) )
127 
128 #endif
129 
130 #if 0 /* v2.11: obsolete, field fullname removed */
131 static char *GetFullPath( const char *name, char *buff, size_t max )
132 /******************************************************************/
133 {
134     char        *p;
135 
136     p = _fullpath( buff, name, max );
137     if( p == NULL )
138         p = (char *)name;
139 
140 #if defined(__UNIX__)
141     if( (p[0] == '/' && p[1] == '/') && (name[0] != '/' || name[1] != '/') ) {
142         /*
143          * if the _fullpath result has a node number and
144          * the user didn't specify one, strip the node number
145          * off before returning
146          */
147         p += 2;
148         while( *(p++) != '/' ) ;
149     }
150 #endif
151     return( p );
152 }
153 #endif
154 
155 /* v2.12: function added - _splitpath()/_makepath() removed */
156 
GetFNamePart(const char * fname)157 const char *GetFNamePart( const char *fname )
158 /*******************************************/
159 {
160     const char *rc;
161     for ( rc = fname; *fname; fname++ )
162         if ( ISPC( *fname ) )
163             rc = fname + 1;
164     return( rc );
165 }
166 
167 /* fixme: if the dot is at pos 0 of filename, ignore it */
168 
GetExtPart(const char * fname)169 char *GetExtPart( const char *fname )
170 /***********************************/
171 {
172     char *rc;
173     for( rc = NULL; *fname; fname++ ) {
174         if( *fname == '.' ) {
175             rc = (char *)fname;
176         } else if( ISPC( *fname ) ) {
177             rc = NULL;
178         }
179     }
180     return( rc ? rc : (char *)fname );
181 }
182 
183 /* check if a file is in the array of known files.
184  * if no, store the file at the array's end.
185  * returns array index.
186  * used for the main source and all INCLUDEd files.
187  * the array is stored in the standard C heap!
188  * the filenames are stored in the "local" heap.
189  */
AddFile(char const * fname)190 static unsigned AddFile( char const *fname )
191 /******************************************/
192 {
193     unsigned    index;
194 
195     DebugMsg1(("AddFile(%s) enter, curr index=%u\n", fname, ModuleInfo.g.cnt_fnames ));
196     for( index = 0; index < ModuleInfo.g.cnt_fnames; index++ ) {
197         if( filecmp( fname, ModuleInfo.g.FNames[index].fname ) == 0 ) {
198 #ifdef DEBUG_OUT
199             if ( Parse_Pass == PASS_1 )
200                 ModuleInfo.g.FNames[index].included++;
201 #endif
202             return( index );
203         }
204     }
205 
206     if ( ( index % 64 ) == 0 ) {
207         struct fname_item *newfn;
208         newfn = (struct fname_item *)MemAlloc( ( index + 64 ) * sizeof( struct fname_item ) );
209         if ( ModuleInfo.g.FNames ) {
210             memcpy( newfn, ModuleInfo.g.FNames, index * sizeof( struct fname_item ) );
211             MemFree( ModuleInfo.g.FNames );
212         }
213         ModuleInfo.g.FNames = newfn;
214     }
215     ModuleInfo.g.cnt_fnames++;
216 
217     /* v2.11: use name directly - allows COFF .file entries with relative paths */
218     //_splitpath( fname, NULL, NULL, name, ext );
219 
220     ModuleInfo.g.FNames[index].fname = (char *)LclAlloc( strlen( fname ) + 1 );
221     strcpy( ModuleInfo.g.FNames[index].fname, fname );
222     /* v2.11: field fullname removed */
223     //ModuleInfo.g.FNames[index].fullname = (char *)LclAlloc( strlen( fullname ) + 1 );
224     //strcpy( ModuleInfo.g.FNames[index].fullname, fullname );
225     DebugCmd( ModuleInfo.g.FNames[index].included = 1 );
226     return( index );
227 }
228 
GetFName(unsigned index)229 const struct fname_item *GetFName( unsigned index )
230 /*************************************************/
231 {
232     return( ModuleInfo.g.FNames+index );
233 }
234 
235 /* free the file array.
236  * this is done once for each module after the last pass.
237  */
238 
FreeFiles(void)239 static void FreeFiles( void )
240 /***************************/
241 {
242 #if FASTMEM==0
243     int i;
244 
245     /* remove the main src item from src stack */
246     src_stack->next = SrcFree;
247     SrcFree = src_stack;
248 #endif
249     /* v2.03: set src_stack=NULL to ensure that GetCurrSrcPos()
250      * won't find something when called from main().
251      */
252     src_stack = NULL;
253 
254 #if FASTMEM==0
255     /* free the "free src_items"-heap */
256     while ( SrcFree ) {
257         struct src_item *next;
258         next = SrcFree->next;
259         LclFree( SrcFree );
260         SrcFree = next;
261     };
262     for ( i = 0; i < ModuleInfo.g.cnt_fnames; i++ ) {
263         LclFree( ModuleInfo.g.FNames[i].fname );
264         //LclFree( ModuleInfo.g.FNames[i].fullname );
265     }
266 #endif
267     if ( ModuleInfo.g.FNames ) {
268         MemFree( ModuleInfo.g.FNames );
269         ModuleInfo.g.FNames = NULL;
270     }
271     return;
272 }
273 
274 /* clear input source stack (include files and open macros).
275  * This is done after each pass.
276  * Usually the stack is empty when the END directive occurs,
277  * but it isn't required that the END directive is located in
278  * the main source file. Also, an END directive might be
279  * simulated if a "too many errors" condition occurs.
280  */
281 
ClearSrcStack(void)282 void ClearSrcStack( void )
283 /************************/
284 {
285     struct src_item   *nextfile;
286 
287     DeleteLineQueue();
288 
289     /* dont close the last item (which is the main src file) */
290     for( ; src_stack->next ; src_stack = nextfile ) {
291         nextfile = src_stack->next;
292         if ( src_stack->type == SIT_FILE ) {
293             fclose( src_stack->file );
294         }
295         //LclFree( src_stack );
296         src_stack->next = SrcFree;
297         SrcFree = src_stack;
298     }
299     return;
300 }
301 
302 /* get/set value of predefined symbol @Line */
303 
UpdateLineNumber(struct asym * sym,void * p)304 void UpdateLineNumber( struct asym *sym, void *p )
305 /************************************************/
306 {
307     struct src_item *curr;
308     for ( curr = src_stack; curr ; curr = curr->next )
309         if ( curr->type == SIT_FILE ) {
310             sym->value = curr->line_num;
311             break;
312         }
313     return;
314 }
315 
GetLineNumber(void)316 uint_32 GetLineNumber( void )
317 /***************************/
318 {
319     UpdateLineNumber( LineCur, NULL );
320     return( LineCur->uvalue );
321 }
322 
323 #ifdef DEBUG_OUT
324 
325 extern unsigned GetLqLine( void );
326 
GetTopLine(char * buffer)327 char *GetTopLine( char *buffer )
328 /******************************/
329 {
330     *buffer = NULLC;
331     if ( ModuleInfo.GeneratedCode )
332         sprintf( buffer, "(%u)", GetLqLine() );
333     else if( src_stack->type == SIT_MACRO )
334         sprintf( buffer, "[%s.%" I32_SPEC "u]", src_stack->mi->macro->name, src_stack->line_num );
335     return( buffer );
336 }
337 
GetTopSrcName(void)338 char *GetTopSrcName( void )
339 /*************************/
340 {
341     if ( src_stack->type == SIT_MACRO )
342         return( src_stack->mi->macro->name );
343     return( GetFName( src_stack->srcfile )->fname );
344 }
345 
346 #endif
347 
348 /* read one line from current source file.
349  * returns NULL if EOF has been detected and no char stored in buffer
350  * v2.08: 00 in the stream no longer causes an exit. Hence if the
351  * char occurs in the comment part, everything is ok.
352  */
my_fgets(char * buffer,int max,FILE * fp)353 static char *my_fgets( char *buffer, int max, FILE *fp )
354 /******************************************************/
355 {
356     char        *ptr = buffer;
357     char        *last = buffer + max;
358     int         c;
359 
360     c = getc( fp );
361     while( ptr < last ) {
362         switch ( c ) {
363         case '\r':
364             break; /* don't store CR */
365         case '\n':
366             /* fall through */
367         //case '\0': /* v2.08: */
368 #ifdef DEBUG_OUT
369             if ( Parse_Pass == PASS_1 )
370                 cntflines++;
371 #endif
372             *ptr = NULLC;
373             return( buffer );
374 #if DETECTCTRLZ
375         case 0x1a:
376             /* since source files are opened in binary mode, ctrl-z
377              * handling must be done here.
378              */
379             /* no break */
380 #endif
381         case EOF:
382             *ptr = NULLC;
383             return( ptr > buffer ? buffer : NULL );
384         default:
385             *ptr++ = c;
386         }
387         c = getc( fp );
388     }
389     EmitErr( LINE_TOO_LONG );
390     *(ptr-1) = NULLC;
391     return( buffer );
392 }
393 
394 #if FILESEQ
AddFileSeq(unsigned file)395 void AddFileSeq( unsigned file )
396 /******************************/
397 {
398     struct file_seq *node;
399     node = LclAlloc( sizeof( struct file_seq ) );
400     node->next = NULL;
401     node->file = file;
402     if ( FileSeq.head == NULL )
403         FileSeq.head = FileSeq.tail = node;
404     else {
405         ((struct file_seq *)FileSeq.tail)->next = node;
406         FileSeq.tail = node;
407     }
408 }
409 #endif
410 
411 /* push a new item onto the source stack.
412  * type: SIT_FILE or SIT_MACRO
413  */
PushSrcItem(char type,void * pv)414 static struct src_item *PushSrcItem( char type, void *pv )
415 /********************************************************/
416 {
417     struct src_item   *curr;
418 
419     if ( SrcFree ) {
420         curr = SrcFree;
421         SrcFree = curr->next;
422     } else
423         curr = LclAlloc( sizeof( struct src_item ) );
424     curr->next = src_stack;
425     src_stack = curr;
426     curr->type = type;
427     curr->content = pv;
428     curr->line_num = 0;
429     return( curr );
430 }
431 
432 /* push a macro onto the source stack. */
433 
PushMacro(struct macro_instance * mi)434 void PushMacro( struct macro_instance *mi )
435 /*****************************************/
436 {
437     DebugMsg1(( "PushMacro(%s)\n", mi->macro->name ));
438     PushSrcItem( SIT_MACRO, mi );
439     return;
440 }
441 
442 #if FASTMEM==0
MacroInUse(struct dsym * macro)443 bool MacroInUse( struct dsym *macro )
444 /***********************************/
445 {
446     struct src_item *curr;
447 
448     for ( curr = src_stack; curr ; curr = curr->next )
449         if ( curr->type == SIT_MACRO && curr->mi->macro == &macro->sym )
450             return( TRUE );
451 
452     return( FALSE );
453 }
454 #endif
455 
get_curr_srcfile(void)456 unsigned get_curr_srcfile( void )
457 /*******************************/
458 {
459     struct src_item *curr;
460     for ( curr = src_stack; curr ; curr = curr->next )
461         if ( curr->type == SIT_FILE )
462             return( curr->srcfile );
463     return( ModuleInfo.srcfile );
464 }
465 
466 #if FASTPASS
set_curr_srcfile(unsigned file,uint_32 line_num)467 void set_curr_srcfile( unsigned file, uint_32 line_num )
468 /******************************************************/
469 {
470     if ( file != 0xFFF ) /* 0xFFF is the special value for macro lines */
471         src_stack->srcfile = file;
472     src_stack->line_num = line_num;
473     return;
474 }
475 #endif
476 
SetLineNumber(unsigned line)477 void SetLineNumber( unsigned line )
478 /*********************************/
479 {
480     src_stack->line_num = line;
481     return;
482 }
483 
484 /* for error listing, render the current source file and line */
485 /* this function is also called if pass is > 1,
486  * which is a problem for FASTPASS because the file stack is empty.
487  */
GetCurrSrcPos(char * buffer)488 int GetCurrSrcPos( char *buffer )
489 /*******************************/
490 {
491     struct src_item *curr;
492 
493     for( curr = src_stack; curr; curr = curr->next ) {
494         if ( curr->type == SIT_FILE ) {
495             return( sprintf( buffer, ModuleInfo.EndDirFound == FALSE ? "%s(%" I32_SPEC "u) : " : "%s : ", GetFName( curr->srcfile )->fname , curr->line_num ) );
496         }
497     }
498     *buffer = NULLC;
499     return( 0 );
500 }
501 
502 /* for error listing, render the source nesting structure.
503  * the structure consists of include files and macros.
504  */
505 
print_source_nesting_structure(void)506 void print_source_nesting_structure( void )
507 /*****************************************/
508 {
509     struct src_item *curr;
510     unsigned        tab = 1;
511 
512     DebugMsg1(("print_source_nesting_structure enter, src_stack=%s\n",
513               src_stack == NULL ? "<null>" : GetTopSrcName() ));
514     /* in main source file? */
515     if ( src_stack == NULL || src_stack->next == NULL )
516         return;
517 
518     for( curr = src_stack; curr->next ; curr = curr->next ) {
519         if( curr->type == SIT_FILE ) {
520             PrintNote( NOTE_INCLUDED_BY, tab, "", GetFName( curr->srcfile )->fname, curr->line_num );
521             tab++;
522         } else {
523             //char fname[_MAX_FNAME+_MAX_EXT];
524             if (*(curr->mi->macro->name) == NULLC ) {
525                 PrintNote( NOTE_ITERATION_MACRO_CALLED_FROM, tab, "", "MacroLoop", curr->line_num, curr->mi->macro->value + 1 );
526             } else {
527                 PrintNote( NOTE_MACRO_CALLED_FROM, tab, "", curr->mi->macro->name, curr->line_num, GetFNamePart( GetFName(((struct dsym *)curr->mi->macro)->e.macroinfo->srcfile)->fname ) ) ;
528             }
529             tab++;
530         }
531     }
532     PrintNote( NOTE_MAIN_LINE_CODE, tab, "", GetFName( curr->srcfile )->fname, curr->line_num );
533 }
534 
535 /* Scan the include path for a file!
536  * variable ModuleInfo.g.IncludePath also contains directories set with -I cmdline option.
537  */
open_file_in_include_path(const char * name,char fullpath[])538 static FILE *open_file_in_include_path( const char *name, char fullpath[] )
539 /*************************************************************************/
540 {
541     char            *curr;
542     char            *next;
543     int             i;
544     int             namelen;
545     FILE            *file = NULL;
546 
547     while( isspace( *name ) )
548         name++;
549 
550     curr = ModuleInfo.g.IncludePath;
551     namelen = strlen( name );
552 
553     DebugMsg(("open_file_in_include_path(%s) enter\n", name ));
554     for ( ; curr; curr = next ) {
555         next = strchr( curr, INC_PATH_DELIM );
556         if ( next ) {
557             i = next - curr;
558             next++; /* skip path delimiter char (; or :) */
559         } else {
560             i = strlen( curr );
561         }
562 
563         /* v2.06: ignore
564          * - "empty" entries in PATH
565          * - entries which would cause a buffer overflow
566          */
567         if ( i == 0 || ( ( i + namelen ) >= FILENAME_MAX ) )
568             continue;
569 
570         memcpy( fullpath, curr, i );
571         if( fullpath[i-1] != '/'
572 #if !defined(__UNIX__)
573            && fullpath[i-1] != '\\' && fullpath[i-1] != ':'
574 #endif
575         ) {
576             fullpath[i] = DIR_SEPARATOR;
577             i++;
578         }
579         strcpy( fullpath+i, name );
580 
581         DebugMsg(("open_file_in_include_path: >%s<\n", fullpath ));
582         file = fopen( fullpath, "rb" );
583         if( file ) {
584             break;
585         }
586     }
587     DebugMsg(("open_file_in_include_path()=%p\n", file ));
588     return( file );
589 }
590 
591 /* the worker behind the INCLUDE directive. Also used
592  * by INCBIN and the -Fi cmdline option.
593  * the main source file is added in InputInit().
594  * v2.12: _splitpath()/_makepath() removed
595  */
596 
SearchFile(const char * path,bool queue)597 FILE *SearchFile( const char *path, bool queue )
598 /**********************************************/
599 {
600     FILE        *file = NULL;
601     struct src_item *fl;
602     const char  *fn;
603     bool        isabs;
604     char        fullpath[FILENAME_MAX];
605 
606     DebugMsg1(("SearchFile(%s) enter\n", path ));
607 
608     //_splitpath( path, drive, dir, fname, ext );
609     //DebugMsg1(("SearchFile(): drive=%s, dir=%s, fname=%s, ext=%s\n", drive, dir, fname, ext ));
610     fn = GetFNamePart( path );
611 
612     /* if no absolute path is given, then search in the directory
613      * of the current source file first!
614      * v2.11: various changes because field fullpath has been removed.
615      */
616 
617     isabs = ISABS( path );
618     //if ( dir[0] != '\\' && dir[0] != '/' ) {
619     if ( !isabs ) {
620         for ( fl = src_stack; fl ; fl = fl->next ) {
621             if ( fl->type == SIT_FILE ) {
622                 const char  *fn2;
623                 char        *src;
624                 //_splitpath( GetFName( fl->srcfile )->fname, drive2, dir2, NULL, NULL );
625                 //DebugMsg1(("SearchFile(): curr src=%s, split into drive=%s, dir=%s\n", GetFName( fl->srcfile)->fname, drive2, dir2 ));
626                 src = GetFName( fl->srcfile )->fname;
627                 fn2 = GetFNamePart( src );
628                 if ( fn2 != src ) {
629                     int i = fn2 - src;
630                     /* v2.10: if there's a directory part, add it to the directory part of the current file.
631                      * fixme: check that both parts won't exceed FILENAME_MAX!
632                      * fixme: 'path' is relative, but it may contain a drive letter!
633                      */
634                     memcpy( fullpath, src, i );
635                     strcpy( fullpath + i, path );
636                     if ( file = fopen( fullpath, "rb" ) ) {
637                         DebugMsg1(("SearchFile(): file found, fopen(%s)=%X\n", fullpath, file ));
638                         path = fullpath;
639                     }
640 #ifdef DEBUG_OUT
641                     else
642                         DebugMsg1(("SearchFile(): fopen(%s) failed\n", fullpath ));
643 #endif
644                 }
645                 break;
646             }
647         }
648     }
649     if ( file == NULL ) {
650         fullpath[0] = NULLC;
651         file = fopen( path, "rb" );
652         DebugMsg1(("SearchFile(): fopen(%s)=%X\n", path, file ));
653 
654         /* if the file isn't found yet and include paths have been set,
655          * and NO absolute path is given, then search include dirs
656          */
657         if( file == NULL && ModuleInfo.g.IncludePath != NULL && !isabs ) {
658             if ( file = open_file_in_include_path( path, fullpath ) ) {
659                 DebugMsg1(("SearchFile(): open_file_in_include_path(%s)=%X [%s]\n", path, file, fullpath ));
660                 path = fullpath;
661             }
662 #ifdef DEBUG_OUT
663             else
664                 DebugMsg1(("SearchFile(): open_file_in_include_path(%s)=NULL\n", path ));
665 #endif
666         }
667         if( file == NULL ) {
668             EmitErr( CANNOT_OPEN_FILE, path, ErrnoStr() );
669             return( NULL );
670         }
671     }
672     /* is the file to be added to the file stack?
673      * assembly files usually are, but binary files ( INCBIN ) aren't.
674      */
675     if ( queue ) {
676         fl = PushSrcItem( SIT_FILE, file );
677         fl->srcfile = AddFile( path );
678         FileCur->string_ptr = GetFName( fl->srcfile )->fname;
679 #if FILESEQ
680         if ( Options.line_numbers && Parse_Pass == PASS_1 )
681             AddFileSeq( fl->srcfile );
682 #endif
683     }
684     return( file );
685 }
686 
687 /* get the next source line from file or macro.
688  * v2.11: line queues are no longer read here,
689  * this is now done in RunLineQueue().
690  * Also, if EOF/EOM is reached, the function will
691  * now return NULL in any case.
692  */
693 
GetTextLine(char * buffer)694 char *GetTextLine( char *buffer )
695 /*******************************/
696 {
697     struct src_item *curr = src_stack;
698 
699     if ( curr->type == SIT_FILE ) {
700 
701         if( my_fgets( buffer, MAX_LINE_LEN, curr->file ) ) {
702             curr->line_num++;
703 #ifdef DEBUG_OUT
704             if ( Parse_Pass == PASS_1 ) cntlines++;
705 #endif
706             return( buffer );
707         }
708         DebugCmd( ModuleInfo.g.FNames[curr->srcfile].lines = curr->line_num );
709         DebugMsg1(("GetTextLine: ***** EOF file %s (idx=%u) *****\n", GetFName( curr->srcfile )->fname, curr->srcfile ));
710         /* don't close and remove main source file */
711         if ( curr->next ) {
712             fclose( curr->file );
713             src_stack = curr->next;
714             curr->next = SrcFree;
715             SrcFree = curr;
716         }
717         /* update value of @FileCur variable */
718         for( curr = src_stack; curr->type != SIT_FILE; curr = curr->next );
719         FileCur->string_ptr = GetFName( curr->srcfile)->fname;
720 #if FILESEQ
721         if ( Options.line_numbers && Parse_Pass == PASS_1 )
722             AddFileSeq( curr->srcfile );
723 #endif
724 
725     } else {
726 
727         curr->mi->currline = ( curr->mi->currline ? curr->mi->currline->next : curr->mi->startline );
728         if ( curr->mi->currline ) {
729             /* if line contains placeholders, replace them by current values */
730             if ( curr->mi->currline->ph_count ) {
731                 fill_placeholders( buffer,
732                                   curr->mi->currline->line,
733                                   curr->mi->parmcnt,
734                                   curr->mi->localstart, curr->mi->parm_array );
735             } else {
736                 strcpy( buffer, curr->mi->currline->line );
737             }
738             curr->line_num++;
739 #ifdef DEBUG_OUT
740             if ( Parse_Pass == PASS_1 ) cntlines++;
741 #endif
742             return( buffer );
743         }
744         src_stack = curr->next;
745         curr->next = SrcFree;
746         SrcFree = curr;
747     }
748 
749     return( NULL ); /* end of file or macro reached */
750 }
751 
752 /* add a string to the include path.
753  * called for -I cmdline options.
754  * the include path is rebuilt for each assembled module.
755  * it is stored in the standard C heap.
756  */
AddStringToIncludePath(const char * string)757 void AddStringToIncludePath( const char *string )
758 /***********************************************/
759 {
760     char *tmp;
761     int len;
762 
763     DebugMsg(("AddStringToIncludePath(%s) enter\n", string ));
764     while( isspace( *string ) )
765         string++;
766     len = strlen( string );
767     if ( len == 0 )
768         return;
769     if( ModuleInfo.g.IncludePath == NULL ) {
770         ModuleInfo.g.IncludePath = MemAlloc( len + 1 );
771         strcpy( ModuleInfo.g.IncludePath, string );
772     } else {
773         tmp = ModuleInfo.g.IncludePath;
774         ModuleInfo.g.IncludePath = MemAlloc( strlen( tmp ) + sizeof( INC_PATH_DELIM_STR ) +
775                                 len + 1 );
776         strcpy( ModuleInfo.g.IncludePath, tmp );
777         strcat( ModuleInfo.g.IncludePath, INC_PATH_DELIM_STR );
778         strcat( ModuleInfo.g.IncludePath, string );
779         MemFree( tmp );
780     }
781 }
782 
783 #if 0
784 /* function to get value of @FileCur.
785  * won't work, because text macros don't use asym.sfunc_ptr
786  */
787 static void GetFileCur( struct asym *sym )
788 /****************************************/
789 {
790     struct src_item *curr;
791 
792     for( curr = src_stack; curr && curr->type != SIT_FILE; curr = curr->next );
793     sym->string_ptr = GetFName( curr->srcfile )->name;
794     DebugMsg1(("GetFileCur: curr value=%s\n", sym->string_ptr ));
795 }
796 #endif
797 
798 /* input buffers
799  * 1. src line stack ( default I86: 2*600  = 1200 )
800  * 2. tokenarray     ( default I86: 150*12 = 1800 )
801  * 3. string buffer  ( default I86: 2*600  = 1200 )
802  */
803 
804 #ifdef __I86__
805 #define SIZE_SRCLINES     ( MAX_LINE_LEN * 2 )
806 #define SIZE_TOKENARRAY   ( sizeof( struct asm_tok ) * MAX_TOKEN )
807 #define SIZE_STRINGBUFFER ( MAX_LINE_LEN * 2 )
808 #else
809 #define SIZE_SRCLINES     ( MAX_LINE_LEN * ( MAX_MACRO_NESTING + 1 ) )
810 #define SIZE_TOKENARRAY   ( sizeof( struct asm_tok ) * MAX_TOKEN * MAX_MACRO_NESTING )
811 #define SIZE_STRINGBUFFER ( MAX_LINE_LEN * MAX_MACRO_NESTING )
812 #endif
813 
814 /* PushInputStatus() is used whenever a macro or generated code is to be "executed".
815  * after the macro/code has been assembled, PopInputStatus() is required to restore
816  * the saved status.
817  * the status information that is saved includes
818  * - the source line ( including the comment )
819  * - the token buffer
820  * - the string buffer (used to store token strings)
821  * - field Token_Count
822  * - field line_flags
823  */
824 
PushInputStatus(struct input_status * oldstat)825 struct asm_tok *PushInputStatus( struct input_status *oldstat )
826 /*************************************************************/
827 {
828     oldstat->token_stringbuf = token_stringbuf;
829     oldstat->token_count = Token_Count;
830     oldstat->currsource = CurrSource;
831     /* if there's a comment, attach it to current source */
832     if ( ModuleInfo.CurrComment ) {
833         int i = strlen( CurrSource );
834         oldstat->CurrComment = CurrSource + i;
835         strcpy( oldstat->CurrComment, ModuleInfo.CurrComment );
836     } else
837         oldstat->CurrComment = NULL;
838     oldstat->line_flags = ModuleInfo.line_flags; /* v2.08 */
839 #ifdef __I86__
840     oldstat->tokenarray = ModuleInfo.tokenarray;
841     oldstat->stringbufferend = StringBufferEnd;
842     CurrSource = MemAlloc( MAX_LINE_LEN + SIZE_TOKENARRAY + SIZE_STRINGBUFFER );
843     ModuleInfo.tokenarray = (struct asm_tok *)( CurrSource + MAX_LINE_LEN );
844     token_stringbuf = CurrSource + MAX_LINE_LEN + SIZE_TOKENARRAY;
845 #else
846     token_stringbuf = StringBufferEnd;
847     ModuleInfo.tokenarray += Token_Count + 1;
848     CurrSource = GetAlignedPointer( CurrSource, strlen( CurrSource ) );
849     /**/myassert( ( CurrSource + MAX_LINE_LEN ) <= (char *)ModuleInfo.tokenarray );
850 #ifdef DEBUG_OUT
851     /**/myassert( ( ModuleInfo.tokenarray + sizeof( struct asm_tok ) * MAX_TOKEN ) <= end_tokenarray );
852     /**/myassert( ( token_stringbuf + 2 * MAX_LINE_LEN ) <= end_stringbuf );
853 #endif
854 #endif
855     DebugMsg1(("PushInputStatus() stringbuf-tokencnt-currsrc old=%X-%u-%X new=%X-%X-%X\n",
856                oldstat->token_stringbuf, oldstat->token_count, oldstat->currsource,
857                token_stringbuf, ModuleInfo.tokenarray, CurrSource ));
858     return( ModuleInfo.tokenarray );
859 }
860 
PopInputStatus(struct input_status * newstat)861 void PopInputStatus( struct input_status *newstat )
862 /*************************************************/
863 {
864     DebugMsg1(("PopInputStatus() old=%X-%u-%X new=%X-%u-%X\n",
865                token_stringbuf, Token_Count, CurrSource,
866                newstat->token_stringbuf, newstat->token_count, newstat->currsource ));
867 #ifdef __I86__
868     MemFree( CurrSource );
869 #else
870     StringBufferEnd = token_stringbuf;
871 #endif
872     token_stringbuf = newstat->token_stringbuf;
873     Token_Count = newstat->token_count;
874     CurrSource = newstat->currsource;
875     if ( newstat->CurrComment ) {
876         ModuleInfo.CurrComment = commentbuffer;
877         strcpy( ModuleInfo.CurrComment, newstat->CurrComment );
878         *newstat->CurrComment = NULLC;
879     } else
880         ModuleInfo.CurrComment = NULL;
881 #ifdef __I86__
882     StringBufferEnd = newstat->stringbufferend;
883     ModuleInfo.tokenarray = newstat->tokenarray;
884 #else
885     ModuleInfo.tokenarray -= Token_Count + 1;
886 #endif
887     ModuleInfo.line_flags = newstat->line_flags; /* v2.08 */
888     return;
889 }
890 
891 /* Initializer, called once for each module. */
892 
InputInit(void)893 void InputInit( void )
894 /********************/
895 {
896     struct src_item *fl;
897 #if 0
898     char        path[FILENAME_MAX];
899     char        drive[_MAX_DRIVE];
900     char        dir[_MAX_DIR];
901 #endif
902 
903     DebugMsg(( "InputInit() enter\n" ));
904     //ModuleInfo.g.cnt_fnames = 0;
905     //ModuleInfo.g.FNames = NULL;
906     //IncludePath = NULL;
907     //src_stack = NULL;
908     SrcFree = NULL; /* v2.11 */
909 #if FILESEQ
910     FileSeq.head = NULL;
911 #endif
912 #ifdef DEBUG_OUT
913     cntppl0 = 0;
914     cntppl1 = 0;
915     cntppl2 = 0;
916     cnttok0 = 0;
917     cnttok1 = 0;
918     cntflines = 0;
919     cntlines = 0;
920 #endif
921 
922     /* add path of main module to the include path.
923      * v2.12: unnecessary since v2.10, since the directory part of the
924      * current source is added if a file is to be included; see SearchFile().
925      */
926     //_splitpath( CurrFName[ASM], drive, dir, NULL, NULL );
927     //if ( drive[0] || dir[0] ) {
928     //    _makepath( path, drive, dir, NULL, NULL );
929     //    AddStringToIncludePath( path );
930     //}
931 
932     srclinebuffer = LclAlloc( SIZE_SRCLINES + SIZE_TOKENARRAY + SIZE_STRINGBUFFER );
933     /* the comment buffer is at the end of the source line buffer */
934     commentbuffer = srclinebuffer + SIZE_SRCLINES - MAX_LINE_LEN;
935     /* behind the comment buffer is the token buffer */
936     ModuleInfo.tokenarray = (struct asm_tok *)( srclinebuffer + SIZE_SRCLINES );
937     token_stringbuf = srclinebuffer + SIZE_SRCLINES + SIZE_TOKENARRAY;
938 #ifdef DEBUG_OUT
939     end_tokenarray = (struct asm_tok *)token_stringbuf;
940     end_stringbuf = token_stringbuf + SIZE_STRINGBUFFER;
941     DebugMsg(( "InputInit: srclinebuffer=%p, tokenarray=%p, token_stringbuf=%p end_stringbuf=%p\n", srclinebuffer, ModuleInfo.tokenarray, token_stringbuf, end_stringbuf ));
942 #endif
943 
944     fl = PushSrcItem( SIT_FILE, CurrFile[ASM] );
945     fl->srcfile = ModuleInfo.srcfile = AddFile( CurrFName[ASM] );
946     /* setting a function pointer won't work for text macros! */
947     //FileCur->sfunc_ptr = &GetFileCur;
948     FileCur->string_ptr = GetFName( fl->srcfile )->fname;
949 
950     DebugMsg(( "InputInit() exit\n" ));
951 }
952 
953 /* init for each pass */
954 
InputPassInit(void)955 void InputPassInit( void )
956 /************************/
957 {
958     DebugMsg(( "InputPassInit() enter\n" ));
959     src_stack->line_num = 0;
960     //inside_comment = NULLC;
961     CurrSource = srclinebuffer;
962     *CurrSource = NULLC;
963     StringBufferEnd = token_stringbuf;
964     return;
965 }
966 
967 /* release input buffers for a module */
968 
InputFini(void)969 void InputFini( void )
970 /********************/
971 {
972 #ifdef DEBUG_OUT
973     int   i;
974 
975     /* for the main source file, lines usually isn't filled yet */
976     if ( ModuleInfo.g.FNames )
977         ModuleInfo.g.FNames[ModuleInfo.srcfile].lines = src_stack->line_num;
978     for( i = 0; i < ModuleInfo.g.cnt_fnames; i++ ) {
979         if ( Options.log_all_files ) {
980             if ( ModuleInfo.g.FNames[i].included > 1 )
981                 printf("%2u: %5u *%2u %s\n", i+1, ModuleInfo.g.FNames[i].lines, ModuleInfo.g.FNames[i].included, ModuleInfo.g.FNames[i].fname );
982             else
983                 printf("%2u: %5u     %s\n", i+1, ModuleInfo.g.FNames[i].lines, ModuleInfo.g.FNames[i].fname );
984         }
985         DebugMsg(( "InputFini: idx=%u name=%s\n", i, ModuleInfo.g.FNames[i].fname ));
986     }
987 #endif
988     if ( ModuleInfo.g.IncludePath )
989         MemFree( ModuleInfo.g.IncludePath );
990 
991     /* free items in ModuleInfo.g.FNames ( and FreeFile, if FASTMEM==0 ) */
992     FreeFiles();
993 #ifdef DEBUG_OUT
994     if ( Options.quiet == FALSE ) {
995         printf("lines read(files)/processed in pass one: %" I32_SPEC "u / %" I32_SPEC "u\n", cntflines, cntlines );
996         printf("invokations: PreprocessLine=%" I32_SPEC "u/%" I32_SPEC "u/%" I32_SPEC "u, Tokenize=%" I32_SPEC "u/%" I32_SPEC "u\n", cntppl0, cntppl1, cntppl2, cnttok0, cnttok1 );
997     }
998 #endif
999     ModuleInfo.tokenarray = NULL;
1000 #ifdef DEBUG_OUT
1001     token_stringbuf = NULL;
1002     StringBufferEnd = NULL;
1003     commentbuffer = NULL;
1004     CurrSource = NULL;
1005 #endif
1006     LclFree( srclinebuffer );
1007 }
1008