1 /*****************************************************************************/
5 /* Library data structures and helpers for the ar65 archiver */
9 /* (C) 1998-2012, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
58 /*****************************************************************************/
60 /*****************************************************************************/
64 /* Name of the library file */
65 const char* LibName = 0;
67 /* File descriptor for the library file */
71 /* The library header */
72 static LibHeader Header = {
81 /*****************************************************************************/
82 /* Writing file data structures */
83 /*****************************************************************************/
87 static void ReadHeader (void)
88 /* Read the header of a library file */
90 /* Seek to position zero */
91 fseek (Lib, 0, SEEK_SET);
93 /* Read the header fields, checking magic and version */
94 Header.Magic = Read32 (Lib);
95 if (Header.Magic != LIB_MAGIC) {
96 Error ("`%s' is not a valid library file", LibName);
98 Header.Version = Read16 (Lib);
99 if (Header.Version != LIB_VERSION) {
100 Error ("Wrong data version in `%s'", LibName);
102 Header.Flags = Read16 (Lib);
103 Header.IndexOffs = Read32 (Lib);
108 static void ReadIndexEntry (void)
109 /* Read one entry in the index */
111 /* Create a new entry and insert it into the list */
112 ObjData* O = NewObjData ();
114 /* Module name/flags/MTime/Start/Size */
115 O->Name = ReadStr (Lib);
116 O->Flags = Read16 (Lib);
117 O->MTime = Read32 (Lib);
118 O->Start = Read32 (Lib);
119 O->Size = Read32 (Lib);
124 static void ReadIndex (void)
125 /* Read the index of a library file */
129 /* Seek to the start of the index */
130 fseek (Lib, Header.IndexOffs, SEEK_SET);
132 /* Read the object file count and calculate the cross ref size */
133 Count = ReadVar (Lib);
135 /* Read all entries in the index */
140 /* Read basic object file data from the actual entries */
141 for (I = 0; I < CollCount (&ObjPool); ++I) {
143 /* Get the object file entry */
144 ObjData* O = CollAtUnchecked (&ObjPool, I);
147 ObjReadData (Lib, O);
153 /*****************************************************************************/
154 /* Writing file data structures */
155 /*****************************************************************************/
159 static void WriteHeader (void)
160 /* Write the header to the library file */
162 /* Seek to position zero */
163 fseek (NewLib, 0, SEEK_SET);
165 /* Write the header fields */
166 Write32 (NewLib, Header.Magic);
167 Write16 (NewLib, Header.Version);
168 Write16 (NewLib, Header.Flags);
169 Write32 (NewLib, Header.IndexOffs);
174 static void WriteIndexEntry (const ObjData* O)
175 /* Write one index entry */
177 /* Module name/flags/MTime/start/size */
178 WriteStr (NewLib, O->Name);
179 Write16 (NewLib, O->Flags & ~OBJ_HAVEDATA);
180 Write32 (NewLib, O->MTime);
181 Write32 (NewLib, O->Start);
182 Write32 (NewLib, O->Size);
187 static void WriteIndex (void)
188 /* Write the index of a library file */
192 /* Sync I/O in case the last operation was a read */
193 fseek (NewLib, 0, SEEK_CUR);
195 /* Remember the current offset in the header */
196 Header.IndexOffs = ftell (NewLib);
198 /* Write the object file count */
199 WriteVar (NewLib, CollCount (&ObjPool));
201 /* Write the object files */
202 for (I = 0; I < CollCount (&ObjPool); ++I) {
203 WriteIndexEntry (CollConstAt (&ObjPool, I));
209 /*****************************************************************************/
210 /* High level stuff */
211 /*****************************************************************************/
215 void LibOpen (const char* Name, int MustExist, int NeedTemp)
216 /* Open an existing library and a temporary copy. If MustExist is true, the
217 * old library is expected to exist. If NeedTemp is true, a temporary library
221 /* Remember the name */
222 LibName = xstrdup (Name);
224 /* Open the existing library for reading */
225 Lib = fopen (Name, "rb");
228 /* File does not exist */
230 Error ("Library `%s' does not exist", Name);
232 Warning ("Library `%s' not found - will be created", Name);
237 /* We have an existing file: Read the header */
240 /* Now read the existing index */
246 /* Create the temporary library */
249 Error ("Cannot create temporary file: %s", strerror (errno));
252 /* Write a dummy header to the temp file */
259 unsigned long LibCopyTo (FILE* F, unsigned long Bytes)
260 /* Copy data from F to the temp library file, return the start position in
261 * the temporary library file.
264 unsigned char Buf [4096];
266 /* Remember the position */
267 unsigned long Pos = ftell (NewLib);
271 unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
272 ReadData (F, Buf, Count);
273 WriteData (NewLib, Buf, Count);
277 /* Return the start position */
283 void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F)
284 /* Copy data from the library file into another file */
286 unsigned char Buf [4096];
288 /* Seek to the correct position */
289 fseek (Lib, Pos, SEEK_SET);
293 unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
294 ReadData (Lib, Buf, Count);
295 WriteData (F, Buf, Count);
302 static void LibCheckExports (ObjData* O)
303 /* Insert all exports from the given object file into the global list
304 * checking for duplicates.
309 /* Let the user know what we do */
310 Print (stdout, 1, "Module `%s' (%u exports):\n", O->Name, CollCount (&O->Exports));
312 /* Insert the exports into the global table */
313 for (I = 0; I < CollCount (&O->Exports); ++I) {
315 /* Get the name of the export */
316 const char* Name = CollConstAt (&O->Exports, I);
318 /* Insert the name into the hash table */
319 Print (stdout, 1, " %s\n", Name);
327 /* Write remaining data, close both files and copy the temp file to the old
331 /* Do we have a temporary library? */
335 unsigned char Buf [4096];
338 /* Walk through the object file list, inserting exports into the
339 * export list checking for duplicates. Copy any data that is still
340 * in the old library into the new one.
342 for (I = 0; I < CollCount (&ObjPool); ++I) {
344 /* Get a pointer to the object */
345 ObjData* O = CollAtUnchecked (&ObjPool, I);
347 /* Check exports, make global export table */
350 /* Copy data if needed */
351 if ((O->Flags & OBJ_HAVEDATA) == 0) {
352 /* Data is still in the old library */
353 fseek (Lib, O->Start, SEEK_SET);
354 O->Start = ftell (NewLib);
355 LibCopyTo (Lib, O->Size);
356 O->Flags |= OBJ_HAVEDATA;
360 /* Write the index */
363 /* Write the updated header */
367 if (Lib && fclose (Lib) != 0) {
368 Error ("Error closing library: %s", strerror (errno));
371 /* Reopen the library and truncate it */
372 Lib = fopen (LibName, "wb");
374 Error ("Cannot open library `%s' for writing: %s",
375 LibName, strerror (errno));
378 /* Copy the new library to the new one */
379 fseek (NewLib, 0, SEEK_SET);
380 while ((Count = fread (Buf, 1, sizeof (Buf), NewLib)) != 0) {
381 if (fwrite (Buf, 1, Count, Lib) != Count) {
382 Error ("Cannot write to `%s': %s", LibName, strerror (errno));
387 /* Close both files */
388 if (Lib && fclose (Lib) != 0) {
389 Error ("Problem closing `%s': %s", LibName, strerror (errno));
391 if (NewLib && fclose (NewLib) != 0) {
392 Error ("Problem closing temporary library file: %s", strerror (errno));