home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume34 / splash / part01 < prev    next >
Encoding:
Text File  |  1993-01-18  |  52.8 KB  |  1,948 lines

  1. Newsgroups: comp.sources.misc
  2. From: morris@netcom.com (Jim Morris)
  3. Subject: v34i121: splash - Small Perl-like List And String Handling class lib, v1.8, Part01/03
  4. Message-ID: <csm-v34i121=splash.154150@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: 2601085c844b126ccc51b73fff701afa
  6. Date: Mon, 18 Jan 1993 21:42:47 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: morris@netcom.com (Jim Morris)
  10. Posting-number: Volume 34, Issue 121
  11. Archive-name: splash/part01
  12. Environment: C++
  13.  
  14. SPLASH is a c++ class library that implements a string data type and a
  15. list data type. These data types are based on the equivalent data types
  16. found in Larry Wall's Perl language.
  17.  
  18. Splash has extensive regular expression operations on strings and lists
  19. of strings as well as the typical string operations.
  20.  
  21. The list data type allows entry of data to the top, bottom and middle
  22. of the list. It also implements the ability to extract slices from
  23. lists.
  24.  
  25. An associative array data type, is also implemented using the list class.
  26.  
  27. -----------------
  28. #! /bin/sh
  29. # This is a shell archive.  Remove anything before this line, then feed it
  30. # into a shell via "sh file" or similar.  To overwrite existing files,
  31. # type "sh file -c".
  32. # Contents:  README Patchlevel regex.c sample slicetst.v splash.doc
  33. # Wrapped by kent@sparky on Mon Jan 18 15:29:04 1993
  34. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  35. echo If this archive is complete, you will see the following message:
  36. echo '          "shar: End of archive 1 (of 3)."'
  37. if test -f 'README' -a "${1}" != "-c" ; then 
  38.   echo shar: Will not clobber existing file \"'README'\"
  39. else
  40.   echo shar: Extracting \"'README'\" \(6887 characters\)
  41.   sed "s/^X//" >'README' <<'END_OF_FILE'
  42. XThe SPLASH c++ class library
  43. X============================
  44. X
  45. X(Small Perl-like List And String Handling class library)
  46. X
  47. X
  48. XSPLASH is a c++ class library that implements my favourite Perl
  49. Xconstructs.
  50. X
  51. XFor those not familiar with Perl, it is an excellent scripting language
  52. Xby Larry Wall and is available for most platforms.
  53. X
  54. XThis Class library provides List and String handling capabilities based
  55. Xon those provided in Perl, because the Perl constructs are so useful.
  56. X
  57. XOverview
  58. X-------- 
  59. XIn a nut-shell SPLASH provides a Dynamic List template class
  60. X(SPList<T>) that allows you to add and extract data from the top of the
  61. Xlist (push & pop), and from the bottom of the list (unshift & shift).
  62. Xie a FIFO could be implemented by push'ing data onto the list and
  63. Xshift'ing data off the list.  The list can be sorted (uses operator< on
  64. Xthe elements) and reversed.  (mylist.sort().reverse() will produce a
  65. Xlist sorted in reverse order).  Another list can be inserted anywhere
  66. Xin a list, or elements deleted from within the list (splice).  And any
  67. Xindividual element can be accessed using the '[]' operator.
  68. X
  69. XThe String class (SPString) implements a Dynamic string which provides
  70. Xan index() and rindex() function that finds the offset within the
  71. Xstring of a sub-string. A substring may be extracted from the string,
  72. Xor assigned to within a string (expanding or shrinking the string as
  73. Xrequired). The string may be used anywhere a const char * can be used.
  74. XThe standard comparison functions (< > == etc) are available.  It
  75. Xallows string concatenation using the '+' and '+=' operator.  It
  76. Xprovides regular expressions (with sub-expression extraction) that can
  77. Xbe easily applied to the strings. A powerful substitute function and
  78. Xtranslation function (s() and tr()) are available.
  79. X
  80. XThe String List class (SPStringList) is basically a List class with
  81. Xsome added functionality specific to lists of strings. It lets you grep
  82. Xfor a regular expression within the list, returning a list of strings
  83. Xthat match. It lets you generate a list of strings from a single string
  84. Xby splitting the string at a given regular expression (token parsing).
  85. XIt lets you generate a single string by concatenating a list of strings
  86. Xseparated by a given string.
  87. X
  88. XThe Associative array class (Assoc<T>) lets you keep a list which is
  89. Xindexed by a string.
  90. X
  91. XAll the Classes have fully implemented streams operators for input and
  92. Xoutput, to allow convenient file or stream processing.
  93. X
  94. XThe Regexp class fully encapsulates the regular expression library, so
  95. Xyou can easily use your own favourite one.
  96. X
  97. XUsage Restrictions
  98. X------------------
  99. X
  100. XThere are none. This Code is not Copyright, use as you will.  The
  101. Xregexp code is Copyright by Henry Spencer, see the comments in regex.c
  102. Xfor Copyright info.  The only changes I have made are to the header
  103. Xfile, by adding a c++ prototype field.
  104. X
  105. XClass description
  106. X-----------------
  107. XThe Class Hierarchy and member functions are:-
  108. X
  109. Xclass SPList<T>
  110. X    T& operator[]    // index into list
  111. X    void reset()    // clear out list
  112. X    int scalar()    // returns number of elements in list
  113. X    int count()        // ditto
  114. X    T pop()        // returns and removes top of list
  115. X    void push(T)    // enters element onto top of list
  116. X    void push(SPList<T>) // enters a list of elements onto top of list
  117. X    T shift()        // returns & removes element at bottom of list
  118. X    int unshift(T)    // enters element into bottom of list
  119. X    int unshift(SPList<T>) // enters lists into bottom of list
  120. X    SPList<T> reverse()       // returns reverse order of list
  121. X    SPList<T> splice(offset) // removes elements in list from 'offset'
  122. X    SPList<T> splice(offset, len) // removes 'len' elements in list
  123. X    SPList<T> splice(offset, len, SPList<T>)// replaces elements in list
  124. X    SPList<T> sort() // sorts list according to result of '<' operator
  125. X    ostream& operator>>() // input stream
  126. X    istream& operator<<() // output stream
  127. X
  128. X    class SPStringList // everything SPList does and ...
  129. X        int split(str [,pat] [,limit]) // splits string on pattern
  130. X    SPString join([pat])     // concatenates list with 'pat'
  131. X    int m(exp, targ)      // makes list of sub exp matches
  132. X    SPStringList grep(exp) // returns matches in list
  133. X    ostream& operator>>()
  134. X        istream& operator<<()
  135. X
  136. Xclass SPString
  137. X    int length()    // length of string
  138. X    char chop()        // remove last character in string
  139. X    int index(SPString [, offset]) // find string from start
  140. X    int rindex(SPString [, offset]) // find string from end
  141. X    SPString substr(offset [, len]) // substring works as lvalue as well
  142. X    operator[]    // index character
  143. X    operator<   // less than
  144. X    operator>
  145. X    operator<=
  146. X    operator>=
  147. X    operator==
  148. X    operator!=
  149. X    operator+        // concatenate 2 strings
  150. X    operator+=        // as per c
  151. X    int m(exp)         // return true if regexp matches string
  152. X    int m(exp, SPStringList&) // ditto & generates a list of subexpressions
  153. X    int tr(exp, rep [,opts]) // translate 'ex'p into 'rep'
  154. X    int s(exp, rep [,opts]) // substitute 'exp' with 'rep'
  155. X    ostream& operator>>()
  156. X    istream& operator<<()
  157. X
  158. XAssociative array and helpers
  159. X-----------------------------
  160. X
  161. Xclass Binar<T>    // a key, value pair
  162. X    T& value()
  163. X    SPString& key()
  164. X
  165. Xclass Assoc<T>    // an associateive array, loosely based on the perl one
  166. X    T& operator(SPString) // equivalent to perl $assoc{"one"} = value
  167. X    Binar& operator[n]      // returns n'th entry in associative array
  168. X    SPStringList keys()   // returns a list of keys
  169. X    SPList<T> values()    // returns a list of values
  170. X    int isin(SPString)    // tests if key is in assoc array
  171. X    T adelete(SPString)    // deletes given key/value
  172. X
  173. XOther Classes
  174. X-------------
  175. X
  176. XVarString    - A variable length string class, used in SPString.
  177. X
  178. XSPListBase<T>     - is the base class for SPList and handles the
  179. X          auto expanding dynamic array, optimized for
  180. X          prepending and appending data.
  181. X
  182. XTempString     - makes a copy of a string, and can return a char *
  183. X               and will free the storage when done. Something like
  184. X          a cross between strsave() and alloca().
  185. X
  186. XRegexp        - Handles the interface to the regular expression
  187. X          library being used.
  188. X
  189. XRange         - Simple class to maintain a range, just makes things
  190. X          easier.
  191. X
  192. XFor More Info
  193. X=============
  194. X
  195. XSee readme.2nd for how to build and test, and various caveats.
  196. XSee splash.doc for documentation on each function.
  197. XSee sample/*.c++ for examples of how to use splash
  198. XSee regexp.doc for an explanation of the regexp library used
  199. X
  200. XDistribution
  201. X------------
  202. X
  203. XThis is also available as a compressed tar file or
  204. X.zoo format with MSDOS compatible names.
  205. X
  206. XEmail: morris@netcom.com or jegm@sgi.com for a different format.
  207. Xor
  208. Xget the latest version of SPLASH, which is always available via
  209. Xanonymous FTP.
  210. X
  211. XAlso the current alpha version will also be available. This is for
  212. Xadventurous users only. It will be called splalphaxxx.tar.Z
  213. X
  214. Xsite:-
  215. Xnetcom.com
  216. X
  217. XPath:-
  218. X~ftp/pub/morris/splash.tar.Z
  219. X~ftp/pub/morris/splash.zoo
  220. X
  221. END_OF_FILE
  222.   if test 6887 -ne `wc -c <'README'`; then
  223.     echo shar: \"'README'\" unpacked with wrong size!
  224.   fi
  225.   # end of 'README'
  226. fi
  227. if test -f 'Patchlevel' -a "${1}" != "-c" ; then 
  228.   echo shar: Will not clobber existing file \"'Patchlevel'\"
  229. else
  230.   echo shar: Extracting \"'Patchlevel'\" \(4 characters\)
  231.   sed "s/^X//" >'Patchlevel' <<'END_OF_FILE'
  232. X1.8
  233. END_OF_FILE
  234.   if test 4 -ne `wc -c <'Patchlevel'`; then
  235.     echo shar: \"'Patchlevel'\" unpacked with wrong size!
  236.   fi
  237.   # end of 'Patchlevel'
  238. fi
  239. if test -f 'regex.c' -a "${1}" != "-c" ; then 
  240.   echo shar: Will not clobber existing file \"'regex.c'\"
  241. else
  242.   echo shar: Extracting \"'regex.c'\" \(27702 characters\)
  243.   sed "s/^X//" >'regex.c' <<'END_OF_FILE'
  244. X/*
  245. X * regcomp and regexec -- regsub and regerror are elsewhere
  246. X *
  247. X *    Copyright (c) 1986 by University of Toronto.
  248. X *    Written by Henry Spencer.  Not derived from licensed software.
  249. X *
  250. X *    Permission is granted to anyone to use this software for any
  251. X *    purpose on any computer system, and to redistribute it freely,
  252. X *    subject to the following restrictions:
  253. X *
  254. X *    1. The author is not responsible for the consequences of use of
  255. X *        this software, no matter how awful, even if they arise
  256. X *        from defects in it.
  257. X *
  258. X *    2. The origin of this software must not be misrepresented, either
  259. X *        by explicit claim or by omission.
  260. X *
  261. X *    3. Altered versions must be plainly marked as such, and must not
  262. X *        be misrepresented as being the original software.
  263. X *
  264. X * Beware that some of this code is subtly aware of the way operator
  265. X * precedence is structured in regular expressions.  Serious changes in
  266. X * regular-expression syntax might require a total rethink.
  267. X */
  268. X#include <stdio.h>
  269. X#include <stdlib.h>
  270. X#include "regex.h"
  271. X#include "regmagic.h"
  272. X
  273. X/*
  274. X * The "internal use only" fields in regexp.h are present to pass info from
  275. X * compile to execute that permits the execute phase to run lots faster on
  276. X * simple cases.  They are:
  277. X *
  278. X * regstart    char that must begin a match; '\0' if none obvious
  279. X * reganch    is the match anchored (at beginning-of-line only)?
  280. X * regmust    string (pointer into program) that match must include, or NULL
  281. X * regmlen    length of regmust string
  282. X *
  283. X * Regstart and reganch permit very fast decisions on suitable starting points
  284. X * for a match, cutting down the work a lot.  Regmust permits fast rejection
  285. X * of lines that cannot possibly match.  The regmust tests are costly enough
  286. X * that regcomp() supplies a regmust only if the r.e. contains something
  287. X * potentially expensive (at present, the only such thing detected is * or +
  288. X * at the start of the r.e., which can involve a lot of backup).  Regmlen is
  289. X * supplied because the test in regexec() needs it and regcomp() is computing
  290. X * it anyway.
  291. X */
  292. X
  293. X/*
  294. X * Structure for regexp "program".  This is essentially a linear encoding
  295. X * of a nondeterministic finite-state machine (aka syntax charts or
  296. X * "railroad normal form" in parsing technology).  Each node is an opcode
  297. X * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
  298. X * all nodes except BRANCH implement concatenation; a "next" pointer with
  299. X * a BRANCH on both ends of it is connecting two alternatives.  (Here we
  300. X * have one of the subtle syntax dependencies:  an individual BRANCH (as
  301. X * opposed to a collection of them) is never concatenated with anything
  302. X * because of operator precedence.)  The operand of some types of node is
  303. X * a literal string; for others, it is a node leading into a sub-FSM.  In
  304. X * particular, the operand of a BRANCH node is the first node of the branch.
  305. X * (NB this is *not* a tree structure:  the tail of the branch connects
  306. X * to the thing following the set of BRANCHes.)  The opcodes are:
  307. X */
  308. X
  309. X/* definition    number    opnd?    meaning */
  310. X#define    END    0    /* no    End of program. */
  311. X#define    BOL    1    /* no    Match "" at beginning of line. */
  312. X#define    EOL    2    /* no    Match "" at end of line. */
  313. X#define    ANY    3    /* no    Match any one character. */
  314. X#define    ANYOF    4    /* str    Match any character in this string. */
  315. X#define    ANYBUT    5    /* str    Match any character not in this string. */
  316. X#define    BRANCH    6    /* node    Match this alternative, or the next... */
  317. X#define    BACK    7    /* no    Match "", "next" ptr points backward. */
  318. X#define    EXACTLY    8    /* str    Match this string. */
  319. X#define    NOTHING    9    /* no    Match empty string. */
  320. X#define    STAR    10    /* node    Match this (simple) thing 0 or more times. */
  321. X#define    PLUS    11    /* node    Match this (simple) thing 1 or more times. */
  322. X#define    OPEN    20    /* no    Mark this point in input as start of #n. */
  323. X            /*    OPEN+1 is number 1, etc. */
  324. X#define    CLOSE    30    /* no    Analogous to OPEN. */
  325. X
  326. X/*
  327. X * Opcode notes:
  328. X *
  329. X * BRANCH    The set of branches constituting a single choice are hooked
  330. X *        together with their "next" pointers, since precedence prevents
  331. X *        anything being concatenated to any individual branch.  The
  332. X *        "next" pointer of the last BRANCH in a choice points to the
  333. X *        thing following the whole choice.  This is also where the
  334. X *        final "next" pointer of each individual branch points; each
  335. X *        branch starts with the operand node of a BRANCH node.
  336. X *
  337. X * BACK        Normal "next" pointers all implicitly point forward; BACK
  338. X *        exists to make loop structures possible.
  339. X *
  340. X * STAR,PLUS    '?', and complex '*' and '+', are implemented as circular
  341. X *        BRANCH structures using BACK.  Simple cases (one character
  342. X *        per match) are implemented with STAR and PLUS for speed
  343. X *        and to minimize recursive plunges.
  344. X *
  345. X * OPEN,CLOSE    ...are numbered at compile time.
  346. X */
  347. X
  348. X/*
  349. X * A node is one char of opcode followed by two chars of "next" pointer.
  350. X * "Next" pointers are stored as two 8-bit pieces, high order first.  The
  351. X * value is a positive offset from the opcode of the node containing it.
  352. X * An operand, if any, simply follows the node.  (Note that much of the
  353. X * code generation knows about this implicit relationship.)
  354. X *
  355. X * Using two bytes for the "next" pointer is vast overkill for most things,
  356. X * but allows patterns to get big without disasters.
  357. X */
  358. X#define    OP(p)    (*(p))
  359. X#define    NEXT(p)    (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
  360. X#define    OPERAND(p)    ((p) + 3)
  361. X
  362. X/*
  363. X * See regmagic.h for one further detail of program structure.
  364. X */
  365. X
  366. X
  367. X/*
  368. X * Utility definitions.
  369. X */
  370. X#ifndef CHARBITS
  371. X#define    UCHARAT(p)    ((int)*(unsigned char *)(p))
  372. X#else
  373. X#define    UCHARAT(p)    ((int)*(p)&CHARBITS)
  374. X#endif
  375. X
  376. X#define    FAIL(m)    { regerror(m); return(NULL); }
  377. X#define    ISMULT(c)    ((c) == '*' || (c) == '+' || (c) == '?')
  378. X#define    META    "^$.[()|?+*\\"
  379. X
  380. X/*
  381. X * Flags to be passed up and down.
  382. X */
  383. X#define    HASWIDTH    01    /* Known never to match null string. */
  384. X#define    SIMPLE        02    /* Simple enough to be STAR/PLUS operand. */
  385. X#define    SPSTART        04    /* Starts with * or +. */
  386. X#define    WORST        0    /* Worst case. */
  387. X
  388. X/*
  389. X * Global work variables for regcomp().
  390. X */
  391. Xstatic char *regparse;        /* Input-scan pointer. */
  392. Xstatic int regnpar;        /* () count. */
  393. Xstatic char regdummy;
  394. Xstatic char *regcode;        /* Code-emit pointer; ®dummy = don't. */
  395. Xstatic long regsize;        /* Code size. */
  396. X
  397. X/*
  398. X * Forward declarations for regcomp()'s friends.
  399. X */
  400. X#ifndef STATIC
  401. X#define    STATIC    static
  402. X#endif
  403. XSTATIC char *reg();
  404. XSTATIC char *regbranch();
  405. XSTATIC char *regpiece();
  406. XSTATIC char *regatom();
  407. XSTATIC char *regnode();
  408. XSTATIC char *regnext();
  409. XSTATIC void regc();
  410. XSTATIC void reginsert();
  411. XSTATIC void regtail();
  412. XSTATIC void regoptail();
  413. X#ifdef STRCSPN
  414. XSTATIC int strcspn();
  415. X#endif
  416. X
  417. X/*
  418. X - regcomp - compile a regular expression into internal code
  419. X *
  420. X * We can't allocate space until we know how big the compiled form will be,
  421. X * but we can't compile it (and thus know how big it is) until we've got a
  422. X * place to put the code.  So we cheat:  we compile it twice, once with code
  423. X * generation turned off and size counting turned on, and once "for real".
  424. X * This also means that we don't allocate space until we are sure that the
  425. X * thing really will compile successfully, and we never have to move the
  426. X * code and thus invalidate pointers into it.  (Note that it has to be in
  427. X * one piece because free() must be able to free it all.)
  428. X *
  429. X * Beware that the optimization-preparation code in here knows about some
  430. X * of the structure of the compiled regexp.
  431. X */
  432. Xregexp *
  433. Xregcomp(exp)
  434. Xchar *exp;
  435. X{
  436. X    register regexp *r;
  437. X    register char *scan;
  438. X    register char *longest;
  439. X    register int len;
  440. X    int flags;
  441. X
  442. X    if (exp == NULL)
  443. X        FAIL("NULL argument");
  444. X
  445. X    /* First pass: determine size, legality. */
  446. X    regparse = exp;
  447. X    regnpar = 1;
  448. X    regsize = 0L;
  449. X    regcode = ®dummy;
  450. X    regc(MAGIC);
  451. X    if (reg(0, &flags) == NULL)
  452. X        return(NULL);
  453. X
  454. X    /* Small enough for pointer-storage convention? */
  455. X    if (regsize >= 32767L)        /* Probably could be 65535L. */
  456. X        FAIL("regexp too big");
  457. X
  458. X    /* Allocate space. */
  459. X    r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
  460. X    if (r == NULL)
  461. X        FAIL("out of space");
  462. X
  463. X    /* Second pass: emit code. */
  464. X    regparse = exp;
  465. X    regnpar = 1;
  466. X    regcode = r->program;
  467. X    regc(MAGIC);
  468. X    if (reg(0, &flags) == NULL)
  469. X        return(NULL);
  470. X
  471. X    /* Dig out information for optimizations. */
  472. X    r->regstart = '\0';    /* Worst-case defaults. */
  473. X    r->reganch = 0;
  474. X    r->regmust = NULL;
  475. X    r->regmlen = 0;
  476. X    scan = r->program+1;            /* First BRANCH. */
  477. X    if (OP(regnext(scan)) == END) {        /* Only one top-level choice. */
  478. X        scan = OPERAND(scan);
  479. X
  480. X        /* Starting-point info. */
  481. X        if (OP(scan) == EXACTLY)
  482. X            r->regstart = *OPERAND(scan);
  483. X        else if (OP(scan) == BOL)
  484. X            r->reganch++;
  485. X
  486. X        /*
  487. X         * If there's something expensive in the r.e., find the
  488. X         * longest literal string that must appear and make it the
  489. X         * regmust.  Resolve ties in favor of later strings, since
  490. X         * the regstart check works with the beginning of the r.e.
  491. X         * and avoiding duplication strengthens checking.  Not a
  492. X         * strong reason, but sufficient in the absence of others.
  493. X         */
  494. X        if (flags&SPSTART) {
  495. X            longest = NULL;
  496. X            len = 0;
  497. X            for (; scan != NULL; scan = regnext(scan))
  498. X                if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
  499. X                    longest = OPERAND(scan);
  500. X                    len = strlen(OPERAND(scan));
  501. X                }
  502. X            r->regmust = longest;
  503. X            r->regmlen = len;
  504. X        }
  505. X    }
  506. X
  507. X    return(r);
  508. X}
  509. X
  510. X/*
  511. X - reg - regular expression, i.e. main body or parenthesized thing
  512. X *
  513. X * Caller must absorb opening parenthesis.
  514. X *
  515. X * Combining parenthesis handling with the base level of regular expression
  516. X * is a trifle forced, but the need to tie the tails of the branches to what
  517. X * follows makes it hard to avoid.
  518. X */
  519. Xstatic char *
  520. Xreg(paren, flagp)
  521. Xint paren;            /* Parenthesized? */
  522. Xint *flagp;
  523. X{
  524. X    register char *ret;
  525. X    register char *br;
  526. X    register char *ender;
  527. X    register int parno;
  528. X    int flags;
  529. X
  530. X    *flagp = HASWIDTH;    /* Tentatively. */
  531. X
  532. X    /* Make an OPEN node, if parenthesized. */
  533. X    if (paren) {
  534. X        if (regnpar >= NSUBEXP)
  535. X            FAIL("too many ()");
  536. X        parno = regnpar;
  537. X        regnpar++;
  538. X        ret = regnode(OPEN+parno);
  539. X    } else
  540. X        ret = NULL;
  541. X
  542. X    /* Pick up the branches, linking them together. */
  543. X    br = regbranch(&flags);
  544. X    if (br == NULL)
  545. X        return(NULL);
  546. X    if (ret != NULL)
  547. X        regtail(ret, br);    /* OPEN -> first. */
  548. X    else
  549. X        ret = br;
  550. X    if (!(flags&HASWIDTH))
  551. X        *flagp &= ~HASWIDTH;
  552. X    *flagp |= flags&SPSTART;
  553. X    while (*regparse == '|') {
  554. X        regparse++;
  555. X        br = regbranch(&flags);
  556. X        if (br == NULL)
  557. X            return(NULL);
  558. X        regtail(ret, br);    /* BRANCH -> BRANCH. */
  559. X        if (!(flags&HASWIDTH))
  560. X            *flagp &= ~HASWIDTH;
  561. X        *flagp |= flags&SPSTART;
  562. X    }
  563. X
  564. X    /* Make a closing node, and hook it on the end. */
  565. X    ender = regnode((paren) ? CLOSE+parno : END);    
  566. X    regtail(ret, ender);
  567. X
  568. X    /* Hook the tails of the branches to the closing node. */
  569. X    for (br = ret; br != NULL; br = regnext(br))
  570. X        regoptail(br, ender);
  571. X
  572. X    /* Check for proper termination. */
  573. X    if (paren && *regparse++ != ')') {
  574. X        FAIL("unmatched ()");
  575. X    } else if (!paren && *regparse != '\0') {
  576. X        if (*regparse == ')') {
  577. X            FAIL("unmatched ()");
  578. X        } else
  579. X            FAIL("junk on end");    /* "Can't happen". */
  580. X        /* NOTREACHED */
  581. X    }
  582. X
  583. X    return(ret);
  584. X}
  585. X
  586. X/*
  587. X - regbranch - one alternative of an | operator
  588. X *
  589. X * Implements the concatenation operator.
  590. X */
  591. Xstatic char *
  592. Xregbranch(flagp)
  593. Xint *flagp;
  594. X{
  595. X    register char *ret;
  596. X    register char *chain;
  597. X    register char *latest;
  598. X    int flags;
  599. X
  600. X    *flagp = WORST;        /* Tentatively. */
  601. X
  602. X    ret = regnode(BRANCH);
  603. X    chain = NULL;
  604. X    while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
  605. X        latest = regpiece(&flags);
  606. X        if (latest == NULL)
  607. X            return(NULL);
  608. X        *flagp |= flags&HASWIDTH;
  609. X        if (chain == NULL)    /* First piece. */
  610. X            *flagp |= flags&SPSTART;
  611. X        else
  612. X            regtail(chain, latest);
  613. X        chain = latest;
  614. X    }
  615. X    if (chain == NULL)    /* Loop ran zero times. */
  616. X        (void) regnode(NOTHING);
  617. X
  618. X    return(ret);
  619. X}
  620. X
  621. X/*
  622. X - regpiece - something followed by possible [*+?]
  623. X *
  624. X * Note that the branching code sequences used for ? and the general cases
  625. X * of * and + are somewhat optimized:  they use the same NOTHING node as
  626. X * both the endmarker for their branch list and the body of the last branch.
  627. X * It might seem that this node could be dispensed with entirely, but the
  628. X * endmarker role is not redundant.
  629. X */
  630. Xstatic char *
  631. Xregpiece(flagp)
  632. Xint *flagp;
  633. X{
  634. X    register char *ret;
  635. X    register char op;
  636. X    register char *next;
  637. X    int flags;
  638. X
  639. X    ret = regatom(&flags);
  640. X    if (ret == NULL)
  641. X        return(NULL);
  642. X
  643. X    op = *regparse;
  644. X    if (!ISMULT(op)) {
  645. X        *flagp = flags;
  646. X        return(ret);
  647. X    }
  648. X
  649. X    if (!(flags&HASWIDTH) && op != '?')
  650. X        FAIL("*+ operand could be empty");
  651. X    *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
  652. X
  653. X    if (op == '*' && (flags&SIMPLE))
  654. X        reginsert(STAR, ret);
  655. X    else if (op == '*') {
  656. X        /* Emit x* as (x&|), where & means "self". */
  657. X        reginsert(BRANCH, ret);            /* Either x */
  658. X        regoptail(ret, regnode(BACK));        /* and loop */
  659. X        regoptail(ret, ret);            /* back */
  660. X        regtail(ret, regnode(BRANCH));        /* or */
  661. X        regtail(ret, regnode(NOTHING));        /* null. */
  662. X    } else if (op == '+' && (flags&SIMPLE))
  663. X        reginsert(PLUS, ret);
  664. X    else if (op == '+') {
  665. X        /* Emit x+ as x(&|), where & means "self". */
  666. X        next = regnode(BRANCH);            /* Either */
  667. X        regtail(ret, next);
  668. X        regtail(regnode(BACK), ret);        /* loop back */
  669. X        regtail(next, regnode(BRANCH));        /* or */
  670. X        regtail(ret, regnode(NOTHING));        /* null. */
  671. X    } else if (op == '?') {
  672. X        /* Emit x? as (x|) */
  673. X        reginsert(BRANCH, ret);            /* Either x */
  674. X        regtail(ret, regnode(BRANCH));        /* or */
  675. X        next = regnode(NOTHING);        /* null. */
  676. X        regtail(ret, next);
  677. X        regoptail(ret, next);
  678. X    }
  679. X    regparse++;
  680. X    if (ISMULT(*regparse))
  681. X        FAIL("nested *?+");
  682. X
  683. X    return(ret);
  684. X}
  685. X
  686. X/*
  687. X - regatom - the lowest level
  688. X *
  689. X * Optimization:  gobbles an entire sequence of ordinary characters so that
  690. X * it can turn them into a single node, which is smaller to store and
  691. X * faster to run.  Backslashed characters are exceptions, each becoming a
  692. X * separate node; the code is simpler that way and it's not worth fixing.
  693. X */
  694. Xstatic char *
  695. Xregatom(flagp)
  696. Xint *flagp;
  697. X{
  698. X    register char *ret;
  699. X    int flags;
  700. X
  701. X    *flagp = WORST;        /* Tentatively. */
  702. X
  703. X    switch (*regparse++) {
  704. X    case '^':
  705. X        ret = regnode(BOL);
  706. X        break;
  707. X    case '$':
  708. X        ret = regnode(EOL);
  709. X        break;
  710. X    case '.':
  711. X        ret = regnode(ANY);
  712. X        *flagp |= HASWIDTH|SIMPLE;
  713. X        break;
  714. X    case '[': {
  715. X            register int class;
  716. X            register int classend;
  717. X
  718. X            if (*regparse == '^') {    /* Complement of range. */
  719. X                ret = regnode(ANYBUT);
  720. X                regparse++;
  721. X            } else
  722. X                ret = regnode(ANYOF);
  723. X            if (*regparse == ']' || *regparse == '-')
  724. X                regc(*regparse++);
  725. X            while (*regparse != '\0' && *regparse != ']') {
  726. X                if (*regparse == '-') {
  727. X                    regparse++;
  728. X                    if (*regparse == ']' || *regparse == '\0')
  729. X                        regc('-');
  730. X                    else {
  731. X                        class = UCHARAT(regparse-2)+1;
  732. X                        classend = UCHARAT(regparse);
  733. X                        if (class > classend+1)
  734. X                            FAIL("invalid [] range");
  735. X                        for (; class <= classend; class++)
  736. X                            regc(class);
  737. X                        regparse++;
  738. X                    }
  739. X                } else
  740. X                    regc(*regparse++);
  741. X            }
  742. X            regc('\0');
  743. X            if (*regparse != ']')
  744. X                FAIL("unmatched []");
  745. X            regparse++;
  746. X            *flagp |= HASWIDTH|SIMPLE;
  747. X        }
  748. X        break;
  749. X    case '(':
  750. X        ret = reg(1, &flags);
  751. X        if (ret == NULL)
  752. X            return(NULL);
  753. X        *flagp |= flags&(HASWIDTH|SPSTART);
  754. X        break;
  755. X    case '\0':
  756. X    case '|':
  757. X    case ')':
  758. X        FAIL("internal urp");    /* Supposed to be caught earlier. */
  759. X        break;
  760. X    case '?':
  761. X    case '+':
  762. X    case '*':
  763. X        FAIL("?+* follows nothing");
  764. X        break;
  765. X    case '\\':
  766. X        if (*regparse == '\0')
  767. X            FAIL("trailing \\");
  768. X        ret = regnode(EXACTLY);
  769. X        regc(*regparse++);
  770. X        regc('\0');
  771. X        *flagp |= HASWIDTH|SIMPLE;
  772. X        break;
  773. X    default: {
  774. X            register int len;
  775. X            register char ender;
  776. X
  777. X            regparse--;
  778. X            len = strcspn(regparse, META);
  779. X            if (len <= 0)
  780. X                FAIL("internal disaster");
  781. X            ender = *(regparse+len);
  782. X            if (len > 1 && ISMULT(ender))
  783. X                len--;        /* Back off clear of ?+* operand. */
  784. X            *flagp |= HASWIDTH;
  785. X            if (len == 1)
  786. X                *flagp |= SIMPLE;
  787. X            ret = regnode(EXACTLY);
  788. X            while (len > 0) {
  789. X                regc(*regparse++);
  790. X                len--;
  791. X            }
  792. X            regc('\0');
  793. X        }
  794. X        break;
  795. X    }
  796. X
  797. X    return(ret);
  798. X}
  799. X
  800. X/*
  801. X - regnode - emit a node
  802. X */
  803. Xstatic char *            /* Location. */
  804. Xregnode(op)
  805. Xchar op;
  806. X{
  807. X    register char *ret;
  808. X    register char *ptr;
  809. X
  810. X    ret = regcode;
  811. X    if (ret == ®dummy) {
  812. X        regsize += 3;
  813. X        return(ret);
  814. X    }
  815. X
  816. X    ptr = ret;
  817. X    *ptr++ = op;
  818. X    *ptr++ = '\0';        /* Null "next" pointer. */
  819. X    *ptr++ = '\0';
  820. X    regcode = ptr;
  821. X
  822. X    return(ret);
  823. X}
  824. X
  825. X/*
  826. X - regc - emit (if appropriate) a byte of code
  827. X */
  828. Xstatic void
  829. Xregc(b)
  830. Xchar b;
  831. X{
  832. X    if (regcode != ®dummy)
  833. X        *regcode++ = b;
  834. X    else
  835. X        regsize++;
  836. X}
  837. X
  838. X/*
  839. X - reginsert - insert an operator in front of already-emitted operand
  840. X *
  841. X * Means relocating the operand.
  842. X */
  843. Xstatic void
  844. Xreginsert(op, opnd)
  845. Xchar op;
  846. Xchar *opnd;
  847. X{
  848. X    register char *src;
  849. X    register char *dst;
  850. X    register char *place;
  851. X
  852. X    if (regcode == ®dummy) {
  853. X        regsize += 3;
  854. X        return;
  855. X    }
  856. X
  857. X    src = regcode;
  858. X    regcode += 3;
  859. X    dst = regcode;
  860. X    while (src > opnd)
  861. X        *--dst = *--src;
  862. X
  863. X    place = opnd;        /* Op node, where operand used to be. */
  864. X    *place++ = op;
  865. X    *place++ = '\0';
  866. X    *place++ = '\0';
  867. X}
  868. X
  869. X/*
  870. X - regtail - set the next-pointer at the end of a node chain
  871. X */
  872. Xstatic void
  873. Xregtail(p, val)
  874. Xchar *p;
  875. Xchar *val;
  876. X{
  877. X    register char *scan;
  878. X    register char *temp;
  879. X    register int offset;
  880. X
  881. X    if (p == ®dummy)
  882. X        return;
  883. X
  884. X    /* Find last node. */
  885. X    scan = p;
  886. X    for (;;) {
  887. X        temp = regnext(scan);
  888. X        if (temp == NULL)
  889. X            break;
  890. X        scan = temp;
  891. X    }
  892. X
  893. X    if (OP(scan) == BACK)
  894. X        offset = scan - val;
  895. X    else
  896. X        offset = val - scan;
  897. X    *(scan+1) = (offset>>8)&0377;
  898. X    *(scan+2) = offset&0377;
  899. X}
  900. X
  901. X/*
  902. X - regoptail - regtail on operand of first argument; nop if operandless
  903. X */
  904. Xstatic void
  905. Xregoptail(p, val)
  906. Xchar *p;
  907. Xchar *val;
  908. X{
  909. X    /* "Operandless" and "op != BRANCH" are synonymous in practice. */
  910. X    if (p == NULL || p == ®dummy || OP(p) != BRANCH)
  911. X        return;
  912. X    regtail(OPERAND(p), val);
  913. X}
  914. X
  915. X/*
  916. X * regexec and friends
  917. X */
  918. X
  919. X/*
  920. X * Global work variables for regexec().
  921. X */
  922. Xstatic char *reginput;        /* String-input pointer. */
  923. Xstatic char *regbol;        /* Beginning of input, for ^ check. */
  924. Xstatic char **regstartp;    /* Pointer to startp array. */
  925. Xstatic char **regendp;        /* Ditto for endp. */
  926. X
  927. X/*
  928. X * Forwards.
  929. X */
  930. XSTATIC int regtry();
  931. XSTATIC int regmatch();
  932. XSTATIC int regrepeat();
  933. X
  934. X#ifdef DEBUG
  935. Xint regnarrate = 0;
  936. Xvoid regdump();
  937. XSTATIC char *regprop();
  938. X#endif
  939. X
  940. X/*
  941. X - regexec - match a regexp against a string
  942. X */
  943. Xint
  944. Xregexec(prog, string)
  945. Xregister regexp *prog;
  946. Xregister char *string;
  947. X{
  948. X    register char *s;
  949. X    extern char *strchr();
  950. X
  951. X    /* Be paranoid... */
  952. X    if (prog == NULL || string == NULL) {
  953. X        regerror("NULL parameter");
  954. X        return(0);
  955. X    }
  956. X
  957. X    /* Check validity of program. */
  958. X    if (UCHARAT(prog->program) != MAGIC) {
  959. X        regerror("corrupted program");
  960. X        return(0);
  961. X    }
  962. X
  963. X    /* If there is a "must appear" string, look for it. */
  964. X    if (prog->regmust != NULL) {
  965. X        s = string;
  966. X        while ((s = strchr(s, prog->regmust[0])) != NULL) {
  967. X            if (strncmp(s, prog->regmust, prog->regmlen) == 0)
  968. X                break;    /* Found it. */
  969. X            s++;
  970. X        }
  971. X        if (s == NULL)    /* Not present. */
  972. X            return(0);
  973. X    }
  974. X
  975. X    /* Mark beginning of line for ^ . */
  976. X    regbol = string;
  977. X
  978. X    /* Simplest case:  anchored match need be tried only once. */
  979. X    if (prog->reganch)
  980. X        return(regtry(prog, string));
  981. X
  982. X    /* Messy cases:  unanchored match. */
  983. X    s = string;
  984. X    if (prog->regstart != '\0')
  985. X        /* We know what char it must start with. */
  986. X        while ((s = strchr(s, prog->regstart)) != NULL) {
  987. X            if (regtry(prog, s))
  988. X                return(1);
  989. X            s++;
  990. X        }
  991. X    else
  992. X        /* We don't -- general case. */
  993. X        do {
  994. X            if (regtry(prog, s))
  995. X                return(1);
  996. X        } while (*s++ != '\0');
  997. X
  998. X    /* Failure. */
  999. X    return(0);
  1000. X}
  1001. X
  1002. X/*
  1003. X - regtry - try match at specific point
  1004. X */
  1005. Xstatic int            /* 0 failure, 1 success */
  1006. Xregtry(prog, string)
  1007. Xregexp *prog;
  1008. Xchar *string;
  1009. X{
  1010. X    register int i;
  1011. X    register char **sp;
  1012. X    register char **ep;
  1013. X
  1014. X    reginput = string;
  1015. X    regstartp = prog->startp;
  1016. X    regendp = prog->endp;
  1017. X
  1018. X    sp = prog->startp;
  1019. X    ep = prog->endp;
  1020. X    for (i = NSUBEXP; i > 0; i--) {
  1021. X        *sp++ = NULL;
  1022. X        *ep++ = NULL;
  1023. X    }
  1024. X    if (regmatch(prog->program + 1)) {
  1025. X        prog->startp[0] = string;
  1026. X        prog->endp[0] = reginput;
  1027. X        return(1);
  1028. X    } else
  1029. X        return(0);
  1030. X}
  1031. X
  1032. X/*
  1033. X - regmatch - main matching routine
  1034. X *
  1035. X * Conceptually the strategy is simple:  check to see whether the current
  1036. X * node matches, call self recursively to see whether the rest matches,
  1037. X * and then act accordingly.  In practice we make some effort to avoid
  1038. X * recursion, in particular by going through "ordinary" nodes (that don't
  1039. X * need to know whether the rest of the match failed) by a loop instead of
  1040. X * by recursion.
  1041. X */
  1042. Xstatic int            /* 0 failure, 1 success */
  1043. Xregmatch(prog)
  1044. Xchar *prog;
  1045. X{
  1046. X    register char *scan;    /* Current node. */
  1047. X    char *next;        /* Next node. */
  1048. X    extern char *strchr();
  1049. X
  1050. X    scan = prog;
  1051. X#ifdef DEBUG
  1052. X    if (scan != NULL && regnarrate)
  1053. X        fprintf(stderr, "%s(\n", regprop(scan));
  1054. X#endif
  1055. X    while (scan != NULL) {
  1056. X#ifdef DEBUG
  1057. X        if (regnarrate)
  1058. X            fprintf(stderr, "%s...\n", regprop(scan));
  1059. X#endif
  1060. X        next = regnext(scan);
  1061. X
  1062. X        switch (OP(scan)) {
  1063. X        case BOL:
  1064. X            if (reginput != regbol)
  1065. X                return(0);
  1066. X            break;
  1067. X        case EOL:
  1068. X            if (*reginput != '\0')
  1069. X                return(0);
  1070. X            break;
  1071. X        case ANY:
  1072. X            if (*reginput == '\0')
  1073. X                return(0);
  1074. X            reginput++;
  1075. X            break;
  1076. X        case EXACTLY: {
  1077. X                register int len;
  1078. X                register char *opnd;
  1079. X
  1080. X                opnd = OPERAND(scan);
  1081. X                /* Inline the first character, for speed. */
  1082. X                if (*opnd != *reginput)
  1083. X                    return(0);
  1084. X                len = strlen(opnd);
  1085. X                if (len > 1 && strncmp(opnd, reginput, len) != 0)
  1086. X                    return(0);
  1087. X                reginput += len;
  1088. X            }
  1089. X            break;
  1090. X        case ANYOF:
  1091. X             if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
  1092. X                return(0);
  1093. X            reginput++;
  1094. X            break;
  1095. X        case ANYBUT:
  1096. X             if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
  1097. X                return(0);
  1098. X            reginput++;
  1099. X            break;
  1100. X        case NOTHING:
  1101. X            break;
  1102. X        case BACK:
  1103. X            break;
  1104. X        case OPEN+1:
  1105. X        case OPEN+2:
  1106. X        case OPEN+3:
  1107. X        case OPEN+4:
  1108. X        case OPEN+5:
  1109. X        case OPEN+6:
  1110. X        case OPEN+7:
  1111. X        case OPEN+8:
  1112. X        case OPEN+9: {
  1113. X                register int no;
  1114. X                register char *save;
  1115. X
  1116. X                no = OP(scan) - OPEN;
  1117. X                save = reginput;
  1118. X
  1119. X                if (regmatch(next)) {
  1120. X                    /*
  1121. X                     * Don't set startp if some later
  1122. X                     * invocation of the same parentheses
  1123. X                     * already has.
  1124. X                     */
  1125. X                    if (regstartp[no] == NULL)
  1126. X                        regstartp[no] = save;
  1127. X                    return(1);
  1128. X                } else
  1129. X                    return(0);
  1130. X            }
  1131. X            break;
  1132. X        case CLOSE+1:
  1133. X        case CLOSE+2:
  1134. X        case CLOSE+3:
  1135. X        case CLOSE+4:
  1136. X        case CLOSE+5:
  1137. X        case CLOSE+6:
  1138. X        case CLOSE+7:
  1139. X        case CLOSE+8:
  1140. X        case CLOSE+9: {
  1141. X                register int no;
  1142. X                register char *save;
  1143. X
  1144. X                no = OP(scan) - CLOSE;
  1145. X                save = reginput;
  1146. X
  1147. X                if (regmatch(next)) {
  1148. X                    /*
  1149. X                     * Don't set endp if some later
  1150. X                     * invocation of the same parentheses
  1151. X                     * already has.
  1152. X                     */
  1153. X                    if (regendp[no] == NULL)
  1154. X                        regendp[no] = save;
  1155. X                    return(1);
  1156. X                } else
  1157. X                    return(0);
  1158. X            }
  1159. X            break;
  1160. X        case BRANCH: {
  1161. X                register char *save;
  1162. X
  1163. X                if (OP(next) != BRANCH)        /* No choice. */
  1164. X                    next = OPERAND(scan);    /* Avoid recursion. */
  1165. X                else {
  1166. X                    do {
  1167. X                        save = reginput;
  1168. X                        if (regmatch(OPERAND(scan)))
  1169. X                            return(1);
  1170. X                        reginput = save;
  1171. X                        scan = regnext(scan);
  1172. X                    } while (scan != NULL && OP(scan) == BRANCH);
  1173. X                    return(0);
  1174. X                    /* NOTREACHED */
  1175. X                }
  1176. X            }
  1177. X            break;
  1178. X        case STAR:
  1179. X        case PLUS: {
  1180. X                register char nextch;
  1181. X                register int no;
  1182. X                register char *save;
  1183. X                register int min;
  1184. X
  1185. X                /*
  1186. X                 * Lookahead to avoid useless match attempts
  1187. X                 * when we know what character comes next.
  1188. X                 */
  1189. X                nextch = '\0';
  1190. X                if (OP(next) == EXACTLY)
  1191. X                    nextch = *OPERAND(next);
  1192. X                min = (OP(scan) == STAR) ? 0 : 1;
  1193. X                save = reginput;
  1194. X                no = regrepeat(OPERAND(scan));
  1195. X                while (no >= min) {
  1196. X                    /* If it could work, try it. */
  1197. X                    if (nextch == '\0' || *reginput == nextch)
  1198. X                        if (regmatch(next))
  1199. X                            return(1);
  1200. X                    /* Couldn't or didn't -- back up. */
  1201. X                    no--;
  1202. X                    reginput = save + no;
  1203. X                }
  1204. X                return(0);
  1205. X            }
  1206. X            break;
  1207. X        case END:
  1208. X            return(1);    /* Success! */
  1209. X            break;
  1210. X        default:
  1211. X            regerror("memory corruption");
  1212. X            return(0);
  1213. X            break;
  1214. X        }
  1215. X
  1216. X        scan = next;
  1217. X    }
  1218. X
  1219. X    /*
  1220. X     * We get here only if there's trouble -- normally "case END" is
  1221. X     * the terminating point.
  1222. X     */
  1223. X    regerror("corrupted pointers");
  1224. X    return(0);
  1225. X}
  1226. X
  1227. X/*
  1228. X - regrepeat - repeatedly match something simple, report how many
  1229. X */
  1230. Xstatic int
  1231. Xregrepeat(p)
  1232. Xchar *p;
  1233. X{
  1234. X      char *strchr();
  1235. X    register int count = 0;
  1236. X    register char *scan;
  1237. X    register char *opnd;
  1238. X
  1239. X    scan = reginput;
  1240. X    opnd = OPERAND(p);
  1241. X    switch (OP(p)) {
  1242. X    case ANY:
  1243. X        count = strlen(scan);
  1244. X        scan += count;
  1245. X        break;
  1246. X    case EXACTLY:
  1247. X        while (*opnd == *scan) {
  1248. X            count++;
  1249. X            scan++;
  1250. X        }
  1251. X        break;
  1252. X    case ANYOF:
  1253. X        while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
  1254. X            count++;
  1255. X            scan++;
  1256. X        }
  1257. X        break;
  1258. X    case ANYBUT:
  1259. X        while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
  1260. X            count++;
  1261. X            scan++;
  1262. X        }
  1263. X        break;
  1264. X    default:        /* Oh dear.  Called inappropriately. */
  1265. X        regerror("internal foulup");
  1266. X        count = 0;    /* Best compromise. */
  1267. X        break;
  1268. X    }
  1269. X    reginput = scan;
  1270. X
  1271. X    return(count);
  1272. X}
  1273. X
  1274. X/*
  1275. X - regnext - dig the "next" pointer out of a node
  1276. X */
  1277. Xstatic char *
  1278. Xregnext(p)
  1279. Xregister char *p;
  1280. X{
  1281. X    register int offset;
  1282. X
  1283. X    if (p == ®dummy)
  1284. X        return(NULL);
  1285. X
  1286. X    offset = NEXT(p);
  1287. X    if (offset == 0)
  1288. X        return(NULL);
  1289. X
  1290. X    if (OP(p) == BACK)
  1291. X        return(p-offset);
  1292. X    else
  1293. X        return(p+offset);
  1294. X}
  1295. X
  1296. X#ifdef DEBUG
  1297. X
  1298. XSTATIC char *regprop();
  1299. X
  1300. X/*
  1301. X - regdump - dump a regexp onto stdout in vaguely comprehensible form
  1302. X */
  1303. Xvoid
  1304. Xregdump(r)
  1305. Xregexp *r;
  1306. X{
  1307. X    register char *s;
  1308. X    register char op = EXACTLY;    /* Arbitrary non-END op. */
  1309. X    register char *next;
  1310. X    extern char *strchr();
  1311. X
  1312. X
  1313. X    s = r->program + 1;
  1314. X    while (op != END) {    /* While that wasn't END last time... */
  1315. X        op = OP(s);
  1316. X        printf("%2d%s", s-r->program, regprop(s));    /* Where, what. */
  1317. X        next = regnext(s);
  1318. X        if (next == NULL)        /* Next ptr. */
  1319. X            printf("(0)");
  1320. X        else 
  1321. X            printf("(%d)", (s-r->program)+(next-s));
  1322. X        s += 3;
  1323. X        if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
  1324. X            /* Literal string, where present. */
  1325. X            while (*s != '\0') {
  1326. X                putchar(*s);
  1327. X                s++;
  1328. X            }
  1329. X            s++;
  1330. X        }
  1331. X        putchar('\n');
  1332. X    }
  1333. X
  1334. X    /* Header fields of interest. */
  1335. X    if (r->regstart != '\0')
  1336. X        printf("start `%c' ", r->regstart);
  1337. X    if (r->reganch)
  1338. X        printf("anchored ");
  1339. X    if (r->regmust != NULL)
  1340. X        printf("must have \"%s\"", r->regmust);
  1341. X    printf("\n");
  1342. X}
  1343. X
  1344. X/*
  1345. X - regprop - printable representation of opcode
  1346. X */
  1347. Xstatic char *
  1348. Xregprop(op)
  1349. Xchar *op;
  1350. X{
  1351. X    register char *p;
  1352. X    static char buf[50];
  1353. X
  1354. X    (void) strcpy(buf, ":");
  1355. X
  1356. X    switch (OP(op)) {
  1357. X    case BOL:
  1358. X        p = "BOL";
  1359. X        break;
  1360. X    case EOL:
  1361. X        p = "EOL";
  1362. X        break;
  1363. X    case ANY:
  1364. X        p = "ANY";
  1365. X        break;
  1366. X    case ANYOF:
  1367. X        p = "ANYOF";
  1368. X        break;
  1369. X    case ANYBUT:
  1370. X        p = "ANYBUT";
  1371. X        break;
  1372. X    case BRANCH:
  1373. X        p = "BRANCH";
  1374. X        break;
  1375. X    case EXACTLY:
  1376. X        p = "EXACTLY";
  1377. X        break;
  1378. X    case NOTHING:
  1379. X        p = "NOTHING";
  1380. X        break;
  1381. X    case BACK:
  1382. X        p = "BACK";
  1383. X        break;
  1384. X    case END:
  1385. X        p = "END";
  1386. X        break;
  1387. X    case OPEN+1:
  1388. X    case OPEN+2:
  1389. X    case OPEN+3:
  1390. X    case OPEN+4:
  1391. X    case OPEN+5:
  1392. X    case OPEN+6:
  1393. X    case OPEN+7:
  1394. X    case OPEN+8:
  1395. X    case OPEN+9:
  1396. X        sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
  1397. X        p = NULL;
  1398. X        break;
  1399. X    case CLOSE+1:
  1400. X    case CLOSE+2:
  1401. X    case CLOSE+3:
  1402. X    case CLOSE+4:
  1403. X    case CLOSE+5:
  1404. X    case CLOSE+6:
  1405. X    case CLOSE+7:
  1406. X    case CLOSE+8:
  1407. X    case CLOSE+9:
  1408. X        sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
  1409. X        p = NULL;
  1410. X        break;
  1411. X    case STAR:
  1412. X        p = "STAR";
  1413. X        break;
  1414. X    case PLUS:
  1415. X        p = "PLUS";
  1416. X        break;
  1417. X    default:
  1418. X        regerror("corrupted opcode");
  1419. X        break;
  1420. X    }
  1421. X    if (p != NULL)
  1422. X        (void) strcat(buf, p);
  1423. X    return(buf);
  1424. X}
  1425. X#endif
  1426. X
  1427. X/*
  1428. X * The following is provided for those people who do not have strcspn() in
  1429. X * their C libraries.  They should get off their butts and do something
  1430. X * about it; at least one public-domain implementation of those (highly
  1431. X * useful) string routines has been published on Usenet.
  1432. X */
  1433. X#ifdef STRCSPN
  1434. X/*
  1435. X * strcspn - find length of initial segment of s1 consisting entirely
  1436. X * of characters not from s2
  1437. X */
  1438. X
  1439. Xstatic int
  1440. Xstrcspn(s1, s2)
  1441. Xchar *s1;
  1442. Xchar *s2;
  1443. X{
  1444. X    register char *scan1;
  1445. X    register char *scan2;
  1446. X    register int count;
  1447. X
  1448. X    count = 0;
  1449. X    for (scan1 = s1; *scan1 != '\0'; scan1++) {
  1450. X        for (scan2 = s2; *scan2 != '\0';)    /* ++ moved down. */
  1451. X            if (*scan1 == *scan2++)
  1452. X                return(count);
  1453. X        count++;
  1454. X    }
  1455. X    return(count);
  1456. X}
  1457. X#endif
  1458. X
  1459. Xvoid regerror(char *s)
  1460. X{
  1461. X    fprintf(stderr, "regerror: %s\n", s);
  1462. X}
  1463. END_OF_FILE
  1464.   if test 27702 -ne `wc -c <'regex.c'`; then
  1465.     echo shar: \"'regex.c'\" unpacked with wrong size!
  1466.   fi
  1467.   # end of 'regex.c'
  1468. fi
  1469. if test ! -d 'sample' ; then
  1470.     echo shar: Creating directory \"'sample'\"
  1471.     mkdir 'sample'
  1472. fi
  1473. if test -f 'slicetst.v' -a "${1}" != "-c" ; then 
  1474.   echo shar: Will not clobber existing file \"'slicetst.v'\"
  1475. else
  1476.   echo shar: Extracting \"'slicetst.v'\" \(984 characters\)
  1477.   sed "s/^X//" >'slicetst.v' <<'END_OF_FILE'
  1478. X1,2 1 - 2 (2)
  1479. X
  1480. X1,2,3,4,5,6,7,8,9,10 1 - 10 (10)
  1481. X
  1482. X1,2,5,10 1 - 2 (2)
  1483. X5 - 5 (1)
  1484. X10 - 10 (1)
  1485. X
  1486. X39,1,38,2,4,5,37,7,8,9,20,22 39 - 39 (1)
  1487. X1 - 1 (1)
  1488. X38 - 38 (1)
  1489. X2 - 2 (1)
  1490. X4 - 5 (2)
  1491. X37 - 37 (1)
  1492. X7 - 9 (3)
  1493. X20 - 20 (1)
  1494. X22 - 22 (1)
  1495. X
  1496. Xix1= [0]1 [1]2 [2]3 [3]4 
  1497. X
  1498. Xix2= [0]22 [1]33 
  1499. X
  1500. Xix1(1, 2)= ix2: ix1= [0]1 [1]22 [2]33 [3]4 
  1501. X
  1502. Xtl ctor(ix1(2, 3)): tl= [0]33 [1]4 [2]0 
  1503. X
  1504. Xtl2= [0]0 [1]1 [2]2 [3]3 [4]4 
  1505. X
  1506. Xtl2(2, 3)= [0]2 [1]3 [2]4 
  1507. X
  1508. X
  1509. Xtl2(Slice(1, 2, 4, -1))= [0]1 [1]2 [2]4 
  1510. X
  1511. X
  1512. Xtl= tl2(Range(2, 4)): tl= [0]2 [1]3 [2]4 
  1513. X
  1514. Xtl2(Slice(1, 2, -1))= ix2: tl2 = [0]0 [1]22 [2]33 [3]3 [4]4 
  1515. X
  1516. Xtl3= tl2(1, 4): tl3 = [0]22 [1]33 [2]3 [3]4 
  1517. X
  1518. Xtl3.push(tl2(1, 2)): tl3= [0]22 [1]33 [2]3 [3]4 [4]22 [5]33 
  1519. X
  1520. Xtl3(Slice(4, 1, -1))= [0]22 [1]33 
  1521. X
  1522. X
  1523. Xtl3(Slice(2, 1, -1))= [0]3 [1]33 
  1524. X
  1525. X
  1526. Xtl4("1..3,6,10-22,30,31,35,37") = 1 - 3 (3)
  1527. X6 - 6 (1)
  1528. X10 - 22 (13)
  1529. X30 - 31 (2)
  1530. X35 - 35 (1)
  1531. X37 - 37 (1)
  1532. X
  1533. X[0]1 [1]2 [2]3 [3]6 [4]10 [5]11 [6]12 [7]13 [8]14 [9]15 [10]16 [11]17 [12]18 [13]19 [14]20 [15]21 [16]22 [17]30 [18]31 [19]35 [20]37 
  1534. X
  1535. X
  1536. END_OF_FILE
  1537.   if test 984 -ne `wc -c <'slicetst.v'`; then
  1538.     echo shar: \"'slicetst.v'\" unpacked with wrong size!
  1539.   fi
  1540.   # end of 'slicetst.v'
  1541. fi
  1542. if test -f 'splash.doc' -a "${1}" != "-c" ; then 
  1543.   echo shar: Will not clobber existing file \"'splash.doc'\"
  1544. else
  1545.   echo shar: Extracting \"'splash.doc'\" \(12844 characters\)
  1546.   sed "s/^X//" >'splash.doc' <<'END_OF_FILE'
  1547. Xclass SPList<T>    - A list of any type specified by T
  1548. X
  1549. X    T& operator[n]    - returns a reference to the element at index
  1550. X              'n' (0 based). Generates an ASSERT error
  1551. X              if n < 0, can be used as an lvalue. Using
  1552. X              an index greater than the current size of the
  1553. X              list will cause the list to grow upto that
  1554. X              index. The values inbetween will be undefined
  1555. X              if <T> is a built-in type.
  1556. X
  1557. X    operator void*()    - returns NULL if the list is empty,
  1558. X              can be used like: if(list) // not empty
  1559. X
  1560. X    int isempty()    - returns TRUE if the list is empty, as an
  1561. X              alternative for the previous technique
  1562. X
  1563. X    void reset()    - clears all elements in the list, but doesn't
  1564. X              actually free up the storage until it is
  1565. X              destroyed
  1566. X
  1567. X    int count()        - returns the number of elements in the list
  1568. X    int scalar()    - Perl-like Synonym (alias) for count()
  1569. X
  1570. X    T pop()        - removes and returns the last element on the
  1571. X              list. If the list is empty the value returned
  1572. X              is usually undefined
  1573. X
  1574. X    void push(T x)    - puts the single value 'x' at the end of the
  1575. X              list
  1576. X
  1577. X
  1578. X    void push(SPList<T> l)
  1579. X             - puts all the elements in the list 'l' at the
  1580. X              end of the list.
  1581. X
  1582. X    T shift()        - removes and returns the first element
  1583. X              in the list
  1584. X
  1585. X    int unshift(T x)    - puts the single value 'x' at the start
  1586. X              of the list
  1587. X
  1588. X    int unshift(SPList<T> l)
  1589. X            - puts all the elements in the list 'l'
  1590. X              at the start of the list
  1591. X
  1592. X    SPList<T> reverse()
  1593. X            - returns a list that is in the reverse
  1594. X              order
  1595. X
  1596. X    SPList<T> splice(offset, len, SPList<T> l)
  1597. X            - removes 'len' elements from 'offset' (0 based)
  1598. X              and inserts all the elements in the list 'l'
  1599. X              at the same position
  1600. X                
  1601. X    SPList<T> splice(offset, len)
  1602. X            - removes 'len' elements from 'offset' (0 based)
  1603. X
  1604. X    SPList<T> splice(offset)
  1605. X            - removes all the elements from 'offset'
  1606. X              (0 based)
  1607. X
  1608. X    SPList<T> sort()    - returns a list that has been sorted according
  1609. X              to the rules that T::operator<() returns
  1610. X              for the type T.
  1611. X
  1612. X    SubList<T> operator(offset, len)
  1613. X            - Returns the SubList from 'offset' for 'len'
  1614. X              elements. Maybe assigned to a SPList or used
  1615. X              wherever an SPList may be used. Can also be
  1616. X              assigned to, in which case the specified
  1617. X              elements are replaced with the RHS
  1618. X
  1619. X    SubList<T> operator(Range rng)
  1620. X            - Same as above, but returns the range
  1621. X              specified by 'rng'
  1622. X
  1623. X    SubList<T> operator(Slice slc)
  1624. X            - Same as above, but returns the slice
  1625. X              specified by 'slc'. A slice can be a
  1626. X              non-contiguous set of Ranges. See Slice
  1627. X              below.
  1628. X
  1629. X    SubList<T> operator(char *s)
  1630. X            - Same as above, but returns the slice
  1631. X              specified by 's' where 's' is a string that
  1632. X              specifies a set of indices.
  1633. X              's' can be:-
  1634. X                "a..b" or "a-b" which specifies a
  1635. X                 continuous range from a thru' b.
  1636. X                "a,b,c" which specifies individual indices
  1637. X                 a, b and c.
  1638. X                "a..b,c,d" which specifies a range and 2
  1639. X                 individual indices.
  1640. X
  1641. Xclass SPStringList    - everything SPList does and ...
  1642. X
  1643. X    int split(str [,pat] [,limit])
  1644. X            - appends the results of splitting the string
  1645. X              'str' to the list. If 'pat' is specified then
  1646. X              any string that matches the RE 'pat' is
  1647. X              considered a separator to split on, the
  1648. X              default is white-space. If 'limit' is specified
  1649. X              then no more than that number of elements is
  1650. X              generated. If 'limit' is not specified, then empty
  1651. X              entries are stripped from the end of the list.
  1652. X              If the RE includes subexpressions then they
  1653. X              are inserted into the list as well.
  1654. X              If 'pat' is equal to the string "' '" then
  1655. X              a special case is done which matches awks
  1656. X              handling of whitespace. If 'pat' is an empty
  1657. X              string "", then all characters are split into
  1658. X              the list
  1659. X
  1660. X    SPString join([pat])
  1661. X            - Returns the string that is the result of
  1662. X              combining all the elements in the list, and
  1663. X              separating them by 'pat'. If 'pat' is omitted
  1664. X              then the elements are separated by a space
  1665. X
  1666. X    int m(const char *exp, targ [,opts)
  1667. X            - Appends to the list all the subexpression
  1668. X              matches that occured when applying the regular
  1669. X              expression 'exp' to the string 'targ'.
  1670. X              The number of matches is returned. The first
  1671. X              element generated is the entire matched string
  1672. X              opts: (a const char * with default "")
  1673. X                  i - Forces case insensitive match
  1674. X    
  1675. X    SPStringList grep(const char *exp [,opts])
  1676. X            - returns a list of all the elements that
  1677. X              matched the regular expression 'exp'.
  1678. X              opts: (a const char * with default "")
  1679. X                  i - Forces the search to be case insensitive
  1680. X
  1681. Xclass SPString        - A standard c null-terminated string may be
  1682. X              used anywhere that a SPString can be used
  1683. X              and vice-versa.
  1684. X            - Individual characters may be read with
  1685. X              the '[]' operator.
  1686. X
  1687. X    int length()    - returns the length of the string
  1688. X
  1689. X    char chop()        - removes and returns the last character in the
  1690. X              string
  1691. X
  1692. X    int index(SPString str [, offset])
  1693. X            - returns the offset in the string that matches
  1694. X              the string 'str', starting at position
  1695. X              'offset' if specified, otherwise searches the
  1696. X              entire string.
  1697. X              Returns -1 if no match is found
  1698. X
  1699. X    int rindex(SPString str [, offset])
  1700. X            - returns the offset in the string that matches
  1701. X              the string 'str', starting at the end of the
  1702. X              string - 'offset' if specified, otherwise
  1703. X              searches the entire string.
  1704. X              Returns -1 if no match is found
  1705. X
  1706. X    substring substr(offset [, len])
  1707. X            - returns the substring within the string that
  1708. X              starts at 'offset' and is 'len' characters, if
  1709. X              'len' is omitted the rest of the string is
  1710. X              returned.
  1711. X              This may be used as an lvalue, in which case
  1712. X              the characters are removed, and the RHS of the
  1713. X              expression in inserted at the same postion.
  1714. X
  1715. X    SPStringList split([,pat] [,limit])
  1716. X            - same as SPStringList::split() but returns
  1717. X              a list of splits
  1718. X
  1719. X    operator<        - These operators do what you would expect
  1720. X    operator>
  1721. X    operator<=
  1722. X    operator>=
  1723. X    operator==
  1724. X    operator!=
  1725. X
  1726. X    operator+        - returns the result of contenating two or more
  1727. X              strings
  1728. X
  1729. X    operator+=        - replaces the LHS of the expression with the
  1730. X              concatenation of the LHS with the RHS
  1731. X
  1732. X    int m(const char *exp [,opts])
  1733. X            - returns 0 if the regular expression 'exp'
  1734. X              fails to match the string. Returns 1 if a
  1735. X              match was made
  1736. X              opts: (a const char * with default "")
  1737. X                  i - Forces case insensitive match
  1738. X    int m(const Regexp& exp)
  1739. X            - Same as above but takes a precompiled
  1740. X              regular expression.
  1741. X
  1742. X    int m(const char *exp, SPStringList& l [,opts])
  1743. X            - Loads the list 'l' with all subexpression
  1744. X              matches of the regular expression 'exp' with
  1745. X              the string. Returns 0 if no matches were made.
  1746. X              Returns the number of matches if any
  1747. X              opts: (a const char * with default "")
  1748. X                  i - Forces case insensitive match
  1749. X
  1750. X    int m(const Regexp& exp, SPStringList& l)
  1751. X            - Same as above but takes a precompiled
  1752. X              regular expression.
  1753. X
  1754. X    int tr(search, repl [,opts])
  1755. X            - replaces all occurrences of characters in 'search'
  1756. X              with the equivalent character in 'repl'. If 'repl'
  1757. X              is empty then just counts the characters.
  1758. X              opts: (a const char *) default is ""
  1759. X                 c - complements the 'search' pattern. Replaces
  1760. X                 all characters that are not in 'search', with
  1761. X                 the last character specified in 'repl'.
  1762. X                 d - deletes characters in 'search' that don't have an
  1763. X                 equivalent 'repl'
  1764. X                cd - deletes characters not in 'search' 
  1765. X                 s - compresses sequences of translated characters
  1766. X                 in resulting string
  1767. X
  1768. X    int s(exp, repl [,opts])
  1769. X            - substitute the first substring matched by
  1770. X              'exp' with the string 'repl'. $& in 'repl'
  1771. X              will be replaced by the entire matching
  1772. X              string, $1 - $9 will be replaced by the
  1773. X              respective subexpression match. \$ or \\
  1774. X              will insert a $ or \ respectively.
  1775. X              opts: (a const char *) default is ""
  1776. X                 g - causes all occurrences of 'exp' in
  1777. X                 the string to be replaced by 'repl'
  1778. X                 i - Forces case insensitive matching                
  1779. X
  1780. Xclass Assoc<T>        - an associative array whose key is a SPString
  1781. X              and the value is any type T
  1782. X
  1783. X    Assoc(SPString defkey, T defvalue)
  1784. X            - Constructor for an associative array, 'defkey'
  1785. X              becomes the default key, and 'defvalue' is the
  1786. X              default value. The default value is used to
  1787. X              create a new Association if a key is specified
  1788. X              that doesn't yet exist.
  1789. X
  1790. X    T& operator(SPString str)
  1791. X            - returns a reference to the value that is
  1792. X              associated with the key 'str'. This may be
  1793. X              used as an lvalue, and is in the only way to
  1794. X              make an association. If the key didn't exist
  1795. X              it will be entered with the default value, if
  1796. X              it was specified in the constructor, and a
  1797. X              reference to that is returned. If no default
  1798. X              was specified, then the value will be
  1799. X              undefined
  1800. X
  1801. X    Binar& operator[n]    - Returns the (key, value) pair found at index
  1802. X              'n' of the associative array
  1803. X
  1804. X    SPStringList keys()
  1805. X            - Returns a list of all the keys in the
  1806. X              associative array.
  1807. X
  1808. X    SPList<T> values()
  1809. X            - Returns a list of all the values in the
  1810. X              associative array.
  1811. X
  1812. X    int isin(SPString key)
  1813. X            - Returns 1 if the string 'key' is a valid key
  1814. X              in the associative array. Returns 0 otherwise.
  1815. X
  1816. X    T adelete(SPString key)
  1817. X            - deletes the entry whose key matches the string
  1818. X              'key'. The value of the deleted entry is
  1819. X              returned. Nothing happens if the key is not
  1820. X              found.
  1821. X
  1822. XMiscellaneous
  1823. X=============
  1824. Xclass Range        - stores the range used in Regexp
  1825. X
  1826. X    Range(s, e)        - creates a range whose start is at position
  1827. X              's' and the last character in the range is at
  1828. X              position 'e'. (inclusive range)
  1829. X    
  1830. X    int start()        - returns the start of the range
  1831. X
  1832. X    int end()        - returns the end of the range (the position
  1833. X              of the last character in the range)
  1834. X
  1835. X    int length()    - returns the length of the range
  1836. X
  1837. X    set(s, e)        - sets the start of the range to 's' and the
  1838. X              end of the range to 'e'
  1839. X
  1840. Xclass Slice        - allows the creation of a set of index ranges
  1841. X              for use in SPList to create SubLists.
  1842. X              The order in which elements of an SPList is
  1843. X              accessed is the same as the order that the
  1844. X              indices are added to the Slice.
  1845. X
  1846. X    Slice(const char *s)
  1847. X            - creates a slice specified by 's' where 's' is
  1848. X              a string that specifies a set of indices.
  1849. X              's' can be:-
  1850. X                "a..b" or "a-b" which specifies a
  1851. X                   continuous range from 'a' thru 'b'.
  1852. X                "a,b,c" which specifies individual indices
  1853. X                   'a' 'b' 'c'.
  1854. X                "a..b,c,d" which specifies a range and 2
  1855. X                individual indices.
  1856. X
  1857. X    Slice(int i1, i2, ... , -1)
  1858. X            - creates a slice from a set of indices
  1859. X              specified by 'i1' 'i2' upto a parameter that
  1860. X              is -1. This is a variable number of arguments
  1861. X              terminated by a -1. NOTE that this is not
  1862. X              type safe.
  1863. X
  1864. X    Slice(Range rng)    - creates a slice that is a range specified by
  1865. X              'rng'.
  1866. X     
  1867. X    add(int i)        - allows the dynamic creation of a slice by
  1868. X              adding individual indices to the slice.
  1869. X
  1870. X    compact()        - may be used after add()'ing indices to a
  1871. X              Slice, and before using the Slice to optimise
  1872. X              it. (Optional)
  1873. X
  1874. Xclass Regexp        - Henry Spencers regular expression package
  1875. X              oo-ized
  1876. X
  1877. X    Regexp(exp [,opts])    - Compiles a regular expression that can be
  1878. X              passed to one of the m() functions.
  1879. X              opts: (an int with default 0)
  1880. X                  Regexp::nocase - Forces case insensitive
  1881. X                           match
  1882. X
  1883. X    int match(targ)    - returns 1 if the compield RE matches 'targ'
  1884. X              returns 0 if not
  1885. X    
  1886. X    int groups()    - returns 1 + the number of subexpression
  1887. X              matches found in the last match(). If the
  1888. X              previous match() succeeded then the whole
  1889. X              match is included in the count (hence +1)
  1890. X    
  1891. X    Range getgroup(n)    - returns the range of the 'n'th subgroup.
  1892. X              'n' = 0 is the range of the entire match
  1893. X
  1894. XSPStringList m(exp, targ [,opts])
  1895. X            - returns a list of all the subexpression
  1896. X              matches that occured when applying the
  1897. X              regular expression 'exp' to the string
  1898. X              'targ'. element 0 of the list is the first
  1899. X              subexpression, element 1 the next, etc.
  1900. X              opts: (a const char * with default "")
  1901. X                  i - Forces case insensitive match
  1902. X
  1903. Xxin >> astring        - Text from the stream xin is loaded into
  1904. X              astring, the text is expected to be
  1905. X              terminated by '\n', which is removed from
  1906. X              the stream, but not put into astring.
  1907. X              asring is cleared first.
  1908. X
  1909. Xxin >> astringlist    - Each Text line, as defined above, is loaded
  1910. X              into an element of astringlist, which
  1911. X              is reset first.
  1912. X
  1913. XTo pre-compile a regular expression use Regexp(const char *, iflg).
  1914. Xeg
  1915. XRegexp rexp("...([a-z*)$");
  1916. X//Regexp rexp("...([a-z*)$", Regexp::nocase); // for case insensitive
  1917. XSPString s;
  1918. X
  1919. Xfor(int i=0;i<large_number;i++){
  1920. X    ... load s with string ...
  1921. X    if(s.m(rexp)) ... do something when matched
  1922. X}
  1923. X
  1924. X
  1925. END_OF_FILE
  1926.   if test 12844 -ne `wc -c <'splash.doc'`; then
  1927.     echo shar: \"'splash.doc'\" unpacked with wrong size!
  1928.   fi
  1929.   # end of 'splash.doc'
  1930. fi
  1931. echo shar: End of archive 1 \(of 3\).
  1932. cp /dev/null ark1isdone
  1933. MISSING=""
  1934. for I in 1 2 3 ; do
  1935.     if test ! -f ark${I}isdone ; then
  1936.     MISSING="${MISSING} ${I}"
  1937.     fi
  1938. done
  1939. if test "${MISSING}" = "" ; then
  1940.     echo You have unpacked all 3 archives.
  1941.     rm -f ark[1-9]isdone
  1942. else
  1943.     echo You still must unpack the following archives:
  1944.     echo "        " ${MISSING}
  1945. fi
  1946. exit 0
  1947. exit 0 # Just in case...
  1948.