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 */ |
55 | static Collection FileInfos = STATIC_COLLECTION_INITIALIZER; |
56 | |
57 | |
58 | |
59 | /*****************************************************************************/ |
60 | /* Code */ |
61 | /*****************************************************************************/ |
62 | |
63 | |
64 | |
65 | static 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 | |
105 | static 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 | |
124 | static 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 | |
136 | FileInfo* 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 | |
196 | unsigned FileInfoCount (void) |
197 | /* Return the total number of file infos */ |
198 | { |
199 | return CollCount (&FileInfos); |
200 | } |
201 | |
202 | |
203 | |
204 | void 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 | |
230 | void 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 | |