]> git.sur5r.net Git - cc65/blob - ar65/library.c
Fixed _textcolor definition.
[cc65] / ar65 / library.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 library.c                                 */
4 /*                                                                           */
5 /*         Library data structures and helpers for the ar65 archiver         */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998     Ullrich von Bassewitz                                        */
10 /*              Wacholderweg 14                                              */
11 /*              D-70597 Stuttgart                                            */
12 /* EMail:       uz@musoftware.de                                             */
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 #include <stdio.h>
37 #include <string.h>
38 #include <errno.h>
39
40 #include "../common/libdefs.h"
41 #include "../common/symdefs.h"
42 #include "../common/exprdefs.h"
43 #include "../common/filepos.h"
44 #include "../common/bitops.h"
45
46 #include "mem.h"
47 #include "error.h"
48 #include "global.h"
49 #include "fileio.h"
50 #include "objdata.h"
51 #include "exports.h"
52 #include "library.h"
53
54
55
56 /*****************************************************************************/
57 /*                                   Data                                    */
58 /*****************************************************************************/
59
60
61
62 /* File descriptor for the library file */
63 FILE*                   NewLib = 0;
64 static FILE*            Lib = 0;
65 static const char*      LibName = 0;
66
67 /* The library header */
68 static LibHeader        Header = {
69     LIB_MAGIC,
70     LIB_VERSION
71 };
72
73
74
75 /*****************************************************************************/
76 /*                       Writing file data structures                        */
77 /*****************************************************************************/
78
79
80
81 static void ReadHeader (void)
82 /* Read the header of a library file */
83 {
84     /* Seek to position zero */
85     fseek (Lib, 0, SEEK_SET);
86
87     /* Read the header fields, checking magic and version */
88     Header.Magic   = Read32 (Lib);
89     if (Header.Magic != LIB_MAGIC) {
90         Error ("`%s' is not a valid library file", LibName);
91     }
92     Header.Version = Read16 (Lib);
93     if (Header.Version != LIB_VERSION) {
94         Error ("Wrong data version in `%s'", LibName);
95     }
96     Header.Flags   = Read16 (Lib);
97     Header.IndexOffs = Read32 (Lib);
98 }
99
100
101
102 static void ReadIndexEntry (void)
103 /* Read one entry in the index */
104 {
105     /* Create a new entry and insert it into the list */
106     ObjData* O  = NewObjData ();
107
108     /* Module name/flags/MTime/Start/Size */
109     O->Name     = ReadStr (Lib);
110     O->Flags    = Read16 (Lib);
111     O->MTime    = Read32 (Lib);
112     O->Start    = Read32 (Lib);
113     O->Size     = Read32 (Lib);
114
115     /* Exports */
116     O->ExportSize = Read16 (Lib);
117     O->Exports    = Xmalloc (O->ExportSize);
118     ReadData (Lib, O->Exports, O->ExportSize);
119
120     /* Imports */
121     O->ImportSize = Read16 (Lib);
122     O->Imports    = Xmalloc (O->ImportSize);
123     ReadData (Lib, O->Imports, O->ImportSize);
124 }
125
126
127
128 static void ReadIndex (void)
129 /* Read the index of a library file */
130 {
131     unsigned Count;
132
133     /* Seek to the start of the index */
134     fseek (Lib, Header.IndexOffs, SEEK_SET);
135
136     /* Read the object file count and calculate the cross ref size */
137     Count = Read16 (Lib);
138
139     /* Read all entries in the index */
140     while (Count--) {
141         ReadIndexEntry ();
142     }
143 }
144
145
146
147 /*****************************************************************************/
148 /*                       Writing file data structures                        */
149 /*****************************************************************************/
150
151
152
153 static void WriteHeader (void)
154 /* Write the header to the library file */
155 {
156     /* Seek to position zero */
157     fseek (NewLib, 0, SEEK_SET);
158
159     /* Write the header fields */
160     Write32 (NewLib, Header.Magic);
161     Write16 (NewLib, Header.Version);
162     Write16 (NewLib, Header.Flags);
163     Write32 (NewLib, Header.IndexOffs);
164 }
165
166
167
168 static void WriteIndexEntry (ObjData* O)
169 /* Write one index entry */
170 {
171     /* Module name/flags/MTime/start/size */
172     WriteStr (NewLib, O->Name);
173     Write16  (NewLib, O->Flags & ~OBJ_HAVEDATA);
174     Write32  (NewLib, O->MTime);
175     Write32  (NewLib, O->Start);
176     Write32  (NewLib, O->Size);
177
178     /* Exports */
179     Write16 (NewLib, O->ExportSize);
180     WriteData (NewLib, O->Exports, O->ExportSize);
181
182     /* Imports */
183     Write16 (NewLib, O->ImportSize);
184     WriteData (NewLib, O->Imports, O->ImportSize);
185 }
186
187
188
189 static void WriteIndex (void)
190 /* Write the index of a library file */
191 {
192     ObjData* O;
193
194     /* Sync I/O in case the last operation was a read */
195     fseek (NewLib, 0, SEEK_CUR);
196
197     /* Remember the current offset in the header */
198     Header.IndexOffs = ftell (NewLib);
199
200     /* Write the object file count */
201     Write16 (NewLib, ObjCount);
202
203     /* Write the object files */
204     O = ObjRoot;
205     while (O) {
206         WriteIndexEntry (O);
207         O = O->Next;
208     }
209 }
210
211
212
213 /*****************************************************************************/
214 /*                             High level stuff                              */
215 /*****************************************************************************/
216
217
218
219 void LibOpen (const char* Name, int MustExist, int NeedTemp)
220 /* Open an existing library and a temporary copy. If MustExist is true, the
221  * old library is expected to exist. If NeedTemp is true, a temporary library
222  * is created.
223  */
224 {
225     /* Remember the name */
226     LibName = StrDup (Name);
227
228     /* Open the existing library for reading */
229     Lib = fopen (Name, "rb");
230     if (Lib == 0) {
231
232         /* File does not exist */
233         if (MustExist) {
234             Error ("Library `%s' does not exist", Name);
235         } else {
236             Warning ("Library `%s' not found - will be created", Name);
237         }
238
239     } else {
240
241         /* We have an existing file: Read the header */
242         ReadHeader ();
243
244         /* Now read the existing index */
245         ReadIndex ();
246
247     }
248
249     if (NeedTemp) {
250         /* Create the temporary library */
251         NewLib = tmpfile ();
252         if (NewLib == 0) {
253             Error ("Cannot create temporary file: %s", strerror (errno));
254         }
255
256         /* Write a dummy header to the temp file */
257         WriteHeader ();
258     }
259 }
260
261
262
263 unsigned long LibCopyTo (FILE* F, unsigned long Bytes)
264 /* Copy data from F to the temp library file, return the start position in
265  * the temporary library file.
266  */
267 {
268     unsigned char Buf [4096];
269
270     /* Remember the position */
271     unsigned long Pos = ftell (NewLib);
272
273     /* Copy loop */
274     while (Bytes) {
275         unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
276         ReadData (F, Buf, Count);
277         WriteData (NewLib, Buf, Count);
278         Bytes -= Count;
279     }
280
281     /* Return the start position */
282     return Pos;
283 }
284
285
286
287 void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F)
288 /* Copy data from the library file into another file */
289 {
290     unsigned char Buf [4096];
291
292     /* Seek to the correct position */
293     fseek (Lib, Pos, SEEK_SET);
294
295     /* Copy loop */
296     while (Bytes) {
297         unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
298         ReadData (Lib, Buf, Count);
299         WriteData (F, Buf, Count);
300         Bytes -= Count;
301     }
302 }
303
304
305
306 static void SkipExpr (unsigned char** Buf)
307 /* Skip an expression in Buf */
308 {
309     /* Get the operation and skip it */
310     unsigned char Op = **Buf;
311     ++(*Buf);
312
313     /* Filter leaf nodes */
314     switch (Op) {
315
316         case EXPR_NULL:
317             return;
318
319         case EXPR_LITERAL:
320             /* 32 bit literal value */
321             *Buf += 4;
322             return;
323
324         case EXPR_SYMBOL:
325             /* 16 bit symbol index */
326             *Buf += 2;
327             return;
328
329         case EXPR_SEGMENT:
330             /* 8 bit segment number */
331             *Buf += 1;
332             return;
333     }
334
335     /* What's left are unary and binary nodes */
336     SkipExpr (Buf);             /* Skip left */
337     SkipExpr (Buf);             /* Skip right */
338 }
339
340
341
342 static void LibCheckExports (ObjData* O)
343 /* Insert all exports from the given object file into the global list
344  * checking for duplicates.
345  */
346 {
347     char Name [256];
348
349     /* Get a pointer to the buffer */
350     unsigned char* Exports = O->Exports;
351
352     /* First two bytes are export count */
353     unsigned Lo = *Exports++;
354     unsigned Hi = *Exports++;
355     unsigned Count = (Hi << 8) + Lo;
356
357     /* Read the exports */
358     if (Verbose > 1) {
359         printf ("Module `%s' (%u exports):\n", O->Name, Count);
360     }
361     while (Count--) {
362
363         unsigned char Len;
364
365         /* Get the export tag */
366         unsigned char Tag = *Exports++;
367
368         /* Next thing is name of symbol */
369         Len = *Exports++;
370         memcpy (Name, Exports, Len);
371         Name [Len] = '\0';
372         Exports += Len;
373
374         /* Skip value of symbol */
375         if (Tag & EXP_EXPR) {
376             /* Expression tree */
377             SkipExpr (&Exports);
378         } else {
379             /* Constant 32 bit value */
380             Exports += 4;
381         }
382
383         /* Skip the position */
384         Exports += POS_SIZE;
385
386         /* Insert the name into the hash table */
387         if (Verbose > 1) {
388                 printf ("  %s\n", Name);
389         }
390         ExpInsert (Name, O->Index);
391     }
392 }
393
394
395
396 void LibClose (void)
397 /* Write remaining data, close both files and copy the temp file to the old
398  * filename
399  */
400 {
401     /* Do we have a temporary library? */
402     if (NewLib) {
403
404         unsigned I;
405         unsigned char Buf [4096];
406         size_t Count;
407
408         /* Index the object files and make an array containing the objects */
409         MakeObjPool ();
410
411         /* Walk through the object file list, inserting exports into the
412          * export list checking for duplicates. Copy any data that is still
413          * in the old library into the new one.
414          */
415         for (I = 0; I < ObjCount; ++I) {
416
417             /* Get a pointer to the object */
418             ObjData* O = ObjPool [I];
419
420             /* Check exports, make global export table */
421             LibCheckExports (O);
422
423             /* Copy data if needed */
424             if ((O->Flags & OBJ_HAVEDATA) == 0) {
425                 /* Data is still in the old library */
426                 fseek (Lib, O->Start, SEEK_SET);
427                 O->Start = ftell (NewLib);
428                 LibCopyTo (Lib, O->Size);
429                 O->Flags |= OBJ_HAVEDATA;
430             }
431         }
432
433         /* Write the index */
434         WriteIndex ();
435
436         /* Write the updated header */
437         WriteHeader ();
438
439         /* Close the file */
440         if (Lib && fclose (Lib) != 0) {
441             Error ("Error closing library: %s", strerror (errno));
442         }
443
444         /* Reopen the library and truncate it */
445         Lib = fopen (LibName, "wb");
446         if (Lib == 0) {
447             Error ("Cannot open library `%s' for writing: %s",
448                    LibName, strerror (errno));
449         }
450
451         /* Copy the new library to the new one */
452         fseek (NewLib, 0, SEEK_SET);
453         while ((Count = fread (Buf, 1, sizeof (Buf), NewLib)) != 0) {
454             if (fwrite (Buf, 1, Count, Lib) != Count) {
455                 Error ("Cannot write to `%s': %s", LibName, strerror (errno));
456             }
457         }
458     }
459
460     /* Close both files */
461     if (Lib && fclose (Lib) != 0) {
462         Error ("Problem closing `%s': %s", LibName, strerror (errno));
463     }
464     if (NewLib && fclose (NewLib) != 0) {
465         Error ("Problem closing temporary library file: %s", strerror (errno));
466     }
467 }
468
469
470