Document case-insensitivity bug.
[nasm.git] / rdoff / rdlar.c
blob4728b57b536b9300634faa9b65e584ca58963f9b
1 /*
2 * rdlar.c - new librarian/archiver for RDOFF2.
3 * Copyright (c) 2002 RET & COM Research.
4 */
6 #include "compiler.h"
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <ctype.h>
11 #include <stdarg.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <time.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
18 #include "rdlar.h"
20 #define PROGRAM_VERSION "0.1"
22 /** Constants **/
23 const char commands[] = "adnrtx";
24 const char modifiers[] = "cflouvV";
26 /** Global variables **/
27 char *progname = "rdlar";
28 char **_argv = NULL;
29 struct {
30 bool createok;
31 bool usefname;
32 bool align;
33 bool odate;
34 bool fresh;
35 int verbose;
36 } options = {
37 0, 0, 0, 0, 0, 0};
39 #define _ENDIANNESS 0 /* 0 for little, 1 for big */
42 * Convert int32_t to little endian (if we were compiled on big-endian machine)
44 static void int32_ttolocal(int32_t *l)
46 #if _ENDIANNESS
47 uint8_t t;
48 uint8_t *p = (uint8_t *)l;
50 t = p[0];
51 p[0] = p[3];
52 p[3] = t;
53 t = p[1];
54 p[1] = p[2];
55 p[2] = p[1];
56 #endif
60 * Print version information
62 void show_version(void)
64 puts("New RDOFF2 librarian/archiver, version " PROGRAM_VERSION "\n"
65 "Copyright (c) 2002 RET & COM Research.\n"
66 "This program is free software and distributed under GPL (version 2 or later);\n"
67 "see http://www.gnu.org/copyleft/gpl.html for details.");
71 * Print usage instructions
73 void usage(void)
75 printf("Usage: %s [-]{%s}[%s] libfile [module-name] [files]\n",
76 progname, commands, modifiers);
77 puts(" commands:\n"
78 " a - add module(s) to the library\n"
79 " d - delete module(s) from the library\n"
80 " n - create the library\n"
81 " r - replace module(s)\n"
82 " t - display contents of library\n"
83 " x - extract module(s)\n"
84 " command specific modifiers:\n"
85 " o - preserve original dates\n"
86 " u - only replace modules that are newer than library contents\n"
87 " generic modifiers:\n"
88 " c - do not warn if the library had to be created\n"
89 " f - use file name as a module name\n"
90 " v - be verbose\n"
91 " V - display version information");
95 * Print an error message and exit
97 void error_exit(int errcode, bool useperror, const char *fmt, ...)
99 va_list ap;
101 fprintf(stderr, "%s: ", progname);
102 va_start(ap, fmt);
103 vfprintf(stderr, fmt, ap);
104 va_end(ap);
105 putc('\n', stderr);
106 if (useperror)
107 perror(progname);
108 exit(errcode);
112 * Fill in and write a header
114 void put_header(struct rdlm_hdr *hdr, FILE * libfp, char *modname)
116 int n = 0;
118 hdr->hdrsize = sizeof(*hdr);
119 if (modname)
120 hdr->hdrsize += (n = strlen(modname) + 1);
121 if (libfp == NULL)
122 return;
123 if (fwrite(hdr, 1, sizeof(*hdr), libfp) != sizeof(*hdr) ||
124 (modname && (fwrite(modname, 1, n, libfp) != n)))
125 error_exit(3, true, "could not write header");
129 * Copy n bytes from one file to another and return last character read.
131 char copybytes(FILE * fp, FILE * fp2, int n)
133 int i, t = 0;
135 for (i = 0; i < n; i++) {
136 t = fgetc(fp);
137 if (t == EOF)
138 error_exit(1, false, "premature end of file in '%s'",
139 _argv[2]);
140 if (fp2)
141 if (fputc(t, fp2) == EOF)
142 error_exit(1, false, "write error");
144 return (char)t;
148 * Copy uint32_t from one file to another.
149 * Return local presentation of int32_t.
151 int32_t copyint32_t(FILE * fp, FILE * fp2)
153 int32_t l;
154 int i, t;
155 uint8_t *p = (uint8_t *)&l;
157 for (i = 0; i < 4; i++) {
158 t = fgetc(fp);
159 if (t == EOF)
160 error_exit(1, false, "premature end of file in '%s'",
161 _argv[2]);
162 if (fp2)
163 if (fputc(t, fp2) == EOF)
164 error_exit(1, false, "write error");
165 *p++ = t;
167 int32_ttolocal(&l);
168 return l;
172 * Create a new library
174 int create_library(char *libname)
176 FILE *libfp;
177 struct rdlm_hdr hdr;
179 hdr.magic = RDLAMAG;
180 hdr.hdrsize = 0;
181 hdr.date = time(NULL);
182 hdr.owner = getuid();
183 hdr.group = getgid();
184 hdr.mode = umask(022);
185 hdr.size = 0;
187 libfp = fopen(libname, "wb");
188 if (!libfp)
189 error_exit(1, true, "could not open '%s'\n", libname);
191 /* Write library header */
192 put_header(&hdr, libfp, NULL);
194 fclose(libfp);
195 return true;
199 * Add a module to the library
201 int add_module(FILE * libfp, const char *fname, char *modname)
203 FILE *modfp;
204 struct rdlm_hdr hdr = { RDLMMAG, 0, 0, 0, 0, 0, 0 };
205 struct stat finfo;
206 int i;
208 if (options.verbose)
209 fprintf(stderr, "adding module %s\n", modname);
211 /* Initialize some fields in the module header */
212 if (stat(fname, &finfo) < 0)
213 error_exit(1, true, "could not stat '%s'", fname);
214 hdr.date = finfo.st_mtime;
215 hdr.owner = finfo.st_uid;
216 hdr.group = finfo.st_gid;
217 hdr.size = finfo.st_size;
219 modfp = fopen(fname, "rb");
220 if (!modfp)
221 error_exit(1, true, "could not open '%s'", fname);
223 /* Write module header */
224 put_header(&hdr, libfp, modname);
226 /* Put the module itself */
227 while (!feof(modfp)) {
228 i = fgetc(modfp);
229 if (i == EOF)
230 break;
231 if (fputc(i, libfp) == EOF)
232 error_exit(1, false, "write error");
235 fclose(modfp);
236 return true;
240 * Main
242 int main(int argc, char **argv)
244 FILE *libfp, *tmpfp, *modfp = NULL;
245 struct stat finfo;
246 struct rdlm_hdr hdr;
247 char buf[MAXMODNAMELEN], *p = NULL;
248 char c;
249 int i;
251 progname = argv[0];
252 _argv = argv;
254 if (argc < 2) {
255 usage();
256 exit(1);
259 /* Check whether some modifiers were specified */
260 for (i = 1; i < strlen(argv[1]); i++) {
261 switch (c = argv[1][i]) {
262 case 'c':
263 options.createok = true;
264 break;
265 case 'f':
266 options.usefname = true;
267 break;
268 case 'l':
269 options.align = true;
270 break;
271 case 'o':
272 options.odate = true;
273 break;
274 case 'u':
275 options.fresh = true;
276 break;
277 case 'v':
278 options.verbose++;
279 break;
280 case 'V':
281 show_version();
282 exit(0);
283 default:
284 if (strchr(commands, c) == NULL)
285 error_exit(2, false, "invalid command or modifier '%c'",
290 if (argc < 3)
291 error_exit(2, false, "missing library name");
293 /* Process the command */
294 if (argv[1][0] == '-')
295 argv[1]++;
296 switch (c = argv[1][0]) {
297 case 'a': /* add a module */
298 if (argc < 4 || (!options.usefname && argc != 5))
299 error_exit(2, false, "invalid number of arguments");
301 /* Check if a library already exists. If not - create it */
302 if (access(argv[2], F_OK) < 0) {
303 if (!options.createok)
304 fprintf(stderr, "creating library %s\n", argv[2]);
305 create_library(argv[2]);
308 libfp = fopen(argv[2], "ab");
309 if (!libfp)
310 error_exit(1, true, "could not open '%s'", argv[2]);
312 if (!options.usefname)
313 add_module(libfp, argv[4], argv[3]);
314 else
315 for (i = 3; i < argc; i++)
316 add_module(libfp, argv[i], argv[i]);
318 fclose(libfp);
319 break;
321 case 'n': /* create library */
322 create_library(argv[2]);
323 break;
325 case 'x': /* extract module(s) */
326 if (!options.usefname)
327 argc--;
328 if (argc < 4)
329 error_exit(2, false, "required parameter missing");
330 p = options.usefname ? argv[3] : argv[4];
331 case 't': /* list library contents */
332 libfp = fopen(argv[2], "rb");
333 if (!libfp)
334 error_exit(1, true, "could not open '%s'\n", argv[2]);
336 /* Read library header */
337 if (fread(&hdr, 1, sizeof(hdr), libfp) != sizeof(hdr) ||
338 hdr.magic != RDLAMAG)
339 error_exit(1, false, "invalid library format");
341 /* Walk through the library looking for requested module */
342 while (!feof(libfp)) {
343 /* Read module header */
344 i = fread(&hdr, 1, sizeof(hdr), libfp);
345 if (feof(libfp))
346 break;
347 if (i != sizeof(hdr) || hdr.magic != RDLMMAG)
348 error_exit(1, false, "invalid module header");
349 /* Read module name */
350 i = hdr.hdrsize - sizeof(hdr);
351 if (i > sizeof(buf) || fread(buf, 1, i, libfp) != i)
352 error_exit(1, false, "invalid module name");
353 if (c == 'x') {
354 /* Check against desired name */
355 if (!strcmp(buf, argv[3])) {
356 if (options.verbose)
357 fprintf(stderr,
358 "extracting module %s to file %s\n", buf,
360 modfp = fopen(p, "wb");
361 if (!modfp)
362 error_exit(1, true, "could not open '%s'", p);
364 } else {
365 printf("%-40s ", buf);
366 if (options.verbose) {
367 printf("%ld bytes", hdr.size);
369 putchar('\n');
372 copybytes(libfp, modfp, hdr.size);
373 if (modfp)
374 break;
377 fclose(libfp);
378 if (modfp)
379 fclose(modfp);
380 else if (c == 'x')
381 error_exit(1, false, "module '%s' not found in '%s'",
382 argv[3], argv[2]);
383 break;
385 case 'r': /* replace module(s) */
386 argc--;
387 if (stat(argv[4], &finfo) < 0)
388 error_exit(1, true, "could not stat '%s'", argv[4]);
389 case 'd': /* delete module(s) */
390 if (argc < 4)
391 error_exit(2, false, "required parameter missing");
393 libfp = fopen(argv[2], "rb");
394 if (!libfp)
395 error_exit(1, true, "could not open '%s'", argv[2]);
397 /* Copy the library into a temporary file */
398 tmpfp = tmpfile();
399 if (!tmpfp)
400 error_exit(1, true, "could not open temporary file");
402 stat(argv[2], &finfo);
403 copybytes(libfp, tmpfp, finfo.st_size);
404 rewind(tmpfp);
405 freopen(argv[2], "wb", libfp);
407 /* Read library header and write it to a new file */
408 if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) ||
409 hdr.magic != RDLAMAG)
410 error_exit(1, false, "invalid library format");
411 put_header(&hdr, libfp, NULL);
413 /* Walk through the library looking for requested module */
414 while (!feof(tmpfp)) {
415 /* Read module header */
416 if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) ||
417 hdr.magic != RDLMMAG)
418 error_exit(1, false, "invalid module header");
419 /* Read module name */
420 i = hdr.hdrsize - sizeof(hdr);
421 if (i > sizeof(buf) || fread(buf, 1, i, tmpfp) != i)
422 error_exit(1, false, "invalid module name");
423 /* Check against desired name */
424 if (!strcmp(buf, argv[3]) &&
425 (c == 'd' || !options.odate
426 || finfo.st_mtime <= hdr.date)) {
427 if (options.verbose)
428 fprintf(stderr, "deleting module %s\n", buf);
429 fseek(tmpfp, hdr.size, SEEK_CUR);
430 break;
431 } else {
432 put_header(&hdr, libfp, buf);
433 copybytes(tmpfp, libfp, hdr.size);
437 if (c == 'r') {
438 /* Copy new module into library */
439 p = options.usefname ? argv[4] : argv[3];
440 add_module(libfp, argv[4], p);
443 /* Copy rest of library if any */
444 while (!feof(tmpfp)) {
445 if ((i = fgetc(tmpfp)) == EOF)
446 break;
448 if (fputc(i, libfp) == EOF)
449 error_exit(1, false, "write error");
452 fclose(libfp);
453 fclose(tmpfp);
454 break;
456 default:
457 error_exit(2, false, "invalid command '%c'\n", c);
460 return 0;