home *** CD-ROM | disk | FTP | other *** search
- /*
-
- PolyXarc: de-archives most archive formats (with the help of the
- de-archive programs).
-
- */
- #define R_VERS "2.1a"
- #define R_DATE "12 May 1991"
-
- #ifdef AMIGA
- #define R_PORT "(Amiga 0.02)"
- #endif
-
- #ifdef OS_2
- #define R_PORT "(OS/2 1.3)"
- #endif
-
- #ifdef MSDOS
- #define R_PORT "(MSDOS)"
- #endif
-
- /*
- -----------------------------------------------------------------------------
- Version 2.1a, 12 May 1991: if pak_dosort found a header error, it would return
- the same error level as for a fatal error (couldn't open or read the file).
- We were leaving the filename intact and exiting instead of renaming to
- BAD_ARC and continuing when we were doing bundles. pak_dosort now returns
- a 6 for that error.
- Now MSC 6.0a compatible (hexit didn't work).
- Version 2.1, 5 April 1991: Released DOS and OS/2 versions.
- 1 January 1991: Will now accept quoted strings and hex numbers in the
- SIGNATURE and ARC lines.
- - A whitespace character is a space or tab.
- - Normally, each non-whitespace character is simply treated as a
- character.
- - If you place double-quotes (") around a string or part of a string,
- that string will be accepted intact, including whitespace.
- - If you place a less-than sign (<) in a string, the following characters
- will be considered to be 2-digit hex numbers until a greater-than sign
- (>) is reached. A hex digit is any numeric digit (0-9) or any letter
- from A to F (a-f or A-F). Normally the hex digits will be taken in
- pairs, but if any other character is imbedded, it will be considered to
- be a number break and the next digit will start the next number.
- - If you imbed a backslash ('\'), the backslash will be thrown away and
- the next character will be accepted as a character. This allows you
- to imbed the double-quote (") and less-than (<) characters as
- characters.
- 10 December 1990: Now sorts .ARC signatures, primarily by ARC version,
- secondarily by signature level. This means the user need not worry about
- the order, and it simplifies explanation greatly. Added new examples for
- PAK 2.51 to POLYXARC.CFG.
- 18 September 1990: Added support for type 1 ARC headers (see PAKSORTM).
- Added support for version 6 headers; version 5 ARC programs can't handle
- them. There is now an alternate verb in the config file for version 6
- archivers, ARC6. ARC or ARC5 will work for the old stuff.
- 23 May, 1990: Added a visual indication of the errorlevel at exit to
- expedite debugging.
- 21 May, 1990: Added the -# flag, which tells PolyXarc to ignore any
- bundle names that don't end with a decimal digit when using the -F
- option. Occasionally a file with a .MOD or some such extension shows
- up, and can cause all kinds of havoc. The default is to process them.
- Version 2.0, 9 April 1990: Cleaned up some minor stuff. Lattice 'C' on the
- Amiga seems to have a problem with leading zeros with the %.3d format, so
- we changed it to %0.3d for the Amiga implementation only. Ripped out a
- bunch of comments that described the .CFG file in detail; this code is
- big enough as it is! Released version 2.0 (finally!). jjn
- 31 March 1990: Bill Andrus added definitions, DIRFIND.C, and conditional
- compilations for IBM C/2 1.1 (or MSC 5.1) under OS/2 with the IBM SDK
- Version 1.2 Toolkit. Also insured the MSC conditional works for C/2.
- 22 March 1990: Steve Palm added definitions and conditional compilations
- for Lattice C on the Amiga. I altered some of the stuff to make it even
- more portable.
- 20 February 1990: Changed the way the template works. First I eliminated
- the format type. Then I changed the %s specifications to %1, %2, %3, and
- %4. Then I added the ability to have more than one file spec on the
- command line; everything after the first spec will name a file to be
- extracted. So now the four template specs are:
- %1: extract string
- %2: overwrite string
- %3: archive name string
- %4: extract name string
- Version 1.1a, 3 December 1989: I found another flaw in the bubble sort
- routine. jjn
- Version 1.1, 2 December 1989: David Page pointed out that SPAZ would
- automatically assume a wildcard extension if the archive name was
- specified without an extension. I have added this to PolyXarc. jjn
- Version 1.0, 2 December 1989: This is the initial release. I now have the
- NOSORT verb override the -F switch if it is used. That is, specifying
- -F and NOSORT will cause PolyXarc not to sort .ARC files. Also found a
- logic error in my bubble sort and fixed it. jjn
- Version 0.7, 25 November 1989: Previously, any error would cause PolyXarc
- to exit. Now, if it is in -f mode, if the file is 0-length then PolyXarc
- will simply delete it; if it gets an error return from the archiver, it
- spits out a warning message, renames the file to BAD_ARC.???, and keeps
- going. I also changed the config file a bit. jjn
- Version 0.6, 21 November 1989: Whoops! this_arc didn't get reset after each
- file, so if you unpacked an .ARC file and then something else, it
- wouldn't work. Fixed that by resetting this_arc at the same time as
- this_signature. Added wildcard support for the non-f mode, which should
- have been there in the first place. jjn
- Version 0.5, 20 November 1989: Fixed a bug in the -m support; I was
- subtracting in the wrong direction. If the configuration file is not
- specified on the command line, PolyXarc now looks for the default in
- the current directory, then in the directory of the .EXE file, then
- looks for a PENGUIN file. jjn
- Version 0.4, 18 November 1989: Fixed a bug in the -f support: Turbo C cannot
- malloc(0), so I now always malloc() at least one item. jjn
- Version 0.3, 18 November 1989: More code cleanup. Removed the extensive
- help stuff. Changed from Microsoft C 5.1 to Turbo C 2.0, which went from
- 96k to 32k (runtime, not .EXE size). Added the runtime configuration
- display and -f option support. jjn
- Version 0.2, 17 November 1989: Cleaned up some error handling. jjn
- Version 0.1, 16 November 1989: Created by Jeffrey J. Nonken
- -----------------------------------------------------------------------------
-
- Public domain by Jeffrey J. Nonken, February 1991. No strings, no bullshit.
- Do what you want with it. Nobody owns it.
-
- However, I would like it if you would refer all changes and enhancements to
- me. This way I can maintain it properly. Thanks.
-
- Jeffrey J. Nonken: sysop of Opus 1:273/715 Blue Bell, Pa. (215)279-9799
- My address and phone number will probably change in July, 1991.
- Please send correspondence to:
- Jeffrey J. Nonken
- 507 Ave. Presidio
- San Clemente, Ca. 92672
-
- This was compiled with Turbo C v2.0.
-
- -----
-
- Steve Palm was not available to help with an Amiga port of 2.1. The following
- applies only to version 2.0:
-
- Amiga Correspondence can go to:
- Steven M. Palm, sysop of "The Siberian Amiga (MAIL ONLY) 1:11/16"
- 1000 E. Easterday Ave, #2
- Sault Ste. Marie, MI 49783
-
- All thanks and credit for the program belong to Jeffrey, though.
-
- Amiga version compiled under Lattice C 5.05
-
- -----
-
- Bill Andrus of 1:109/301 is responsible for the OS/2 port.
-
- -----
-
- Please note: this source should compile under Lattice C 5.05 on the Amiga,
- or Turbo C 2.0 or Microsoft C 5.1 under MSDOS on the IBM. All you need do is
- predefine the appropriate label on the command line. However, Turbo C has
- a problem with the source files if they have been formatted by the Amiga.
- TC requires CRLF newline sequences, where the Amiga only uses LF for newlines.
- MSC doesn't seem to have any problem with the Amiga's newline sequences.
-
- It should also compile under IBM C/2 and MSC 6.0a under OS/2.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <dos.h>
- #include <errno.h>
-
- #ifdef AMIGA
- #define _NEAR_
- #endif
-
- #ifdef TURBOC
- #include <dir.h>
- #include <process.h>
- #define _NEAR_
- #endif
-
- #ifdef MSC
- #include <malloc.h>
- #include <memory.h>
- #include <process.h>
- #define _NEAR_ near
- #endif
-
- #ifdef OS_2
- #include <process.h>
- extern int dir_findfirst(char *filename,int attribute,struct find_t *dta);
- extern int dir_findnext(struct find_t *dta);
- #endif
-
- #include "p_common.h" /* Portability defines. Must be after */
- /* system includes on the Amiga... */
-
- #include "pakmdefn.h" /* Mike Housky's sort function definitions. */
-
- /****************************************************************************/
-
- #ifdef TURBOC
- #define bf_name ff_name
- #define bf_time ff_ftime
- #define bf_date ff_fdate
- #define bf_size ff_fsize
- #endif
- #ifdef AMIGA
- #define bf_name filename
- #define bf_time time
- #define bf_date date
- #define bf_size size
- #endif
- #ifdef MSC
- #define bf_name name
- #define bf_time wr_time
- #define bf_date wr_date
- #define bf_size size
- #endif
-
- #define OVER_LEN 6 /* Size of overwrite string. */
- #define EXTR_LEN 6 /* Size of extract string. */
- #define SIGN_LEN 6 /* Size of signature string. */
-
- #define DEFAULT_NAME "POLYXARC.CFG" /* Default name for configuration file. */
-
- typedef struct SIGNATURE_TAG /* 'Signature' structure. */
- {
- long file_offset; /* Offset from beginning/end of file. */
- char overwrite[OVER_LEN]; /* Overwrite parameter string. */
- char extract[EXTR_LEN]; /* Extract parameter string. */
- char signature[SIGN_LEN]; /* Actual signature string. */
- char *cmdline; /* Command line for calling de-archiver. */
- } SIGNATURE_TYPE;
-
- typedef struct ARC_TAG /* 'Archive level' structure. */
- {
- byte type; /* .ARC level */
- byte version; /* True if version 6 headers found. */
- char overwrite[OVER_LEN]; /* Overwrite parameter string. */
- char extract[EXTR_LEN]; /* Extract parameter string. */
- char *cmdline; /* Command line for calling de-archiver. */
- } ARC_TYPE;
-
- typedef struct FILE_TAG /* Bundle file directory information. */
- {
- #ifdef AMIGA
- char filename[108]; /* currently 30 chars are used */
- long time;
- long date;
- #endif
- #ifdef IBM
- char filename[13]; /* FILENAME.EXT of file. */
- unsigned time; /* Last time updated. */
- unsigned date; /* Last date updated. */
- #endif
- long size; /* Size of the file in bytes. */
- } FILE_TYPE;
-
- /****************************************************************************/
-
- FILE_TYPE * _NEAR_ file_list = NULL; /* list of files ('malloc'ed). */
- ARC_TYPE * _NEAR_ arc_list;
- SIGNATURE_TYPE * _NEAR_ signature_list;
-
- int _NEAR_ this_net; /* Our net number. */
- int _NEAR_ this_node; /* Our node number. */
- int _NEAR_ config_name_set = 0; /* TRUE if config name specified. */
- int _NEAR_ archive_name_set = 0; /* TRUE if archive name specified. */
- int _NEAR_ arc_count = 0; /* Number of .ARC formats defined. */
- int _NEAR_ signature_count = 0; /* Number of other formats defined. */
- int _NEAR_ nosort = 0; /* TRUE if should not sort .ARC files. */
- int _NEAR_ delete_archives = 0; /* TRUE if should auto-delete files. */
- int _NEAR_ do_all_bundles = 0; /* TRUE if processing all mail bundles. */
- int _NEAR_ do_n_bundles = 0; /* Number of archives to do (0 == all). */
- int _NEAR_ show_addresses = 0; /* TRUE to display bundle addresses. */
- int _NEAR_ this_signature = -1; /* Which signature was found. */
- int _NEAR_ this_arc = -1; /* Which arc level was found. */
- int _NEAR_ arc = 0; /* TRUE if an .ARC format file found. */
- int _NEAR_ overwrite = 0; /* TRUE if automatic overwrite. */
- int _NEAR_ quiet = 0; /* TRUE makes PolyXarc quieter. */
- int _NEAR_ name_count = 0; /* Counts number of non-switch parameters. */
- int _NEAR_ ignore_archiver_errors = 0; /* TRUE continues on archiver errors. */
- int _NEAR_ digits_only = 0; /* TRUE forces digits only on bundle names. */
-
-
- #ifdef AMIGA
- extern int errno;
- int _NEAR_ msflag = 1; /* causes dir searches to use */
- /* MS-DOS wildcards */
- #endif
- char _NEAR_ archive_name[fname_len] = "";/* Name of archive (from command line). */
- char _NEAR_ extract_name[128] = ""; /* Name(s) of file(s) to be extracted
- (from command line). */
- char _NEAR_ config_name[fname_len] = DEFAULT_NAME; /* Name of configuration file. */
-
- /****************************************************************************
- The following define the find_first/find_next environment. The functions that
- come with MSC and TURBO C are nearly identical, varying only in some minor
- details. 'buffer' is the structure in which the file search routines store
- the file information. 'jjn_findfirst' and 'jjn_findnext' are macros that
- resolve to the actual calls to the first/next library routines in the two
- different libraries. The only differences are the function names, and that two
- parameters are swapped in the find_first routine.
- ****************************************************************************/
- #ifdef TURBOC
- static struct ffblk _NEAR_ buffer;
- #define jjn_findfirst(f,a,b) findfirst(f,b,a)
- #define jjn_findnext(b) findnext(b)
- #endif
-
- #ifdef AMIGA
- struct ffblk {
- LONG diskkey;
- LONG direntrytype;
- char filename[108];
- LONG protection;
- LONG entrytype;
- LONG size;
- LONG numblocks;
- LONG date;
- LONG time;
- LONG ticks;
- char comment[80];
- char reserved[36];
- };
- static struct ffblk _NEAR_ buffer;
- # define jjn_findfirst(f,a,b) dfind((struct FileInfoBlock *) b,(char *) f,(int) a)
- # define jjn_findnext(b) dnext((struct FileInfoBlock *) b)
- #endif
-
-
- #ifdef MSC
-
- #ifdef MSDOS
- static struct find_t _NEAR_ buffer;
- #define jjn_findfirst(f,a,b) _dos_findfirst(f,a,b)
- #define jjn_findnext(b) _dos_findnext(b)
- #endif
-
- #ifdef OS_2
- static struct find_t _NEAR_ buffer;
- #define jjn_findfirst(f,a,b) dir_findfirst(f,a,b)
- #define jjn_findnext(b) dir_findnext(b)
- #endif
-
- #endif
-
- /* This holds the highest compression level found in an .ARC file. */
- extern int16 _NEAR_ highest_type;
- /* This tells whether we have found version 6 headers. */
- extern int16 _NEAR_ version6;
-
-
- /*****************************************************************************
- quit() tells what errorlevel is being returned, then calls exit().
- *****************************************************************************/
- void quit(int errorlevel)
- {
- if (!quiet)
- printf("\nErrorlevel on exit: %d.\n",errorlevel);
- exit(errorlevel);
- }
-
- /*****************************************************************************
- default_ext() appends a default extension to a filename. Normal operation
- happens when the given default extension does not have a period as the first
- character. If this is the case, the default extension is only appended if
- dest does not already have one. If the given default extension has a period,
- it forces the dest to have the default extension even if it already had one.
-
- -----> NOTE: The AmigaDOS system does not require nor expect a filename
- to contain an extension. DO NOT USE THIS ROUTINE there.
-
- Examples:
- Assume filename is "MYFILE.JNK".
-
- default_ext(filename,"EXT"); [filename is left as "MYFILE.JNK".]
- default_ext(filename,".EXT"); [filename is now "MYFILE.EXT".]
-
- Assume filename is "MYFILE".
-
- default_ext(filename,"EXT"); [filename is now "MYFILE.EXT".]
- default_ext(filename,".EXT"); [filename is now "MYFILE.EXT".]
- *****************************************************************************/
- #ifndef AMIGA
- char *default_ext(char *dest,char *def_ext)
- {
- register int i;
-
- for (i = strlen(dest) - 1; i >= 0; --i) /* Look for \, :, or . */
- {
- if (dest[i] == '.') /* Found a period. Force it? */
- {
- if (def_ext[0] != '.') /* If none in default ext, forget it. */
- {
- return(dest); /* Return the given extension. */
- }
- else
- {
- strcpy(dest+i,def_ext); /* Otherwise, copy new default ext. */
- return(dest); /* Return with a new extension. */
- }
- }
- if (dest[i] == c_slash || dest[i] == ':') /* Found one, no period. */
- i = 0; /* Force it to drop through. */
- }
- /* If it got this far, there was no extension. */
- if (def_ext[0] != '.') /* Is there a period in the default ext? */
- strcat(dest,"."); /* If not, add one. */
- strcat(dest,def_ext); /* Now add the default extension. */
- return(dest);
- }
- #endif
-
- /****************************************************************************
- Limit a string to len characters. This routine modifies the original string
- and returns the string's address.
- ****************************************************************************/
- char *strtrunc(char *string,int len)
- {
- register int i; /* Index into the string. */
-
- i = 0; /* Start from the beginning. */
- while (string[i] != '\0') /* Do until we reach the end. */
- {
- if (i == len) /* Did we count len characters? */
- {
- string[i] = '\0'; /* Yes, truncate the string here. */
- return(string); /* Return the truncated string. */
- }
- ++i; /* Not found yet, look farther. */
- }
- return(string); /* String too short for truncation, return unmodified. */
- }
-
- /****************************************************************************
- Add a backslash (\) to the end of a path. Only does so if the last character
- is not already a backslash or a colon. Note: the Amiga uses a forward slash.
- ****************************************************************************/
- #ifdef IBM
- # pragma check_stack-
- #endif
- void slash(char *pathspec)
- {
- register int i;
-
- i = strlen(pathspec); /* Find the end of the string. */
- if (i--) /* Check for 0 length. If non-zero, backpedal and process it. */
- if ((pathspec[i] != c_slash) && /* See if last char is a backslash */
- (pathspec[i] != ':')) /* or a colon. */
- strcat(pathspec,s_slash); /* If not, add a backslash. */
- }
- #ifdef IBM
- # pragma check_stack+
- #endif
- /****************************************************************************
- Separate drive:directory from name.ext. The original string is not changed.
- ****************************************************************************/
- void path_name(char *filespec,char *path,char *name)
- {
- register int i;
-
- strupr(filespec); /* Make it upper case. */
- for (i = strlen(filespec); i >= 0; --i) /* Start from the end. */
- {
- if (filespec[i] == ':' || filespec[i] == c_slash) /* '\' or ':'? */
- {
- ++i; /* Yes, point to next char. */
- if (name != NULL) /* Copy filename if there is an address. */
- strcpy(name,filespec + i);
- if (path != NULL) /* Copy file if there is an address. */
- {
- strncpy(path,filespec,i); /* Copy only i characters. */
- path[i] = '\0'; /* Terminate the dest string. */
- }
- return; /* We got it; now let's return it. */
- }
- }
-
- /* If we get this far, we never found a colon or backslash. That implies that
- the filespec is filename.ext only, no path. */
-
- if (path != NULL) /* Copy empty path if an address was provided. */
- strcpy(path,"");
- if (name != NULL) /* Copy filename.ext if an address was provided. */
- strcpy(name,filespec);
- }
-
- /****************************************************************************
- This converts a hexASCII digit into a numeric value.
- ****************************************************************************/
- char hexit(char c)
- {
- c = (char) toupper(c); /* Necessary for MSC 6.0a */
- c -= '0';
- if (c > 9)
- c -= 7;
- return(c);
- }
-
- /****************************************************************************
- This parses off one parameter from the given string and returns its address.
- It works similarly to strtok() except that only the string parameter is
- specified; the parsing action is fixed.
-
- On the first call per string, pass the string address.
- On subsequent calls for that string, pass a NULL pointer.
- ****************************************************************************/
- #define SCANNING 1
- #define QUOTE 2
- #define HEX1 3
- #define HEX2 4
- #define FINISHED 5
- #define DEADSTOP 6
-
- char *parmtok(char *string,char *tokens)
- {
- static char *oldstring;
- char *newstring;
- register int i;
- register int j;
- register int state;
-
- if (string != NULL)
- oldstring = string;
- while (strchr(tokens,*oldstring) != NULL)
- if (*oldstring == '\0')
- return(NULL);
- else
- ++oldstring;
- i = 0;
- j = 0;
- state = SCANNING;
- do
- {
- switch(state)
- {
- case SCANNING:
- if (oldstring[i] == '\0')
- state = DEADSTOP;
- else if (strchr(tokens,oldstring[i]) != NULL)
- state = FINISHED;
- else if (oldstring[i] == '"')
- state = QUOTE;
- else if (oldstring[i] == '\\')
- {
- if (oldstring[++i] == '\0')
- state = DEADSTOP;
- else
- oldstring[j++] = oldstring[i];
- }
- else if (oldstring[i] == '<')
- state = HEX1;
- else
- oldstring[j++] = oldstring[i];
- break;
- case QUOTE:
- if (oldstring[i] == '\\')
- oldstring[j++] = oldstring[++i];
- else if (oldstring[i] == '"')
- state = SCANNING;
- else if (oldstring[i] == '\0')
- state = DEADSTOP;
- else
- oldstring[j++] = oldstring[i];
- break;
- case HEX1:
- case HEX2:
- if (oldstring[i] == '>')
- state = SCANNING;
- else if (oldstring[i] == '\0')
- state = DEADSTOP;
- else if (isxdigit(oldstring[i]))
- {
- if (state == HEX1)
- {
- oldstring[j] = hexit(oldstring[i]);
- state = HEX2;
- }
- else
- {
- oldstring[j] = (char) (((byte) oldstring[j] << 4) | (byte) hexit(oldstring[i]));
- state = HEX1;
- ++j;
- }
- }
- else
- {
- if (state == HEX2)
- ++j;
- state = HEX1;
- }
- break;
- }
- ++i;
- } while (state != FINISHED && state != DEADSTOP);
- oldstring[j] = '\0';
- newstring = oldstring;
- oldstring += (state == DEADSTOP) ? (i - 1) : i;
- return(newstring);
- }
-
- /****************************************************************************
- If the first file timestamp is later than the second, return TRUE.
- ****************************************************************************/
- #ifdef IBM
- # pragma check_stack-
- #endif
- int compare(FILE_TYPE *f1,FILE_TYPE *f2)
- {
- if (f1->date > f2->date) /* If first file date is later, return TRUE. */
- return(1);
- if (f1->date < f2->date) /* If first file date is earlier, FALSE. */
- return(0);
- /* The dates were the same, so try the time. */
- if (f1->time > f2->time) /* If first file time is later, return TRUE. */
- return(1);
- /* The first file is the same as or earlier than the second. In either case,
- we don't want to bother swapping, so just return FALSE. */
- return(0);
- }
- #ifdef IBM
- # pragma check_stack+
- #endif
- /****************************************************************************
- Find highest BAD_ARC.???, rename current file to the next one.
- ****************************************************************************/
- int ren_bad_arc(char *path,char *bad_name)
- {
- register int i; /* Highest BAD_ARC.### found so far. */
- register int j; /* Holds results from first/next calls. */
- register int k; /* Converted BAD_ARC.### value. */
- char filespec[fname_len]; /* Filespec of new name. */
- /* Also first/next search pattern. */
- char bad_spec[fname_len]; /* Complete filespec of bad filename. */
-
- sprintf(filespec,"%sBAD_ARC.???",path); /* Create search pattern. */
- i = -1; /* Highest found so far. */
- j = jjn_findfirst(filespec, 0, &buffer); /* Find the first one. */
- while (j == 0) /* While we keep finding them... */
- {
- /* Convert the extension to its numeric value. */
- k = atoi(strchr(buffer.bf_name,'.') + 1);
- if (k > i) /* Is it higher than all the previous found? */
- i = k; /* If so, save this one as the highest. */
- j = jjn_findnext(&buffer); /* Find the next one, if you can! */
- }
- /* Gets here when no more can be found. */
- /* Create a filespec including the path and BAD_ARC.(i+1). */
- #ifdef AMIGA
- sprintf(filespec,"%sBAD_ARC.%0.3d",path,i + 1);
- #else
- sprintf(filespec,"%sBAD_ARC.%.3d",path,i + 1);
- #endif
- /* Create a filespec including the path and the original filename. */
- sprintf(bad_spec,"%s%s",path,bad_name);
- /* Tell the operator what is happening. */
- printf("Renaming %s to %s.\n",bad_spec,filespec);
- /* Rename the file to BAD_ARC.###. */
- rename(bad_spec,filespec);
- return(i);
- }
-
- /****************************************************************************
- Find all .SU?, .MO?, .TU?, .WE?, .TH?, .FR?, and .SA? files.
- ****************************************************************************/
- int get_files(char *path,int do_bundles)
- {
- char *p;
- register int i;
- register int j;
- register int k;
- int found;
- int ok;
- char filespec[64];
- static char bundles[7][6] =
- {
- "*.SU?",
- "*.MO?",
- "*.TU?",
- "*.WE?",
- "*.TH?",
- "*.FR?",
- "*.SA?"
- };
- FILE_TYPE f;
-
-
- strcpy(filespec,path); /* Start the filespec out with the path. */
- p = filespec + strlen(filespec); /* Point to the end of the path.
- This lets us use strcpy() instead
- of strcat to concatonate, and
- relieves us from having to copy the
- path back in every time. */
- file_list = (FILE_TYPE *)malloc(sizeof(FILE_TYPE)); /* Allocate 1. */
- if (file_list == NULL) /* Check to see if it worked. */
- return(-1); /* If not, we have a memory problem. */
- i = 0; /* Start index/counter at 0. */
- for (j = 0; j < 7; ++j) /* Run through all the extensions. */
- {
- if (do_bundles) /* If doing all bundles, */
- strcpy(p,bundles[j]); /* get the search pattern. */
- else /* Otherwise we're just looking for one file; */
- j = 7; /* set index for once through. */
- if (jjn_findfirst(filespec, 0, &buffer) == 0) /* Find first one. */
- {
- ok = TRUE;
- if (digits_only)
- if (!isdigit(buffer.bf_name[strlen(buffer.bf_name) - 1]))
- ok = FALSE;
- if (ok)
- { /* If we found one, allocate room for more. */
- file_list = (FILE_TYPE *)realloc((char *)file_list,(i + 1) * sizeof(FILE_TYPE));
- if (file_list == NULL)
- return(-1); /* If allocation didn't work, no more memory. */
- strcpy(file_list[i].filename,buffer.bf_name); /* Get filename. */
- file_list[i].time = buffer.bf_time; /* Get time. */
- file_list[i].date = buffer.bf_date; /* Get date. */
- file_list[i].size = buffer.bf_size; /* Get size. */
- ++i; /* Count up. */
- }
- while (jjn_findnext(&buffer) == 0) /* We're greedy, look for more. */
- {
- ok = TRUE;
- if (digits_only)
- if (!isdigit(buffer.bf_name[strlen(buffer.bf_name) - 1]))
- ok = FALSE;
- if (ok)
- { /* If we found one, allocate room for more. */
- file_list = (FILE_TYPE *)realloc((char *)file_list,(i + 1) * sizeof(FILE_TYPE));
- if (file_list == NULL)
- return(-1); /* If allocation didn't work, no more memory. */
- strcpy(file_list[i].filename,buffer.bf_name);/* Get filename. */
- file_list[i].time = buffer.bf_time; /* Get time. */
- file_list[i].date = buffer.bf_date; /* Get date. */
- file_list[i].size = buffer.bf_size; /* Get size. */
- ++i; /* Count up. */
- }
- }
- }
- }
- /* We've found all the filenames there are to find. Now we use a bubble sort
- to get them all into order by time/datestamp. I used a bubble sort because
- the quicksort is much larger, and besides, I don't expect there to be
- enough files to make the quicksort time-effective. In fact, I expect that
- the files will usually be in order, in which case the bubble sort is
- faster because it will only require one pass to find that out. */
-
- if (i > 1) /* Did we find more than one file? */
- { /* Yes, do a bubble sort. */
- j = 0; /* Start outside index at 0. */
- do
- {
- found = FALSE; /* This flag says whether any swaps made. */
-
- /* The inside loop starts from the top and goes down to the outside loop
- index. That way the lowest gets sorted to the bottom each time, and we
- can safely ignore it from then on, and so increment the outside counter. */
-
- for (k = i - 2; k >= j; --k)
- {
- /* We want the earlier file first. Compare returns TRUE if the earlier one
- is second. If they are the same date, we don't care and leave them alone. */
- if (compare(&file_list[k],&file_list[k+1]))
- { /* Wrong order, swap the files. */
- found = TRUE; /* Trip the flag; forces another pass. */
- memcpy((char *)&f,(char *)&file_list[k],sizeof(f));
- memcpy((char *)&file_list[k],(char *)&file_list[k+1],sizeof(f));
- memcpy((char *)&file_list[k+1],(char *)&f,sizeof(f));
- }
- }
- } while (++j < (i - 1) && found); /* Do until they're in order. */
- }
- return(i); /* Return the number of files found. */
- }
-
- /************************************************************************
- Build the command line, based upon template & cmd type
- ***********************************************************************/
- int build_cmd (char *extract_spec, char *overwrite_s, char *extract_s,
- char *template_s, char *filespec, char *cmdline)
- {
- int i, j, percent;
- char c, *t;
-
- /* Build the command line according to the template. */
-
- for (i = 0, j = 0, percent = FALSE; template_s[i] != '\0'; ++i)
- {
- c = template_s[i]; /* Get the character. */
- if (percent) /* Was the last one a '%'? */
- {
- t = NULL; /* Yup. Init this to NULL for testing. */
- switch(c) /* Find out which string we want. */
- {
- case '1': t = overwrite ? "" : extract_s;
- break; /* Get the extract string. */
- case '2': t = overwrite ? overwrite_s : "";
- break; /* Get the overwrite string. */
- case '3': t = filespec;
- break; /* Get the file spec. */
- case '4': t = extract_spec;
- break; /* Get the extracted file spec. */
- default: cmdline[j++] = c;
- break; /* Neither, just copy the character. */
- }
- if (t != NULL) /* If non-null, we got a string. */
- {
- strcpy(cmdline + j,t); /* Yup, copy the string in place of the %?. */
- j = strlen(cmdline); /* Update the index. */
- }
- percent = FALSE; /* Reset our '%' flag. */
- }
- else if (c == '%') /* See if this is a '%'. */
- percent = TRUE; /* If so, process next character. */
- else
- cmdline[j++] = c; /* Else just copy this character. */
- }
- cmdline[j] = '\0'; /* Append a null. It's now a string. */
- return (0);
- }
-
- /************************************************************************
- Tokenize the command line.
- ************************************************************************/
- int tokenize (char *cmdline, int *argc, char *argv[], char **path)
- {
- char *t;
-
- /* Now we tokenize the command line. Separate everything at the spaces. I
- currently ignore quotes, so this may want some enhancement. */
- t = strtok(cmdline," ");
- if (t == NULL)
- {
- printf("Error: encountered empty command line while attempting to tokenize.\n");
- return(1); /* No command found! Return an error. */
- }
- *path = t; /* Store this as the execution path, */
- argv[0] = t; /* and as the first argument. */
- *argc = 1; /* Set the argument counter/index. */
- do
- {
- t = strtok(NULL," "); /* Get the next token. */
- argv[(*argc)++] = t; /* Set it as the next argument and count up. */
- } while (t != NULL); /* Do it until we run out of tokens. */
- /* The beauty of that scheme is that the argument array is terminated by a
- NULL address, which that loop will store as the last argument. */
-
- return(0);
- }
-
- /****************************************************************************
- Create and execute a command. Don't use COMMAND.COM, we need the result code!
- ****************************************************************************/
- int execute(char *overwrite_s, char *extract_s, char *template_s,
- char *filespec, char *extract_spec)
- {
- char *argv[21]; /* Argument list. Allow 20 arguments + command name. */
- char *path; /* Command name. Also stored as argv[0]. */
- int argc; /* Number of arguments found. */
- int i; /* String index, and result of the spawn. */
- char *t; /* String pointer, and token pointer. */
- int retval;
-
- #ifdef AMIGA
- int offset; /* offset to just past the archiver name in cmd */
- char justpath[110];
- char justfile[110];
- char buffer[256]; /* buffer for my new CMD string */
- char cmdline[256]; /* The command string */
- struct ProcID pid;
- #else
- char cmdline[128]; /* The command string. */
- #endif
-
- retval = build_cmd (extract_spec, overwrite_s, extract_s, template_s,
- filespec, cmdline);
- if (!quiet)
- printf("-> Executing '%s'\n",cmdline);
- if (retval != 0) return (retval);
- retval = tokenize (cmdline, &argc, argv, &path);
- if (retval != 0) return (retval);
-
- #ifdef AMIGA
- /* A Bug in lattice causes the forkv function to NOT search */
- /* the C: device for commands. This is why I have to manually */
- /* try that combination. Darn irritating! */
-
- i = forkv(path,argv,NULL,&pid); /* Spawn the task. */
- if (i == -1) {
- path_name (path, justpath, justfile); /* get archiver name */
- offset = strlen (path); /* how far past name into cmdline? */
- strcpy (buffer, "C:"); /* start with C: path */
- strcat (buffer, justfile); /* and add the name on here */
- retval = build_cmd (extract_spec, overwrite_s, extract_s, template_s,
- filespec, cmdline);
- if (retval != 0) return (retval);
- strcat (buffer, &cmdline[offset]); /* move the args in */
- strcpy (cmdline, buffer); /* now put this all back into cmdline */
- retval = tokenize (cmdline, &argc, argv, &path);
- if (retval != 0) return(retval);
- i = forkv (path, argv, NULL, &pid);
- }
- #else
- i = spawnvp(P_WAIT,path,argv); /* Spawn the task. */
- #endif
- if (i == -1) /* Did we get an error trying to execute? */
- {
- switch (errno) /* Yup, figure out why. */
- {
- case E2BIG:
- t = "Argument list too long";
- break;
- case EINVAL:
- t = "Invalid argument";
- break;
- case ENOENT:
- t = "Path or file name too long";
- break;
- case ENOEXEC:
- t = "Exec format error";
- break;
- case ENOMEM:
- t = "Not enough memory";
- break;
-
- /* we must put a default in, as Lattice is not properly
- setting the errno flag! Thus, I haven't tried to work
- around it, I just admit it isn't specified... */
- /* Actually, that's a good idea anyway. jjn */
- default:
- t = "Unspecified Error";
- break;
- }
- printf("Error in execution; reason given: %s.\n",t);
- return(-1);
- }
- #ifdef AMIGA
- i = wait(&pid); /* wait for our child process to terminate before
- we continue our processing. Ain't multi-tasking
- nice??? ;^) */
- /* Whaddya think P_WAIT is for in the spawn command? :) */
- #endif
- return(i); /* No, we managed to execute it. Return the result. */
- }
-
- /****************************************************************************
- Search through the given file and figure out which type it is.
- ****************************************************************************/
- int find_type(char *path, char *filename, char *filespec)
- {
- FILE *file; /* File pointer. */
- SIGNATURE_TYPE *s; /* Pointer into signature list; provides dereferencing. */
- long offset; /* Offset into the file. */
- register int i; /* Index into the signature list. */
- int l; /* Length of the signature. */
- char buffer[SIGN_LEN]; /* Read buffer for the signatures. */
-
-
- arc = FALSE; /* Note that no .ARC type found. */
- file = fopen(filespec,"rb"); /* Open the file for binary read. */
- if (file == NULL) /* If can't open it, return with error. */
- {
- printf("Error: cannot open %s.\n",filespec);
- return(1);
- }
- this_arc = -1; /* Show that nothing found so far. */
- this_signature = -1;
- i = 0; /* Start index at first signature. */
- offset = 0xffffffff; /* Show a ridiculous offset at first. */
- while (i < signature_count && this_signature == -1)
- {
- s = &signature_list[i]; /* Dereference this signature. */
- l = strlen(s->signature); /* Get the signature length. */
- if (s->file_offset != offset) /* See if we already have that spot. */
- {
- offset = s->file_offset; /* Nope, move to it and read it. */
- fseek(file,offset,(offset < 0) ? 2 : 0);
- fread(buffer,sizeof(buffer),1,file);
- }
- if (strncmp(s->signature,buffer,l) == 0) /* Are they the same? */
- /* Note: case sensitive! */
- this_signature = i; /* If so, record it. */
- ++i; /* Increment the counter. */
- } /* Do that until we find a signature or run out. */
- if (this_signature == -1) /* Did we find a signature? */
- { /* If not, look for an .ARC file. */
- if (offset != 0l) /* See if we have this in memory. */
- {
- fseek(file,0l,0); /* If not, seek 0 and read 1 byte. */
- fread(buffer,1,1,file);
- }
- if (buffer[0] == 0x1a) /* 1A is the .ARC signature. */
- arc = TRUE; /* If so, assume it's an .ARC file. */
- }
- fclose(file); /* Either way, we're done for now. */
- if (arc) /* Is it an .ARC file? */
- {
- i = pak_dosort(path,filename,!nosort); /* If so, try to sort. */
- printf("Highest ARC level found: %d.\n",highest_type);
- /*
- Actually, pak_dosort() scans through the .ARC file, finding the highest
- level of compression used. It only sorts if nosort is FALSE.
-
- Returns 0 if successful, or error:
- 1 = Can't open/read source. (missing pakfile or DOS error)
- 2 = Can't create/write dest. (maybe disk or directory full)
- 3 = Can't delete old source file. (read-only)
- 4 = Can't rename temp file to source name. (DOS error)
- 5 = Out of memory.
- 6 = Invalid pakfile. (Header error)
-
- If we got 2, print a warning and go on. Otherwise, we quit on any error.
- */
- if (i == 2)
- {
- printf("Warning: sort failed. Attempting extract anyway.\n");
- }
- else if (i != 0)
- return(i);
- /* Did ok, so let's see what we've got. */
- i = 0;
- while (i < arc_count && this_arc == -1)
- {
- if ((version6 && arc_list[i].version) || !version6)
- if ((byte)highest_type <= arc_list[i].type)
- this_arc = i; /* Set this_arc to .ARC type found. */
- /* If the highest .ARC type is higher than we can handle, it never finds it.
- The calling routine will claim that we couldn't find the archive type.
- If the archive has version 6 headers, then the extractor must also be
- capable of version 6 extraction. */
- ++i;
- }
- }
- return(0);
- }
-
- /****************************************************************************
- Converts the first 4 characters from a string from hex to a signed integer.
- If there are any non-digits in those four characters, it returns -65536.
- ****************************************************************************/
- long one_hex(char *name)
- {
- int i; /* Index. */
- register int16 j; /* Accumulated result. */
- register int16 c; /* Holding place for the converted character. */
-
- j = 0; /* Reset accumulated result. */
- for (i = 0; i < 4; ++i) /* Go through the first 4 characters. */
- {
- c = toupper(name[i]); /* Get the upper case character. */
- if (!isxdigit(c)) /* Is it a hex digit? */
- return -65536; /* If not, return error. */
- if (c >= 'A') /* Change 'A'-'F' into A-F. */
- c -= 7;
- j = (j << 4) + c - '0'; /* Subtract ASCII offset and accumulate. */
- }
- return (long)j; /* Return the result. */
- }
-
- /****************************************************************************
- Display address of sender.
- ****************************************************************************/
- void sender_is(char *filename)
- {
- int net;
- int node;
- long i;
-
- i = one_hex(filename); /* Convert first 4 characters of filename. */
- if (i == -65536) /* If not hex number, ignore it. */
- return;
- net = (int16)i; /* Assume this is a net difference. */
- i = one_hex(filename + 4); /* Convert last 4 characters of filename. */
- if (i == -65536) /* If not hex number, ignore it. */
- return;
- node = (int16)i; /* Assume this is a node difference. */
-
- /* Calculate the net/node address from the filename and your address, and
- display the result. */
- printf("Extracting bundle from %u/%u.\n",this_net + net,this_node + node);
- }
-
- /****************************************************************************
- Discombobulate one file.
- ****************************************************************************/
- int discombobulate(char *path,char *filename, char *extract_spec)
- {
- int i; /* General purpose variable. */
- char filespec[fname_len]; /* File specification generated from path and name. */
-
- if (show_addresses) /* If we're supposed to show the address, do so. */
- sender_is(filename);
- strcpy(filespec,path); /* Create the filespec from the path */
- strcat(filespec,filename); /* and the filename. */
- i = find_type(path,filename,filespec); /* Find the type of file. */
- if (i) /* If can't do it, return with the error. */
- return(i);
- if (this_arc != -1) /* See if it's an .ARC file. */
- {
- i = execute(arc_list[this_arc].overwrite,
- arc_list[this_arc].extract,
- arc_list[this_arc].cmdline,
- filespec,
- extract_spec); /* Try to extract. */
- }
- else if (this_signature != -1) /* Nope, see if it's something else. */
- {
- i = execute(signature_list[this_signature].overwrite,
- signature_list[this_signature].extract,
- signature_list[this_signature].cmdline,
- filespec,
- extract_spec); /* Try to extract. */
- }
- else /* Whoops! We couldn't figure it out. */
- {
- printf("Error: cannot determine archive type of %s.\n",filespec);
- if (arc && this_arc == -1)
- printf("The ARC level was higher than anything defined.\n");
- return(6);
- }
- if (i > 0) /* This means the archiver ran into trouble. */
- {
- printf("Error return %d from archiver.\n",i);
- i = 8;
- }
- else if (i < 0) /* This means we never got to execute it. */
- {
- return(10);
- }
- else if (delete_archives) /* No problems. Erase the evidence. */
- {
- printf("Unpack successful: deleting %s.\n",filespec);
- i = unlink(filespec);
- if (i)
- {
- printf("Error: could not delete %s.",filespec);
- #ifdef OS_2
- printf("\nERRNO is %d.",errno);
- #endif
-
-
- i = 3;
- }
- }
- printf("\n");
- return(i);
- }
-
- /****************************************************************************
- Discombobulate all bundles (or n bundles if do_n_bundles != 0).
- ****************************************************************************/
- int discombobulate_all(char *path, char *extract_spec, int do_bundles)
- {
- int numfiles; /* How many files we found. */
- int count; /* Index counter. */
- int i; /* General purpose register. */
-
- numfiles = get_files(path,do_bundles); /* Collect filenames. */
- if (numfiles < 0) /* < 0 means we got an error in allocation. */
- return(5);
-
- /* Not having anything to discombobulate with the -F switch isn't _really_ an
- error condition. Having PolyXarc return an error under these circumstances
- made me and Peter Stern spend several days beating our heads against the
- wall. From now on we'll just return 0 if this happens. -jjn */
-
- if (numfiles == 0) /* == 0 means no files found. */
- return(do_all_bundles ? 0 : 1);
- if (do_n_bundles) /* If limited, */
- if (numfiles > do_n_bundles) /* and if past the limit, */
- numfiles = do_n_bundles; /* limit the file count. */
-
- /* If we're not doing bundles, then path was actually a filespec. In that case
- we need to throw away the filename.ext and keep the path. The filename.ext
- will be drawn from the list of files that we got from get_files(). */
- if (!do_bundles)
- path_name(path,path,NULL);
-
- for (count = 0; count < numfiles; ++count) /* Do all the files. */
- {
- if (file_list[count].size == 0l) /* Is this an empty file? */
- {
- if (do_bundles) /* Are we doing bundles? */
- {
- unlink(file_list[count].filename); /* Yes; just delete it. */
- printf("Zero-length file %s deleted.",file_list[count].filename);
- }
- else /* No, consider this an error. */
- {
- printf("Error: file %s is length 0.",file_list[count].filename);
- return(9);
- }
- }
- else /* The file is not zero length. */
- {
- i = discombobulate(path,file_list[count].filename,extract_spec);
- /* Extract. */
- if (do_bundles) /* Are we doing bundles? */
- {
- switch (i) /* If so, look at the return value. */
- {
- case 0: /* Nothing went wrong, do nothing. */
- break;
- case 1:
- case 2: /* Fatal error, return error code. */
- case 4:
- case 5:
- case 7:
- return(i);
- default: /* Non-fatal, rename file and continue. */
- ren_bad_arc(path,file_list[count].filename);
- }
- }
- else /* Not doing bundles. If we got an error, just return it. */
- {
- if (i == 8 && ignore_archiver_errors)
- i = 0;
- else
- if (i)
- return(i);
- }
- }
- }
- return(0); /* No fatal errors. Return. */
- }
-
- /****************************************************************************
- Find "PENGUIN=" in environment
-
- Unfortunately, under Amiga Lattice the 'getenv()' function only returns
- Commodore's Environment variables, *NOT* the more common Manx/ARP/Rockiki
- style variables... I will try to remedy this in the future.
- ****************************************************************************/
- int p_env(void)
- {
- char *t;
-
- t = getenv("PENGUIN"); /* Try to find a PENGUIN file. */
-
- if (t != NULL) /* See if "PENGUIN=" in environment. */
- {
- strcpy(config_name,strupr(t)); /* Get the name of the file. */
- return(1); /* Return TRUE. */
- }
- return(0); /* Nothing found, return FALSE. */
- }
-
- /****************************************************************************
- Process the configuration file.
-
- The configuration file consists of one or more blocks that start with
- BEGIN POLYXARC and end with END POLYXARC (case insensitive). Between the
- delimiting statements are one or more keywords, one per line. Most keywords
- will have parameters sharing the line. Keywords are:
-
- ARC level overwrite extract extract_command_template
-
- %1: extraction string
- %2: overwrite string
- %3: archive file spec
- %4: extracted file spec
-
- SIGNATURE offset signature overwrite extract extract_command_template
-
- %1: extraction string
- %2: overwrite string
- %3: archive file spec
- %4: extracted file spec
-
- NOSORT
-
- ****************************************************************************/
- int get_config(char *argv0)
- {
- FILE *config=NULL; /* Config file. */
- char *f; /* Scratch string */
- char *g; /* Scratch string */
- char *s1; /* Pointer to signature token. */
- char *s2; /* Pointer to overwrite token. */
- char *s3; /* Pointer to extract token. */
- char oneline[132]; /* Holds one line from file. */
- register int i; /* scratch integer */
- int quit;
- int arc6; /* True if found version 6 definition. */
- long l;
-
- if (config_name_set || !(config_name == NULL))
- config = fopen(config_name,"rt"); /* Open the config file. */
- if (config == NULL && !config_name_set) /* Did it work? */
- { /* Nope. */
- path_name(argv0,config_name,NULL); /* Get path of POLYXARC.EXE. */
- strcat(config_name,DEFAULT_NAME); /* Add the default .CFG name. */
- config = fopen(config_name,"rt"); /* Now try to open it. */
- if (config == NULL) /* Did that work? */
- { /* Nope. */
-
- /* Set up the config name to default to the default name in the current
- directory, then try to find a PENGUIN file. If there is a penguin file,
- it overrides the default. Otherwise, we'll try the default. */
- strcpy(config_name,DEFAULT_NAME); /* Restore the default. */
- if (p_env()) /* Get PENGUIN file, if any. */
- config = fopen(config_name,"rt");/* Try to open it. */
- }
- }
- if (config == NULL) /* Nothing worked! */
- {
- printf("Cannot open configuration file %s.\n",config_name);
- return(1);
- }
- arc_list = /* Pre-allocate 1. */
- (ARC_TYPE *)malloc(sizeof(ARC_TYPE));
- signature_list = /* Pre-allocate 1. */
- (SIGNATURE_TYPE *)malloc(sizeof(SIGNATURE_TYPE));
- do /* Do until we run out of file. */
- {
- i = TRUE; /* Initialize this flag. */
- do /* Do until i == FALSE. */
- {
- f = fgets(oneline,sizeof(oneline),config); /* Get one line. */
- if (f == NULL) /* Did it work? */
- i = FALSE; /* If not, drop through. */
- else
- {
- if ((g = parmtok(oneline," \t\n")) != NULL)/* Tokenize the line. */
- {
- if (stricmp(g,"BEGIN") == 0)/* First word BEGIN? */
- {
- g = parmtok(NULL," \t\n"); /* If so, tokenize again. */
- if (stricmp(g,"POLYXARC") == 0) /* Second word POLYXARC? */
- i = FALSE; /* If so, drop through. */
- }
- }
- }
- } while (i); /* Do this until i == FALSE. */
- quit = 0; /* Don't quit yet! */
- do /* Do until quit. */
- {
- f = fgets(oneline,sizeof(oneline),config); /* Get a line. */
- if (f != NULL) /* Did it work? */
- { /* Yup. */
- if ((g = parmtok(oneline," \t\n")) != NULL)/* Tokenize. */
- {
- /* ARC level command_template */
- if (strnicmp(g,"ARC",3) == 0) /* First word ARC? */
- { /* Yup. */
- arc6 = ('6' == g[3]);
- i = atoi(parmtok(NULL," \t\n"));/* Get ARC level. */
- s2 = parmtok(NULL," \t\n"); /* Get overwrite switch. */
- s3 = parmtok(NULL," \t\n"); /* Get extract switch. */
- g = parmtok(NULL,"\n"); /* Get the template. */
- if (g == NULL) /* Did we get all those fields? */
- { /* Nope, something was left out. */
- printf("Syntax error in config file.\n");
- return(7);
- }
- while (*g == ' ' || *g == '\t') /* Remove leading spaces. */
- ++g;
- arc_list = /* Allocate room for more. */
- (ARC_TYPE *)realloc(arc_list,
- (arc_count + 1) * sizeof(ARC_TYPE));
- arc_list[arc_count].type = (byte)i; /* Save ARC level. */
- arc_list[arc_count].version = (byte)arc6;/* Record if version 6. */
- strcpy(arc_list[arc_count].overwrite, /* Save overwrite. */
- strtrunc(s2,OVER_LEN - 1));
- strcpy(arc_list[arc_count].extract, /* Save extract. */
- strtrunc(s3,EXTR_LEN - 1));
- arc_list[arc_count].cmdline = /* Allocate for template. */
- malloc(strlen(g) + 1);
- strcpy(arc_list[arc_count].cmdline,g); /* Save template. */
- ++arc_count; /* Count up. */
- }
- /* SIGNATURE offset signature command_template */
- else if (stricmp(g,"SIGNATURE") == 0) /* First word SIGNATURE? */
- { /* Yup. */
- l = atol(parmtok(NULL," \t\n"));/* Get ARC level. */
- s1 = parmtok(NULL," \t\n"); /* Get signature string. */
- s2 = parmtok(NULL," \t\n"); /* Get overwrite switch. */
- s3 = parmtok(NULL," \t\n"); /* Get extract switch. */
- g = parmtok(NULL,"\n"); /* Get the template. */
- if (g == NULL) /* Did we get all those fields? */
- { /* Nope, something was left out. */
- printf("Syntax error in config file.\n");
- return(7);
- }
- while (*g == ' ' || *g == '\t') /* Remove leading spaces. */
- ++g;
- signature_list = /* Allocate room for more. */
- (SIGNATURE_TYPE *)realloc(signature_list,
- (signature_count + 1) * sizeof(SIGNATURE_TYPE));
- signature_list[signature_count].file_offset = l;/* Save offset. */
- strcpy(signature_list[signature_count].signature,/* Save signature. */
- strtrunc(s1,SIGN_LEN - 1));
- strcpy(signature_list[signature_count].overwrite,/* Save overwrite. */
- strtrunc(s2,OVER_LEN - 1));
- strcpy(signature_list[signature_count].extract, /* Save extract. */
- strtrunc(s3,EXTR_LEN - 1));
- signature_list[signature_count].cmdline = /* Allocate for template. */
- malloc(strlen(g) + 1);
- strcpy(signature_list[signature_count].cmdline,g); /* Save template. */
- ++signature_count; /* Count up. */
- }
- else if (stricmp(g,"NOSORT") == 0) /* First word NOSORT? */
- { /* Yup. */
- nosort = TRUE; /* Override sort directive. */
- }
- else if (stricmp(g,"END") == 0) /* First word END? */
- { /* Yup. */
- g = parmtok(NULL," \t\n"); /* Tokenize again. */
- if (stricmp(g,"POLYXARC") == 0) /* Second word POLYXARC? */
- quit = 1; /* Yup. Ignore everything
- until end of file or
- another BEGIN POLYXARC. */
- }
- }
- }
- else
- quit = 2; /* Reached end of file, really quit now. */
- } while (!quit); /* Do until quit. */
- } while (quit < 2); /* If quit == 1, not end of file, just end of
- BEGIN/END block. Keep looking. */
- fclose(config); /* End of file, close it. */
- return(0); /* No errors, return 0. */
- }
-
- /****************************************************************************
- This sorts the .ARC list by type.
- ****************************************************************************/
- void sort_arc_list(void)
- {
- ARC_TYPE local_arc_list;
- register int i;
- register int j;
- register int k;
- register int swapped;
-
- k = arc_count - 1;
- do
- {
- swapped = 0;
- for (i = 0; i < k; ++i)
- {
- j = arc_list[i].version - arc_list[i+1].version;
- if (j > 0 || (j == 0 && arc_list[i].type > arc_list[i+1].type))
- {
- memcpy((char *)&local_arc_list,(char *)&arc_list[i],sizeof(ARC_TYPE));
- memcpy((char *)&arc_list[i],(char *)&arc_list[i+1],sizeof(ARC_TYPE));
- memcpy((char *)&arc_list[i+1],(char *)&local_arc_list,sizeof(ARC_TYPE));
- swapped = 1;
- }
- }
- --k;
- } while (swapped);
- }
-
- /****************************************************************************
- Process command-line parameters
-
- -# Does not recognize a .MO? - .SU? file unless it ends
- with a decimal digit. Used only with the -F flag.
- -Cconf Specify configuration file. Default is POLYXARC.CFG.
- -D Will delete the archive if the extract was successful.
- -F[n] Will process all Compressed Mail bundles found in Dir.
- -Maddr Will calculate Compressed Mail bundle name to show the
- sending Net Address. "addr" is YOUR Net/Node address.
- -N Will NOT attempt to sort the archive prior to extract.
- -O Overwrite. Will NOT prompt if existing file is found.
- -R Same as -O, included for ARCE syntax compatibility.
- -Q QuietMode. Will NOT display the runtime configuration.
-
- If -F is used then "Archive" MUST be a Path ONLY, not a Filename.
- Use of -F forces -D and -O to be set TRUE and -N to be set False.
- (The NOSORT verb in the configuration file overrides the -F parameter
- and forces -N to be set True.) If a number is specified with the
- -F parameter, then PolyXarc will only process that number of archives
- (as a maximum).
- ****************************************************************************/
- void process_args(char *arg)
- {
- char *tok;
-
- tok = strtok(arg,"\n");
- if (tok == NULL)
- return;
- if (*tok == '/' || *tok == '-')
- {
- ++tok;
- switch(toupper(*tok))
- {
- case '#': digits_only = TRUE;
- break;
- case 'C': strcpy(config_name,strupr(++tok));
- config_name_set = TRUE;
- break;
- case 'D': delete_archives = TRUE;
- break;
- case 'F': do_all_bundles = TRUE;
- do_n_bundles = atoi(++tok);
- break;
- case 'I': ignore_archiver_errors = TRUE;
- break;
- case 'M': show_addresses = TRUE;
- this_net = (unsigned int)atol(strtok(++tok,"/."));
- this_node = (unsigned int)atol(strtok(NULL,"/."));
- break;
- case 'N': nosort = TRUE;
- break;
- case 'O':
- case 'R': overwrite = TRUE;
- break;
- case 'Q': quiet = TRUE;
- break;
- }
- }
- else
- {
- switch(name_count++)
- {
- case 0: strcpy(archive_name,strupr(tok)); /* Get archive filespec. */
- archive_name_set = TRUE;
- break;
- case 1: strcpy(extract_name,tok); /* Get extract name filespec. */
- break;
- default: strcat(extract_name," "); /* Add a space for parameter separation. */
- strcat(extract_name,tok); /* Get another extract name filespec. */
- break;
- }
- }
- }
-
- /****************************************************************************
- Display the run-time configuration.
- ****************************************************************************/
- void display_configuration(void)
- {
- printf("Archive %s is %s.\n",
- do_all_bundles ? "path" : "name",
- archive_name_set ? (char *)archive_name : "the current directory");
- printf("Using configuration file %s.\n",config_name);
- printf("%s delete archives after extraction.\n",
- delete_archives ? "Will" : "Will not");
- if (do_all_bundles)
- {
- if (do_n_bundles)
- printf("Will process up to %d mail archives.\n",do_n_bundles);
- else
- printf("Will process all mail archives.\n");
- }
- printf("%s show source addresses.\n",show_addresses ? "Will" : "Will not");
- if (show_addresses)
- printf("This node's address is %u/%u.\n",this_net,this_node);
- printf("%s sort .ARC format archives.\n",nosort ? "Will not" : "Will");
- printf("%s automatically overwrite existing files.\n\n",
- overwrite ? "Will" : "Will not");
- if (ignore_archiver_errors)
- printf("Will ignore errors from the archiver(s).\n");
- }
-
- /****************************************************************************
- Main function.
-
- Returns 0 if successful, or errorlevel for DOS on error:
- 1 = Can't open/read source. (missing or invalid file)
- 2 = Can't create/write dest (maybe disk or directory full)
- 3 = Can't delete old source file. (read-only)
- 4 = Can't rename temp file to source name.
- 5 = Out of memory.
- 6 = Cannot determine archive type.
- 7 = Configuration file syntax error.
- 8 = Non-0 error return from archive extractor.
- 9 = Zero-length file.
- 10 = Error while attempting to execute the archiver.
- ****************************************************************************/
- int main(int argc,char **argv)
- {
- int i;
-
- printf("\nPolyXarc v" R_VERS " " R_PORT " " R_DATE "; Public Domain.\n");
- printf("Written by Jeffrey Nonken of 1:273/715@Fidonet (215)279-9799.\n\n");
- #ifdef AMIGA
- printf("Ported to the Amiga by Steven M. Palm. 1:11/16 @ FidoNet\n");
- printf("Subject to change without notice. No support implied.\n");
- printf("Just a reminder: This uses MS-DOS style wildcards.\n\n");
- #endif
- #ifdef OS_2
- printf("Ported to OS/2 by Bill Andrus of 1:109/301@Fidonet.\n\n");
- #endif
-
-
- if (argc == 2) if (stricmp(argv[1],"?") == 0)
- {
- printf("PolyXarc archive [-Cconf] [-D] [-F[n]] [-#] [-Maddr] [-N]\n"
- " [-O|R] [-Q] [-I] [filename [filename...]]\n"
- "See POLYXARC.DOC for more details.\n");
- quit(0);
- }
- for (i = 1; i < argc; ++i) /* Process command-line arguments. */
- process_args(argv[i]);
- if (do_all_bundles) /* If -f, override some settings. */
- {
- delete_archives = TRUE; /* Delete archives when done. */
- overwrite = TRUE; /* Overwrite existing files. */
- nosort = FALSE; /* Don't sort. */
- slash(archive_name); /* Add trailing backslash to path. */
- }
- #ifndef AMIGA
- else /* I said we don't do default extensions under AmigaDOS... ;^) */
- default_ext(archive_name,"*"); /* If no extension, add ".*". */
- #endif
- i = get_config(argv[0]); /* Get the configuration file. */
- if (!i) /* If it worked, keep going. */
- {
- sort_arc_list(); /* Sort the .ARC list by level. */
- if (!do_all_bundles /* Doing bundles? */
- && !archive_name_set) /* If not, needs a filename. */
- { /* No file name specified! Return error. */
- printf("Error: archive name not specified. Use 'PolyXarc ?' for help.\n");
- quit(1);
- }
- if (!quiet) /* If no -q, display runtime config. */
- display_configuration();
- i = discombobulate_all(archive_name,extract_name,do_all_bundles);
- }
- fcloseall(); /* Close all files. */
-
- #ifdef AMIGA
- quit(i); /* for some reason, return() will not function as the */
- /* exit the main function prperly under Lattice 5.05. */
- /* It always gives 0. I don't s'pose it would hurt to */
- /* do this on the IBM set as well.... */
- #endif
-
- /* Actually, you get a warning from the MSC compiler if you don't have
- a return statement in a function. I decided to leave the return in for
- MSC and TURBOC. jjn */
-
- #ifdef IBM
- quit(i);
- return(i);
- #endif
- }