1 /*****************************************************************************/
5 /* Library data structures and helpers for the ar65 archiver */
9 /* (C) 1998-2011, 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 /*****************************************************************************/
57 /*****************************************************************************/
59 /*****************************************************************************/
63 /* File descriptor for the library file */
66 static const char* LibName = 0;
68 /* The library header */
69 static LibHeader Header = {
78 /*****************************************************************************/
79 /* Writing file data structures */
80 /*****************************************************************************/
84 static void ReadHeader (void)
85 /* Read the header of a library file */
87 /* Seek to position zero */
88 fseek (Lib, 0, SEEK_SET);
90 /* Read the header fields, checking magic and version */
91 Header.Magic = Read32 (Lib);
92 if (Header.Magic != LIB_MAGIC) {
93 Error ("`%s' is not a valid library file", LibName);
95 Header.Version = Read16 (Lib);
96 if (Header.Version != LIB_VERSION) {
97 Error ("Wrong data version in `%s'", LibName);
99 Header.Flags = Read16 (Lib);
100 Header.IndexOffs = Read32 (Lib);
105 static void ReadIndexEntry (void)
106 /* Read one entry in the index */
110 /* Create a new entry and insert it into the list */
111 ObjData* O = NewObjData ();
113 /* Module name/flags/MTime/Start/Size */
114 O->Name = ReadStr (Lib);
115 O->Flags = Read16 (Lib);
116 O->MTime = Read32 (Lib);
117 O->Start = Read32 (Lib);
118 O->Size = Read32 (Lib);
121 O->StringCount = ReadVar (Lib);
122 O->Strings = xmalloc (O->StringCount * sizeof (char*));
123 for (I = 0; I < O->StringCount; ++I) {
124 O->Strings[I] = ReadStr (Lib);
128 O->ImportSize = ReadVar (Lib);
129 O->Imports = xmalloc (O->ImportSize);
130 ReadData (Lib, O->Imports, O->ImportSize);
133 O->ExportSize = ReadVar (Lib);
134 O->Exports = xmalloc (O->ExportSize);
135 ReadData (Lib, O->Exports, O->ExportSize);
140 static void ReadIndex (void)
141 /* Read the index of a library file */
145 /* Seek to the start of the index */
146 fseek (Lib, Header.IndexOffs, SEEK_SET);
148 /* Read the object file count and calculate the cross ref size */
149 Count = ReadVar (Lib);
151 /* Read all entries in the index */
159 /*****************************************************************************/
160 /* Writing file data structures */
161 /*****************************************************************************/
165 static void WriteHeader (void)
166 /* Write the header to the library file */
168 /* Seek to position zero */
169 fseek (NewLib, 0, SEEK_SET);
171 /* Write the header fields */
172 Write32 (NewLib, Header.Magic);
173 Write16 (NewLib, Header.Version);
174 Write16 (NewLib, Header.Flags);
175 Write32 (NewLib, Header.IndexOffs);
180 static void WriteIndexEntry (const ObjData* O)
181 /* Write one index entry */
185 /* Module name/flags/MTime/start/size */
186 WriteStr (NewLib, O->Name);
187 Write16 (NewLib, O->Flags & ~OBJ_HAVEDATA);
188 Write32 (NewLib, O->MTime);
189 Write32 (NewLib, O->Start);
190 Write32 (NewLib, O->Size);
193 WriteVar (NewLib, O->StringCount);
194 for (I = 0; I < O->StringCount; ++I) {
195 WriteStr (NewLib, O->Strings[I]);
199 WriteVar (NewLib, O->ImportSize);
200 WriteData (NewLib, O->Imports, O->ImportSize);
203 WriteVar (NewLib, O->ExportSize);
204 WriteData (NewLib, O->Exports, O->ExportSize);
209 static void WriteIndex (void)
210 /* Write the index of a library file */
214 /* Sync I/O in case the last operation was a read */
215 fseek (NewLib, 0, SEEK_CUR);
217 /* Remember the current offset in the header */
218 Header.IndexOffs = ftell (NewLib);
220 /* Write the object file count */
221 WriteVar (NewLib, CollCount (&ObjPool));
223 /* Write the object files */
224 for (I = 0; I < CollCount (&ObjPool); ++I) {
225 WriteIndexEntry (CollConstAt (&ObjPool, I));
231 /*****************************************************************************/
232 /* High level stuff */
233 /*****************************************************************************/
237 void LibOpen (const char* Name, int MustExist, int NeedTemp)
238 /* Open an existing library and a temporary copy. If MustExist is true, the
239 * old library is expected to exist. If NeedTemp is true, a temporary library
243 /* Remember the name */
244 LibName = xstrdup (Name);
246 /* Open the existing library for reading */
247 Lib = fopen (Name, "rb");
250 /* File does not exist */
252 Error ("Library `%s' does not exist", Name);
254 Warning ("Library `%s' not found - will be created", Name);
259 /* We have an existing file: Read the header */
262 /* Now read the existing index */
268 /* Create the temporary library */
271 Error ("Cannot create temporary file: %s", strerror (errno));
274 /* Write a dummy header to the temp file */
281 unsigned long LibCopyTo (FILE* F, unsigned long Bytes)
282 /* Copy data from F to the temp library file, return the start position in
283 * the temporary library file.
286 unsigned char Buf [4096];
288 /* Remember the position */
289 unsigned long Pos = ftell (NewLib);
293 unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
294 ReadData (F, Buf, Count);
295 WriteData (NewLib, Buf, Count);
299 /* Return the start position */
305 void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F)
306 /* Copy data from the library file into another file */
308 unsigned char Buf [4096];
310 /* Seek to the correct position */
311 fseek (Lib, Pos, SEEK_SET);
315 unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
316 ReadData (Lib, Buf, Count);
317 WriteData (F, Buf, Count);
324 static unsigned long GetVar (unsigned char** Buf)
325 /* Get a variable sized value from Buf */
334 /* Add this char to the value */
335 V |= ((unsigned long)(C & 0x7F)) << Shift;
340 /* Return the result */
346 static void SkipExpr (unsigned char** Buf)
347 /* Skip an expression in Buf */
349 /* Get the operation and skip it */
350 unsigned char Op = **Buf;
353 /* Filter leaf nodes */
360 /* 32 bit literal value */
365 /* Variable seized symbol index */
370 /* 8 bit segment number */
375 /* What's left are unary and binary nodes */
376 SkipExpr (Buf); /* Skip left */
377 SkipExpr (Buf); /* Skip right */
382 static void SkipLineInfoList (unsigned char** Buf)
383 /* Skip a list of line infos in Buf */
385 /* Number of indices preceeds the list */
386 unsigned long Count = GetVar (Buf);
396 static void LibCheckExports (ObjData* O)
397 /* Insert all exports from the given object file into the global list
398 * checking for duplicates.
401 /* Get a pointer to the buffer */
402 unsigned char* Exports = O->Exports;
404 /* Get the export count */
405 unsigned Count = GetVar (&Exports);
407 /* Read the exports */
408 Print (stdout, 1, "Module `%s' (%u exports):\n", O->Name, Count);
413 /* Get the export tag and skip the address size */
414 unsigned Type = GetVar (&Exports);
417 /* condes decls may follow */
418 Exports += SYM_GET_CONDES_COUNT (Type);
420 /* Next thing is index of name of symbol */
421 Name = GetObjString (O, GetVar (&Exports));
423 /* Skip value of symbol */
424 if (SYM_IS_EXPR (Type)) {
425 /* Expression tree */
428 /* Constant 32 bit value */
432 /* Skip the line info */
433 SkipLineInfoList (&Exports);
435 /* Insert the name into the hash table */
436 Print (stdout, 1, " %s\n", Name);
444 /* Write remaining data, close both files and copy the temp file to the old
448 /* Do we have a temporary library? */
452 unsigned char Buf [4096];
455 /* Walk through the object file list, inserting exports into the
456 * export list checking for duplicates. Copy any data that is still
457 * in the old library into the new one.
459 for (I = 0; I < CollCount (&ObjPool); ++I) {
461 /* Get a pointer to the object */
462 ObjData* O = CollAt (&ObjPool, I);
464 /* Check exports, make global export table */
467 /* Copy data if needed */
468 if ((O->Flags & OBJ_HAVEDATA) == 0) {
469 /* Data is still in the old library */
470 fseek (Lib, O->Start, SEEK_SET);
471 O->Start = ftell (NewLib);
472 LibCopyTo (Lib, O->Size);
473 O->Flags |= OBJ_HAVEDATA;
477 /* Write the index */
480 /* Write the updated header */
484 if (Lib && fclose (Lib) != 0) {
485 Error ("Error closing library: %s", strerror (errno));
488 /* Reopen the library and truncate it */
489 Lib = fopen (LibName, "wb");
491 Error ("Cannot open library `%s' for writing: %s",
492 LibName, strerror (errno));
495 /* Copy the new library to the new one */
496 fseek (NewLib, 0, SEEK_SET);
497 while ((Count = fread (Buf, 1, sizeof (Buf), NewLib)) != 0) {
498 if (fwrite (Buf, 1, Count, Lib) != Count) {
499 Error ("Cannot write to `%s': %s", LibName, strerror (errno));
504 /* Close both files */
505 if (Lib && fclose (Lib) != 0) {
506 Error ("Problem closing `%s': %s", LibName, strerror (errno));
508 if (NewLib && fclose (NewLib) != 0) {
509 Error ("Problem closing temporary library file: %s", strerror (errno));