mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-03-01 17:35:38 +08:00
Concentrate compiler dependencies to compiler.h; make sure compiler.h is included first in every .c file (since some prototypes may depend on the presence of feature request macros.) Actually use the conditional inclusion of various functions (totally broken in previous releases.)
465 lines
12 KiB
C
465 lines
12 KiB
C
/*
|
|
* rdlar.c - new librarian/archiver for RDOFF2.
|
|
* Copyright (c) 2002 RET & COM Research.
|
|
*/
|
|
|
|
#include "compiler.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "rdlar.h"
|
|
|
|
#define PROGRAM_VERSION "0.1"
|
|
|
|
/** Types **/
|
|
typedef enum { FALSE, TRUE } bool;
|
|
|
|
/** Constants **/
|
|
const char commands[] = "adnrtx";
|
|
const char modifiers[] = "cflouvV";
|
|
|
|
/** Global variables **/
|
|
char *progname = "rdlar";
|
|
char **_argv = NULL;
|
|
struct {
|
|
bool createok;
|
|
bool usefname;
|
|
bool align;
|
|
bool odate;
|
|
bool fresh;
|
|
int verbose;
|
|
} options = {
|
|
0, 0, 0, 0, 0, 0};
|
|
|
|
#define _ENDIANNESS 0 /* 0 for little, 1 for big */
|
|
|
|
/*
|
|
* Convert int32_t to little endian (if we were compiled on big-endian machine)
|
|
*/
|
|
static void int32_ttolocal(int32_t *l)
|
|
{
|
|
#if _ENDIANNESS
|
|
uint8_t t;
|
|
uint8_t *p = (uint8_t *)l;
|
|
|
|
t = p[0];
|
|
p[0] = p[3];
|
|
p[3] = t;
|
|
t = p[1];
|
|
p[1] = p[2];
|
|
p[2] = p[1];
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Print version information
|
|
*/
|
|
void show_version(void)
|
|
{
|
|
puts("New RDOFF2 librarian/archiver, version " PROGRAM_VERSION "\n"
|
|
"Copyright (c) 2002 RET & COM Research.\n"
|
|
"This program is free software and distributed under GPL (version 2 or later);\n"
|
|
"see http://www.gnu.org/copyleft/gpl.html for details.");
|
|
}
|
|
|
|
/*
|
|
* Print usage instructions
|
|
*/
|
|
void usage(void)
|
|
{
|
|
printf("Usage: %s [-]{%s}[%s] libfile [module-name] [files]\n",
|
|
progname, commands, modifiers);
|
|
puts(" commands:\n"
|
|
" a - add module(s) to the library\n"
|
|
" d - delete module(s) from the library\n"
|
|
" n - create the library\n"
|
|
" r - replace module(s)\n"
|
|
" t - display contents of library\n"
|
|
" x - extract module(s)\n"
|
|
" command specific modifiers:\n"
|
|
" o - preserve original dates\n"
|
|
" u - only replace modules that are newer than library contents\n"
|
|
" generic modifiers:\n"
|
|
" c - do not warn if the library had to be created\n"
|
|
" f - use file name as a module name\n"
|
|
" v - be verbose\n"
|
|
" V - display version information");
|
|
}
|
|
|
|
/*
|
|
* Print an error message and exit
|
|
*/
|
|
void error_exit(int errcode, bool useperror, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
fprintf(stderr, "%s: ", progname);
|
|
va_start(ap, fmt);
|
|
vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
putc('\n', stderr);
|
|
if (useperror)
|
|
perror(progname);
|
|
exit(errcode);
|
|
}
|
|
|
|
/*
|
|
* Fill in and write a header
|
|
*/
|
|
void put_header(struct rdlm_hdr *hdr, FILE * libfp, char *modname)
|
|
{
|
|
int n = 0;
|
|
|
|
hdr->hdrsize = sizeof(*hdr);
|
|
if (modname)
|
|
hdr->hdrsize += (n = strlen(modname) + 1);
|
|
if (libfp == NULL)
|
|
return;
|
|
if (fwrite(hdr, 1, sizeof(*hdr), libfp) != sizeof(*hdr) ||
|
|
(modname && (fwrite(modname, 1, n, libfp) != n)))
|
|
error_exit(3, TRUE, "could not write header");
|
|
}
|
|
|
|
/*
|
|
* Copy n bytes from one file to another and return last character read.
|
|
*/
|
|
char copybytes(FILE * fp, FILE * fp2, int n)
|
|
{
|
|
int i, t = 0;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
t = fgetc(fp);
|
|
if (t == EOF)
|
|
error_exit(1, FALSE, "premature end of file in '%s'",
|
|
_argv[2]);
|
|
if (fp2)
|
|
if (fputc(t, fp2) == EOF)
|
|
error_exit(1, FALSE, "write error");
|
|
}
|
|
return (char)t;
|
|
}
|
|
|
|
/*
|
|
* Copy uint32_t from one file to another.
|
|
* Return local presentation of int32_t.
|
|
*/
|
|
int32_t copyint32_t(FILE * fp, FILE * fp2)
|
|
{
|
|
int32_t l;
|
|
int i, t;
|
|
uint8_t *p = (uint8_t *)&l;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
t = fgetc(fp);
|
|
if (t == EOF)
|
|
error_exit(1, FALSE, "premature end of file in '%s'",
|
|
_argv[2]);
|
|
if (fp2)
|
|
if (fputc(t, fp2) == EOF)
|
|
error_exit(1, FALSE, "write error");
|
|
*p++ = t;
|
|
}
|
|
int32_ttolocal(&l);
|
|
return l;
|
|
}
|
|
|
|
/*
|
|
* Create a new library
|
|
*/
|
|
int create_library(char *libname)
|
|
{
|
|
FILE *libfp;
|
|
struct rdlm_hdr hdr;
|
|
|
|
hdr.magic = RDLAMAG;
|
|
hdr.hdrsize = 0;
|
|
hdr.date = time(NULL);
|
|
hdr.owner = getuid();
|
|
hdr.group = getgid();
|
|
hdr.mode = umask(022);
|
|
hdr.size = 0;
|
|
|
|
libfp = fopen(libname, "wb");
|
|
if (!libfp)
|
|
error_exit(1, TRUE, "could not open '%s'\n", libname);
|
|
|
|
/* Write library header */
|
|
put_header(&hdr, libfp, NULL);
|
|
|
|
fclose(libfp);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Add a module to the library
|
|
*/
|
|
int add_module(FILE * libfp, const char *fname, char *modname)
|
|
{
|
|
FILE *modfp;
|
|
struct rdlm_hdr hdr = { RDLMMAG, 0, 0, 0, 0, 0, 0 };
|
|
struct stat finfo;
|
|
int i;
|
|
|
|
if (options.verbose)
|
|
fprintf(stderr, "adding module %s\n", modname);
|
|
|
|
/* Initialize some fields in the module header */
|
|
if (stat(fname, &finfo) < 0)
|
|
error_exit(1, TRUE, "could not stat '%s'", fname);
|
|
hdr.date = finfo.st_mtime;
|
|
hdr.owner = finfo.st_uid;
|
|
hdr.group = finfo.st_gid;
|
|
hdr.size = finfo.st_size;
|
|
|
|
modfp = fopen(fname, "rb");
|
|
if (!modfp)
|
|
error_exit(1, TRUE, "could not open '%s'", fname);
|
|
|
|
/* Write module header */
|
|
put_header(&hdr, libfp, modname);
|
|
|
|
/* Put the module itself */
|
|
while (!feof(modfp)) {
|
|
i = fgetc(modfp);
|
|
if (i == EOF)
|
|
break;
|
|
if (fputc(i, libfp) == EOF)
|
|
error_exit(1, FALSE, "write error");
|
|
}
|
|
|
|
fclose(modfp);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Main
|
|
*/
|
|
int main(int argc, char **argv)
|
|
{
|
|
FILE *libfp, *tmpfp, *modfp = NULL;
|
|
struct stat finfo;
|
|
struct rdlm_hdr hdr;
|
|
char buf[MAXMODNAMELEN], *p = NULL;
|
|
char c;
|
|
int i;
|
|
|
|
progname = argv[0];
|
|
_argv = argv;
|
|
|
|
if (argc < 2) {
|
|
usage();
|
|
exit(1);
|
|
}
|
|
|
|
/* Check whether some modifiers were specified */
|
|
for (i = 1; i < strlen(argv[1]); i++) {
|
|
switch (c = argv[1][i]) {
|
|
case 'c':
|
|
options.createok = TRUE;
|
|
break;
|
|
case 'f':
|
|
options.usefname = TRUE;
|
|
break;
|
|
case 'l':
|
|
options.align = TRUE;
|
|
break;
|
|
case 'o':
|
|
options.odate = TRUE;
|
|
break;
|
|
case 'u':
|
|
options.fresh = TRUE;
|
|
break;
|
|
case 'v':
|
|
options.verbose++;
|
|
break;
|
|
case 'V':
|
|
show_version();
|
|
exit(0);
|
|
default:
|
|
if (strchr(commands, c) == NULL)
|
|
error_exit(2, FALSE, "invalid command or modifier '%c'",
|
|
c);
|
|
}
|
|
}
|
|
|
|
if (argc < 3)
|
|
error_exit(2, FALSE, "missing library name");
|
|
|
|
/* Process the command */
|
|
if (argv[1][0] == '-')
|
|
argv[1]++;
|
|
switch (c = argv[1][0]) {
|
|
case 'a': /* add a module */
|
|
if (argc < 4 || (!options.usefname && argc != 5))
|
|
error_exit(2, FALSE, "invalid number of arguments");
|
|
|
|
/* Check if a library already exists. If not - create it */
|
|
if (access(argv[2], F_OK) < 0) {
|
|
if (!options.createok)
|
|
fprintf(stderr, "creating library %s\n", argv[2]);
|
|
create_library(argv[2]);
|
|
}
|
|
|
|
libfp = fopen(argv[2], "ab");
|
|
if (!libfp)
|
|
error_exit(1, TRUE, "could not open '%s'", argv[2]);
|
|
|
|
if (!options.usefname)
|
|
add_module(libfp, argv[4], argv[3]);
|
|
else
|
|
for (i = 3; i < argc; i++)
|
|
add_module(libfp, argv[i], argv[i]);
|
|
|
|
fclose(libfp);
|
|
break;
|
|
|
|
case 'n': /* create library */
|
|
create_library(argv[2]);
|
|
break;
|
|
|
|
case 'x': /* extract module(s) */
|
|
if (!options.usefname)
|
|
argc--;
|
|
if (argc < 4)
|
|
error_exit(2, FALSE, "required parameter missing");
|
|
p = options.usefname ? argv[3] : argv[4];
|
|
case 't': /* list library contents */
|
|
libfp = fopen(argv[2], "rb");
|
|
if (!libfp)
|
|
error_exit(1, TRUE, "could not open '%s'\n", argv[2]);
|
|
|
|
/* Read library header */
|
|
if (fread(&hdr, 1, sizeof(hdr), libfp) != sizeof(hdr) ||
|
|
hdr.magic != RDLAMAG)
|
|
error_exit(1, FALSE, "invalid library format");
|
|
|
|
/* Walk through the library looking for requested module */
|
|
while (!feof(libfp)) {
|
|
/* Read module header */
|
|
i = fread(&hdr, 1, sizeof(hdr), libfp);
|
|
if (feof(libfp))
|
|
break;
|
|
if (i != sizeof(hdr) || hdr.magic != RDLMMAG)
|
|
error_exit(1, FALSE, "invalid module header");
|
|
/* Read module name */
|
|
i = hdr.hdrsize - sizeof(hdr);
|
|
if (i > sizeof(buf) || fread(buf, 1, i, libfp) != i)
|
|
error_exit(1, FALSE, "invalid module name");
|
|
if (c == 'x') {
|
|
/* Check against desired name */
|
|
if (!strcmp(buf, argv[3])) {
|
|
if (options.verbose)
|
|
fprintf(stderr,
|
|
"extracting module %s to file %s\n", buf,
|
|
p);
|
|
modfp = fopen(p, "wb");
|
|
if (!modfp)
|
|
error_exit(1, TRUE, "could not open '%s'", p);
|
|
}
|
|
} else {
|
|
printf("%-40s ", buf);
|
|
if (options.verbose) {
|
|
printf("%ld bytes", hdr.size);
|
|
}
|
|
putchar('\n');
|
|
}
|
|
|
|
copybytes(libfp, modfp, hdr.size);
|
|
if (modfp)
|
|
break;
|
|
}
|
|
|
|
fclose(libfp);
|
|
if (modfp)
|
|
fclose(modfp);
|
|
else if (c == 'x')
|
|
error_exit(1, FALSE, "module '%s' not found in '%s'",
|
|
argv[3], argv[2]);
|
|
break;
|
|
|
|
case 'r': /* replace module(s) */
|
|
argc--;
|
|
if (stat(argv[4], &finfo) < 0)
|
|
error_exit(1, TRUE, "could not stat '%s'", argv[4]);
|
|
case 'd': /* delete module(s) */
|
|
if (argc < 4)
|
|
error_exit(2, FALSE, "required parameter missing");
|
|
|
|
libfp = fopen(argv[2], "rb");
|
|
if (!libfp)
|
|
error_exit(1, TRUE, "could not open '%s'", argv[2]);
|
|
|
|
/* Copy the library into a temporary file */
|
|
tmpfp = tmpfile();
|
|
if (!tmpfp)
|
|
error_exit(1, TRUE, "could not open temporary file");
|
|
|
|
stat(argv[2], &finfo);
|
|
copybytes(libfp, tmpfp, finfo.st_size);
|
|
rewind(tmpfp);
|
|
freopen(argv[2], "wb", libfp);
|
|
|
|
/* Read library header and write it to a new file */
|
|
if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) ||
|
|
hdr.magic != RDLAMAG)
|
|
error_exit(1, FALSE, "invalid library format");
|
|
put_header(&hdr, libfp, NULL);
|
|
|
|
/* Walk through the library looking for requested module */
|
|
while (!feof(tmpfp)) {
|
|
/* Read module header */
|
|
if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) ||
|
|
hdr.magic != RDLMMAG)
|
|
error_exit(1, FALSE, "invalid module header");
|
|
/* Read module name */
|
|
i = hdr.hdrsize - sizeof(hdr);
|
|
if (i > sizeof(buf) || fread(buf, 1, i, tmpfp) != i)
|
|
error_exit(1, FALSE, "invalid module name");
|
|
/* Check against desired name */
|
|
if (!strcmp(buf, argv[3]) &&
|
|
(c == 'd' || !options.odate
|
|
|| finfo.st_mtime <= hdr.date)) {
|
|
if (options.verbose)
|
|
fprintf(stderr, "deleting module %s\n", buf);
|
|
fseek(tmpfp, hdr.size, SEEK_CUR);
|
|
break;
|
|
} else {
|
|
put_header(&hdr, libfp, buf);
|
|
copybytes(tmpfp, libfp, hdr.size);
|
|
}
|
|
}
|
|
|
|
if (c == 'r') {
|
|
/* Copy new module into library */
|
|
p = options.usefname ? argv[4] : argv[3];
|
|
add_module(libfp, argv[4], p);
|
|
}
|
|
|
|
/* Copy rest of library if any */
|
|
while (!feof(tmpfp)) {
|
|
if ((i = fgetc(tmpfp)) == EOF)
|
|
break;
|
|
|
|
if (fputc(i, libfp) == EOF)
|
|
error_exit(1, FALSE, "write error");
|
|
}
|
|
|
|
fclose(libfp);
|
|
fclose(tmpfp);
|
|
break;
|
|
|
|
default:
|
|
error_exit(2, FALSE, "invalid command '%c'\n", c);
|
|
}
|
|
|
|
return 0;
|
|
}
|