]> git.sur5r.net Git - cc65/blob - src/cc65/input.c
Use the xmalloc module from the common directory.
[cc65] / src / cc65 / input.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  input.c                                  */
4 /*                                                                           */
5 /*                            Input file handling                            */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000      Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <errno.h>
39
40 #include "../common/xmalloc.h"
41
42 #include "asmcode.h"
43 #include "check.h"
44 #include "error.h"
45 #include "global.h"
46 #include "incpath.h"
47 #include "io.h"
48 #include "input.h"
49
50
51
52 /*****************************************************************************/
53 /*                                   Data                                    */
54 /*****************************************************************************/
55
56
57
58 /* Maximum count of nested includes */
59 #define MAX_INC_NESTING         16
60
61 /* Struct that describes an input file */
62 typedef struct IFile IFile;
63 struct IFile {
64     IFile*      Next;           /* Next file in single linked list      */
65     IFile*      Active;         /* Next file in list of active includes */
66     unsigned    Index;          /* File index                           */
67     unsigned    Line;           /* Line number for this file            */
68     FILE*       F;              /* Input file stream                    */
69     char        Name[1];        /* Name of file (dynamically allocated) */
70 };
71
72 /* List of input files */
73 static unsigned IFileTotal = 0; /* Total number of files                */
74 static IFile*   IFileList  = 0; /* Single linked list of all files      */
75 static unsigned IFileCount = 0; /* Number of active input files         */
76 static IFile*   Input      = 0; /* Single linked list of active files   */
77
78
79
80 /*****************************************************************************/
81 /*                               struct IFile                                */
82 /*****************************************************************************/
83
84
85
86 static IFile* NewIFile (const char* Name, FILE* F)
87 /* Create and return a new IFile */
88 {
89     /* Get the length of the name */
90     unsigned Len = strlen (Name);
91
92     /* Allocate a IFile structure */
93     IFile* IF = xmalloc (sizeof (IFile) + Len);
94
95     /* Initialize the fields */
96     IF->Index   = ++IFileTotal;
97     IF->Line    = 0;
98     IF->F       = F;
99     memcpy (IF->Name, Name, Len+1);
100
101     /* Insert the structure into both lists */
102     IF->Next    = IFileList;
103     IFileList   = IF;
104     IF->Active  = Input;
105     Input       = IF;
106     ++IFileCount;
107
108     /* Return the new struct */
109     return IF;
110 }
111
112
113
114 /*****************************************************************************/
115 /*                                   Code                                    */
116 /*****************************************************************************/
117
118
119
120 void OpenMainFile (const char* Name)
121 /* Open the main file. Will call Fatal() in case of failures. */
122 {
123     /* Open the file for reading */
124     FILE* F = fopen (Name, "r");
125     if (F == 0) {
126         /* Cannot open */
127         Fatal (FAT_CANNOT_OPEN_INPUT, strerror (errno));
128     }
129
130     /* Setup a new IFile structure */
131     NewIFile (Name, F);
132 }
133
134
135
136 void OpenIncludeFile (const char* Name, unsigned DirSpec)
137 /* Open an include file and insert it into the tables. */
138 {
139     char* N;
140     FILE* F;
141
142     /* Check for the maximum include nesting */
143     if (IFileCount > MAX_INC_NESTING) {
144         PPError (ERR_INCLUDE_NESTING);
145         return;
146     }
147
148     /* Search for the file */
149     N = FindInclude (Name, DirSpec);
150     if (N == 0) {
151         PPError (ERR_INCLUDE_NOT_FOUND, Name);
152         return;
153     }
154
155     /* Open the file */
156     F = fopen (N, "r");
157     if (F == 0) {
158         /* Error opening the file */
159         PPError (ERR_INCLUDE_OPEN_FAILURE, N);
160         xfree (N);
161         return;
162     }
163
164     /* Allocate a new IFile structure */
165     NewIFile (N, F);
166
167     /* We don't need the full name any longer */
168     xfree (N);
169 }
170
171
172
173 static void CloseIncludeFile (void)
174 /* Close an include file and switch to the higher level file. Set Input to
175  * NULL if this was the main file.
176  */
177 {
178     /* Must have an input file when called */
179     PRECONDITION (Input != 0);
180
181     /* Close the current input file (we're just reading so no error check) */
182     fclose (Input->F);
183
184     /* Make this file inactive and the last one active again */
185     Input = Input->Active;
186 }
187
188
189
190 int NextLine (void)
191 /* Get a line from the current input. Returns 0 on end of file. */
192 {
193     unsigned    Len;
194     unsigned    Part;
195     unsigned    Start;
196     int         Done;
197
198     /* Setup the line */
199     kill ();
200
201     /* If there is no file open, bail out */
202     if (Input == 0) {
203         return 0;
204     }
205
206     /* Read lines until we get one with real contents */
207     Len = 0;
208     Done = 0;
209     while (!Done && Len < LINESIZE) {
210
211         while (fgets (line + Len, LINESIZE - Len, Input->F) == 0) {
212
213             /* eof */
214             kill ();
215
216             /* Leave the current file */
217             CloseIncludeFile ();
218
219             /* If this was the last file, bail out */
220             if (Input == 0) {
221                 return 0;
222             }
223         }
224
225         /* We got a new line */
226         ++Input->Line;
227
228         /* Remove the trailing newline if we have one */
229         Part = strlen (line + Len);
230         Start = Len;
231         Len += Part;
232         while (Len > 0 && line [Len-1] == '\n') {
233             --Len;
234         }
235         line [Len] = '\0';
236
237         /* Output the source line in the generated assembler file
238          * if requested.
239          */
240         if (AddSource && line[Start] != '\0') {
241             AddCodeLine ("; %s", line+Start);
242         }
243
244         /* Check if we have a line continuation character at the end. If not,
245          * we're done.
246          */
247         if (Len > 0 && line[Len-1] == '\\') {
248             line[Len-1] = '\n';         /* Replace by newline */
249         } else {
250             Done = 1;
251         }
252     }
253
254     /* Got a line */
255     return 1;
256 }
257
258
259
260 const char* GetCurrentFile (void)
261 /* Return the name of the current input file */
262 {
263     if (Input == 0) {
264         return "(outside file scope)";
265     } else {
266         return Input->Name;
267     }
268 }
269
270
271
272 unsigned GetCurrentLine (void)
273 /* Return the line number in the current input file */
274 {
275     return Input? Input->Line : 0;
276 }
277
278
279