1 /*****************************************************************************/
5 /* Input file handling */
9 /* (C) 2000 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
54 /*****************************************************************************/
56 /*****************************************************************************/
60 /* Input line stuff */
61 static char LineBuf [LINESIZE];
63 const char* lptr = LineBuf;
65 /* Current and next input character */
69 /* Maximum count of nested includes */
70 #define MAX_INC_NESTING 16
72 /* Struct that describes an input file */
73 typedef struct IFile IFile;
75 unsigned Index; /* File index */
76 unsigned Usage; /* Usage counter */
77 char Name[1]; /* Name of file (dynamically allocated) */
80 /* Struct that describes an active input file */
81 typedef struct AFile AFile;
83 unsigned Line; /* Line number for this file */
84 FILE* F; /* Input file stream */
85 const char* Name; /* Points to corresponding IFile name */
88 /* List of all input files */
89 static Collection IFiles = STATIC_COLLECTION_INITIALIZER;
91 /* List of all active files */
92 static Collection AFiles = STATIC_COLLECTION_INITIALIZER;
96 /*****************************************************************************/
98 /*****************************************************************************/
102 static IFile* NewIFile (const char* Name)
103 /* Create and return a new IFile */
105 /* Get the length of the name */
106 unsigned Len = strlen (Name);
108 /* Allocate a IFile structure */
109 IFile* IF = xmalloc (sizeof (IFile) + Len);
111 /* Initialize the fields */
112 IF->Index = CollCount (&IFiles) + 1;
114 memcpy (IF->Name, Name, Len+1);
116 /* Insert the new structure into the IFile collection */
117 CollAppend (&IFiles, IF);
119 /* Return the new struct */
125 /*****************************************************************************/
127 /*****************************************************************************/
131 static AFile* NewAFile (IFile* IF, FILE* F)
132 /* Create and return a new AFile */
134 /* Allocate a AFile structure */
135 AFile* AF = xmalloc (sizeof (AFile));
137 /* Initialize the fields */
142 /* Increment the usage counter of the corresponding IFile */
145 /* Insert the new structure into the AFile collection */
146 CollAppend (&AFiles, AF);
148 /* Return the new struct */
154 static void FreeAFile (AFile* AF)
155 /* Free an AFile structure */
162 /*****************************************************************************/
164 /*****************************************************************************/
168 static IFile* FindFile (const char* Name)
169 /* Find the file with the given name in the list of all files. Since the list
170 * is not large (usually less than 10), I don't care about using hashes or
171 * similar things and do a linear search.
175 for (I = 0; I < CollCount (&IFiles); ++I) {
176 /* Get the file struct */
177 IFile* IF = CollAt (&IFiles, I);
179 if (strcmp (Name, IF->Name) == 0) {
180 /* Found, return the struct */
191 void OpenMainFile (const char* Name)
192 /* Open the main file. Will call Fatal() in case of failures. */
194 /* Setup a new IFile structure for the main file */
195 IFile* IF = NewIFile (Name);
197 /* Open the file for reading */
198 FILE* F = fopen (Name, "r");
201 Fatal (FAT_CANNOT_OPEN_INPUT, strerror (errno));
204 /* Allocate a new AFile structure for the file */
205 (void) NewAFile (IF, F);
210 void OpenIncludeFile (const char* Name, unsigned DirSpec)
211 /* Open an include file and insert it into the tables. */
217 /* Check for the maximum include nesting */
218 if (CollCount (&AFiles) > MAX_INC_NESTING) {
219 PPError (ERR_INCLUDE_NESTING);
223 /* Search for the file */
224 N = FindInclude (Name, DirSpec);
226 PPError (ERR_INCLUDE_NOT_FOUND, Name);
230 /* Search the list of all input files for this file. If we don't find
231 * it, create a new IFile object.
238 /* We don't need N any longer, since we may now use IF->Name */
242 F = fopen (IF->Name, "r");
244 /* Error opening the file */
245 PPError (ERR_INCLUDE_OPEN_FAILURE, IF->Name, strerror (errno));
249 /* Allocate a new AFile structure */
250 (void) NewAFile (IF, F);
255 static void CloseIncludeFile (void)
256 /* Close an include file and switch to the higher level file. Set Input to
257 * NULL if this was the main file.
262 /* Get the number of active input files */
263 unsigned AFileCount = CollCount (&AFiles);
265 /* Must have an input file when called */
266 PRECONDITION (AFileCount > 0);
268 /* Get the current active input file */
269 Input = CollLast (&AFiles);
271 /* Close the current input file (we're just reading so no error check) */
274 /* Delete the last active file from the active file collection */
275 CollDelete (&AFiles, AFileCount-1);
277 /* Delete the active file structure */
283 void ClearLine (void)
284 /* Clear the current input line */
294 void InitLine (const char* Buf)
295 /* Initialize lptr from Buf and read CurC and NextC from the new input line */
309 /* Read the next character from the input stream and make CurC and NextC
310 * valid. If end of line is reached, both are set to NUL, no more lines
311 * are read by this function.
314 if (lptr[0] != '\0') {
330 /* Get a line from the current input. Returns 0 on end of file. */
341 /* If there is no file open, bail out, otherwise get the current input file */
342 if (CollCount (&AFiles) == 0) {
345 Input = CollLast (&AFiles);
347 /* Read lines until we get one with real contents */
350 while (!Done && Len < LINESIZE) {
352 while (fgets (line + Len, LINESIZE - Len, Input->F) == 0) {
357 /* Leave the current file */
360 /* If there is no file open, bail out, otherwise get the
363 if (CollCount (&AFiles) == 0) {
366 Input = CollLast (&AFiles);
370 /* We got a new line */
373 /* Remove the trailing newline if we have one */
374 Part = strlen (line + Len);
377 while (Len > 0 && line [Len-1] == '\n') {
382 /* Output the source line in the generated assembler file
385 if (AddSource && line[Start] != '\0') {
386 AddCodeLine ("; %s", line+Start);
389 /* Check if we have a line continuation character at the end. If not,
392 if (Len > 0 && line[Len-1] == '\\') {
393 line[Len-1] = '\n'; /* Replace by newline */
399 /* Got a line. Initialize the current and next characters. */
408 const char* GetCurrentFile (void)
409 /* Return the name of the current input file */
411 unsigned AFileCount = CollCount (&AFiles);
412 if (AFileCount > 0) {
413 const AFile* AF = CollAt (&AFiles, AFileCount-1);
416 /* No open file. Use the main file if we have one. */
417 unsigned IFileCount = CollCount (&IFiles);
418 if (IFileCount > 0) {
419 const IFile* IF = CollAt (&IFiles, 0);
422 return "(outside file scope)";
429 unsigned GetCurrentLine (void)
430 /* Return the line number in the current input file */
432 unsigned AFileCount = CollCount (&AFiles);
433 if (AFileCount > 0) {
434 const AFile* AF = CollAt (&AFiles, AFileCount-1);
444 void WriteDependencies (FILE* F, const char* OutputFile)
445 /* Write a makefile dependency list to the given file */
449 /* Get the number of input files */
450 unsigned IFileCount = CollCount (&IFiles);
452 /* Print the output file followed by a tab char */
453 fprintf (F, "%s:\t", OutputFile);
455 /* Loop over all files */
456 for (I = 0; I < IFileCount; ++I) {
457 /* Get the next input file */
458 const IFile* IF = CollAt (&IFiles, I);
459 /* If this is not the first file, add a space */
460 const char* Format = (I == 0)? "%s" : " %s";
461 /* Print the dependency */
462 fprintf (F, Format, IF->Name);