improve overwrite confirmation prompt.
add option to (not) overwrite identical (by size and crc) files
--HG--
branch : HEAD
diff --git a/src/zipmerge.c b/src/zipmerge.c
index fccc725..708804f 100644
--- a/src/zipmerge.c
+++ b/src/zipmerge.c
@@ -1,5 +1,5 @@
/*
- $NiH$
+ $NiH: zipmerge.c,v 1.1 2004/05/15 23:56:55 dillo Exp $
zipmerge.c -- merge zip archives
Copyright (C) 2004 Dieter Baron and Thomas Klausner
@@ -49,7 +49,7 @@
char *prg;
-char *usage = "usage: %s [-hVDiI] target-zip zip...\n";
+char *usage = "usage: %s [-hVDiIsS] target-zip zip...\n";
char help_head[] = PACKAGE " by Dieter Baron and Thomas Klausner\n\n";
@@ -59,6 +59,8 @@
-D ignore directory component in file names\n\
-i ask before overwriting files\n\
-I ignore case in file names\n\
+ -s overwrite identical files without asking\n\
+ -S don't overwrite identical files\n\
\n\
Report bugs to <nih@giga.or.at>.\n";
@@ -69,12 +71,18 @@
" PACKAGE " under the terms of the GNU General Public License.\n\
For more information about these matters, see the files named COPYING.\n";
-#define OPTIONS "hVDiI"
+#define OPTIONS "hVDiIsS"
+
+#define CONFIRM_ALL_YES 0x001
+#define CONFIRM_ALL_NO 0x002
+#define CONFIRM_SAME_YES 0x010
+#define CONFIRM_SAME_NO 0x020
int confirm;
int name_flags;
-static int confirm_replace(const char *, const char *, const char *);
+static int confirm_replace(struct zip *, const char *, int,
+ struct zip *, const char *, int);
static int merge_zip(struct zip *zt, const char *, const char *);
@@ -88,7 +96,7 @@
prg = argv[0];
- confirm = 0;
+ confirm = CONFIRM_ALL_YES;
name_flags = 0;
while ((c=getopt(argc, argv, OPTIONS)) != -1) {
@@ -97,11 +105,19 @@
name_flags |= ZIP_FL_NODIR;
break;
case 'i':
- confirm = 1;
+ confirm &= ~CONFIRM_ALL_YES;
break;
case 'I':
name_flags |= ZIP_FL_NOCASE;
break;
+ case 's':
+ confirm &= ~CONFIRM_SAME_NO;
+ confirm |= CONFIRM_SAME_YES;
+ break;
+ case 'S':
+ confirm &= ~CONFIRM_SAME_YES;
+ confirm |= CONFIRM_SAME_NO;
+ break;
case 'h':
fputs(help_head, stdout);
@@ -148,16 +164,46 @@
static int
-confirm_replace(const char *tname, const char *sname, const char *fname)
+confirm_replace(struct zip *zt, const char *tname, int it,
+ struct zip *zs, const char *sname, int is)
{
char line[1024];
+ struct zip_stat st, ss;
- printf("replace `%s' in `%s' from `%s'? ",
- fname, tname, sname);
+ if (confirm & CONFIRM_ALL_YES)
+ return 1;
+ else if (confirm & CONFIRM_ALL_NO)
+ return 0;
+
+ if (zip_stat_index(zt, it, ZIP_FL_UNCHANGED, &st) < 0) {
+ fprintf(stderr, "%s: cannot stat file %d in `%s': %s\n",
+ prg, it, tname, zip_strerror(zt));
+ return -1;
+ }
+ if (zip_stat_index(zs, is, 0, &ss) < 0) {
+ fprintf(stderr, "%s: cannot stat file %d in `%s': %s\n",
+ prg, is, sname, zip_strerror(zs));
+ return -1;
+ }
+
+ if (st.size == ss.size && st.crc == ss.crc) {
+ if (confirm & CONFIRM_SAME_YES)
+ return 1;
+ else if (confirm & CONFIRM_SAME_NO)
+ return 0;
+ }
+
+ printf("replace `%s' (%qu / %08x) in `%s'\n"
+ " with `%s' (%qu / %08x) from `%s'? ",
+ st.name, st.size, st.crc, tname,
+ ss.name, ss.size, ss.crc, sname);
fflush(stdout);
- if (fgets(line, sizeof(line), stdin) == NULL)
- return 0;
+ if (fgets(line, sizeof(line), stdin) == NULL) {
+ fprintf(stderr, "%s: read error from stdin: %s\n",
+ prg, strerror(errno));
+ return -1;
+ }
if (tolower(line[0]) == 'y')
return 1;
@@ -186,13 +232,27 @@
fname = zip_get_name(zs, i);
if ((idx=zip_name_locate(zt, fname, name_flags)) != -1) {
- if (!confirm || confirm_replace(tname, sname, fname)) {
- if (zip_replace_zip(zt, idx, zs, i, 0, 0, 0) < 0) {
+ switch (confirm_replace(zt, tname, idx, zs, sname, i)) {
+ case 0:
+ break;
+
+ case 1:
+ if ((err=zip_replace_zip(zt, idx, zs, i, 0, 0, 0) < 0)) {
fprintf(stderr,
"%s: cannot replace `%s' in `%s': %s\n",
prg, fname, tname, zip_strerror(zt));
return -1;
}
+ break;
+
+ case -1:
+ return -1;
+
+ default:
+ fprintf(stderr, "%s: internal error: "
+ "unexpected return code from confirm (%d)\n",
+ prg, err);
+ return -1;
}
}
else {