1 /*****************************************************************************/
5 /* Library data structures and helpers for the ar65 archiver */
9 /* (C) 1998-2000 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
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 /* File descriptor for the library file */
67 static const char* LibName = 0;
69 /* The library header */
70 static LibHeader Header = {
77 /*****************************************************************************/
78 /* Writing file data structures */
79 /*****************************************************************************/
83 static void ReadHeader (void)
84 /* Read the header of a library file */
86 /* Seek to position zero */
87 fseek (Lib, 0, SEEK_SET);
89 /* Read the header fields, checking magic and version */
90 Header.Magic = Read32 (Lib);
91 if (Header.Magic != LIB_MAGIC) {
92 Error ("`%s' is not a valid library file", LibName);
94 Header.Version = Read16 (Lib);
95 if (Header.Version != LIB_VERSION) {
96 Error ("Wrong data version in `%s'", LibName);
98 Header.Flags = Read16 (Lib);
99 Header.IndexOffs = Read32 (Lib);
104 static void ReadIndexEntry (void)
105 /* Read one entry in the index */
107 /* Create a new entry and insert it into the list */
108 ObjData* O = NewObjData ();
110 /* Module name/flags/MTime/Start/Size */
111 O->Name = ReadStr (Lib);
112 O->Flags = Read16 (Lib);
113 O->MTime = Read32 (Lib);
114 O->Start = Read32 (Lib);
115 O->Size = Read32 (Lib);
118 O->ExportSize = Read16 (Lib);
119 O->Exports = xmalloc (O->ExportSize);
120 ReadData (Lib, O->Exports, O->ExportSize);
123 O->ImportSize = Read16 (Lib);
124 O->Imports = xmalloc (O->ImportSize);
125 ReadData (Lib, O->Imports, O->ImportSize);
130 static void ReadIndex (void)
131 /* Read the index of a library file */
135 /* Seek to the start of the index */
136 fseek (Lib, Header.IndexOffs, SEEK_SET);
138 /* Read the object file count and calculate the cross ref size */
139 Count = Read16 (Lib);
141 /* Read all entries in the index */
149 /*****************************************************************************/
150 /* Writing file data structures */
151 /*****************************************************************************/
155 static void WriteHeader (void)
156 /* Write the header to the library file */
158 /* Seek to position zero */
159 fseek (NewLib, 0, SEEK_SET);
161 /* Write the header fields */
162 Write32 (NewLib, Header.Magic);
163 Write16 (NewLib, Header.Version);
164 Write16 (NewLib, Header.Flags);
165 Write32 (NewLib, Header.IndexOffs);
170 static void WriteIndexEntry (ObjData* O)
171 /* Write one index entry */
173 /* Module name/flags/MTime/start/size */
174 WriteStr (NewLib, O->Name);
175 Write16 (NewLib, O->Flags & ~OBJ_HAVEDATA);
176 Write32 (NewLib, O->MTime);
177 Write32 (NewLib, O->Start);
178 Write32 (NewLib, O->Size);
181 Write16 (NewLib, O->ExportSize);
182 WriteData (NewLib, O->Exports, O->ExportSize);
185 Write16 (NewLib, O->ImportSize);
186 WriteData (NewLib, O->Imports, O->ImportSize);
191 static void WriteIndex (void)
192 /* Write the index of a library file */
196 /* Sync I/O in case the last operation was a read */
197 fseek (NewLib, 0, SEEK_CUR);
199 /* Remember the current offset in the header */
200 Header.IndexOffs = ftell (NewLib);
202 /* Write the object file count */
203 Write16 (NewLib, ObjCount);
205 /* Write the object files */
215 /*****************************************************************************/
216 /* High level stuff */
217 /*****************************************************************************/
221 void LibOpen (const char* Name, int MustExist, int NeedTemp)
222 /* Open an existing library and a temporary copy. If MustExist is true, the
223 * old library is expected to exist. If NeedTemp is true, a temporary library
227 /* Remember the name */
228 LibName = xstrdup (Name);
230 /* Open the existing library for reading */
231 Lib = fopen (Name, "rb");
234 /* File does not exist */
236 Error ("Library `%s' does not exist", Name);
238 Warning ("Library `%s' not found - will be created", Name);
243 /* We have an existing file: Read the header */
246 /* Now read the existing index */
252 /* Create the temporary library */
255 Error ("Cannot create temporary file: %s", strerror (errno));
258 /* Write a dummy header to the temp file */
265 unsigned long LibCopyTo (FILE* F, unsigned long Bytes)
266 /* Copy data from F to the temp library file, return the start position in
267 * the temporary library file.
270 unsigned char Buf [4096];
272 /* Remember the position */
273 unsigned long Pos = ftell (NewLib);
277 unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
278 ReadData (F, Buf, Count);
279 WriteData (NewLib, Buf, Count);
283 /* Return the start position */
289 void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F)
290 /* Copy data from the library file into another file */
292 unsigned char Buf [4096];
294 /* Seek to the correct position */
295 fseek (Lib, Pos, SEEK_SET);
299 unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
300 ReadData (Lib, Buf, Count);
301 WriteData (F, Buf, Count);
308 static unsigned long GetVar (unsigned char** Buf)
309 /* Get a variable sized value from Buf */
318 /* Add this char to the value */
319 V |= ((unsigned long)(C & 0x7F)) << Shift;
324 /* Return the result */
330 static void SkipExpr (unsigned char** Buf)
331 /* Skip an expression in Buf */
333 /* Get the operation and skip it */
334 unsigned char Op = **Buf;
337 /* Filter leaf nodes */
344 /* 32 bit literal value */
349 /* 16 bit symbol index */
354 /* 8 bit segment number */
359 /* What's left are unary and binary nodes */
360 SkipExpr (Buf); /* Skip left */
361 SkipExpr (Buf); /* Skip right */
366 static void SkipFilePos (unsigned char** Buf)
367 /* Skip a file position in Buf */
369 (void) GetVar (Buf); /* Line */
370 (void) GetVar (Buf); /* Col */
371 (void) GetVar (Buf); /* Name */
376 static void LibCheckExports (ObjData* O)
377 /* Insert all exports from the given object file into the global list
378 * checking for duplicates.
381 /* Get a pointer to the buffer */
382 unsigned char* Exports = O->Exports;
384 /* Get the export count */
385 unsigned Count = GetVar (&Exports);
387 /* Read the exports */
389 printf ("Module `%s' (%u exports):\n", O->Name, Count);
397 /* Get the export tag */
400 /* condes decls may follow */
401 Exports += GET_EXP_CONDES_COUNT (Tag);
403 /* Next thing is name of symbol */
404 Len = GetVar (&Exports);
405 Name = xmalloc (Len + 1);
406 memcpy (Name, Exports, Len);
410 /* Skip value of symbol */
411 if (Tag & EXP_EXPR) {
412 /* Expression tree */
415 /* Constant 32 bit value */
419 /* Skip the position */
420 SkipFilePos (&Exports);
422 /* Insert the name into the hash table */
424 printf (" %s\n", Name);
426 ExpInsert (Name, O->Index);
436 /* Write remaining data, close both files and copy the temp file to the old
440 /* Do we have a temporary library? */
444 unsigned char Buf [4096];
447 /* Index the object files and make an array containing the objects */
450 /* Walk through the object file list, inserting exports into the
451 * export list checking for duplicates. Copy any data that is still
452 * in the old library into the new one.
454 for (I = 0; I < ObjCount; ++I) {
456 /* Get a pointer to the object */
457 ObjData* O = ObjPool [I];
459 /* Check exports, make global export table */
462 /* Copy data if needed */
463 if ((O->Flags & OBJ_HAVEDATA) == 0) {
464 /* Data is still in the old library */
465 fseek (Lib, O->Start, SEEK_SET);
466 O->Start = ftell (NewLib);
467 LibCopyTo (Lib, O->Size);
468 O->Flags |= OBJ_HAVEDATA;
472 /* Write the index */
475 /* Write the updated header */
479 if (Lib && fclose (Lib) != 0) {
480 Error ("Error closing library: %s", strerror (errno));
483 /* Reopen the library and truncate it */
484 Lib = fopen (LibName, "wb");
486 Error ("Cannot open library `%s' for writing: %s",
487 LibName, strerror (errno));
490 /* Copy the new library to the new one */
491 fseek (NewLib, 0, SEEK_SET);
492 while ((Count = fread (Buf, 1, sizeof (Buf), NewLib)) != 0) {
493 if (fwrite (Buf, 1, Count, Lib) != Count) {
494 Error ("Cannot write to `%s': %s", LibName, strerror (errno));
499 /* Close both files */
500 if (Lib && fclose (Lib) != 0) {
501 Error ("Problem closing `%s': %s", LibName, strerror (errno));
503 if (NewLib && fclose (NewLib) != 0) {
504 Error ("Problem closing temporary library file: %s", strerror (errno));