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

  1. Newsgroups: comp.sources.misc
  2. From: morris@netcom.com (Jim Morris)
  3. Subject: v34i122: splash - Small Perl-like List And String Handling class lib, v1.8, Part02/03
  4. Message-ID: <1993Jan18.214322.29972@sparky.imd.sterling.com>
  5. X-Md4-Signature: 0d2a471b88d3deaf43177fb733d19083
  6. Date: Mon, 18 Jan 1993 21:43:22 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: morris@netcom.com (Jim Morris)
  10. Posting-number: Volume 34, Issue 122
  11. Archive-name: splash/part02
  12. Environment: C++
  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:  regex.h splash.c++ splash.h spltest.c++
  19. # Wrapped by kent@sparky on Mon Jan 18 15:29:05 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 2 (of 3)."'
  23. if test -f 'regex.h' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'regex.h'\"
  25. else
  26.   echo shar: Extracting \"'regex.h'\" \(731 characters\)
  27.   sed "s/^X//" >'regex.h' <<'END_OF_FILE'
  28. X/*
  29. X * Definitions etc. for regexp(3) routines.
  30. X *
  31. X * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
  32. X * not the System V one.
  33. X */
  34. X#define NSUBEXP  10
  35. Xtypedef struct regexp {
  36. X    char *startp[NSUBEXP];
  37. X    char *endp[NSUBEXP];
  38. X    char regstart;        /* Internal use only. */
  39. X    char reganch;        /* Internal use only. */
  40. X    char *regmust;        /* Internal use only. */
  41. X    int regmlen;        /* Internal use only. */
  42. X    char program[1];    /* Unwarranted chumminess with compiler. */
  43. X} regexp;
  44. X
  45. X/*
  46. X * c++ headers added by Jim Morris.
  47. X */
  48. X#ifdef    __cplusplus
  49. Xextern "C"{
  50. Xregexp *regcomp(const char *);
  51. Xint regexec(regexp *, const char *);
  52. X}
  53. X#else
  54. Xextern regexp *regcomp();
  55. Xextern int regexec();
  56. Xextern void regsub();
  57. Xextern void regerror();
  58. X#endif
  59. END_OF_FILE
  60.   if test 731 -ne `wc -c <'regex.h'`; then
  61.     echo shar: \"'regex.h'\" unpacked with wrong size!
  62.   fi
  63.   # end of 'regex.h'
  64. fi
  65. if test -f 'splash.c++' -a "${1}" != "-c" ; then 
  66.   echo shar: Will not clobber existing file \"'splash.c++'\"
  67. else
  68.   echo shar: Extracting \"'splash.c++'\" \(15937 characters\)
  69.   sed "s/^X//" >'splash.c++' <<'END_OF_FILE'
  70. X/*
  71. X * Version 1.8
  72. X * Written by Jim Morris,  jegm@sgi.com
  73. X * Kudos to Larry Wall for inventing SP
  74. X * Copyrights only exist on the regex stuff,  and all
  75. X * have been left intact.
  76. X * The only thing I ask is that you let me know of any nifty fixes or
  77. X * additions.
  78. X * Credits:
  79. X * I'd like to thank Michael Golan <mg@Princeton.EDU> for his critiques
  80. X * and clever suggestions. Some of which have actually been implemented
  81. X */
  82. X#include <iostream.h>
  83. X#include <string.h>
  84. X#include <malloc.h>
  85. X#include <stdio.h>
  86. X
  87. X#ifdef    __TURBOC__
  88. X#pragma hdrstop
  89. X#endif
  90. X
  91. X#include "splash.h"
  92. X
  93. X//************************************************************
  94. X// VarString Implementation
  95. X//************************************************************
  96. X
  97. XVarString& VarString::operator=(const char *s)
  98. X{
  99. X    int nl= strlen(s);
  100. X    if(nl+1 >= allocated) grow((nl-allocated)+allocinc);
  101. X    assert(allocated > nl+1);
  102. X    strcpy(a, s);
  103. X    len= nl;
  104. X    return *this;
  105. X}
  106. X
  107. XVarString& VarString::operator=(const VarString& n)
  108. X{
  109. X    if(this != &n){
  110. X    if(n.len+1 >= allocated){ // if it is not big enough
  111. X#        ifdef    DEBUG
  112. X        fprintf(stderr, "~operator=(VarString&) a= %p\n", a);
  113. X#        endif
  114. X        delete [] a; // get rid of old one
  115. X        allocated= n.allocated;
  116. X        allocinc= n.allocinc;
  117. X        a= new char[allocated];
  118. X#        ifdef    DEBUG
  119. X        fprintf(stderr, "operator=(VarString&) a= %p, source= %p\n", a, n.a);
  120. X#        endif
  121. X    }
  122. X        len= n.len;
  123. X    strcpy(a, n.a);
  124. X    }
  125. X    return *this;
  126. X}
  127. X
  128. Xvoid VarString::grow(int n)
  129. X{
  130. X    if(n == 0) n= allocinc;
  131. X    allocated += n;
  132. X    char *tmp= new char[allocated];
  133. X    strcpy(tmp, a);
  134. X#ifdef    DEBUG
  135. X    fprintf(stderr, "VarString::grow() a= %p, old= %p, allocinc= %d\n", tmp, a, allocinc);
  136. X    fprintf(stderr, "~VarString::grow() a= %p\n", a);
  137. X#endif
  138. X    delete [] a;
  139. X    a= tmp;
  140. X}
  141. X
  142. Xvoid VarString::add(char c)
  143. X{
  144. X    if(len+1 >= allocated) grow();
  145. X    assert(allocated > len+1);
  146. X    a[len++]= c; a[len]= '\0';
  147. X}
  148. X
  149. Xvoid VarString::add(const char *s)
  150. X{
  151. X    int nl= strlen(s);
  152. X    if(len+nl >= allocated) grow(((len+nl)-allocated)+allocinc);
  153. X    assert(allocated > len+nl);
  154. X    strcat(a, s);
  155. X    len+=nl;
  156. X}
  157. X
  158. Xvoid VarString::add(int ip, const char *s)
  159. X{
  160. X    int nl= strlen(s);
  161. X    if(len+nl >= allocated) grow(((len+nl)-allocated)+allocinc);
  162. X    assert(allocated > len+nl);
  163. X    memmove(&a[ip+nl], &a[ip], (len-ip)+1); // shuffle up
  164. X    memcpy(&a[ip], s, nl);
  165. X    len+=nl;
  166. X    assert(a[len] == '\0');
  167. X}
  168. X
  169. Xvoid VarString::remove(int ip, int n)
  170. X{
  171. X    assert(ip+n <= len);
  172. X    memmove(&a[ip], &a[ip+n], len-ip); // shuffle down
  173. X    len-=n;
  174. X    assert(a[len] == '\0');    
  175. X}
  176. X
  177. X//************************************************************
  178. X// SPString stuff
  179. X//************************************************************
  180. X
  181. X// assignments
  182. XSPString& SPString::operator=(const SPString& n)
  183. X{
  184. X    if(this == &n) return *this;
  185. X    pstr= n.pstr;
  186. X    return *this;
  187. X}
  188. X
  189. XSPString& SPString::operator=(const substring& sb)
  190. X{
  191. X    VarString tmp(sb.pt, sb.len);
  192. X    pstr= tmp;
  193. X    return *this;
  194. X}
  195. X
  196. X// concatenations
  197. XSPString SPString::operator+(const SPString& s) const
  198. X{
  199. X    SPString ts(*this);
  200. X    ts.pstr.add(s);    
  201. X    return ts; 
  202. X}
  203. X
  204. XSPString SPString::operator+(const char *s) const
  205. X{
  206. X    SPString ts(*this);
  207. X    ts.pstr.add(s);
  208. X    return ts; 
  209. X}
  210. X
  211. XSPString SPString::operator+(char c) const
  212. X{
  213. X    SPString ts(*this);
  214. X    ts.pstr.add(c);
  215. X    return ts; 
  216. X}
  217. X
  218. XSPString operator+(const char *s1, const SPString& s2)
  219. X{
  220. X    SPString ts(s1);
  221. X    ts = ts + s2;
  222. X//    cout << "s2[0] = " << s2[0] << endl; // gives incorrect error
  223. X    return ts; 
  224. X}
  225. X
  226. X//************************************************************
  227. X// other stuff
  228. X//************************************************************
  229. X
  230. Xchar SPString::chop(void)
  231. X{
  232. X    int n= length();
  233. X    if(n <= 0) return '\0'; // empty
  234. X    char tmp= pstr[n-1];
  235. X    pstr.remove(n-1);
  236. X    return tmp;
  237. X}
  238. X
  239. Xint SPString::index(const SPString& s, int offset)
  240. X{
  241. X    if(offset < 0) offset= 0;
  242. X    for(int i=offset;i<length();i++){
  243. X    if(strncmp(&pstr[i], s, s.length()) == 0) return i;
  244. X    }
  245. X
  246. X    return -1;
  247. X}
  248. X
  249. Xint SPString::rindex(const SPString& s, int offset)
  250. X{
  251. X    if(offset == -1) offset= length()-s.length();
  252. X    else offset= offset-s.length()+1;
  253. X    if(offset > length()-s.length()) offset= length()-s.length();
  254. X      
  255. X    for(int i=offset;i>=0;i--){
  256. X    if(strncmp(&pstr[i], s, s.length()) == 0) return i;
  257. X    }
  258. X    return -1;
  259. X}
  260. X
  261. XSPString::substring SPString::substr(int offset, int len)
  262. X{
  263. X    if(len == -1) len= length() - offset; // default use rest of string
  264. X    if(offset < 0){
  265. X    offset= length() + offset;  // count from end of string
  266. X    if(offset < 0) offset= 0;   // went too far, adjust to start
  267. X    }
  268. X    return substring(*this, offset, len);
  269. X}
  270. X
  271. X// this is private
  272. X// it shrinks or expands string as required
  273. Xvoid SPString::insert(int pos, int len, const char *s, int nlen)
  274. X{
  275. X    if(pos < length()){ // nothing to delete if not true
  276. X    if((len+pos) > length()) len= length() - pos;
  277. X    pstr.remove(pos, len);  // first remove subrange
  278. X    }else pos= length();
  279. X
  280. X    VarString tmp(s, nlen);
  281. X    pstr.add(pos, tmp);        // then insert new substring
  282. X}
  283. X
  284. Xint SPString::m(Regexp& r)
  285. X{
  286. X    return r.match(*this);
  287. X}
  288. X
  289. Xint SPString::m(const char *pat, const char *opts)
  290. X{
  291. Xint iflg= strchr(opts, 'i') != NULL;
  292. X    Regexp r(pat, iflg?Regexp::nocase:0);
  293. X    return m(r);
  294. X}
  295. X
  296. Xint SPString::m(Regexp& r, SPStringList& psl)
  297. X{
  298. X    if(!r.match(*this)) return 0;
  299. X    psl.reset();    // clear it first
  300. X    Range rng;
  301. X    for (int i=0; i<r.groups(); i++){
  302. X        rng= r.getgroup(i);
  303. X    psl.push(substr(rng.start(), rng.length()));
  304. X    }
  305. X    return r.groups();
  306. X}
  307. X
  308. Xint SPString::m(const char *pat, SPStringList& psl, const char *opts)
  309. X{
  310. Xint iflg= strchr(opts, 'i') != NULL;
  311. X    Regexp r(pat, iflg?Regexp::nocase:0);
  312. X    return m(r, psl);
  313. X}
  314. X
  315. X//
  316. X// I know! This is not fast, but it works!!
  317. X//
  318. Xint SPString::tr(const char *sl, const char *rl, const char *opts)
  319. X{
  320. X    if(length() == 0 || strlen(sl) == 0) return 0;
  321. X
  322. X    int cflg= strchr(opts, 'c') != NULL; // thanks Michael
  323. X    int dflg= strchr(opts, 'd') != NULL;
  324. X    int sflg= strchr(opts, 's') != NULL;
  325. X
  326. X    int cnt= 0, flen= 0;
  327. X    SPString t;
  328. X    unsigned char lstc= '\0', fr[256];
  329. X    
  330. X    // build search array, which is a 256 byte array that stores the index+1
  331. X    // in the search string for each character found, == 0 if not in search
  332. X    memset(fr, 0, 256);
  333. X    for(int i=0;i<strlen(sl);i++){
  334. X    if(i && sl[i] == '-'){ // got a range
  335. X        assert(i+1 < strlen(sl) && lstc <= sl[i+1]); // sanity check
  336. X        for(unsigned char c=lstc+1;c<=sl[i+1];c++){
  337. X        fr[c]= ++flen;
  338. X        }
  339. X        i++; lstc= '\0';
  340. X    }else{
  341. X        lstc= sl[i];
  342. X        fr[sl[i]]= ++flen;
  343. X    }
  344. X    }
  345. X
  346. X    int rlen;
  347. X    // build replacement list
  348. X    if((rlen=strlen(rl)) != 0){
  349. X    for(i=0;i<rlen;i++){
  350. X        if(i && rl[i] == '-'){ // got a range
  351. X        assert(i+1 < rlen && t[t.length()-1] <= rl[i+1]); // sanity check
  352. X        for(char c=t[i-1]+1;c<=rl[i+1];c++) t += c;
  353. X        i++;
  354. X        }else t += rl[i];
  355. X    }
  356. X    }
  357. X
  358. X    // replacement string that is shorter uses last character for rest of string
  359. X    // unless the delete option is in effect or it is empty
  360. X    while(!dflg && rlen && flen > t.length()){
  361. X    t += t[t.length()-1]; // duplicate last character
  362. X    }
  363. X
  364. X    rlen= t.length(); // length of translation string   
  365. X   
  366. X    // do translation, and deletion if dflg (actually falls out of length of t)
  367. X    // also squeeze translated characters if sflg
  368. X
  369. X    SPString tmp; // need this in case dflg, and string changes size
  370. X    for(i=0;i<length();i++){
  371. X    int off;
  372. X    if(cflg){ // complement, ie if NOT in f
  373. X        char rc= !dflg ? t[t.length()-1] : '\0'; // always use last character for replacement
  374. X        if((off=fr[(*this)[i]]) == 0){ // not in map
  375. X        cnt++;
  376. X        if(!dflg && (!sflg || tmp.length() == 0 || tmp[tmp.length()-1] != rc))
  377. X            tmp += rc;
  378. X        }else tmp += (*this)[i]; // just stays the same
  379. X    }else{ // in fr so substitute with t, if no equiv in t then delete
  380. X        if((off=fr[(*this)[i]]) > 0){
  381. X        off--; cnt++;
  382. X        if(rlen==0 && !dflg && (!sflg || tmp.length() == 0 || tmp[tmp.length()-1] != (*this)[i])) tmp += (*this)[i]; // stays the same
  383. X        else if(off < rlen && (!sflg || tmp.length() == 0 || tmp[tmp.length()-1] != t[off]))
  384. X            tmp += t[off]; // substitute
  385. X        }else tmp += (*this)[i]; // just stays the same
  386. X    }
  387. X    }
  388. X
  389. X    *this= tmp;
  390. X    return cnt;
  391. X}
  392. X
  393. Xint SPString::s(const char *exp, const char *repl, const char *opts)
  394. X{
  395. Xint gflg= strchr(opts, 'g') != NULL;
  396. Xint iflg= strchr(opts, 'i') != NULL;
  397. Xint cnt= 0;
  398. XRegexp re(exp, iflg?Regexp::nocase:0);
  399. XRange rg;
  400. X
  401. X    if(re.match(*this)){
  402. X    // OK I know, this is a horrible hack, but it seems to work
  403. X    if(gflg){ // recursively call s() until applied to whole string
  404. X        rg= re.getgroup(0);
  405. X        if(rg.end()+1 < length()){
  406. X        SPString st(substr(rg.end()+1));
  407. X//        cout << "Substring: " << st << endl;
  408. X        cnt += st.s(exp, repl, opts);
  409. X        substr(rg.end()+1)= st;
  410. X//        cout << "NewString: " << *this << endl;
  411. X        }
  412. X    }    
  413. X
  414. X    if(!strchr(repl, '$')){ // straight, simple substitution
  415. X        rg= re.getgroup(0);
  416. X        substr(rg.start(), rg.length())= repl;
  417. X        cnt++;    
  418. X    }else{ // need to do subexpression substitution
  419. X        char c;
  420. X        const char *src= repl;
  421. X        SPString dst;
  422. X        int no;
  423. X        while ((c = *src++) != '\0') {
  424. X        if(c == '$' && *src == '&'){
  425. X            no = 0; src++;
  426. X        }else if(c == '$' && '0' <= *src && *src <= '9')
  427. X            no = *src++ - '0';
  428. X        else no = -1;
  429. X
  430. X        if(no < 0){    /* Ordinary character. */
  431. X            if(c == '\\' && (*src == '\\' || *src == '$'))
  432. X            c = *src++;
  433. X            dst += c;
  434. X        }else{
  435. X            rg= re.getgroup(no);
  436. X            dst += substr(rg.start(), rg.length());
  437. X        }
  438. X        }
  439. X        rg= re.getgroup(0);
  440. X        substr(rg.start(), rg.length())= dst;
  441. X        cnt++;
  442. X    }
  443. X
  444. X    return cnt;
  445. X    }
  446. X    return cnt;
  447. X}
  448. X
  449. XSPStringList SPString::split(const char *pat, int limit)
  450. X{
  451. XSPStringList l;
  452. X
  453. X    l.split(*this, pat, limit);
  454. X    return l;
  455. X}
  456. X
  457. X//************************************************************
  458. X// SPStringList stuff
  459. X//************************************************************
  460. X
  461. Xint SPStringList::split(const char *str, const char *pat, int limit)
  462. X{
  463. XRegexp re(pat);
  464. XRange rng;
  465. XSPString s(str);
  466. Xint cnt= 1;
  467. X    
  468. X    if(*pat == '\0'){ // special empty string case splits entire thing
  469. X    while(*str){
  470. X        s= *str++;
  471. X        push(s);
  472. X    }
  473. X    return count();
  474. X    }
  475. X
  476. X    if(strcmp(pat, "' '") == 0){ // special awk case
  477. X    char *p, *ws= " \t\n";
  478. X    TempString t(str); // can't hack users data
  479. X    p= strtok(t, ws);
  480. X    while(p){
  481. X        push(p);
  482. X        p= strtok(NULL, ws);
  483. X    }
  484. X    return count();
  485. X    }
  486. X
  487. X    while(re.match(s) && (limit < 0 || cnt < limit)){ // find separator
  488. X    rng= re.getgroup(0); // full matched string (entire separator)
  489. X    push(s.substr(0, rng.start()));
  490. X    for(int i=1;i<re.groups();i++){
  491. X        push(s.substr(re.getgroup(i))); // add subexpression matches
  492. X    }
  493. X    
  494. X    s= s.substr(rng.end()+1);
  495. X    cnt++;
  496. X    }
  497. X    if(s.length()) push(s);
  498. X
  499. X    if(limit < 0){ // strip trailing null entries
  500. X    int off= count()-1;
  501. X    while(off >= 0 && (*this)[off].length() == 0){
  502. X        off--;
  503. X    }
  504. X    splice(off+1);
  505. X    }
  506. X    return count();
  507. X}
  508. X
  509. XSPString SPStringList::join(const char *pat)
  510. X{
  511. XSPString ts;
  512. X
  513. X    for(int i=0;i<count();i++){
  514. X    ts += (*this)[i];
  515. X    if(i<count()-1) ts += pat;
  516. X    }
  517. X    return ts;
  518. X}
  519. X
  520. X
  521. XSPStringList::SPStringList(const SPStringList& n)
  522. X{
  523. X    for(int i=0;i<n.count();i++){
  524. X    push(n[i]);
  525. X    }
  526. X}
  527. X
  528. XSPStringList& SPStringList::operator=(const SPList<SPString>& n)
  529. X{
  530. X    if(this == &n) return *this;
  531. X    // erase old one
  532. X    reset();
  533. X    
  534. X    for(int i=0;i<n.count();i++){
  535. X    push(n[i]);
  536. X    }
  537. X    return *this;
  538. X}
  539. X
  540. Xint SPStringList::m(const char *rege, const char *targ, const char *opts)
  541. X{
  542. Xint iflg= strchr(opts, 'i') != NULL;
  543. XRegexp r(rege, iflg?Regexp::nocase:0);
  544. X    if(!r.match(targ)) return 0;
  545. X    Range rng;
  546. X    for (int i=0; i<r.groups(); i++){
  547. X        rng= r.getgroup(i);
  548. X    push(SPString(targ).substr(rng.start(), rng.length()));
  549. X    }
  550. X    return r.groups();
  551. X}
  552. X
  553. XSPStringList SPStringList::grep(const char *rege, const char *opts)
  554. X{
  555. XSPStringList rt;
  556. Xint iflg= strchr(opts, 'i') != NULL;
  557. X
  558. X    Regexp rexp(rege, iflg?Regexp::nocase:0);    // compile once
  559. X    for(int i=0;i<count();i++){
  560. X        if(rexp.match((*this)[i])){
  561. X        rt.push((*this)[i]);
  562. X    }
  563. X    }
  564. X    return rt;
  565. X}
  566. X
  567. X//************************************************************
  568. X// streams stuff
  569. X//************************************************************
  570. X
  571. Xistream& operator>>(istream& ifs, SPString& s)
  572. X{
  573. Xchar c;
  574. X#if 0
  575. Xchar buf[40];
  576. X#else
  577. Xchar buf[132];
  578. X#endif
  579. X
  580. X    s= ""; // empty string
  581. X    ifs.get(buf, sizeof buf); 
  582. X    // This is tricky because a line teminated by end of file that is not terminated
  583. X    // with a '\n' first is considered an OK line, but ifs.good() will fail.
  584. X    // This will correctly return the last line if it is terminated by eof with the
  585. X    // stream still in a non-fail condition, but at eof, so next call will fail as
  586. X    // expected
  587. X    if(ifs){         // previous operation was ok
  588. X        s += buf;     // append buffer to string
  589. X//    cout << "<" << buf << ">" << endl;
  590. X    // if its a long line continue appending to string
  591. X    while(ifs.good() && (c=ifs.get()) != '\n'){
  592. X//        cout << "eof1= " << ifs.eof() << endl;
  593. X        ifs.putback(c);
  594. X//          cout << "eof2= " << ifs.eof() << endl;
  595. X        if(ifs.get(buf, sizeof buf)) s += buf; // append to line
  596. X    }
  597. X    }
  598. X    return ifs;    
  599. X}
  600. X
  601. Xistream& operator>>(istream& ifs, SPStringList& sl)
  602. X{
  603. XSPString s;
  604. X
  605. X    // Should I reset sl first?
  606. X    sl.reset(); // I think so, to be consistent
  607. X    
  608. X    while(ifs >> s){
  609. X    sl.push(s);
  610. X//    cout << "<" << s << ">" << endl;
  611. X    };
  612. X    return ifs;    
  613. X}
  614. X
  615. Xostream& operator<<(ostream& os,  const SPString& arr)
  616. X{
  617. X#ifdef TEST
  618. X    os << "(" << arr.length() << ")" << "\"";
  619. X    os << (const char *)arr;
  620. X    os << "\"";
  621. X#else
  622. X    os << (const char *)arr;
  623. X#endif
  624. X    return os;   
  625. X}
  626. X
  627. Xostream& operator<<(ostream& os,  const SPStringList& arr)
  628. X{
  629. X
  630. X    for(int i=0;i<arr.count();i++)
  631. X#ifdef TEST
  632. X    os << "[" << i << "]" << arr[i] << endl;
  633. X#else     
  634. X    os << arr[i] << endl; 
  635. X#endif     
  636. X    return os;   
  637. X}
  638. X
  639. X//************************************************************
  640. X// Slice stuff
  641. X//************************************************************
  642. X
  643. X// a..b is range a thru b
  644. X// a-b is also range a thru b
  645. X// a,b,c is a and b and c
  646. XSlice::Slice(const char *s)
  647. X{
  648. XSPStringList sl;
  649. XSPString sep;
  650. Xint i1, i2;
  651. X
  652. X    rl= new SPList<Range>;
  653. X    sl.split(s, "([-,]|\\.\\.)"); // split on separators and save them
  654. X//    cout << sl << endl;
  655. X    
  656. X    while(sl){
  657. X    i1= atoi(sl.shift()); // +++ should check it is a valid number            
  658. X        if(sl){
  659. X        sep= sl.shift(); // get separator
  660. X            if(sep == "-" || sep == ".."){ // its a range
  661. X        if(sl.isempty()){ // check there is more
  662. X                    cerr << "\nError in Slice, bad range in string: " << s << endl;
  663. X            return;                         
  664. X                }
  665. X        i2= atoi(sl.shift()); // +++ get end of range
  666. X                rl->push(Range(i1, i2)); // +++ Should see if range is reversed, or contiguous
  667. X                if(sl && (sep=sl.shift()) != ","){
  668. X                    cerr << "\nError in Slice, Range not terminated correctly in string: "
  669. X                         << s << " by: " << sep << endl;
  670. X                }
  671. X            }else if(sep == ","){ // its a single
  672. X        add(i1);
  673. X            }else{ // oops
  674. X                cerr << "\nError in Slice, bad separator in string: " << s
  675. X             << "at: " << sep << endl;
  676. X                return;
  677. X            }
  678. X        }else add(i1); // last one must be a single
  679. X    }
  680. X    cout << *this << endl;
  681. X}
  682. X
  683. Xvoid Slice::add(int i)
  684. X{
  685. Xint n= rl->count()-1;
  686. X    // if and only if this index is one greater than the previous on
  687. X    if(n >= 0 && (*rl)[n].end() == i-1){ // extend end of range by 1
  688. X    ((*rl)[n])++;
  689. X    }else rl->push(Range(i, i));
  690. X}
  691. X
  692. X// a list of at least one indices, terminated by -1
  693. XSlice::Slice(int n, ...)
  694. X{
  695. Xva_list ap;
  696. Xint arg;
  697. Xva_start(ap, n);
  698. X
  699. X    rl= new SPList<Range>;
  700. X    add(n);
  701. X    while((arg=va_arg(ap, int)) >= 0){
  702. X    add(arg);
  703. X    }
  704. X    va_end(ap);
  705. X}
  706. X
  707. Xostream& operator<<(ostream& os, const Slice& sl)
  708. X{
  709. X    for(int i=0;i<sl.rl->count();i++){
  710. X        os << (*sl.rl)[i] << endl;
  711. X    }
  712. X    return os;
  713. X}
  714. END_OF_FILE
  715.   if test 15937 -ne `wc -c <'splash.c++'`; then
  716.     echo shar: \"'splash.c++'\" unpacked with wrong size!
  717.   fi
  718.   # end of 'splash.c++'
  719. fi
  720. if test -f 'splash.h' -a "${1}" != "-c" ; then 
  721.   echo shar: Will not clobber existing file \"'splash.h'\"
  722. else
  723.   echo shar: Extracting \"'splash.h'\" \(21764 characters\)
  724.   sed "s/^X//" >'splash.h' <<'END_OF_FILE'
  725. X/*
  726. X * Version 1.8
  727. X * Written by Jim Morris,  jegm@sgi.com
  728. X * Kudos to Larry Wall for inventing Perl
  729. X * Copyrights only exist on the regex stuff, and all have been left intact.
  730. X * The only thing I ask is that you let me know of any nifty fixes or
  731. X * additions.
  732. X * 
  733. X * Credits:
  734. X * I'd like to thank Michael Golan <mg@Princeton.EDU> for his critiques
  735. X * and clever suggestions. Some of which have actually been implemented
  736. X */
  737. X
  738. X#ifndef    _SPLASH_H
  739. X#define    _SPLASH_H
  740. X
  741. X#include <string.h>
  742. X#include "regexp.h"
  743. X
  744. X#if    DEBUG
  745. X#include    <stdio.h>
  746. X#endif
  747. X
  748. X#define    INLINE    inline
  749. X
  750. X//************************************************************
  751. X// This is the base class for SPList, it handles the underlying
  752. X// dynamic array mechanism
  753. X//************************************************************
  754. X
  755. Xtemplate<class T>
  756. Xclass SPListBase
  757. X{
  758. Xprivate:
  759. X    enum{ALLOCINC=20};
  760. X    T *a;
  761. X    int cnt;
  762. X    int first;
  763. X    int allocated;
  764. X    int allocinc;
  765. X    void grow(int amnt= 0, int newcnt= -1);
  766. X
  767. Xprotected:
  768. X    void compact(const int i);
  769. X
  770. Xpublic:
  771. X#ifdef    USLCOMPILER
  772. X    // USL 3.0 bug with enums losing the value
  773. X    SPListBase(int n= 20)
  774. X#else
  775. X    SPListBase(int n= ALLOCINC)
  776. X#endif
  777. X    {
  778. X    a= new T[n];
  779. X    cnt= 0;
  780. X        first= n>>1;
  781. X    allocated= n;
  782. X    allocinc= n;
  783. X#    ifdef    DEBUG
  784. X    fprintf(stderr, "SPListBase(int %d) a= %p\n", allocinc, a);
  785. X#    endif
  786. X    }
  787. X
  788. X    SPListBase(const SPListBase<T>& n);
  789. X    SPListBase<T>& SPListBase<T>::operator=(const SPListBase<T>& n);
  790. X    virtual ~SPListBase(){
  791. X#       ifdef    DEBUG
  792. X    fprintf(stderr, "~SPListBase() a= %p, allocinc= %d\n", a, allocinc);
  793. X#       endif
  794. X    delete [] a;
  795. X    }
  796. X
  797. X    INLINE T& operator[](const int i);
  798. X    INLINE const T& operator[](const int i) const;
  799. X
  800. X    int count(void) const{ return cnt; }
  801. X
  802. X    void add(const T& n);
  803. X    void add(const int i, const T& n);
  804. X    void erase(void){ cnt= 0; first= (allocated>>1);}
  805. X};
  806. X
  807. X// forward declarations
  808. Xclass SPStringList;
  809. Xclass Slice;
  810. Xtemplate <class T> class SPList;
  811. Xtemplate <class T> class SubList;
  812. X
  813. X//************************************************************
  814. X// Slice class to keep track of, and create, slices
  815. X//************************************************************
  816. X
  817. X#include <stdarg.h>
  818. Xclass Slice
  819. X{
  820. Xprivate:
  821. X    SPList<Range> *rl;
  822. X
  823. Xpublic:
  824. X    inline Slice();
  825. X    Slice(const char *); // parse the string to get a slice
  826. X    Slice(int n, ...); // list of indices to add to slice
  827. X    inline Slice(const Slice& slc);
  828. X    inline Slice(const Range& r);
  829. X    inline ~Slice();
  830. X     
  831. X    inline int count(void) const;
  832. X    inline const Range& operator[](int i) const;
  833. X    void add(int i); // add one element to slice
  834. X    friend ostream& operator<<(ostream&, const Slice&);
  835. X};
  836. X
  837. X//************************************************************
  838. X// Allows assignment to slices of a list
  839. X//************************************************************
  840. X
  841. Xtemplate <class T>
  842. Xclass SubList
  843. X{
  844. Xprivate:
  845. X    // This has to be a pointer because we don't know the size of Splice
  846. X    // and there is a nasty cyclic interdependency between the next 3 classes
  847. X    Slice *sl; // because we may want to use a temp in call T/O convenience with efficiency
  848. X    SPList<T>& l;
  849. X
  850. Xpublic:
  851. X    SubList(SPList<T>& lst, const Slice& slc);
  852. X    SubList(SPList<T>& lst, int st, int len);
  853. X    SubList(SPList<T>& lst, const Range& r);
  854. X    ~SubList();
  855. X    SubList<T>& operator=(const SPList<T>& lst);
  856. X    friend SPList<T>;
  857. X};
  858. X
  859. X//************************************************************
  860. X// SPList
  861. X//************************************************************
  862. X
  863. Xtemplate <class T>
  864. Xclass SPList: private SPListBase<T>
  865. X{
  866. Xpublic:
  867. X
  868. X    SPList(int sz= 10): SPListBase<T>(sz){}
  869. X    SPList(const SubList<T>& sbl);
  870. X    
  871. X    // stuff I want public to see from SPListBase
  872. X    T& operator[](const int i){return SPListBase<T>::operator[](i);}
  873. X    const T& operator[](const int i) const{return SPListBase<T>::operator[](i);}
  874. X    SPListBase<T>::count;   // some compilers don't like this
  875. X
  876. X    // add perl-like synonyms
  877. X    void reset(void){ erase(); }
  878. X    int scalar(void) const { return count(); }
  879. X
  880. X    operator void*() { return count()?this:0; } // so it can be used in tests
  881. X    int isempty(void) const{ return !count(); } // for those that don't like the above (hi michael)
  882. X
  883. X    T pop(void)
  884. X    {
  885. X    T tmp;
  886. X    int n= count()-1;
  887. X    if(n >= 0){
  888. X        tmp= (*this)[n];
  889. X        compact(n);
  890. X    }
  891. X    return tmp;
  892. X    }
  893. X
  894. X    void push(const T& a){ add(a);}
  895. X    void push(const SPList<T>& l);
  896. X
  897. X    T shift(void)
  898. X    {
  899. X    T tmp= (*this)[0];
  900. X    compact(0);
  901. X    return tmp;
  902. X    }
  903. X    
  904. X    int unshift(const T& a)
  905. X    {
  906. X    add(0, a);
  907. X    return count();
  908. X    }
  909. X    
  910. X    int unshift(const SPList<T>& l);
  911. X
  912. X    SPList<T> reverse(void);
  913. X    SPList<T> sort();
  914. X    
  915. X    SPList<T> splice(int offset, int len, const SPList<T>& l);
  916. X    SPList<T> splice(int offset, int len);
  917. X    SPList<T> splice(int offset);
  918. X
  919. X    SubList<T> operator()(int st, int len){return SubList<T>(*this, st, len);}
  920. X    SubList<T> operator()(const Range& r){return SubList<T>(*this, r);}
  921. X    SubList<T> operator()(const Slice& slc){return SubList<T>(*this, slc);}
  922. X    SubList<T> operator()(const char *s){return SubList<T>(*this, Slice(s));}
  923. X};
  924. X
  925. X//****************************************************************
  926. X// just a mechanism for self deleteing strings which can be hacked
  927. X//****************************************************************
  928. X
  929. Xclass TempString
  930. X{
  931. Xprivate:
  932. X    char *str;
  933. Xpublic:
  934. X    TempString(const char *s)    
  935. X    {
  936. X        str= new char[strlen(s) + 1];
  937. X        strcpy(str, s);
  938. X    }
  939. X    
  940. X    TempString(const char *s, int len)    
  941. X    {
  942. X        str= new char[len + 1];
  943. X        if(len) strncpy(str, s, len);
  944. X        str[len]= '\0';
  945. X    }
  946. X
  947. X    ~TempString(){ delete [] str; }
  948. X
  949. X    operator char*() const { return str; }
  950. X};
  951. X
  952. X//************************************************************
  953. X// This class takes care of the mechanism behind variable
  954. X// length strings
  955. X//************************************************************
  956. X
  957. Xclass VarString
  958. X{
  959. Xprivate:
  960. X    enum{ALLOCINC=32};
  961. X    char *a;
  962. X    int len;
  963. X    int allocated;
  964. X    int allocinc;
  965. X    INLINE void grow(int n= 0);
  966. X
  967. Xpublic:
  968. X#ifdef    USLCOMPILER
  969. X    // USL 3.0 bug with enums losing the value
  970. X    INLINE VarString(int n= 32);
  971. X#else
  972. X    INLINE VarString(int n= ALLOCINC);
  973. X#endif
  974. X
  975. X    INLINE VarString(const VarString& n);
  976. X    INLINE VarString(const char *);
  977. X    INLINE VarString(const char* s, int n);
  978. X    INLINE VarString(char);
  979. X
  980. X    ~VarString(){
  981. X#       ifdef    DEBUG
  982. X    fprintf(stderr, "~VarString() a= %p, allocinc= %d\n", a, allocinc);
  983. X#       endif
  984. X    delete [] a;
  985. X    }
  986. X
  987. X    VarString& operator=(const VarString& n);
  988. X    VarString& operator=(const char *);
  989. X
  990. X    INLINE const char operator[](const int i) const;
  991. X    INLINE char& operator[](const int i);
  992. X
  993. X    operator const char *() const{ return a; }
  994. X
  995. X    int length(void) const{ return len; }
  996. X
  997. X    void add(char);
  998. X    void add(const char *);
  999. X    void add(int, const char *);
  1000. X    void remove(int, int= 1);
  1001. X
  1002. X    void erase(void){ len= 0; }
  1003. X};
  1004. X
  1005. Xclass SPStringList;
  1006. X
  1007. X//************************************************************
  1008. X// Implements the perl specific string functionality 
  1009. X//************************************************************
  1010. X
  1011. Xclass SPString
  1012. X{
  1013. Xprivate:
  1014. X    VarString pstr;  // variable length string mechanism
  1015. X    
  1016. Xpublic:
  1017. X    class substring;
  1018. X    
  1019. X    SPString():pstr(){}
  1020. X    SPString(const SPString& n) : pstr(n.pstr){}     
  1021. X    SPString(const char *s) : pstr(s){}
  1022. X    SPString(const char c) : pstr(c){}
  1023. X    SPString(const substring& sb) : pstr(sb.pt, sb.len){}
  1024. X    
  1025. X    SPString& operator=(const char *s){pstr= s; return *this;}        
  1026. X    SPString& operator=(const SPString& n); 
  1027. X    SPString& operator=(const substring& sb);
  1028. X
  1029. X    operator const char*() const{return pstr;}
  1030. X    const char operator[](int n) const{ return pstr[n]; }
  1031. X
  1032. X    int length(void) const{ return pstr.length(); }
  1033. X    
  1034. X    char chop(void);
  1035. X    
  1036. X    int index(const SPString& s, int offset= 0);    
  1037. X    int rindex(const SPString& s, int offset= -1);
  1038. X    substring substr(int offset, int len= -1);
  1039. X    substring substr(const Range& r){ return substr(r.start(), r.length());}
  1040. X        
  1041. X    int m(const char *, const char *opts=""); // the regexp match m/.../ equiv
  1042. X    int m(Regexp&);
  1043. X    int m(const char *, SPStringList&, const char *opts="");
  1044. X    int m(Regexp&, SPStringList&);
  1045. X   
  1046. X    int tr(const char *, const char *, const char *opts="");
  1047. X    int s(const char *, const char *, const char *opts="");
  1048. X
  1049. X    SPStringList split(const char *pat= "[ \t\n]+", int limit= -1);
  1050. X    
  1051. X    int operator<(const SPString& s) const { return (strcmp(pstr, s) < 0); }
  1052. X    int operator>(const SPString& s) const { return (strcmp(pstr, s) > 0); }
  1053. X    int operator<=(const SPString& s) const { return (strcmp(pstr, s) <= 0); }
  1054. X    int operator>=(const SPString& s) const { return (strcmp(pstr, s) >= 0); }
  1055. X    int operator==(const SPString& s) const { return (strcmp(pstr, s) == 0); }
  1056. X    int operator!=(const SPString& s) const { return (strcmp(pstr, s) != 0); }
  1057. X
  1058. X    int operator<(const char *s) const { return (strcmp(pstr, s) < 0); }
  1059. X    int operator>(const char *s) const { return (strcmp(pstr, s) > 0); }
  1060. X    int operator<=(const char *s) const { return (strcmp(pstr, s) <= 0); }
  1061. X    int operator>=(const char *s) const { return (strcmp(pstr, s) >= 0); }
  1062. X    int operator==(const char *s) const { return (strcmp(pstr, s) == 0); }
  1063. X    int operator!=(const char *s) const { return (strcmp(pstr, s) != 0); }
  1064. X
  1065. X    friend int operator<(const char *s, const SPString& sp)  { return (strcmp(s, sp.pstr) < 0); }
  1066. X    friend int operator>(const char *s, const SPString& sp)  { return (strcmp(s, sp.pstr) > 0); }
  1067. X    friend int operator<=(const char *s, const SPString& sp)  { return (strcmp(s, sp.pstr) <= 0); }
  1068. X    friend int operator>=(const char *s, const SPString& sp)  { return (strcmp(s, sp.pstr) >= 0); }
  1069. X    friend int operator==(const char *s, const SPString& sp)  { return (strcmp(s, sp.pstr) == 0); }
  1070. X    friend int operator!=(const char *s, const SPString& sp)  { return (strcmp(s, sp.pstr) != 0); }
  1071. X
  1072. X    SPString operator+(const SPString& s) const;
  1073. X    SPString operator+(const char *s) const;
  1074. X    SPString operator+(char c) const;
  1075. X    friend SPString operator+(const char *s1, const SPString& s2);
  1076. X
  1077. X    SPString& operator+=(const SPString& s){pstr.add(s); return *this;}
  1078. X    SPString& operator+=(const char *s){pstr.add(s); return *this;}
  1079. X    SPString& operator+=(char c){pstr.add(c); return *this;}
  1080. X    friend substring;
  1081. X
  1082. Xprivate:
  1083. X    void insert(int pos, int len, const char *pt, int nlen);
  1084. X
  1085. X    // This idea lifted from NIH class library -
  1086. X    // to handle substring LHS assignment
  1087. X    // Note if subclasses can't be used then take external and make
  1088. X    // the constructors private, and specify friend SPString
  1089. X    class substring
  1090. X    {
  1091. X    public:
  1092. X        int pos, len;
  1093. X    SPString& str;
  1094. X    char *pt;
  1095. X    public:
  1096. X        substring(SPString& os, int p, int l) : str(os)
  1097. X    {
  1098. X        if(p > os.length()) p= os.length();
  1099. X        if((p+l) > os.length()) l= os.length() - p;
  1100. X        pos= p; len= l;
  1101. X        if(p == os.length()) pt= 0; // append to end of string
  1102. X        else pt= &os.pstr[p];
  1103. X    }
  1104. X
  1105. X        void operator=(const SPString& s)
  1106. X        {
  1107. X            if(&str == &s){ // potentially overlapping
  1108. X        VarString tmp(s);
  1109. X        str.insert(pos, len, tmp, strlen(tmp));
  1110. X        }else str.insert(pos, len, s, s.length());
  1111. X        }
  1112. X        
  1113. X        void operator=(const substring& s)
  1114. X        {
  1115. X        if(&str == &s.str){ // potentially overlapping
  1116. X        VarString tmp(s.pt, s.len);
  1117. X        str.insert(pos, len, tmp, strlen(tmp));
  1118. X        }else str.insert(pos, len, s.pt, s.len);
  1119. X        }
  1120. X
  1121. X        void operator=(const char *s)
  1122. X        {
  1123. X            str.insert(pos, len, s, strlen(s));
  1124. X        }
  1125. X    };
  1126. X};
  1127. X
  1128. X//************************************************************
  1129. X// SPStringList
  1130. X//************************************************************
  1131. X
  1132. Xclass SPStringList: public SPList<SPString>
  1133. X{
  1134. Xpublic:
  1135. X    SPStringList(int sz= 6):SPList<SPString>(sz){}
  1136. X    // copy lists, need to duplicate all internal strings
  1137. X    SPStringList(const SPStringList& n);
  1138. X
  1139. X    SPStringList& operator=(const SPList<SPString>& n);
  1140. X    int split(const char *str, const char *pat= "[ \t\n]+", int limit= -1);
  1141. X    SPString join(const char *pat= " ");
  1142. X    int m(const char *rege, const char *targ, const char *opts=""); // makes list of sub exp matches
  1143. X    friend SPStringList m(const char *pat, const char *str, const char *opts="")
  1144. X    {
  1145. X    SPStringList l;
  1146. X    l.m(pat, str, opts);
  1147. X        l.shift(); // remove the first element which would be $&
  1148. X        return l;
  1149. X    }
  1150. X    SPStringList grep(const char *rege, const char *opts=""); // trys rege against elements in list
  1151. X};
  1152. X
  1153. X//************************************************************
  1154. X// Streams operators
  1155. X//************************************************************
  1156. X
  1157. Xtemplate <class T>
  1158. Xistream& operator>>(istream& ifs, SPList<T>& arr)
  1159. X{
  1160. XT a;
  1161. X    // Should I reset arr first?
  1162. X    arr.reset(); // I think so, to be consistent
  1163. X    
  1164. X    while(ifs >> a){
  1165. X    arr.push(a);
  1166. X//    cout << "<" << a << ">" << endl;
  1167. X    };
  1168. X    return ifs;    
  1169. X}
  1170. X
  1171. Xtemplate <class T>
  1172. Xostream& operator<<(ostream& os,  const SPList<T>& arr)
  1173. X{
  1174. X
  1175. X    for(int i=0;i<arr.count();i++){
  1176. X#ifdef    TEST
  1177. X    os << "[" << i << "]" << arr[i] << " ";
  1178. X    }
  1179. X    os << endl; 
  1180. X#else
  1181. X    os << arr[i] << endl;
  1182. X    }
  1183. X#endif
  1184. X    return os;   
  1185. X}
  1186. X
  1187. Xistream& operator>>(istream& ifs, SPString& s);
  1188. Xistream& operator>>(istream& ifs, SPStringList& sl);
  1189. Xostream& operator<<(ostream& os,  const SPString& arr);
  1190. Xostream& operator<<(ostream& os,  const SPStringList& arr);
  1191. X
  1192. X//************************************************************
  1193. X// Implementation of template functions for splistbase
  1194. X//************************************************************
  1195. X
  1196. Xtemplate <class T>
  1197. XINLINE T& SPListBase<T>::operator[](const int i)
  1198. X{
  1199. X    assert((i >= 0) && (first >= 0) && ((first+cnt) <= allocated));
  1200. X    int indx= first+i;
  1201. X        
  1202. X    if(indx >= allocated){  // need to grow it
  1203. X    grow((indx-allocated)+allocinc, i+1); // index as yet unused element
  1204. X    indx= first+i;              // first will have changed in grow()
  1205. X    }
  1206. X    assert(indx >= 0 && indx < allocated);
  1207. X
  1208. X    if(i >= cnt) cnt= i+1;  // it grew
  1209. X    return a[indx];
  1210. X}
  1211. X
  1212. Xtemplate <class T>
  1213. XINLINE const T& SPListBase<T>::operator[](const int i) const
  1214. X{
  1215. X     assert((i >= 0) && (i < cnt));
  1216. X     return a[first+i];
  1217. X}
  1218. X
  1219. Xtemplate <class T>
  1220. XSPListBase<T>::SPListBase(const SPListBase<T>& n)
  1221. X{
  1222. X    allocated= n.allocated;
  1223. X    allocinc= n.allocinc;
  1224. X    cnt= n.cnt;
  1225. X    first= n.first;
  1226. X    a= new T[allocated];
  1227. X    for(int i=0;i<cnt;i++) a[first+i]= n.a[first+i];
  1228. X#ifdef    DEBUG
  1229. X    fprintf(stderr, "SPListBase(SPListBase&) a= %p, source= %p\n", a, n.a);
  1230. X#endif
  1231. X
  1232. X}
  1233. X
  1234. Xtemplate <class T>
  1235. XSPListBase<T>& SPListBase<T>::operator=(const SPListBase<T>& n){
  1236. X//  cout << "SPListBase<T>::operator=()" << endl;
  1237. X    if(this == &n) return *this;
  1238. X#ifdef    DEBUG
  1239. X    fprintf(stderr, "~operator=(SPListBase&) a= %p\n", a);
  1240. X#endif
  1241. X    delete [] a; // get rid of old one
  1242. X    allocated= n.allocated;
  1243. X    allocinc= n.allocinc;
  1244. X    cnt= n.cnt;
  1245. X    first= n.first;
  1246. X    a= new T[allocated];
  1247. X    for(int i=0;i<cnt;i++) a[first+i]= n.a[first+i];
  1248. X#ifdef    DEBUG
  1249. X    fprintf(stderr, "operator=(SPListBase&) a= %p, source= %p\n", a, n.a);
  1250. X#endif
  1251. X    return *this;
  1252. X}
  1253. X
  1254. Xtemplate <class T>
  1255. Xvoid SPListBase<T>::grow(int amnt, int newcnt){
  1256. X    if(amnt <= 0) amnt= allocinc; // default value
  1257. X    if(newcnt < 0) newcnt= cnt;   // default
  1258. X    allocated += amnt;
  1259. X    T *tmp= new T[allocated];
  1260. X    int newfirst= (allocated>>1) - (newcnt>>1);
  1261. X    for(int i=0;i<cnt;i++) tmp[newfirst+i]= a[first+i];
  1262. X#ifdef    DEBUG
  1263. X    fprintf(stderr, "SPListBase::grow() a= %p, old= %p, allocinc= %d\n", tmp, a, allocinc);
  1264. X    fprintf(stderr, "~SPListBase::grow() a= %p\n", a);
  1265. X#endif
  1266. X    delete [] a;
  1267. X    a= tmp;
  1268. X    first= newfirst;
  1269. X}
  1270. X
  1271. Xtemplate <class T>
  1272. Xvoid SPListBase<T>::add(const T& n){
  1273. X    if(cnt+first >= allocated) grow();
  1274. X    a[first+cnt]= n;
  1275. X    cnt++;
  1276. X}
  1277. X
  1278. Xtemplate <class T>
  1279. Xvoid SPListBase<T>::add(const int ip, const T& n){
  1280. X    assert(ip >= 0);
  1281. X    if(first == 0 || (first+cnt) >= allocated) grow();
  1282. X    assert((first > 0) && ((first+cnt) < allocated));
  1283. X    if(ip == 0){ // just stick it on the bottom
  1284. X        first--;
  1285. X        a[first]= n;
  1286. X    }else{
  1287. X        for(int i=cnt;i>ip;i--) // shuffle up
  1288. X        a[first+i]= a[(first+i)-1];
  1289. X        a[first+ip]= n;
  1290. X    }
  1291. X    cnt++;
  1292. X}
  1293. X
  1294. Xtemplate <class T>
  1295. Xvoid SPListBase<T>::compact(const int n){ // shuffle down starting at n
  1296. Xint i;
  1297. X    assert((n >= 0) && (n < cnt));
  1298. X    if(n == 0) first++;
  1299. X    else for(i=n;i<cnt-1;i++){
  1300. X        a[first+i]= a[(first+i)+1];
  1301. X    }
  1302. X    cnt--;
  1303. X}
  1304. X
  1305. X//************************************************************
  1306. X// implementation of template functions for SPList
  1307. X//************************************************************
  1308. X
  1309. Xtemplate <class T>
  1310. Xvoid SPList<T>::push(const SPList<T>& l)
  1311. X{
  1312. X    for(int i=0;i<l.count();i++)
  1313. X    add(l[i]);
  1314. X}
  1315. X
  1316. Xtemplate <class T>
  1317. Xint SPList<T>::unshift(const SPList<T>& l)
  1318. X{
  1319. X    for(int i=l.count()-1;i>=0;i--)
  1320. X    unshift(l[i]);
  1321. X    return count();
  1322. X}
  1323. X
  1324. Xtemplate <class T>
  1325. XSPList<T> SPList<T>::reverse(void)
  1326. X{
  1327. X    SPList<T> tmp;
  1328. X    for(int i=count()-1;i>=0;i--)
  1329. X    tmp.add((*this)[i]);
  1330. X    
  1331. X    return tmp;    
  1332. X}
  1333. X
  1334. Xtemplate <class T>
  1335. XSPList<T> SPList<T>::sort(void)
  1336. X{
  1337. XSPList<T> tmp(*this);
  1338. Xint n= tmp.scalar();
  1339. X
  1340. X    for(int i=0;i<n-1;i++)
  1341. X    for(int j=n-1;i<j;j--)
  1342. X        if(tmp[j] < tmp[j-1]){
  1343. X        T temp = tmp[j];
  1344. X        tmp[j] = tmp[j-1];
  1345. X        tmp[j-1]= temp;
  1346. X        }
  1347. X    
  1348. X    return tmp;    
  1349. X}
  1350. X
  1351. Xtemplate <class T>
  1352. XSPList<T> SPList<T>::splice(int offset, int len, const SPList<T>& l)
  1353. X{
  1354. XSPList<T> r= splice(offset, len);
  1355. X
  1356. X    if(offset > count()) offset= count();
  1357. X    for(int i=0;i<l.count();i++){
  1358. X    add(offset+i, l[i]);    // insert into list
  1359. X    }
  1360. X    return r;
  1361. X}
  1362. X
  1363. Xtemplate <class T>
  1364. XSPList<T>  SPList<T>::splice(int offset, int len)
  1365. X{
  1366. XSPList<T> r;
  1367. X
  1368. X    if(offset >= count()) return r;
  1369. X    for(int i=offset;i<offset+len;i++){
  1370. X        r.add((*this)[i]);
  1371. X    }
  1372. X
  1373. X    for(i=offset;i<offset+len;i++)
  1374. X    compact(offset);
  1375. X    return r;
  1376. X}
  1377. X
  1378. Xtemplate <class T>
  1379. XSPList<T>  SPList<T>::splice(int offset)
  1380. X{
  1381. XSPList<T> r;
  1382. X
  1383. X    if(offset >= count()) return r;
  1384. X    for(int i=offset;i<count();i++){
  1385. X    r.add((*this)[i]);
  1386. X    }
  1387. X
  1388. X    int n= count(); // count() will change so remember what it is
  1389. X    for(i=offset;i<n;i++)
  1390. X    compact(offset);
  1391. X    return r;
  1392. X}
  1393. X
  1394. X//************************************************************
  1395. X// VarString Implementation
  1396. X//************************************************************
  1397. X
  1398. XINLINE VarString::VarString(int n)
  1399. X{
  1400. X    a= new char[n];
  1401. X    *a= '\0';
  1402. X    len= 0;
  1403. X    allocated= n;
  1404. X    allocinc= n;
  1405. X#   ifdef    DEBUG
  1406. X    fprintf(stderr, "VarString(int %d) a= %p\n", allocinc, a);
  1407. X#   endif
  1408. X}
  1409. X
  1410. XINLINE VarString::VarString(const char* s)
  1411. X{
  1412. X    int n= strlen(s) + 1;
  1413. X    a= new char[n];
  1414. X    strcpy(a, s);
  1415. X    len= n-1;
  1416. X    allocated= n;
  1417. X    allocinc= ALLOCINC;
  1418. X#   ifdef    DEBUG
  1419. X    fprintf(stderr, "VarString(const char *(%d)) a= %p\n", allocinc, a);
  1420. X#   endif
  1421. X}
  1422. X
  1423. XINLINE VarString::VarString(const char* s, int n)
  1424. X{
  1425. X    a= new char[n+1];
  1426. X    if(n) strncpy(a, s, n);
  1427. X    a[n]= '\0';
  1428. X    len= n;
  1429. X    allocated= n+1;
  1430. X    allocinc= ALLOCINC;
  1431. X#   ifdef    DEBUG
  1432. X    fprintf(stderr, "VarString(const char *, int(%d)) a= %p\n", allocinc, a);
  1433. X#   endif
  1434. X}
  1435. X
  1436. XINLINE VarString::VarString(char c)
  1437. X{
  1438. X    int n= 2;
  1439. X    a= new char[n];
  1440. X    a[0]= c; a[1]= '\0';
  1441. X    len= 1;
  1442. X    allocated= n;
  1443. X    allocinc= ALLOCINC;
  1444. X#   ifdef    DEBUG
  1445. X    fprintf(stderr, "VarString(char (%d)) a= %p\n", allocinc, a);
  1446. X#   endif
  1447. X}
  1448. X
  1449. X
  1450. XINLINE ostream& operator<<(ostream& os,  const VarString& arr)
  1451. X{
  1452. X#ifdef TEST
  1453. X    os << "(" << arr.length() << ")" << (const char *)arr;
  1454. X#else
  1455. X    os << (const char *)arr;
  1456. X#endif
  1457. X    
  1458. X    return os;    
  1459. X}
  1460. X
  1461. XINLINE const char VarString::operator[](const int i) const
  1462. X{
  1463. X     assert((i >= 0) && (i < len) && (a[len] == '\0'));
  1464. X     return a[i];
  1465. X}
  1466. X
  1467. XINLINE char& VarString::operator[](const int i)
  1468. X{
  1469. X     assert((i >= 0) && (i < len) && (a[len] == '\0'));
  1470. X     return a[i];
  1471. X}
  1472. X
  1473. XINLINE VarString::VarString(const VarString& n)
  1474. X{
  1475. X    allocated= n.allocated;
  1476. X    allocinc= n.allocinc;
  1477. X    len= n.len;
  1478. X    a= new char[allocated];
  1479. X    strcpy(a, n.a);
  1480. X#ifdef    DEBUG
  1481. X    fprintf(stderr, "VarString(VarString&) a= %p, source= %p\n", a, n.a);
  1482. X#endif
  1483. X
  1484. X}
  1485. X
  1486. X//************************************************************
  1487. X// Sublist and Slice stuff
  1488. X//************************************************************
  1489. X
  1490. Xtemplate <class T>
  1491. XSubList<T>::SubList(SPList<T>& lst, const Slice& slc) : l(lst)
  1492. X{
  1493. X    sl= new Slice(slc);
  1494. X}
  1495. X
  1496. Xtemplate <class T>
  1497. XSubList<T>::SubList(SPList<T>& lst, int st, int len) : l(lst)
  1498. X{
  1499. X    sl= new Slice(Range(st, st+len-1));
  1500. X}
  1501. X
  1502. Xtemplate <class T>
  1503. XSubList<T>::SubList(SPList<T>& lst, const Range& r) : l(lst)
  1504. X{
  1505. X    sl= new Slice(r);
  1506. X}
  1507. X
  1508. Xtemplate <class T>
  1509. XSubList<T>::~SubList()
  1510. X{
  1511. X    delete sl;
  1512. X}
  1513. X
  1514. Xtemplate <class T>
  1515. XSubList<T>& SubList<T>::operator=(const SPList<T>& lst)
  1516. X{
  1517. Xint n= 0;
  1518. X    for(int i=0;i<sl->count();i++){
  1519. X    for(int j=(*sl)[i].start();j<=(*sl)[i].end();j++){
  1520. X            if(n < lst.count()) l[j]= lst[n++];
  1521. X        }
  1522. X    }        
  1523. X    return *this;
  1524. X}
  1525. X
  1526. Xtemplate <class T>
  1527. XSPList<T>::SPList(const SubList<T>& sbl)
  1528. X{
  1529. X    for(int i=0;i<sbl.sl->count();i++){
  1530. X    for(int j=(*sbl.sl)[i].start();j<=(*sbl.sl)[i].end();j++)
  1531. X        (*this).push(sbl.l[j]);
  1532. X    }
  1533. X}
  1534. X
  1535. X//************************************************************
  1536. X// Slice inline stuff
  1537. X//************************************************************
  1538. X
  1539. Xinline Slice::Slice(const Range& r)
  1540. X{
  1541. X    rl= new SPList<Range>;
  1542. X    rl->push(r);
  1543. X}
  1544. X
  1545. Xinline Slice::Slice()
  1546. X{
  1547. X    rl= new SPList<Range>;
  1548. X}
  1549. X
  1550. Xinline Slice::Slice(const Slice& slc)
  1551. X{
  1552. X    rl= new SPList<Range>(*slc.rl);    
  1553. X}
  1554. X
  1555. X
  1556. Xinline Slice::~Slice()
  1557. X{
  1558. X    delete rl;
  1559. X}
  1560. X     
  1561. Xinline int Slice::count(void) const
  1562. X{
  1563. X    return rl->count();
  1564. X}
  1565. X
  1566. Xinline const Range& Slice::operator[](int i) const
  1567. X{
  1568. X    return (*rl)[i];
  1569. X}
  1570. X
  1571. X
  1572. X// For Old-timers compatibility
  1573. Xtypedef SPStringList PerlStringList;
  1574. Xtypedef SPString PerlString;
  1575. X#define PerlList SPList
  1576. X#endif
  1577. X
  1578. END_OF_FILE
  1579.   if test 21764 -ne `wc -c <'splash.h'`; then
  1580.     echo shar: \"'splash.h'\" unpacked with wrong size!
  1581.   fi
  1582.   # end of 'splash.h'
  1583. fi
  1584. if test -f 'spltest.c++' -a "${1}" != "-c" ; then 
  1585.   echo shar: Will not clobber existing file \"'spltest.c++'\"
  1586. else
  1587.   echo shar: Extracting \"'spltest.c++'\" \(12772 characters\)
  1588.   sed "s/^X//" >'spltest.c++' <<'END_OF_FILE'
  1589. X#ifdef    TEST
  1590. X
  1591. X#include <iostream.h>
  1592. X/*
  1593. X * V1.8
  1594. X */
  1595. X
  1596. X#include <string.h>
  1597. X#include <malloc.h>
  1598. X#include <stdio.h>
  1599. X
  1600. X#ifdef    __TURBOC__
  1601. X#pragma hdrstop
  1602. X#endif
  1603. X
  1604. X#include "splash.h"
  1605. X
  1606. Xint main()
  1607. X{
  1608. XSPList<int> il, il1, il2, il3;
  1609. XSPStringList x, y, z;
  1610. Xint n;
  1611. X
  1612. X    if(x) cout << "x is not empty" << endl;
  1613. X    else cout << "x is empty" << endl;
  1614. X
  1615. X    if(x.isempty()) cout << "x.isempty() is true" << endl;
  1616. X    else cout << "x.isempty() is false" << endl;
  1617. X
  1618. X    n= x.split("a b c d e f");
  1619. X
  1620. X    if(x) cout << "x is not empty" << endl;
  1621. X    else cout << "x is empty" << endl;
  1622. X
  1623. X    if(x.isempty()) cout << "x.isempty() is true" << endl;
  1624. X    else cout << "x.isempty() is false" << endl;
  1625. X
  1626. X    cout << "x.split(a b c d e f)= " << n << ": " << x << endl;
  1627. X    cout << "x[0] = " << x[0] << endl;
  1628. X    z= x; z[0]= "x";
  1629. X    cout << "z= x; z[0]=\"x\" " << "z: " << z << endl;
  1630. X
  1631. X    SPString ss("1.2.3.4.5.6.7.8.9.0");
  1632. X    y= ss.split("\\.");
  1633. X    cout << "ss= " << ss << ", y= ss.split(\"\\.\"), y=" << endl << y << endl;
  1634. X    cout << "y.join(\" \")" << y.join(" ") << endl;       
  1635. X    {
  1636. X    SPString xx= "a b c\nd e\tf   g";
  1637. X        cout << xx << endl << "xx.split()= " << xx.split() << endl;
  1638. X    xx= "a b c d e f g";
  1639. X    cout << xx << endl << "xx.split(\",\")= " << xx.split(",") << endl;
  1640. X    xx= "  a b c d e f g hi  ";
  1641. X    cout << xx << endl << "xx.split(\"\")= " << xx.split("") << endl;
  1642. X    xx= "a,b,c,d,,e,f,g,,,,";
  1643. X    cout << xx << endl << "xx.split(\",\")= " << xx.split(",") << endl;
  1644. X    xx= "a,b,c,d,,e,f,g,,";
  1645. X    cout << xx << endl << "xx.split(\",\", 5)= " << xx.split(",", 5) << endl;
  1646. X    xx= " a b c d e f g  ";
  1647. X    cout << xx << endl << "xx.split(\" \")= " << xx.split(" ") << endl;
  1648. X    xx= "a b c d,e,f g";
  1649. X    cout << xx << endl << "xx.split(\"([ ,])+\")= " << xx.split("([ ,])+") << endl;
  1650. X    xx= ",,,,";
  1651. X    cout << xx << endl << "xx.split(\",\")= " << xx.split(",") << endl;
  1652. X    xx= "";
  1653. X    cout << xx << endl << "xx.split(\",\")= " << xx.split(",") << endl;
  1654. X     xx= "   a b c\td    e\nf  g   ";
  1655. X    cout << xx << endl << "xx.split(\"' '\")= " << xx.split("' '") << endl;
  1656. X   }
  1657. X
  1658. X    cout << "x = " << x << endl;
  1659. X
  1660. X    cout << "x.pop() : " << x.pop() << ", " ;
  1661. X    cout << x.pop() << endl << "x= " << x << endl;;
  1662. X    cout << "x.shift() : " << x.shift() << ", ";
  1663. X    cout << x.shift() << endl<< "x= " << x << endl;
  1664. X    
  1665. X    x.unshift(y);
  1666. X    cout << "x.unshift(y): " << x << endl;
  1667. X    
  1668. X    if(il) cout << "il is not empty" << endl;
  1669. X    else cout << "il is empty" << endl;
  1670. X    
  1671. X    il.push(1); il.push(2); il.push(3); il.push(4);
  1672. X
  1673. X    if(il) cout << "il is not empty" << endl;
  1674. X    else cout << "il is empty" << endl;
  1675. X    
  1676. X    cout << "il(1, 2, 3, 4) : " << il << endl;
  1677. X    il3= il; il3[0]= 9999;
  1678. X    cout << "il3= il; il3[0]= 9999; il3 = " << il3 << endl << "il= " << il << endl;
  1679. X
  1680. X    il1= il.reverse();
  1681. X    cout << "il.reverse: " << il1 << endl;
  1682. X
  1683. X    cout << "il1.sort(): " << il1.sort() << endl;
  1684. X
  1685. X    y.reset();
  1686. X    y.push("one"); y.push("two"); y.push("three"); y.push("four");
  1687. X    cout << "y = " << endl << y;
  1688. X    cout << "y.reverse() " << y.reverse() << endl;
  1689. X    cout << "y.sort() " << y.sort() << endl;
  1690. X    cout << "y.sort().reverse() " << y.sort().reverse() << endl;
  1691. X        
  1692. X    il2.push(3); il2.push(4);
  1693. X    cout << "il2.push(3, 4) : " << il2 << endl;
  1694. X
  1695. X    il.push(il2);    
  1696. X    cout << "il.push(il2) : " << il << endl;
  1697. X    
  1698. X    cout << "il.pop() : " << il.pop() << ", ";
  1699. X    cout << il.pop() << endl;
  1700. X    
  1701. X    il.unshift(il2);    
  1702. X    cout << "il.unshift(il2) : " << il << endl;
  1703. X    
  1704. X    cout << "il.shift() : " << il.shift() << ", ";
  1705. X    cout << il.shift() << endl;
  1706. X
  1707. X    il.reset();
  1708. X    il.push(1); il.push(2);
  1709. X    if(il.shift() != 1) cout << "FIFO1 error" << endl;
  1710. X    if(il.shift() != 2) cout << "FIFO2 error" << endl;
  1711. X
  1712. X    for(int i=0;i<100;i++) il.push(i);
  1713. X    i= 0;
  1714. X    while(il){
  1715. X    if(il.shift() != i)  cout << "FIFO3 error" << endl;
  1716. X    i++;
  1717. X    }
  1718. X    if(i != 100) cout << "FIFO over/under run" << endl;
  1719. X    
  1720. X    cout << "testing splice:" << endl;
  1721. X    x.reset();
  1722. X    x.split("a b c d e f g h i");
  1723. X    cout << "x = " << x << endl;
  1724. X    z= x.splice(2, 3);
  1725. X    cout << "z= x.splice(2, 3): z= " << z << endl << "x = " << x << endl;
  1726. X    cout << "x.splice(2, 0, z): " << x.splice(2, 0, z);
  1727. X    cout << "x= " << x << endl;
  1728. X    cout << "z.splice(1, 1, x): " << z.splice(1, 1, x);
  1729. X    cout << "z= " << z << endl;
  1730. X    cout << "x= " << x << endl;
  1731. X    cout << "z.splice(20, 1, x): " << z.splice(20, 1, x);
  1732. X    cout << "z= " << z << endl;
  1733. X    
  1734. X // test auto expand
  1735. X    SPList<int> ile;
  1736. X    ile[3]= 3;
  1737. X    cout << ile.scalar() << ", " << ile[3] << endl;
  1738. X    ile[100]= 1234;
  1739. X    ile[0]= 5678;
  1740. X    cout << ile.scalar() << ", " << ile[0] << ", " << ile[100] << endl;
  1741. X    SPList<int> ile2;
  1742. X    for(i=0;i<=100;i++) ile2[i]= i;
  1743. X    for(i=200;i>100;i--) ile2[i]= i;
  1744. X    for(i=0;i<=200;i++) if(ile2[i] != i) cout << "error at index " << i << endl;
  1745. X    cout << "Index check done" << endl;
  1746. X    cout << ile2.scalar() << ", " << ile2[0] << ", " << ile2[200] << endl;
  1747. X
  1748. X// test Regexp stuff
  1749. X    cout << endl << "testing regexp stuff:" << endl;
  1750. X    x.reset();
  1751. X    cout << "x.m(\".*X((...)...(...))\", \"12345Xabcxyzdef\") returns " <<
  1752. X     x.m(".*X((...)...(...))", "12345Xabcxyzdef") << endl;
  1753. X    cout << "subs matched = " << x << endl;
  1754. X
  1755. X    Regexp rexp("abc");
  1756. X    SPString rst("12345Xabcxyzdef");
  1757. X    cout << "rst.m(rexp) returns " << rst.m(rexp) << endl;
  1758. X    
  1759. X    cout << endl << "testing grep:" << endl;
  1760. X    x.reset();
  1761. X    x.push("abcd"); x.push("a2345"); x.push("X2345"); x.push("Xaaaaa"); x.push("aaaaa");
  1762. X    
  1763. X    y= x.grep("^a.*");
  1764. X    cout << "x: " << endl << x << endl << "grep(^a.*)" << endl;
  1765. X    cout << "Expect 3 matches:" << endl << y << endl;
  1766. X    {
  1767. X    SPString s1("abcdef");
  1768. X        cout << "s1= " << s1 << ", s1.m(\"^cde\") : " << s1.m("^cde") << endl;
  1769. X    cout << "s1= " << s1 << ", s1.m(\"^..cde\") : " << s1.m("^..cde") << endl;
  1770. X    }
  1771. X    {
  1772. X    SPStringList sl;
  1773. X    SPString str= "ab cd ef";
  1774. X    sl = m("(..) (..)", str);
  1775. X    cout << "sl = m(\"(..) (..)\", \"ab cd ef\"); sl = " << endl <<
  1776. X         sl << endl;
  1777. X    }
  1778. X
  1779. X    {
  1780. X    Regexp ncr("abc", Regexp::nocase);
  1781. X    Regexp cr("abc");
  1782. X    SPString s= "ABC";
  1783. X    cout << "s= " << s << ": s.m(ncr)= " << s.m(ncr) << endl;
  1784. X    cout << "s= " << s << ": s.m(cr)= " << s.m(cr) << endl;
  1785. X    cout << "s.m(\"abc\", \"i\")= " << s.m("abc", "i") << endl;
  1786. X    cout << "s.m(\"abc\")= " << s.m("abc") << endl;
  1787. X    }
  1788. X    
  1789. X// Test strings
  1790. X    cout << "test string stuff:" << endl;
  1791. X
  1792. X    SPString s1("string1"), s2, s3;
  1793. X    const char *s= s1;
  1794. X
  1795. X    cout << "Empty string: " << s2 << " length= " << s2.length()
  1796. X     << ",  strlen(s2) = " << strlen(s2) << endl;
  1797. X    
  1798. X    cout << "s1:" << s1 << endl;
  1799. X    cout << "s[0]= " << s[0] << ", s[5]= " << s[5] << endl;
  1800. X//    s[2]= 'X';
  1801. X//    cout << "s[2]= 'X', s= " << s << endl;
  1802. X//    s[2]= 'r';
  1803. X    
  1804. X    cout << "const char *s= s1: s= " << s << endl;
  1805. X    s2= s1;
  1806. X    cout << "s2=s1,  s2:" << s2 << endl;
  1807. X    s1.chop();
  1808. X    cout << "s1.chop()" << s1 << endl;
  1809. X    s3= s;
  1810. X    cout << "s3= s: s3 = " << s3 << endl;
  1811. X    cout << "index(\"ri\") in " << s1 << ": " << s1.index("ri") << endl;
  1812. X    s3= "1";
  1813. X    cout << "index(" << s3 << ") in " << s1 << ": " << s1.index(s3) << endl;
  1814. X    s3= "abcabcabc";
  1815. X    cout << "rindex(abc) in" << s3 << ": " << s3.rindex("abc") << endl;
  1816. X    cout << "rindex(abc, 5) in" << s3 << ": " << s3.rindex("abc", 5) << endl;
  1817. X
  1818. X// test substrings
  1819. X    cout << "substr(5, 3) in " << s3 << ": " << s3.substr(5, 3) << endl;
  1820. X    s3.substr(5, 3)= "XXX";
  1821. X    cout << "s3.substr(5, 3) = \"XXX\"" << s3 << endl;
  1822. X    s3.substr(5, 3)= s1;
  1823. X    cout << "s3.substr(5, 3) = s1" << s3 << endl;
  1824. X    s3.substr(5, 3)= s1.substr(1, 3);
  1825. X    cout << "s3.substr(5, 3) = s1.substr(1, 3)" << s3 << endl;
  1826. X    s3.substr(0, 6)= s1.substr(0, 3);
  1827. X    cout << "s3.substr(0, 6) = s1.substr(0, 3)" << s3 << endl;
  1828. X    s3.substr(-3, 2)= s1.substr(0, 2);
  1829. X    cout << "s3.substr(-3, 2) = s1.substr(0, 2)" << s3 << endl;
  1830. X
  1831. X// test overlapping substrings
  1832. X    s1= "1234567890";
  1833. X    cout << "s1 = " << s1 << endl;
  1834. X    s1.substr(0, 10)= s1.substr(1, 9);
  1835. X    cout << "s1.substr(0, 10)= s1.substr(1, 9) " << s1 << endl;
  1836. X    s1= "1234567890";
  1837. X    cout << "s1 = " << s1 << endl;
  1838. X    s1.substr(1, 9)= s1.substr(0, 10);
  1839. X    cout << "s1.substr(1, 9)= s1.substr(0, 10) " << s1 << endl;
  1840. X
  1841. X    // test over-large substrings
  1842. X    s1= "1234567890"; s1.substr(7, 10)= "abcdefghij";
  1843. X    cout << "s1.substr(7, 10)= \"abcdefghij\" " << s1 << endl;
  1844. X    s1= "1234567890"; s1.substr(10, 5)= "abcdefghij";
  1845. X    cout << "s1.substr(10, 5)= \"abcdefghij\" " << s1 << endl;
  1846. X    s1= "1234567890"; s1.substr(20, 1)= "abcdefghij";
  1847. X    cout << "s1.substr(20, 1)= \"abcdefghij\" " << s1 << endl;
  1848. X
  1849. X    s1= "abcdef"; s2= "123456";
  1850. X     
  1851. X    cout << s1 << " + " << s2 << ": " << s1 + s2 << endl;
  1852. X    cout << s1 << " + " << "\"hello\"= " << s1 + "hello" << endl;
  1853. X    cout << "\"hello\"" << " + " << s1 << "= " << "hello" + s1 << endl;
  1854. X    cout << s1 << " + \'x\' = " << s1 + 'x' << endl;
  1855. X    
  1856. X    s1= "abc"; s2= "def"; s3= "abc";
  1857. X    cout << s1 << " == " << s2 << ": " << (s1 == s2) << endl; 
  1858. X    cout << s1 << " != " << s2 << ": " << (s1 != s2) << endl;
  1859. X    cout << s1 << " == " << s3 << ": " << (s1 == s3) << endl; 
  1860. X    cout << s1 << " != " << s3 << ": " << (s1 != s3) << endl;
  1861. X    cout << s1 << " < " << s2 << ": " << (s1 < s2) << endl; 
  1862. X    cout << s1 << " > " << s2 << ": " << (s1 > s2) << endl; 
  1863. X    cout << s1 << " <= " << s2 << ": " << (s1 <= s2) << endl; 
  1864. X    cout << s1 << " >= " << s3 << ": " << (s1 >= s3) << endl; 
  1865. X
  1866. X    cout << s1 << " == abc:" << (s1 == "abc") << endl; 
  1867. X    cout << "abc == " << s1 << ("abc" == s1) << endl; 
  1868. X
  1869. X    cout << s1 << " != abc:" << (s1 != "abc") << endl; 
  1870. X    cout << "abc != " << s1 << ("abc" != s1) << endl; 
  1871. X
  1872. X// Test the tr() functions
  1873. X    s1= "abcdefghi";
  1874. X    cout << "s1 = " << s1;
  1875. X    cout << ", s1.tr(\"ceg\", \"123\") = " << s1.tr("ceg", "123");
  1876. X    cout << ", s1 = " << s1 << endl;
  1877. X    s1= "abcdefghi";
  1878. X    cout << "s1.tr(\"a-z\", \"A-Z\") = " << s1.tr("a-z", "A-Z");
  1879. X    cout << ", s1 = " << s1 << endl;
  1880. X    s1= "abcdefghi";
  1881. X    cout << "s1.tr(\"efg\", \"\") = " << s1.tr("efg", "");
  1882. X    cout << ", s1 = " << s1 << endl;
  1883. X    s1= "abcdefghi";
  1884. X    cout << "s1.tr(\"ac-e\", \"X\") = " << s1.tr("ac-e", "X");
  1885. X    cout << ", s1 = " << s1 << endl;
  1886. X    s1= "abcdefghiiii";
  1887. X    cout << "s1 = " << s1;
  1888. X    cout << ", s1.tr(\"ac-e\", \"X\", \"s\") = " << s1.tr("ac-e", "X", "s");
  1889. X    cout << ", s1 = " << s1 << endl;
  1890. X    s1= "abcdefghi";
  1891. X    cout << "s1.tr(\"ac-e\", \"\", \"d\") = " << s1.tr("ac-e", "", "d");
  1892. X    cout << ", s1 = " << s1 << endl;
  1893. X    s1= "abcdefghi";
  1894. X    cout << "s1.tr(\"ac-e\", \"d\", \"d\") = " << s1.tr("ac-e", "d", "d");
  1895. X    cout << ", s1 = " << s1 << endl;
  1896. X    s1= "abcdefghi";
  1897. X    cout << "s1.tr(\"ac-e\", \"\", \"cd\") = " << s1.tr("ac-e", "", "cd");
  1898. X    cout << ", s1 = " << s1 << endl;
  1899. X    s1= "bookkeeper";
  1900. X    cout << s1;
  1901. X    cout << ": s1.tr(\"a-zA-Z\", \"\", \"s\") = " << s1.tr("a-zA-Z", "", "s");
  1902. X    cout << ", s1 = " << s1 << endl;
  1903. X    s1= "abc123def456ghi";
  1904. X    cout << s1;
  1905. X    cout << ": s1.tr(\"a-zA-Z\", \" \", \"c\") = " << s1.tr("a-zA-Z", " ", "c");
  1906. X    cout << ", s1 = " << s1 << endl;
  1907. X    s1= "abc123def456ghi789aaa";
  1908. X    cout << s1;
  1909. X    cout << ": s1.tr(\"a-zA-Z\", \" \", \"cs\") = " << s1.tr("a-zA-Z", " ", "cs");
  1910. X    cout << ", s1 = " << s1 << endl;
  1911. X    s1= "abcdddaaaxxx";
  1912. X    cout << s1;
  1913. X    cout << ": s1.tr(\"a\", \"d\", \"s\") = " << s1.tr("a", "d", "s");
  1914. X    cout << ", s1 = " << s1 << endl;
  1915. X    
  1916. X// Test substitute command
  1917. X    s1= "abcdefghi";
  1918. X    cout << s1;
  1919. X    cout <<" s1.s(\"def\", \"FED\") = " << s1.s("def", "FED");
  1920. X    cout << ", s1= " << s1 << endl;
  1921. X    s1= "abcDEFghi";
  1922. X    cout << s1;
  1923. X    cout <<" s1.s(\"def\", \"FED\") = " << s1.s("def", "FED");
  1924. X    cout << ", s1= " << s1 << endl;
  1925. X    s1= "abcDEFghi";
  1926. X    cout << s1;
  1927. X    cout <<" s1.s(\"def\", \"FED\", \"i\") = " << s1.s("def", "FED", "i");
  1928. X    cout << ", s1= " << s1 << endl;
  1929. X    s1= "abcdefghi";
  1930. X    cout << s1;
  1931. X    cout <<" s1.s(\"(...)(...)\", \"\\$,$&,$2 $1\") = " <<
  1932. X         s1.s("(...)(...)", "\\$,$&,$2 $1");
  1933. X    cout << ", s1= " << s1 << endl;
  1934. X    s1= "abcdefabcghiabc";
  1935. X    cout << s1;
  1936. X    cout <<" s1.s(\"abc\", \"XabcX\", \"g\") = " << s1.s("abc", "XabcX", "g");
  1937. X    cout << ", s1= " << s1 << endl;
  1938. X    s1= "abcdefabcghiabc";
  1939. X    cout << s1;
  1940. X    cout <<" s1.s(\"abc\", \"X\", \"g\") = " << s1.s("abc", "X", "g");
  1941. X    cout << ", s1= " << s1 << endl;
  1942. X    s1= "abcdefabcghiabc";
  1943. X    cout << s1;
  1944. X    cout <<" s1.s(\"abc(.)\", \"X$1abcX$1\", \"g\") = " <<
  1945. X         s1.s("abc(.)", "X$1abcX$1", "g");
  1946. X    cout << ", s1= " << s1 << endl;
  1947. X    s1= "abcdefabcghiabc";
  1948. X    cout << s1;
  1949. X    cout <<" s1.s(\"(.)abc\", \"$1X$1abcX\", \"g\") = " <<
  1950. X         s1.s("(.)abc", "$1X$1abcX", "g");
  1951. X    cout << ", s1= " << s1 << endl;
  1952. X    s1= "1234567890";
  1953. X    cout << s1;
  1954. X    cout <<" s1.s(\"(.)(.)\", \"$2$1\", \"g\") = " <<
  1955. X         s1.s("(.)(.)", "$2$1", "g");
  1956. X    cout << ", s1= " << s1 << endl;
  1957. X
  1958. X}
  1959. X#endif
  1960. END_OF_FILE
  1961.   if test 12772 -ne `wc -c <'spltest.c++'`; then
  1962.     echo shar: \"'spltest.c++'\" unpacked with wrong size!
  1963.   fi
  1964.   # end of 'spltest.c++'
  1965. fi
  1966. echo shar: End of archive 2 \(of 3\).
  1967. cp /dev/null ark2isdone
  1968. MISSING=""
  1969. for I in 1 2 3 ; do
  1970.     if test ! -f ark${I}isdone ; then
  1971.     MISSING="${MISSING} ${I}"
  1972.     fi
  1973. done
  1974. if test "${MISSING}" = "" ; then
  1975.     echo You have unpacked all 3 archives.
  1976.     rm -f ark[1-9]isdone
  1977. else
  1978.     echo You still must unpack the following archives:
  1979.     echo "        " ${MISSING}
  1980. fi
  1981. exit 0
  1982. exit 0 # Just in case...
  1983.