doc: Describe changes
[nasm.git] / rdoff / rdlar.c
blob98b0f8f6c5c9b19c19e0819afd0f2748a44fec7e
1 /* ----------------------------------------------------------------------- *
2 *
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 /* Check whether some modifiers were specified */
289 for (i = 1; i < strlen(argv[1]); i++) {
290 switch (c = argv[1][i]) {
291 case 'c':
292 options.createok = true;
293 break;
294 case 'f':
295 options.usefname = true;
296 break;
297 case 'l':
298 options.align = true;
299 break;
300 case 'o':
301 options.odate = true;
302 break;
303 case 'u':
304 options.fresh = true;
305 break;
306 case 'v':
307 options.verbose++;
308 break;
309 case 'V':
310 show_version();
311 exit(0);
312 default:
313 if (strchr(commands, c) == NULL)
314 error_exit(2, false, "invalid command or modifier '%c'",
319 if (argc < 3)
320 error_exit(2, false, "missing library name");
322 /* Process the command */
323 if (argv[1][0] == '-')
324 argv[1]++;
325 switch (c = argv[1][0]) {
326 case 'a': /* add a module */
327 if (argc < 4 || (!options.usefname && argc != 5))
328 error_exit(2, false, "invalid number of arguments");
330 /* Check if a library already exists. If not - create it */
331 if (access(argv[2], F_OK) < 0) {
332 if (!options.createok)
333 fprintf(stderr, "creating library %s\n", argv[2]);
334 create_library(argv[2]);
337 libfp = fopen(argv[2], "ab");
338 if (!libfp)
339 error_exit(1, true, "could not open '%s'", argv[2]);
341 if (!options.usefname)
342 add_module(libfp, argv[4], argv[3]);
343 else
344 for (i = 3; i < argc; i++)
345 add_module(libfp, argv[i], argv[i]);
347 fclose(libfp);
348 break;
350 case 'n': /* create library */
351 create_library(argv[2]);
352 break;
354 case 'x': /* extract module(s) */
355 if (!options.usefname)
356 argc--;
357 if (argc < 4)
358 error_exit(2, false, "required parameter missing");
359 p = options.usefname ? argv[3] : argv[4];
360 case 't': /* list library contents */
361 libfp = fopen(argv[2], "rb");
362 if (!libfp)
363 error_exit(1, true, "could not open '%s'\n", argv[2]);
365 /* Read library header */
366 if (fread(&hdr, 1, sizeof(hdr), libfp) != sizeof(hdr) ||
367 hdr.magic != RDLAMAG)
368 error_exit(1, false, "invalid library format");
370 /* Walk through the library looking for requested module */
371 while (!feof(libfp)) {
372 /* Read module header */
373 i = fread(&hdr, 1, sizeof(hdr), libfp);
374 if (feof(libfp))
375 break;
376 if (i != sizeof(hdr) || hdr.magic != RDLMMAG)
377 error_exit(1, false, "invalid module header");
378 /* Read module name */
379 i = hdr.hdrsize - sizeof(hdr);
380 if (i > sizeof(buf) || fread(buf, 1, i, libfp) != i)
381 error_exit(1, false, "invalid module name");
382 if (c == 'x') {
383 /* Check against desired name */
384 if (!strcmp(buf, argv[3])) {
385 if (options.verbose)
386 fprintf(stderr,
387 "extracting module %s to file %s\n", buf,
389 modfp = fopen(p, "wb");
390 if (!modfp)
391 error_exit(1, true, "could not open '%s'", p);
393 } else {
394 printf("%-40s ", buf);
395 if (options.verbose) {
396 printf("%ld bytes", hdr.size);
398 putchar('\n');
401 copybytes(libfp, modfp, hdr.size);
402 if (modfp)
403 break;
406 fclose(libfp);
407 if (modfp)
408 fclose(modfp);
409 else if (c == 'x')
410 error_exit(1, false, "module '%s' not found in '%s'",
411 argv[3], argv[2]);
412 break;
414 case 'r': /* replace module(s) */
415 argc--;
416 if (stat(argv[4], &finfo) < 0)
417 error_exit(1, true, "could not stat '%s'", argv[4]);
418 case 'd': /* delete module(s) */
419 if (argc < 4)
420 error_exit(2, false, "required parameter missing");
422 libfp = fopen(argv[2], "rb");
423 if (!libfp)
424 error_exit(1, true, "could not open '%s'", argv[2]);
426 /* Copy the library into a temporary file */
427 tmpfp = tmpfile();
428 if (!tmpfp)
429 error_exit(1, true, "could not open temporary file");
431 stat(argv[2], &finfo);
432 copybytes(libfp, tmpfp, finfo.st_size);
433 rewind(tmpfp);
434 freopen(argv[2], "wb", libfp);
436 /* Read library header and write it to a new file */
437 if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) ||
438 hdr.magic != RDLAMAG)
439 error_exit(1, false, "invalid library format");
440 put_header(&hdr, libfp, NULL);
442 /* Walk through the library looking for requested module */
443 while (!feof(tmpfp)) {
444 /* Read module header */
445 if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) ||
446 hdr.magic != RDLMMAG)
447 error_exit(1, false, "invalid module header");
448 /* Read module name */
449 i = hdr.hdrsize - sizeof(hdr);
450 if (i > sizeof(buf) || fread(buf, 1, i, tmpfp) != i)
451 error_exit(1, false, "invalid module name");
452 /* Check against desired name */
453 if (!strcmp(buf, argv[3]) &&
454 (c == 'd' || !options.odate
455 || finfo.st_mtime <= hdr.date)) {
456 if (options.verbose)
457 fprintf(stderr, "deleting module %s\n", buf);
458 fseek(tmpfp, hdr.size, SEEK_CUR);
459 break;
460 } else {
461 put_header(&hdr, libfp, buf);
462 copybytes(tmpfp, libfp, hdr.size);
466 if (c == 'r') {
467 /* Copy new module into library */
468 p = options.usefname ? argv[4] : argv[3];
469 add_module(libfp, argv[4], p);
472 /* Copy rest of library if any */
473 while (!feof(tmpfp)) {
474 if ((i = fgetc(tmpfp)) == EOF)
475 break;
477 if (fputc(i, libfp) == EOF)
478 error_exit(1, false, "write error");
481 fclose(libfp);
482 fclose(tmpfp);
483 break;
485 default:
486 error_exit(2, false, "invalid command '%c'\n", c);
489 return 0;