1 /***********************************************************************
2   This file is part of HA, a general purpose file archiver.
3   Copyright (C) 1995 Harri Hirvola
4 
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 ************************************************************************
19   HA main program
20 ***********************************************************************/
21 
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <sys/types.h>
27 #include <dirent.h>
28 #include "error.h"
29 #include "ha.h"
30 #include "archive.h"
31 #include "haio.h"
32 #include "cpy.h"
33 #include "asc.h"
34 #include "hsc.h"
35 
36 /***********************************************************************
37   Commands
38 */
39 
40 #define ADD		'a'
41 #define EXTRACT		'e'
42 #define PEXTRACT	'x'
43 #define FRESHEN		'f'
44 #define UPDATE		'u'
45 #define LIST		'l'
46 #define DELETE		'd'
47 #define TEST		't'
48 #define INFO            'h'
49 
50 char *myname;
51 int quiet=0,useattr=0,special=0;
52 static unsigned ilen=0;
53 static int fulllist=0,usepath=1,yes=0,touch=0,recurse=0,savedir=0,move=0;
54 static char *defpat[]={ALLFILES};
55 static int metqueue[M_UNK+1]={M_UNK};
56 static int (*addthis)(char*, char*);
dummy(void)57 static void dummy(void) {
58 	/* Do nothing */
59 }
60 
61 struct {
62     char *name;
63     void (*encode)(void);
64     void (*decode)(void);
65     void (*cleanup)(void); } method[]= {
66 	{"CPY",cpy,cpy,dummy},
67 	{"ASC",asc_pack,asc_unpack,asc_cleanup},
68 	{"HSC",hsc_pack,hsc_unpack,hsc_cleanup},
69 	{"3"},{"4"},{"5"},{"6"},{"7"},{"8"},{"9"},{"10"},{"11"},{"12"},{"13"},
70 	{"DIR"},
71 	{"SPC"}
72     };
73 
banner(void)74 static void banner(void) {
75 
76     fprintf(stderr,BANNER);
77     fflush(stderr);
78 }
79 
getinfo(unsigned char * buf,unsigned blen)80 static unsigned getinfo(unsigned char *buf, unsigned blen) {
81 
82     static unsigned char *idat=infodat;
83     unsigned i;
84 
85     for (i=0;i<blen && --ilen;i++) {
86 	buf[i]=*idat++;
87     }
88     return i;
89 }
90 
info(void)91 static void info(void) {
92 
93     setoutput(STDOUT_FILENO,0,"stdout");
94     ilen=infolen;
95     inspecial=getinfo;
96     ibl=0;
97     fprintf(stdout,BANNER);
98     fflush(stdout);
99     (*method[M_HSC].decode)();
100     fflush(stdout);
101     exit(lasterror);
102 }
103 
104 
infoout(unsigned char * buf,unsigned blen)105 static void infoout(unsigned char *buf, unsigned blen) {
106 
107     U16B i;
108     char ds[10];
109 
110     for (i=0;i<blen;++i) {
111 	if (ilen) write(arcfile,",",1);
112 	if (!(ilen++&0xf)) write(arcfile,"\n\t",2);
113 	sprintf(ds,"0x%02X",buf[i]);
114 	write(arcfile,ds,strlen(ds));
115     }
116 }
117 
makeinfo(char * ifile,char * ofile)118 static void makeinfo(char *ifile, char *ofile) {
119 
120     int df;
121     char ds[256];
122 
123     if ((df=open(ifile,O_RDONLY|O_BINARY))<0 ||
124 	(arcfile=open(ofile,O_WRONLY|O_BINARY|O_TRUNC|O_CREAT,DEF_FILEATTR))<0)
125       exit(99);
126     setinput(df,0,"ifile");
127     outspecial=infoout;
128     obl=0;
129     strcpy(ds,"unsigned char infodat[]={");
130     write(arcfile,ds,strlen(ds));
131     (*method[M_HSC].encode)();
132     sprintf(ds,"\n};\n\nunsigned infolen=%d;\n",ilen);
133     write(arcfile,ds,strlen(ds));
134     close(df);
135     close(arcfile);
136     exit(0);
137 }
138 
usage(int ex)139 static void usage(int ex) {
140 
141     banner();
142     fprintf(stderr,"\n usage : HA <cmd> archive [files]"
143 	    EXAMPLE
144 	    "\n"
145 	    "\n commands :"
146 	    "\n   a[sdqemr012] - Add files      d[q]         - Delete files"
147 	    "\n   e[aqty]      - Extract files  f[sdqemr012] - Freshen files"
148 	    "\n   l[f]         - List files     t[q]         - Test files"
149 	    "\n   u[sdqemr012] - Update files   x[aqty]      -"
150 	    " eXtract files with pathnames"
151 	    "\n"
152 	    "\n switches :"
153 	    "\n   0,1,2  - try method (0-CPY,1-ASC,2-HSC)"
154 	    "\n   t      - Touch files          r      - Recurse subdirs"
155 	    "\n   f      - Full listing         y      -"
156 	    " assume Yes on all questions"
157 	    "\n   m      - Move files           a      -"
158 	    " set system specific file Attributes"
159 	    "\n   e      - Exclude pathnames    s      - find Special files"
160 	    "\n   q      - Quiet operation      d      -"
161 	    " make Directory entries"
162 	    "\n"
163 	    "\nType \"ha h | more\" to get more information about HA."
164 	    "\n"
165 	    );
166     fflush(stderr);
167     if (ex) {
168 	cu_do(NULL);
169 	exit(ex);
170     }
171 }
172 
yesno(char * format,char * string)173 static int yesno(char *format, char *string) {
174 
175     int rep;
176 
177     if (yes || quiet) return 1;
178     printf(format,string);
179     fflush(stdout);
180     for (rep=0;!rep;) {
181 	switch (rep=getchar()) {
182 	  case 'Y' :
183 	  case 'y' :
184 	  case 'N' :
185 	  case 'n' :
186 	  case 'A' :
187 	  case 'a' :
188 	    break;
189 	  default :
190 	    rep=0;
191 	    break;
192 	}
193     }
194     if (rep=='Y'||rep=='y') rep=1;
195     else if (rep=='A'||rep=='a') rep=yes=1;
196     else rep=0;
197     return rep;
198 }
199 
backstep(int len)200 static void backstep(int len) {
201 
202     while (--len) putchar(0x08);
203 }
204 
do_list(void)205 static void do_list(void) {
206 
207     U32B tcs,tos;
208     unsigned files;
209     Fheader *hd;
210 
211     arc_reset();
212     if ((hd=arc_seek())==NULL) error(1,ERR_NOFILES);
213     printf("\n  filename        original    compressed"
214 	   "   rate     date        time   m");
215     if (fulllist)  {
216 	printf("\n CRC-32    path");
217 	md_listhdr();
218     }
219     printf("\n================================="
220 	   "==========================================");
221     tcs=tos=files=0;
222     for(;;) {
223 	if (hd->type==0xff) continue;
224 	if (fulllist && files) {
225 	    printf("\n-------------------------"
226 		   "--------------------------------------------------");
227 	}
228 	printf("\n  %-15s %-11" F_32B " %-11" F_32B " %3d.%d %%   %s  %s",
229 	       hd->name,hd->olen,hd->clen,
230 	       (hd->olen==0?100:(int)(100*hd->clen/hd->olen)),
231 	       (hd->olen==0?0:(int)((1000*hd->clen/hd->olen)%10)),
232 	       md_timestring(hd->time),method[hd->type].name);
233 	if (fulllist) {
234 	    printf("\n %08" FX_32B "  %s",hd->crc,
235 		   *hd->path==0?"(none)":md_tomdpath(hd->path));
236 	    md_listdat();
237 	}
238 	tcs+=hd->clen;
239 	tos+=hd->olen;
240 	++files;
241 	if ((hd=arc_seek())==NULL) break;
242     }
243     printf("\n============================="
244 	   "==============================================");
245     printf("\n  %-4d            %-11" F_32B " %-11" F_32B " %3d.%d %%\n",
246 	   files,tos,tcs,(tos==0?100:(int)(100*tcs/tos)),
247 	   (tos==0?0:(int)((1000*tcs/tos)%10)));
248 }
249 
do_extract(void)250 static void do_extract(void) {
251 
252     Fheader *hd;
253     char *ofname;
254     unsigned char *sdata;
255     int of,newdir;
256     void *cumark;
257 
258     arc_reset();
259     if ((hd=arc_seek())==NULL) error(1,ERR_NOFILES);
260     do {
261 	if (usepath) {
262 	    makepath(hd->path);
263 	    ofname=md_tomdpath(fullpath(hd->path,hd->name));
264 	}
265 	else ofname=md_tomdpath(hd->name);
266 	switch(hd->type) {
267 	  case M_SPECIAL:
268 	    if (!access(ofname,F_OK)) {
269 		if (!yesno("\nOverwrite special file %s ? (y/n/a) ",ofname))
270 		  break;
271 	    }
272 	    if (!quiet) {
273 		printf("\nMaking    SPC        %s",ofname);
274 		backstep(strlen(ofname)+8);
275 	    }
276 	    if (hd->clen) {
277 		if ((sdata=malloc(hd->clen))==NULL)
278 		  error(1,ERR_MEM,"do_extract()");
279 		if (read(arcfile,sdata,hd->clen)!=hd->clen)
280 		  error(1,ERR_READ,arcname);
281 	    }
282 	    else sdata=NULL;
283 	    if (!md_mkspecial(ofname,hd->clen,sdata)) {
284 		if (sdata!=NULL) free(sdata);
285 		break;
286 	    }
287 	    if (sdata!=NULL) free(sdata);
288 	    if (touch) md_setft(ofname,md_systime());
289 	    else md_setft(ofname,hd->time);
290 	    if (!quiet) printf("DONE");
291 	    break;
292 	  case M_DIR:
293 	    if (!(newdir=access(ofname,F_OK)) && useattr) {
294 		if (!yesno("\nRemake directory %s ? (y/n/a) ",ofname)) break;
295 	    }
296 	    if (!quiet) {
297 		printf("\nMaking    DIR        %s",ofname);
298 		backstep(strlen(ofname)+8);
299 	    }
300 	    if (newdir) {
301 		if (mkdir(ofname,DEF_DIRATTR)<0) error(0,ERR_MKDIR,ofname);
302 	    }
303 	    if (touch) md_setft(ofname,md_systime());
304 	    else md_setft(ofname,hd->time);
305 	    if (useattr) md_setfattrs(ofname);
306 	    if (!quiet) printf("DONE");
307 	    break;
308 	  default:
309 	    of=open(ofname,O_WRONLY|O_BINARY|O_CREAT|O_EXCL,DEF_FILEATTR);
310 	    if (of<0) {
311 		if (!yesno("\nOverwrite file %s ? (y/n/a) ",ofname)) continue;
312 		if (remove(ofname)<0) {
313 		    error(0,ERR_REMOVE,ofname);
314 		    continue;
315 		}
316 		if ((of=open(ofname,O_WRONLY|O_BINARY|O_CREAT|O_EXCL,
317 			     DEF_FILEATTR))<0) error(0,ERR_OPEN,ofname);
318 	    }
319 	    setinput(arcfile,0,arcname);
320 	    if (quiet) setoutput(of,CRCCALC,ofname);
321 	    else setoutput(of,CRCCALC|PROGDISP,ofname);
322 	    if (!quiet) {
323 		printf("\nUnpacking %s        %s",
324 		       method[hd->type].name,ofname);
325 		backstep(strlen(ofname)+8);
326 	    }
327 	    fflush(stdout);
328 	    if (hd->olen!=0) {
329 		totalsize=hd->olen;
330 		cumark=cu_add(CU_FUNC,method[hd->type].cleanup);
331 		cu_add(CU_RMFILE|CU_CANRELAX,ofname,of);
332 		(*method[hd->type].decode)();
333 		cu_relax(cumark);
334 		cu_do(cumark);
335 	    }
336 	    else if (!quiet) printf("100 %%");
337 	    fflush(stdout);
338 	    close(of);
339 	    if (hd->crc!=getcrc()) error(0,ERR_CRC,NULL);
340 	    if (touch) md_setft(ofname,md_systime());
341 	    else md_setft(ofname,hd->time);
342 	    if (useattr) md_setfattrs(ofname);
343 	    break;
344 	}
345     } while ((hd=arc_seek())!=NULL);
346     if (!quiet) printf("\n");
347 }
348 
do_test(void)349 static void do_test(void) {
350 
351     Fheader *hd;
352     char *ofname;
353     void *cumark;
354 
355     arc_reset();
356     if ((hd=arc_seek())==NULL) error(1,ERR_NOFILES);
357     do {
358 	ofname=md_tomdpath(fullpath(hd->path,hd->name));
359 	switch(hd->type) {
360 	  case M_DIR:
361 	    if (!quiet) printf("\nTesting DIR DONE   %s",ofname);
362 	    break;
363 	  case M_SPECIAL:
364 	    if (!quiet) printf("\nTesting SPC DONE   %s",ofname);
365 	    break;
366 	  default:
367 	    setinput(arcfile,0,arcname);
368 	    if (quiet) setoutput(-1,CRCCALC,"none ??");
369 	    else setoutput(-1,CRCCALC|PROGDISP,"none ??");
370 	    if (!quiet) {
371 		printf("\nTesting %s        %s",method[hd->type].name,ofname);
372 		backstep(strlen(ofname)+8);
373 		fflush(stdout);
374 	    }
375 	    if (hd->olen!=0) {
376 		totalsize=hd->olen;
377 		cumark=cu_add(CU_FUNC,method[hd->type].cleanup);
378 		(*method[hd->type].decode)();
379 		cu_do(cumark);
380 	    }
381 	    else if (!quiet) printf("100 %%");
382 	    fflush(stdout);
383 	    if (hd->crc!=getcrc()) error(0,ERR_CRC,NULL);
384 	    break;
385 	}
386     } while ((hd=arc_seek())!=NULL);
387     if (!quiet) printf("\n");
388 }
389 
do_delete(void)390 static void do_delete(void) {
391 
392     Fheader *hd;
393 
394     arc_reset();
395     if ((hd=arc_seek())==NULL) error(1,ERR_NOFILES);
396     do {
397 	if (!quiet) {
398 	    printf("\nDeleting %s",md_tomdpath(fullpath(hd->path,hd->name)));
399 	    fflush(stdout);
400 	}
401 	arc_delete();
402     } while ((hd=arc_seek())!=NULL);
403     if (!quiet) printf("\n");
404 }
405 
adddir(char * path,char * name)406 static int adddir(char *path, char *name) {
407 
408     char *fullname;
409 
410     fullname=md_pconcat(0,path,name);
411     if (!quiet) {
412 	printf("\nSaving  DIR          %s",fullname);
413 	backstep(strlen(fullname)+10);
414 	fflush(stdout);
415     }
416     arc_newfile(usepath?path:"",name);
417     if (arc_adddir()){
418 	if (!quiet) {
419 	    printf(" DONE");
420 	    fflush(stdout);
421 	}
422 	if (move) cu_add(CU_RMDIR,fullname);
423 	free(fullname);
424 	return 1;
425     }
426     else {
427 	free(fullname);
428 	return 0;
429     }
430 }
431 
addspecial(char * path,char * name)432 static int addspecial(char *path, char *name) {
433 
434     char *fullname;
435 
436     fullname=md_pconcat(0,path,name);
437     if (!quiet) {
438 	printf("\nSaving  SPC          %s",fullname);
439 	backstep(strlen(fullname)+10);
440 	fflush(stdout);
441     }
442     arc_newfile(usepath?path:"",name);
443     if (arc_addspecial(fullname)) {
444 	if (!quiet) {
445 	    printf(" DONE");
446 	    fflush(stdout);
447 	}
448 	if (move) {
449 	    if (remove(fullname)<0) {
450 		error(0,ERR_REMOVE,fullname);
451 	    }
452 	}
453 	free(fullname);
454 	return 1;
455     }
456     else {
457 	free(fullname);
458 	return 0;
459     }
460 }
461 
addfile(char * path,char * name)462 static int addfile(char *path, char *name) {
463 
464     char *fullname;
465     int i,best,inf;
466     U32B bestsize;
467     void *cumark;
468 
469     bestsize=totalsize=md_curfilesize();
470     best=M_CPY;
471     arc_newfile(usepath?path:"",name);
472     fullname=md_pconcat(0,path,name);
473     if ((inf=open(fullname,O_RDONLY|O_BINARY))<0) {
474 	error(0,ERR_OPEN,fullname);
475 	free(fullname);
476 	return 0;
477     }
478     if (!quiet) printf("\n");
479     setoutput(arcfile,0,arcname);
480     if (quiet) setinput(inf,CRCCALC,fullname);
481     else setinput(inf,CRCCALC|PROGDISP,fullname);
482     if (totalsize) {
483 	for (i=0;;) {
484 	    arc_trynext();
485 	    cumark=cu_add(CU_FUNC,method[metqueue[i]].cleanup);
486 	    if (!quiet) {
487 		printf("\rPacking %s          %s",
488 		       method[metqueue[i]].name,fullname);
489 		backstep(strlen(fullname)+10);
490 		fflush(stdout);
491 	    }
492 	    (*method[metqueue[i]].encode)();
493 	    cu_do(cumark);
494 	    if (ocnt<bestsize || metqueue[i]==M_CPY) {
495 		arc_accept(best=metqueue[i]);
496 		bestsize=ocnt;
497 	    }
498 	    if (metqueue[++i]==M_UNK ||
499 		(metqueue[i]==M_CPY && bestsize!=totalsize)) break;
500 	    setoutput(arcfile,0,arcname);
501 	    lseek(inf,0,SEEK_SET);
502 	    if (quiet) setinput(inf,CRCCALC,fullname);
503 	    else setinput(inf,CRCCALC|PROGDISP,fullname);
504 	}
505     }
506     else {
507 	if (!quiet) {
508 	    printf("\rPacking CPY          %s",fullname);
509 	    backstep(strlen(fullname)+10);
510 	    fflush(stdout);
511 	}
512 	arc_accept(M_CPY);
513     }
514     if (!quiet) {
515 	backstep(5);
516 	printf("%s %3d.%d %%",method[best].name,
517 	       (bestsize==0?100:(int)(bestsize*100/totalsize)),
518 	       (bestsize==0?0:(int)((bestsize*1000/totalsize)%10)));
519     }
520     fflush(stdout);
521     arc_addfile();
522     if (move) {
523 	if (remove(fullname)<0) {
524 	    error(0,ERR_REMOVE,fullname);
525 	}
526     }
527     free(fullname);
528     close(inf);
529     return 1;
530 }
531 
addtest(char * path,char * name)532 static int addtest(char* path, char* name) {
533 
534     return 1;
535 }
536 
freshentest(char * path,char * name)537 static int freshentest(char *path, char *name) {
538 
539     Fheader *hd;
540     char *ptab[1];
541 
542     ptab[0]=fullpath(md_tohapath(path),name);
543     patterns=ptab;
544     patcnt=1;
545     arc_reset();
546     if ((hd=arc_seek())==NULL || hd->time>=md_curfiletime()) return 0;
547     return 1;
548 }
549 
updatetest(char * path,char * name)550 static int updatetest(char *path, char *name) {
551 
552     Fheader *hd;
553     char *ptab[1];
554 
555     ptab[0]=fullpath(md_tohapath(path),name);
556     patterns=ptab;
557     patcnt=1;
558     arc_reset();
559     if ((hd=arc_seek())!=NULL && hd->time>=md_curfiletime()) return 0;
560     return 1;
561 }
562 
addindir(char * path,char * pattern)563 static int addindir(char *path, char *pattern) {
564 
565     int found;
566     char *newpath;
567     DIR *dir;
568     struct dirent *ent;
569     void *cumark;
570 
571     found=0;
572     if (*path) dir=opendir(path);
573     else dir=opendir(".");
574     if (dir==NULL) {
575 	error(0,ERR_DIROPEN,path);
576 	return found;
577     }
578     cumark=cu_getmark();
579     while ((ent=readdir(dir))!=NULL) {
580 	switch(md_filetype(path,md_strcase(ent->d_name))) {
581 	  case T_DIR:
582 	    if (savedir && addthis(path,ent->d_name))
583 	      found|=adddir(path,ent->d_name);
584 	    if (!recurse) break;
585 	    newpath=md_pconcat(1,path,ent->d_name);
586 	    found|=addindir(newpath,pattern);
587 	    free(newpath);
588 	    break;
589 	  case T_SPECIAL:
590 	    if (!md_namecmp(pattern,ent->d_name) || !special) break;
591 	    if (addthis(path,ent->d_name)) found|=addspecial(path,ent->d_name);
592 	    break;
593 	  case T_REGULAR:
594 	    if (!md_namecmp(pattern,ent->d_name)) break;
595 	    if (addthis(path,ent->d_name)) found|=addfile(path,ent->d_name);
596 	    break;
597 	}
598     }
599     closedir(dir);
600     cu_do(cumark);
601     return found;
602 }
603 
do_add(void)604 static void do_add(void) {
605 
606     int i,found;
607     char *path,*pattern;
608 
609     for (found=i=0;i<patcnt;++i) {
610 	path=md_strippath(patterns[i]);
611 	pattern=md_stripname(patterns[i]);
612 	found|=addindir(md_strcase(path),md_strcase(pattern));
613     }
614     if (!quiet) {
615 	if (found) printf("\n");
616 	else printf("\nNothing to do\n");
617 	fflush(stdout);
618     }
619 }
620 
switchparse(char * s,char * valid)621 static void switchparse(char *s, char *valid) {
622 
623     int i;
624 
625     while (*s) {
626 	if (strchr(valid,tolower(*s))==NULL) error(1,ERR_INVSW,*s);
627 	switch (tolower(*s)) {
628 	  case 'q':
629 	    quiet=1;
630 	    break;
631 	  case 'y':
632 	    yes=1;
633 	    break;
634 	  case 'f':
635 	    fulllist=1;
636 	    break;
637 	  case 'a':
638 	    useattr=1;
639 	    break;
640 	  case 't':
641 	    touch=1;
642 	    break;
643 	  case 'r':
644 	    recurse=1;
645 	    break;
646 	  case 's':
647 	    special=1;
648 	    break;
649 	  case 'd':
650 	    savedir=1;
651 	    break;
652 	  case 'e':
653 	    usepath=0;
654 	    break;
655 	  case 'm':
656 	    move=1;
657 	    break;
658 	  case '0':
659 	  case '1':
660 	  case '2':
661 	    for (*s-='0',i=0;i<M_UNK;++i) {
662 		if (metqueue[i]==*s) break;
663 		else if (metqueue[i]==M_UNK) {
664 		    metqueue[i]=*s;
665 		    metqueue[i+1]=M_UNK;
666 		    break;
667 		}
668 	    }
669 	    break;
670 	  default :
671 	    error(1,ERR_INVSW,NULL,*s);
672 	    break;
673 	}
674 	++s;
675     }
676     if (!quiet) banner();
677 }
678 
fix_methods(void)679 static void fix_methods(void) {
680 
681     int i;
682 
683     if (metqueue[0]==M_UNK) {
684 	metqueue[0]=M_ASC;
685 	metqueue[1]=M_CPY;
686 	metqueue[2]=M_UNK;
687     }
688     else {
689 	for (i=0;metqueue[i]!=M_UNK;++i) {
690 	    if (metqueue[i]==M_CPY) break;
691 	}
692 	if (metqueue[i]==M_UNK) {
693 	    metqueue[i]=M_CPY;
694 	    metqueue[i+1]=M_UNK;
695 	}
696     }
697 }
698 
parse_cmds(char * cs[])699 static void (*parse_cmds(char *cs[]))(void) {
700 
701     void (*cmd)(void)=do_list;
702 
703     switch(tolower(cs[0][0])) {
704       case ADD:
705 	switchparse(cs[0]+1,"sdqemr012");
706 	if (!usepath) savedir=0;
707 	arc_open(cs[1],ARC_OLD|ARC_NEW);
708 	addthis=addtest;
709 	cmd=do_add;
710 	fix_methods();
711 	break;
712       case FRESHEN:
713 	switchparse(cs[0]+1,"sdqemr012");
714 	if (!usepath) savedir=0;
715 	arc_open(cs[1],ARC_OLD);
716 	addthis=freshentest;
717 	cmd=do_add;
718 	fix_methods();
719 	sloppymatch=0;
720 	break;
721       case UPDATE:
722 	switchparse(cs[0]+1,"sdqemr012");
723 	if (!usepath) savedir=0;
724 	arc_open(cs[1],ARC_OLD|ARC_NEW);
725 	addthis=updatetest;
726 	cmd=do_add;
727 	fix_methods();
728 	sloppymatch=0;
729 	break;
730       case EXTRACT:
731 	usepath=0;
732       case PEXTRACT:
733 	switchparse(cs[0]+1,"aqty");
734 	arc_open(cs[1],ARC_OLD|ARC_RDO);
735 	cmd=do_extract;
736 	break;
737       case TEST:
738 	switchparse(cs[0]+1,"qe");
739 	arc_open(cs[1],ARC_OLD|ARC_RDO);
740 	cmd=do_test;
741 	break;
742       case LIST:
743 	switchparse(cs[0]+1,"f");
744 	arc_open(cs[1],ARC_OLD|ARC_RDO);
745 	cmd=do_list;
746 	break;
747       case DELETE:
748 	switchparse(cs[0]+1,"qe");
749 	arc_open(cs[1],ARC_OLD);
750 	cmd=do_delete;
751 	break;
752       case INFO:
753 	info();
754 	break;
755       default:
756 	usage(ERR_UNKNOWN);
757     }
758     return cmd;
759 }
760 
main(int argc,char * argv[])761 int main(int argc, char *argv[]) {
762 
763     void (*command)(void);
764 
765     myname=argv[0];
766     md_init();
767     if (argc<2) usage(ERR_UNKNOWN);
768     if (argc==4 && strcmp(argv[1],"MAKEINFO")==0) makeinfo(argv[2],argv[3]);
769     command=parse_cmds(argv+1);
770     testsizes();
771     switch (argc) {
772       case 2:
773 	if (command!=info) usage(ERR_UNKNOWN);
774 	break;
775       case 3:
776 	patterns=defpat;
777 	patcnt=1;
778 	break;
779       default :
780 	patterns=argv+3;
781 	patcnt=argc-3;
782 	break;
783     }
784     command();
785     cu_do(NULL);
786     return lasterror;
787 }
788 
789 
790