home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-04-18 | 60.0 KB | 1,832 lines |
- Newsgroups: comp.sources.misc,alt.binaries.pictures.utilities
- From: jstevens@teal.csn.org (John W.M. Stevens)
- Subject: v36i118: unpost - Smart multi-part uudecoder v2.1.2, Part05/07
- Message-ID: <1993Apr19.052534.29070@sparky.imd.sterling.com>
- X-Md4-Signature: ca453234eabb492cd4625500f4a37a38
- Date: Mon, 19 Apr 1993 05:25:34 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: jstevens@teal.csn.org (John W.M. Stevens)
- Posting-number: Volume 36, Issue 118
- Archive-name: unpost/part05
- Environment: UNIX, MS-DOS, OS/2, Windows, MacIntosh, Amiga, Vax/VMS
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # Contents: changes.doc decode.c list.h rematch.c unpost.c uudec.c
- # Wrapped by kent@sparky on Sun Apr 18 23:10:31 1993
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 5 (of 7)."'
- if test -f 'changes.doc' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'changes.doc'\"
- else
- echo shar: Extracting \"'changes.doc'\" \(8870 characters\)
- sed "s/^X//" >'changes.doc' <<'END_OF_FILE'
- XChanges for UNPOST Version 2.0.2
- X--------------------------------
- X
- X1) Fixed minor bug with zero length lines.
- X
- X2) Added if-defs around sys_errlist declarations so that they
- X can be conditionally not compiled.
- X
- X3) Modified part 0/# processing so that description articles
- X are written to the incompletes file ONLY if the -d switch is
- X set on the command line.
- X
- X4) Added version printing switch, -v.
- X
- X5) Added AIX make file.
- X
- X6) Added an NNTP client for automated extraction of all articles from
- X specified news groups.
- X
- X The source code is in the nntp directory, and it can be compiled
- X by typing:
- X
- X gcc -o client -ansi client.c
- X
- X on a Sun running:
- X
- X SunOS 4.1 4
- X
- X using gcc:
- X
- X version 2.1
- X
- X Documentation for CLIENT is in the nntp directory.
- X
- X This program is NOT portable. As far as I know, it can only be
- X used by the people who have, at a bare minimum, a Unix that
- X supports sockets as used in the program for communications.
- X
- X If the above does not make sense to you, don't even try it,
- X unless you have a Unix/C/Socket/BDS/Communications expert to
- X try to help you.
- X
- X CLIENT is provided as a tool only for use by experts. You have
- X been warned.
- X
- XChanges for UNPOST Version 2.0.3
- X--------------------------------
- X
- X1) Fixed bug in the way part 0/# segments were handled, as they were
- X not being written out properly.
- X
- X2) Fixed bug in the way part 1/# segments with no uuencode begin line
- X are handled. An error check was placed in the decode logic to report
- X an error if the file name is missing, even though all the
- X segments are present.
- X
- X3) Fixed def.cfg so that it would get through the new parser
- X (removed unnecesary commas).
- X
- X4) Removed '^From ' as one of the segment prefix recognition regular
- X expressions from the default configuration. Sorry about that,
- X for you people whose news readers (like nn, I think) use that as
- X the first line, and who process email.
- X
- X To make up for it, a configuration file (called email.cfg)
- X has been included that should make UNPOST act properly.
- X
- X5) Added an OS/2 EMX/gcc makefile (called makefile.os2) that has the
- X necesary define set to compile out the sys_errlist declarations.
- X
- X6) Added a summary file (you're reading it now), that contains the
- X latest changes as well as a summary for use in posting a
- X description and keeping providing a location for only the changes
- X that have occured since the last version. All changes from
- X version to version, from now on will be copied to the changes.doc
- X file.
- X
- X7) Added a syntax check and very brief syntax description line to
- X retest.
- X
- X8) Added a new debugging utility, mofs. It is a single file program
- X that allows the user to view a file, ala more, starting at a
- X decimal offset.
- X
- X9) Added a configuration file for use in UNPOSTing comp.binaries.ibm.pc
- X and comp.binaries.ms-windows postings (named cbip.cfg).
- X
- X10) Added a new command line switch (-b) to tell UNPOST to write the segments
- X of an incomplete (or damaged) posting to separate files, instead of
- X to the incompletes file.
- X
- XChanges for UNPOST Version 2.1.0
- X--------------------------------
- X
- X1) Bug Fix: UNPOST would not recognize a short (does not start with a
- X 'M', ' ' or '`' character) UU encoded line as the first uuencoded
- X line of a segment. Major bug (truncates files), rarely happens
- X (UNPOST will only skip this line if it is the first line in a
- X segment, and that only happens when a segment is posted with only
- X three lines) therefore hard to notice, but very easy to fix.
- X
- X2) Bug Fix: UNPOST would add one or two extra bytes at the end of a
- X file when decoding. This is due to uuencoders that put out four
- X characters irregardless of whether or not all three bytes are
- X valid. I've been told that this is the standard, so UNPOST was
- X wrong (BZzzt! Got me!).
- X
- X3) Modified the email.cfg file so that it is valid for both the nn
- X news reader and email extraction. Thanks to the alert user who
- X not only found the problem, but also designed THEIR OWN CONFIGURATION
- X FILE (yes, it can be done!) and sent the change to me.
- X
- X4) If a segment has multiple sources of information for the part # of
- X # of parts and binary ID information, the last source now wins. The
- X last source is usually a header dumped into the body by an auto
- X uuencode and split program, and this information is more likely to
- X be correct than the hand typed Subject: stuff in the header.
- X
- X5) Tacked the Subject: line tree into the body, as well as the header
- X in the default configuration. This is for the new anonymous service
- X postings that put a copy of the header from the original message
- X into the body of the posting (irritating, to say the least, that
- X the two Subject: lines often disagree).
- X
- X6) Moved all compiler header files (.h) files into a file called
- X "compiler.h" to simplify making changes as new systems are brought
- X up, and for things that are not the same across all systems.
- X
- X I hated doing this, but it should make things a little easier
- X for those who know enough to make some minor changes to port
- X it to their systems. This suggestion was from Tom Lane
- X (Independent JPEG group, check out the djpeg and cjpeg code,
- X this stuff is really useful to have around).
- X
- X7) Made a few changes according to the suggestions sent to me by a
- X user who modified the program slightly to run under VMS.
- X
- X8) Added if-def's for nn vs. rn news readers, and defines for setting the
- X binary switch default settings. See file compiler.h.
- X
- X Another Tom Lane suggestion.
- X
- X9) Changed source slightly so that the SEGMENT begin line will also be
- X checked for part # of # of parts and binary ID information. This
- X change was made to assist me in creating a working configuration file
- X for Fido Gateway and UUNET users.
- X
- X10) I added an example to the Theory of Operations section in the
- X documentation, and moved some other sections around as per request
- X by a user who thought the order of the configuration, configuration
- X file and regular expression tutorial sections was confusing.
- X
- X Thanks for the input.
- X
- X11) Wrote my own MemCopy and MemMove functions to quash the idiocy with
- X having to if def the hell out of the code to decide which one of
- X three functions to use. Also, I have exactly the same version of
- X gcc on two exactly similiar machines (both the same type of Sparc
- X Station, running exactly the same version of the operating system)
- X but on one machine, gcc bitches about conflicting definitions for
- X memcpy between the builtin function versus the header file, while
- X on the other machine. . . silence. I really hate this sort of
- X garbage.
- X
- X Hey, Tom! Give me solution for this one, and I'll implement it
- X without expressing any opinion at all. . . :-)
- X
- X12) Changed the routine that extracts the binary ID string to use only
- X one word (a string delimited by white space) out of the string,
- X preferably one that has a '.' character in it. This string is
- X filtered to have only MS-DOS/USENET standard file name characters
- X in it. Hopefully, this will reduce the number of misinterpretations,
- X and avoid putting segments of the same posting into different
- X file segment lists. It should, for example, solve the problem
- X of putting
- X
- X Subject: WHITE.GIF (Part 1/2)
- X
- X and
- X
- X Subject: WHITE.GIF, part 1 of 2
- X
- X into two separate file lists, as the comma is NOT an acceptable
- X file name character.
- X
- XChanges for UNPOST Version 2.1.1
- X--------------------------------
- X
- X1) Bug fix. On MS-DOS and OS/2 systems, if you feed UNPOST a non-text
- X file (one that has only line feeds, no carriage returns), very
- X strange things happen. The simple fix was to change from opening
- X the source files in text mode to opening them in binary mode.
- X
- X2) Change 12 for version 2.1.0 had a bug in it that in some (rare)
- X circumstances, would cause core dumps due to accessing a NULL
- X pointer. This has (fingers crossed) been fixed. Thanks to the
- X user who analyzed the problem and sent me the article header
- X that was causing the core dump.
- X
- X3) The help summary now tells the default state of the binary switches.
- X
- X4) In response to the people who need support, a small amount of
- X debugging code has been added. This is activated by defining the
- X UNPOST_DEBUG variable (in compiler.h).
- X
- X5) New switch (-r) tells UNPOST which one of four news readers you
- X are using.
- X -r r For RN, -r e For Email
- X -r n For NN, -r g Look for Newsgroups: line.
- X
- X6) For OS/2 only and if the proper variable is defined, UNPOST will
- X set the file name munging switch on the basis of the file
- X system type of the default drive.
- X
- Xjstevens@csn.org
- END_OF_FILE
- if test 8870 -ne `wc -c <'changes.doc'`; then
- echo shar: \"'changes.doc'\" unpacked with wrong size!
- fi
- # end of 'changes.doc'
- fi
- if test -f 'decode.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'decode.c'\"
- else
- echo shar: Extracting \"'decode.c'\" \(12412 characters\)
- sed "s/^X//" >'decode.c' <<'END_OF_FILE'
- X/******************************************************************************
- X* Module : UUdecode --- Test for and decode a uuencoded text.
- X*
- X* Author : John W. M. Stevens
- X******************************************************************************/
- X
- X#include "compiler.h"
- X
- X#include "unpost.h"
- X#include "regexp.h"
- X#include "parse.h"
- X#include "uudec.h"
- X#include "decode.h"
- X#include "modflnm.h"
- X#include "utils.h"
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : OpenBinFile() --- Find the begin line, and open the output
- X| binary file.
- X|
- X| Inputs : InFlPtr - Pointer to input source file.
- X| InBfr - Buffer to read lines into when searching for
- X| begin line.
- X|
- X| Returns : Pointer to the binary file to write to.
- X-----------------------------------------------------------------------------*/
- X
- Xstatic
- XFILE *OpenBinFile(FILE *InFlPtr,
- X char *FlName,
- X char *InBfr)
- X{
- X auto FILE *OutFlPtr;
- X auto char **RetStrs;
- X
- X extern FILE *ErrFile;
- X
- X /* Get begin line. */
- X if (ReadLine(InFlPtr, InBfr, BFR_SIZE) != EOF)
- X {
- X /* Is this the begin line? */
- X if ( MatchBegin(InBfr, &RetStrs) )
- X {
- X /* Check to make sure that file does not already exist. */
- X if ( FileExists( FlName ) )
- X {
- X fprintf(ErrFile,
- X "\t%s %d : Error - file '%s' already exists.\n",
- X __FILE__,
- X __LINE__,
- X FlName);
- X return( NULL );
- X }
- X
- X /* Open the file. */
- X if ((OutFlPtr = fopen(FlName, BIN_WRITE)) == NULL)
- X {
- X fprintf(ErrFile,
- X "\t%s %d : Error - %s\n\t'%s'\n",
- X __FILE__,
- X __LINE__,
- X sys_errlist[errno],
- X FlName);
- X return( NULL );
- X }
- X
- X /* Return the file pointer. */
- X return( OutFlPtr );
- X }
- X else
- X {
- X /* Missing begin line. */
- X fprintf(ErrFile,
- X "\t%s %d : Error - missing begin line.\n",
- X __FILE__,
- X __LINE__);
- X fprintf(ErrFile,
- X "\t'%s'\n",
- X InBfr);
- X }
- X }
- X else
- X {
- X /* Missing begin line. */
- X fprintf(ErrFile,
- X "\t%s %d : Error - missing begin line.\n",
- X __FILE__,
- X __LINE__);
- X }
- X
- X /* Return NULL file pointer. */
- X return( NULL );
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : WriteDesc() --- Write descriptions to a separate file.
- X|
- X| Inputs : InFlPtr - Pointer to source file.
- X| DescFlName - Name of description file.
- X| FlDesc - Pointer to file descriptor structure.
- X| InBfr - Pointer to buffer to read lines into.
- X-----------------------------------------------------------------------------*/
- X
- Xstatic
- Xint WriteDesc(FILE *InFlPtr,
- X char *DescFlName,
- X FL_LIST *FlDesc,
- X char *InBfr)
- X{
- X auto CHK_UU_ENC UULnType;
- X auto char **RetStrs;
- X auto int EncLen;
- X auto IDENT *Hdr;
- X auto IDENT *Body;
- X auto FILE *DescFile;
- X
- X extern FILE *ErrFile;
- X
- X /* Open the description file. */
- X if ((DescFile = fopen(DescFlName, TXT_WRITE)) == NULL)
- X {
- X fprintf(ErrFile,
- X "\t%s %d : Error - Could not open description file ",
- X __FILE__,
- X __LINE__);
- X fprintf(ErrFile,
- X "'%s' for writing.\n",
- X DescFlName);
- X return( ERROR );
- X }
- X
- X /* Check to see which one of the segments exist. */
- X if ( FlDesc->Segs[0].Exists )
- X {
- X /* Position file pointer to start of segment. */
- X if (fseek(InFlPtr, FlDesc->Segs[0].SegOfs, SEEK_SET) != 0)
- X {
- X fprintf(ErrFile,
- X "\t%s %d : Error - %s\n",
- X __FILE__,
- X __LINE__,
- X sys_errlist[errno]);
- X fclose( DescFile );
- X return( ERROR );
- X }
- X
- X /* Dump lines until the start of the next segment is seen. */
- X if (ReadLine(InFlPtr, InBfr, BFR_SIZE) != EOF)
- X {
- X /* Print the line. */
- X fprintf(DescFile, "%s\n", InBfr);
- X
- X /* Print description. */
- X while (ReadLine(InFlPtr, InBfr, BFR_SIZE) != EOF)
- X {
- X /* Is this a SEGMENT begin line? */
- X if ( MatchSegment(InBfr, &Hdr, &Body) )
- X break;
- X
- X /* Print the line. */
- X fprintf(DescFile, "%s\n", InBfr);
- X }
- X }
- X }
- X
- X /* Position file pointer to start of segment. */
- X if (fseek(InFlPtr, FlDesc->Segs[1].SegOfs, SEEK_SET) != 0)
- X {
- X fprintf(ErrFile,
- X "\t%s %d : Error - %s\n",
- X __FILE__,
- X __LINE__,
- X sys_errlist[errno]);
- X fclose( DescFile );
- X return( ERROR );
- X }
- X
- X /* Dump lines until first UU encoded line is seen. */
- X while (ReadLine(InFlPtr, InBfr, BFR_SIZE) != EOF)
- X {
- X /* Print the line. */
- X fprintf(DescFile, "%s\n", InBfr);
- X
- X /* Check to see if this line is a UU encoded line. */
- X UULnType = ChkUULine(InBfr, &RetStrs, &EncLen);
- X if (UULnType == UU_BEGIN ||
- X UULnType == UU_END ||
- X UULnType == IS_UU_LINE)
- X break;
- X }
- X
- X /* Return no error. */
- X fprintf(DescFile, "\n");
- X fclose( DescFile );
- X return( OK );
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : DecSeg() --- Decode a single segment.
- X|
- X| Inputs : InFlPtr - Pointer to source file.
- X| OutFlPtr - Pointer to output binary file.
- X| Outputs : UULnType - Returns UU line type.
- X|
- X| Returns : EOF - For end of file.
- X| ERROR - For a binary file write error.
- X-----------------------------------------------------------------------------*/
- X
- Xint DecSeg(FILE *InFlPtr,
- X FILE *OutFlPtr,
- X CHK_UU_ENC *UULnType)
- X{
- X auto int OutLen;
- X
- X /* Externals used by this function. */
- X extern char InBfr[];
- X extern BYTE OutBfr[];
- X extern FILE *ErrFile;
- X
- X /* Decode lines until end of segment. */
- X for ( ; ; )
- X {
- X /* Get a line from the file. */
- X if (ReadLine(InFlPtr, InBfr, BFR_SIZE) == EOF)
- X return( EOF );
- X
- X /* Check the line to make sure that it is a UUENCODE
- X * line, and if it is, decode it.
- X */
- X *UULnType = DecUULine(InBfr, &OutLen, OutBfr);
- X if (*UULnType == NOT_UU_LINE ||
- X *UULnType == UU_BEGIN ||
- X *UULnType == UU_END)
- X break;
- X else if (*UULnType == UU_SPACE)
- X continue;
- X
- X /* Are there any bytes to write? */
- X if ( OutLen )
- X {
- X /* Write the buffer to the output file. */
- X if (fwrite(OutBfr, 1, OutLen, OutFlPtr) != OutLen)
- X {
- X fprintf(ErrFile,
- X "\t%s %d : Error - Bad write to binary file.\n",
- X __FILE__,
- X __LINE__);
- X return( ERROR );
- X }
- X }
- X }
- X
- X /* No errors, all is cool. */
- X return( OK );
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : DeCode() --- Decode the file.
- X|
- X| Inputs : InFlPtr - Pointer to source file.
- X| FlDesc - Pointer to file descriptor.
- X-----------------------------------------------------------------------------*/
- X
- Xint DeCode(FILE *InFlPtr,
- X FL_LIST *FlDesc)
- X{
- X register int i;
- X auto FILE *OutFlPtr;
- X auto int ret;
- X auto CHK_UU_ENC UULnType;
- X auto char OutFlNm[FL_NM_SZ];
- X
- X /* Externals used by this function. */
- X extern int DumpDesc;
- X extern char InBfr[];
- X extern FILE *ErrFile;
- X
- X /* Check to make sure that all segments are present before we
- X * decode.
- X */
- X for (i = 1; i <= FlDesc->NoSegs; i++)
- X {
- X /* Check for missing segments. */
- X if (FlDesc->Segs[i].SegNo == 0)
- X {
- X fprintf(ErrFile,
- X "\t%s %d : Error - missing segment #%d.\n",
- X __FILE__,
- X __LINE__,
- X i);
- X fprintf(ErrFile,
- X "\tBinary ID: '%s'\n",
- X FlDesc->IDString);
- X return( ERROR );
- X }
- X }
- X
- X /* Check for file name. If none, report error. */
- X if (! FlDesc->FlName)
- X {
- X fprintf(ErrFile,
- X "\t%s %d : Error - missing file name.\n",
- X __FILE__,
- X __LINE__);
- X fprintf(ErrFile,
- X "\tBinary ID: '%s'\n",
- X FlDesc->IDString);
- X return( ERROR );
- X }
- X
- X /* If we want descriptions, dump the first part of segment one. */
- X if ( DumpDesc )
- X {
- X /* Dump description for zero segment, if one exists, and
- X * dump the first part of segment one (up to and including
- X * the begin line.
- X */
- X ModExten(FlDesc->FlName, ".inf", OutFlNm);
- X WriteDesc(InFlPtr, OutFlNm, FlDesc, InBfr);
- X }
- X
- X /* Now that we have scanned all lines, decode file. */
- X for (i = 1; i <= FlDesc->NoSegs; i++)
- X {
- X /* Position file pointer to first UUencoded
- X * line of segment.
- X */
- X if (fseek(InFlPtr, FlDesc->Segs[i].UUOfs, SEEK_SET) != 0)
- X {
- X fprintf(ErrFile,
- X "\t%s %d : Error - %s\n",
- X __FILE__,
- X __LINE__,
- X sys_errlist[errno]);
- X return( ERROR );
- X }
- X
- X /* Open the binary file. */
- X if (i == 1)
- X {
- X /* Open the binary file. */
- X if ((OutFlPtr = OpenBinFile(InFlPtr,
- X FlDesc->FlName,
- X InBfr)) == NULL)
- X return( ERROR );
- X }
- X
- X /* Decode lines until end of segment. */
- X if ((ret = DecSeg(InFlPtr, OutFlPtr, &UULnType)) == EOF ||
- X ret == ERROR)
- X {
- X /* Close output file, return error. */
- X fclose( OutFlPtr );
- X return( ret );
- X }
- X
- X /* Check for various errors. */
- X if (UULnType == NOT_UU_LINE)
- X {
- X /* Is there supposed to be a end line in this segment? */
- X if (i == FlDesc->NoSegs)
- X {
- X fprintf(ErrFile,
- X "\t%s %d : Error - Missing UU end line.\n",
- X __FILE__,
- X __LINE__);
- X fprintf(ErrFile,
- X "\t'%s'\n",
- X InBfr);
- X fclose( OutFlPtr );
- X return( ERROR );
- X }
- X }
- X else if (UULnType == UU_END)
- X {
- X /* Is this supposed to be the end? */
- X if (i < FlDesc->NoSegs)
- X {
- X fprintf(ErrFile,
- X "\t%s %d : Warning - Early uuencode end line.\n",
- X __FILE__,
- X __LINE__);
- X }
- X break;
- X }
- X else if (UULnType == UU_BEGIN)
- X {
- X /* What the HELL is this doing here?! */
- X fprintf(ErrFile,
- X "\t%s %d : Error - Unexpected UU begin line.\n",
- X __FILE__,
- X __LINE__);
- X return( ERROR );
- X }
- X }
- X
- X /* Close the output file. */
- X fclose( OutFlPtr );
- X return( OK );
- X}
- END_OF_FILE
- if test 12412 -ne `wc -c <'decode.c'`; then
- echo shar: \"'decode.c'\" unpacked with wrong size!
- fi
- # end of 'decode.c'
- fi
- if test -f 'list.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'list.h'\"
- else
- echo shar: Extracting \"'list.h'\" \(843 characters\)
- sed "s/^X//" >'list.h' <<'END_OF_FILE'
- X/******************************************************************************
- X* Module : List --- List building and maintenance module.
- X*
- X* Author : John Stevens.
- X******************************************************************************/
- X
- X#if ! defined(LIST_HEADER_FILE)
- X#define LIST_HEADER_FILE
- X
- X/* Define a list header structure. */
- Xtypedef struct {
- X int NoElems;
- X int TotElems;
- X int ElemSz;
- X char List[1];
- X} LIST;
- X
- X/* Function prototypes. */
- Xextern void *AddList(LIST *, void *, int);
- Xextern void *CrtList(int);
- Xextern int SrchList(LIST *Head,
- X void *Elem,
- X int (*CmpFn)(void *, void *),
- X int *InsPt);
- Xextern void *ListIdx(LIST *, int);
- Xextern void *AppList(LIST *, void *);
- X
- X#endif
- END_OF_FILE
- if test 843 -ne `wc -c <'list.h'`; then
- echo shar: \"'list.h'\" unpacked with wrong size!
- fi
- # end of 'list.h'
- fi
- if test -f 'rematch.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'rematch.c'\"
- else
- echo shar: Extracting \"'rematch.c'\" \(13245 characters\)
- sed "s/^X//" >'rematch.c' <<'END_OF_FILE'
- X/******************************************************************************
- X* Module : Regular Expression Matching.
- X*
- X* Author : John W. M. Stevens.
- X******************************************************************************/
- X
- X#include "compiler.h"
- X
- X#include "sets.h"
- X#include "regexp.h"
- X#include "utils.h"
- X
- X/* Define sub expression list. */
- Xtypedef struct {
- X char *Start; /* Start of sub-string in source. */
- X char *End; /* End of sub-string in source. */
- X char *SubStr; /* Pointer to sub-string. */
- X} SUB_EXPR;
- Xstatic SUB_EXPR SubExprs[MAX_SUB_EXPRS + 1];
- X
- Xstatic CASE_CMP CmpCase = CASE_SENSITIVE;
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : ExtSubStrs() --- Extract the sub-strings from the string to
- X| match against.
- X-----------------------------------------------------------------------------*/
- X
- Xstatic
- Xvoid ExtSubStrs(void)
- X{
- X register int i;
- X register int StrLen;
- X auto char *Str;
- X extern FILE *ErrFile;
- X
- X /* Extract all sub strings from the source string. */
- X for (i = 0; i <= MAX_SUB_EXPRS; i++)
- X {
- X /* Report run time error. */
- X if (SubExprs[i].Start == NULL || SubExprs[i].End == NULL)
- X continue;
- X else if (SubExprs[i].Start > SubExprs[i].End)
- X {
- X fprintf(ErrFile,
- X "%s %d : Error - sub expression #%d extraction failed.\n",
- X __FILE__,
- X __LINE__,
- X i);
- X exit( 1 );
- X }
- X
- X /* Determine length of string. */
- X for (StrLen = 0, Str = SubExprs[i].Start;
- X Str != SubExprs[i].End;
- X StrLen++, Str++
- X )
- X ;
- X
- X /* Allocate space for the string. */
- X if ((Str = (char *) calloc(1, StrLen + 1)) == NULL)
- X {
- X fprintf(ErrFile,
- X "%s %d : Out of memory.\n",
- X __FILE__,
- X __LINE__);
- X exit( 1 );
- X }
- X
- X /* Copy the string to the new space. */
- X MemCopy(Str, SubExprs[i].Start, StrLen);
- X Str[StrLen] = '\0';
- X
- X /* Add string to sub expression string buffer. */
- X SubExprs[i].SubStr = Str;
- X }
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : ReStrCmp() --- Regular expression string compare.
- X|
- X| Inputs : Str - Pointer to string to attempt to match.
- X| ReStr - Pointer to regular expression string.
- X|
- X| Returns : Returns zero for no match, non-zero for a match.
- X-----------------------------------------------------------------------------*/
- X
- Xstatic
- Xint ReStrCmp(char *Str,
- X char *ReStr)
- X{
- X /* While not end of regular expression string, compare characters. */
- X while ( *ReStr )
- X {
- X /* If the characters do not match, return no match. */
- X if (CmpCase == IGN_CASE)
- X {
- X /* Compare characters regardless of case. */
- X if (tolower( *ReStr ) != tolower( *Str ))
- X return( 0 );
- X
- X /* They match. Increment pointers to next characters. */
- X ReStr++;
- X Str++;
- X }
- X else if (*ReStr++ != *Str++)
- X return( 0 );
- X }
- X return( 1 );
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : ReData() --- Evaluate a regular expression data node.
- X|
- X| Inputs : SrcStart - Start of source string (for left anchor
- X| comparisons).
- X| Str - Pointer to string to attempt to match.
- X| ReExpr - Pointer to regular expression node.
- X| Outputs : Str - Pointer to string after matched portion, or
- X| unchanged since input, if no match.
- X| Srch - Pointer to search description structure.
- X|
- X| Returns : Returns 1 for a match, 0 for no match.
- X-----------------------------------------------------------------------------*/
- X
- Xstatic
- Xint ReData(char *SrcStart,
- X char **Str,
- X REG_EXP_NODE *ReExpr)
- X{
- X register int Match;
- X extern FILE *ErrFile;
- X
- X /* Attempt match. */
- X switch ( ReExpr->NodeType )
- X {
- X case DATA_STRING:
- X /* Compare string. */
- X if ((Match = ReStrCmp(*Str, ReExpr->data.MatchStr)) != 0)
- X {
- X /* Bump the source string pointer. */
- X (*Str) += strlen( ReExpr->data.MatchStr );
- X }
- X break;
- X case DATA_SET:
- X /* Is the current character a member of the set? (Don't
- X * forget that negated sets are already negated at this
- X * point.)
- X */
- X if ((Match = InSet(ReExpr->data.CSet, **Str)) != 0)
- X {
- X /* Bump source string pointer. */
- X (*Str)++;
- X }
- X break;
- X case DATA_ANY:
- X /* Match any character except end of line. */
- X if ((Match = **Str && **Str != '\n') != 0)
- X {
- X /* Bump source string pointer. */
- X (*Str)++;
- X }
- X break;
- X case DATA_LEFT_ANCHOR:
- X /* Is this the start of the line? */
- X Match = *Str == SrcStart;
- X break;
- X case DATA_RIGHT_ANCHOR:
- X /* Is the current character an end of line character? */
- X Match = **Str == '\n' || **Str == '\0';
- X break;
- X default:
- X fprintf(ErrFile,
- X "%s %d : Error - illegal regular expression node type.\n",
- X __FILE__,
- X __LINE__);
- X exit( 1 );
- X }
- X
- X /* Return match state. */
- X return( Match );
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : ReOp() --- Execute a regular expression operator.
- X|
- X| Inputs : SrcStart - Start of source string (for left anchor
- X| comparisons).
- X| Str - Pointer to string to attempt to match.
- X| ReExpr - Pointer to regular expression node.
- X| Outputs : Str - Pointer to string after matched portion, or
- X| unchanged since input, if no match.
- X| Cont - Current regular expression node pointer.
- X|
- X| Returns : Returns 1 for a match, 0 for no match.
- X-----------------------------------------------------------------------------*/
- X
- Xstatic
- Xint ReOp(char *SrcStart,
- X char **Str,
- X REG_EXP_NODE *ReExpr,
- X REG_EXP_NODE **Cont)
- X{
- X register int i;
- X register int Match;
- X auto char *ChkPt;
- X auto REG_EXP_NODE *Tmp;
- X auto REG_EXP_NODE *Node;
- X extern FILE *ErrFile;
- X
- X /* Do operations. */
- X do
- X {
- X /* Attempt match. */
- X switch ( ReExpr->NodeType )
- X {
- X case OP_OR:
- X /* Save check point for backtracking. */
- X ChkPt = *Str;
- X
- X /* Attempt left branch first. */
- X if ((Match = ReOp(SrcStart,
- X Str,
- X ReExpr->Left,
- X &Node)) == 0)
- X {
- X /* Attempt to match the right hand branch. */
- X *Str = ChkPt;
- X Match = ReOp(SrcStart, Str, ReExpr->Right, &Node);
- X }
- X
- X /* Get end of OR. */
- X ReExpr = Node;
- X break;
- X case DATA_SPAN:
- X /* Scan for at least the minimum number of characters. */
- X for (Match = 1, i = 0; i < ReExpr->MinSpan; i++)
- X if (**Str == '\0' || **Str == '\n')
- X {
- X Match = 0;
- X break;
- X }
- X if (! Match)
- X break;
- X
- X /* Skip over all control node types to see if there is
- X * a terminating expression for this span.
- X */
- X for (Tmp = ReExpr->Right;
- X Tmp &&
- X (Tmp->NodeType == OP_L_PAREN ||
- X Tmp->NodeType == OP_R_PAREN ||
- X Tmp->NodeType == END_OR);
- X Tmp = Tmp->Right)
- X ;
- X
- X /* If there is no span terminating expression, then we
- X * automatically match to end of line.
- X */
- X if (Tmp == NULL)
- X {
- X /* Scan to end of input string. */
- X for ( ; **Str; ++*Str)
- X ;
- X
- X /* This is a definite match. */
- X Match = 1;
- X break;
- X }
- X
- X /* We matched at least the minimum number. Now attempt the
- X * maximum number.
- X */
- X for (ChkPt = *Str;
- X *ChkPt && i < ReExpr->MaxSpan;
- X ChkPt++, i++)
- X {
- X /* Search forward until a match is found, or the
- X * max number of any character has been spanned.
- X */
- X *Str = ChkPt;
- X if ((Match = ReOp(SrcStart,
- X Str,
- X ReExpr->Right,
- X &Node)) != 0)
- X {
- X break;
- X }
- X }
- X
- X /* Check for a match. */
- X if (i >= ReExpr->MaxSpan)
- X Match = 0;
- X ReExpr = Node;
- X break;
- X case OP_ENUM:
- X /* Match the correct number of sub-expressions. */
- X for (i = 0; i < ReExpr->MaxSpan; i++)
- X {
- X /* Attempt data match. */
- X if ((Match = ReData(SrcStart,
- X Str,
- X ReExpr->Left)) == 0)
- X {
- X /* Have we at least the minimum? */
- X if (i >= ReExpr->MinSpan)
- X Match = 1;
- X break;
- X }
- X }
- X break;
- X case OP_L_PAREN:
- X /* Save start of sub-expression. */
- X SubExprs[ReExpr->SubExprNo].Start = *Str;
- X Match = 1;
- X break;
- X case OP_R_PAREN:
- X /* Save start of sub-expression. */
- X SubExprs[ReExpr->SubExprNo].End = *Str;
- X Match = 1;
- X break;
- X default:
- X Match = ReData(SrcStart, Str, ReExpr);
- X break;
- X }
- X
- X /* Check for end. */
- X if (ReExpr != NULL)
- X ReExpr = ReExpr->Right;
- X
- X } while (Match && ReExpr && ReExpr->NodeType != END_OR);
- X
- X /* Return match. */
- X *Cont = ReExpr;
- X return( Match );
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : ReMatch() --- Regular expression match.
- X|
- X| Inputs : Str - Pointer to string to attempt to match.
- X| Case - Flag for case sensitivity.
- X| ReExpr - Pointer to regular expression tree root.
- X| Outputs : SubStrs - Pointer to array of returned strings.
- X| NoSubStrs - Size of returned string array.
- X|
- X| Returns : Returns zero for no match, non-zero for a match.
- X-----------------------------------------------------------------------------*/
- X
- Xint ReMatch(char *Str,
- X CASE_CMP Case,
- X REG_EXP_NODE *ReExpr,
- X char ***SubStrs)
- X{
- X register int i;
- X register int Match;
- X auto char *tp;
- X auto char *Loop;
- X auto REG_EXP_NODE *Node;
- X
- X static char *RetStrs[MAX_SUB_EXPRS];
- X extern FILE *ErrFile;
- X
- X /* Run list and free strings. */
- X for (i = 1; i < MAX_SUB_EXPRS; i++)
- X {
- X /* Free previous sub strings. */
- X if (RetStrs[i] != NULL)
- X free( RetStrs[i] );
- X
- X /* Initialize the sub expression list. */
- X RetStrs[i] = NULL;
- X SubExprs[i].Start = SubExprs[i].End = SubExprs[i].SubStr = NULL;
- X }
- X
- X /* If the first node is a left anchor, no shifting is necesary. */
- X tp = Str;
- X CmpCase = Case;
- X if (ReExpr->NodeType == DATA_LEFT_ANCHOR)
- X Match = ReOp(Str, &tp, ReExpr->Right, &Node);
- X else
- X {
- X /* Search forward. */
- X for (Loop = Str; ; Loop++)
- X {
- X /* Search for a match. */
- X tp = Loop;
- X if ((Match = ReOp(Str, &tp, ReExpr, &Node)) != 0)
- X break;
- X
- X /* Check for end of loop. */
- X if (*Loop == '\0' || *Loop == '\n')
- X break;
- X }
- X }
- X
- X /* Create sub string array. */
- X if ( Match )
- X {
- X /* Extract sub expression strings. */
- X ExtSubStrs();
- X for (i = 1; i < MAX_SUB_EXPRS; i++)
- X RetStrs[i] = SubExprs[i].SubStr;
- X
- X /* Return sub string array. */
- X *SubStrs = RetStrs;
- X }
- X
- X /* Return match true or false. */
- X return( Match );
- X}
- END_OF_FILE
- if test 13245 -ne `wc -c <'rematch.c'`; then
- echo shar: \"'rematch.c'\" unpacked with wrong size!
- fi
- # end of 'rematch.c'
- fi
- if test -f 'unpost.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'unpost.c'\"
- else
- echo shar: Extracting \"'unpost.c'\" \(12250 characters\)
- sed "s/^X//" >'unpost.c' <<'END_OF_FILE'
- X/******************************************************************************
- X* Module : Unpost --- Extract a binary file from a multi-part, uuencoded
- X* USENET News posting.
- X*
- X* Author : John W. M. Stevens
- X*
- X* Notes : See the file unpost.doc for information.
- X******************************************************************************/
- X
- X#include "compiler.h"
- X
- X#include "unpost.h"
- X#include "parse.h"
- X#include "segment.h"
- X
- X/*********************************** Globals *********************************/
- Xchar *Version = "UNPOST V2.1.2";
- Xint LineNumber = 0;
- X
- X/* Binary switches. See file compiler.h to change default settings. */
- Xint MsDosFileNms = MUNGE_FILE_NMS;
- Xint DumpDesc = DUMP_DESC_FILES;
- Xint SepIncomps = SEP_INCOMPLETES;
- X
- X/* File pointers. */
- XFILE *ErrFile = NULL; /* Error file. */
- XFILE *TextFile = NULL; /* Write non-binary to file. */
- XFILE *IncompFile = NULL; /* Incompletes file. */
- X/*****************************************************************************/
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : ReadLine() --- Get a line from the file.
- X|
- X| Inputs : FlPtr - Pointer to file to read from.
- X| InBfr - Pointer to buffer to read into.
- X| BfrMax - Max buffer size.
- X|
- X| Returns : Returns EOF or OK.
- X-----------------------------------------------------------------------------*/
- X
- Xint ReadLine(FILE *FlPtr,
- X char *InBfr,
- X int BfrMax)
- X{
- X register int i;
- X extern FILE *ErrFile;
- X
- X /* Get a line from the file. */
- X if (fgets(InBfr, BfrMax, FlPtr) == NULL)
- X {
- X /* Check for end of file. */
- X if ( feof( FlPtr ) )
- X return( EOF );
- X else if ( ferror( FlPtr ) )
- X {
- X fprintf(ErrFile,
- X "%s %d : Error - reading source file.\n",
- X __FILE__,
- X __LINE__);
- X exit( 1 );
- X }
- X }
- X
- X /* Remove trailing '\n' character.
- X *
- X * Maybe THIS time I got it right. . .
- X */
- X LineNumber++;
- X for (i = strlen( InBfr );
- X i > 0 && (InBfr[i - 1] == '\n' || InBfr[i - 1] == '\r');
- X i--
- X )
- X ;
- X InBfr[i] = '\0';
- X
- X /* Return OK. */
- X return( OK );
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : ShowSynopsis() --- Show a summary of the command line
- X| syntax.
- X-----------------------------------------------------------------------------*/
- X
- Xstatic char *Synopsis[] =
- X{
- X"Options:\n",
- X" -b[-] Break incompletes into separate files.\n",
- X" -d[-] Dump descriptions flag.\n",
- X" -e <file> File for errors (default standard error).\n",
- X" -f[-] Modify file names to be MS-DOS compatible.\n",
- X" -h Interpret headers in source files.\n",
- X" -i <file> File to write incomplete binaries to.\n",
- X" -r <e|g|n|r> Set news reader type (SEGMENT begin line RE).\n",
- X" -s Assume segments in order in file.\n",
- X" -t <file> File for text only segments.\n",
- X" -u UU decoder, pure and simple.\n",
- X" -v Print the version number and quit.\n",
- X" -? Show this help summary.\n\n",
- X"Example:\n",
- X" unpost -d -e errors -t text -i multiple.1 multiple.uue\n",
- X" Save errors, text segments, descriptions and incompletes.\n\n",
- XNULL
- X};
- X
- Xstatic
- Xvoid ShowSynopsis(void)
- X{
- X register int i;
- X
- X /* Show header and version number. */
- X printf("%s --- Extract a uuencoded binary from a multi-part posting.\n\n",
- X Version);
- X
- X /* Show synopsis. */
- X for (i = 0; Synopsis[i]; i++)
- X printf( Synopsis[i] );
- X
- X /* Show current state of binary flags. */
- X printf("File Name Modifying (-f) : %-3.3s\n",
- X (MsDosFileNms) ? "On" : "Off");
- X printf("Create Description Files (-d) : %-3.3s\n",
- X (DumpDesc) ? "On" : "Off");
- X printf("Separate Incomplete Files (-b) : %-3.3s\n",
- X (SepIncomps) ? "On" : "Off");
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : CmdLineParse() --- Parse the command line.
- X|
- X| Inputs : argc - Number of command line arguments.
- X| argv - List of command line argument strings.
- X| SwList - Switch list.
- X-----------------------------------------------------------------------------*/
- X
- Xstatic
- Xvoid CmdLineParse(int argc,
- X char **argv,
- X char *SwList)
- X{
- X register int i;
- X auto char *ArgPtr;
- X auto char *SwPtr;
- X auto char SwChar;
- X auto char ModeFlag;
- X
- X /* Check for no arguments. */
- X if (argc < 2)
- X {
- X /* Give synopsis and quit. */
- X ShowSynopsis();
- X exit( 1 );
- X }
- X
- X /* Scan entire command line. */
- X ErrFile = stderr;
- X ModeFlag = 'h';
- X for (i = 1; i < argc; i++)
- X {
- X /* Get a pointer to the argument. */
- X ArgPtr = argv[i];
- X
- X /* Is this a switch? */
- X if (*ArgPtr == '-')
- X {
- X /* Get switch character. */
- X if ((SwChar = *++ArgPtr) == '\0')
- X {
- X /* There is no character after the switch marker,
- X * so declare an error.
- X */
- X ShowSynopsis();
- X exit( 1 );
- X }
- X else if ((SwPtr = strchr(SwList, SwChar)) == NULL)
- X {
- X /* Error, this is evidently an illegal switch
- X * character.
- X */
- X ShowSynopsis();
- X exit( 1 );
- X }
- X else if (SwPtr[1] == '>')
- X {
- X /* Get parameter string. Parameter string can
- X * follow immediately after the switch character,
- X * or it can be the next command line string.
- X */
- X if (*++ArgPtr == '\0')
- X {
- X /* Next command line parameter is switch
- X * parameter string.
- X */
- X if (i + 1 < argc)
- X ArgPtr = argv[++i];
- X else
- X {
- X ShowSynopsis();
- X exit( 1 );
- X }
- X }
- X }
- X else
- X ArgPtr++;
- X }
- X else
- X SwChar = ' ';
- X
- X /* Have argument processed. */
- X switch ( SwChar )
- X {
- X case 'b':
- X /* Set or reset flag that tells UNPOST to separate incompletes
- X * into their own files.
- X */
- X if (*ArgPtr == '-')
- X SepIncomps = 0;
- X else
- X SepIncomps = 1;
- X break;
- X case 'c':
- X /* Initialize the parser, using the default configuration OR
- X * the configuration file.
- X */
- X LoadCfg( ArgPtr );
- X break;
- X case 'd':
- X if (*ArgPtr == '-')
- X DumpDesc = 0;
- X else
- X DumpDesc = 1;
- X break;
- X case 'e':
- X /* Close a file that is already open. */
- X if ( ErrFile )
- X fclose( ErrFile );
- X
- X /* Open a new error file. */
- X if ((ErrFile = fopen(ArgPtr, TXT_WRITE)) == NULL)
- X {
- X fprintf(stderr,
- X "%s %d : Error - Could not open file '%s' ",
- X __FILE__,
- X __LINE__,
- X ArgPtr);
- X fprintf(stderr, "for output.\n");
- X exit( 1 );
- X }
- X break;
- X case 'f':
- X if (*ArgPtr == '-')
- X MsDosFileNms = 0;
- X else
- X MsDosFileNms = 1;
- X break;
- X case 'i':
- X /* Close a file that is already open. */
- X if ( IncompFile )
- X fclose( IncompFile );
- X
- X /* Open an incompletes file. */
- X if ((IncompFile = fopen(ArgPtr, TXT_APPEND)) == NULL)
- X {
- X fprintf(stderr,
- X "%s %d : Error - Could not open file '%s' ",
- X __FILE__,
- X __LINE__,
- X ArgPtr);
- X fprintf(stderr, "for output.\n");
- X exit( 1 );
- X }
- X break;
- X case 'r':
- X SetSegBegin( ArgPtr );
- X break;
- X case 't':
- X /* Close a file that is already open. */
- X if ( TextFile )
- X fclose( TextFile );
- X
- X /* Open file for saving text only segments. */
- X if ((TextFile = fopen(ArgPtr, TXT_WRITE)) == NULL)
- X {
- X fprintf(stderr,
- X "%s %d : Error - Could not open file '%s' ",
- X __FILE__,
- X __LINE__,
- X ArgPtr);
- X fprintf(stderr, "for output.\n");
- X exit( 1 );
- X }
- X break;
- X case 'h':
- X case 'u':
- X case 's':
- X ModeFlag = SwChar;
- X break;
- X case 'v':
- X printf("%s\n", Version);
- X exit( 0 );
- X case ' ':
- X /* Select mode. */
- X switch ( ModeFlag )
- X {
- X case 'h':
- X Multiple( ArgPtr );
- X break;
- X case 's':
- X Single( ArgPtr );
- X break;
- X case 'u':
- X UUDecode( ArgPtr );
- X break;
- X }
- X break;
- X default:
- X ShowSynopsis();
- X exit( 1 );
- X }
- X }
- X}
- X
- X#if defined(MUNGE_FILE_NAMES_PER_FS) && defined(SYSTEM_OS_2)
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : IsHpfs() --- Is this an HPFS?
- X|
- X| Returns : Returns 0 for not a HPFS, or non zero for is.
- X-----------------------------------------------------------------------------*/
- X
- X#if defined(EMX_GCC_COMPILER)
- X
- Xint IsHpfs(void)
- X{
- X auto unsigned long ulDrive;
- X auto unsigned long ulLogical;
- X auto char drive[3];
- X auto char name[16];
- X
- X /* Check operating system mode. */
- X if (_osmode == DOS_MODE)
- X return( 0 );
- X
- X /* Get current disk drive. */
- X DosQueryCurrentDisk(&ulDrive, &ulLogical);
- X
- X /* Set up drive name string. */
- X drive[0] = (char) (ulDrive + '@');
- X drive[1] = ':';
- X drive[2] = '\0';
- X
- X /* Get file system name string. */
- X if (_filesys(drive, name, 16) == -1)
- X return( 0 );
- X
- X /* Is this an HPFS? */
- X if (strcmp(name, "HPFS") == 0)
- X return( 1 );
- X return( 0 );
- X}
- X
- X#elif defined(OS_2_MSC_COMPILER)
- X
- Xint IsHpfs(void)
- X{
- X auto USHORT nDrive;
- X auto ULONG lMap;
- X auto BYTE bData[64];
- X auto BYTE bName[3];
- X auto USHORT cbData;
- X
- X /* MS-DOS does not have HPFS. */
- X if (_osmode == DOS_MODE)
- X return( 0 );
- X
- X /* Get the default drive. */
- X DosQCurDisk(&nDrive, &lMap);
- X
- X /* Set up the drive name. */
- X bName[0] = (char) (nDrive + '@');
- X bName[1] = ':';
- X bName[2] = 0;
- X cbData = sizeof( bData );
- X
- X /* Read the info, if we fail - assume non-HPFS. */
- X if ( DosQFSAttach(bName, 0, FSAIL_QUERYNAME, bData, &cbData, 0L) )
- X return( 0 );
- X else if (strcmp(bData + (*((USHORT *) (bData + 2)) + 7), "HPFS") == 0)
- X return( 1 );
- X return( 0 );
- X}
- X
- X#endif
- X
- X#endif
- X
- Xint main(int argc,
- X char **argv)
- X{
- X /* If the user wants different file name munging on different
- X * systems, set -f flag accordingly, otherwise, leave alone.
- X */
- X#if defined(MUNGE_FILE_NAMES_PER_FS) && defined(SYSTEM_OS_2)
- X MsDosFileNms = ! IsHpfs();
- X#endif
- X
- X /* Parse command line parameters. */
- X ParseInit();
- X CmdLineParse(argc, argv, "bc>de>fhi>r>st>uv");
- X return( 0 );
- X}
- END_OF_FILE
- if test 12250 -ne `wc -c <'unpost.c'`; then
- echo shar: \"'unpost.c'\" unpacked with wrong size!
- fi
- # end of 'unpost.c'
- fi
- if test -f 'uudec.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'uudec.c'\"
- else
- echo shar: Extracting \"'uudec.c'\" \(8450 characters\)
- sed "s/^X//" >'uudec.c' <<'END_OF_FILE'
- X/******************************************************************************
- X* Module : UUdecode --- Test for and decode a uuencoded text.
- X*
- X* Author : John W. M. Stevens
- X******************************************************************************/
- X
- X#include "compiler.h"
- X
- X#include "unpost.h"
- X#include "regexp.h"
- X#include "parse.h"
- X#include "uudec.h"
- X
- X#define DEC_CHAR(c) (((c) - ' ') & 0x3f)
- X#define CHK_SUM_MASK 0x3f
- X
- Xstatic int FixBitNetTwiddleFlag = 0;
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : UULnDec() --- UU decode a line.
- X|
- X| Inputs : LnLen - Length of line.
- X| Line - Pointer to the line buffer.
- X| Outputs : Bfr - Points to buffer for decoded output.
- X-----------------------------------------------------------------------------*/
- X
- Xstatic
- Xint UULnDec(int LnLen,
- X char *Line,
- X BYTE *Bfr)
- X{
- X register int i;
- X register int j;
- X auto int RecLen;
- X auto int tmp;
- X auto int Shift;
- X
- X /* Zero out buffer. */
- X RecLen = DEC_CHAR( *Line );
- X memset(Bfr, 0, RecLen);
- X
- X /* Do actual line decoding. Skip first character, as it is line
- X * length.
- X */
- X for (i = 1, j = 0, Shift = 2;
- X i <= LnLen;
- X i++)
- X {
- X /* Get six bits. */
- X tmp = DEC_CHAR( Line[i] );
- X
- X /* Put into buffer. */
- X Bfr[j] |= tmp << Shift;
- X if (Shift > 2)
- X Bfr[j - 1] |= tmp >> (8 - Shift);
- X
- X /* Increment byte pointer if neccesary. */
- X if (Shift < 6)
- X j++;
- X
- X /* Adjust shift size. */
- X Shift = (Shift + 2) & 0x7;
- X }
- X
- X /* Return size of buffer. */
- X return( RecLen );
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : ChkUUChars() --- Check that a line of the proper length has
- X| the proper characters.
- X|
- X| Inputs : LnLen - Length of line.
- X| Line - Pointer to the line buffer.
- X| Outputs : Line - Pointer to the line buffer with fixes.
- X|
- X| Returns : Returns TRUE - This is a uuencoded line.
- X| FALSE - This is not a uudecoded line.
- X-----------------------------------------------------------------------------*/
- X
- Xstatic
- Xint ChkUUChars(int LnLen,
- X char *Line)
- X{
- X register int i;
- X
- X /* Loop through line, checking that all characters are in proper
- X * range.
- X */
- X for (i = 0; i < LnLen; i++)
- X if (Line[i] == '~' && FixBitNetTwiddleFlag)
- X Line[i] = '^';
- X else if (Line[i] < ' ' || Line[i] > '`')
- X return( NOT_UU_LINE );
- X
- X /* Return that this is an encoded line. */
- X return( IS_UU_LINE );
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : ChkUULine() --- Check to see if this is a UUencoded line.
- X|
- X| Inputs : Line - Pointer to line buffer.
- X| Outputs : RetStrs - Pointer to array of sub strings.
- X| EncLen - Length of unencoded line in bytes.
- X|
- X| Returns : Returns IS_UU_LINE - This is a uuencoded line.
- X| NOT_UU_LINE - This is not a uuencoded line.
- X| UU_SPACE - This is a valid uuencoded empty line.
- X| UU_BEGIN - This is a uuencode begin line.
- X| UU_END - This is a uuencode end line.
- X-----------------------------------------------------------------------------*/
- X
- XCHK_UU_ENC ChkUULine(char *Line,
- X char ***RetStrs,
- X int *EncLen)
- X{
- X auto int RecLen;
- X auto int BfrLen;
- X
- X /* Check for a character in the range of 0x20 to 0x60 inclusive. */
- X if ((*Line >= ' ' && *Line <= 'M') || *Line == '`')
- X {
- X /* Get record length. */
- X RecLen = DEC_CHAR( *Line );
- X
- X /* Get line length. */
- X BfrLen = strlen( Line );
- X
- X /* Calculate the line length based on the record size character. */
- X if (*Line == 'M')
- X *EncLen = 60;
- X else if (*Line == ' ' || *Line == '`')
- X *EncLen = 0;
- X else
- X {
- X /* This is a short line, so calculate the lenght that it's
- X * record length character says it should have.
- X *
- X * The first calculation assumes that for any number of
- X * bytes between 1 and 3 inclusive, that the UU encoder
- X * always spits out four characters.
- X */
- X if (RecLen % 3)
- X *EncLen = 4 * (RecLen / 3 + 1);
- X else
- X *EncLen = 4 * (RecLen / 3);
- X
- X /* If the UU encoder spits out less than four characters
- X * for 1 or 2 bytes, then we need a different calculation.
- X */
- X if (BfrLen != *EncLen + 1 && BfrLen != *EncLen + 2)
- X *EncLen = 4 * (RecLen / 3) + (RecLen % 3 + 1);
- X }
- X
- X /* Check for short or long buffer. */
- X if (BfrLen != *EncLen + 1 && BfrLen != *EncLen + 2)
- X return( NOT_UU_LINE );
- X
- X /* Check for the expected UU characters. */
- X if (ChkUUChars(BfrLen, Line) == NOT_UU_LINE)
- X return( NOT_UU_LINE );
- X
- X /* Return one of two different flags. */
- X if (RecLen == 0)
- X return( UU_SPACE );
- X return( IS_UU_LINE );
- X }
- X else
- X {
- X /* Test for a begin line. */
- X if ( MatchBegin(Line, RetStrs) )
- X return( UU_BEGIN );
- X
- X /* Test for end line. */
- X if ( MatchEnd( Line ) )
- X return( UU_END );
- X }
- X
- X /* This is not a UUencoded line. */
- X return( NOT_UU_LINE );
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : DecUULine() --- Decode a UU encoded line.
- X|
- X| Inputs : Line - Pointer to line buffer.
- X| Outputs : Len - Number of bytes in the buffer.
- X| Bfr - Points to buffer for decoded output.
- X|
- X| Returns : Returns IS_UU_LINE - This is a uuencoded line.
- X| NOT_UU_LINE - This is not a uuencoded line.
- X| UU_SPACE - This is a valid uuencoded empty line.
- X| UU_BEGIN - This is a uuencode begin line.
- X| UU_END - This is a uuencode end line.
- X-----------------------------------------------------------------------------*/
- X
- XCHK_UU_ENC DecUULine(char *Line,
- X int *Len,
- X BYTE *Bfr)
- X{
- X auto int EncLen;
- X auto CHK_UU_ENC UULnType;
- X auto char **RetStrs;
- X
- X /* If this is not a uuencoded line, then it cannot be decoded.
- X * Check it first.
- X */
- X *Len = 0;
- X UULnType = ChkUULine(Line, &RetStrs, &EncLen);
- X if (UULnType != IS_UU_LINE)
- X return( UULnType );
- X
- X /* Do actual UU decode. */
- X *Len = UULnDec(EncLen, Line, Bfr);
- X
- X /* Return the type of line this is. */
- X return( IS_UU_LINE );
- X}
- X
- X/*-----------------------------------------------------------------------------
- X| Routine : DecTruncUULn() --- Decode a possibly truncated UU encoded
- X| line.
- X|
- X| Inputs : Line - Pointer to line buffer.
- X| Outputs : Len - Number of bytes in the buffer.
- X| Bfr - Points to buffer for decoded output.
- X-----------------------------------------------------------------------------*/
- X
- Xvoid DecTruncUULn(char *Line,
- X int *Len,
- X BYTE *Bfr)
- X{
- X register int i;
- X auto int RecLen;
- X auto int BfrLen;
- X auto int EncLen;
- X
- X /* Get line length. */
- X BfrLen = strlen( Line );
- X
- X /* Calculate the line length. */
- X RecLen = DEC_CHAR( *Line );
- X if (RecLen % 3)
- X EncLen = 4 * (RecLen / 3 + 1);
- X else
- X EncLen = 4 * (RecLen / 3);
- X
- X /* If the actual line is shorter than the record length indicates
- X * it ought to be, then pad with spaces.
- X */
- X if (BfrLen <= EncLen)
- X {
- X /* Loop, putting spaces at end. */
- X for (i = BfrLen; i <= EncLen; i++)
- X Line[i] = '`';
- X Line[i] = '\0';
- X }
- X
- X /* Do actual UU line decode. */
- X *Len = UULnDec(EncLen, Line, Bfr);
- X}
- END_OF_FILE
- if test 8450 -ne `wc -c <'uudec.c'`; then
- echo shar: \"'uudec.c'\" unpacked with wrong size!
- fi
- # end of 'uudec.c'
- fi
- echo shar: End of archive 5 \(of 7\).
- cp /dev/null ark5isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 7 archives.
- rm -f ark[1-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-