]> git.sur5r.net Git - cc65/blob - src/ar65/objfile.c
first working version (with filenames at least, devices not tested yet)
[cc65] / src / ar65 / objfile.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 objfile.c                                 */
4 /*                                                                           */
5 /*                Object file handling 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 <string.h>
37 #include <errno.h>
38 #ifdef __WATCOMC__
39 /* Watcom has the file in the wrong directory */
40 #  include <sys/utime.h>
41 #else
42 #  include <sys/types.h>                /* FreeBSD needs this */
43 #  include <utime.h>
44 #endif
45 #include <time.h>
46 #include <sys/stat.h>
47
48 #include "error.h"
49 #include "mem.h"
50 #include "objdata.h"
51 #include "fileio.h"
52 #include "library.h"
53 #include "objfile.h"
54
55
56
57 /*****************************************************************************/
58 /*                                   Code                                    */
59 /*****************************************************************************/
60
61
62
63 static const char* GetModule (const char* Name)
64 /* Get a module name from the file name */
65 {
66     /* Make a module name from the file name */
67     const char* Module = Name + strlen (Name);
68     while (Module > Name) {
69         --Module;
70         if (*Module == '/' || *Module == '\\') {
71             ++Module;
72             break;
73         }
74     }
75     if (*Module == 0) {
76         Error ("Cannot make module name from `%s'", Name);
77     }
78     return Module;
79 }
80
81
82
83 void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name)
84 /* Read the header of the object file checking the signature */
85 {
86     H->Magic      = Read32 (Obj);
87     if (H->Magic != OBJ_MAGIC) {
88         Error ("`%s' is not an object file", Name);
89     }
90     H->Version    = Read16 (Obj);
91     if (H->Version != OBJ_VERSION) {
92         Error ("Object file `%s' has wrong version", Name);
93     }
94     H->Flags      = Read16 (Obj);
95     H->OptionOffs = Read32 (Obj);
96     H->OptionSize = Read32 (Obj);
97     H->FileOffs   = Read32 (Obj);
98     H->FileSize   = Read32 (Obj);
99     H->SegOffs    = Read32 (Obj);
100     H->SegSize    = Read32 (Obj);
101     H->ImportOffs = Read32 (Obj);
102     H->ImportSize = Read32 (Obj);
103     H->ExportOffs = Read32 (Obj);
104     H->ExportSize = Read32 (Obj);
105     H->DbgSymOffs = Read32 (Obj);
106     H->DbgSymSize = Read32 (Obj);
107 }
108
109
110
111 void ObjWriteHeader (FILE* Obj, ObjHeader* H)
112 /* Write the header of the object file */
113 {
114     Write32 (Obj, H->Magic);
115     Write16 (Obj, H->Version);
116     Write16 (Obj, H->Flags);
117     Write32 (Obj, H->OptionOffs);
118     Write32 (Obj, H->OptionSize);
119     Write32 (Obj, H->FileOffs);
120     Write32 (Obj, H->FileSize);
121     Write32 (Obj, H->SegOffs);
122     Write32 (Obj, H->SegSize);
123     Write32 (Obj, H->ImportOffs);
124     Write32 (Obj, H->ImportSize);
125     Write32 (Obj, H->ExportOffs);
126     Write32 (Obj, H->ExportSize);
127     Write32 (Obj, H->DbgSymOffs);
128     Write32 (Obj, H->DbgSymSize);
129 }
130
131
132
133 void ObjAdd (const char* Name)
134 /* Add an object file to the library */
135 {
136     struct stat StatBuf;
137     const char* Module;
138     ObjHeader H;
139     ObjData* O;
140
141     /* Open the object file */
142     FILE* Obj = fopen (Name, "rb");
143     if (Obj == 0) {
144         Error ("Could not open `%s': %s", Name, strerror (errno));
145     }
146
147     /* Get the modification time of the object file */
148     if (fstat (fileno (Obj), &StatBuf) != 0) {
149         Error ("Cannot stat object file `%s': %s", Name, strerror (errno));
150     }
151
152     /* Read and check the header */
153     ObjReadHeader (Obj, &H, Name);
154
155     /* Make a module name from the file name */
156     Module = GetModule (Name);
157
158     /* Check if we already have a module with this name */
159     O = FindObjData (Module);
160     if (O == 0) {
161         /* Not found, create a new entry */
162         O = NewObjData ();
163     } else {
164         /* Found - check the file modification times of the internal copy
165          * and the external one.
166          */
167         if (difftime ((time_t)O->MTime, StatBuf.st_mtime) > 0.0) {
168             Warning ("Replacing module `%s' by older version", O->Name);
169         }
170     }
171
172     /* Initialize the object module data structure */
173     O->Name       = StrDup (Module);
174     O->Flags      = OBJ_HAVEDATA;
175     O->MTime      = StatBuf.st_mtime;
176     O->ImportSize = H.ImportSize;
177     O->Imports    = Xmalloc (O->ImportSize);
178     O->ExportSize = H.ExportSize;
179     O->Exports    = Xmalloc (O->ExportSize);
180
181     /* Read imports and exports */
182     fseek (Obj, H.ImportOffs, SEEK_SET);
183     ReadData (Obj, O->Imports, O->ImportSize);
184     fseek (Obj, H.ExportOffs, SEEK_SET);
185     ReadData (Obj, O->Exports, O->ExportSize);
186
187     /* Skip the object file header */
188     O->Start = ftell (NewLib);
189     fseek (NewLib, OBJ_HDR_SIZE, SEEK_CUR);
190
191     /* Copy the remaining sections */
192     fseek (Obj, H.DbgSymOffs, SEEK_SET);
193     H.DbgSymOffs = LibCopyTo (Obj, H.DbgSymSize) - O->Start;
194     fseek (Obj, H.OptionOffs, SEEK_SET);
195     H.OptionOffs = LibCopyTo (Obj, H.OptionSize) - O->Start;
196     fseek (Obj, H.SegOffs, SEEK_SET);
197     H.SegOffs = LibCopyTo (Obj, H.SegSize) - O->Start;
198     fseek (Obj, H.FileOffs, SEEK_SET);
199     H.FileOffs = LibCopyTo (Obj, H.FileSize) - O->Start;
200
201     /* Calculate the amount of data written */
202     O->Size = ftell (NewLib) - O->Start;
203
204     /* Clear the remaining header fields */
205     H.ImportOffs = H.ImportSize = 0;
206     H.ExportOffs = H.ExportSize = 0;
207
208     /* Seek back and write the updated header */
209     fseek (NewLib, O->Start, SEEK_SET);
210     ObjWriteHeader (NewLib, &H);
211
212     /* Now seek again to end of file */
213     fseek (NewLib, 0, SEEK_END);
214
215     /* Done, close the file (we read it only, so no error check) */
216     fclose (Obj);
217 }
218
219
220
221 void ObjExtract (const char* Name)
222 /* Extract a module from the library */
223 {
224     unsigned long ImportStart;
225     unsigned long ExportStart;
226     struct utimbuf U;
227     ObjHeader H;
228     FILE* Obj;
229
230
231     /* Make a module name from the file name */
232     const char* Module = GetModule (Name);
233
234     /* Try to find the module in the library */
235     ObjData* O = FindObjData (Module);
236
237     /* Bail out if the module does not exist */
238     if (O == 0) {
239         Error ("Module `%s' not found in library", Module);
240     }
241
242     /* Open the output file */
243     Obj = fopen (Name, "w+b");
244     if (Obj == 0) {
245         Error ("Cannot open target file `%s': %s", Name, strerror (errno));
246     }
247
248     /* Copy the first four segments including the header to the new file */
249     LibCopyFrom (O->Start, O->Size, Obj);
250
251     /* Write imports and exports */
252     ImportStart = ftell (Obj);
253     WriteData (Obj, O->Imports, O->ImportSize);
254     ExportStart = ftell (Obj);
255     WriteData (Obj, O->Exports, O->ExportSize);
256
257     /* Seek back and read the header */
258     fseek (Obj, 0, SEEK_SET);
259     ObjReadHeader (Obj, &H, Name);
260
261     /* Update the header fields */
262     H.ImportOffs = ImportStart;
263     H.ImportSize = O->ImportSize;
264     H.ExportOffs = ExportStart;
265     H.ExportSize = O->ExportSize;
266
267     /* Write the changed header */
268     fseek (Obj, 0, SEEK_SET);
269     ObjWriteHeader (Obj, &H);
270
271     /* Close the file */
272     if (fclose (Obj) != 0) {
273         Error ("Problem closing object file `%s': %s", Name, strerror (errno));
274     }
275
276     /* Set access and modification time */
277     U.actime = O->MTime;
278     U.modtime = O->MTime;
279     if (utime (Name, &U) != 0) {
280         Error ("Cannot set mod time on `%s': %s", Name, strerror (errno));
281     }
282 }
283
284
285
286
287
288