home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume36 / unpost / part05 < prev    next >
Encoding:
Text File  |  1993-04-18  |  60.0 KB  |  1,832 lines

  1. Newsgroups: comp.sources.misc,alt.binaries.pictures.utilities
  2. From: jstevens@teal.csn.org (John W.M. Stevens)
  3. Subject: v36i118:  unpost - Smart multi-part uudecoder v2.1.2, Part05/07
  4. Message-ID: <1993Apr19.052534.29070@sparky.imd.sterling.com>
  5. X-Md4-Signature: ca453234eabb492cd4625500f4a37a38
  6. Date: Mon, 19 Apr 1993 05:25:34 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: jstevens@teal.csn.org (John W.M. Stevens)
  10. Posting-number: Volume 36, Issue 118
  11. Archive-name: unpost/part05
  12. Environment: UNIX, MS-DOS, OS/2, Windows, MacIntosh, Amiga, Vax/VMS
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  changes.doc decode.c list.h rematch.c unpost.c uudec.c
  19. # Wrapped by kent@sparky on Sun Apr 18 23:10:31 1993
  20. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  21. echo If this archive is complete, you will see the following message:
  22. echo '          "shar: End of archive 5 (of 7)."'
  23. if test -f 'changes.doc' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'changes.doc'\"
  25. else
  26.   echo shar: Extracting \"'changes.doc'\" \(8870 characters\)
  27.   sed "s/^X//" >'changes.doc' <<'END_OF_FILE'
  28. XChanges for UNPOST Version 2.0.2
  29. X--------------------------------
  30. X
  31. X1)  Fixed minor bug with zero length lines.
  32. X
  33. X2)  Added if-defs around sys_errlist declarations so that they
  34. X    can be conditionally not compiled.
  35. X
  36. X3)  Modified part 0/# processing so that description articles
  37. X    are written to the incompletes file ONLY if the -d switch is
  38. X    set on the command line.
  39. X
  40. X4)  Added version printing switch, -v.
  41. X
  42. X5)  Added AIX make file.
  43. X
  44. X6)  Added an NNTP client for automated extraction of all articles from
  45. X    specified news groups.
  46. X
  47. X    The source code is in the nntp directory, and it can be compiled
  48. X    by typing:
  49. X
  50. X    gcc -o client -ansi client.c
  51. X
  52. X    on a Sun running:
  53. X
  54. X    SunOS 4.1 4
  55. X
  56. X    using gcc:
  57. X
  58. X    version 2.1
  59. X
  60. X    Documentation for CLIENT is in the nntp directory.
  61. X
  62. X    This program is NOT portable.  As far as I know, it can only be
  63. X    used by the people who have, at a bare minimum, a Unix that
  64. X    supports sockets as used in the program for communications.
  65. X
  66. X    If the above does not make sense to you, don't even try it,
  67. X    unless you have a Unix/C/Socket/BDS/Communications expert to
  68. X    try to help you.
  69. X
  70. X    CLIENT is provided as a tool only for use by experts.  You have
  71. X    been warned.
  72. X
  73. XChanges for UNPOST Version 2.0.3
  74. X--------------------------------
  75. X
  76. X1)  Fixed bug in the way part 0/# segments were handled, as they were
  77. X    not being written out properly.
  78. X
  79. X2)  Fixed bug in the way part 1/# segments with no uuencode begin line
  80. X    are handled.  An error check was placed in the decode logic to report
  81. X    an error if the file name is missing, even though all the
  82. X    segments are present.
  83. X
  84. X3)  Fixed def.cfg so that it would get through the new parser
  85. X    (removed unnecesary commas).
  86. X
  87. X4)  Removed '^From ' as one of the segment prefix recognition regular
  88. X    expressions from the default configuration.  Sorry about that,
  89. X    for you people whose news readers (like nn, I think) use that as
  90. X    the first line, and who process email.
  91. X
  92. X    To make up for it, a configuration file (called email.cfg)
  93. X    has been included that should make UNPOST act properly.
  94. X
  95. X5)  Added an OS/2 EMX/gcc makefile (called makefile.os2) that has the
  96. X    necesary define set to compile out the sys_errlist declarations.
  97. X
  98. X6)  Added a summary file (you're reading it now), that contains the
  99. X    latest changes as well as a summary for use in posting a
  100. X    description and keeping providing a location for only the changes
  101. X    that have occured since the last version.  All changes from
  102. X    version to version, from now on will be copied to the changes.doc
  103. X    file.
  104. X
  105. X7)  Added a syntax check and very brief syntax description line to
  106. X    retest.
  107. X
  108. X8)  Added a new debugging utility, mofs.  It is a single file program
  109. X    that allows the user to view a file, ala more, starting at a
  110. X    decimal offset.
  111. X
  112. X9)  Added a configuration file for use in UNPOSTing comp.binaries.ibm.pc
  113. X    and comp.binaries.ms-windows postings (named cbip.cfg).
  114. X
  115. X10) Added a new command line switch (-b) to tell UNPOST to write the segments
  116. X    of an incomplete (or damaged) posting to separate files, instead of
  117. X    to the incompletes file.
  118. X
  119. XChanges for UNPOST Version 2.1.0
  120. X--------------------------------
  121. X
  122. X1)  Bug Fix:  UNPOST would not recognize a short (does not start with a
  123. X    'M', ' ' or '`' character) UU encoded line as the first uuencoded
  124. X    line of a segment.  Major bug (truncates files), rarely happens
  125. X    (UNPOST will only skip this line if it is the first line in a
  126. X    segment, and that only happens when a segment is posted with only
  127. X    three lines) therefore hard to notice, but very easy to fix.
  128. X
  129. X2)  Bug Fix: UNPOST would add one or two extra bytes at the end of a
  130. X    file when decoding.  This is due to uuencoders that put out four
  131. X    characters irregardless of whether or not all three bytes are
  132. X    valid.  I've been told that this is the standard, so UNPOST was
  133. X    wrong (BZzzt! Got me!).
  134. X
  135. X3)  Modified the email.cfg file so that it is valid for both the nn
  136. X    news reader and email extraction.  Thanks to the alert user who
  137. X    not only found the problem, but also designed THEIR OWN CONFIGURATION
  138. X    FILE (yes, it can be done!) and sent the change to me.
  139. X
  140. X4)  If a segment has multiple sources of information for the part # of
  141. X    # of parts and binary ID information, the last source now wins.  The
  142. X    last source is usually a header dumped into the body by an auto
  143. X    uuencode and split program, and this information is more likely to
  144. X    be correct than the hand typed Subject: stuff in the header.
  145. X
  146. X5)  Tacked the Subject: line tree into the body, as well as the header
  147. X    in the default configuration.  This is for the new anonymous service
  148. X    postings that put a copy of the header from the original message
  149. X    into the body of the posting (irritating, to say the least, that
  150. X    the two Subject: lines often disagree).
  151. X
  152. X6)  Moved all compiler header files (.h) files into a file called
  153. X    "compiler.h" to simplify making changes as new systems are brought
  154. X    up, and for things that are not the same across all systems.
  155. X
  156. X    I hated doing this, but it should make things a little easier
  157. X    for those who know enough to make some minor changes to port
  158. X    it to their systems.  This suggestion was from Tom Lane
  159. X    (Independent JPEG group, check out the djpeg and cjpeg code,
  160. X    this stuff is really useful to have around).
  161. X
  162. X7)  Made a few changes according to the suggestions sent to me by a
  163. X    user who modified the program slightly to run under VMS.
  164. X
  165. X8)  Added if-def's for nn vs. rn news readers, and defines for setting the
  166. X    binary switch default settings.  See file compiler.h.
  167. X
  168. X    Another Tom Lane suggestion.
  169. X
  170. X9)  Changed source slightly so that the SEGMENT begin line will also be
  171. X    checked for part # of # of parts and binary ID information.  This
  172. X    change was made to assist me in creating a working configuration file
  173. X    for Fido Gateway and UUNET users.
  174. X
  175. X10) I added an example to the Theory of Operations section in the
  176. X    documentation, and moved some other sections around as per request
  177. X    by a user who thought the order of the configuration, configuration
  178. X    file and regular expression tutorial sections was confusing.
  179. X
  180. X    Thanks for the input.
  181. X
  182. X11) Wrote my own MemCopy and MemMove functions to quash the idiocy with
  183. X    having to if def the hell out of the code to decide which one of
  184. X    three functions to use.  Also, I have exactly the same version of
  185. X    gcc on two exactly similiar machines (both the same type of Sparc
  186. X    Station, running exactly the same version of the operating system)
  187. X    but on one machine, gcc bitches about conflicting definitions for
  188. X    memcpy between the builtin function versus the header file, while
  189. X    on the other machine. . .  silence.  I really hate this sort of
  190. X    garbage.
  191. X
  192. X    Hey, Tom!  Give me solution for this one, and I'll implement it
  193. X    without expressing any opinion at all. . . :-)
  194. X
  195. X12) Changed the routine that extracts the binary ID string to use only
  196. X    one word (a string delimited by white space) out of the string,
  197. X    preferably one that has a '.' character in it.  This string is
  198. X    filtered to have only MS-DOS/USENET standard file name characters
  199. X    in it.  Hopefully, this will reduce the number of misinterpretations,
  200. X    and avoid putting segments of the same posting into different
  201. X    file segment lists.  It should, for example, solve the problem
  202. X    of putting
  203. X
  204. X    Subject: WHITE.GIF (Part 1/2)
  205. X
  206. X    and
  207. X
  208. X    Subject: WHITE.GIF, part 1 of 2
  209. X
  210. X    into two separate file lists, as the comma is NOT an acceptable
  211. X    file name character.
  212. X
  213. XChanges for UNPOST Version 2.1.1
  214. X--------------------------------
  215. X
  216. X1)  Bug fix.  On MS-DOS and OS/2 systems, if you feed UNPOST a non-text
  217. X    file (one that has only line feeds, no carriage returns), very
  218. X    strange things happen.  The simple fix was to change from opening
  219. X    the source files in text mode to opening them in binary mode.
  220. X
  221. X2)  Change 12 for version 2.1.0 had a bug in it that in some (rare)
  222. X    circumstances, would cause core dumps due to accessing a NULL
  223. X    pointer.  This has (fingers crossed) been fixed.  Thanks to the
  224. X    user who analyzed the problem and sent me the article header
  225. X    that was causing the core dump.
  226. X
  227. X3)  The help summary now tells the default state of the binary switches.
  228. X
  229. X4)  In response to the people who need support, a small amount of
  230. X    debugging code has been added.  This is activated by defining the
  231. X    UNPOST_DEBUG variable (in compiler.h).
  232. X
  233. X5)  New switch (-r) tells UNPOST which one of four news readers you
  234. X    are using.
  235. X        -r r    For RN,     -r e    For Email
  236. X        -r n    For NN,     -r g    Look for Newsgroups: line.
  237. X
  238. X6)  For OS/2 only and if the proper variable is defined, UNPOST will
  239. X    set the file name munging switch on the basis of the file
  240. X    system type of the default drive.
  241. X
  242. Xjstevens@csn.org
  243. END_OF_FILE
  244.   if test 8870 -ne `wc -c <'changes.doc'`; then
  245.     echo shar: \"'changes.doc'\" unpacked with wrong size!
  246.   fi
  247.   # end of 'changes.doc'
  248. fi
  249. if test -f 'decode.c' -a "${1}" != "-c" ; then 
  250.   echo shar: Will not clobber existing file \"'decode.c'\"
  251. else
  252.   echo shar: Extracting \"'decode.c'\" \(12412 characters\)
  253.   sed "s/^X//" >'decode.c' <<'END_OF_FILE'
  254. X/******************************************************************************
  255. X* Module    :   UUdecode --- Test for and decode a uuencoded text.
  256. X*
  257. X* Author    :   John W. M. Stevens
  258. X******************************************************************************/
  259. X
  260. X#include    "compiler.h"
  261. X
  262. X#include    "unpost.h"
  263. X#include    "regexp.h"
  264. X#include    "parse.h"
  265. X#include    "uudec.h"
  266. X#include    "decode.h"
  267. X#include    "modflnm.h"
  268. X#include    "utils.h"
  269. X
  270. X/*-----------------------------------------------------------------------------
  271. X| Routine   :   OpenBinFile() --- Find the begin line, and open the output
  272. X|               binary file.
  273. X|
  274. X| Inputs    :   InFlPtr - Pointer to input source file.
  275. X|               InBfr   - Buffer to read lines into when searching for
  276. X|                         begin line.
  277. X|
  278. X| Returns   :   Pointer to the binary file to write to.
  279. X-----------------------------------------------------------------------------*/
  280. X
  281. Xstatic
  282. XFILE        *OpenBinFile(FILE   *InFlPtr,
  283. X                         char   *FlName,
  284. X                         char   *InBfr)
  285. X{
  286. X    auto        FILE            *OutFlPtr;
  287. X    auto        char            **RetStrs;
  288. X
  289. X    extern      FILE            *ErrFile;
  290. X
  291. X    /*  Get begin line. */
  292. X    if (ReadLine(InFlPtr, InBfr, BFR_SIZE) != EOF)
  293. X    {
  294. X        /*  Is this the begin line? */
  295. X        if ( MatchBegin(InBfr, &RetStrs) )
  296. X        {
  297. X            /*  Check to make sure that file does not already exist.    */
  298. X            if ( FileExists( FlName ) )
  299. X            {
  300. X                fprintf(ErrFile,
  301. X                        "\t%s %d : Error - file '%s' already exists.\n",
  302. X                        __FILE__,
  303. X                        __LINE__,
  304. X                        FlName);
  305. X                return( NULL );
  306. X            }
  307. X
  308. X            /*  Open the file.  */
  309. X            if ((OutFlPtr = fopen(FlName, BIN_WRITE)) == NULL)
  310. X            {
  311. X                fprintf(ErrFile,
  312. X                        "\t%s %d : Error - %s\n\t'%s'\n",
  313. X                        __FILE__,
  314. X                        __LINE__,
  315. X                        sys_errlist[errno],
  316. X                        FlName);
  317. X                return( NULL );
  318. X            }
  319. X
  320. X            /*  Return the file pointer.    */
  321. X            return( OutFlPtr );
  322. X        }
  323. X        else
  324. X        {
  325. X            /*  Missing begin line. */
  326. X            fprintf(ErrFile,
  327. X                    "\t%s %d : Error - missing begin line.\n",
  328. X                    __FILE__,
  329. X                    __LINE__);
  330. X            fprintf(ErrFile,
  331. X                    "\t'%s'\n",
  332. X                    InBfr);
  333. X        }
  334. X    }
  335. X    else
  336. X    {
  337. X        /*  Missing begin line. */
  338. X        fprintf(ErrFile,
  339. X                "\t%s %d : Error - missing begin line.\n",
  340. X                __FILE__,
  341. X                __LINE__);
  342. X    }
  343. X
  344. X    /*  Return NULL file pointer.   */
  345. X    return( NULL );
  346. X}
  347. X
  348. X/*-----------------------------------------------------------------------------
  349. X| Routine   :   WriteDesc() --- Write descriptions to a separate file.
  350. X|
  351. X| Inputs    :   InFlPtr     - Pointer to source file.
  352. X|               DescFlName  - Name of description file.
  353. X|               FlDesc      - Pointer to file descriptor structure.
  354. X|               InBfr       - Pointer to buffer to read lines into.
  355. X-----------------------------------------------------------------------------*/
  356. X
  357. Xstatic
  358. Xint     WriteDesc(FILE      *InFlPtr,
  359. X                  char      *DescFlName,
  360. X                  FL_LIST   *FlDesc,
  361. X                  char      *InBfr)
  362. X{
  363. X    auto        CHK_UU_ENC      UULnType;
  364. X    auto        char            **RetStrs;
  365. X    auto        int             EncLen;
  366. X    auto        IDENT           *Hdr;
  367. X    auto        IDENT           *Body;
  368. X    auto        FILE            *DescFile;
  369. X
  370. X    extern      FILE            *ErrFile;
  371. X
  372. X    /*  Open the description file.  */
  373. X    if ((DescFile = fopen(DescFlName, TXT_WRITE)) == NULL)
  374. X    {
  375. X        fprintf(ErrFile,
  376. X                "\t%s %d : Error - Could not open description file ",
  377. X                __FILE__,
  378. X                __LINE__);
  379. X        fprintf(ErrFile,
  380. X                "'%s' for writing.\n",
  381. X                DescFlName);
  382. X        return( ERROR );
  383. X    }
  384. X
  385. X    /*  Check to see which one of the segments exist.   */
  386. X    if ( FlDesc->Segs[0].Exists )
  387. X    {
  388. X        /*  Position file pointer to start of segment.  */
  389. X        if (fseek(InFlPtr, FlDesc->Segs[0].SegOfs, SEEK_SET) != 0)
  390. X        {
  391. X            fprintf(ErrFile,
  392. X                    "\t%s %d : Error - %s\n",
  393. X                    __FILE__,
  394. X                    __LINE__,
  395. X                    sys_errlist[errno]);
  396. X            fclose( DescFile );
  397. X            return( ERROR );
  398. X        }
  399. X
  400. X        /*  Dump lines until the start of the next segment is seen. */
  401. X        if (ReadLine(InFlPtr, InBfr, BFR_SIZE) != EOF)
  402. X        {
  403. X            /*  Print the line. */
  404. X            fprintf(DescFile, "%s\n", InBfr);
  405. X
  406. X            /*  Print description.  */
  407. X            while (ReadLine(InFlPtr, InBfr, BFR_SIZE) != EOF)
  408. X            {
  409. X                /*  Is this a SEGMENT begin line?    */
  410. X                if ( MatchSegment(InBfr, &Hdr, &Body) )
  411. X                    break;
  412. X
  413. X                /*  Print the line. */
  414. X                fprintf(DescFile, "%s\n", InBfr);
  415. X            }
  416. X        }
  417. X    }
  418. X
  419. X    /*  Position file pointer to start of segment.  */
  420. X    if (fseek(InFlPtr, FlDesc->Segs[1].SegOfs, SEEK_SET) != 0)
  421. X    {
  422. X        fprintf(ErrFile,
  423. X                "\t%s %d : Error - %s\n",
  424. X                __FILE__,
  425. X                __LINE__,
  426. X                sys_errlist[errno]);
  427. X        fclose( DescFile );
  428. X        return( ERROR );
  429. X    }
  430. X
  431. X    /*  Dump lines until first UU encoded line is seen. */
  432. X    while (ReadLine(InFlPtr, InBfr, BFR_SIZE) != EOF)
  433. X    {
  434. X        /*  Print the line. */
  435. X        fprintf(DescFile, "%s\n", InBfr);
  436. X
  437. X        /*  Check to see if this line is a UU encoded line. */
  438. X        UULnType = ChkUULine(InBfr, &RetStrs, &EncLen);
  439. X        if (UULnType == UU_BEGIN ||
  440. X            UULnType == UU_END   ||
  441. X            UULnType == IS_UU_LINE)
  442. X            break;
  443. X    }
  444. X
  445. X    /*  Return no error.    */
  446. X    fprintf(DescFile, "\n");
  447. X    fclose( DescFile );
  448. X    return( OK );
  449. X}
  450. X
  451. X/*-----------------------------------------------------------------------------
  452. X| Routine   :   DecSeg() --- Decode a single segment.
  453. X|
  454. X| Inputs    :   InFlPtr     - Pointer to source file.
  455. X|               OutFlPtr    - Pointer to output binary file.
  456. X| Outputs   :   UULnType    - Returns UU line type.
  457. X|
  458. X| Returns   :   EOF     - For end of file.
  459. X|               ERROR   - For a binary file write error.
  460. X-----------------------------------------------------------------------------*/
  461. X
  462. Xint     DecSeg(FILE         *InFlPtr,
  463. X               FILE         *OutFlPtr,
  464. X               CHK_UU_ENC   *UULnType)
  465. X{
  466. X    auto        int     OutLen;
  467. X
  468. X    /*  Externals used by this function.    */
  469. X    extern      char    InBfr[];
  470. X    extern      BYTE    OutBfr[];
  471. X    extern      FILE    *ErrFile;
  472. X
  473. X    /*  Decode lines until end of segment.  */
  474. X    for ( ; ; )
  475. X    {
  476. X        /*  Get a line from the file.   */
  477. X        if (ReadLine(InFlPtr, InBfr, BFR_SIZE) == EOF)
  478. X            return( EOF );
  479. X
  480. X        /*  Check the line to make sure that it is a UUENCODE
  481. X        *   line, and if it is, decode it.
  482. X        */
  483. X        *UULnType = DecUULine(InBfr, &OutLen, OutBfr);
  484. X        if (*UULnType == NOT_UU_LINE ||
  485. X            *UULnType == UU_BEGIN    ||
  486. X            *UULnType == UU_END)
  487. X            break;
  488. X        else if (*UULnType == UU_SPACE)
  489. X            continue;
  490. X
  491. X        /*  Are there any bytes to write?   */
  492. X        if ( OutLen )
  493. X        {
  494. X            /*  Write the buffer to the output file.    */
  495. X            if (fwrite(OutBfr, 1, OutLen, OutFlPtr) != OutLen)
  496. X            {
  497. X                fprintf(ErrFile,
  498. X                        "\t%s %d : Error - Bad write to binary file.\n",
  499. X                        __FILE__,
  500. X                        __LINE__);
  501. X                return( ERROR );
  502. X            }
  503. X        }
  504. X    }
  505. X
  506. X    /*  No errors, all is cool. */
  507. X    return( OK );
  508. X}
  509. X
  510. X/*-----------------------------------------------------------------------------
  511. X| Routine   :   DeCode() --- Decode the file.
  512. X|
  513. X| Inputs    :   InFlPtr - Pointer to source file.
  514. X|               FlDesc  - Pointer to file descriptor.
  515. X-----------------------------------------------------------------------------*/
  516. X
  517. Xint         DeCode(FILE     *InFlPtr,
  518. X                   FL_LIST  *FlDesc)
  519. X{
  520. X    register    int         i;
  521. X    auto        FILE        *OutFlPtr;
  522. X    auto        int         ret;
  523. X    auto        CHK_UU_ENC  UULnType;
  524. X    auto        char        OutFlNm[FL_NM_SZ];
  525. X
  526. X    /*  Externals used by this function.    */
  527. X    extern      int     DumpDesc;
  528. X    extern      char    InBfr[];
  529. X    extern      FILE    *ErrFile;
  530. X
  531. X    /*  Check to make sure that all segments are present before we
  532. X    *   decode.
  533. X    */
  534. X    for (i = 1; i <= FlDesc->NoSegs; i++)
  535. X    {
  536. X        /*  Check for missing segments. */
  537. X        if (FlDesc->Segs[i].SegNo == 0)
  538. X        {
  539. X            fprintf(ErrFile,
  540. X                    "\t%s %d : Error - missing segment #%d.\n",
  541. X                    __FILE__,
  542. X                    __LINE__,
  543. X                    i);
  544. X            fprintf(ErrFile,
  545. X                    "\tBinary ID: '%s'\n",
  546. X                    FlDesc->IDString);
  547. X            return( ERROR );
  548. X        }
  549. X    }
  550. X
  551. X    /*  Check for file name.  If none, report error.    */
  552. X    if (! FlDesc->FlName)
  553. X    {
  554. X        fprintf(ErrFile,
  555. X                "\t%s %d : Error - missing file name.\n",
  556. X                __FILE__,
  557. X                __LINE__);
  558. X        fprintf(ErrFile,
  559. X                "\tBinary ID: '%s'\n",
  560. X                FlDesc->IDString);
  561. X        return( ERROR );
  562. X    }
  563. X
  564. X    /*  If we want descriptions, dump the first part of segment one.    */
  565. X    if ( DumpDesc )
  566. X    {
  567. X        /*  Dump description for zero segment, if one exists, and
  568. X        *   dump the first part of segment one (up to and including
  569. X        *   the begin line.
  570. X        */
  571. X        ModExten(FlDesc->FlName, ".inf", OutFlNm);
  572. X        WriteDesc(InFlPtr, OutFlNm, FlDesc, InBfr);
  573. X    }
  574. X
  575. X    /*  Now that we have scanned all lines, decode file.    */
  576. X    for (i = 1; i <= FlDesc->NoSegs; i++)
  577. X    {
  578. X        /*  Position file pointer to first UUencoded
  579. X        *   line of segment.
  580. X        */
  581. X        if (fseek(InFlPtr, FlDesc->Segs[i].UUOfs, SEEK_SET) != 0)
  582. X        {
  583. X            fprintf(ErrFile,
  584. X                    "\t%s %d : Error - %s\n",
  585. X                    __FILE__,
  586. X                    __LINE__,
  587. X                    sys_errlist[errno]);
  588. X            return( ERROR );
  589. X        }
  590. X
  591. X        /*  Open the binary file.   */
  592. X        if (i == 1)
  593. X        {
  594. X            /*  Open the binary file.   */
  595. X            if ((OutFlPtr = OpenBinFile(InFlPtr,
  596. X                                        FlDesc->FlName,
  597. X                                        InBfr)) == NULL)
  598. X                return( ERROR );
  599. X        }
  600. X
  601. X        /*  Decode lines until end of segment.  */
  602. X        if ((ret = DecSeg(InFlPtr, OutFlPtr, &UULnType)) == EOF ||
  603. X            ret == ERROR)
  604. X        {
  605. X            /*  Close output file, return error.    */
  606. X            fclose( OutFlPtr );
  607. X            return( ret );
  608. X        }
  609. X
  610. X        /*  Check for various errors.   */
  611. X        if (UULnType == NOT_UU_LINE)
  612. X        {
  613. X            /*  Is there supposed to be a end line in this segment? */
  614. X            if (i == FlDesc->NoSegs)
  615. X            {
  616. X                fprintf(ErrFile,
  617. X                        "\t%s %d : Error - Missing UU end line.\n",
  618. X                        __FILE__,
  619. X                        __LINE__);
  620. X                fprintf(ErrFile,
  621. X                        "\t'%s'\n",
  622. X                        InBfr);
  623. X                fclose( OutFlPtr );
  624. X                return( ERROR );
  625. X            }
  626. X        }
  627. X        else if (UULnType == UU_END)
  628. X        {
  629. X            /*  Is this supposed to be the end? */
  630. X            if (i < FlDesc->NoSegs)
  631. X            {
  632. X                fprintf(ErrFile,
  633. X                        "\t%s %d : Warning - Early uuencode end line.\n",
  634. X                        __FILE__,
  635. X                        __LINE__);
  636. X            }
  637. X            break;
  638. X        }
  639. X        else if (UULnType == UU_BEGIN)
  640. X        {
  641. X            /*  What the HELL is this doing here?!  */
  642. X            fprintf(ErrFile,
  643. X                    "\t%s %d : Error - Unexpected UU begin line.\n",
  644. X                    __FILE__,
  645. X                    __LINE__);
  646. X            return( ERROR );
  647. X        }
  648. X    }
  649. X
  650. X    /*  Close the output file.  */
  651. X    fclose( OutFlPtr );
  652. X    return( OK );
  653. X}
  654. END_OF_FILE
  655.   if test 12412 -ne `wc -c <'decode.c'`; then
  656.     echo shar: \"'decode.c'\" unpacked with wrong size!
  657.   fi
  658.   # end of 'decode.c'
  659. fi
  660. if test -f 'list.h' -a "${1}" != "-c" ; then 
  661.   echo shar: Will not clobber existing file \"'list.h'\"
  662. else
  663.   echo shar: Extracting \"'list.h'\" \(843 characters\)
  664.   sed "s/^X//" >'list.h' <<'END_OF_FILE'
  665. X/******************************************************************************
  666. X* Module    :   List --- List building and maintenance module.
  667. X*
  668. X* Author    :   John Stevens.
  669. X******************************************************************************/
  670. X
  671. X#if ! defined(LIST_HEADER_FILE)
  672. X#define     LIST_HEADER_FILE
  673. X
  674. X/*  Define a list header structure. */
  675. Xtypedef struct  {
  676. X    int     NoElems;
  677. X    int     TotElems;
  678. X    int     ElemSz;
  679. X    char    List[1];
  680. X} LIST;
  681. X
  682. X/*  Function prototypes.    */
  683. Xextern  void    *AddList(LIST *, void *, int);
  684. Xextern  void    *CrtList(int);
  685. Xextern  int     SrchList(LIST   *Head,
  686. X                         void   *Elem,
  687. X                         int    (*CmpFn)(void *, void *),
  688. X                         int    *InsPt);
  689. Xextern  void    *ListIdx(LIST *, int);
  690. Xextern  void    *AppList(LIST *, void *);
  691. X
  692. X#endif
  693. END_OF_FILE
  694.   if test 843 -ne `wc -c <'list.h'`; then
  695.     echo shar: \"'list.h'\" unpacked with wrong size!
  696.   fi
  697.   # end of 'list.h'
  698. fi
  699. if test -f 'rematch.c' -a "${1}" != "-c" ; then 
  700.   echo shar: Will not clobber existing file \"'rematch.c'\"
  701. else
  702.   echo shar: Extracting \"'rematch.c'\" \(13245 characters\)
  703.   sed "s/^X//" >'rematch.c' <<'END_OF_FILE'
  704. X/******************************************************************************
  705. X* Module    :   Regular Expression Matching.
  706. X*
  707. X* Author    :   John W. M. Stevens.
  708. X******************************************************************************/
  709. X
  710. X#include    "compiler.h"
  711. X
  712. X#include    "sets.h"
  713. X#include    "regexp.h"
  714. X#include    "utils.h"
  715. X
  716. X/*  Define sub expression list. */
  717. Xtypedef struct  {
  718. X    char        *Start;         /*  Start of sub-string in source.  */
  719. X    char        *End;           /*  End of sub-string in source.  */
  720. X    char        *SubStr;        /*  Pointer to sub-string.          */
  721. X} SUB_EXPR;
  722. Xstatic  SUB_EXPR    SubExprs[MAX_SUB_EXPRS + 1];
  723. X
  724. Xstatic  CASE_CMP    CmpCase = CASE_SENSITIVE;
  725. X
  726. X/*-----------------------------------------------------------------------------
  727. X| Routine   :   ExtSubStrs() --- Extract the sub-strings from the string to
  728. X|               match against.
  729. X-----------------------------------------------------------------------------*/
  730. X
  731. Xstatic
  732. Xvoid    ExtSubStrs(void)
  733. X{
  734. X    register    int             i;
  735. X    register    int             StrLen;
  736. X    auto        char            *Str;
  737. X    extern      FILE            *ErrFile;
  738. X
  739. X    /*  Extract all sub strings from the source string. */
  740. X    for (i = 0; i <= MAX_SUB_EXPRS; i++)
  741. X    {
  742. X        /*  Report run time error.  */
  743. X        if (SubExprs[i].Start == NULL || SubExprs[i].End == NULL)
  744. X            continue;
  745. X        else if (SubExprs[i].Start > SubExprs[i].End)
  746. X        {
  747. X            fprintf(ErrFile,
  748. X                    "%s %d : Error - sub expression #%d extraction failed.\n",
  749. X                    __FILE__,
  750. X                    __LINE__,
  751. X                    i);
  752. X            exit( 1 );
  753. X        }
  754. X
  755. X        /*  Determine length of string. */
  756. X        for (StrLen = 0, Str = SubExprs[i].Start;
  757. X             Str != SubExprs[i].End;
  758. X             StrLen++, Str++
  759. X            )
  760. X             ;
  761. X
  762. X        /*  Allocate space for the string.  */
  763. X        if ((Str = (char *) calloc(1, StrLen + 1)) == NULL)
  764. X        {
  765. X            fprintf(ErrFile,
  766. X                    "%s %d : Out of memory.\n",
  767. X                    __FILE__,
  768. X                    __LINE__);
  769. X            exit( 1 );
  770. X        }
  771. X
  772. X        /*  Copy the string to the new space.   */
  773. X        MemCopy(Str, SubExprs[i].Start, StrLen);
  774. X        Str[StrLen] = '\0';
  775. X
  776. X        /*  Add string to sub expression string buffer. */
  777. X        SubExprs[i].SubStr = Str;
  778. X    }
  779. X}
  780. X
  781. X/*-----------------------------------------------------------------------------
  782. X| Routine   :   ReStrCmp() --- Regular expression string compare.
  783. X|
  784. X| Inputs    :   Str     - Pointer to string to attempt to match.
  785. X|               ReStr   - Pointer to regular expression string.
  786. X|
  787. X| Returns   :   Returns zero for no match, non-zero for a match.
  788. X-----------------------------------------------------------------------------*/
  789. X
  790. Xstatic
  791. Xint     ReStrCmp(char   *Str,
  792. X                 char   *ReStr)
  793. X{
  794. X    /*  While not end of regular expression string, compare characters. */
  795. X    while ( *ReStr )
  796. X    {
  797. X        /*  If the characters do not match, return no match.    */
  798. X        if (CmpCase == IGN_CASE)
  799. X        {
  800. X            /*  Compare characters regardless of case.  */
  801. X            if (tolower( *ReStr ) != tolower( *Str ))
  802. X                return( 0 );
  803. X
  804. X            /*  They match.  Increment pointers to next characters. */
  805. X            ReStr++;
  806. X            Str++;
  807. X        }
  808. X        else if (*ReStr++ != *Str++)
  809. X            return( 0 );
  810. X    }
  811. X    return( 1 );
  812. X}
  813. X
  814. X/*-----------------------------------------------------------------------------
  815. X| Routine   :   ReData() --- Evaluate a regular expression data node.
  816. X|
  817. X| Inputs    :   SrcStart    - Start of source string (for left anchor
  818. X|                             comparisons).
  819. X|               Str         - Pointer to string to attempt to match.
  820. X|               ReExpr      - Pointer to regular expression node.
  821. X| Outputs   :   Str         - Pointer to string after matched portion, or
  822. X|                             unchanged since input, if no match.
  823. X|               Srch        - Pointer to search description structure.
  824. X|
  825. X| Returns   :   Returns 1 for a match, 0 for no match.
  826. X-----------------------------------------------------------------------------*/
  827. X
  828. Xstatic
  829. Xint     ReData(char         *SrcStart,
  830. X               char         **Str,
  831. X               REG_EXP_NODE *ReExpr)
  832. X{
  833. X    register    int     Match;
  834. X    extern      FILE    *ErrFile;
  835. X
  836. X    /*  Attempt match.  */
  837. X    switch ( ReExpr->NodeType )
  838. X    {
  839. X    case DATA_STRING:
  840. X        /*  Compare string. */
  841. X        if ((Match = ReStrCmp(*Str, ReExpr->data.MatchStr)) != 0)
  842. X        {
  843. X            /*  Bump the source string pointer. */
  844. X            (*Str) += strlen( ReExpr->data.MatchStr );
  845. X        }
  846. X        break;
  847. X    case DATA_SET:
  848. X        /*  Is the current character a member of the set?  (Don't
  849. X        *   forget that negated sets are already negated at this
  850. X        *   point.)
  851. X        */
  852. X        if ((Match = InSet(ReExpr->data.CSet, **Str)) != 0)
  853. X        {
  854. X            /*  Bump source string pointer. */
  855. X            (*Str)++;
  856. X        }
  857. X        break;
  858. X    case DATA_ANY:
  859. X        /*  Match any character except end of line. */
  860. X        if ((Match = **Str && **Str != '\n') != 0)
  861. X        {
  862. X            /*  Bump source string pointer. */
  863. X            (*Str)++;
  864. X        }
  865. X        break;
  866. X    case DATA_LEFT_ANCHOR:
  867. X        /*  Is this the start of the line?  */
  868. X        Match = *Str == SrcStart;
  869. X        break;
  870. X    case DATA_RIGHT_ANCHOR:
  871. X        /*  Is the current character an end of line character?  */
  872. X        Match = **Str == '\n' || **Str == '\0';
  873. X        break;
  874. X    default:
  875. X        fprintf(ErrFile,
  876. X                "%s %d : Error - illegal regular expression node type.\n",
  877. X                __FILE__,
  878. X                __LINE__);
  879. X        exit( 1 );
  880. X    }
  881. X
  882. X    /*  Return match state. */
  883. X    return( Match );
  884. X}
  885. X
  886. X/*-----------------------------------------------------------------------------
  887. X| Routine   :   ReOp() --- Execute a regular expression operator.
  888. X|
  889. X| Inputs    :   SrcStart    - Start of source string (for left anchor
  890. X|                             comparisons).
  891. X|               Str         - Pointer to string to attempt to match.
  892. X|               ReExpr      - Pointer to regular expression node.
  893. X| Outputs   :   Str         - Pointer to string after matched portion, or
  894. X|                             unchanged since input, if no match.
  895. X|               Cont        - Current regular expression node pointer.
  896. X|
  897. X| Returns   :   Returns 1 for a match, 0 for no match.
  898. X-----------------------------------------------------------------------------*/
  899. X
  900. Xstatic
  901. Xint     ReOp(char           *SrcStart,
  902. X             char           **Str,
  903. X             REG_EXP_NODE   *ReExpr,
  904. X             REG_EXP_NODE   **Cont)
  905. X{
  906. X    register    int             i;
  907. X    register    int             Match;
  908. X    auto        char            *ChkPt;
  909. X    auto        REG_EXP_NODE    *Tmp;
  910. X    auto        REG_EXP_NODE    *Node;
  911. X    extern      FILE            *ErrFile;
  912. X
  913. X    /*  Do operations.  */
  914. X    do
  915. X    {
  916. X        /*  Attempt match.  */
  917. X        switch ( ReExpr->NodeType )
  918. X        {
  919. X        case OP_OR:
  920. X            /*  Save check point for backtracking.  */
  921. X            ChkPt = *Str;
  922. X
  923. X            /*  Attempt left branch first.  */
  924. X            if ((Match = ReOp(SrcStart,
  925. X                              Str,
  926. X                              ReExpr->Left,
  927. X                              &Node)) == 0)
  928. X            {
  929. X                /*  Attempt to match the right hand branch. */
  930. X                *Str = ChkPt;
  931. X                Match = ReOp(SrcStart, Str, ReExpr->Right, &Node);
  932. X            }
  933. X
  934. X            /*  Get end of OR.  */
  935. X            ReExpr = Node;
  936. X            break;
  937. X        case DATA_SPAN:
  938. X            /*  Scan for at least the minimum number of characters. */
  939. X            for (Match = 1, i = 0; i < ReExpr->MinSpan; i++)
  940. X                if (**Str == '\0' || **Str == '\n')
  941. X                {
  942. X                    Match = 0;
  943. X                    break;
  944. X                }
  945. X            if (! Match)
  946. X                break;
  947. X
  948. X            /*  Skip over all control node types to see if there is
  949. X            *   a terminating expression for this span.
  950. X            */
  951. X            for (Tmp = ReExpr->Right;
  952. X                 Tmp &&
  953. X                 (Tmp->NodeType == OP_L_PAREN   ||
  954. X                  Tmp->NodeType == OP_R_PAREN   ||
  955. X                  Tmp->NodeType == END_OR);
  956. X                 Tmp = Tmp->Right)
  957. X                ;
  958. X
  959. X            /*  If there is no span terminating expression, then we
  960. X            *   automatically match to end of line.
  961. X            */
  962. X            if (Tmp == NULL)
  963. X            {
  964. X                /*  Scan to end of input string.    */
  965. X                for ( ; **Str; ++*Str)
  966. X                    ;
  967. X
  968. X                /*  This is a definite match.   */
  969. X                Match = 1;
  970. X                break;
  971. X            }
  972. X
  973. X            /*  We matched at least the minimum number.  Now attempt the
  974. X            *   maximum number.
  975. X            */
  976. X            for (ChkPt = *Str;
  977. X                 *ChkPt && i < ReExpr->MaxSpan;
  978. X                 ChkPt++, i++)
  979. X            {
  980. X                /*  Search forward until a match is found, or the
  981. X                *   max number of any character has been spanned.
  982. X                */
  983. X                *Str = ChkPt;
  984. X                if ((Match = ReOp(SrcStart,
  985. X                                  Str,
  986. X                                  ReExpr->Right,
  987. X                                  &Node)) != 0)
  988. X                {
  989. X                    break;
  990. X                }
  991. X            }
  992. X
  993. X            /*  Check for a match.  */
  994. X            if (i >= ReExpr->MaxSpan)
  995. X                Match = 0;
  996. X            ReExpr = Node;
  997. X            break;
  998. X        case OP_ENUM:
  999. X            /*  Match the correct number of sub-expressions.    */
  1000. X            for (i = 0; i < ReExpr->MaxSpan; i++)
  1001. X            {
  1002. X                /*  Attempt data match. */
  1003. X                if ((Match = ReData(SrcStart,
  1004. X                                    Str,
  1005. X                                    ReExpr->Left)) == 0)
  1006. X                {
  1007. X                    /*  Have we at least the minimum?   */
  1008. X                    if (i >= ReExpr->MinSpan)
  1009. X                        Match = 1;
  1010. X                    break;
  1011. X                }
  1012. X            }
  1013. X            break;
  1014. X        case OP_L_PAREN:
  1015. X            /*  Save start of sub-expression.   */
  1016. X            SubExprs[ReExpr->SubExprNo].Start = *Str;
  1017. X            Match = 1;
  1018. X            break;
  1019. X        case OP_R_PAREN:
  1020. X            /*  Save start of sub-expression.   */
  1021. X            SubExprs[ReExpr->SubExprNo].End = *Str;
  1022. X            Match = 1;
  1023. X            break;
  1024. X         default:
  1025. X            Match = ReData(SrcStart, Str, ReExpr);
  1026. X            break;
  1027. X        }
  1028. X
  1029. X        /*  Check for end.  */
  1030. X        if (ReExpr != NULL)
  1031. X            ReExpr = ReExpr->Right;
  1032. X
  1033. X    } while (Match && ReExpr && ReExpr->NodeType != END_OR);
  1034. X
  1035. X    /*  Return match.   */
  1036. X    *Cont = ReExpr;
  1037. X    return( Match );
  1038. X}
  1039. X
  1040. X/*-----------------------------------------------------------------------------
  1041. X| Routine   :   ReMatch() --- Regular expression match.
  1042. X|
  1043. X| Inputs    :   Str         - Pointer to string to attempt to match.
  1044. X|               Case        - Flag for case sensitivity.
  1045. X|               ReExpr      - Pointer to regular expression tree root.
  1046. X| Outputs   :   SubStrs     - Pointer to array of returned strings.
  1047. X|               NoSubStrs   - Size of returned string array.
  1048. X|
  1049. X| Returns   :   Returns zero for no match, non-zero for a match.
  1050. X-----------------------------------------------------------------------------*/
  1051. X
  1052. Xint     ReMatch(char            *Str,
  1053. X                CASE_CMP        Case,
  1054. X                REG_EXP_NODE    *ReExpr,
  1055. X                char            ***SubStrs)
  1056. X{
  1057. X    register    int             i;
  1058. X    register    int             Match;
  1059. X    auto        char            *tp;
  1060. X    auto        char            *Loop;
  1061. X    auto        REG_EXP_NODE    *Node;
  1062. X
  1063. X    static      char        *RetStrs[MAX_SUB_EXPRS];
  1064. X    extern      FILE        *ErrFile;
  1065. X
  1066. X    /*  Run list and free strings.  */
  1067. X    for (i = 1; i < MAX_SUB_EXPRS; i++)
  1068. X    {
  1069. X        /*  Free previous sub strings.  */
  1070. X        if (RetStrs[i] != NULL)
  1071. X            free( RetStrs[i] );
  1072. X
  1073. X        /*  Initialize the sub expression list. */
  1074. X        RetStrs[i] = NULL;
  1075. X        SubExprs[i].Start = SubExprs[i].End = SubExprs[i].SubStr = NULL;
  1076. X    }
  1077. X
  1078. X    /*  If the first node is a left anchor, no shifting is necesary.    */
  1079. X    tp = Str;
  1080. X    CmpCase = Case;
  1081. X    if (ReExpr->NodeType == DATA_LEFT_ANCHOR)
  1082. X        Match = ReOp(Str, &tp, ReExpr->Right, &Node);
  1083. X    else
  1084. X    {
  1085. X        /*  Search forward. */
  1086. X        for (Loop = Str; ; Loop++)
  1087. X        {
  1088. X            /*  Search for a match. */
  1089. X            tp = Loop;
  1090. X            if ((Match = ReOp(Str, &tp, ReExpr, &Node)) != 0)
  1091. X                break;
  1092. X
  1093. X            /*  Check for end of loop.  */
  1094. X            if (*Loop == '\0' || *Loop == '\n')
  1095. X                break;
  1096. X        }
  1097. X    }
  1098. X
  1099. X    /*  Create sub string array. */
  1100. X    if ( Match )
  1101. X    {
  1102. X        /*  Extract sub expression strings. */
  1103. X        ExtSubStrs();
  1104. X        for (i = 1; i < MAX_SUB_EXPRS; i++)
  1105. X            RetStrs[i] = SubExprs[i].SubStr;
  1106. X
  1107. X        /*  Return sub string array.    */
  1108. X        *SubStrs = RetStrs;
  1109. X    }
  1110. X
  1111. X    /*  Return match true or false. */
  1112. X    return( Match );
  1113. X}
  1114. END_OF_FILE
  1115.   if test 13245 -ne `wc -c <'rematch.c'`; then
  1116.     echo shar: \"'rematch.c'\" unpacked with wrong size!
  1117.   fi
  1118.   # end of 'rematch.c'
  1119. fi
  1120. if test -f 'unpost.c' -a "${1}" != "-c" ; then 
  1121.   echo shar: Will not clobber existing file \"'unpost.c'\"
  1122. else
  1123.   echo shar: Extracting \"'unpost.c'\" \(12250 characters\)
  1124.   sed "s/^X//" >'unpost.c' <<'END_OF_FILE'
  1125. X/******************************************************************************
  1126. X* Module    :   Unpost --- Extract a binary file from a multi-part, uuencoded
  1127. X*               USENET News posting.
  1128. X*
  1129. X* Author    :   John W. M. Stevens
  1130. X*
  1131. X* Notes     :   See the file unpost.doc for information.
  1132. X******************************************************************************/
  1133. X
  1134. X#include    "compiler.h"
  1135. X
  1136. X#include    "unpost.h"
  1137. X#include    "parse.h"
  1138. X#include    "segment.h"
  1139. X
  1140. X/*********************************** Globals *********************************/
  1141. Xchar    *Version = "UNPOST V2.1.2";
  1142. Xint     LineNumber = 0;
  1143. X
  1144. X/*  Binary switches.  See file compiler.h to change default settings.   */
  1145. Xint     MsDosFileNms = MUNGE_FILE_NMS;
  1146. Xint     DumpDesc = DUMP_DESC_FILES;
  1147. Xint     SepIncomps = SEP_INCOMPLETES;
  1148. X
  1149. X/*  File pointers.  */
  1150. XFILE    *ErrFile = NULL;        /*  Error file.                             */
  1151. XFILE    *TextFile = NULL;       /*  Write non-binary to file.               */
  1152. XFILE    *IncompFile = NULL;     /*  Incompletes file.                       */
  1153. X/*****************************************************************************/
  1154. X
  1155. X/*-----------------------------------------------------------------------------
  1156. X| Routine   :   ReadLine() --- Get a line from the file.
  1157. X|
  1158. X| Inputs    :   FlPtr   - Pointer to file to read from.
  1159. X|               InBfr   - Pointer to buffer to read into.
  1160. X|               BfrMax  - Max buffer size.
  1161. X|
  1162. X| Returns   :   Returns EOF or OK.
  1163. X-----------------------------------------------------------------------------*/
  1164. X
  1165. Xint     ReadLine(FILE   *FlPtr,
  1166. X                 char   *InBfr,
  1167. X                 int    BfrMax)
  1168. X{
  1169. X    register    int     i;
  1170. X    extern      FILE    *ErrFile;
  1171. X
  1172. X    /*  Get a line from the file.   */
  1173. X    if (fgets(InBfr, BfrMax, FlPtr) == NULL)
  1174. X    {
  1175. X        /*  Check for end of file.  */
  1176. X        if ( feof( FlPtr ) )
  1177. X            return( EOF );
  1178. X        else if ( ferror( FlPtr ) )
  1179. X        {
  1180. X            fprintf(ErrFile,
  1181. X                    "%s %d : Error - reading source file.\n",
  1182. X                    __FILE__,
  1183. X                    __LINE__);
  1184. X            exit( 1 );
  1185. X        }
  1186. X    }
  1187. X
  1188. X    /*  Remove trailing '\n' character.
  1189. X    *
  1190. X    *   Maybe THIS time I got it right. . .
  1191. X    */
  1192. X    LineNumber++;
  1193. X    for (i = strlen( InBfr );
  1194. X         i > 0 && (InBfr[i - 1] == '\n' || InBfr[i - 1] == '\r');
  1195. X         i--
  1196. X        )
  1197. X        ;
  1198. X    InBfr[i] = '\0';
  1199. X
  1200. X    /*  Return OK.  */
  1201. X    return( OK );
  1202. X}
  1203. X
  1204. X/*-----------------------------------------------------------------------------
  1205. X| Routine   :   ShowSynopsis() --- Show a summary of the command line
  1206. X|               syntax.
  1207. X-----------------------------------------------------------------------------*/
  1208. X
  1209. Xstatic  char    *Synopsis[] =
  1210. X{
  1211. X"Options:\n",
  1212. X"    -b[-]        Break incompletes into separate files.\n",
  1213. X"    -d[-]        Dump descriptions flag.\n",
  1214. X"    -e <file>    File for errors (default standard error).\n",
  1215. X"    -f[-]        Modify file names to be MS-DOS compatible.\n",
  1216. X"    -h           Interpret headers in source files.\n",
  1217. X"    -i <file>    File to write incomplete binaries to.\n",
  1218. X"    -r <e|g|n|r> Set news reader type (SEGMENT begin line RE).\n",
  1219. X"    -s           Assume segments in order in file.\n",
  1220. X"    -t <file>    File for text only segments.\n",
  1221. X"    -u           UU decoder, pure and simple.\n",
  1222. X"    -v           Print the version number and quit.\n",
  1223. X"    -?           Show this help summary.\n\n",
  1224. X"Example:\n",
  1225. X"    unpost -d -e errors -t text -i multiple.1 multiple.uue\n",
  1226. X"        Save errors, text segments, descriptions and incompletes.\n\n",
  1227. XNULL
  1228. X};
  1229. X
  1230. Xstatic
  1231. Xvoid    ShowSynopsis(void)
  1232. X{
  1233. X    register    int     i;
  1234. X
  1235. X    /*  Show header and version number. */
  1236. X    printf("%s --- Extract a uuencoded binary from a multi-part posting.\n\n",
  1237. X           Version);
  1238. X
  1239. X    /*  Show synopsis.  */
  1240. X    for (i = 0; Synopsis[i]; i++)
  1241. X        printf( Synopsis[i] );
  1242. X
  1243. X    /*  Show current state of binary flags. */
  1244. X    printf("File Name Modifying       (-f) : %-3.3s\n",
  1245. X            (MsDosFileNms) ? "On" : "Off");
  1246. X    printf("Create Description Files  (-d) : %-3.3s\n",
  1247. X            (DumpDesc) ? "On" : "Off");
  1248. X    printf("Separate Incomplete Files (-b) : %-3.3s\n",
  1249. X            (SepIncomps) ? "On" : "Off");
  1250. X}
  1251. X
  1252. X/*-----------------------------------------------------------------------------
  1253. X| Routine   :   CmdLineParse() --- Parse the command line.
  1254. X|
  1255. X| Inputs    :   argc    - Number of command line arguments.
  1256. X|               argv    - List of command line argument strings.
  1257. X|               SwList  - Switch list.
  1258. X-----------------------------------------------------------------------------*/
  1259. X
  1260. Xstatic
  1261. Xvoid    CmdLineParse(int        argc,
  1262. X                     char       **argv,
  1263. X                     char       *SwList)
  1264. X{
  1265. X    register    int     i;
  1266. X    auto        char    *ArgPtr;
  1267. X    auto        char    *SwPtr;
  1268. X    auto        char    SwChar;
  1269. X    auto        char    ModeFlag;
  1270. X
  1271. X    /*  Check for no arguments. */
  1272. X    if (argc < 2)
  1273. X    {
  1274. X        /*  Give synopsis and quit. */
  1275. X        ShowSynopsis();
  1276. X        exit( 1 );
  1277. X    }
  1278. X
  1279. X    /*  Scan entire command line.   */
  1280. X    ErrFile = stderr;
  1281. X    ModeFlag = 'h';
  1282. X    for (i = 1; i < argc; i++)
  1283. X    {
  1284. X        /*  Get a pointer to the argument.  */
  1285. X        ArgPtr = argv[i];
  1286. X
  1287. X        /*  Is this a switch?   */
  1288. X        if (*ArgPtr == '-')
  1289. X        {
  1290. X            /*  Get switch character.   */
  1291. X            if ((SwChar = *++ArgPtr) == '\0')
  1292. X            {
  1293. X                /*  There is no character after the switch marker,
  1294. X                *   so declare an error.
  1295. X                */
  1296. X                ShowSynopsis();
  1297. X                exit( 1 );
  1298. X            }
  1299. X            else if ((SwPtr = strchr(SwList, SwChar)) == NULL)
  1300. X            {
  1301. X                /*  Error, this is evidently an illegal switch
  1302. X                *   character.
  1303. X                */
  1304. X                ShowSynopsis();
  1305. X                exit( 1 );
  1306. X            }
  1307. X            else if (SwPtr[1] == '>')
  1308. X            {
  1309. X                /*  Get parameter string.  Parameter string can
  1310. X                *   follow immediately after the switch character,
  1311. X                *   or it can be the next command line string.
  1312. X                */
  1313. X                if (*++ArgPtr == '\0')
  1314. X                {
  1315. X                    /*  Next command line parameter is switch
  1316. X                    *   parameter string.
  1317. X                    */
  1318. X                    if (i + 1 < argc)
  1319. X                        ArgPtr = argv[++i];
  1320. X                    else
  1321. X                    {
  1322. X                        ShowSynopsis();
  1323. X                        exit( 1 );
  1324. X                    }
  1325. X                }
  1326. X            }
  1327. X            else
  1328. X                ArgPtr++;
  1329. X        }
  1330. X        else
  1331. X            SwChar = ' ';
  1332. X
  1333. X        /*  Have argument processed.    */
  1334. X        switch ( SwChar )
  1335. X        {
  1336. X        case 'b':
  1337. X            /*  Set or reset flag that tells UNPOST to separate incompletes
  1338. X            *   into their own files.
  1339. X            */
  1340. X            if (*ArgPtr == '-')
  1341. X                SepIncomps = 0;
  1342. X            else
  1343. X                SepIncomps = 1;
  1344. X            break;
  1345. X        case 'c':
  1346. X            /*  Initialize the parser, using the default configuration OR
  1347. X            *   the configuration file.
  1348. X            */
  1349. X            LoadCfg( ArgPtr );
  1350. X            break;
  1351. X        case 'd':
  1352. X            if (*ArgPtr == '-')
  1353. X                DumpDesc = 0;
  1354. X            else
  1355. X                DumpDesc = 1;
  1356. X            break;
  1357. X        case 'e':
  1358. X            /*  Close a file that is already open.  */
  1359. X            if ( ErrFile )
  1360. X                fclose( ErrFile );
  1361. X
  1362. X            /*  Open a new error file.  */
  1363. X            if ((ErrFile = fopen(ArgPtr, TXT_WRITE)) == NULL)
  1364. X            {
  1365. X                fprintf(stderr,
  1366. X                        "%s %d : Error - Could not open file '%s' ",
  1367. X                        __FILE__,
  1368. X                        __LINE__,
  1369. X                        ArgPtr);
  1370. X                fprintf(stderr, "for output.\n");
  1371. X                exit( 1 );
  1372. X            }
  1373. X            break;
  1374. X        case 'f':
  1375. X            if (*ArgPtr == '-')
  1376. X                MsDosFileNms = 0;
  1377. X            else
  1378. X                MsDosFileNms = 1;
  1379. X            break;
  1380. X        case 'i':
  1381. X            /*  Close a file that is already open.  */
  1382. X            if ( IncompFile )
  1383. X                fclose( IncompFile );
  1384. X
  1385. X            /*  Open an incompletes file.   */
  1386. X            if ((IncompFile = fopen(ArgPtr, TXT_APPEND)) == NULL)
  1387. X            {
  1388. X                fprintf(stderr,
  1389. X                        "%s %d : Error - Could not open file '%s' ",
  1390. X                        __FILE__,
  1391. X                        __LINE__,
  1392. X                        ArgPtr);
  1393. X                fprintf(stderr, "for output.\n");
  1394. X                exit( 1 );
  1395. X            }
  1396. X            break;
  1397. X        case 'r':
  1398. X            SetSegBegin( ArgPtr );
  1399. X            break;
  1400. X        case 't':
  1401. X            /*  Close a file that is already open.  */
  1402. X            if ( TextFile )
  1403. X                fclose( TextFile );
  1404. X
  1405. X            /*  Open file for saving text only segments.    */
  1406. X            if ((TextFile = fopen(ArgPtr, TXT_WRITE)) == NULL)
  1407. X            {
  1408. X                fprintf(stderr,
  1409. X                        "%s %d : Error - Could not open file '%s' ",
  1410. X                        __FILE__,
  1411. X                        __LINE__,
  1412. X                        ArgPtr);
  1413. X                fprintf(stderr, "for output.\n");
  1414. X                exit( 1 );
  1415. X            }
  1416. X            break;
  1417. X        case 'h':
  1418. X        case 'u':
  1419. X        case 's':
  1420. X            ModeFlag = SwChar;
  1421. X            break;
  1422. X        case 'v':
  1423. X            printf("%s\n", Version);
  1424. X            exit( 0 );
  1425. X        case ' ':
  1426. X            /*  Select mode.    */
  1427. X            switch ( ModeFlag )
  1428. X            {
  1429. X            case 'h':
  1430. X                Multiple( ArgPtr );
  1431. X                break;
  1432. X            case 's':
  1433. X                Single( ArgPtr );
  1434. X                break;
  1435. X            case 'u':
  1436. X                UUDecode( ArgPtr );
  1437. X                break;
  1438. X            }
  1439. X            break;
  1440. X        default:
  1441. X            ShowSynopsis();
  1442. X            exit( 1 );
  1443. X        }
  1444. X    }
  1445. X}
  1446. X
  1447. X#if defined(MUNGE_FILE_NAMES_PER_FS) && defined(SYSTEM_OS_2)
  1448. X
  1449. X/*-----------------------------------------------------------------------------
  1450. X| Routine   :   IsHpfs() --- Is this an HPFS?
  1451. X|
  1452. X| Returns   :   Returns 0 for not a HPFS, or non zero for is.
  1453. X-----------------------------------------------------------------------------*/
  1454. X
  1455. X#if defined(EMX_GCC_COMPILER)
  1456. X
  1457. Xint IsHpfs(void)
  1458. X{
  1459. X    auto    unsigned long   ulDrive;
  1460. X    auto    unsigned long   ulLogical;
  1461. X    auto    char            drive[3];
  1462. X    auto    char            name[16];
  1463. X
  1464. X    /*  Check operating system mode.    */
  1465. X    if (_osmode == DOS_MODE)
  1466. X        return( 0 );
  1467. X
  1468. X    /*  Get current disk drive. */
  1469. X    DosQueryCurrentDisk(&ulDrive, &ulLogical);
  1470. X
  1471. X    /*  Set up drive name string.   */
  1472. X    drive[0] = (char) (ulDrive + '@');
  1473. X    drive[1] = ':';
  1474. X    drive[2] = '\0';
  1475. X
  1476. X    /*  Get file system name string.    */
  1477. X    if (_filesys(drive, name, 16) == -1)
  1478. X        return( 0 );
  1479. X
  1480. X    /*  Is this an HPFS?    */
  1481. X    if (strcmp(name, "HPFS") == 0)
  1482. X        return( 1 );
  1483. X    return( 0 );
  1484. X}
  1485. X
  1486. X#elif   defined(OS_2_MSC_COMPILER)
  1487. X
  1488. Xint IsHpfs(void)
  1489. X{
  1490. X    auto    USHORT  nDrive;
  1491. X    auto    ULONG   lMap;
  1492. X    auto    BYTE    bData[64];
  1493. X    auto    BYTE    bName[3];
  1494. X    auto    USHORT  cbData;
  1495. X
  1496. X    /*  MS-DOS does not have HPFS.  */
  1497. X    if (_osmode == DOS_MODE)
  1498. X        return( 0 );
  1499. X
  1500. X    /*  Get the default drive.  */
  1501. X    DosQCurDisk(&nDrive, &lMap);
  1502. X
  1503. X    /*  Set up the drive name.  */
  1504. X    bName[0] = (char) (nDrive + '@');
  1505. X    bName[1] = ':';
  1506. X    bName[2] = 0;
  1507. X    cbData = sizeof( bData );
  1508. X
  1509. X    /*  Read the info, if we fail - assume non-HPFS.    */
  1510. X    if ( DosQFSAttach(bName, 0, FSAIL_QUERYNAME, bData, &cbData, 0L) )
  1511. X        return( 0 );
  1512. X    else if (strcmp(bData + (*((USHORT *) (bData + 2)) + 7), "HPFS") == 0)
  1513. X        return( 1 );
  1514. X    return( 0 );
  1515. X}
  1516. X
  1517. X#endif
  1518. X
  1519. X#endif
  1520. X
  1521. Xint     main(int    argc,
  1522. X             char   **argv)
  1523. X{
  1524. X    /*  If the user wants different file name munging on different
  1525. X    *   systems, set -f flag accordingly, otherwise, leave alone.
  1526. X    */
  1527. X#if defined(MUNGE_FILE_NAMES_PER_FS) && defined(SYSTEM_OS_2)
  1528. X    MsDosFileNms = ! IsHpfs();
  1529. X#endif
  1530. X
  1531. X    /*  Parse command line parameters.  */
  1532. X    ParseInit();
  1533. X    CmdLineParse(argc, argv, "bc>de>fhi>r>st>uv");
  1534. X    return( 0 );
  1535. X}
  1536. END_OF_FILE
  1537.   if test 12250 -ne `wc -c <'unpost.c'`; then
  1538.     echo shar: \"'unpost.c'\" unpacked with wrong size!
  1539.   fi
  1540.   # end of 'unpost.c'
  1541. fi
  1542. if test -f 'uudec.c' -a "${1}" != "-c" ; then 
  1543.   echo shar: Will not clobber existing file \"'uudec.c'\"
  1544. else
  1545.   echo shar: Extracting \"'uudec.c'\" \(8450 characters\)
  1546.   sed "s/^X//" >'uudec.c' <<'END_OF_FILE'
  1547. X/******************************************************************************
  1548. X* Module    :   UUdecode --- Test for and decode a uuencoded text.
  1549. X*
  1550. X* Author    :   John W. M. Stevens
  1551. X******************************************************************************/
  1552. X
  1553. X#include    "compiler.h"
  1554. X
  1555. X#include    "unpost.h"
  1556. X#include    "regexp.h"
  1557. X#include    "parse.h"
  1558. X#include    "uudec.h"
  1559. X
  1560. X#define     DEC_CHAR(c)     (((c) - ' ') & 0x3f)
  1561. X#define     CHK_SUM_MASK    0x3f
  1562. X
  1563. Xstatic  int     FixBitNetTwiddleFlag = 0;
  1564. X
  1565. X/*-----------------------------------------------------------------------------
  1566. X| Routine   :   UULnDec() --- UU decode a line.
  1567. X|
  1568. X| Inputs    :   LnLen   - Length of line.
  1569. X|               Line    - Pointer to the line buffer.
  1570. X| Outputs   :   Bfr     - Points to buffer for decoded output.
  1571. X-----------------------------------------------------------------------------*/
  1572. X
  1573. Xstatic
  1574. Xint     UULnDec(int     LnLen,
  1575. X                char    *Line,
  1576. X                BYTE    *Bfr)
  1577. X{
  1578. X    register    int     i;
  1579. X    register    int     j;
  1580. X    auto        int     RecLen;
  1581. X    auto        int     tmp;
  1582. X    auto        int     Shift;
  1583. X
  1584. X    /*  Zero out buffer.    */
  1585. X    RecLen = DEC_CHAR( *Line );
  1586. X    memset(Bfr, 0, RecLen);
  1587. X
  1588. X    /*  Do actual line decoding.  Skip first character, as it is line
  1589. X    *   length.
  1590. X    */
  1591. X    for (i = 1, j = 0, Shift = 2;
  1592. X         i <= LnLen;
  1593. X         i++)
  1594. X    {
  1595. X        /*  Get six bits.   */
  1596. X        tmp = DEC_CHAR( Line[i] );
  1597. X
  1598. X        /*  Put into buffer.    */
  1599. X        Bfr[j] |= tmp << Shift;
  1600. X        if (Shift > 2)
  1601. X            Bfr[j - 1] |= tmp >> (8 - Shift);
  1602. X
  1603. X        /*  Increment byte pointer if neccesary.    */
  1604. X        if (Shift < 6)
  1605. X            j++;
  1606. X
  1607. X        /*  Adjust shift size.  */
  1608. X        Shift = (Shift + 2) & 0x7;
  1609. X    }
  1610. X
  1611. X    /*  Return size of buffer.  */
  1612. X    return( RecLen );
  1613. X}
  1614. X
  1615. X/*-----------------------------------------------------------------------------
  1616. X| Routine   :   ChkUUChars() --- Check that a line of the proper length has
  1617. X|               the proper characters.
  1618. X|
  1619. X| Inputs    :   LnLen   - Length of line.
  1620. X|               Line    - Pointer to the line buffer.
  1621. X| Outputs   :   Line    - Pointer to the line buffer with fixes.
  1622. X|
  1623. X| Returns   :   Returns TRUE    - This is a uuencoded line.
  1624. X|                       FALSE   - This is not a uudecoded line.
  1625. X-----------------------------------------------------------------------------*/
  1626. X
  1627. Xstatic
  1628. Xint     ChkUUChars(int  LnLen,
  1629. X                   char *Line)
  1630. X{
  1631. X    register    int     i;
  1632. X
  1633. X    /*  Loop through line, checking that all characters are in proper
  1634. X    *   range.
  1635. X    */
  1636. X    for (i = 0; i < LnLen; i++)
  1637. X        if (Line[i] == '~' && FixBitNetTwiddleFlag)
  1638. X            Line[i] = '^';
  1639. X        else if (Line[i] < ' ' || Line[i] > '`')
  1640. X            return( NOT_UU_LINE );
  1641. X
  1642. X    /*  Return that this is an encoded line.    */
  1643. X    return( IS_UU_LINE );
  1644. X}
  1645. X
  1646. X/*-----------------------------------------------------------------------------
  1647. X| Routine   :   ChkUULine() --- Check to see if this is a UUencoded line.
  1648. X|
  1649. X| Inputs    :   Line    - Pointer to line buffer.
  1650. X| Outputs   :   RetStrs - Pointer to array of sub strings.
  1651. X|               EncLen  - Length of unencoded line in bytes.
  1652. X|
  1653. X| Returns   :   Returns IS_UU_LINE  - This is a uuencoded line.
  1654. X|                       NOT_UU_LINE - This is not a uuencoded line.
  1655. X|                       UU_SPACE    - This is a valid uuencoded empty line.
  1656. X|                       UU_BEGIN    - This is a uuencode begin line.
  1657. X|                       UU_END      - This is a uuencode end line.
  1658. X-----------------------------------------------------------------------------*/
  1659. X
  1660. XCHK_UU_ENC  ChkUULine(char  *Line,
  1661. X                      char  ***RetStrs,
  1662. X                      int   *EncLen)
  1663. X{
  1664. X    auto        int     RecLen;
  1665. X    auto        int     BfrLen;
  1666. X
  1667. X    /*  Check for a character in the range of 0x20 to 0x60 inclusive.   */
  1668. X    if ((*Line >= ' ' && *Line <= 'M') || *Line == '`')
  1669. X    {
  1670. X        /*  Get record length.  */
  1671. X        RecLen = DEC_CHAR( *Line );
  1672. X
  1673. X        /*  Get line length.    */
  1674. X        BfrLen = strlen( Line );
  1675. X
  1676. X        /*  Calculate the line length based on the record size character.   */
  1677. X        if (*Line == 'M')
  1678. X            *EncLen = 60;
  1679. X        else if (*Line == ' ' || *Line == '`')
  1680. X            *EncLen = 0;
  1681. X        else
  1682. X        {
  1683. X            /*  This is a short line, so calculate the lenght that it's
  1684. X            *   record length character says it should have.
  1685. X            *
  1686. X            *   The first calculation assumes that for any number of
  1687. X            *   bytes between 1 and 3 inclusive, that the UU encoder
  1688. X            *   always spits out four characters.
  1689. X            */
  1690. X            if (RecLen % 3)
  1691. X                *EncLen = 4 * (RecLen / 3 + 1);
  1692. X            else
  1693. X                *EncLen = 4 * (RecLen / 3);
  1694. X
  1695. X            /*  If the UU encoder spits out less than four characters
  1696. X            *   for 1 or 2 bytes, then we need a different calculation.
  1697. X            */
  1698. X            if (BfrLen != *EncLen + 1 && BfrLen != *EncLen + 2)
  1699. X                *EncLen = 4 * (RecLen / 3) + (RecLen % 3 + 1);
  1700. X        }
  1701. X
  1702. X        /*  Check for short or long buffer. */
  1703. X        if (BfrLen != *EncLen + 1 && BfrLen != *EncLen + 2)
  1704. X            return( NOT_UU_LINE );
  1705. X
  1706. X        /*  Check for the expected UU characters.   */
  1707. X        if (ChkUUChars(BfrLen, Line) == NOT_UU_LINE)
  1708. X            return( NOT_UU_LINE );
  1709. X
  1710. X        /*  Return one of two different flags.    */
  1711. X        if (RecLen == 0)
  1712. X            return( UU_SPACE );
  1713. X        return( IS_UU_LINE );
  1714. X    }
  1715. X    else
  1716. X    {
  1717. X        /*  Test for a begin line.  */
  1718. X        if ( MatchBegin(Line, RetStrs) )
  1719. X            return( UU_BEGIN );
  1720. X
  1721. X        /*  Test for end line.  */
  1722. X        if ( MatchEnd( Line ) )
  1723. X            return( UU_END );
  1724. X    }
  1725. X
  1726. X    /*  This is not a UUencoded line.   */
  1727. X    return( NOT_UU_LINE );
  1728. X}
  1729. X
  1730. X/*-----------------------------------------------------------------------------
  1731. X| Routine   :   DecUULine() --- Decode a UU encoded line.
  1732. X|
  1733. X| Inputs    :   Line    - Pointer to line buffer.
  1734. X| Outputs   :   Len     - Number of bytes in the buffer.
  1735. X|               Bfr     - Points to buffer for decoded output.
  1736. X|
  1737. X| Returns   :   Returns IS_UU_LINE  - This is a uuencoded line.
  1738. X|                       NOT_UU_LINE - This is not a uuencoded line.
  1739. X|                       UU_SPACE    - This is a valid uuencoded empty line.
  1740. X|                       UU_BEGIN    - This is a uuencode begin line.
  1741. X|                       UU_END      - This is a uuencode end line.
  1742. X-----------------------------------------------------------------------------*/
  1743. X
  1744. XCHK_UU_ENC  DecUULine(char  *Line,
  1745. X                      int   *Len,
  1746. X                      BYTE  *Bfr)
  1747. X{
  1748. X    auto        int         EncLen;
  1749. X    auto        CHK_UU_ENC  UULnType;
  1750. X    auto        char        **RetStrs;
  1751. X
  1752. X    /*  If this is not a uuencoded line, then it cannot be decoded.
  1753. X    *   Check it first.
  1754. X    */
  1755. X    *Len = 0;
  1756. X    UULnType = ChkUULine(Line, &RetStrs, &EncLen);
  1757. X    if (UULnType != IS_UU_LINE)
  1758. X        return( UULnType );
  1759. X
  1760. X    /*  Do actual UU decode.    */
  1761. X    *Len = UULnDec(EncLen, Line, Bfr);
  1762. X
  1763. X    /*  Return the type of line this is.    */
  1764. X    return( IS_UU_LINE );
  1765. X}
  1766. X
  1767. X/*-----------------------------------------------------------------------------
  1768. X| Routine   :   DecTruncUULn() --- Decode a possibly truncated UU encoded
  1769. X|               line.
  1770. X|
  1771. X| Inputs    :   Line    - Pointer to line buffer.
  1772. X| Outputs   :   Len     - Number of bytes in the buffer.
  1773. X|               Bfr     - Points to buffer for decoded output.
  1774. X-----------------------------------------------------------------------------*/
  1775. X
  1776. Xvoid        DecTruncUULn(char   *Line,
  1777. X                         int    *Len,
  1778. X                         BYTE   *Bfr)
  1779. X{
  1780. X    register    int         i;
  1781. X    auto        int         RecLen;
  1782. X    auto        int         BfrLen;
  1783. X    auto        int         EncLen;
  1784. X
  1785. X    /*  Get line length.    */
  1786. X    BfrLen = strlen( Line );
  1787. X
  1788. X    /*  Calculate the line length.  */
  1789. X    RecLen = DEC_CHAR( *Line );
  1790. X    if (RecLen % 3)
  1791. X        EncLen = 4 * (RecLen / 3 + 1);
  1792. X    else
  1793. X        EncLen = 4 * (RecLen / 3);
  1794. X
  1795. X    /*  If the actual line is shorter than the record length indicates
  1796. X    *   it ought to be, then pad with spaces.
  1797. X    */
  1798. X    if (BfrLen <= EncLen)
  1799. X    {
  1800. X        /*  Loop, putting spaces at end.    */
  1801. X        for (i = BfrLen; i <= EncLen; i++)
  1802. X            Line[i] = '`';
  1803. X        Line[i] = '\0';
  1804. X    }
  1805. X
  1806. X    /*  Do actual UU line decode.   */
  1807. X    *Len = UULnDec(EncLen, Line, Bfr);
  1808. X}
  1809. END_OF_FILE
  1810.   if test 8450 -ne `wc -c <'uudec.c'`; then
  1811.     echo shar: \"'uudec.c'\" unpacked with wrong size!
  1812.   fi
  1813.   # end of 'uudec.c'
  1814. fi
  1815. echo shar: End of archive 5 \(of 7\).
  1816. cp /dev/null ark5isdone
  1817. MISSING=""
  1818. for I in 1 2 3 4 5 6 7 ; do
  1819.     if test ! -f ark${I}isdone ; then
  1820.     MISSING="${MISSING} ${I}"
  1821.     fi
  1822. done
  1823. if test "${MISSING}" = "" ; then
  1824.     echo You have unpacked all 7 archives.
  1825.     rm -f ark[1-9]isdone
  1826. else
  1827.     echo You still must unpack the following archives:
  1828.     echo "        " ${MISSING}
  1829. fi
  1830. exit 0
  1831. exit 0 # Just in case...
  1832.