home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 2: PC
/
frozenfish_august_1995.bin
/
bbs
/
d09xx
/
d0952.lha
/
UUArc
/
UUArc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-22
|
41KB
|
1,304 lines
/* */
/* 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 <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
/* 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 -<command>[%c][%c] <archive> [<filename> ... ]\n",
TITLE, PATHOPT, MOVEOPT);
fprintf(ostrm, "\nWhere <command> is one of-\n");
fprintf(ostrm, "\t%c = List contents of <archive>.\n", LISTCOM);
fprintf(ostrm, "\t%c = Test contents of <archive>.\n", TESTCOM);
fprintf(ostrm, "\t%c = Add <filename(s)> to <archive>.\n", ADDCOM);
fprintf(ostrm, "\t%c = Extract <filenames> from <archive>.\n", EXTRACTCOM);
fprintf(ostrm, "\t (All files if no <filenames> given.)\n");
fprintf(ostrm, "\t%c = Delete <filenames> from <archive>.\n", DELETECOM);
fprintf(ostrm, "\t (All files if no <filenames> 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, <archive> 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)<linelen) && (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<linelen)
&& (linetype != BADLINE))
if (buffer[datapos++] != ' ')
linetype = BADLINE;
if (linetype == BADLINE) {
fprintf(stderr,
"Data line too long - %s\n", arcfile);
numerrors++;
}
}
/* If the line was okay, and file checksum status */
/* is still unknown, then establish the status */
if ((checkflag == DUNNO) && (linetype == DATALINE)) {
if ((linelen-datapos) == 0)
checkflag = NO;
else {
if (checksum == DECODE(buffer[datapos])) {
checkflag = YES;
}
else {
fprintf(stderr,
"Bad checksum/linesize - %s\n",
arcfile);
numerrors++;
linetype = BADLINE;
}
}
}
}
/* If line is completely error free */
if (linetype == DATALINE) {
/* Increment file size counter */
filesize += (numdata = DECODE(*buffer));
/* If file has been opened for output, write out */
/* decoded bytes */
if (file_fptr != NULL)
while(numdata > 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);
}