nasm.nsi: use LZMA compression
[nasm.git] / rdoff / rdlar.c
blobc63ad3a80f5a9623e6e084748e4b51c75ea3a1a5
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 "\n"
97 "Copyright (c) 2002 RET & COM Research.\n"
98 "This program is free software and distributed under GPL (version 2 or later);\n"
99 "see http://www.gnu.org/copyleft/gpl.html for details.");
103 * Print usage instructions
105 void usage(void)
107 printf("Usage: %s [-]{%s}[%s] libfile [module-name] [files]\n",
108 progname, commands, modifiers);
109 puts(" commands:\n"
110 " a - add module(s) to the library\n"
111 " d - delete module(s) from the library\n"
112 " n - create the library\n"
113 " r - replace module(s)\n"
114 " t - display contents of library\n"
115 " x - extract module(s)\n"
116 " command specific modifiers:\n"
117 " o - preserve original dates\n"
118 " u - only replace modules that are newer than library contents\n"
119 " generic modifiers:\n"
120 " c - do not warn if the library had to be created\n"
121 " f - use file name as a module name\n"
122 " v - be verbose\n"
123 " V - display version information");
127 * Print an error message and exit
129 void error_exit(int errcode, bool useperror, const char *fmt, ...)
131 va_list ap;
133 fprintf(stderr, "%s: ", progname);
134 va_start(ap, fmt);
135 vfprintf(stderr, fmt, ap);
136 va_end(ap);
137 putc('\n', stderr);
138 if (useperror)
139 perror(progname);
140 exit(errcode);
144 * Fill in and write a header
146 void put_header(struct rdlm_hdr *hdr, FILE * libfp, char *modname)
148 int n = 0;
150 hdr->hdrsize = sizeof(*hdr);
151 if (modname)
152 hdr->hdrsize += (n = strlen(modname) + 1);
153 if (libfp == NULL)
154 return;
155 if (fwrite(hdr, 1, sizeof(*hdr), libfp) != sizeof(*hdr) ||
156 (modname && (fwrite(modname, 1, n, libfp) != n)))
157 error_exit(3, true, "could not write header");
161 * Copy n bytes from one file to another and return last character read.
163 char copybytes(FILE * fp, FILE * fp2, int n)
165 int i, t = 0;
167 for (i = 0; i < n; i++) {
168 t = fgetc(fp);
169 if (t == EOF)
170 error_exit(1, false, "premature end of file in '%s'",
171 _argv[2]);
172 if (fp2)
173 if (fputc(t, fp2) == EOF)
174 error_exit(1, false, "write error");
176 return (char)t;
180 * Copy uint32_t from one file to another.
181 * Return local presentation of int32_t.
183 int32_t copyint32_t(FILE * fp, FILE * fp2)
185 int32_t l;
186 int i, t;
187 uint8_t *p = (uint8_t *)&l;
189 for (i = 0; i < 4; i++) {
190 t = fgetc(fp);
191 if (t == EOF)
192 error_exit(1, false, "premature end of file in '%s'",
193 _argv[2]);
194 if (fp2)
195 if (fputc(t, fp2) == EOF)
196 error_exit(1, false, "write error");
197 *p++ = t;
199 int32_ttolocal(&l);
200 return l;
204 * Create a new library
206 int create_library(char *libname)
208 FILE *libfp;
209 struct rdlm_hdr hdr;
211 hdr.magic = RDLAMAG;
212 hdr.hdrsize = 0;
213 hdr.date = time(NULL);
214 hdr.owner = getuid();
215 hdr.group = getgid();
216 hdr.mode = umask(022);
217 hdr.size = 0;
219 libfp = fopen(libname, "wb");
220 if (!libfp)
221 error_exit(1, true, "could not open '%s'\n", libname);
223 /* Write library header */
224 put_header(&hdr, libfp, NULL);
226 fclose(libfp);
227 return true;
231 * Add a module to the library
233 int add_module(FILE * libfp, const char *fname, char *modname)
235 FILE *modfp;
236 struct rdlm_hdr hdr = { RDLMMAG, 0, 0, 0, 0, 0, 0 };
237 struct stat finfo;
238 int i;
240 if (options.verbose)
241 fprintf(stderr, "adding module %s\n", modname);
243 /* Initialize some fields in the module header */
244 if (stat(fname, &finfo) < 0)
245 error_exit(1, true, "could not stat '%s'", fname);
246 hdr.date = finfo.st_mtime;
247 hdr.owner = finfo.st_uid;
248 hdr.group = finfo.st_gid;
249 hdr.size = finfo.st_size;
251 modfp = fopen(fname, "rb");
252 if (!modfp)
253 error_exit(1, true, "could not open '%s'", fname);
255 /* Write module header */
256 put_header(&hdr, libfp, modname);
258 /* Put the module itself */
259 while (!feof(modfp)) {
260 i = fgetc(modfp);
261 if (i == EOF)
262 break;
263 if (fputc(i, libfp) == EOF)
264 error_exit(1, false, "write error");
267 fclose(modfp);
268 return true;
272 * Main
274 int main(int argc, char **argv)
276 FILE *libfp, *tmpfp, *modfp = NULL;
277 struct stat finfo;
278 struct rdlm_hdr hdr;
279 char buf[MAXMODNAMELEN], *p = NULL;
280 char c;
281 int i;
283 progname = argv[0];
284 _argv = argv;
286 if (argc < 2) {
287 usage();
288 exit(1);
291 /* Check whether some modifiers were specified */
292 for (i = 1; i < strlen(argv[1]); i++) {
293 switch (c = argv[1][i]) {
294 case 'c':
295 options.createok = true;
296 break;
297 case 'f':
298 options.usefname = true;
299 break;
300 case 'l':
301 options.align = true;
302 break;
303 case 'o':
304 options.odate = true;
305 break;
306 case 'u':
307 options.fresh = true;
308 break;
309 case 'v':
310 options.verbose++;
311 break;
312 case 'V':
313 show_version();
314 exit(0);
315 default:
316 if (strchr(commands, c) == NULL)
317 error_exit(2, false, "invalid command or modifier '%c'",
322 if (argc < 3)
323 error_exit(2, false, "missing library name");
325 /* Process the command */
326 if (argv[1][0] == '-')
327 argv[1]++;
328 switch (c = argv[1][0]) {
329 case 'a': /* add a module */
330 if (argc < 4 || (!options.usefname && argc != 5))
331 error_exit(2, false, "invalid number of arguments");
333 /* Check if a library already exists. If not - create it */
334 if (access(argv[2], F_OK) < 0) {
335 if (!options.createok)
336 fprintf(stderr, "creating library %s\n", argv[2]);
337 create_library(argv[2]);
340 libfp = fopen(argv[2], "ab");
341 if (!libfp)
342 error_exit(1, true, "could not open '%s'", argv[2]);
344 if (!options.usefname)
345 add_module(libfp, argv[4], argv[3]);
346 else
347 for (i = 3; i < argc; i++)
348 add_module(libfp, argv[i], argv[i]);
350 fclose(libfp);
351 break;
353 case 'n': /* create library */
354 create_library(argv[2]);
355 break;
357 case 'x': /* extract module(s) */
358 if (!options.usefname)
359 argc--;
360 if (argc < 4)
361 error_exit(2, false, "required parameter missing");
362 p = options.usefname ? argv[3] : argv[4];
363 case 't': /* list library contents */
364 libfp = fopen(argv[2], "rb");
365 if (!libfp)
366 error_exit(1, true, "could not open '%s'\n", argv[2]);
368 /* Read library header */
369 if (fread(&hdr, 1, sizeof(hdr), libfp) != sizeof(hdr) ||
370 hdr.magic != RDLAMAG)
371 error_exit(1, false, "invalid library format");
373 /* Walk through the library looking for requested module */
374 while (!feof(libfp)) {
375 /* Read module header */
376 i = fread(&hdr, 1, sizeof(hdr), libfp);
377 if (feof(libfp))
378 break;
379 if (i != sizeof(hdr) || hdr.magic != RDLMMAG)
380 error_exit(1, false, "invalid module header");
381 /* Read module name */
382 i = hdr.hdrsize - sizeof(hdr);
383 if (i > sizeof(buf) || fread(buf, 1, i, libfp) != i)
384 error_exit(1, false, "invalid module name");
385 if (c == 'x') {
386 /* Check against desired name */
387 if (!strcmp(buf, argv[3])) {
388 if (options.verbose)
389 fprintf(stderr,
390 "extracting module %s to file %s\n", buf,
392 modfp = fopen(p, "wb");
393 if (!modfp)
394 error_exit(1, true, "could not open '%s'", p);
396 } else {
397 printf("%-40s ", buf);
398 if (options.verbose) {
399 printf("%ld bytes", hdr.size);
401 putchar('\n');
404 copybytes(libfp, modfp, hdr.size);
405 if (modfp)
406 break;
409 fclose(libfp);
410 if (modfp)
411 fclose(modfp);
412 else if (c == 'x')
413 error_exit(1, false, "module '%s' not found in '%s'",
414 argv[3], argv[2]);
415 break;
417 case 'r': /* replace module(s) */
418 argc--;
419 if (stat(argv[4], &finfo) < 0)
420 error_exit(1, true, "could not stat '%s'", argv[4]);
421 case 'd': /* delete module(s) */
422 if (argc < 4)
423 error_exit(2, false, "required parameter missing");
425 libfp = fopen(argv[2], "rb");
426 if (!libfp)
427 error_exit(1, true, "could not open '%s'", argv[2]);
429 /* Copy the library into a temporary file */
430 tmpfp = tmpfile();
431 if (!tmpfp)
432 error_exit(1, true, "could not open temporary file");
434 stat(argv[2], &finfo);
435 copybytes(libfp, tmpfp, finfo.st_size);
436 rewind(tmpfp);
437 freopen(argv[2], "wb", libfp);
439 /* Read library header and write it to a new file */
440 if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) ||
441 hdr.magic != RDLAMAG)
442 error_exit(1, false, "invalid library format");
443 put_header(&hdr, libfp, NULL);
445 /* Walk through the library looking for requested module */
446 while (!feof(tmpfp)) {
447 /* Read module header */
448 if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) ||
449 hdr.magic != RDLMMAG)
450 error_exit(1, false, "invalid module header");
451 /* Read module name */
452 i = hdr.hdrsize - sizeof(hdr);
453 if (i > sizeof(buf) || fread(buf, 1, i, tmpfp) != i)
454 error_exit(1, false, "invalid module name");
455 /* Check against desired name */
456 if (!strcmp(buf, argv[3]) &&
457 (c == 'd' || !options.odate
458 || finfo.st_mtime <= hdr.date)) {
459 if (options.verbose)
460 fprintf(stderr, "deleting module %s\n", buf);
461 fseek(tmpfp, hdr.size, SEEK_CUR);
462 break;
463 } else {
464 put_header(&hdr, libfp, buf);
465 copybytes(tmpfp, libfp, hdr.size);
469 if (c == 'r') {
470 /* Copy new module into library */
471 p = options.usefname ? argv[4] : argv[3];
472 add_module(libfp, argv[4], p);
475 /* Copy rest of library if any */
476 while (!feof(tmpfp)) {
477 if ((i = fgetc(tmpfp)) == EOF)
478 break;
480 if (fputc(i, libfp) == EOF)
481 error_exit(1, false, "write error");
484 fclose(libfp);
485 fclose(tmpfp);
486 break;
488 default:
489 error_exit(2, false, "invalid command '%c'\n", c);
492 return 0;