/* */ /* UUARC V1.3 04/10/93 */ /* J.G.Brandon */ /* */ /* */ /* Archiving system based on the 'UU' encoding/decoding */ /* algorythms. */ /* */ /* Written in 'C' for the public domain using NorthC V1.3 */ /* on a Commodore Amiga. Ought to compile/run under most */ /* compilers/environments. */ /* */ /* No system specific commands/libraries/includes/headers */ /* used to make 'C' source portable. The only system */ /* specific part of the program is the pre-processor */ /* defined function to identify 'directory separator' */ /* characters, used to separate file-names from their */ /* paths. */ /* */ /* If required, comment the next line to stop checksums being added */ /* (This only effects encoding output, decoding will still check */ /* checksums if checksums are present) */ #define ADDCHECK /* Title/version definitions */ #define TITLE "UUArc" #define AUTHOR "Miss J.G.Brandon" #define VERSION 1 #define REVISION 3 #define TITLESTR "\n%s Version %d.%d by %s %s.\n\n" #define TITLESTRPAR TITLE, VERSION, REVISION, AUTHOR, __DATE__ /* Required standard libraries */ #include #include #include #include #include /* When are standard includes not standard includes? */ /* When they miss out definitions that should be there. */ /* I'll name no names; but it's a very popular compiler... */ /* (VERY naughty, as it sets the _STDC_ flag to indicate */ /* that it is completely ANSI standard conforming; */ /* and these are just the ones missed out that this */ /* program needs, there are many more.) */ #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif #ifndef EXIT_FAILURE #define EXIT_FAILURE 20 #endif #ifndef L_tmpnam #define L_tmpnam 0x0FF #endif /* Define conditional close function; attempts to close a file indicated */ /* by the supplied file pointer if the pointer is not null */ #define COND_CLOSE(fptr) if (fptr != NULL) fclose(fptr) /* Define 'directory-separator' identifier - system specific unfortunately */ #define DIR_CHAR(c) ((c == ':') || (c == '/')) /* Define uuencoding/decoding/checking functions */ #define VALIDATE(c) ((c < 0x020) || (c > 0x060)) #define DECODE(c) ((c - 0x020) & 0x03F) #define ENCODE(c) (c ? ((c & 0x03F) + 0x020) : 0x060) /* Definitions required by program */ #define LISTCOM 'l' #define TESTCOM 't' #define EXTRACTCOM 'x' #define DELETECOM 'd' #define ADDCOM 'a' #define MOVEOPT 'm' #define PATHOPT 'p' #define BUFSIZE 0x0FF #define ENCODESIZE 45 #define DEFAULTMODE 0744 #define NOFILE 0 #define FOUNDFILE 1 #define DATALINE 0 #define BEGINLINE 1 #define ENDLINE 2 #define SIZELINE 3 #define BADLINE 4 #define STRIPPATH 0 #define LEAVEPATH 1 #define LEAVEFILE 0 #define MOVEFILE 1 #define SHOWUSAGE 0 #define NOUSAGE 1 #define DUNNO 0 #define YES 1 #define NO 2 #define CHECKSIZE 64 /* If this is ANSI 'C', do function prototyping */ #ifdef _STDC_ char *prname(char *, int); int anycasecmp(char *, char *) int filecmp(char *, char *[], int) void pr_head(char *) void pr_tail(void) void operout(char *, int) void succout(char *, int) void errsout(long) void usage(FILE *) void cleanexit(int) void errorexit(char *, int) void abnormalexit(int) int listarc(void) int deletearc(char *, char *[], int) int extractarc(char, char *[], int) int fileread(char *) int addarc(char *[], int) #endif /* Globally accessable archive, file and temporary file details */ FILE *arc_fptr = NULL, *file_fptr = NULL, *temp_fptr = NULL; char temp_name[L_tmpnam] = ""; /* Globally accessable number of errors counter */ long numerrors = 0; /* Globally accessable path strip flag */ int pathflag = STRIPPATH; /* Globally accessable move files flag */ int moveflag = LEAVEFILE; /* Strip path name from a filename if required */ char *prname(filename, flag) char *filename; int flag; { char *stripname; /* If full path has been requested, leave it in */ if (flag == LEAVEPATH) return filename; /* Hunt from left to right for a path-indicator character */ for(stripname = filename+strlen(filename); ((stripname > filename) && (!DIR_CHAR(*stripname))); stripname--) ; /* If path-indicator character found, increment pointer to */ /* point to start of file name */ if DIR_CHAR(*stripname) stripname++; /* Return pointer to filename without path extension */ return stripname; } /* String comparison, ignoring case - result same as strcmp */ int anycasecmp(string1, string2) char *string1, *string2; { int i; for (i = 0; toupper(string1[i]) == toupper(string2[i]); i++) if (string1[i] == '\0') return 0; return toupper(string1[i]) - toupper(string2[i]); } /* Check filename against list of given filenames */ int filecmp(filename, argv, argc) char *filename; char *argv[]; int argc; { int targc; int filematch = NOFILE; if (argc == 3) filematch = FOUNDFILE; else for (targc = 3; targc < argc; targc++) if (anycasecmp(prname(filename, pathflag), prname(argv[targc], pathflag)) == 0) filematch = FOUNDFILE; return filematch; } /* Print archive header information */ void pr_head(archive) char *archive; { printf(" archive '%s':\n", archive); printf("---------------------------------------------\n"); } /* Print archive tail information */ void pr_tail() { printf("---------------------------------------------\n"); } /* Outputs details of an operation, taking plurals into account */ void operout(operstr,numfiles) char *operstr; int numfiles; { if (numfiles == 0) printf("No "); else printf("%d ",numfiles); if (numfiles != 1) printf("files "); else printf("file "); printf("%s.\n",operstr); } /* Outputs details of success of an operation */ void succout(operstr, numerrs) char *operstr; int numerrs; { if (numerrs == 0) printf("%s successful.\n\n",operstr); else fprintf(stderr,"%s not entirely successful.\n\n",operstr); } /* Outputs details of errors, taking plurals into account */ void errsout(numerrs) long numerrs; { if (numerrs != 0) { fprintf(stderr, "%d error", numerrs); if (numerrs != 1) fprintf(stderr, "s.\n"); else fprintf(stderr, ".\n"); } } /* Sends details of command usage to output stream 'ostrm' */ void usage(ostrm) FILE *ostrm; { fprintf(ostrm, "\nUSAGE:\t%s -[%c][%c] [ ... ]\n", TITLE, PATHOPT, MOVEOPT); fprintf(ostrm, "\nWhere is one of-\n"); fprintf(ostrm, "\t%c = List contents of .\n", LISTCOM); fprintf(ostrm, "\t%c = Test contents of .\n", TESTCOM); fprintf(ostrm, "\t%c = Add to .\n", ADDCOM); fprintf(ostrm, "\t%c = Extract from .\n", EXTRACTCOM); fprintf(ostrm, "\t (All files if no given.)\n"); fprintf(ostrm, "\t%c = Delete from .\n", DELETECOM); fprintf(ostrm, "\t (All files if no given.)\n"); fprintf(ostrm, "\nIf included after the archiver command, the '%c' option\n", PATHOPT); fprintf(ostrm, "specifies full path names to be considered; otherwise path\n"); fprintf(ostrm, "names will be ignored.\n"); fprintf(ostrm, "\nIf included after an add/extract archiver command, the '%c'\n", MOVEOPT); fprintf(ostrm, "option specifies files to be moved from source, i.e. source\n"); fprintf(ostrm, "files will be deleted; otherwise they are left as is.\n"); fprintf(ostrm, "\nIf applicable, must include the '.uue' extension.\n\n"); } /* A 'clean' exit routine; closes any open files, deletes the temporary */ /* file if used, and exits with return code 'retcode' */ void cleanexit(retcode) int retcode; { COND_CLOSE(arc_fptr); COND_CLOSE(file_fptr); COND_CLOSE(temp_fptr); if (strcmp(temp_name,"") != 0) remove(temp_name); exit(retcode); } /* Exit routine for errors; displays error 'errorstr' and command usage */ /* to the standard error output stream, then 'cleanexit's with a failure */ /* return code */ void errorexit(errorstr, usageflag) char *errorstr; int usageflag; { fprintf(stderr, "\n\aERROR: %s.\n\n", errorstr); if (usageflag == SHOWUSAGE) usage(stderr); cleanexit(EXIT_FAILURE); } /* Deal with abnormal program termination */ void abnormalexit(sig) int sig; { fprintf(stderr, "\n\aERROR: Program aborted.\n\n"); cleanexit(EXIT_FAILURE); } /* List files in the opened archive */ int listarc() { char buffer[BUFSIZE], filestr[BUFSIZE]; int filemode, numfiles = 0; /* Go through archive until error/end-of-file, listing any files found */ while(fgets(buffer, BUFSIZE, arc_fptr) != NULL) { if (sscanf(buffer, "begin %o %s", &filemode, filestr) == 2) { numfiles++; printf("Found - %s\n", filestr); } } return numfiles; } /* Delete files from an archive */ int deletearc(arcname, argv, argc) char *arcname; char *argv[]; int argc; { char buffer[BUFSIZE], filestr[BUFSIZE], arcfile[BUFSIZE]; int filemode, numdel = 0, fileflag = NOFILE; int deleteflag = NOFILE, lastdelete = NOFILE; int linetype, lastline = DATALINE; long expectedsize; /* Open archive for input, and a temporary file for output/input */ if (arc_fptr == NULL) if ((arc_fptr = fopen(arcname, "r")) == NULL) errorexit("Can't open archive for input", SHOWUSAGE); if ((temp_fptr = fopen((tmpnam(temp_name)), "w+")) == NULL) errorexit("Can't open temporary file", NOUSAGE); /* Deal with each line in archive until end-of-file/error */ while(fgets(buffer, BUFSIZE, arc_fptr) != NULL) { /* Signal a data line by default */ linetype = DATALINE; /* Deal with a begin statement */ if (sscanf(buffer, "begin %o %s", &filemode, filestr) == 2) { /* Indicate command line */ linetype = BEGINLINE; /* If already dealing with a file, error - missing end */ if (fileflag == FOUNDFILE) { fprintf(stderr, "Missing 'end' - %s\n", arcfile); numerrors++; printf("Deleted - %s\n", arcfile); numdel++; } /* Remember file name, signal that a file's been found */ strcpy(arcfile, filestr); fileflag = FOUNDFILE; /* Store previous delete status */ lastdelete = deleteflag; /* Signal whether or not file is to be deleted */ deleteflag = filecmp(arcfile, argv, argc); } /* Deal with a size statement */ if (sscanf(buffer, "size %d", &expectedsize) == 1) { /* Indicate command line */ linetype = SIZELINE; /* A size statement is only expected after an end statement */ if (lastline != ENDLINE) { fprintf(stderr, "Misplaced 'size' - %s\n", arcfile); numerrors++; } } /* Copy lines not to be deleted from archive to temporary file */ if (!((deleteflag == FOUNDFILE) || ((lastline == ENDLINE) && (linetype == SIZELINE) && (lastdelete == FOUNDFILE)))) if (fputs(buffer, temp_fptr) == EOF) errorexit("File error writing to temporary file", NOUSAGE); /* Deal with an end statement */ if (strncmp(buffer, "end", 3) == 0) { /* Indicate command line */ linetype = ENDLINE; /* An end statement; so make sure we had a start statement */ if (fileflag == FOUNDFILE) { /* Signal that file has been processed, and increment */ /* number of files deleted counter if necessary */ if (deleteflag == FOUNDFILE) { printf("Deleted - %s\n", arcfile); numdel++; } else printf("Skipped - %s\n", arcfile); } else { /* If no relevant start statement, error - missing begin */ fprintf(stderr, "Missing 'begin' - ?\n"); numerrors++; } /* Store previous delete status */ lastdelete = deleteflag; /* Clear deletion and processing a file */ deleteflag = NOFILE; fileflag = NOFILE; } lastline = linetype; } /* If we hit end of archive file whilst still expecting data, error */ if (fileflag != NOFILE) { fprintf(stderr, "Missing (final) 'end' - %s\n", arcfile); numerrors++; printf("Deleted - %s\n", arcfile); numdel++; } /* Go back to start of temporary file */ rewind(temp_fptr); /* Close archive file, and re-open it (cleared) for output */ COND_CLOSE(arc_fptr); if ((arc_fptr = fopen(arcname, "w")) == NULL) errorexit("Can't open archive for output", SHOWUSAGE); /* Copy contents of temporary file to archive file */ while(fgets(buffer, BUFSIZE, temp_fptr) != NULL) if (fputs(buffer, arc_fptr) == EOF) errorexit("File error writing to archive file", NOUSAGE); /* Return number of files deleted */ return numdel; } /* Extract/Test files in the opened archive */ int extractarc(extcom, argv, argc) char extcom; char *argv[]; int argc; { char buffer[BUFSIZE], filestr[BUFSIZE], arcfile[BUFSIZE], outstr[BUFSIZE]; int ic1, ic2, ic3, ic4; int filemode, numfiles = 0, fileflag = NOFILE; unsigned int checksum; int checkflag; int linetype, lastline = DATALINE, numdata, datapos, linelen; long filesize = 0, expectsize; /* Go through archive until error/end-of-file */ while(fgets(buffer, BUFSIZE, arc_fptr) != NULL) { /* As a default, assume line to be a line of UUencoded data */ linetype = DATALINE; /* Deal with a begin statement */ if (sscanf(buffer, "begin %o %s", &filemode, filestr) == 2) { /* Flag line as being a command line */ linetype = BEGINLINE; /* If already dealing with a file, error - missing end */ if (fileflag == FOUNDFILE) { fprintf(stderr, "Missing 'end' - %s\n", arcfile); numerrors++; COND_CLOSE(file_fptr); file_fptr = NULL; /* If just testing archive, indicate that file has been */ /* processed and increment number of files counter */ if (extcom == TESTCOM) { printf("%21d - %s\n", filesize, arcfile); numfiles++; } else { /* If extracting, indicate that file has been */ /* processed and increment number of files counter */ /* if necessary */ if (file_fptr != NULL) { printf("%21d - %s\n", filesize, arcfile); numfiles++; } else printf("Skipped - %s\n", arcfile); } } /* Remember file name, signal that a file's been found, */ /* set file size counter to 0, and reset checksum status */ strcpy(arcfile, filestr); fileflag = FOUNDFILE; filesize = 0; checkflag = DUNNO; /* If not just testing the archive, open file for output */ if ((extcom != TESTCOM) && (filecmp(arcfile, argv, argc) == FOUNDFILE)) if ((file_fptr = fopen(prname(arcfile, pathflag), "w")) == NULL) { fprintf(stderr, "Can't open for output - %s\n", prname(arcfile, pathflag)); numerrors++; } } /* Deal with an end statement */ if (strncmp(buffer, "end", 3) == 0) { /* Flag line as being a command line */ linetype = ENDLINE; /* An end statement; so make sure we had a start statement */ if (fileflag == FOUNDFILE) { /* If just testing archive, indicate that file has been */ /* processed and increment number of files counter */ fileflag = NOFILE; if (extcom == TESTCOM) { printf("%21d - %s\n", filesize, arcfile); numfiles++; } else { /* If extracting, indicate that file has been */ /* processed and increment number of files counter */ /* if necessary */ if (file_fptr != NULL) { printf("%21d - %s\n", filesize, arcfile); numfiles++; } else printf("Skipped - %s\n", arcfile); } } else { /* If no relevant start statement, error - missing begin */ fprintf(stderr, "Missing 'begin' - ?\n"); numerrors++; } COND_CLOSE(file_fptr); file_fptr = NULL; } /* Deal with a size statement */ if (sscanf(buffer, "size %d", &expectsize) == 1) { /* Flag line as being a command line */ linetype = SIZELINE; /* A size statement is only expected after an end statement */ if (lastline != ENDLINE) { fprintf(stderr, "Misplaced 'size' - %s\n", arcfile); numerrors++; } else { /* Check the size of the file was as expected */ if ((filesize != expectsize) && ((extcom == TESTCOM) || (file_fptr != NULL))) { fprintf(stderr, "File size wrong - %s\n", arcfile); numerrors++; } } } /* Deal with a line of data */ if (linetype == DATALINE) { /* Only want data lines within begin/end statements */ /* And only want to bother decoding file if required */ if ((fileflag == FOUNDFILE) && ((extcom == TESTCOM) || (file_fptr != NULL))) { /* Strip any white-space characters from end of line */ /* that aren't pure space characters */ if ((datapos = strlen(buffer)-1) >= 0) while (isspace(buffer[datapos]) && (buffer[datapos] != ' ') && (datapos >= 0)) { buffer[datapos] = '\0'; datapos--; } linelen=strlen(buffer); /* If any data is in the line */ if (linelen > 0) { /* Reset line checksum */ checksum = 0; /* Error if any characters not within limits */ for(datapos = 0; ((datapos < linelen) && (linetype == DATALINE)); datapos++) if VALIDATE(buffer[datapos]) { fprintf(stderr, "Corrupt byte in line - %s\n", arcfile); numerrors++; linetype = BADLINE; } /* Attempt to decode line */ if (linetype == DATALINE) { /* Fetch total number of bytes to written out */ numdata = DECODE(*buffer); /* Decode relevant number of bytes from archive */ for(datapos = 1; (((datapos+numdata)0)); datapos+=4) { ic1 = DECODE(buffer[datapos]); ic2 = DECODE(buffer[datapos+1]); ic3 = DECODE(buffer[datapos+2]); ic4 = DECODE(buffer[datapos+3]); outstr[numdata+2] = ic1 << 2 | ic2 >> 4; outstr[numdata+1] = ic2 << 4 | ic3 >> 2; outstr[numdata] = ic3 << 6 | ic4 ; checksum = ( checksum + outstr[numdata+2] + outstr[numdata+1] + outstr[numdata] ) % CHECKSIZE; numdata-=3; } /* Error if not enough data in line */ if ((numdata > 0) || ((checkflag == YES) && ((linelen-datapos) < 1))) { fprintf(stderr, "Data line too short - %s\n", arcfile); numerrors++; linetype = BADLINE; } /* If line is okay, and checksums have been */ /* present, then analyse checksum */ if ((checkflag == YES) && (linetype == DATALINE)) { if (checksum != DECODE(buffer[datapos])) { fprintf(stderr, "Checksum error - %s\n", arcfile); numerrors++; linetype = BADLINE; } } /* Error if too much data in line - allow extra */ /* pure space characters though */ if (((checkflag != NO) && ((linelen-datapos) > 2)) || ((checkflag == NO) && ((linelen-datapos) > 1))) { if (checkflag == NO) datapos++; else datapos=datapos + 2; while((datapos 0) { if (fputc(outstr[numdata+2], file_fptr) == EOF) errorexit("File error writing file", NOUSAGE); numdata--; } } } else { fprintf(stderr, "No data, empty line - %s\n", arcfile); numerrors++; } } } lastline = linetype; } /* If we hit end of archive file whilst still expecting data, error */ if (fileflag != NOFILE) { fprintf(stderr, "Missing (final) 'end' - %s\n", arcfile); numerrors++; /* If just testing archive, indicate that file has been */ /* processed and increment number of files counter */ if (extcom == TESTCOM) { printf("%21d - %s\n", filesize, arcfile); numfiles++; } else { /* If extracting, indicate that file has been */ /* processed and increment number of files counter */ /* if necessary */ if (file_fptr != NULL) { printf("%21d - %s\n", filesize, arcfile); numfiles++; } else printf("Skipped - %s\n", arcfile); } } /* Return number of files extracted */ return numfiles; } /* Read from file, dealing with with any errors */ int fileread(buf) char *buf; { int numread; /* Read data into buffer */ numread = fread(buf, sizeof(char), ENCODESIZE, file_fptr); /* If an error occured, exit cleanly with an error */ if ferror(file_fptr) errorexit("File error reading file", NOUSAGE); /* Return number of bytes read */ return numread; } /* Add files specified to the opened archive */ int addarc(argv, argc) char *argv[]; int argc; { char buffer[BUFSIZE], outstr[BUFSIZE]; int ic1, ic2, ic3, oc1, oc2, oc3, oc4; int inpos, outpos, targc, numfiles = 0, n; long filesize; #ifdef ADDCHECK unsigned int checksum; #endif /* Repeat for each filename given */ for (targc = 3; targc < argc; targc++) { /* Reset filesize counter */ filesize = 0; /* Open file for input */ if ((file_fptr = fopen(argv[targc], "r")) == NULL) { fprintf(stderr, "Can't open for input - %s\n", argv[targc]); numerrors++; } else { /* Write begin statement */ fprintf(arc_fptr, "\nbegin %o %s\n", DEFAULTMODE, prname(argv[targc], pathflag)); /* Read and encode from file whilst data is available */ do { n = fileread(buffer); /* Encode number of bytes read into first character */ /* in line */ *outstr = ENCODE(n); #ifdef ADDCHECK /* Reset checksum */ checksum = 0; #endif /* Encode data */ outpos = 1; for(inpos = 0; inpos < n; inpos += 3) { ic1 = buffer[inpos]; ic2 = buffer[inpos+1]; ic3 = buffer[inpos+2]; oc1 = ic1 >> 2; oc2 = (ic1 << 4) & 0x030 | (ic2 >> 4) & 0x00F; oc3 = (ic2 << 2) & 0x03C | (ic3 >> 6) & 0x003; oc4 = ic3 & 0x03F; outstr[outpos] = ENCODE(oc1); outstr[outpos+1] = ENCODE(oc2); outstr[outpos+2] = ENCODE(oc3); outstr[outpos+3] = ENCODE(oc4); outpos += 4; #ifdef ADDCHECK checksum = ( checksum + ic1 + ic2 + ic3 ) % CHECKSIZE; #endif } /* Add termination to output string */ #ifdef ADDCHECK outstr[outpos] = ENCODE(checksum); outpos++; #endif outstr[outpos] = '\n'; outstr[outpos+1] = '\0'; /* Write data into archive */ if (fputs(outstr, arc_fptr) == EOF) errorexit("File error writing to archive file", NOUSAGE); filesize += n; } while (n > 0); /* Write end statement */ fprintf(arc_fptr, "end\n"); fprintf(arc_fptr, "size %d\n", filesize); /* Indicate that file has been processed */ printf("%21d - %s\n", filesize, prname(argv[targc], pathflag)); numfiles++; /* Close file */ COND_CLOSE(file_fptr); file_fptr = NULL; /* In the case of a move command, delete file */ if (moveflag == MOVEFILE) remove(argv[targc]); } } return numfiles; } /* Main entry point, taking standard "main" style parameters */ void main(argc, argv) int argc; char *argv[]; { char command[BUFSIZE]; int numfiles, numdel, comlen, compos; /* Trap program interruption, to exit cleanly */ /* A 'certain' compiler gives warnings -the code */ /* is correct, the compiler is wrong (sorry, but */ /* according to the K&R book, and just about every */ /* other compiler - a signal handler is supposed */ /* supposed to return void, _NOT_ int) - program */ /* will still work, presumably to just ignore the */ /* compiler warnings in this curcumstance is okay */ #ifdef SIGABRT signal(SIGABRT, abnormalexit); #endif #ifdef SIGINT signal(SIGINT, abnormalexit); #endif #ifdef SIGTERM signal(SIGTERM, abnormalexit); #endif /* Display program title */ printf(TITLESTR, TITLESTRPAR); /* If no arguments specified, display usage and exit */ if (argc < 2) { usage(stderr); cleanexit(EXIT_FAILURE); } /* If only argument is a question-mark, display usage and exit */ if (strcmp(argv[1], "?") == 0) { usage(stdout); cleanexit(EXIT_FAILURE); } /* Check existance of an archiver command */ if (sscanf(argv[1], "-%s", command) != 1) errorexit("Archiver command missing/invalid", SHOWUSAGE); comlen = strlen(command); /* Check command is right length */ if ((comlen < 1) || (comlen > 3)) errorexit("Archiver command/options missing/invalid", SHOWUSAGE); /* Deal with flags if given */ compos = 1; while (compos < comlen) { switch(tolower(command[compos])) { case PATHOPT: if (pathflag == LEAVEPATH) errorexit("Archiver options invalid", SHOWUSAGE); pathflag = LEAVEPATH; break; case MOVEOPT: if (moveflag == MOVEFILE) errorexit("Archiver options invalid", SHOWUSAGE); moveflag = MOVEFILE; break; default: errorexit("Archiver options invalid", SHOWUSAGE); } compos++; } /* Remove case dependancy of command */ *command = tolower(*command); /* Check validity of supplied archiver command */ if ((*command != LISTCOM) && (*command != TESTCOM) && (*command != EXTRACTCOM) && (*command != DELETECOM) && (*command != ADDCOM)) errorexit("Invalid archiver command", SHOWUSAGE); /* Perform required action dependant upon user supplied command */ switch(*command) { /* In the case of an archive listing request */ case LISTCOM: /* Check archiver options are valid for this operation */ if ((moveflag == MOVEFILE) || (pathflag == LEAVEPATH)) errorexit("Archiver options invalid", SHOWUSAGE); /* Check number of arguments */ if (argc != 3) errorexit("Wrong number of arguments", SHOWUSAGE); /* Open archive for input */ if ((arc_fptr = fopen(argv[2], "r")) == NULL) errorexit("Can't open archive for input", SHOWUSAGE); /* Print header information */ printf("Listing"); pr_head(argv[2]); /* Perform listing operation */ numfiles = listarc(); /* Print tail information */ pr_tail(); /* Give operation statistics */ operout("found",numfiles); succout("Listing", numerrors); /* Exit program cleanly */ cleanexit(EXIT_SUCCESS); /* In the case of an archive deletion request */ case DELETECOM: /* Check archiver options are valid for this operation */ if ((moveflag == MOVEFILE) || (pathflag == LEAVEPATH)) errorexit("Archiver options invalid", SHOWUSAGE); /* Check number of arguments */ if (argc < 3) errorexit("Wrong number of arguments", SHOWUSAGE); /* Print header information */ printf("Deleting from"); pr_head(argv[2]); /* Perform deletion operation */ numdel = deletearc(argv[2], argv, argc); /* Print tail information */ pr_tail(); /* Give operation statistics */ operout("deleted", numdel); errsout(numerrors); succout("Deletion", numerrors); /* Exit program cleanly */ if (numerrors == 0) cleanexit(EXIT_SUCCESS); else cleanexit(EXIT_FAILURE); /* In the case of an archive extraction/testing request */ case TESTCOM: case EXTRACTCOM: /* Check archiver options are valid for this operation */ if ((*command == TESTCOM) && ((moveflag == MOVEFILE) || (pathflag == LEAVEPATH))) errorexit("Archiver options invalid", SHOWUSAGE); /* Check number of arguments */ if ((*command == TESTCOM) && (argc != 3)) errorexit("Wrong number of arguments", SHOWUSAGE); if ((*command != TESTCOM) && (argc < 3)) errorexit("Not enough arguments", SHOWUSAGE); /* Open archive for input */ if ((arc_fptr = fopen(argv[2], "r")) == NULL) errorexit("Can't open archive for input", SHOWUSAGE); /* Print header information */ if (*command == TESTCOM) printf("Testing "); else printf("Extracting from "); pr_head(argv[2]); /* Perform extraction operation */ numfiles = extractarc(*command, argv, argc); /* Print tail information */ pr_tail(); /* Give operation statistics */ if (*command != TESTCOM) { operout("extracted", numfiles); errsout(numerrors); succout("Extraction", numerrors); } else { operout("tested", numfiles); errsout(numerrors); succout("Testing", numerrors); } /* In the case of a move option */ if (moveflag == MOVEFILE) { /* If there were errors in extraction, don't */ /* risk deleting from archive */ if (numerrors != 0) printf("Not risking deleting from archive!\n"); /* Otherwise, delete files that were extracted */ else { /* Close the archive file first */ COND_CLOSE(arc_fptr); arc_fptr = NULL; /* Print header information */ printf("Deleting from"); pr_head(argv[2]); /* Perform deletion operation */ numdel = deletearc(argv[2], argv, argc); /* Print tail information */ pr_tail(); /* Give operation statistics */ operout("deleted", numdel); errsout(numerrors); succout("Deletion", numerrors); } } /* Exit program cleanly */ if (numerrors == 0) cleanexit(EXIT_SUCCESS); else cleanexit(EXIT_FAILURE); /* In the case of an add/move to an archive request */ case ADDCOM: /* Check number of arguments */ if (argc < 4) errorexit("Not enough arguments", SHOWUSAGE); /* Open archive for update */ if ((arc_fptr = fopen(argv[2], "a")) == NULL) errorexit("Can't open archive", SHOWUSAGE); /* Print header information */ if (*command == ADDCOM) printf("Adding to"); else printf("Moving to"); pr_head(argv[2]); /* Perform add operation */ numfiles = addarc(argv, argc); /* Print tail information */ pr_tail(); /* Give operation statistics */ if (*command == ADDCOM) { operout("added", numfiles); errsout(numerrors); succout("Adding", numerrors); } else { operout("moved", numfiles); errsout(numerrors); succout("Moving", numerrors); } /* Exit program cleanly */ if (numerrors == 0) cleanexit(EXIT_SUCCESS); else cleanexit(EXIT_FAILURE); } /* By logic the program should never get this far */ errorexit("Internal error - improper program execution", NOUSAGE); }