]> git.sur5r.net Git - cc65/blob - src/ca65/filetab.c
Changed most "backticks" (grave accents) into apostrophes.
[cc65] / src / ca65 / filetab.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 filetab.h                                 */
4 /*                                                                           */
5 /*                         Input file table for ca65                         */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2008 Ullrich von Bassewitz                                       */
10 /*               Roemerstrasse 52                                            */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
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 /* common */
41 #include "check.h"
42 #include "coll.h"
43 #include "hashtab.h"
44 #include "xmalloc.h"
45
46 /* ca65 */
47 #include "error.h"
48 #include "filetab.h"
49 #include "global.h"
50 #include "objfile.h"
51 #include "spool.h"
52
53
54
55 /*****************************************************************************/
56 /*                                 Forwards                                  */
57 /*****************************************************************************/
58
59
60
61 static unsigned HT_GenHash (const void* Key);
62 /* Generate the hash over a key. */
63
64 static const void* HT_GetKey (const void* Entry);
65 /* Given a pointer to the user entry data, return a pointer to the key. */
66
67 static int HT_Compare (const void* Key1, const void* Key2);
68 /* Compare two keys. The function must return a value less than zero if
69 ** Key1 is smaller than Key2, zero if both are equal, and a value greater
70 ** than zero if Key1 is greater then Key2.
71 */
72
73
74
75 /*****************************************************************************/
76 /*                                   Data                                    */
77 /*****************************************************************************/
78
79
80
81 /* Number of entries in the table and the mask to generate the hash */
82 #define HASHTAB_MASK    0x1F
83 #define HASHTAB_COUNT   (HASHTAB_MASK + 1)
84
85 /* An entry in the file table */
86 typedef struct FileEntry FileEntry;
87 struct FileEntry {
88     HashNode            Node;
89     unsigned            Name;           /* File name */
90     unsigned            Index;          /* Index of entry */
91     FileType            Type;           /* Type of file */
92     unsigned long       Size;           /* Size of file */
93     unsigned long       MTime;          /* Time of last modification */
94 };
95
96 /* Array of all entries, listed by index */
97 static Collection FileTab = STATIC_COLLECTION_INITIALIZER;
98
99 /* Hash table functions */
100 static const HashFunctions HashFunc = {
101     HT_GenHash,
102     HT_GetKey,
103     HT_Compare
104 };
105
106 /* Hash table, hashed by name */
107 static HashTable HashTab = STATIC_HASHTABLE_INITIALIZER (HASHTAB_COUNT, &HashFunc);
108
109
110
111 /*****************************************************************************/
112 /*                           Hash table functions                            */
113 /*****************************************************************************/
114
115
116
117 static unsigned HT_GenHash (const void* Key)
118 /* Generate the hash over a key. */
119 {
120     return (*(const unsigned*)Key & HASHTAB_MASK);
121 }
122
123
124
125 static const void* HT_GetKey (const void* Entry)
126 /* Given a pointer to the user entry data, return a pointer to the index */
127 {
128     return &((FileEntry*) Entry)->Name;
129 }
130
131
132
133 static int HT_Compare (const void* Key1, const void* Key2)
134 /* Compare two keys. The function must return a value less than zero if
135 ** Key1 is smaller than Key2, zero if both are equal, and a value greater
136 ** than zero if Key1 is greater then Key2.
137 */
138 {
139     return (int)*(const unsigned*)Key1 - (int)*(const unsigned*)Key2;
140 }
141
142
143
144 /*****************************************************************************/
145 /*                                   Code                                    */
146 /*****************************************************************************/
147
148
149
150 static FileEntry* NewFileEntry (unsigned Name, FileType Type,
151                                 unsigned long Size, unsigned long MTime)
152 /* Create a new FileEntry, insert it into the tables and return it */
153 {
154     /* Allocate memory for the entry */
155     FileEntry* F = xmalloc (sizeof (FileEntry));
156
157     /* Initialize the fields */
158     InitHashNode (&F->Node);
159     F->Name     = Name;
160     F->Index    = CollCount (&FileTab) + 1;     /* First file has index #1 */
161     F->Type     = Type;
162     F->Size     = Size;
163     F->MTime    = MTime;
164
165     /* Insert the file into the file table */
166     CollAppend (&FileTab, F);
167
168     /* Insert the entry into the hash table */
169     HT_Insert (&HashTab, F);
170
171     /* Return the new entry */
172     return F;
173 }
174
175
176
177 const StrBuf* GetFileName (unsigned Name)
178 /* Get the name of a file where the name index is known */
179 {
180     static const StrBuf ErrorMsg = LIT_STRBUF_INITIALIZER ("(outside file scope)");
181
182     const FileEntry* F;
183
184     if (Name == 0) {
185         /* Name was defined outside any file scope, use the name of the first
186         ** file instead. Errors are then reported with a file position of
187         ** line zero in the first file.
188         */
189         if (CollCount (&FileTab) == 0) {
190             /* No files defined until now */
191             return &ErrorMsg;
192         } else {
193             F = CollConstAt (&FileTab, 0);
194         }
195     } else {
196         F = CollConstAt (&FileTab, Name-1);
197     }
198     return GetStrBuf (F->Name);
199 }
200
201
202
203 unsigned GetFileIndex (const StrBuf* Name)
204 /* Return the file index for the given file name. */
205 {
206     /* Get the string pool index from the name */
207     unsigned NameIdx = GetStrBufId (Name);
208
209     /* Search in the hash table for the name */
210     const FileEntry* F = HT_Find (&HashTab, &NameIdx);
211
212     /* If we don't have this index, print a diagnostic and use the main file */
213     if (F == 0) {
214         Error ("File name '%m%p' not found in file table", Name);
215         return 0;
216     } else {
217         return F->Index;
218     }
219 }
220
221
222
223 unsigned AddFile (const StrBuf* Name, FileType Type,
224                   unsigned long Size, unsigned long MTime)
225 /* Add a new file to the list of input files. Return the index of the file in
226 ** the table.
227 */
228 {
229     /* Create a new file entry and insert it into the tables */
230     FileEntry* F = NewFileEntry (GetStrBufId (Name), Type, Size, MTime);
231
232     /* Return the index */
233     return F->Index;
234 }
235
236
237
238 void WriteFiles (void)
239 /* Write the list of input files to the object file */
240 {
241     unsigned I;
242
243     /* Tell the obj file module that we're about to start the file list */
244     ObjStartFiles ();
245
246     /* Write the file count */
247     ObjWriteVar (CollCount (&FileTab));
248
249     /* Write the file data */
250     for (I = 0; I < CollCount (&FileTab); ++I) {
251         /* Get a pointer to the entry */
252         const FileEntry* F = CollConstAt (&FileTab, I);
253         /* Write the fields */
254         ObjWriteVar (F->Name);
255         ObjWrite32 (F->MTime);
256         ObjWriteVar (F->Size);
257     }
258
259     /* Done writing files */
260     ObjEndFiles ();
261 }
262
263
264
265 static void WriteEscaped (FILE* F, const char* Name)
266 /* Write a file name to a dependency file escaping spaces */
267 {
268     while (*Name) {
269         if (*Name == ' ') {
270             /* Escape spaces */
271             fputc ('\\', F);
272         }
273         fputc (*Name, F);
274         ++Name;
275     }
276 }
277
278
279
280 static void WriteDep (FILE* F, FileType Types)
281 /* Helper function. Writes all file names that match Types to the output */
282 {
283     unsigned I;
284
285     /* Loop over all files */
286     for (I = 0; I < CollCount (&FileTab); ++I) {
287
288         const StrBuf* Filename;
289
290         /* Get the next input file */
291         const FileEntry* E = (const FileEntry*) CollAt (&FileTab, I);
292
293         /* Ignore it if it is not of the correct type */
294         if ((E->Type & Types) == 0) {
295             continue;
296         }
297
298         /* If this is not the first file, add a space */
299         if (I > 0) {
300             fputc (' ', F);
301         }
302
303         /* Print the dependency escaping spaces */
304         Filename = GetStrBuf (E->Name);
305         WriteEscaped (F, SB_GetConstBuf (Filename));
306     }
307 }
308
309
310
311 static void CreateDepFile (const char* Name, FileType Types)
312 /* Create a dependency file with the given name and place dependencies for
313 ** all files with the given types there.
314 */
315 {
316     /* Open the file */
317     FILE* F = fopen (Name, "w");
318     if (F == 0) {
319         Fatal ("Cannot open dependency file '%s': %s", Name, strerror (errno));
320     }
321
322     /* Print the output file followed by a tab char */
323     WriteEscaped (F, OutFile);
324     fputs (":\t", F);
325
326     /* Write out the dependencies for the output file */
327     WriteDep (F, Types);
328     fputs ("\n\n", F);
329
330     /* Write out a phony dependency for the included files */
331     WriteDep (F, Types);
332     fputs (":\n\n", F);
333
334     /* Close the file, check for errors */
335     if (fclose (F) != 0) {
336         remove (Name);
337         Fatal ("Cannot write to dependeny file (disk full?)");
338     }
339 }
340
341
342
343 void CreateDependencies (void)
344 /* Create dependency files requested by the user */
345 {
346     if (SB_NotEmpty (&DepName)) {
347         CreateDepFile (SB_GetConstBuf (&DepName),
348                        FT_MAIN | FT_INCLUDE | FT_BINARY);
349     }
350     if (SB_NotEmpty (&FullDepName)) {
351         CreateDepFile (SB_GetConstBuf (&FullDepName),
352                        FT_MAIN | FT_INCLUDE | FT_BINARY | FT_DBGINFO);
353     }
354 }