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
61static unsigned HT_GenHash (const void* Key);
62/* Generate the hash over a key. */
63
64static const void* HT_GetKey (const void* Entry);
65/* Given a pointer to the user entry data, return a pointer to the key. */
66
67static 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 */
86typedef struct FileEntry FileEntry;
87struct 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 */
97static Collection FileTab = STATIC_COLLECTION_INITIALIZER;
98
99/* Hash table functions */
100static const HashFunctions HashFunc = {
101 HT_GenHash,
102 HT_GetKey,
103 HT_Compare
104};
105
106/* Hash table, hashed by name */
107static HashTable HashTab = STATIC_HASHTABLE_INITIALIZER (HASHTAB_COUNT, &HashFunc);
108
109
110
111/*****************************************************************************/
112/* Hash table functions */
113/*****************************************************************************/
114
115
116
117static 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
125static 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
133static 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
150static 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
177const 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
203unsigned 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
223unsigned 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
238void 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
265static 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
280static 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
311static 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
343void 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}
355