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