|
|
1.1 root 1: /*
2:
3: Copyright (C) 1990-1992 Mark Adler, Richard B. Wales, Jean-loup Gailly,
4: Kai Uwe Rommel and Igor Mandrichenko.
5: Permission is granted to any individual or institution to use, copy, or
6: redistribute this software so long as all of the original files are included
7: unmodified, that it is not sold for profit, and that this copyright notice
8: is retained.
9:
10: */
11:
12: /*
13: * zipnote.c by Mark Adler.
14: */
15:
16: #define UTIL
17: #include "revision.h"
18: #include "zip.h"
19: #include <signal.h>
20:
21:
22: /* Character to mark zip entry names in the comment file */
23: #define MARK '@'
24:
25: /* Temporary zip file name and file pointer */
26: local char *tempzip;
27: local FILE *tempzf;
28:
29:
30: /* Local functions */
31: #ifdef PROTO
32: local void handler(int);
33: local void license(void);
34: local void help(void);
35: local void putclean(char *, int);
36: local int catalloc(char * far *, char *);
37: void main(int, char **);
38: #endif /* PROTO */
39:
40:
41:
42: void err(c, h)
43: int c; /* error code from the ZE_ class */
44: char *h; /* message about how it happened */
45: /* Issue a message for the error, clean up files and memory, and exit. */
46: {
47: if (PERR(c))
48: perror("zipnote error");
49: fprintf(stderr, "zipnote error: %s (%s)\n", errors[c-1], h);
50: if (tempzf != NULL)
51: fclose(tempzf);
52: if (tempzip != NULL)
53: {
54: destroy(tempzip);
55: free((voidp *)tempzip);
56: }
57: if (zipfile != NULL)
58: free((voidp *)zipfile);
59: #ifdef VMS
60: exit(0);
61: #else /* !VMS */
62: exit(c);
63: #endif /* ?VMS */
64: }
65:
66:
67: local void handler(s)
68: int s; /* signal number (ignored) */
69: /* Upon getting a user interrupt, abort cleanly using err(). */
70: {
71: #ifndef MSDOS
72: putc('\n', stderr);
73: #endif /* !MSDOS */
74: err(ZE_ABORT, "aborting");
75: s++; /* keep some compilers happy */
76: }
77:
78:
79: void warn(a, b)
80: char *a, *b; /* message strings juxtaposed in output */
81: /* Print a warning message to stderr and return. */
82: {
83: fprintf(stderr, "zipnote warning: %s%s\n", a, b);
84: }
85:
86:
87: local void license()
88: /* Print license information to stdout. */
89: {
90: extent i; /* counter for copyright array */
91:
92: for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
93: printf(copyright[i], "zipnote");
94: putchar('\n');
95: }
96: for (i = 0; i < sizeof(disclaimer)/sizeof(char *); i++)
97: puts(disclaimer[i]);
98: }
99:
100:
101: local void help()
102: /* Print help (along with license info) to stdout. */
103: {
104: extent i; /* counter for help array */
105:
106: /* help array */
107: static char *text[] = {
108: "",
109: "ZipNote %d.%d (%s)",
110: "Usage: zipnote [-w] [-b path] zipfile",
111: " the default action is to write the comments in zipfile to stdout",
112: " -w write the zipfile comments from stdin",
113: " -b use \"path\" for the temporary zip file",
114: " -h show this help -L show software license",
115: "",
116: "Example:",
117: #ifdef VMS
118: " define/user sys$output foo.tmp",
119: " zipnote foo.zip",
120: " edit foo.tmp",
121: " ... then you edit the comments, save, and exit ...",
122: " define/user sys$input foo.tmp",
123: " zipnote -w foo.zip"
124: #else /* !VMS */
125: " zipnote foo.zip > foo.tmp",
126: " ed foo.tmp",
127: " ... then you edit the comments, save, and exit ...",
128: " zipnote -w foo.zip < foo.tmp"
129: #endif /* ?VMS */
130: };
131:
132: for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
133: printf(copyright[i], "zipnote");
134: putchar('\n');
135: }
136: for (i = 0; i < sizeof(text)/sizeof(char *); i++)
137: {
138: printf(text[i], REVISION / 10, REVISION % 10, REVDATE);
139: putchar('\n');
140: }
141: }
142:
143:
144: local void putclean(s, n)
145: char *s; /* string to write to stdout */
146: int n; /* length of string */
147: /* Write the string s to stdout, filtering out control characters that are
148: not tab or newline (mainly to remove carriage returns), and prefix MARK's
149: and backslashes with a backslash. Also, terminate with a newline if
150: needed. */
151: {
152: int c; /* next character in string */
153: int e; /* last character written */
154:
155: e = '\n'; /* if empty, write nothing */
156: while (n--)
157: {
158: c = *(uch *)s++;
159: if (c == MARK || c == '\\')
160: putchar('\\');
161: if (c >= ' ' || c == '\t' || c == '\n')
162: putchar(e = c);
163: }
164: if (e != '\n')
165: putchar('\n');
166: }
167:
168:
169: local int catalloc(a, s)
170: char * far *a; /* pointer to a pointer to a malloc'ed string */
171: char *s; /* string to concatenate on a */
172: /* Concatentate the string s to the malloc'ed string pointed to by a.
173: Preprocess s by removing backslash escape characters. */
174: {
175: char *p; /* temporary pointer */
176: char *q; /* temporary pointer */
177:
178: for (p = q = s; *q; *p++ = *q++)
179: if (*q == '\\' && *(q+1))
180: q++;
181: *p = 0;
182: if ((p = malloc(strlen(*a) + strlen(s) + 3)) == NULL)
183: return ZE_MEM;
184: strcat(strcat(strcpy(p, *a), **a ? "\r\n" : ""), s);
185: free((voidp *)*a);
186: *a = p;
187: return ZE_OK;
188: }
189:
190:
191: void main(argc, argv)
192: int argc; /* number of tokens in command line */
193: char **argv; /* command line tokens */
194: /* Write the comments in the zipfile to stdout, or read them from stdin. */
195: {
196: char a[FNMAX+1]; /* input line buffer */
197: ulg c; /* start of central directory */
198: int k; /* next argument type */
199: char *q; /* steps through option arguments */
200: int r; /* arg counter, temporary variable */
201: ulg s; /* length of central directory */
202: int t; /* attributes of zip file */
203: int w; /* true if updating zip file from stdin */
204: FILE *x, *y; /* input and output zip files */
205: struct zlist far *z; /* steps through zfiles linked list */
206:
207:
208: /* If no args, show help */
209: if (argc == 1)
210: {
211: help();
212: exit(0);
213: }
214:
215: init_upper(); /* build case map table */
216:
217: /* Go through args */
218: zipfile = tempzip = NULL;
219: tempzf = NULL;
220: signal(SIGINT, handler);
221: signal(SIGTERM, handler);
222: k = w = 0;
223: for (r = 1; r < argc; r++)
224: if (*argv[r] == '-')
225: if (argv[r][1])
226: for (q = argv[r]+1; *q; q++)
227: switch(*q)
228: {
229: case 'b': /* Specify path for temporary file */
230: if (k)
231: err(ZE_PARMS, "use -b before zip file name");
232: else
233: k = 1; /* Next non-option is path */
234: break;
235: case 'h': /* Show help */
236: help(); exit(0);
237: case 'l': case 'L': /* Show copyright and disclaimer */
238: license(); exit(0);
239: case 'w':
240: w = 1; break;
241: default:
242: err(ZE_PARMS, "unknown option");
243: }
244: else
245: err(ZE_PARMS, "zip file cannot be stdin");
246: else
247: if (k == 0)
248: if (zipfile == NULL)
249: {
250: if ((zipfile = ziptyp(argv[r])) == NULL)
251: err(ZE_MEM, "was processing arguments");
252: }
253: else
254: err(ZE_PARMS, "can only specify one zip file");
255: else
256: {
257: tempath = argv[r];
258: k = 0;
259: }
260: if (zipfile == NULL)
261: err(ZE_PARMS, "need to specify zip file");
262:
263: /* Read zip file */
264: if ((r = readzipfile()) != ZE_OK)
265: err(r, zipfile);
266: if (zfiles == NULL)
267: err(ZE_NAME, zipfile);
268:
269: /* Put comments to stdout, if not -w */
270: if (!w)
271: {
272: for (z = zfiles; z != NULL; z = z->nxt)
273: {
274: printf("%c %s\n", MARK, z->zname);
275: putclean(z->comment, z->com);
276: putchar(MARK); putchar('\n');
277: }
278: putchar(MARK); putchar('\n');
279: putclean(zcomment, zcomlen);
280: exit(ZE_OK);
281: }
282:
283: /* If updating comments, make sure zip file is writeable */
284: if ((x = fopen(zipfile, "a")) == NULL)
285: err(ZE_CREAT, zipfile);
286: fclose(x);
287: t = getfileattr(zipfile);
288:
289: /* Process stdin, replacing comments */
290: for (z = zfiles; z != NULL; z = z->nxt)
291: {
292: if (gets(a) == NULL || a[0] != MARK || a[1] != ' ' ||
293: strcmp(a + 2, z->zname))
294: err(ZE_NOTE, "missing entry name");
295: if (z->com)
296: free((voidp *)z->comment);
297: z->comment = malloc(1); *(z->comment) = 0;
298: while (gets(a) != NULL && *a != MARK)
299: if ((r = catalloc(&(z->comment), a)) != ZE_OK)
300: err(r, "was building new comments");
301: if (a[1])
302: err(ZE_NOTE, "missing comment end line");
303: z->com = strlen(z->comment);
304: }
305: if (gets(a) == NULL || a[0] != MARK || a[1])
306: err(ZE_NOTE, "missing zip file comment marker line");
307: zcomment = malloc(1); *zcomment = 0;
308: while (gets(a) != NULL)
309: if ((r = catalloc(&zcomment, a)) != ZE_OK)
310: err(r, "was building new comments");
311: zcomlen = strlen(zcomment);
312:
313: /* Open output zip file for writing */
314: if ((tempzf = y = fopen(tempzip = tempname(zipfile), FOPW)) == NULL)
315: err(ZE_TEMP, tempzip);
316:
317: /* Open input zip file again, copy preamble if any */
318: if ((x = fopen(zipfile, FOPR)) == NULL)
319: err(ZE_NAME, zipfile);
320: if (zipbeg && (r = fcopy(x, y, zipbeg)) != ZE_OK)
321: err(r, r == ZE_TEMP ? tempzip : zipfile);
322:
323: /* Go through local entries, copying them over as is */
324: for (z = zfiles; z != NULL; z = z->nxt)
325: if ((r = zipcopy(z, x, y)) != ZE_OK)
326: err(r, "was copying an entry");
327: fclose(x);
328:
329: /* Write central directory and end of central directory with new comments */
330: if ((c = ftell(y)) == -1L) /* get start of central */
331: err(ZE_TEMP, tempzip);
332: for (z = zfiles; z != NULL; z = z->nxt)
333: if ((r = putcentral(z, y)) != ZE_OK)
334: err(r, tempzip);
335: if ((s = ftell(y)) == -1L) /* get end of central */
336: err(ZE_TEMP, tempzip);
337: s -= c; /* compute length of central */
338: if ((r = putend((int)zcount, s, c, zcomlen, zcomment, y)) != ZE_OK)
339: err(r, tempzip);
340: tempzf = NULL;
341: if (fclose(y))
342: err(ZE_TEMP, tempzip);
343: if ((r = replace(zipfile, tempzip)) != ZE_OK)
344: {
345: warn("new zip file left as: ", tempzip);
346: free((voidp *)tempzip);
347: tempzip = NULL;
348: err(r, "was replacing the original zip file");
349: }
350: free((voidp *)tempzip);
351: tempzip = NULL;
352: setfileattr(zipfile, t);
353: free((voidp *)zipfile);
354: zipfile = NULL;
355:
356: /* Done! */
357: exit(ZE_OK);
358: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.