scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

commit 9a0e9d213b244658a182d7c076d71059a8253f70
parent d56850a6e8abf570ec83aba1792b87dbde4dca07
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Tue,  8 Jan 2019 11:18:09 +0000

[ar] Move ar to cmd directory

Diffstat:
Msrc/Makefile | 2+-
Dsrc/ar/Makefile | 22----------------------
Dsrc/ar/deps.mk | 5-----
Dsrc/ar/main.c | 643-------------------------------------------------------------------------------
Dsrc/ar/posix/driver.c | 14--------------
Dsrc/cmd/.gitignore | 3---
Msrc/cmd/Makefile | 19++++++++++---------
Asrc/cmd/ar-posix.c | 14++++++++++++++
Asrc/cmd/ar.c | 642+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsrc/ar/posix/driver.h -> src/cmd/ar.h | 0
Msrc/cmd/deps.mk | 4++++
11 files changed, 671 insertions(+), 697 deletions(-)

diff --git a/src/Makefile b/src/Makefile @@ -3,7 +3,7 @@ PROJECTDIR = .. include $(PROJECTDIR)/scripts/rules.mk -TOOLS = cc1 cc2 ld as objdump ar cmd +TOOLS = cc1 cc2 ld as objdump cmd LIBS = libscc libc libcrt libmach DIRS = $(TOOLS) $(LIBS) diff --git a/src/ar/Makefile b/src/ar/Makefile @@ -1,22 +0,0 @@ -.POSIX: - -PROJECTDIR = ../.. -include $(PROJECTDIR)/scripts/rules.mk - -MORECFLAGS = -I$(DRIVER) - -OBJS = main.o \ - $(DRIVER)/driver.o \ - -TARGET = $(BINDIR)/ar - -all: $(TARGET) - -$(TARGET): $(LIBDIR)/libscc.a - -$(TARGET): $(OBJS) - $(CC) $(SCC_LDFLAGS) $(OBJS) -lscc -o $@ - -dep: inc-dep - -include deps.mk diff --git a/src/ar/deps.mk b/src/ar/deps.mk @@ -1,5 +0,0 @@ -#deps -main.o: $(INCDIR)/scc/scc/ar.h -main.o: $(INCDIR)/scc/scc/arg.h -main.o: $(INCDIR)/scc/scc/scc.h -posix/driver.o: posix/driver.h diff --git a/src/ar/main.c b/src/ar/main.c @@ -1,643 +0,0 @@ -static char sccsid[] = "@(#) ./ar/main.c"; - -#include <errno.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include <driver.h> - -#include <scc/ar.h> -#include <scc/arg.h> -#include <scc/scc.h> - -enum { - BEFORE, - INDOT, - AFTER, -}; - -struct tmp { - char *name; - FILE *fp; -} tmps[3]; - -char *argv0; - -static int bflag, vflag, cflag, lflag, uflag, aflag; -static char *arfile, *posname; - -struct member { - FILE *src; - struct ar_hdr hdr; - int cur; - char *fname; - long size; - long mode; - long long date; -}; - -static void -cleanup(void) -{ - int i; - - for (i = 0; i < 3; i++) { - if (tmps[i].name) - remove(tmps[i].name); - } -} - -/* - * I do know that you cannot call remove from a signal handler - * but we only can use stdio function to deal with files - * because we are C99 compliant, and it is very likely that - * remove is going to work in this case - */ -static void -sigfun(int signum) -{ - cleanup(); - _Exit(1); -} - -static FILE * -openar(void) -{ - FILE *fp; - char magic[SARMAG+1]; - - if ((fp = fopen(arfile,"r+b")) == NULL) { - if (!cflag) - fprintf(stderr, "ar: creating %s\n", arfile); - if ((fp = fopen(arfile, "w+b")) == NULL) { - perror("ar:opening archive"); - exit(1); - } - fputs(ARMAG, fp); - if (fflush(fp) == EOF) { - perror("ar:writing magic number"); - exit(1); - } - } else { - if (fgets(magic, sizeof(magic), fp) == NULL) { - perror("ar:error reading magic number"); - exit(1); - } - if (strcmp(magic, ARMAG)) { - fprintf(stderr, - "ar:%s:invalid magic number '%s'\n", - arfile, - magic); - exit(1); - } - } - return fp; -} - -static void -archive(char *fname, FILE *to, char letter) -{ - int c; - size_t n; - FILE *from; - char mtime[13]; - struct stat st; - - if (vflag) - printf("%c - %s\n", letter, fname); - if (strlen(fname) > 16) - fprintf(stderr, "ar:%s: too long name\n", fname); - if ((from = fopen(fname, "rb")) == NULL) { - fprintf(stderr, - "ar:opening member '%s':%s\n", - fname, - strerror(errno)); - exit(1); - } - if (stat(fname, &st) < 0) { - fprintf(stderr, "ar:error getting '%s' attributes\n", fname); - exit(1); - } - strftime(mtime, sizeof(mtime), "%s", gmtime(&st.st_mtime)); - fprintf(to, - "%-16.16s%-12s%-6u%-6u%-8o%-10llu`\n", - fname, - mtime, - st.st_uid, - st.st_gid, - st.st_mode, - (unsigned long long) st.st_size); - for (n = 0; (c = getc(from)) != EOF; n++) - putc(c, to); - if (n & 1) - putc('\n', to); - if (ferror(from)) { - fprintf(stderr, - "ar:reading input '%s':%s\n", - fname, strerror(errno)); - exit(1); - } - fclose(from); -} - -static void -append(FILE *fp, char *argv[]) -{ - char *fname; - - if (fseek(fp, 0, SEEK_END) == EOF) { - perror("ar:seeking archive"); - exit(1); - } - - for ( ; fname = *argv; ++argv) { - *argv = NULL; - archive(fname, fp, 'a'); - } - - if (fclose(fp) == EOF) { - perror("ar:error writing archive"); - exit(1); - } -} - -static void -copy(struct member *m, struct tmp *tmp) -{ - int c; - size_t siz = m->size; - struct ar_hdr *hdr = &m->hdr; - - fwrite(hdr, sizeof(*hdr), 1, tmp->fp); - if ((siz & 1) == 1) - siz++; - while (siz--) { - if ((c = getc(m->src)) == EOF) - break; - fputc(c, tmp->fp); - } -} - -static void -letters(unsigned long val, char *s) -{ - *s++ = (val & 04) ? 'r' : '-'; - *s++ = (val & 02) ? 'w' : '-'; - *s++ = (val & 01) ? 'x' : '-'; -} - -static char * -perms(struct member *m) -{ - static char buf[10]; - - letters(m->mode >> 6, buf); - letters(m->mode >> 3, buf+3); - letters(m->mode, buf +6); - buf[9] = '\0'; - - return buf; -} - -static int -inlist(char *fname, int argc, char *argv[]) -{ - for (; argc-- > 0; ++argv) { - if (*argv && !strcmp(*argv, fname)) { - *argv = NULL; - return 1; - } - } - return 0; -} - -static void -move(struct member *m, int argc, char *argv[]) -{ - int where; - - if (inlist(m->fname, argc, argv)) { - if (vflag) - printf("m - %s\n", m->fname); - where = INDOT; - } else if (posname && !strcmp(posname, m->fname)) { - where = (bflag) ? AFTER : BEFORE; - m->cur = AFTER; - } else { - where = m->cur; - } - copy(m, &tmps[where]); -} - -static void -insert(int argc, char *argv[]) -{ - for (; argc-- > 0; ++argv) { - if (*argv) { - archive(*argv, tmps[INDOT].fp, 'a'); - *argv = NULL; - } - } -} - -static void -update(struct member *m, int argc, char *argv[]) -{ - int where; - FILE *fp = tmps[BEFORE].fp; - - if (inlist(m->fname, argc, argv)) { - archive(m->fname, tmps[m->cur].fp, 'r'); - return; - } else if (posname && !strcmp(posname, m->fname)) { - where = (bflag) ? AFTER : BEFORE; - m->cur = AFTER; - } else { - where = m->cur; - } - copy(m, &tmps[where]); -} - -static void -extract(struct member *m, int argc, char *argv[]) -{ - int c; - long siz; - FILE *fp; - - if (argc > 0 && !inlist(m->fname, argc, argv)) - return; - if (vflag) - printf("x - %s\n", m->fname); - siz = m->size; - - if ((fp = fopen(m->fname, "wb")) == NULL) - goto error_file; - while (siz-- > 0 && (c = getc(m->src)) != EOF) - putc(c, fp); - fflush(fp); - if (fclose(fp) == EOF) - goto error_file; - - /* TODO: set attributes */ - return; - - -error_file: - perror("ar:error extracting file"); - exit(1); -} - -static void -print(struct member *m, int argc, char *argv[]) -{ - long siz; - int c; - - if (argc > 0 && !inlist(m->fname, argc, argv)) - return; - if (vflag) - printf("\n<%s>\n\n", m->fname); - siz = m->size; - while (siz-- > 0 && (c = getc(m->src)) != EOF) - putchar(c); -} - -static void -list(struct member *m, int argc, char *argv[]) -{ - time_t t; - struct ar_hdr *hdr = &m->hdr; - char mtime[30]; - - if (argc > 0 && !inlist(m->fname, argc, argv)) - return; - if (!vflag) { - printf("%s\n", m->fname); - } else { - t = totime(m->date); - strftime(mtime, sizeof(mtime), "%c", localtime(&t)); - printf("%s %ld/%ld\t%s %s\n", - perms(m), - atol(hdr->ar_uid), - atol(hdr->ar_gid), - mtime, - m->fname); - } -} - -static void -del(struct member *m, int argc, char *argv[]) -{ - if (inlist(m->fname, argc, argv)) { - if (vflag) - printf("d - %s\n", m->fname); - return; - } - copy(m, &tmps[BEFORE]); -} - -static char * -getfname(struct ar_hdr *hdr) -{ - static char fname[SARNAM+1]; - size_t i; - - memcpy(fname, hdr->ar_name, SARNAM); - fname[SARNAM] = '\0'; - - for (i = SARNAM-1; i >= 0; --i) { - if (fname[i] != ' ' && fname[i] != '/') - break; - fname[i] = '\0'; - } - return fname; -} - -static long long -getnum(char *s, int size, int base) -{ - int c; - long long val; - char *p; - static char digits[] = "0123456789"; - - for (val = 0; size > 0; val += c) { - --size; - if ((c = *s++) == ' ') - break; - if ((p = strchr(digits, c)) == NULL) - return -1; - if ((c = p - digits) >= base) - return -1; - val *= base; - } - - while (size > 0 && *s++ == ' ') - --size; - return (size == 0) ? val : -1; -} - -static int -valid(struct member *m) -{ - struct ar_hdr *hdr = &m->hdr; - - m->fname = getfname(&m->hdr); - m->size = getnum(hdr->ar_size, sizeof(hdr->ar_size), 10); - m->mode = getnum(hdr->ar_mode, sizeof(hdr->ar_mode), 8); - m->date = getnum(hdr->ar_date, sizeof(hdr->ar_date), 10); - - if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(hdr->ar_fmag)) || - m->size < 0 || m->mode < 0 || m->date < 0) { - return 0; - } - return 1; -} - -static void -run(FILE *fp, int argc, char *argv[], - void (*fun)(struct member *, int argc, char *files[])) -{ - struct member m; - - m.src = fp; - m.cur = BEFORE; - - while (fread(&m.hdr, sizeof(m.hdr), 1, fp) == 1) { - fpos_t pos; - - if (!valid(&m)) { - fprintf(stderr, - "ar:corrupted member '%s'\n", - m.fname); - exit(1); - } - fgetpos(fp, &pos); - (*fun)(&m, argc, argv); - fsetpos(fp, &pos); - fseek(fp, m.size+1 & ~1, SEEK_CUR); - } - if (ferror(fp) || fclose(fp) == EOF) { - perror("ar:reading members"); - exit(1); - } -} - -static void -merge(void) -{ - FILE *fp, *fi; - int c, i; - - - if ((fp = fopen(arfile, "wb")) == NULL) { - perror("ar:reopening archive"); - exit(1); - } - - fputs(ARMAG, fp); - - for (i = 0; i < 3; i++) { - if ((fi = tmps[i].fp) == NULL) - continue; - fseek(fi, 0, SEEK_SET); - while ((c = getc(fi)) != EOF) - putc(c, fp); - if (ferror(fi)) { - perror("ar:error in temporary"); - exit(1); - } - } - - if (fclose(fp) == EOF) { - perror("ar:writing archive file"); - exit(1); - } -} - -static void -closetmp(int which) -{ - struct tmp *tmp = &tmps[which]; - - if (!tmp->fp) - return; - if (fclose(tmp->fp) == EOF) { - perror("ar:closing temporaries"); - exit(1); - } -} - -static void -opentmp(char *fname, int which) -{ - struct tmp *tmp = &tmps[which]; - - if (lflag) { - tmp->name = fname; - tmp->fp = fopen(fname, "w+b"); - } else { - tmp->fp = tmpfile(); - } - - if (tmp->fp == NULL) { - perror("ar:creating temporary"); - exit(1); - } -} - -static void -doit(int key, char *argv[], int argc) -{ - FILE *fp; - - fp = openar(); - if (argc == 0 && - (key == 'r' || key == 'd' || key == 'm' || key == 'q')) { - if (fclose(fp) == EOF) { - perror("ar:early close of archive file"); - exit(-1); - } - return; - } - - if (key == 'r' || key == 'm' || key == 'd') - opentmp("ar.tmp1", BEFORE); - if (key == 'r' || key == 'm') { - opentmp("ar.tmp2", INDOT); - opentmp("ar.tmp3", AFTER); - } - - switch (key) { - case 'r': - run(fp, argc, argv, update); - insert(argc, argv); - merge(); - break; - case 'm': - run(fp, argc, argv, move); - merge(); - break; - case 'd': - run(fp, argc, argv, del); - merge(); - break; - case 't': - run(fp, argc, argv, list); - break; - case 'p': - run(fp, argc, argv, print); - break; - case 'x': - run(fp, argc, argv, extract); - break; - case 'q': - append(fp, argv); - break; - } - - closetmp(BEFORE); - closetmp(INDOT); - closetmp(AFTER); - - for ( ; argc-- > 0; ++argv) { - if (*argv) { - fprintf(stderr, "ar: No member named '%s'\n", *argv); - exit(1); - } - } -} - -static void -usage(void) -{ - fputs("ar [-drqtpmx][posname] [-vuaibcl] [posname] arfile name ...\n", - stderr); - exit(1); -} - -int -main(int argc, char *argv[]) -{ - int key, nkey = 0, pos = 0; - - atexit(cleanup); - ARGBEGIN { - case 'd': - nkey++; - key = 'd'; - break; - case 'r': - nkey++; - key = 'r'; - break; - case 'q': - nkey++; - key = 'q'; - break; - case 't': - nkey++; - key = 't'; - break; - case 'p': - nkey++; - key = 'p'; - break; - case 'm': - nkey++; - key = 'm'; - break; - case 'x': - nkey++; - key = 'x'; - break; - case 'a': - aflag = 1; - pos++; - posname = EARGF(usage()); - break; - case 'i': - case 'b': - bflag = 1; - pos++; - posname = EARGF(usage()); - break; - case 'v': - vflag = 1; - break; - case 'c': - cflag = 1; - break; - case 'l': - lflag = 1; - break; - case 'u': - /* TODO */ - abort(); - uflag = 1; - break; - default: - usage(); - } ARGEND - - if (nkey == 0 || nkey > 1 || pos > 1 || argc == 0) - usage(); - - signal(SIGINT, sigfun); - signal(SIGQUIT, sigfun); - signal(SIGTERM, sigfun); - - arfile = *argv; - doit(key, ++argv, --argc); - - if (fflush(stdout) == EOF) { - perror("ar:error writing to stdout"); - exit(1); - } - - return 0; -} diff --git a/src/ar/posix/driver.c b/src/ar/posix/driver.c @@ -1,14 +0,0 @@ -static char sccsid[] = "@(#) ./ar/posix/driver.c"; - -#include "driver.h" - -time_t -totime(long long t) -{ - return t; -} - -int -setattr() -{ -} diff --git a/src/cmd/.gitignore b/src/cmd/.gitignore @@ -1,3 +0,0 @@ -nm -strip -size diff --git a/src/cmd/Makefile b/src/cmd/Makefile @@ -6,24 +6,25 @@ include $(PROJECTDIR)/scripts/rules.mk TARGET = $(BINDIR)/nm \ $(BINDIR)/strip \ $(BINDIR)/size \ + $(BINDIR)/ar \ LIBS = -lmach all: $(TARGET) -nm strip: $(LIBDIR)/libmach.a +$(TARGET): $(LIBDIR)/libmach.a -$(BINDIR)/nm: nm - cp nm $@ +$(BINDIR)/nm: nm.o + $(CC) $(SCC_LDFLAGS) nm.o -lmach -o $@ -$(BINDIR)/strip: strip - cp strip $@ +$(BINDIR)/strip: strip.o + $(CC) $(SCC_LDFLAGS) strip.o -lmach -o $@ -$(BINDIR)/size: size - cp size $@ +$(BINDIR)/size: size.o + $(CC) $(SCC_LDFLAGS) size.o -lmach -o $@ -clean: - rm -f nm strip size +$(BINDIR)/ar: ar.o ar-$(DRIVER).o + $(CC) $(SCC_LDFLAGS) ar.o ar-$(DRIVER).o -o $@ dep: inc-dep diff --git a/src/cmd/ar-posix.c b/src/cmd/ar-posix.c @@ -0,0 +1,14 @@ +static char sccsid[] = "@(#) ./ar/posix/driver.c"; + +#include "ar.h" + +time_t +totime(long long t) +{ + return t; +} + +int +setattr() +{ +} diff --git a/src/cmd/ar.c b/src/cmd/ar.c @@ -0,0 +1,642 @@ +static char sccsid[] = "@(#) ./ar/main.c"; + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "ar.h" + +#include <scc/ar.h> +#include <scc/arg.h> + +enum { + BEFORE, + INDOT, + AFTER, +}; + +struct tmp { + char *name; + FILE *fp; +} tmps[3]; + +char *argv0; + +static int bflag, vflag, cflag, lflag, uflag, aflag; +static char *arfile, *posname; + +struct member { + FILE *src; + struct ar_hdr hdr; + int cur; + char *fname; + long size; + long mode; + long long date; +}; + +static void +cleanup(void) +{ + int i; + + for (i = 0; i < 3; i++) { + if (tmps[i].name) + remove(tmps[i].name); + } +} + +/* + * I do know that you cannot call remove from a signal handler + * but we only can use stdio function to deal with files + * because we are C99 compliant, and it is very likely that + * remove is going to work in this case + */ +static void +sigfun(int signum) +{ + cleanup(); + _Exit(1); +} + +static FILE * +openar(void) +{ + FILE *fp; + char magic[SARMAG+1]; + + if ((fp = fopen(arfile,"r+b")) == NULL) { + if (!cflag) + fprintf(stderr, "ar: creating %s\n", arfile); + if ((fp = fopen(arfile, "w+b")) == NULL) { + perror("ar:opening archive"); + exit(1); + } + fputs(ARMAG, fp); + if (fflush(fp) == EOF) { + perror("ar:writing magic number"); + exit(1); + } + } else { + if (fgets(magic, sizeof(magic), fp) == NULL) { + perror("ar:error reading magic number"); + exit(1); + } + if (strcmp(magic, ARMAG)) { + fprintf(stderr, + "ar:%s:invalid magic number '%s'\n", + arfile, + magic); + exit(1); + } + } + return fp; +} + +static void +archive(char *fname, FILE *to, char letter) +{ + int c; + size_t n; + FILE *from; + char mtime[13]; + struct stat st; + + if (vflag) + printf("%c - %s\n", letter, fname); + if (strlen(fname) > 16) + fprintf(stderr, "ar:%s: too long name\n", fname); + if ((from = fopen(fname, "rb")) == NULL) { + fprintf(stderr, + "ar:opening member '%s':%s\n", + fname, + strerror(errno)); + exit(1); + } + if (stat(fname, &st) < 0) { + fprintf(stderr, "ar:error getting '%s' attributes\n", fname); + exit(1); + } + strftime(mtime, sizeof(mtime), "%s", gmtime(&st.st_mtime)); + fprintf(to, + "%-16.16s%-12s%-6u%-6u%-8o%-10llu`\n", + fname, + mtime, + st.st_uid, + st.st_gid, + st.st_mode, + (unsigned long long) st.st_size); + for (n = 0; (c = getc(from)) != EOF; n++) + putc(c, to); + if (n & 1) + putc('\n', to); + if (ferror(from)) { + fprintf(stderr, + "ar:reading input '%s':%s\n", + fname, strerror(errno)); + exit(1); + } + fclose(from); +} + +static void +append(FILE *fp, char *argv[]) +{ + char *fname; + + if (fseek(fp, 0, SEEK_END) == EOF) { + perror("ar:seeking archive"); + exit(1); + } + + for ( ; fname = *argv; ++argv) { + *argv = NULL; + archive(fname, fp, 'a'); + } + + if (fclose(fp) == EOF) { + perror("ar:error writing archive"); + exit(1); + } +} + +static void +copy(struct member *m, struct tmp *tmp) +{ + int c; + size_t siz = m->size; + struct ar_hdr *hdr = &m->hdr; + + fwrite(hdr, sizeof(*hdr), 1, tmp->fp); + if ((siz & 1) == 1) + siz++; + while (siz--) { + if ((c = getc(m->src)) == EOF) + break; + fputc(c, tmp->fp); + } +} + +static void +letters(unsigned long val, char *s) +{ + *s++ = (val & 04) ? 'r' : '-'; + *s++ = (val & 02) ? 'w' : '-'; + *s++ = (val & 01) ? 'x' : '-'; +} + +static char * +perms(struct member *m) +{ + static char buf[10]; + + letters(m->mode >> 6, buf); + letters(m->mode >> 3, buf+3); + letters(m->mode, buf +6); + buf[9] = '\0'; + + return buf; +} + +static int +inlist(char *fname, int argc, char *argv[]) +{ + for (; argc-- > 0; ++argv) { + if (*argv && !strcmp(*argv, fname)) { + *argv = NULL; + return 1; + } + } + return 0; +} + +static void +move(struct member *m, int argc, char *argv[]) +{ + int where; + + if (inlist(m->fname, argc, argv)) { + if (vflag) + printf("m - %s\n", m->fname); + where = INDOT; + } else if (posname && !strcmp(posname, m->fname)) { + where = (bflag) ? AFTER : BEFORE; + m->cur = AFTER; + } else { + where = m->cur; + } + copy(m, &tmps[where]); +} + +static void +insert(int argc, char *argv[]) +{ + for (; argc-- > 0; ++argv) { + if (*argv) { + archive(*argv, tmps[INDOT].fp, 'a'); + *argv = NULL; + } + } +} + +static void +update(struct member *m, int argc, char *argv[]) +{ + int where; + FILE *fp = tmps[BEFORE].fp; + + if (inlist(m->fname, argc, argv)) { + archive(m->fname, tmps[m->cur].fp, 'r'); + return; + } else if (posname && !strcmp(posname, m->fname)) { + where = (bflag) ? AFTER : BEFORE; + m->cur = AFTER; + } else { + where = m->cur; + } + copy(m, &tmps[where]); +} + +static void +extract(struct member *m, int argc, char *argv[]) +{ + int c; + long siz; + FILE *fp; + + if (argc > 0 && !inlist(m->fname, argc, argv)) + return; + if (vflag) + printf("x - %s\n", m->fname); + siz = m->size; + + if ((fp = fopen(m->fname, "wb")) == NULL) + goto error_file; + while (siz-- > 0 && (c = getc(m->src)) != EOF) + putc(c, fp); + fflush(fp); + if (fclose(fp) == EOF) + goto error_file; + + /* TODO: set attributes */ + return; + + +error_file: + perror("ar:error extracting file"); + exit(1); +} + +static void +print(struct member *m, int argc, char *argv[]) +{ + long siz; + int c; + + if (argc > 0 && !inlist(m->fname, argc, argv)) + return; + if (vflag) + printf("\n<%s>\n\n", m->fname); + siz = m->size; + while (siz-- > 0 && (c = getc(m->src)) != EOF) + putchar(c); +} + +static void +list(struct member *m, int argc, char *argv[]) +{ + time_t t; + struct ar_hdr *hdr = &m->hdr; + char mtime[30]; + + if (argc > 0 && !inlist(m->fname, argc, argv)) + return; + if (!vflag) { + printf("%s\n", m->fname); + } else { + t = totime(m->date); + strftime(mtime, sizeof(mtime), "%c", localtime(&t)); + printf("%s %ld/%ld\t%s %s\n", + perms(m), + atol(hdr->ar_uid), + atol(hdr->ar_gid), + mtime, + m->fname); + } +} + +static void +del(struct member *m, int argc, char *argv[]) +{ + if (inlist(m->fname, argc, argv)) { + if (vflag) + printf("d - %s\n", m->fname); + return; + } + copy(m, &tmps[BEFORE]); +} + +static char * +getfname(struct ar_hdr *hdr) +{ + static char fname[SARNAM+1]; + size_t i; + + memcpy(fname, hdr->ar_name, SARNAM); + fname[SARNAM] = '\0'; + + for (i = SARNAM-1; i >= 0; --i) { + if (fname[i] != ' ' && fname[i] != '/') + break; + fname[i] = '\0'; + } + return fname; +} + +static long long +getnum(char *s, int size, int base) +{ + int c; + long long val; + char *p; + static char digits[] = "0123456789"; + + for (val = 0; size > 0; val += c) { + --size; + if ((c = *s++) == ' ') + break; + if ((p = strchr(digits, c)) == NULL) + return -1; + if ((c = p - digits) >= base) + return -1; + val *= base; + } + + while (size > 0 && *s++ == ' ') + --size; + return (size == 0) ? val : -1; +} + +static int +valid(struct member *m) +{ + struct ar_hdr *hdr = &m->hdr; + + m->fname = getfname(&m->hdr); + m->size = getnum(hdr->ar_size, sizeof(hdr->ar_size), 10); + m->mode = getnum(hdr->ar_mode, sizeof(hdr->ar_mode), 8); + m->date = getnum(hdr->ar_date, sizeof(hdr->ar_date), 10); + + if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(hdr->ar_fmag)) || + m->size < 0 || m->mode < 0 || m->date < 0) { + return 0; + } + return 1; +} + +static void +run(FILE *fp, int argc, char *argv[], + void (*fun)(struct member *, int argc, char *files[])) +{ + struct member m; + + m.src = fp; + m.cur = BEFORE; + + while (fread(&m.hdr, sizeof(m.hdr), 1, fp) == 1) { + fpos_t pos; + + if (!valid(&m)) { + fprintf(stderr, + "ar:corrupted member '%s'\n", + m.fname); + exit(1); + } + fgetpos(fp, &pos); + (*fun)(&m, argc, argv); + fsetpos(fp, &pos); + fseek(fp, m.size+1 & ~1, SEEK_CUR); + } + if (ferror(fp) || fclose(fp) == EOF) { + perror("ar:reading members"); + exit(1); + } +} + +static void +merge(void) +{ + FILE *fp, *fi; + int c, i; + + + if ((fp = fopen(arfile, "wb")) == NULL) { + perror("ar:reopening archive"); + exit(1); + } + + fputs(ARMAG, fp); + + for (i = 0; i < 3; i++) { + if ((fi = tmps[i].fp) == NULL) + continue; + fseek(fi, 0, SEEK_SET); + while ((c = getc(fi)) != EOF) + putc(c, fp); + if (ferror(fi)) { + perror("ar:error in temporary"); + exit(1); + } + } + + if (fclose(fp) == EOF) { + perror("ar:writing archive file"); + exit(1); + } +} + +static void +closetmp(int which) +{ + struct tmp *tmp = &tmps[which]; + + if (!tmp->fp) + return; + if (fclose(tmp->fp) == EOF) { + perror("ar:closing temporaries"); + exit(1); + } +} + +static void +opentmp(char *fname, int which) +{ + struct tmp *tmp = &tmps[which]; + + if (lflag) { + tmp->name = fname; + tmp->fp = fopen(fname, "w+b"); + } else { + tmp->fp = tmpfile(); + } + + if (tmp->fp == NULL) { + perror("ar:creating temporary"); + exit(1); + } +} + +static void +doit(int key, char *argv[], int argc) +{ + FILE *fp; + + fp = openar(); + if (argc == 0 && + (key == 'r' || key == 'd' || key == 'm' || key == 'q')) { + if (fclose(fp) == EOF) { + perror("ar:early close of archive file"); + exit(-1); + } + return; + } + + if (key == 'r' || key == 'm' || key == 'd') + opentmp("ar.tmp1", BEFORE); + if (key == 'r' || key == 'm') { + opentmp("ar.tmp2", INDOT); + opentmp("ar.tmp3", AFTER); + } + + switch (key) { + case 'r': + run(fp, argc, argv, update); + insert(argc, argv); + merge(); + break; + case 'm': + run(fp, argc, argv, move); + merge(); + break; + case 'd': + run(fp, argc, argv, del); + merge(); + break; + case 't': + run(fp, argc, argv, list); + break; + case 'p': + run(fp, argc, argv, print); + break; + case 'x': + run(fp, argc, argv, extract); + break; + case 'q': + append(fp, argv); + break; + } + + closetmp(BEFORE); + closetmp(INDOT); + closetmp(AFTER); + + for ( ; argc-- > 0; ++argv) { + if (*argv) { + fprintf(stderr, "ar: No member named '%s'\n", *argv); + exit(1); + } + } +} + +static void +usage(void) +{ + fputs("ar [-drqtpmx][posname] [-vuaibcl] [posname] arfile name ...\n", + stderr); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int key, nkey = 0, pos = 0; + + atexit(cleanup); + ARGBEGIN { + case 'd': + nkey++; + key = 'd'; + break; + case 'r': + nkey++; + key = 'r'; + break; + case 'q': + nkey++; + key = 'q'; + break; + case 't': + nkey++; + key = 't'; + break; + case 'p': + nkey++; + key = 'p'; + break; + case 'm': + nkey++; + key = 'm'; + break; + case 'x': + nkey++; + key = 'x'; + break; + case 'a': + aflag = 1; + pos++; + posname = EARGF(usage()); + break; + case 'i': + case 'b': + bflag = 1; + pos++; + posname = EARGF(usage()); + break; + case 'v': + vflag = 1; + break; + case 'c': + cflag = 1; + break; + case 'l': + lflag = 1; + break; + case 'u': + /* TODO */ + abort(); + uflag = 1; + break; + default: + usage(); + } ARGEND + + if (nkey == 0 || nkey > 1 || pos > 1 || argc == 0) + usage(); + + signal(SIGINT, sigfun); + signal(SIGQUIT, sigfun); + signal(SIGTERM, sigfun); + + arfile = *argv; + doit(key, ++argv, --argc); + + if (fflush(stdout) == EOF) { + perror("ar:error writing to stdout"); + exit(1); + } + + return 0; +} diff --git a/src/ar/posix/driver.h b/src/cmd/ar.h diff --git a/src/cmd/deps.mk b/src/cmd/deps.mk @@ -1,4 +1,8 @@ #deps +ar-posix.o: ar.h +ar.o: $(INCDIR)/scc/scc/ar.h +ar.o: $(INCDIR)/scc/scc/arg.h +ar.o: ar.h nm.o: $(INCDIR)/scc/scc/arg.h nm.o: $(INCDIR)/scc/scc/mach.h size.o: $(INCDIR)/scc/scc/arg.h