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

  1. Newsgroups: comp.sources.misc,alt.binaries.pictures.utilities
  2. From: jstevens@teal.csn.org (John W.M. Stevens)
  3. Subject: v36i116:  unpost - Smart multi-part uudecoder v2.1.2, Part03/07
  4. Message-ID: <1993Apr19.052348.28903@sparky.imd.sterling.com>
  5. X-Md4-Signature: a92ad560a37ea7c21d4d55c32bccd7f0
  6. Date: Mon, 19 Apr 1993 05:23:48 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 116
  11. Archive-name: unpost/part03
  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:  nntp/client.cfg parse.c recomp.c
  19. # Wrapped by kent@sparky on Sun Apr 18 23:10:30 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 3 (of 7)."'
  23. if test -f 'nntp/client.cfg' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'nntp/client.cfg'\"
  25. else
  26.   echo shar: Extracting \"'nntp/client.cfg'\" \(44 characters\)
  27.   sed "s/^X//" >'nntp/client.cfg' <<'END_OF_FILE'
  28. Xgroup alt.binaries.pictures.misc abpm.uue 0
  29. END_OF_FILE
  30.   if test 44 -ne `wc -c <'nntp/client.cfg'`; then
  31.     echo shar: \"'nntp/client.cfg'\" unpacked with wrong size!
  32.   fi
  33.   # end of 'nntp/client.cfg'
  34. fi
  35. if test -f 'parse.c' -a "${1}" != "-c" ; then 
  36.   echo shar: Will not clobber existing file \"'parse.c'\"
  37. else
  38.   echo shar: Extracting \"'parse.c'\" \(34667 characters\)
  39.   sed "s/^X//" >'parse.c' <<'END_OF_FILE'
  40. X/******************************************************************************
  41. X* Module    :   Parse --- Search for a particular line.
  42. X*
  43. X* Author    :   John W. M. Stevens
  44. X******************************************************************************/
  45. X
  46. X#include    "compiler.h"
  47. X
  48. X#include    "unpost.h"
  49. X#include    "regexp.h"
  50. X#include    "uudec.h"
  51. X#include    "modflnm.h"
  52. X#include    "ident.h"
  53. X#include    "parse.h"
  54. X#include    "config.h"
  55. X#include    "utils.h"
  56. X
  57. X/*  These are the elements we have to parse out of either the header or
  58. X*   the body of the message BEFORE we find the first UUencoded line.
  59. X*/
  60. Xtypedef enum    {
  61. X    ID_STRING,
  62. X    SEGMENT_NO,
  63. X    NO_SEGMENTS
  64. X} PARSE_ELS;
  65. X
  66. X/*
  67. X*   Regular expression source strings.
  68. X*
  69. X*   To configure the program for different systems, these are the
  70. X*   strings to change.
  71. X*/
  72. Xstatic  PART_RE Parts1[] =
  73. X{
  74. X    {   "^Subject:(.*)[[({]Part[_ \t]*([0-9]+)[^0-9]+([0-9]+)[)\\]}](.*)",
  75. X        1,  2,  3,  4,  IGN_CASE,   NULL
  76. X    },
  77. X    {   "^Subject:(.*)Part[_ \t]*[[({]([0-9]+)[^0-9]+([0-9]+)[)\\]}](.*)",
  78. X        1,  2,  3,  4,  IGN_CASE,   NULL
  79. X    },
  80. X    {   "^Subject:(.*)Part[_ \t]+([0-9]+)[^0-9]+([0-9]+)(.*)",
  81. X        1,  2,  3,  4,  IGN_CASE,   NULL
  82. X    },
  83. X    {   "^Subject:(.*)[([{]([0-9]+)[^0-9]+([0-9]+)[)\\]}](.*)",
  84. X        1,  2,  3,  4,  IGN_CASE,   NULL
  85. X    },
  86. X    {   "^Subject:(.*)([0-9]+)([/|]|[ \t]+of[ \t]+)([0-9]+)(.*)",
  87. X        1,  2,  4,  5,  IGN_CASE,   NULL
  88. X    },
  89. X    {   "^Subject:(.*)",
  90. X        1,  0,  0,  0,  IGN_CASE,   NULL
  91. X    },
  92. X    {   NULL,
  93. X        0,  0,  0,  0,  IGN_CASE,   NULL
  94. X    }
  95. X};
  96. X
  97. Xstatic  PART_RE Parts3[] =
  98. X{
  99. X    {   "^X-File-Name:[ \t]+(.*)",
  100. X        1,  0,  0,  0,  CASE_SENSITIVE,     NULL
  101. X    },
  102. X    {   NULL,
  103. X        0,  0,  0,  0,  IGN_CASE,   NULL
  104. X    }
  105. X};
  106. X
  107. Xstatic  PART_RE Parts4[] =
  108. X{
  109. X    {   "^X-Part:[ \t]+([0-9]+)",
  110. X        0,  1,  0,  0,  CASE_SENSITIVE,     NULL
  111. X    },
  112. X    {   NULL,
  113. X        0,  0,  0,  0,  IGN_CASE,   NULL
  114. X    }
  115. X};
  116. X
  117. Xstatic  PART_RE Parts5[] =
  118. X{
  119. X    {   "^X-Part-Total:[ \t]+([0-9]+)",
  120. X        0,  0,  1,  0,  CASE_SENSITIVE,     NULL
  121. X    },
  122. X    {   NULL,
  123. X        0,  0,  0,  0,  IGN_CASE,   NULL
  124. X    }
  125. X};
  126. X
  127. Xstatic  PART_RE Parts6[] =
  128. X{
  129. X    {   "^Uusplit-part:[ \t]+([0-9]+)",
  130. X        0,  1,  0,  0,  CASE_SENSITIVE,     NULL
  131. X    },
  132. X    {   NULL,
  133. X        0,  0,  0,  0,  IGN_CASE,   NULL
  134. X    }
  135. X};
  136. X
  137. Xstatic  PART_RE Parts7[] =
  138. X{
  139. X    {   "^Uusplit-parts:[ \t]+([0-9]+)",
  140. X        0,  0,  1,  0,  CASE_SENSITIVE,     NULL
  141. X    },
  142. X    {   NULL,
  143. X        0,  0,  0,  0,  IGN_CASE,   NULL
  144. X    }
  145. X};
  146. X
  147. Xstatic  PART_RE Parts8[] =
  148. X{
  149. X    {   "^section ([0-9]+) of uuencode [0-9]+\\.[0-9]+ of file ([^ \t]+)[ \t]+by R.E.M.",
  150. X        2,  1,  0,  0,  CASE_SENSITIVE,     NULL
  151. X    },
  152. X    {   NULL,
  153. X        0,  0,  0,  0,  IGN_CASE,   NULL
  154. X    }
  155. X};
  156. X
  157. Xstatic  PART_RE Parts9[] =
  158. X{
  159. X    {   "^([^ \t]+)[ \t]+section[ \t]+([0-9]+)/([0-9]+)[ \t]+UUXFER ver ",
  160. X        1,  2,  3,  0,  CASE_SENSITIVE,     NULL
  161. X    },
  162. X    {   NULL,
  163. X        0,  0,  0,  0,  IGN_CASE,   NULL
  164. X    }
  165. X};
  166. X
  167. Xstatic  IDENT   Hdr1[] =
  168. X{
  169. X    {   "^Subject:",                            Parts1,     NULL            },
  170. X    {   "^X-File-Name:",                        Parts3,     NULL            },
  171. X    {   "^X-Part:",                             Parts4,     NULL            },
  172. X    {   "^X-Part-Total:",                       Parts5,     NULL            },
  173. X    {   "^Uusplit-part:",                       Parts6,     NULL            },
  174. X    {   "^Uusplit-parts:",                      Parts7,     NULL            },
  175. X    {   NULL,                                   NULL,       NULL            }
  176. X};
  177. X
  178. Xstatic  IDENT   Body1[] =
  179. X{
  180. X    {   "^Subject:",                            Parts1,     NULL            },
  181. X    {   "^section [0-9]+ of uuencode [0-9]+\\.[0-9]+ of file [^ \t]+    by R.E.M.",
  182. X                                                Parts8,     NULL            },
  183. X    {   "^[^ \t]+[ \t]+section[ \t]+[0-9]+/[0-9]+[ \t]+UUXFER ver ",
  184. X                                                Parts9,     NULL            },
  185. X    {   NULL,                                   NULL,       NULL            }
  186. X};
  187. X
  188. X/*=============================================================================
  189. X||  SEGMENT begin line regular expressions are defined below.
  190. X||
  191. X||  These can be set by command line switch.
  192. X=============================================================================*/
  193. X
  194. Xstatic  SEGMENT RnSegs[] =
  195. X{
  196. X    {   "^(Article[:]?|X-NEWS:) ",  Hdr1,   Body1,  NULL    },
  197. X    {   NULL,                       NULL,   NULL,   NULL    }
  198. X};
  199. X
  200. Xstatic  SEGMENT NnSegs[] =
  201. X{
  202. X    {   "^From[:]? ",               Hdr1,   Body1,  NULL    },
  203. X    {   NULL,                       NULL,   NULL,   NULL    }
  204. X};
  205. X
  206. Xstatic  SEGMENT EmailSegs[] =
  207. X{
  208. X    {   "^From ",                   Hdr1,   Body1,  NULL    },
  209. X    {   NULL,                       NULL,   NULL,   NULL    }
  210. X};
  211. X
  212. Xstatic  SEGMENT GroupsSegs[] =
  213. X{
  214. X    {   "^Newsgroups: ",            Hdr1,   Body1,  NULL    },
  215. X    {   NULL,                       NULL,   NULL,   NULL    }
  216. X};
  217. X
  218. Xstatic  SEGMENT         *Segments = RnSegs;
  219. Xstatic  REG_EXP_NODE    *Begin = NULL;
  220. Xstatic  REG_EXP_NODE    *End = NULL;
  221. Xstatic  char            *BeginStr = "^begin[ \t]+([0-7]+)[ \t]+([^ \t]+)";
  222. Xstatic  char            *EndStr   = "^end[ \t]*$";
  223. X
  224. X/*-----------------------------------------------------------------------------
  225. X| Routine   :   GetBinFlNm() --- Get the binary file name.
  226. X|
  227. X| Inputs    :   InFlPtr - Pointer to source file.
  228. X| Outputs   :   FlName  - Pointer to file name buffer.
  229. X-----------------------------------------------------------------------------*/
  230. X
  231. Xvoid    GetBinFlNm(FILE     *InFlPtr,
  232. X                   char     **RetStrs,
  233. X                   char     *FlName)
  234. X{
  235. X    auto        long        LnOfs;
  236. X    auto        char        *tp;
  237. X    auto        char        *sp;
  238. X    auto        int         OutLen;
  239. X    auto        char        Exten[5];
  240. X    auto        char        BeginName[FL_NM_SZ];
  241. X
  242. X    /*  Externals used by this function.    */
  243. X    extern      BYTE        OutBfr[];
  244. X    extern      char        SegLine[];
  245. X    extern      char        InBfr[];
  246. X    extern      char        UULine[];
  247. X    extern      FILE        *ErrFile;
  248. X    extern      int         MsDosFileNms;
  249. X
  250. X    /*  Extract the file name.    */
  251. X    for (tp = BeginName, sp = RetStrs[2];
  252. X         *sp && *sp != '\n' && *sp != ' ' && *sp != '\t';
  253. X        )
  254. X        *tp++ = *sp++;
  255. X    *tp = '\0';
  256. X
  257. X    /*  Munge file name?    */
  258. X    if ( MsDosFileNms )
  259. X    {
  260. X        /*  Get the current file offset.    */
  261. X        LnOfs = ftell( InFlPtr );
  262. X
  263. X        /*  Get next line and identify file type.   */
  264. X        *Exten = '\0';
  265. X        if (ReadLine(InFlPtr, InBfr, BFR_SIZE) == EOF)
  266. X        {
  267. X            fprintf(ErrFile,
  268. X                    "%s %d : Warning - Unexpected end of file in segment:\n",
  269. X                    __FILE__,
  270. X                    __LINE__);
  271. X            fprintf(ErrFile,
  272. X                    "\tSegment: '%s'\n",
  273. X                    SegLine);
  274. X        }
  275. X        else if (DecUULine(InBfr, &OutLen, OutBfr) == NOT_UU_LINE)
  276. X        {
  277. X            fprintf(ErrFile,
  278. X                    "%s %d : Warning - No UU line after begin.\n",
  279. X                    __FILE__,
  280. X                    __LINE__);
  281. X            fprintf(ErrFile,
  282. X                    "\tSegment: '%s'\n",
  283. X                    SegLine);
  284. X        }
  285. X        else
  286. X        {
  287. X            /*  Attempt to ID the file. */
  288. X            IdUUFile(OutBfr, OutLen, Exten);
  289. X
  290. X            /*  Modify the file name to be MS-DOS compatible?   */
  291. X            ModifyFlNm(BeginName, Exten, FlName);
  292. X        }
  293. X
  294. X        /*  Position file pointer to start of line. */
  295. X        if (fseek(InFlPtr, LnOfs, SEEK_SET) != 0)
  296. X        {
  297. X            fprintf(ErrFile,
  298. X                    "%s %d : Error - %s\n",
  299. X                    __FILE__,
  300. X                    __LINE__,
  301. X                    sys_errlist[errno]);
  302. X            exit( 1 );
  303. X        }
  304. X    }
  305. X    else
  306. X        strcpy(FlName, BeginName);
  307. X
  308. X#if defined(UNPOST_DEBUG)
  309. Xprintf("\tBinary File Name: '%s'\n", FlName);
  310. X#endif
  311. X}
  312. X
  313. X/*-----------------------------------------------------------------------------
  314. X| Routine   :   MatchEnd() --- Match a uuencode end line.
  315. X|
  316. X| Inputs    :   Line        - The line to attempt to match against.
  317. X-----------------------------------------------------------------------------*/
  318. X
  319. Xint     MatchEnd(char   *Line)
  320. X{
  321. X    auto    char    **RetStrs;
  322. X
  323. X    /*  Attempt to match the line.  */
  324. X    return( ReMatch(Line, CASE_SENSITIVE, End, &RetStrs) );
  325. X}
  326. X
  327. X/*-----------------------------------------------------------------------------
  328. X| Routine   :   MatchBegin() --- Match a uuencode begin line.
  329. X|
  330. X| Inputs    :   Line        - The line to attempt to match against.
  331. X| Outputs   :   RetStrs     - Returned sub-strings.
  332. X-----------------------------------------------------------------------------*/
  333. X
  334. Xint     MatchBegin(char     *Line,
  335. X                   char     ***RetStrs)
  336. X{
  337. X    /*  Attempt to match the line.  */
  338. X    return( ReMatch(Line, CASE_SENSITIVE, Begin, RetStrs) );
  339. X}
  340. X
  341. X/*-----------------------------------------------------------------------------
  342. X| Routine   :   MatchSegment() --- Match a SEGMENT begin line.
  343. X|
  344. X| Inputs    :   Line    - The line to attempt to match against.
  345. X| Outputs   :   Hdr     - Pointer to header ID line RE's.
  346. X|               Body    - Pointer to body ID line RE's.
  347. X-----------------------------------------------------------------------------*/
  348. X
  349. Xint     MatchSegment(char       *Line,
  350. X                     IDENT      **Hdr,
  351. X                     IDENT      **Body)
  352. X{
  353. X    register    int     i;
  354. X    auto        char    **RetStrs;
  355. X
  356. X    /*  Attempt to match the line.  */
  357. X    for (i = 0; Segments[i].ReExprStr; i++)
  358. X    {
  359. X        /*  Attempt to match one of the segment begin lines.    */
  360. X        if (ReMatch(Line,
  361. X                    CASE_SENSITIVE,
  362. X                    Segments[i].ReExpr,
  363. X                    &RetStrs) != 0)
  364. X        {
  365. X            *Hdr = Segments[i].Header;
  366. X            *Body = Segments[i].Body;
  367. X            return( 1 );
  368. X        }
  369. X    }
  370. X
  371. X    /*  Return not matched. */
  372. X    Hdr = NULL;
  373. X    Body = NULL;
  374. X    return( 0 );
  375. X}
  376. X
  377. X/*-----------------------------------------------------------------------------
  378. X| Routine   :   GetBinID() --- Get binary ID string.
  379. X|
  380. X| Inputs    :   SubStr  - Pointer to possible ID sub-string.
  381. X| Outputs   :   IDStr   - Pointer to ID string buffer.
  382. X-----------------------------------------------------------------------------*/
  383. X
  384. Xstatic
  385. Xvoid    GetBinID(char   *SubStr,
  386. X                 char   *IDStr)
  387. X{
  388. X    register    int     i;
  389. X    auto        int     ExtSep;
  390. X    auto        int     MaxLen;
  391. X    auto        char    *WordPtr;
  392. X    auto        char    *DestPtr;
  393. X    auto        char    *MaxPtr;
  394. X    auto        char    *tp;
  395. X
  396. X    extern      int     MsDosFileNms;
  397. X
  398. X    /*  Filter string.  */
  399. X    FlNmFilter( SubStr );
  400. X
  401. X    /*  Attempt to guess at a file name.    */
  402. X    for (tp = SubStr; *tp; )
  403. X    {
  404. X        /*  Skip white space.   */
  405. X        while (*tp == ' ' || *tp == '\t')
  406. X            tp++;
  407. X
  408. X        /*  Get word. */
  409. X        for (DestPtr = IDStr, ExtSep = 0;
  410. X             *tp && *tp != ' ' && *tp != '\t';
  411. X             tp++)
  412. X        {
  413. X            /*  Check to see if this is and extension separator
  414. X            *   character, and if so, count how many.
  415. X            */
  416. X            if (*tp == EXT_SEP_CHAR)
  417. X                ExtSep++;
  418. X
  419. X            /*  Copy character. */
  420. X            *DestPtr++ = *tp;
  421. X        }
  422. X        *DestPtr = '\0';
  423. X
  424. X        /*  Does this look like a file name?    */
  425. X        if ( ExtSep )
  426. X        {
  427. X#if defined(UNPOST_DEBUG)
  428. Xprintf("\tBinary ID: '%s'\n", IDStr);
  429. X#endif
  430. X            return;
  431. X        }
  432. X    }
  433. X
  434. X    /*  OK, we didn't find anything that looks like it could possibly
  435. X    *   be a file name, so get the longest word and use it.
  436. X    */
  437. X    MaxLen = 0;
  438. X    MaxPtr = NULL;
  439. X    for (tp = SubStr; *tp; )
  440. X    {
  441. X        /*  Skip white space.   */
  442. X        while (*tp == ' ' || *tp == '\t')
  443. X            tp++;
  444. X
  445. X        /*  Copy string.    */
  446. X        for (i = 0, WordPtr = tp;
  447. X             *tp && *tp != ' ' && *tp != '\t';
  448. X             i++)
  449. X            IDStr[i] = *tp++;
  450. X        IDStr[i] = '\0';
  451. X
  452. X        /*  Is this the longest so far? */
  453. X        if (i > MaxLen)
  454. X        {
  455. X            MaxPtr = WordPtr;
  456. X            MaxLen = i;
  457. X        }
  458. X    }
  459. X
  460. X    /*  OK, check for no non-white space characters in sub
  461. X    *   string.
  462. X    */
  463. X    if (MaxPtr == NULL || MaxLen == 0)
  464. X    {
  465. X        *IDStr = '\0';
  466. X        return;
  467. X    }
  468. X
  469. X    /*  Get word. */
  470. X    for (DestPtr = IDStr, tp = MaxPtr;
  471. X         *tp && *tp != ' ' && *tp != '\t';
  472. X         tp++)
  473. X        *DestPtr++ = *tp;
  474. X    *DestPtr = '\0';
  475. X
  476. X#if defined(UNPOST_DEBUG)
  477. Xprintf("\tBinary ID: '%s'\n", IDStr);
  478. X#endif
  479. X}
  480. X
  481. X/*-----------------------------------------------------------------------------
  482. X| Routine   :   ParseIDLine() --- Extract the ID string, part number and
  483. X|               total number of parts from the ID line.
  484. X|
  485. X| Inputs    :   IDLine      - Pointer to ID line.
  486. X|               PartREs     - Array of part number parsing RE's.
  487. X| Outputs   :   Elements    - Aqquisition flags for the three items to
  488. X|                             parse out, ID string, Segment number and
  489. X|                             total number of segments.
  490. X|               SegInfo     - Pointer to segment information buffer.
  491. X-----------------------------------------------------------------------------*/
  492. X
  493. Xstatic
  494. Xvoid    ParseIDLine(char        *IDLine,
  495. X                    PART_RE     *PartREs,
  496. X                    int         *Elements,
  497. X                    SEG_INFO    *SegInfo)
  498. X{
  499. X    register    int     i;
  500. X    auto        char    **RetStrs;
  501. X    auto        PART_RE *PartRec;
  502. X    auto        char    IDBfr[FL_NM_SZ];
  503. X
  504. X    /*  Externals used in this function.    */
  505. X    extern      FILE    *ErrFile;
  506. X
  507. X    /*  Seach for a matching part number parsing regular expression.    */
  508. X    for (PartRec = NULL, i = 0;
  509. X         PartREs[i].ReExpStr;
  510. X         i++)
  511. X    {
  512. X        /*  Does this RE match the ID line? */
  513. X        if (ReMatch(IDLine,
  514. X                    PartREs[i].Case,
  515. X                    PartREs[i].ReExpr,
  516. X                    &RetStrs) != 0)
  517. X        {
  518. X#if defined(UNPOST_DEBUG)
  519. Xprintf("\tExtract RE: /%s/\n", PartREs[i].ReExpStr);
  520. X#endif
  521. X            PartRec = PartREs + i;
  522. X            break;
  523. X        }
  524. X    }
  525. X
  526. X    /*  If no match found, return.  */
  527. X    if (PartRec == NULL)
  528. X        return;
  529. X
  530. X    /*  Get what elements we do not yet have.    */
  531. X    for (i = ID_STRING; i <= NO_SEGMENTS; i++)
  532. X    {
  533. X        /*  Get this element, if it is available.   */
  534. X        switch ( i )
  535. X        {
  536. X        case 0:     /*  Get ID string.  */
  537. X            /*  Check for no ID string.    */
  538. X            if (PartRec->IDStr == 0)
  539. X                break;
  540. X
  541. X            /*  Extract ID string from sub string.  */
  542. X            GetBinID(RetStrs[ PartRec->IDStr ], IDBfr);
  543. X
  544. X            /*  Check to see if there was an ID string or not.  */
  545. X            if (*IDBfr == '\0')
  546. X            {
  547. X                /*  Is there an alternate regular expression for
  548. X                *   extracting the binary ID string?
  549. X                */
  550. X                if (PartRec->AltIDStr > 0)
  551. X                {
  552. X                    /*  OK, try other side. */
  553. X                    GetBinID(RetStrs[ PartRec->AltIDStr ], IDBfr);
  554. X                    if (*IDBfr == '\0')
  555. X                        break;
  556. X                }
  557. X                else
  558. X                    break;
  559. X            }
  560. X
  561. X            /*  Duplicate the ID string.    */
  562. X            if (SegInfo->IDString != NULL)
  563. X                free( SegInfo->IDString );
  564. X            SegInfo->IDString = StrDup( IDBfr );
  565. X            Elements[i] = 1;
  566. X            break;
  567. X        case 1:     /*  Get the segment number. */
  568. X            /*  Check for no segment number.    */
  569. X            if (PartRec->SegNo == 0)
  570. X                break;
  571. X
  572. X            /*  Get the segment number.    */
  573. X            if ((SegInfo->SegNo = atoi( RetStrs[ PartRec->SegNo ] )) < 0)
  574. X                break;
  575. X            Elements[i] = 1;
  576. X            break;
  577. X        case 2:     /*  Get total number of segments.   */
  578. X            /*  Check for no total number of segments.  */
  579. X            if (PartRec->NoSegs == 0)
  580. X                break;
  581. X
  582. X            /*  Get the total number of segments.  */
  583. X            if ((SegInfo->NoSegs = atoi( RetStrs[ PartRec->NoSegs ] )) <= 0)
  584. X                break;
  585. X            Elements[i] = 1;
  586. X            break;
  587. X        }
  588. X    }
  589. X}
  590. X
  591. X/*-----------------------------------------------------------------------------
  592. X| Routine   :   IdSearch() --- Search for an ID line.
  593. X|
  594. X| Inputs    :   InFlPtr     - Input file pointer.
  595. X|               IdPtr       - Pointer to ID RE hierarchy for this SEGMENT.
  596. X| Outputs   :   Elements    - Check list for data elements.
  597. X|               IDLine      - Contains ID line.
  598. X|               UULnType    - Type of UU encoded line found.
  599. X|               RetStrs     - Returned sub strings from RE match.
  600. X|               SegInfo     - Pointer to segment information buffer.
  601. X|
  602. X| Returns   :   Returns one of:
  603. X-----------------------------------------------------------------------------*/
  604. X
  605. Xstatic
  606. Xlong    IdSearch(FILE       *InFlPtr,
  607. X                 IDENT      *IdPtr,
  608. X                 int        *Elements,
  609. X                 char       *IDLine,
  610. X                 CHK_UU_ENC *UULnType,
  611. X                 char       ***RetStrs,
  612. X                 SEG_INFO   *SegInfo)
  613. X{
  614. X    register    int         i;
  615. X    auto        long        LnOfs;
  616. X    auto        int         EncLen;
  617. X    auto        IDENT       *Hdr;
  618. X    auto        IDENT       *Body;
  619. X    extern      FILE        *ErrFile;
  620. X
  621. X    /*  Search forwards through the file for the first ID line. */
  622. X    for ( ; ; )
  623. X    {
  624. X        /*  Get the current file offset.    */
  625. X        LnOfs = ftell( InFlPtr );
  626. X
  627. X        /*  Get a line from the file.   */
  628. X        if (ReadLine(InFlPtr, IDLine, BFR_SIZE) == EOF)
  629. X        {
  630. X            LnOfs = PRS_NO_UU_LN;
  631. X            break;
  632. X        }
  633. X
  634. X        /*  Is this a SEGMENT begin line?    */
  635. X        if ( MatchSegment(IDLine, &Hdr, &Body) )
  636. X        {
  637. X            /*  Position file pointer to start of line. */
  638. X            if (fseek(InFlPtr, LnOfs, SEEK_SET) != 0)
  639. X            {
  640. X                fprintf(ErrFile,
  641. X                        "%s %d : Error - %s\n",
  642. X                        __FILE__,
  643. X                        __LINE__,
  644. X                        sys_errlist[errno]);
  645. X                exit( 1 );
  646. X            }
  647. X
  648. X            /*  Return that no UU encoded line was found.   */
  649. X            LnOfs = PRS_NO_UU_LN;
  650. X            break;
  651. X        }
  652. X
  653. X        /*  Is this a UUencoded line?   */
  654. X        *UULnType = ChkUULine(IDLine, RetStrs, &EncLen);
  655. X        if (*UULnType == IS_UU_LINE ||
  656. X            *UULnType == UU_BEGIN   ||
  657. X            *UULnType == UU_END)
  658. X        {
  659. X            /*  Did we miss getting a piece of data we would like to
  660. X            *   have?
  661. X            */
  662. X            if (Elements[SEGMENT_NO] == 0 && Elements[NO_SEGMENTS])
  663. X            {
  664. X                /*  Error message.  */
  665. X                fprintf(ErrFile,
  666. X                        "%s %d : Error - Got number of segments but not ",
  667. X                        __FILE__,
  668. X                        __LINE__);
  669. X                fprintf(ErrFile,
  670. X                        "segment number.\n");
  671. X
  672. X                /*  Check for totally idiotic mess. */
  673. X                if (SegInfo->NoSegs == 1)
  674. X                {
  675. X                    /*  Attempt assumption. */
  676. X                    fprintf(ErrFile,
  677. X                            "\tNumber of Segments: %d\n",
  678. X                            SegInfo->NoSegs);
  679. X                    fprintf(ErrFile,
  680. X                            "\tAssuming Part 1 of 1\n");
  681. X                    SegInfo->SegNo = SegInfo->NoSegs = 1;
  682. X                }
  683. X                else
  684. X                    LnOfs = PRS_NO_SEG_NUM;
  685. X            }
  686. X            else if (Elements[SEGMENT_NO] && Elements[NO_SEGMENTS] == 0)
  687. X            {
  688. X                /*  Error message.  */
  689. X                fprintf(ErrFile,
  690. X                        "%s %d : Error - Got segment number but not number ",
  691. X                        __FILE__,
  692. X                        __LINE__);
  693. X                fprintf(ErrFile,
  694. X                        "of segments.\n");
  695. X
  696. X                /*  Check segment number.   */
  697. X                if (SegInfo->SegNo == 1)
  698. X                {
  699. X                    /*  Attempt assumption. */
  700. X                    fprintf(ErrFile,
  701. X                            "Segment Number: %d\n\tAssuming Part 1 of 1\n",
  702. X                            SegInfo->SegNo);
  703. X                    SegInfo->SegNo = SegInfo->NoSegs = 1;
  704. X                }
  705. X                else
  706. X                    LnOfs = PRS_NO_NUM_SEGS;
  707. X            }
  708. X            else if (Elements[SEGMENT_NO] == 0 && Elements[NO_SEGMENTS] == 0)
  709. X                SegInfo->SegNo = SegInfo->NoSegs = 1;
  710. X            break;
  711. X        }
  712. X
  713. X        /*  Is this an ID line? */
  714. X        for (i = 0; IdPtr[i].ReExprStr; i++)
  715. X        {
  716. X            /*  Does this line match?   */
  717. X            if (ReMatch(IDLine,
  718. X                        CASE_SENSITIVE,
  719. X                        IdPtr[i].ReExpr,
  720. X                        RetStrs) != 0)
  721. X            {
  722. X#if defined(UNPOST_DEBUG)
  723. Xprintf("\n\tID Line: '%s'\n", IDLine);
  724. Xprintf("\tBody RE: /%s/\n", IdPtr[i].ReExprStr);
  725. X#endif
  726. X                /*  Attempt to parse out one or more elements.  */
  727. X                ParseIDLine(IDLine, IdPtr[i].IdParts, Elements, SegInfo);
  728. X                break;
  729. X            }
  730. X        }
  731. X    }
  732. X
  733. X    /*  Return status.  */
  734. X    return( LnOfs );
  735. X}
  736. X
  737. X/*-----------------------------------------------------------------------------
  738. X| Routine   :   Header() --- Search for legal header ID lines.
  739. X|
  740. X| Inputs    :   InFlPtr     - Input file pointer.
  741. X|               IdPtr       - Pointer to ID RE hierarchy for this SEGMENT.
  742. X| Outputs   :   Elements    - Checklist for needed pieces of information.
  743. X|               IDLine      - Contains ID line.
  744. X|               SegInfo     - Pointer to segment information buffer.
  745. X|
  746. X| Returns   :   Returns one of:
  747. X|                   PRS_NO_UU_LN    - For no uuencoded line found in segment.
  748. X|                   1L              - OK.
  749. X-----------------------------------------------------------------------------*/
  750. X
  751. Xstatic
  752. Xlong    Header(FILE         *InFlPtr,
  753. X               IDENT        *IdPtr,
  754. X               int          *Elements,
  755. X               char         *IDLine,
  756. X               SEG_INFO     *SegInfo)
  757. X{
  758. X    register    int         i;
  759. X    auto        char        **RetStrs;
  760. X    auto        char        *tp;
  761. X    extern      FILE        *ErrFile;
  762. X
  763. X    /*  Search forwards through the file for the first ID line. */
  764. X    for ( ; ; )
  765. X    {
  766. X        /*  Is this an ID line? */
  767. X        for (i = 0; IdPtr[i].ReExprStr; i++)
  768. X        {
  769. X            /*  Does this line match?   */
  770. X            if (ReMatch(IDLine,
  771. X                        CASE_SENSITIVE,
  772. X                        IdPtr[i].ReExpr,
  773. X                        &RetStrs) != 0)
  774. X            {
  775. X#if defined(UNPOST_DEBUG)
  776. Xprintf("\n\tID Line: '%s'\n", IDLine);
  777. Xprintf("\tHeader RE: /%s/\n", IdPtr[i].ReExprStr);
  778. X#endif
  779. X                /*  Attempt to parse out one or more elements.  */
  780. X                ParseIDLine(IDLine, IdPtr[i].IdParts, Elements, SegInfo);
  781. X                break;
  782. X            }
  783. X        }
  784. X
  785. X        /*  Get a line from the file.   */
  786. X        if (ReadLine(InFlPtr, IDLine, BFR_SIZE) == EOF)
  787. X            return( PRS_NO_UU_LN );
  788. X
  789. X        /*  Check for a blank line, which is the header delimiter.  */
  790. X        for (tp = IDLine; *tp == ' ' || *tp == '\t'; tp++)
  791. X            ;
  792. X        if (*tp == '\0' || *tp == '\n')
  793. X            break;
  794. X    }
  795. X
  796. X    /*  Return that no errors occured.  */
  797. X    return( 1L );
  798. X}
  799. X
  800. X/*-----------------------------------------------------------------------------
  801. X| Routine   :   Parse() --- Parse out a SEGMENT and ID line.
  802. X|
  803. X| Inputs    :   InFlPtr     - Input file pointer.
  804. X| Outputs   :   SegLine     - Contains the segment line.
  805. X|               IDLine      - Contains ID line.
  806. X|               UULine      - Contains the first UU encoded line.
  807. X|               SegInfo     - Pointer to segment information buffer.
  808. X|
  809. X| Returns   :   Returns one of:
  810. X|                   PRS_NO_SEGMENT  - End of file found.
  811. X|                   PRS_NO_UU_LN    - No uuencoded line found in article.
  812. X|                   PRS_NO_ID_STR   - No ID string found at all.
  813. X|                   PRS_NO_BEGIN    - No uuencode begin line found in first
  814. X|                                     segment.
  815. X-----------------------------------------------------------------------------*/
  816. X
  817. Xlong    Parse(FILE      *InFlPtr,
  818. X              char      *SegLine,
  819. X              char      *IDLine,
  820. X              SEG_INFO  *SegInfo)
  821. X{
  822. X    register    int         i;
  823. X    auto        long        LnOfs;
  824. X    auto        char        **RetStrs;
  825. X    auto        IDENT       *Hdr;
  826. X    auto        IDENT       *Body;
  827. X    auto        CHK_UU_ENC  UULnType;
  828. X    auto        int         Elements[NO_SEGMENTS + 1];
  829. X    auto        char        FlName[FL_NM_SZ];
  830. X
  831. X    /*  Externals used by this function.    */
  832. X    extern      FILE        *ErrFile;
  833. X    extern      int         MsDosFileNms;
  834. X
  835. X    /*  Initialize the elements array to show that we have none of the
  836. X    *   elements.
  837. X    */
  838. X    for (i = ID_STRING; i <= NO_SEGMENTS; i++)
  839. X        Elements[i] = 0;
  840. X
  841. X    /*  Search forwards through the file for the first SEGMENT
  842. X    *   begin line.
  843. X    */
  844. X    for ( ; ; )
  845. X    {
  846. X        /*  Get the current file offset.    */
  847. X        LnOfs = ftell( InFlPtr );
  848. X
  849. X        /*  Get a line from the file.   */
  850. X        if (ReadLine(InFlPtr, SegLine, BFR_SIZE) == EOF)
  851. X            return( PRS_NO_SEGMENT );
  852. X
  853. X        /*  Is this a SEGMENT begin line?    */
  854. X        if ( MatchSegment(SegLine, &Hdr, &Body) )
  855. X        {
  856. X#if defined(UNPOST_DEBUG)
  857. Xprintf("Segment Begin: '%s'\n", SegLine);
  858. X#endif
  859. X            strcpy(IDLine, SegLine);
  860. X            break;
  861. X        }
  862. X    }
  863. X
  864. X    /*  Initialize new segment. */
  865. X    SegInfo->SegOfs = LnOfs;
  866. X
  867. X    /*  Process header block.   */
  868. X    LnOfs = Header(InFlPtr,
  869. X                   Hdr,
  870. X                   Elements,
  871. X                   IDLine,
  872. X                   SegInfo);
  873. X    if (LnOfs < 0L)
  874. X        return( LnOfs );
  875. X
  876. X    /*  Process body to end of segment or first UU line.    */
  877. X    LnOfs = IdSearch(InFlPtr,
  878. X                     Body,
  879. X                     Elements,
  880. X                     IDLine,
  881. X                     &UULnType,
  882. X                     &RetStrs,
  883. X                     SegInfo);
  884. X    if (LnOfs < 0L)
  885. X        return( LnOfs );
  886. X
  887. X    /*  Is this the begin line? */
  888. X    SegInfo->UUOfs = LnOfs;
  889. X    if (UULnType != UU_BEGIN)
  890. X    {
  891. X        /*  If this is segment number 1 and we did not find a begin line,
  892. X        *   that is BIG trouble, so report an error.
  893. X        */
  894. X        if (SegInfo->SegNo == 1)
  895. X        {
  896. X            fprintf(ErrFile,
  897. X                    "%s %d : Error - No begin line in first segment:\n",
  898. X                    __FILE__,
  899. X                    __LINE__);
  900. X            fprintf(ErrFile,
  901. X                    "\tSegment: '%s'\n",
  902. X                    SegLine);
  903. X            return( PRS_NO_BEGIN );
  904. X        }
  905. X        return( 0L );
  906. X    }
  907. X
  908. X    /*  Get file name from begin line.  */
  909. X    GetBinFlNm(InFlPtr, RetStrs, FlName);
  910. X#if defined(UNPOST_DEBUG)
  911. Xprintf("\tFile Name: '%s'\n", FlName);
  912. X#endif
  913. X
  914. X    /*  Return no errors occurred.  */
  915. X    if ( *FlName )
  916. X        SegInfo->FlName = StrDup( FlName );
  917. X    return( 0L );
  918. X}
  919. X
  920. X/*-----------------------------------------------------------------------------
  921. X| Routine   :   FreeCfg() --- Free a configuration that was created by
  922. X|               reading a configuration file.
  923. X-----------------------------------------------------------------------------*/
  924. X
  925. Xstatic
  926. Xvoid    FreeCfg(void)
  927. X{
  928. X    register    int         i;
  929. X    register    int         j;
  930. X    register    int         k;
  931. X
  932. X    /*  If the default configuration is in place, do nothing, else
  933. X    *   free the old configuration.
  934. X    */
  935. X    if (Segments != NnSegs     && Segments != RnSegs &&
  936. X        Segments != GroupsSegs && Segments != EmailSegs)
  937. X    {
  938. X        /*  Free all ID prefix lists in SEGMENT list.   */
  939. X        for (i = 0; Segments[i].ReExprStr; i++)
  940. X        {
  941. X            /*  Free all ID part lists in ID prefix list.   */
  942. X            for (j = 0;
  943. X                 Segments[i].Header[j].ReExprStr;
  944. X                 j++)
  945. X            {
  946. X                /*  Free all part extraction RE's, etc. */
  947. X                for (k = 0;
  948. X                     Segments[i].Header[j].IdParts[k].ReExpStr;
  949. X                     k++)
  950. X                {
  951. X                     free( Segments[i].Header[j].IdParts[k].ReExpStr );
  952. X                     FreeReExpr( Segments[i].Header[j].IdParts[k].ReExpr );
  953. X                }
  954. X
  955. X                /*  Free list memory and regular expression.    */
  956. X                free( Segments[i].Header[j].IdParts );
  957. X                free( Segments[i].Header[j].ReExprStr );
  958. X                (void) FreeReExpr( Segments[i].Header[j].ReExpr );
  959. X            }
  960. X            free( Segments[i].Header );
  961. X
  962. X            /*  Free all ID part lists in ID prefix list.   */
  963. X            for (j = 0;
  964. X                 Segments[i].Body[j].ReExprStr;
  965. X                 j++)
  966. X            {
  967. X                /*  Free all part extraction RE's, etc. */
  968. X                for (k = 0;
  969. X                     Segments[i].Body[j].IdParts[k].ReExpStr;
  970. X                     k++)
  971. X                {
  972. X                     free( Segments[i].Body[j].IdParts[k].ReExpStr );
  973. X                     FreeReExpr( Segments[i].Body[j].IdParts[k].ReExpr );
  974. X                }
  975. X
  976. X                /*  Free list memory and regular expression.    */
  977. X                free( Segments[i].Body[j].IdParts );
  978. X                free( Segments[i].Body[j].ReExprStr );
  979. X                (void) FreeReExpr( Segments[i].Body[j].ReExpr );
  980. X            }
  981. X            free( Segments[i].Body );
  982. X
  983. X            /*  Free the regular expression graph for the segment.  */
  984. X            free( Segments[i].ReExprStr );
  985. X            (void) FreeReExpr( Segments[i].ReExpr );
  986. X        }
  987. X
  988. X        /*  Free SEGMENT list.  */
  989. X        free( Segments );
  990. X    }
  991. X}
  992. X
  993. X/*-----------------------------------------------------------------------------
  994. X| Routine   :   SetSegBegin() --- Set the segment begin line regular
  995. X|               expression.
  996. X|
  997. X| Inputs    :   SegType - Either 'e', 'g', 'n', 'm', 'r'.
  998. X-----------------------------------------------------------------------------*/
  999. X
  1000. Xvoid    SetSegBegin(char    *SegType)
  1001. X{
  1002. X        register        int             i;
  1003. X
  1004. X    /*  Free any previously allocated configurations (configurations
  1005. X    *   read in from a config file only.
  1006. X    */
  1007. X    FreeCfg();
  1008. X
  1009. X    /*  Determine which type, based on input string.    */
  1010. X    switch ( tolower( *SegType ) )
  1011. X    {
  1012. X    case 'e':
  1013. X        Segments = EmailSegs;
  1014. X        break;
  1015. X    case 'g':
  1016. X        Segments = GroupsSegs;
  1017. X        break;
  1018. X    case 'n':
  1019. X        Segments = NnSegs;
  1020. X        break;
  1021. X    case 'r':
  1022. X    default:
  1023. X        Segments = RnSegs;
  1024. X        break;
  1025. X    }
  1026. X
  1027. X        /*      Compile SEGMENT begin RE's.     */
  1028. X        for (i = 0; Segments[i].ReExprStr; i++)
  1029. X                if (Segments[i].ReExpr == NULL)
  1030. X                        Segments[i].ReExpr = ReCompile( Segments[i].ReExprStr );
  1031. X}
  1032. X
  1033. X/*-----------------------------------------------------------------------------
  1034. X| Routine   :   CompCfg() --- Compile a configuration.
  1035. X-----------------------------------------------------------------------------*/
  1036. X
  1037. Xstatic
  1038. Xvoid    CompCfg(void)
  1039. X{
  1040. X    register    int         i;
  1041. X    register    int         j;
  1042. X    register    int         k;
  1043. X    auto        PART_RE     *PartPtr;
  1044. X    auto        IDENT       *IdPtr;
  1045. X    auto        SEGMENT     *SegPtr;
  1046. X
  1047. X        /*  Compile the regular expressions.    */
  1048. X        for (i = 0; Segments[i].ReExprStr; i++)
  1049. X        {
  1050. X                /*  Compile the unique SEGMENT line prefix. */
  1051. X                SegPtr = Segments + i;
  1052. X                if (SegPtr->ReExpr == NULL)
  1053. X                        SegPtr->ReExpr = ReCompile( SegPtr->ReExprStr );
  1054. X
  1055. X                /*  Compile all Header ID line information.    */
  1056. X                for (j = 0; SegPtr->Header[j].ReExprStr; j++)
  1057. X                {
  1058. X                        /*  Compile the unique ID line prefix.  */
  1059. X                        IdPtr = SegPtr->Header + j;
  1060. X                        IdPtr->ReExpr = ReCompile( IdPtr->ReExprStr );
  1061. X
  1062. X                        /*  Compile the part number parsing RE's.   */
  1063. X                        for (k = 0; IdPtr->IdParts[k].ReExpStr; k++)
  1064. X                        {
  1065. X                                PartPtr = IdPtr->IdParts + k;
  1066. X                                PartPtr->ReExpr = ReCompile( PartPtr->ReExpStr );
  1067. X                        }
  1068. X                }
  1069. X
  1070. X                /*  Compile all Body ID line information.    */
  1071. X                for (j = 0; SegPtr->Body[j].ReExprStr; j++)
  1072. X                {
  1073. X                        /*  Compile the unique Body ID line prefix.  */
  1074. X                        IdPtr = SegPtr->Body + j;
  1075. X                        IdPtr->ReExpr = ReCompile( IdPtr->ReExprStr );
  1076. X
  1077. X                        /*  Compile the part number parsing RE's.   */
  1078. X                        for (k = 0; IdPtr->IdParts[k].ReExpStr; k++)
  1079. X                        {
  1080. X                                PartPtr = IdPtr->IdParts + k;
  1081. X                                PartPtr->ReExpr = ReCompile( PartPtr->ReExpStr );
  1082. X                        }
  1083. X                }
  1084. X        }
  1085. X}
  1086. X
  1087. X/*-----------------------------------------------------------------------------
  1088. X| Routine   :   LoadCfg() --- Load a configuration file.
  1089. X|
  1090. X| Inputs    :   CfgFlNm - Configuration file name.
  1091. X-----------------------------------------------------------------------------*/
  1092. X
  1093. Xvoid    LoadCfg(char   *CfgFlNm)
  1094. X{
  1095. X        extern          FILE            *ErrFile;
  1096. X
  1097. X    /*  Check for reading a configuration file. */
  1098. X    if (CfgFlNm == NULL || *CfgFlNm == '\0')
  1099. X        {
  1100. X                fprintf(ErrFile,
  1101. X                                "%s %d : Error - Missing configuraiton file name.\n",
  1102. X                                __FILE__,
  1103. X                                __LINE__);
  1104. X                return;
  1105. X        }
  1106. X
  1107. X        /*  Free any previously allocated configuration trees.  */
  1108. X        FreeCfg();
  1109. X
  1110. X        /*  Parse configuration file.   */
  1111. X        Segments = ReadConfig( CfgFlNm );
  1112. X
  1113. X        /*      Compile the configuration.      */
  1114. X        CompCfg();
  1115. X}
  1116. X
  1117. X/*-----------------------------------------------------------------------------
  1118. X| Routine   :   ParseInit() --- Compile regular expressions here that will
  1119. X|                               not change during run time, and compile the default
  1120. X|                               configuration.
  1121. X-----------------------------------------------------------------------------*/
  1122. X
  1123. Xvoid    ParseInit(void)
  1124. X{
  1125. X        /*      Compile the RN default configuration.   */
  1126. X        CompCfg();
  1127. X
  1128. X    /*  Compile the UU encoding RE's.   */
  1129. X        Begin = ReCompile( BeginStr );
  1130. X        End = ReCompile( EndStr );
  1131. X}
  1132. END_OF_FILE
  1133.   if test 34667 -ne `wc -c <'parse.c'`; then
  1134.     echo shar: \"'parse.c'\" unpacked with wrong size!
  1135.   fi
  1136.   # end of 'parse.c'
  1137. fi
  1138. if test -f 'recomp.c' -a "${1}" != "-c" ; then 
  1139.   echo shar: Will not clobber existing file \"'recomp.c'\"
  1140. else
  1141.   echo shar: Extracting \"'recomp.c'\" \(22231 characters\)
  1142.   sed "s/^X//" >'recomp.c' <<'END_OF_FILE'
  1143. X/******************************************************************************
  1144. X* Module    :   Regular Expression Compiling.
  1145. X*
  1146. X* Author    :   John W. M. Stevens.
  1147. X*
  1148. X* Notes     :   Use UNIX style regular expressions.  Grammar is:
  1149. X*
  1150. X*   REG_EXPR    ::= ANCHOR
  1151. X*                   | ANCHOR '|' REG_EXPR
  1152. X*
  1153. X*   ANCHOR      ::= CATENATION
  1154. X*                   | '^' CATENATION
  1155. X*                   | CATENATION '$'
  1156. X*                   | '^' CATENATION '$'
  1157. X*
  1158. X*   CATENATION  ::= PHRASE
  1159. X*                   | PHRASE CATENATION
  1160. X*
  1161. X*   PHRASE      ::= UNARY
  1162. X*                   | UNARY ENUM_OP
  1163. X*
  1164. X*   ENUM_OP     ::= '*'
  1165. X*                   | '+'
  1166. X*                   | '?'
  1167. X*                   | '{' SPAN_RNG '}'
  1168. X*
  1169. X*   SPAN_RNG    ::= NUMBER
  1170. X*                   | NUMBER ',' NUMBER
  1171. X*
  1172. X*   UNARY       ::= '(' REG_EXPR ')'
  1173. X*                   | CHAR_STR
  1174. X*                   | '[' SET ']'
  1175. X*                   | '[' '^' SET ']'
  1176. X*                   | '.'
  1177. X*
  1178. X*   SET         ::= CHAR_STR
  1179. X*                   | CHAR_STR SET
  1180. X*                   | CHAR '-' CHAR
  1181. X*                   | CHAR '-' CHAR SET
  1182. X*
  1183. X*   CHAR_STR    ::= CHARACTER
  1184. X*                   | CHARACTER CHARACTER_STR
  1185. X*
  1186. X*   CHARACTER   ::= ' ' - '~' except for []()|{}+*? which are special without
  1187. X*                   being escaped.
  1188. X******************************************************************************/
  1189. X
  1190. X#include    "compiler.h"
  1191. X
  1192. X#include    "unpost.h"
  1193. X#include    "sets.h"
  1194. X#include    "regexp.h"
  1195. X#include    "utils.h"
  1196. X
  1197. X/*  Character Sets. */
  1198. Xstatic  int     ReInitFlag = 0;
  1199. Xstatic  char    *SpecStr = "[().|$";
  1200. Xstatic  SET     SpecSet;
  1201. Xstatic  char    *PostFixStr = "{*?+";
  1202. Xstatic  SET     PostSet;
  1203. Xstatic  char    *DecStr = "0-9";
  1204. Xstatic  SET     DecSet;
  1205. X
  1206. Xstatic  UINT    SubExprNo;
  1207. X
  1208. Xstatic  REG_EXP_NODE    *Alternation(char **);
  1209. X
  1210. X#if defined( RE_TEST )
  1211. X
  1212. X/*-----------------------------------------------------------------------------
  1213. X| Routine   :   PrtReExpr() --- Print a regular expression for debugging
  1214. X|               purposes.  (This may be used in the configuration helper
  1215. X|               in a later release, so make it pretty).
  1216. X|
  1217. X| Inputs    :   Node    - Pointer to current level regular expression node.
  1218. X|               Level   - Current level in tree.
  1219. X-----------------------------------------------------------------------------*/
  1220. X
  1221. Xstatic
  1222. Xvoid    PrtReExpr(REG_EXP_NODE  *Node,
  1223. X                  int           Level)
  1224. X{
  1225. X    register    int     i;
  1226. X    register    int     j;
  1227. X
  1228. X    /*  Traverse right to left so that the tree can be printed
  1229. X    *   on a screen or page rotated 90 degrees to the left.
  1230. X    *
  1231. X    *   (Right to left == top to bottom of screen or page)
  1232. X    */
  1233. X    if ( Node->Right )
  1234. X        PrtReExpr(Node->Right, Level + 1);
  1235. X
  1236. X    /*  Print indentation.  */
  1237. X    for (i = 0; i < Level; i++)
  1238. X        printf("    ");
  1239. X
  1240. X    /*  Print node type and information.    */
  1241. X    switch ( Node->NodeType )
  1242. X    {
  1243. X    case OP_L_PAREN:
  1244. X        printf("(\n");
  1245. X        break;
  1246. X    case DATA_LEFT_ANCHOR:
  1247. X        printf("^\n");
  1248. X        break;
  1249. X    case DATA_RIGHT_ANCHOR:
  1250. X        printf("$\n");
  1251. X        break;
  1252. X    case OP_ENUM:
  1253. X        printf("Enum {%d, %u}\n",
  1254. X                Node->MinSpan,
  1255. X                Node->MaxSpan);
  1256. X        break;
  1257. X    case OP_OR:
  1258. X        printf("|\n");
  1259. X        break;
  1260. X    case OP_AND:
  1261. X        printf("&\n");
  1262. X        break;
  1263. X    case DATA_ANY:
  1264. X        printf(".\n");
  1265. X        break;
  1266. X    case DATA_SPAN:
  1267. X        printf("Span {%d, %u}\n",
  1268. X                Node->MinSpan,
  1269. X                Node->MaxSpan);
  1270. X        break;
  1271. X    case DATA_STRING:
  1272. X        printf("'%s'\n",
  1273. X                Node->data.MatchStr,
  1274. X                Node->SubExprNo);
  1275. X        break;
  1276. X    case DATA_SET:
  1277. X        printf("[");
  1278. X        for (j = 0; j < 128; j++)
  1279. X            if ( InSet(Node->data.CSet, (char) j) )
  1280. X            {
  1281. X                if (j < 32 || j > 127)
  1282. X                    printf("\\x%02x");
  1283. X                else
  1284. X                    putchar( (char) j );
  1285. X            }
  1286. X        printf("]  %d\n", Node->SubExprNo);
  1287. X        break;
  1288. X    case NODE_TYPE_NOT_SET:
  1289. X    default:
  1290. X        printf(">>>> ERROR !, no node type set.\n");
  1291. X        break;
  1292. X    }
  1293. X
  1294. X    /*  Now print left child.   */
  1295. X    if ( Node->Left )
  1296. X        PrtReExpr(Node->Left, Level + 1);
  1297. X}
  1298. X
  1299. X#endif
  1300. X
  1301. X/*-----------------------------------------------------------------------------
  1302. X| Routine   :   AllocRegExpNode() --- Allocate a regular expression node.
  1303. X|
  1304. X| Returns   :   Returns a pointer to the newly allocated regular expression
  1305. X|               node.
  1306. X-----------------------------------------------------------------------------*/
  1307. X
  1308. Xstatic
  1309. XREG_EXP_NODE    *AllocRegExpNode(void)
  1310. X{
  1311. X    auto        REG_EXP_NODE    *New;
  1312. X    extern      FILE            *ErrFile;
  1313. X
  1314. X    /*  Allocate the node.  */
  1315. X    if ((New = (REG_EXP_NODE *) calloc(1, sizeof( REG_EXP_NODE ))) == NULL)
  1316. X    {
  1317. X        fprintf(ErrFile,
  1318. X                "%s %d : Out of memory.\n",
  1319. X                __FILE__,
  1320. X                __LINE__);
  1321. X        exit( 1 );
  1322. X    }
  1323. X    return( New );
  1324. X}
  1325. X
  1326. X/*-----------------------------------------------------------------------------
  1327. X| Routine   :   GetInt() --- Get an integer number for the case of
  1328. X|               regular expression enumeration.
  1329. X|
  1330. X| Inputs    :   Str     - Pointer to string to get number from.
  1331. X| Outputs   :   Str     - Pointer to first character in string after number.
  1332. X|
  1333. X| Returns   :   Returns the integer read from the string.
  1334. X-----------------------------------------------------------------------------*/
  1335. X
  1336. Xstatic
  1337. Xint     GetInt(char **Str)
  1338. X{
  1339. X    auto        int     i;
  1340. X
  1341. X    /*  Strip white space.  */
  1342. X    while (**Str == ' ' || **Str == '\t' || **Str == '\n')
  1343. X        (*Str)++;
  1344. X
  1345. X    /*  Get number. */
  1346. X    i = 0;
  1347. X    while ( InSet(DecSet, **Str) )
  1348. X        i = i * 10 + (*(*Str)++ - '0');
  1349. X
  1350. X    /*  Strip trailing white space. */
  1351. X    while (**Str == ' ' || **Str == '\t' || **Str == '\n')
  1352. X        (*Str)++;
  1353. X
  1354. X    /*  Return number.  */
  1355. X    return( i );
  1356. X}
  1357. X
  1358. X/*-----------------------------------------------------------------------------
  1359. X| Routine   :   EnumOp() --- Get the enumeration modifer.
  1360. X|               node.
  1361. X|
  1362. X| Inputs    :   Str     - Pointer to enumeration operator.
  1363. X|               Root    - Pointer to regular expression node.
  1364. X| Outputs   :   Str     - Pointer after enumeration operator.
  1365. X|
  1366. X| Note      :   A value of zero for maximum span value indicates ANY
  1367. X|               number.
  1368. X-----------------------------------------------------------------------------*/
  1369. X
  1370. Xstatic
  1371. Xvoid    EnumOp(char         **Str,
  1372. X               REG_EXP_NODE *Root)
  1373. X{
  1374. X    extern      FILE    *ErrFile;
  1375. X
  1376. X    /*  Set up the operator and enumerator values.  */
  1377. X    switch ( *(*Str)++ )
  1378. X    {
  1379. X    case '+':
  1380. X        Root->MinSpan = 1;
  1381. X        Root->MaxSpan = ~0;
  1382. X        break;
  1383. X    case '*':
  1384. X        Root->MinSpan = 0;
  1385. X        Root->MaxSpan = ~0;
  1386. X        break;
  1387. X    case '?':
  1388. X        Root->MinSpan = 0;
  1389. X        Root->MaxSpan = 1;
  1390. X        break;
  1391. X    case '{':
  1392. X        /*  Get specifically enumerated span.   */
  1393. X        Root->MinSpan = GetInt( Str );
  1394. X        Root->MaxSpan = Root->MinSpan;
  1395. X
  1396. X        /*  Is there a maximum number of characters?    */
  1397. X        if (**Str == ',')
  1398. X        {
  1399. X            /*  Get maximum span.   */
  1400. X            (*Str)++;
  1401. X
  1402. X            /*  Strip white space.  */
  1403. X            while (**Str == ' ' || **Str == '\t' || **Str == '\n')
  1404. X                (*Str)++;
  1405. X
  1406. X            /*  Set to maximum, or get maximum. */
  1407. X            if (**Str == '}')
  1408. X                Root->MaxSpan = ~0;
  1409. X            else if ( InSet(DecSet, **Str) )
  1410. X                Root->MaxSpan = GetInt( Str );
  1411. X        }
  1412. X
  1413. X        /*  Check for end brace.    */
  1414. X        if (**Str != '}')
  1415. X        {
  1416. X            fprintf(ErrFile,
  1417. X                    "%s %d : Error - missing '}' in regular expression.\n",
  1418. X                    __FILE__,
  1419. X                    __LINE__);
  1420. X            exit( 1 );
  1421. X        }
  1422. X        (*Str)++;
  1423. X        break;
  1424. X    }
  1425. X}
  1426. X
  1427. X/*-----------------------------------------------------------------------------
  1428. X| Routine   :   Unary() --- Unary Operations.
  1429. X|
  1430. X| Inputs    :   Str - Pointer to current character in source RE string.
  1431. X|
  1432. X| Returns   :   Pointer to regular expression node.
  1433. X-----------------------------------------------------------------------------*/
  1434. X
  1435. Xstatic
  1436. XREG_EXP_NODE    *Unary(char **Str)
  1437. X{
  1438. X    auto        REG_EXP_NODE    *Node;
  1439. X    auto        char            Buffer[256];
  1440. X    auto        char            *Tmp;
  1441. X    extern      FILE            *ErrFile;
  1442. X
  1443. X    /*  Get the regular expression atoms.   */
  1444. X    switch ( **Str )
  1445. X    {
  1446. X    case '.':
  1447. X        /*  Allocate a regular expression node. */
  1448. X        (*Str)++;
  1449. X        Node = AllocRegExpNode();
  1450. X        Node->NodeType = DATA_ANY;
  1451. X        break;
  1452. X    case '[':
  1453. X        /*  Allocate a regular expression node. */
  1454. X        Node = AllocRegExpNode();
  1455. X
  1456. X        /*  Allocate a set. */
  1457. X        if ((Node->data.CSet = (SET_TYPE *) calloc(1, SET_SIZE *
  1458. X        sizeof( SET_TYPE ))) == NULL)
  1459. X        {
  1460. X            fprintf(ErrFile,
  1461. X                    "%s %d : Out of memory.\n",
  1462. X                    __FILE__,
  1463. X                    __LINE__);
  1464. X            exit( 1 );
  1465. X        }
  1466. X
  1467. X        /*  Create the set. */
  1468. X        (*Str)++;
  1469. X        CrtSet(Str, Node->data.CSet);
  1470. X        Node->NodeType = DATA_SET;
  1471. X        break;
  1472. X    case '(':
  1473. X        /*  Skip parentheses. */
  1474. X        (*Str)++;
  1475. X
  1476. X        /*  Allocate a regular expression node. */
  1477. X        Node = AllocRegExpNode();
  1478. X        Node->NodeType = OP_L_PAREN;
  1479. X
  1480. X        /*  Save the sub expression number. */
  1481. X        if (SubExprNo > MAX_SUB_EXPRS)
  1482. X        {
  1483. X            fprintf(ErrFile,
  1484. X                    "%s %d : Error - To many sub-expressions.\n",
  1485. X                    __FILE__,
  1486. X                    __LINE__);
  1487. X            exit( 1 );
  1488. X        }
  1489. X        Node->SubExprNo = SubExprNo++;
  1490. X
  1491. X        /*  Get sub expression. */
  1492. X        Node->Right = Alternation( Str );
  1493. X
  1494. X        /*  Check for end parentheses.  */
  1495. X        if (**Str != ')')
  1496. X        {
  1497. X            fprintf(ErrFile,
  1498. X                    "%s %d : Error - missing ')' in regular expression.\n",
  1499. X                    __FILE__,
  1500. X                    __LINE__);
  1501. X            exit( 1 );
  1502. X        }
  1503. X        (*Str)++;
  1504. X        break;
  1505. X    default:
  1506. X        /*  Check for badly formed regular expression.  */
  1507. X        if (InSet(SpecSet, **Str) || InSet(PostSet, **Str))
  1508. X        {
  1509. X            fprintf(ErrFile,
  1510. X                    "%s %d : Error - badly formed regular expression.\n",
  1511. X                    __FILE__,
  1512. X                    __LINE__);
  1513. X            fprintf(ErrFile,
  1514. X                    "\tUnexpected character '%c'\n",
  1515. X                    **Str);
  1516. X            exit( 1 );
  1517. X        }
  1518. X
  1519. X        /*  Allocate a regular expression node. */
  1520. X        Node = AllocRegExpNode();
  1521. X
  1522. X        /*  Get characters while they are not in the set of special
  1523. X        *   characters.
  1524. X        */
  1525. X        for (Tmp = Buffer; **Str; )
  1526. X            if (**Str == '\\' && (*Str)[1])
  1527. X            {
  1528. X                *Tmp++ = *++*Str;
  1529. X                ++*Str;
  1530. X            }
  1531. X            else if (InSet(SpecSet, **Str) || InSet(PostSet, **Str))
  1532. X                break;
  1533. X            else
  1534. X                *Tmp++ = *(*Str)++;
  1535. X        *Tmp = '\0';
  1536. X        Node->NodeType = DATA_STRING;
  1537. X
  1538. X        /*  Duplicate the string and add to the node.   */
  1539. X        if ((Node->data.MatchStr = StrDup( Buffer )) == NULL)
  1540. X        {
  1541. X            fprintf(ErrFile,
  1542. X                    "%s %d : Out of memory.\n",
  1543. X                    __FILE__,
  1544. X                    __LINE__);
  1545. X            exit( 1 );
  1546. X        }
  1547. X        break;
  1548. X    }
  1549. X
  1550. X    /*  Return a pointer to the new node.   */
  1551. X    return( Node );
  1552. X}
  1553. X
  1554. X/*-----------------------------------------------------------------------------
  1555. X| Routine   :   Enumerate() --- Enumerate a regular expression.
  1556. X|
  1557. X| Inputs    :   Str - Pointer to current character in source RE string.
  1558. X|
  1559. X| Returns   :   Pointer to regular expression node.
  1560. X-----------------------------------------------------------------------------*/
  1561. X
  1562. Xstatic
  1563. XREG_EXP_NODE    *Enumerate(char **Str)
  1564. X{
  1565. X    auto    REG_EXP_NODE    *Node;
  1566. X    auto    REG_EXP_NODE    *New;
  1567. X    extern  FILE            *ErrFile;
  1568. X
  1569. X    /*  Get the regular expression. */
  1570. X    Node = Unary( Str );
  1571. X
  1572. X    /*  Test for enumeration.   */
  1573. X    if ( InSet(PostSet, **Str) )
  1574. X    {
  1575. X        /*  Check for the special case of enumerating a '.' */
  1576. X        if (Node->NodeType == DATA_ANY)
  1577. X        {
  1578. X            /*  Modify it to be a DATA_SPAN type.   */
  1579. X            Node->NodeType = DATA_SPAN;
  1580. X        }
  1581. X        else if (Node->NodeType == OP_L_PAREN)
  1582. X        {
  1583. X            fprintf(ErrFile,
  1584. X                    "%s %d : Error, can not enumerate a sub expression.\n",
  1585. X                    __FILE__,
  1586. X                    __LINE__);
  1587. X            exit( 1 );
  1588. X        }
  1589. X        else
  1590. X        {
  1591. X            /*  Allocate an enumeration node.   */
  1592. X            New = AllocRegExpNode();
  1593. X            New->Right = Node;
  1594. X            New->NodeType = OP_ENUM;
  1595. X            Node = New;
  1596. X        }
  1597. X
  1598. X        /*  Determine enumeration value.    */
  1599. X        EnumOp(Str, Node);
  1600. X    }
  1601. X    return( Node );
  1602. X}
  1603. X
  1604. X/*-----------------------------------------------------------------------------
  1605. X| Routine   :   Catenation() --- Concatenate regular expressions.
  1606. X|
  1607. X| Inputs    :   Str - Pointer to current character in source RE string.
  1608. X|
  1609. X| Returns   :   Pointer to regular expression node.
  1610. X-----------------------------------------------------------------------------*/
  1611. X
  1612. Xstatic
  1613. XREG_EXP_NODE    *Catenation(char    **Str)
  1614. X{
  1615. X    auto        REG_EXP_NODE    *Root;
  1616. X    auto        REG_EXP_NODE    *SubExpr;
  1617. X    auto        REG_EXP_NODE    *Prev;
  1618. X    auto        REG_EXP_NODE    *Next;
  1619. X
  1620. X    /*  Loop, getting concatenations (and operation) of regular
  1621. X    *   expressions seperated by OR's.
  1622. X    */
  1623. X    Prev = Root = NULL;
  1624. X    for ( ; ; )
  1625. X    {
  1626. X        /*  Get next sub expression.    */
  1627. X        SubExpr = Enumerate( Str );
  1628. X
  1629. X        /*  Determine type of action to take.   */
  1630. X        if (**Str && **Str != '|' && **Str != ')' && **Str != '$')
  1631. X        {
  1632. X            /*  Create new node.    */
  1633. X            Next = AllocRegExpNode();
  1634. X            Next->Left = SubExpr;
  1635. X            Next->NodeType = OP_AND;
  1636. X
  1637. X            /*  Link to old node.   */
  1638. X            if ( Prev )
  1639. X                Prev->Right = Next;
  1640. X            else
  1641. X                Root = Next;
  1642. X            Prev = Next;
  1643. X        }
  1644. X        else
  1645. X        {
  1646. X            /*  Determine final link type.  */
  1647. X            if ( Prev )
  1648. X                Prev->Right = SubExpr;
  1649. X            else
  1650. X                Root = SubExpr;
  1651. X
  1652. X            /*  End loop.   */
  1653. X            break;
  1654. X        }
  1655. X    }
  1656. X
  1657. X    /*  Return a pointer to the root node.  */
  1658. X    return( Root );
  1659. X}
  1660. X
  1661. X/*-----------------------------------------------------------------------------
  1662. X| Routine   :   Anchor() --- Parse the two anchoring unary operators.
  1663. X|
  1664. X| Inputs    :   Str     - Regular expression source string.
  1665. X|
  1666. X| Returns   :   Returns a pointer to the compiled regular expression.
  1667. X-----------------------------------------------------------------------------*/
  1668. X
  1669. Xstatic
  1670. XREG_EXP_NODE    *Anchor(char    **Str)
  1671. X{
  1672. X    auto        REG_EXP_NODE    *Root;
  1673. X    auto        REG_EXP_NODE    *Node;
  1674. X
  1675. X    /*  Check for begining of line anchor.  */
  1676. X    if (**Str == '^')
  1677. X    {
  1678. X        /*  Next character. */
  1679. X        (*Str)++;
  1680. X
  1681. X        /*  Allocate a node.    */
  1682. X        Root = AllocRegExpNode();
  1683. X        Root->NodeType = DATA_LEFT_ANCHOR;
  1684. X
  1685. X        /*  Get expression. */
  1686. X        Root->Right = Catenation( Str );
  1687. X    }
  1688. X    else
  1689. X        Root = Catenation( Str );
  1690. X
  1691. X    /*  Check for end of line anchor.   */
  1692. X    if (**Str == '$')
  1693. X    {
  1694. X        /*  Next character. */
  1695. X        (*Str)++;
  1696. X
  1697. X        /*  Allocate a node.    */
  1698. X        Node = AllocRegExpNode();
  1699. X        Node->NodeType = DATA_RIGHT_ANCHOR;
  1700. X        Node->Right = Root;
  1701. X        Root = Node;
  1702. X    }
  1703. X
  1704. X    /*  Return regular expression.  */
  1705. X    return( Root );
  1706. X}
  1707. X
  1708. X/*-----------------------------------------------------------------------------
  1709. X| Routine   :   Alternation() --- Parse an alternation expression.
  1710. X|
  1711. X| Inputs    :   Str - Pointer to current character in source RE string.
  1712. X|
  1713. X| Returns   :   Pointer to regular expression node.
  1714. X-----------------------------------------------------------------------------*/
  1715. X
  1716. Xstatic
  1717. XREG_EXP_NODE    *Alternation(char   **Str)
  1718. X{
  1719. X    auto        REG_EXP_NODE    *Root;
  1720. X    auto        REG_EXP_NODE    *New;
  1721. X
  1722. X    /*  Get a concatenation of regular expressions. */
  1723. X    Root = Anchor( Str );
  1724. X
  1725. X    /*  Loop, getting concatenations (and operation) of regular
  1726. X    *   expressions seperated by OR's.
  1727. X    */
  1728. X    while (**Str == '|')
  1729. X    {
  1730. X        /*  Next character. */
  1731. X        (*Str)++;
  1732. X
  1733. X        /*  Allocate a node.    */
  1734. X        New = AllocRegExpNode();
  1735. X        New->Left = Root;
  1736. X        New->NodeType = OP_OR;
  1737. X
  1738. X        /*  Get right hand of expression.   */
  1739. X        New->Right = Anchor( Str );
  1740. X        Root = New;
  1741. X    }
  1742. X
  1743. X    /*  Return root of regular expression tree. */
  1744. X    return( Root );
  1745. X}
  1746. X
  1747. X/*-----------------------------------------------------------------------------
  1748. X| Routine   :   ReGraph() --- Convert a regular expression tree into a graph.
  1749. X|
  1750. X| Inputs    :   Node    - Regular expression tree node.
  1751. X|
  1752. X| Returns   :   Returns a pointer to the compiled regular expression.
  1753. X-----------------------------------------------------------------------------*/
  1754. X
  1755. Xstatic
  1756. XREG_EXP_NODE    *ReGraph(REG_EXP_NODE   *Node,
  1757. X                         REG_EXP_NODE   *Link)
  1758. X{
  1759. X    auto        REG_EXP_NODE    *RetLink;
  1760. X    auto        REG_EXP_NODE    *New;
  1761. X
  1762. X    /*  Determine operation type.   */
  1763. X    switch ( Node->NodeType )
  1764. X    {
  1765. X    case OP_L_PAREN:
  1766. X        /*  Allocate an end of parentheses node.    */
  1767. X        New = AllocRegExpNode();
  1768. X        New->NodeType = OP_R_PAREN;
  1769. X        New->SubExprNo = Node->SubExprNo;
  1770. X        New->Right = Link;
  1771. X
  1772. X        /*  Continue link.  */
  1773. X        Node->Right = ReGraph(Node->Right, New);
  1774. X        RetLink = Node;
  1775. X        break;
  1776. X    case OP_ENUM:
  1777. X        /*  Continue link.  */
  1778. X        Node->Left = Node->Right;
  1779. X        Node->Right = Link;
  1780. X        RetLink = Node;
  1781. X        break;
  1782. X    case OP_AND:
  1783. X        /*  Traverse right, returning a pointer that can be used to
  1784. X        *   link the tree into a graph.
  1785. X        */
  1786. X        RetLink = ReGraph(Node->Right, Link);
  1787. X
  1788. X        /*  Go down left and link together. */
  1789. X        RetLink = ReGraph(Node->Left, RetLink);
  1790. X
  1791. X        /*  Free AND node and return the link.  */
  1792. X        free( Node );
  1793. X        break;
  1794. X    case OP_OR:
  1795. X        /*  Allocate an end of or node. */
  1796. X        New = AllocRegExpNode();
  1797. X        New->NodeType = END_OR;
  1798. X        New->Right = Link;
  1799. X
  1800. X        /*  Process both.   */
  1801. X        Node->Right = ReGraph(Node->Right, New);
  1802. X        Node->Left = ReGraph(Node->Left, New);
  1803. X
  1804. X        /*  Return pointer to OR.   */
  1805. X        RetLink = Node;
  1806. X        break;
  1807. X    case DATA_LEFT_ANCHOR:
  1808. X        Node->Right = ReGraph(Node->Right, Link);
  1809. X        RetLink = Node;
  1810. X        break;
  1811. X    case DATA_RIGHT_ANCHOR:
  1812. X        /*  Allocate an end of parentheses node.    */
  1813. X        New = Node->Right;
  1814. X        Node->Right = Link;
  1815. X        RetLink = ReGraph(New, Node);
  1816. X        break;
  1817. X    case DATA_ANY:
  1818. X    case DATA_SPAN:
  1819. X    case DATA_STRING:
  1820. X    case DATA_SET:
  1821. X        Node->Right = Link;
  1822. X        RetLink = Node;
  1823. X    }
  1824. X
  1825. X    /*  Return a pointer to the tail end of the graph so far.   */
  1826. X    return( RetLink );
  1827. X}
  1828. X
  1829. X/*-----------------------------------------------------------------------------
  1830. X| Routine   :   ReCompile() --- Compile a regular expression.
  1831. X|
  1832. X| Inputs    :   Str     - Regular expression source string.
  1833. X|
  1834. X| Returns   :   Returns a pointer to the compiled regular expression.
  1835. X-----------------------------------------------------------------------------*/
  1836. X
  1837. XREG_EXP_NODE    *ReCompile(char *Str)
  1838. X{
  1839. X    auto        REG_EXP_NODE    *Root;
  1840. X
  1841. X    /*  Construct sets, if not already constructed. */
  1842. X    if (ReInitFlag == 0)
  1843. X    {
  1844. X        auto    char    **Str;
  1845. X
  1846. X        /*  Create the sets.    */
  1847. X        Str = &SpecStr;
  1848. X        CrtSet(Str, SpecSet);
  1849. X        Str = &PostFixStr;
  1850. X        CrtSet(Str, PostSet);
  1851. X        Str = &DecStr;
  1852. X        CrtSet(Str, DecSet);
  1853. X
  1854. X        /*  We have initialized, so set flag saying so. */
  1855. X        ReInitFlag = 1;
  1856. X    }
  1857. X
  1858. X    /*  Check for leading anchor.   */
  1859. X    SubExprNo = 1;
  1860. X    Root = Alternation( &Str );
  1861. X
  1862. X     /*  Print the regular expression tree.  */
  1863. X#if defined( RE_TEST )
  1864. X    PrtReExpr(Root, 0);
  1865. X#endif
  1866. X
  1867. X    /*  Convert to a graph. */
  1868. X    Root = ReGraph(Root, NULL);
  1869. X
  1870. X    /*  Return pointer to regular expression.   */
  1871. X    return( Root );
  1872. X}
  1873. X
  1874. X/*-----------------------------------------------------------------------------
  1875. X| Routine   :   FreeReExpr() --- Free the memory of a regular expression
  1876. X|               graph memory.
  1877. X|
  1878. X| Inputs    :   ReExpr  - Regular expression digraph root.
  1879. X-----------------------------------------------------------------------------*/
  1880. X
  1881. XREG_EXP_NODE    *FreeReExpr(REG_EXP_NODE    *ReExpr)
  1882. X{
  1883. X    auto    REG_EXP_NODE    *Node;
  1884. X    auto    REG_EXP_NODE    *EndOr;
  1885. X    extern  FILE            *ErrFile;
  1886. X
  1887. X    /*  Free the different node types.  */
  1888. X    while (ReExpr && ReExpr->NodeType != END_OR)
  1889. X    {
  1890. X        /*  Get pointer to next node.   */
  1891. X        Node = ReExpr->Right;
  1892. X
  1893. X        /*  Select operation on node type.  */
  1894. X        switch ( ReExpr->NodeType )
  1895. X        {
  1896. X        case OP_ENUM:
  1897. X            (void) FreeReExpr( ReExpr->Left );
  1898. X            break;
  1899. X        case OP_OR:
  1900. X            /*  Free to end of OR branch.   */
  1901. X            (void) FreeReExpr( ReExpr->Right );
  1902. X
  1903. X            /*  Free to end of OR branch, and get pointer to next
  1904. X            *   node.
  1905. X            */
  1906. X            EndOr = FreeReExpr( ReExpr->Left );
  1907. X            Node = EndOr->Right;
  1908. X            free( EndOr );
  1909. X            break;
  1910. X        case DATA_STRING:
  1911. X            free( ReExpr->data.MatchStr );
  1912. X            break;
  1913. X        case DATA_SET:
  1914. X            free( ReExpr->data.CSet );
  1915. X            break;
  1916. X        case OP_AND:
  1917. X        case OP_L_PAREN:
  1918. X        case OP_R_PAREN:
  1919. X        case DATA_LEFT_ANCHOR:
  1920. X        case DATA_RIGHT_ANCHOR:
  1921. X        case DATA_ANY:
  1922. X        case DATA_SPAN:
  1923. X            break;
  1924. X        default:
  1925. X            fprintf(ErrFile,
  1926. X                    "%s %d : Error - illegal regular expression node type.\n",
  1927. X                    __FILE__,
  1928. X                    __LINE__);
  1929. X            exit( 1 );
  1930. X        }
  1931. X
  1932. X        /*  Move along. */
  1933. X        free( ReExpr );
  1934. X        ReExpr = Node;
  1935. X    }
  1936. X
  1937. X    /*  Return pointer to end of chain. */
  1938. X    return( ReExpr );
  1939. X}
  1940. END_OF_FILE
  1941.   if test 22231 -ne `wc -c <'recomp.c'`; then
  1942.     echo shar: \"'recomp.c'\" unpacked with wrong size!
  1943.   fi
  1944.   # end of 'recomp.c'
  1945. fi
  1946. echo shar: End of archive 3 \(of 7\).
  1947. cp /dev/null ark3isdone
  1948. MISSING=""
  1949. for I in 1 2 3 4 5 6 7 ; do
  1950.     if test ! -f ark${I}isdone ; then
  1951.     MISSING="${MISSING} ${I}"
  1952.     fi
  1953. done
  1954. if test "${MISSING}" = "" ; then
  1955.     echo You have unpacked all 7 archives.
  1956.     rm -f ark[1-9]isdone
  1957. else
  1958.     echo You still must unpack the following archives:
  1959.     echo "        " ${MISSING}
  1960. fi
  1961. exit 0
  1962. exit 0 # Just in case...
  1963.