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 == ¯o->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