output: macho -- Add support for N_PEXT in macho output
[nasm.git] / rdoff / rdlar.c
blob419d2d0d42f41c559bc688babb6879a73113a488
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2009 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
35 * rdlar.c - new librarian/archiver for RDOFF2.
38 #include "compiler.h"
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <ctype.h>
43 #include <stdarg.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <time.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
50 #include "rdlar.h"
52 #define PROGRAM_VERSION "0.1"
54 /** Constants **/
55 const char commands[] = "adnrtx";
56 const char modifiers[] = "cflouvV";
58 /** Global variables **/
59 char *progname = "rdlar";
60 char **_argv = NULL;
61 struct {
62 bool createok;
63 bool usefname;
64 bool align;
65 bool odate;
66 bool fresh;
67 int verbose;
68 } options = {
69 0, 0, 0, 0, 0, 0};
71 #define _ENDIANNESS 0 /* 0 for little, 1 for big */
74 * Convert int32_t to little endian (if we were compiled on big-endian machine)
76 static void int32_ttolocal(int32_t *l)
78 #if _ENDIANNESS
79 uint8_t t;
80 uint8_t *p = (uint8_t *)l;
82 t = p[0];
83 p[0] = p[3];
84 p[3] = t;
85 t = p[1];
86 p[1] = p[2];
87 p[2] = p[1];
88 #endif
92 * Print version information
94 void show_version(void)
96 puts("New RDOFF2 librarian/archiver, version " PROGRAM_VERSION);
100 * Print usage instructions
102 void usage(void)
104 printf("Usage: %s [-]{%s}[%s] libfile [module-name] [files]\n",
105 progname, commands, modifiers);
106 puts(" commands:\n"
107 " a - add module(s) to the library\n"
108 " d - delete module(s) from the library\n"
109 " n - create the library\n"
110 " r - replace module(s)\n"
111 " t - display contents of library\n"
112 " x - extract module(s)\n"
113 " command specific modifiers:\n"
114 " o - preserve original dates\n"
115 " u - only replace modules that are newer than library contents\n"
116 " generic modifiers:\n"
117 " c - do not warn if the library had to be created\n"
118 " f - use file name as a module name\n"
119 " v - be verbose\n"
120 " V - display version information");
124 * Print an error message and exit
126 void error_exit(int errcode, bool useperror, const char *fmt, ...)
128 va_list ap;
130 fprintf(stderr, "%s: ", progname);
131 va_start(ap, fmt);
132 vfprintf(stderr, fmt, ap);
133 va_end(ap);
134 putc('\n', stderr);
135 if (useperror)
136 perror(progname);
137 exit(errcode);
141 * Fill in and write a header
143 void put_header(struct rdlm_hdr *hdr, FILE * libfp, char *modname)
145 int n = 0;
147 hdr->hdrsize = sizeof(*hdr);
148 if (modname)
149 hdr->hdrsize += (n = strlen(modname) + 1);
150 if (libfp == NULL)
151 return;
152 if (fwrite(hdr, 1, sizeof(*hdr), libfp) != sizeof(*hdr) ||
153 (modname && (fwrite(modname, 1, n, libfp) != n)))
154 error_exit(3, true, "could not write header");
158 * Copy n bytes from one file to another and return last character read.
160 char copybytes(FILE * fp, FILE * fp2, int n)
162 int i, t = 0;
164 for (i = 0; i < n; i++) {
165 t = fgetc(fp);
166 if (t == EOF)
167 error_exit(1, false, "premature end of file in '%s'",
168 _argv[2]);
169 if (fp2)
170 if (fputc(t, fp2) == EOF)
171 error_exit(1, false, "write error");
173 return (char)t;
177 * Copy uint32_t from one file to another.
178 * Return local presentation of int32_t.
180 int32_t copyint32_t(FILE * fp, FILE * fp2)
182 int32_t l;
183 int i, t;
184 uint8_t *p = (uint8_t *)&l;
186 for (i = 0; i < 4; i++) {
187 t = fgetc(fp);
188 if (t == EOF)
189 error_exit(1, false, "premature end of file in '%s'",
190 _argv[2]);
191 if (fp2)
192 if (fputc(t, fp2) == EOF)
193 error_exit(1, false, "write error");
194 *p++ = t;
196 int32_ttolocal(&l);
197 return l;
201 * Create a new library
203 int create_library(char *libname)
205 FILE *libfp;
206 struct rdlm_hdr hdr;
208 hdr.magic = RDLAMAG;
209 hdr.hdrsize = 0;
210 hdr.date = time(NULL);
211 hdr.owner = getuid();
212 hdr.group = getgid();
213 hdr.mode = umask(022);
214 hdr.size = 0;
216 libfp = fopen(libname, "wb");
217 if (!libfp)
218 error_exit(1, true, "could not open '%s'\n", libname);
220 /* Write library header */
221 put_header(&hdr, libfp, NULL);
223 fclose(libfp);
224 return true;
228 * Add a module to the library
230 int add_module(FILE * libfp, const char *fname, char *modname)
232 FILE *modfp;
233 struct rdlm_hdr hdr = { RDLMMAG, 0, 0, 0, 0, 0, 0 };
234 struct stat finfo;
235 int i;
237 if (options.verbose)
238 fprintf(stderr, "adding module %s\n", modname);
240 /* Initialize some fields in the module header */
241 if (stat(fname, &finfo) < 0)
242 error_exit(1, true, "could not stat '%s'", fname);
243 hdr.date = finfo.st_mtime;
244 hdr.owner = finfo.st_uid;
245 hdr.group = finfo.st_gid;
246 hdr.size = finfo.st_size;
248 modfp = fopen(fname, "rb");
249 if (!modfp)
250 error_exit(1, true, "could not open '%s'", fname);
252 /* Write module header */
253 put_header(&hdr, libfp, modname);
255 /* Put the module itself */
256 while (!feof(modfp)) {
257 i = fgetc(modfp);
258 if (i == EOF)
259 break;
260 if (fputc(i, libfp) == EOF)
261 error_exit(1, false, "write error");
264 fclose(modfp);
265 return true;
269 * Main
271 int main(int argc, char **argv)
273 FILE *libfp, *tmpfp, *modfp = NULL;
274 struct stat finfo;
275 struct rdlm_hdr hdr;
276 char buf[MAXMODNAMELEN], *p = NULL;
277 char c;
278 int i;
280 progname = argv[0];
281 _argv = argv;
283 if (argc < 2) {
284 usage();
285 exit(1);
288 rdoff_init();
290 /* Check whether some modifiers were specified */
291 for (i = 1; i < strlen(argv[1]); i++) {
292 switch (c = argv[1][i]) {
293 case 'c':
294 options.createok = true;
295 break;
296 case 'f':
297 options.usefname = true;
298 break;
299 case 'l':
300 options.align = true;
301 break;
302 case 'o':
303 options.odate = true;
304 break;
305 case 'u':
306 options.fresh = true;
307 break;
308 case 'v':
309 options.verbose++;
310 break;
311 case 'V':
312 show_version();
313 exit(0);
314 default:
315 if (strchr(commands, c) == NULL)
316 error_exit(2, false, "invalid command or modifier '%c'",
321 if (argc < 3)
322 error_exit(2, false, "missing library name");
324 /* Process the command */
325 if (argv[1][0] == '-')
326 argv[1]++;
327 switch (c = argv[1][0]) {
328 case 'a': /* add a module */
329 if (argc < 4 || (!options.usefname && argc != 5))
330 error_exit(2, false, "invalid number of arguments");
332 /* Check if a library already exists. If not - create it */
333 if (access(argv[2], F_OK) < 0) {
334 if (!options.createok)
335 fprintf(stderr, "creating library %s\n", argv[2]);
336 create_library(argv[2]);
339 libfp = fopen(argv[2], "ab");
340 if (!libfp)
341 error_exit(1, true, "could not open '%s'", argv[2]);
343 if (!options.usefname)
344 add_module(libfp, argv[4], argv[3]);
345 else
346 for (i = 3; i < argc; i++)
347 add_module(libfp, argv[i], argv[i]);
349 fclose(libfp);
350 break;
352 case 'n': /* create library */
353 create_library(argv[2]);
354 break;
356 case 'x': /* extract module(s) */
357 if (!options.usefname)
358 argc--;
359 if (argc < 4)
360 error_exit(2, false, "required parameter missing");
361 p = options.usefname ? argv[3] : argv[4];
362 case 't': /* list library contents */
363 libfp = fopen(argv[2], "rb");
364 if (!libfp)
365 error_exit(1, true, "could not open '%s'\n", argv[2]);
367 /* Read library header */
368 if (fread(&hdr, 1, sizeof(hdr), libfp) != sizeof(hdr) ||
369 hdr.magic != RDLAMAG)
370 error_exit(1, false, "invalid library format");
372 /* Walk through the library looking for requested module */
373 while (!feof(libfp)) {
374 /* Read module header */
375 i = fread(&hdr, 1, sizeof(hdr), libfp);
376 if (feof(libfp))
377 break;
378 if (i != sizeof(hdr) || hdr.magic != RDLMMAG)
379 error_exit(1, false, "invalid module header");
380 /* Read module name */
381 i = hdr.hdrsize - sizeof(hdr);
382 if (i > sizeof(buf) || fread(buf, 1, i, libfp) != i)
383 error_exit(1, false, "invalid module name");
384 if (c == 'x') {
385 /* Check against desired name */
386 if (!strcmp(buf, argv[3])) {
387 if (options.verbose)
388 fprintf(stderr,
389 "extracting module %s to file %s\n", buf,
391 modfp = fopen(p, "wb");
392 if (!modfp)
393 error_exit(1, true, "could not open '%s'", p);
395 } else {
396 printf("%-40s ", buf);
397 if (options.verbose) {
398 printf("%ld bytes", hdr.size);
400 putchar('\n');
403 copybytes(libfp, modfp, hdr.size);
404 if (modfp)
405 break;
408 fclose(libfp);
409 if (modfp)
410 fclose(modfp);
411 else if (c == 'x')
412 error_exit(1, false, "module '%s' not found in '%s'",
413 argv[3], argv[2]);
414 break;
416 case 'r': /* replace module(s) */
417 argc--;
418 if (stat(argv[4], &finfo) < 0)
419 error_exit(1, true, "could not stat '%s'", argv[4]);
420 case 'd': /* delete module(s) */
421 if (argc < 4)
422 error_exit(2, false, "required parameter missing");
424 libfp = fopen(argv[2], "rb");
425 if (!libfp)
426 error_exit(1, true, "could not open '%s'", argv[2]);
428 /* Copy the library into a temporary file */
429 tmpfp = tmpfile();
430 if (!tmpfp)
431 error_exit(1, true, "could not open temporary file");
433 stat(argv[2], &finfo);
434 copybytes(libfp, tmpfp, finfo.st_size);
435 rewind(tmpfp);
436 freopen(argv[2], "wb", libfp);
438 /* Read library header and write it to a new file */
439 if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) ||
440 hdr.magic != RDLAMAG)
441 error_exit(1, false, "invalid library format");
442 put_header(&hdr, libfp, NULL);
444 /* Walk through the library looking for requested module */
445 while (!feof(tmpfp)) {
446 /* Read module header */
447 if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) ||
448 hdr.magic != RDLMMAG)
449 error_exit(1, false, "invalid module header");
450 /* Read module name */
451 i = hdr.hdrsize - sizeof(hdr);
452 if (i > sizeof(buf) || fread(buf, 1, i, tmpfp) != i)
453 error_exit(1, false, "invalid module name");
454 /* Check against desired name */
455 if (!strcmp(buf, argv[3]) &&
456 (c == 'd' || !options.odate
457 || finfo.st_mtime <= hdr.date)) {
458 if (options.verbose)
459 fprintf(stderr, "deleting module %s\n", buf);
460 fseek(tmpfp, hdr.size, SEEK_CUR);
461 break;
462 } else {
463 put_header(&hdr, libfp, buf);
464 copybytes(tmpfp, libfp, hdr.size);
468 if (c == 'r') {
469 /* Copy new module into library */
470 p = options.usefname ? argv[4] : argv[3];
471 add_module(libfp, argv[4], p);
474 /* Copy rest of library if any */
475 while (!feof(tmpfp)) {
476 if ((i = fgetc(tmpfp)) == EOF)
477 break;
479 if (fputc(i, libfp) == EOF)
480 error_exit(1, false, "write error");
483 fclose(libfp);
484 fclose(tmpfp);
485 break;
487 default:
488 error_exit(2, false, "invalid command '%c'\n", c);
491 return 0;