shithub: scc

Download patch

ref: 6ae1553550ce5ed7780482765cabacc3fa29a50d
parent: 1d8a64b2aff4f828e53c6ab06fda54f1239eebf6
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Wed Feb 14 06:57:35 EST 2018

[ar] Implement -r key

--- a/ar/main.c
+++ b/ar/main.c
@@ -16,7 +16,7 @@
 char *argv0;
 
 static int bflag, iflag, vflag, cflag, lflag, uflag, aflag;
-static char *posname, *tmpafile;
+static char *posname, *tmpafile1, *tmpafile2;
 
 struct arop {
 	FILE *src;
@@ -31,8 +31,10 @@
 static void
 cleanup(void)
 {
-	if (tmpafile)
-		remove(tmpafile);
+	if (tmpafile1)
+		remove(tmpafile1);
+	if (tmpafile2)
+		remove(tmpafile2);
 }
 
 static void
@@ -78,7 +80,7 @@
 }
 
 static void
-archieve(char *fname, FILE *to)
+archive(char *fname, FILE *to, char letter)
 {
 	int c;
 	size_t n;
@@ -87,7 +89,7 @@
 	struct stat st;
 
 	if (vflag)
-		printf("a - %s\n", fname);
+		printf("%c - %s\n", letter, fname);
 	if (strlen(fname) > 16)
 		fprintf(stderr, "ar:%s: too long name\n", fname);
 	if (stat(fname, &st) < 0) {
@@ -132,8 +134,9 @@
 		perror("ar:seeking archive");
 		exit(1);
 	}
-	while ((fname = *list++) != NULL)
-		archieve(fname, fp);
+	while ((fname = *list++) != NULL) {
+		archive(fname, fp, 'a');
+	}
 	if (fclose(fp) == EOF) {
 		perror("ar:error writing archive");
 		exit(1);
@@ -182,15 +185,56 @@
 	return buf;
 }
 
-static int
+static void
+rmlist(char *list[])
+{
+	for (; *list; ++list)
+		list[0] = list[1];
+}
+
+static char **
 inlist(char *fname, char *list[])
 {
 	while (*list && strcmp(*list, fname))
 		++list;
-	return *list != NULL;
+	if (*list == NULL)
+		return NULL;
+	return list;
 }
 
 static void
+insert(struct arop *op, char *list[])
+{
+	if (!posname || strcmp(op->fname, posname)) {
+		copy(op);
+		return;
+	}
+	if (bflag || iflag) {
+		for ( ; *list; ++list)
+			archive(*list, op->dst, 'a');
+		copy(op);
+	} else {
+		copy(op);
+		for ( ; *list; ++list)
+			archive(*list, op->dst, 'a');
+	}
+}
+
+static void
+update(struct arop *op, char *files[])
+{
+	char **l;
+
+	l = inlist(op->fname, files);
+	if (!l) {
+		copy(op);
+		return;
+	}
+	archive(op->fname, op->dst, 'r');
+	rmlist(l);
+}
+
+static void
 extract(struct arop *op, char *files[])
 {
 	int c;
@@ -345,6 +389,7 @@
 			        op.fname);
 			exit(1);
 		}
+		/* TODO: Implement early break */
 		fgetpos(fp, &pos);
 		(*fun)(&op, files);
 		fsetpos(fp, &pos);
@@ -355,26 +400,25 @@
 		exit(1);
 	}
 	fclose(fp);
+	if (tmp && fflush(tmp) == EOF) {
+		perror("ar:writing in temporary file");
+		exit(1);
+	}
 }
 
 static void
-closetmp(FILE *tmp, char *afile)
+closetmp(FILE *tmp, char **name, char *afile)
 {
 	int c;
 	FILE *fp;
 
-	if (fflush(tmp) == EOF) {
-		perror("ar:writing temporary");
-		exit(1);
-	}
-	if (tmpafile) {
-		fclose(tmp);
-		if (rename(tmpafile, afile) < 0) {
+	if (lflag) {
+		if (afile && rename(*name, afile) < 0) {
 			perror("ar:renaming temporary");
 			exit(1);
 		}
-		tmpafile = NULL;
-	} else {
+		*name = NULL;
+	} else if (afile) {
 		if ((fp = fopen(afile, "wb")) == NULL) {
 			perror("ar:reopening archive file");
 			exit(1);
@@ -388,18 +432,18 @@
 			exit(1);
 		}
 		fclose(fp);
-		fclose(tmp);
 	}
+	fclose(tmp);
 }
 
 static FILE *
-opentmp(void)
+opentmp(char *fname, char **dst)
 {
 	FILE *tmp;
 
 	if (lflag) {
-		tmpafile = "ar.tmp";
-		tmp = fopen(tmpafile, "wb");
+		*dst = fname;
+		tmp = fopen(fname, "wb");
 	} else {
 		tmp = tmpfile();
 	}
@@ -424,8 +468,7 @@
 {
 	int key, nkey = 0, pos = 0;
 	char *afile;
-	FILE *fp, *tmp;;
-	void (*fun)(struct arop *, char *files[]);
+	FILE *fp, *tmp1, *tmp2;;
 
 	atexit(cleanup);
 	ARGBEGIN {
@@ -498,39 +541,40 @@
 	fp = openar(afile);
 
 	switch (key) {
+	case 'r':
+		if (*argv == NULL)
+			return 0;
+		tmp1 = opentmp("ar.tmp1", &tmpafile1);
+		tmp2 = opentmp("ar.tmp2", &tmpafile2);
+		run(fp, tmp1, argv, update);
+		rewind(tmp1);
+		run(tmp1, tmp2, argv, insert);
+		closetmp(tmp1, &tmpafile1, NULL);
+		closetmp(tmp2, &tmpafile2, afile);
+		break;
 	case 'q':
-		tmp = NULL;
-		fun = NULL;
 		append(fp, argv);
 		break;
 	case 'd':
 		if (*argv == NULL)
 			return 0;
-		tmp = opentmp();
-		fun = del;
+		tmp1 = opentmp("ar.tmp", &tmpafile1);
+		run(fp, tmp1, argv, del);
+		closetmp(tmp1, &tmpafile1, afile);
 		break;
 	case 't':
-		tmp = NULL;
-		fun = list;
+		run(fp, NULL, argv, list);
 		break;
 	case 'p':
-		tmp = NULL;
-		fun = print;
+		run(fp, NULL, argv, print);
 		break;
 	case 'x':
-		tmp = NULL;
-		fun = extract;
+		run(fp, NULL, argv, extract);
 		break;
-	case 'r':
 	case 'm':
 		/* TODO */
 		;
 	}
-
-	if (fun)
-		run(fp, tmp, argv, fun);
-	if (tmp)
-		closetmp(tmp, afile);
 
 	if (fflush(stdout) == EOF) {
 		perror("ar:error writing to stdout");