1/*****************************************************************************/
2/* */
3/* fileinfo.c */
4/* */
5/* Source file info structure */
6/* */
7/* */
8/* */
9/* (C) 2001-2011, 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/* common */
37#include "coll.h"
38#include "xmalloc.h"
39
40/* ld65 */
41#include "fileio.h"
42#include "fileinfo.h"
43#include "objdata.h"
44#include "spool.h"
45
46
47
48/*****************************************************************************/
49/* Data */
50/*****************************************************************************/
51
52
53
54/* A list of all file infos without duplicates */
55static Collection FileInfos = STATIC_COLLECTION_INITIALIZER;
56
57
58
59/*****************************************************************************/
60/* Code */
61/*****************************************************************************/
62
63
64
65static int FindFileInfo (unsigned Name, unsigned* Index)
66/* Find the FileInfo for a given file name. The function returns true if the
67** name was found. In this case, Index contains the index of the first item
68** that matches. If the item wasn't found, the function returns false and
69** Index contains the insert position for FileName.
70*/
71{
72 /* Do a binary search */
73 int Lo = 0;
74 int Hi = (int) CollCount (&FileInfos) - 1;
75 int Found = 0;
76 while (Lo <= Hi) {
77
78 /* Mid of range */
79 int Cur = (Lo + Hi) / 2;
80
81 /* Get item */
82 FileInfo* CurItem = CollAt (&FileInfos, Cur);
83
84 /* Found? */
85 if (CurItem->Name < Name) {
86 Lo = Cur + 1;
87 } else {
88 Hi = Cur - 1;
89 /* Since we may have duplicates, repeat the search until we've
90 ** the first item that has a match.
91 */
92 if (CurItem->Name == Name) {
93 Found = 1;
94 }
95 }
96 }
97
98 /* Pass back the index. This is also the insert position */
99 *Index = Lo;
100 return Found;
101}
102
103
104
105static FileInfo* NewFileInfo (unsigned Name, unsigned long MTime, unsigned long Size)
106/* Allocate and initialize a new FileInfo struct and return it */
107{
108 /* Allocate memory */
109 FileInfo* FI = xmalloc (sizeof (FileInfo));
110
111 /* Initialize stuff */
112 FI->Id = ~0U;
113 FI->Name = Name;
114 FI->MTime = MTime;
115 FI->Size = Size;
116 FI->Modules = EmptyCollection;
117
118 /* Return the new struct */
119 return FI;
120}
121
122
123
124static void FreeFileInfo (FileInfo* FI)
125/* Free a file info structure */
126{
127 /* Free the collection */
128 DoneCollection (&FI->Modules);
129
130 /* Free memory for the structure */
131 xfree (FI);
132}
133
134
135
136FileInfo* ReadFileInfo (FILE* F, ObjData* O)
137/* Read a file info from a file and return it */
138{
139 FileInfo* FI;
140
141 /* Read the fields from the file */
142 unsigned Name = MakeGlobalStringId (O, ReadVar (F));
143 unsigned long MTime = Read32 (F);
144 unsigned long Size = ReadVar (F);
145
146 /* Search for the first entry with this name */
147 unsigned Index;
148 if (FindFileInfo (Name, &Index)) {
149
150 /* We have at least one such entry. Try all of them and, if size and
151 ** modification time matches, return the first match. When the loop
152 ** is terminated without finding an entry, Index points one behind
153 ** the last entry with the name, which is the perfect insert position.
154 */
155 FI = CollAt (&FileInfos, Index);
156 while (1) {
157
158 /* Check size and modification time stamp */
159 if (FI->Size == Size && FI->MTime == MTime) {
160 /* Remember that the modules uses this file info, then return it */
161 CollAppend (&FI->Modules, O);
162 return FI;
163 }
164
165 /* Check the next one */
166 if (++Index >= CollCount (&FileInfos)) {
167 /* Nothing left */
168 break;
169 }
170 FI = CollAt (&FileInfos, Index);
171
172 /* Done if the name differs */
173 if (FI->Name != Name) {
174 break;
175 }
176 }
177 }
178
179 /* Not found. Allocate a new FileInfo structure */
180 FI = NewFileInfo (Name, MTime, Size);
181
182 /* Remember that this module uses the file info */
183 CollAppend (&FI->Modules, O);
184
185 /* Insert the file info in our global list. Index points to the insert
186 ** position.
187 */
188 CollInsert (&FileInfos, FI, Index);
189
190 /* Return the new struct */
191 return FI;
192}
193
194
195
196unsigned FileInfoCount (void)
197/* Return the total number of file infos */
198{
199 return CollCount (&FileInfos);
200}
201
202
203
204void AssignFileInfoIds (void)
205/* Remove unused file infos and assign the ids to the remaining ones */
206{
207 unsigned I, J;
208
209 /* Print all file infos */
210 for (I = 0, J = 0; I < CollCount (&FileInfos); ++I) {
211
212 /* Get the next file info */
213 FileInfo* FI = CollAtUnchecked (&FileInfos, I);
214
215 /* If it's unused, free it, otherwise assign the id and keep it */
216 if (CollCount (&FI->Modules) == 0) {
217 FreeFileInfo (FI);
218 } else {
219 FI->Id = J;
220 CollReplace (&FileInfos, FI, J++);
221 }
222 }
223
224 /* The new count is now in J */
225 FileInfos.Count = J;
226}
227
228
229
230void PrintDbgFileInfo (FILE* F)
231/* Output the file info to a debug info file */
232{
233 unsigned I, J;
234
235 /* Print all file infos */
236 for (I = 0; I < CollCount (&FileInfos); ++I) {
237
238 /* Get the file info */
239 const FileInfo* FI = CollAtUnchecked (&FileInfos, I);
240
241 /* Base info */
242 fprintf (F,
243 "file\tid=%u,name=\"%s\",size=%lu,mtime=0x%08lX,mod=",
244 FI->Id, GetString (FI->Name), FI->Size, FI->MTime);
245
246 /* Modules that use the file */
247 for (J = 0; J < CollCount (&FI->Modules); ++J) {
248
249 /* Get the module */
250 const ObjData* O = CollConstAt (&FI->Modules, J);
251
252 /* Output its id */
253 if (J > 0) {
254 fprintf (F, "+%u", O->Id);
255 } else {
256 fprintf (F, "%u", O->Id);
257 }
258 }
259
260 /* Terminate the output line */
261 fputc ('\n', F);
262 }
263}
264