home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-01-18 | 36.2 KB | 1,346 lines |
- Newsgroups: comp.sources.misc
- From: morris@netcom.com (Jim Morris)
- Subject: v34i123: splash - Small Perl-like List And String Handling class lib, v1.8, Part03/03
- Message-ID: <1993Jan18.214349.164@sparky.imd.sterling.com>
- X-Md4-Signature: 9f37b009e02a527e22270bc4faf8732e
- Date: Mon, 18 Jan 1993 21:43:49 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: morris@netcom.com (Jim Morris)
- Posting-number: Volume 34, Issue 123
- Archive-name: splash/part03
- Environment: C++
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # Contents: Changelog Makefile.std Todo assoc.h readme.2nd regexp.doc
- # regexp.h regmagic.h slicetst.c++ splash.v
- # Wrapped by kent@sparky on Mon Jan 18 15:29:06 1993
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 3 (of 3)."'
- if test -f 'Changelog' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Changelog'\"
- else
- echo shar: Extracting \"'Changelog'\" \(3452 characters\)
- sed "s/^X//" >'Changelog' <<'END_OF_FILE'
- XCHANGELOG
- X---------
- Xv1.1 - Added PerlString::tr()
- X - Added PerlString::operator+=(char)
- X - Added PerlString(const char) constructor
- X
- Xv1.2 - Fixed a test case in PerlClass
- X - Increased initial allocation of PerlString to 32 characters
- X - Optimized PerlStringList::grep() by only compiling regexp once
- X - Added PerlString::m(const Regexp&...) so that pre-compiled regular
- X expressions can be used
- X - changed "fprintf(stderr..." to "cerr << ..." in regexp.h
- X - Added c, d & s options to the PerlString::tr() function
- X - fixed some bugs in tr() range processing
- X
- Xv1.3 - Cleaned up MArray constructor - Thanks Michael
- X - Cleaned up tr() some more. Fixed d and s and c option.
- X - Added PerlStringList PerlString::split()
- X - Added operator>>() for PerlString
- X - Added operator>>() for PerlStringList
- X - Fixed operator<<() for PerlStringList
- X - Added operator>>() for PerlList
- X - Fixed operator<<() for PerlList
- X
- Xv1.4 - Implemented PerlList::sort()
- X - Implemented PerlString:s(), the substitute command
- X - Added subexpression replacement in PerlString:s()
- X - split out the test code from perlclass.c++ into perltest.c++
- X - fixed bug in substr() for default length
- X - Added the 'g' option for PerlString:s()
- X - Changed the way that PerlString::m(s, l) works, now the list
- X 'l' is reset first.
- X - Added PerlList<T>:operator void*() so a list can be used in
- X a conditional, and returns 0 if the list is empty
- X - Added PerlStringList m(pat, str) to match perl syntax
- X - Added case insensitive matching to Regexp class
- X - Added 'i' option to PerlStringList::grep
- X - Added 'i' option to the m() functions
- X - Added 'i' option to PerlString::s() function
- X - Added a generic Makefile - Hooray
- X
- Xv1.5 - Added PerlList<T>::isempty()
- X - Added PerlListBase instead of MArray, which uses the empty
- X space technique at front and back as suggested by MG.
- X - Changed PerlListBase::operator[]() to allow indexing non-existing
- X elements, and implemented auto grow.
- X - Fixed splice() to append to end of list if offset is > number
- X of items in list, this matches perls behaviour
- X - Fixed potential overrunning end of string in substring class
- X - added a const version of Binar::key() and value()
- X - Replaced MArray with VarString class for improved string
- X handling - ie faster
- X
- Xv1.6 - Changed VarString::operator=() to not delete and new if
- X enough is already allocated. (as per MG)
- X - Fixed a grow() bug in VarString::add(char)
- X - Sped up tr() by replacing lookup with indexed array for search
- X - Fixed split() so it splits on whitespace by default
- X - Added a PerlString::substring(Range) for convenience
- X - Fixed split() to use regular expression for pattern, as per
- X Perl (including subexpressions)
- X - Fixed pop() to not give an assertion error when list is empty
- X but to return an undefined element instead
- X - Added special awk case to split("' '")
- X - Added special case for empty string in split("")
- X
- Xv1.7 - Changed Names from Perl... to SP... for release to alt.sources
- X - Added typdefs so old names would still work
- X - renamed all files from perlclass.* to splash.*
- X - Put a check in SPString::index() for offset < 0
- X
- Xv1.8 - added comparison operators to SPString to allow permutations
- X of comparisons with char *'s.
- X - added Slice and SubList to handle SPList slices
- X - Added intersection and union of Ranges and test for validity
- X - Added operator++ for extendng end of range by one
- X - Stored length of Range rather than calculate it every time
- X
- X
- END_OF_FILE
- if test 3452 -ne `wc -c <'Changelog'`; then
- echo shar: \"'Changelog'\" unpacked with wrong size!
- fi
- # end of 'Changelog'
- fi
- if test -f 'Makefile.std' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile.std'\"
- else
- echo shar: Extracting \"'Makefile.std'\" \(690 characters\)
- sed "s/^X//" >'Makefile.std' <<'END_OF_FILE'
- X#
- X#
- X# Generic Makefile for splash and tests
- X#
- X#
- X
- XCC = cc
- XCFLAGS = -g
- XLFLAGS =
- X
- X# uncomment the next file if your USL cfront breaks enums
- X#DEFS = -DUSLCOMPILER
- X
- Xspltest: spltest.o tsplash.o regex.o
- X $(CC) $(CFLAGS) $(LFLAGS) -DTEST -o spltest spltest.c++ tsplash.o regex.o
- X
- Xtsplash.o: splash.c++
- X $(CC) $(CFLAGS) $(DEFS) -DTEST -c splash.c++
- X mv splash.o tsplash.o
- X
- Xtsplash.o splash.o: splash.h regexp.h
- Xregex.o: regex.h
- X
- Xassoc: assoc.c++ splash.o regex.o
- X $(CC) $(CFLAGS) $(LFLAGS) $(DEFS) -DTESTASSOC assoc.c++ splash.o regex.o -o assoc
- X
- Xtest:
- X spltest > x
- X diff x splash.v
- X
- Xchgfnt: chgfnt.o splash.o regex.o
- X $(CC) $(CFLAGS) $(DEFS) -DTESTCHGFNT chgfnt.c++ splash.o regex.o -o chgfnt
- X
- END_OF_FILE
- if test 690 -ne `wc -c <'Makefile.std'`; then
- echo shar: \"'Makefile.std'\" unpacked with wrong size!
- fi
- # end of 'Makefile.std'
- fi
- if test -f 'Todo' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Todo'\"
- else
- echo shar: Extracting \"'Todo'\" \(265 characters\)
- sed "s/^X//" >'Todo' <<'END_OF_FILE'
- XThese are things I am likely to do in the near future.
- X======================================================
- X
- XImplement the g option for m() functions generating lists
- X
- XImplement some form of iterator along the lines of Perls foreach
- X
- XOptimise, Optimise, Optimise
- END_OF_FILE
- if test 265 -ne `wc -c <'Todo'`; then
- echo shar: \"'Todo'\" unpacked with wrong size!
- fi
- # end of 'Todo'
- fi
- if test -f 'assoc.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'assoc.h'\"
- else
- echo shar: Extracting \"'assoc.h'\" \(2827 characters\)
- sed "s/^X//" >'assoc.h' <<'END_OF_FILE'
- X/*
- X * Version 1.6
- X * Feeble attempt to duplicate perl associative arrays
- X * So feeble I won't even call it PerlAssoc!
- X * Anyway the key can only be a string, the value can be anything.
- X * Written by Jim Morris, jegm@sgi.com
- X */
- X#ifndef _SPASSOC_H
- X#define _SPASSOC_H
- X
- X#include <iostream.h>
- X#include "splash.h"
- X
- Xtemplate<class T>
- Xclass Binar
- X{
- Xprivate:
- X SPString k;
- X T v;
- X
- Xpublic:
- X Binar(SPString a, T b) : k(a), v(b){}
- X Binar(SPString a) : k(a){}
- X Binar(){}
- X
- X Binar<T>& operator=(const Binar<T>& n){ k= n.k; v= n.v; return *this; }
- X SPString& key(void){ return k; }
- X const SPString& key(void) const { return k; }
- X T& value(void){ return v; }
- X const T& value(void) const { return v; }
- X int operator==(const Binar<T>& b) const{return ((k == b.k) && (v == b.v));}
- X int operator<(const Binar& b) const {return v < b.v;} // to keep sort quiet
- X};
- X
- Xtemplate<class T>
- Xclass Assoc
- X{
- Xprivate:
- X SPList<Binar<T> > dat;
- X Binar<T> def;
- X
- Xpublic:
- X Assoc():def(""){}
- X Assoc(SPString dk, T dv) : def(dk, dv){}
- X
- X int scalar(void) const { return dat.scalar(); }
- X
- X SPStringList keys(void);
- X SPList<T> values(void);
- X
- X int isin(const SPString& k) const;
- X T adelete(const SPString& k);
- X
- X T& operator()(const SPString& k);
- X Binar<T>& operator[](int i){ return dat[i]; }
- X};
- X
- Xtemplate<class T>
- XSPStringList Assoc<T>::keys(void)
- X{
- X SPStringList r;
- X for(int i=0;i<dat.scalar();i++)
- X r.push(dat[i].key());
- X return r;
- X}
- X
- Xtemplate<class T>
- XSPList<T> Assoc<T>::values(void)
- X{
- X SPList<T> r;
- X for(int i=0;i<dat.scalar();i++)
- X r.push(dat[i].value());
- X return r;
- X}
- X
- Xtemplate<class T>
- XT& Assoc<T>::operator()(const SPString& k)
- X{
- X for(int i=0;i<dat.scalar();i++){
- X if(k == dat[i].key()) return dat[i].value();
- X }
- X
- X dat.push(Binar<T>(k, def.value()));
- X return dat[i].value();
- X}
- X
- Xtemplate<class T>
- XT Assoc<T>::adelete(const SPString& k)
- X{
- X for(int i=0;i<dat.scalar();i++){
- X if(k == dat[i].key()){
- X T r= dat[i].value();
- X dat.splice(i, 1);
- X return r;
- X }
- X }
- X
- X return def.value();
- X}
- X
- Xtemplate<class T>
- Xint Assoc<T>::isin(const SPString& k) const
- X{
- X for(int i=0;i<dat.scalar();i++){
- X if(k == dat[i].key()) return i+1;
- X }
- X return 0;
- X}
- X
- Xtemplate<class T>
- Xostream& operator<<(ostream& os, Binar<T>& a)
- X{
- X os << "(" << a.key() << ", " << a.value() << ")";
- X return os;
- X}
- X
- Xtemplate<class T>
- Xostream& operator<<(ostream& os, Assoc<T>& a)
- X{
- X for(int i=0;i<a.scalar();i++){
- X#ifdef TEST
- X os << "[" << i << "] " << a[i] << endl;
- X#else
- X os << a[i] << endl;
- X#endif
- X }
- X return os;
- X}
- X
- X#if 0
- Xtemplate<class T>
- Xistream& operator>>(istream& s, Binar<T>& a)
- X{
- Xchar c= 0;
- X
- X s >> c;
- X if(c == '('){
- X s >> a.key()
- X }
- X os << "(" << a.key() << ", " << a.value() << ")";
- X return os;
- X}
- X#endif
- X#endif
- END_OF_FILE
- if test 2827 -ne `wc -c <'assoc.h'`; then
- echo shar: \"'assoc.h'\" unpacked with wrong size!
- fi
- # end of 'assoc.h'
- fi
- if test -f 'readme.2nd' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'readme.2nd'\"
- else
- echo shar: Extracting \"'readme.2nd'\" \(7332 characters\)
- sed "s/^X//" >'readme.2nd' <<'END_OF_FILE'
- XFor support Email to morris@netcom.com or jegm@sgi.com
- X
- XI would welcome bug reports for a while!
- XAlso comments are always welcome.
- X
- XThe latest version of SPLASH is always available via anonymous
- XFTP from netcom.com in ~ftp/pub/morris/splash.tar.Z (for Unix)
- Xand ~ftp/pub/morris/splash.zoo (for MSDOS)
- X
- XIntroducing SPLASH
- X==================
- X
- XSPLASH is a c++ class library that implements my favourite perl
- Xconstructs. Obviously I can't duplicate all the functionality of perl,
- Xand wouldn't need to as perl already exists!! However I find this
- Xuseful, because it allows me to do Perl-like things in my programs.
- X
- XThis Code is not copyright, use as you will. The regexp code is by
- XHenry Spencer, see the comments for Copyright info. The only changes I
- Xhave made are to the header file, by adding a c++ prototype field.
- X
- XThe Class Hierarchy and member functions are are fully described in
- Xthe file splash.doc
- X
- XBuilding NOTES
- X==============
- XThis must be compiled with a 3.0 or greater c++ compiler that can
- Xhandle Templates and nested classes.
- X
- XIt has been tested on Borland c++ v3.1 and USL-based 3.0. GCC v2.2.2
- Xdoesn't like the Copy constructor syntax in template classes, and gives
- Xan assert error as well.
- X
- XTo build:
- X
- Xcompile splash.c++ and regex.c. Link in with your App.
- XInclude splash.h, (and assoc.h if used).
- X
- X> cc -c regex.c
- X> CC -c splash.c++
- X> CC yourapp.c++ splash.o regex.o -o yourapp
- X
- XTo test:
- X
- X> CC -DTEST spltest.c++ splash.c++ regex.o -o spltest
- X> spltest > x
- X> diff x splash.v
- X
- Xand
- X
- X> CC -DTEST slicetst.c++ splash.o regex.o -o slicetst
- X> slicetst > x
- X> diff x slicetst.v
- X
- XThis will do a full regression test. splash.v & slicetst.v contains the
- Xsample output of a correct run, so no differences should be
- Xencountered.
- X
- Xregex.c is not an ANSI c file, so you will have to turn off prototype
- Xchecking on your ANSI c compiler (or select kr checking).
- X
- XSome of the samples use a file called tracer.h, this is a fairly useful
- XDebugging helper grabbed from the net and slightly modified. I include
- Xtracer.h and tracer.c++ for completeness, however they are not required.
- X
- XCAVEATS (known ones that is)
- X=======
- XThis is not an optimised implementation, by any stretch of the
- Ximagination. It is a quick and dirty, "but it works" one.
- X
- XNo "out of memory checking" is done, I thought I'd wait for
- Xexceptions!!
- X
- XI have taken a few liberties in translating the selected perl
- Xfunctionality into a class library, apologies to Larry Wall, and
- Xanyone else this may offend. You are welcome to fix it, just tell me
- Xhow you did it.
- X
- XA SPList<T> can only contain a list of type T, it cannot, as yet,
- Xhave multiple types in the same list. (This is feasible but messy).
- X
- XAssigning to an element of a SPList that is greater than the current
- Xlength of the SPList will expand the list as in perl, but the values
- Xin the newly created elements will be undefined, unlike perl. Except
- XSPStringList which will create empty strings. Also if <T> is a class
- Xthen the values will be whatever the default constructor creates.
- X
- XAnything that you make a SPList out of must define an operator<(),
- Xfor the sort routine. Its ok if it is a dummy.
- X
- XThe first index of a list is always 0. (Again this could be fixed).
- X
- XUnlike perl you can also access characters within
- Xa SPString using the '[]' syntax. But you must use substr() to
- Xchange them.
- X
- XNote that SPStrings cannot have embedded '\0' like perl, this
- Xis an efficiency trade off, because '\0' as a terminator is so
- Xingrained in c++ and c strings. (This could be fixed by carefully
- Xreplacing all str... functions with mem... functions
- X
- XRegular Expressions
- X-------------------
- X
- XRegular expressions may be slightly different, I used the straight
- XHenry Spencer version. I'm not sure what changes Larry made to them.
- X(It definitely doesn't support \w \b \s \S \d \D, or global match
- Xmode). - If someone can make Larry's regexp stuff into a stand-alone
- Xpackage like the original regex stuff, then I'll use it!
- X
- XThe g & o options are not supported in the m() functions.
- XI will try to support the 'g' option for m() in a list context.
- X
- XSPStringList::m(exp, targ) and SPString::m(exp, list) are used to
- Xsimulate $&, $0 - $9 in perl. In both cases the list gets loaded with
- Xthe subexpression matches. The 0'th element is equivalent to $& in perl
- Xand the 1'st element is equivalent to $1 etc.
- X
- XNote that in the SPStringlist::m() member function, result lists are
- Xappended whereas in SPString::m(s, list) 'list' is reset first.
- Xeg
- X{
- XSPString s;
- XSPStringList l1, l2;
- X
- X s= "hello frobo goodbye";
- X l1.push("was here first1"); l2.push("was here first2");
- X s.m("(.*)frobo(.*)", l2); // Overwrites l with new list
- X l1.m("(.*)frobo(.*)", s); // appends l with new list
- X// produces this result:
- X// l2[0] is "hello frobo goodbye" // equiv of $&
- X// l2[1] is "hello " // equiv of $1
- X// l2[2] is " goodbye" // $2
- X// and
- X// l1[0] is "was here first"
- X// l1[1] is "hello frobo goodbye" // equiv of $&
- X// l1[2] is "hello " // $1
- X// l1[3] is " goodbye" // $2
- X// an l1.reset() preceding the l1.m() would get rid of l1[0] in the
- X// above example.
- X}
- X
- XTo get the exact perl semantics of the m function in a list context
- Xyou can use the global m() function as follows:-
- X{
- XSPStringList sl;
- Xsl = m("(..) (..)", "ab cd ef"); // sl[0] gets "ab", sl[1] gets "cd"
- X}
- X
- XSP expressions (s/123/$&*2/e) in a substitute command
- X(SPString::s()) are obviously not done. However $& and $0-$9 are
- Xcorrectly expanded and substituted.
- X
- XAlso remember that if you want to put a \ in the regular expression
- Xthen you must actually type \\ as the c compiler will interpret a \ for
- Xyou. What happens to things like \t is up to your compiler.
- X
- X
- XI/O
- X---
- XI/O is done using standard c++ streams. I think this is ok, although
- Xsome perl-ism maybe introduced one day.
- Xeg to copy a text file a line at a time:-
- X{
- Xifstream fin("file1.txt");
- Xofstream fout("file2.txt");
- XSPString si;
- X
- X while(fin >> si) fout << si << endl;
- X}
- X
- XThis will read the entire file into a SPStringList:-
- X{
- XSPStringList l;
- Xifstream fin("file1.txt");
- X
- X fin >> l;
- X}
- X
- XOne nifty outcome of using streams this way is the following syntax
- Xwill load a SPStringList and SPList<T> in a reasonably compact
- Xway:-
- X{
- XSPStringList slist;
- Xstrstream ss;
- X ss << "one\n" << "two\nthree\nfour\n";
- X ss >> slist; // creates a 4 element string list
- X
- Xstrstream iss;
- XSPList<int> il;
- X
- X iss << "1 2 3 4 5 6 7 8 9 10" << endl; // quick load an integer array
- X iss >> il; // creates a 10 element integer list
- X}
- X
- X
- XIterators
- X---------
- XThere is no iterator per-se, but all lists (including Assoc) allow
- Xan index to step through the list one by one. So iteration can be
- Xachieved, albeit clumsily.
- Xeg
- X
- XSPList<int> intlist;
- X
- Xfor(int i=0;i<inlist.scalar();i++){
- X cout << intlist[i];
- X}
- X
- Xforeach could be simulated with the following macro:-
- X
- X#define FOREACH(var, array)\
- X for(int i=0;i<array.scalar() && (var=array[i], 1);i++)
- X
- Xeg
- X{
- X
- X SPList<int> fred;
- X int val, tot= 0;
- X
- X { // this is useful to avoid the 'i' in the macro colliding
- X FOREACH(val, fred){
- X tot += val;
- X }
- X }
- X}
- X
- XA SPList or SPStringList may be used in an if statement to test
- Xif the list is empty or not.
- Xeg
- X{
- XSPList<int> il;
- X
- X if(il) cout << "List is not empty" << endl;
- X else il.push(1);
- X}
- X
- X==========
- XDisclaimer
- X==========
- X
- XThis is a personal work, and SGI is not responsible for anything
- Xcontained herein.
- END_OF_FILE
- if test 7332 -ne `wc -c <'readme.2nd'`; then
- echo shar: \"'readme.2nd'\" unpacked with wrong size!
- fi
- # end of 'readme.2nd'
- fi
- if test -f 'regexp.doc' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'regexp.doc'\"
- else
- echo shar: Extracting \"'regexp.doc'\" \(3706 characters\)
- sed "s/^X//" >'regexp.doc' <<'END_OF_FILE'
- XREGULAR EXPRESSION SYNTAX
- X=========================
- XA regular expression is zero or more branches, separated by |. It matches
- Xanything that matches one of the branches. A branch is zero or more pieces,
- Xconcatenated. It matches a match for the first, followed by a match for the
- Xsecond, etc.
- X
- XA piece is an atom possibly followed by *, +, or ?.
- XAn atom followed by * matches a sequence of 0 or more matches of the atom.
- XAn atom followed by + matches a sequence of 1 or more matches of the atom.
- XAn atom followed by ? matches a match of the atom, or the null string.
- X
- XAn atom is a regular expression in parentheses (matching a match for the
- Xregular expression), a range (see below),
- X. (matching any single character),
- X^ (matching the null string at the beginning of the input string),
- X$ (matching the null string at the end of the input string),
- Xa \ followed by a single character (matching that character),
- Xor a single character with no other significance (matching that character).
- X
- XA range is a sequence of characters enclosed in []. It normally matches any
- Xsingle character from the sequence. If the sequence begins with ^, it matches
- Xany single character not from the rest of the sequence. If two characters in
- Xthe sequence are separated by -, this is shorthand for the full list of ASCII
- Xcharacters between them (e.g. [0-9] matches any decimal digit). To include a
- Xliteral ] in the sequence, make it the first character (following a possible
- X^). To include a literal -, make it the first or last character. AMBIGUITY If
- Xa regular expression could match two different parts of the input string, it
- Xwill match the one which begins earliest. If both begin in the same place but
- Xmatch different lengths, or match the same length in different ways, life gets
- Xmessier, as follows.
- X
- XIn general, the possibilities in a list of branches are considered in
- Xleft-to-right order, the possibilities for *, +, and ? are considered
- Xlongest-first, nested constructs are considered from the outermost in, and
- Xconcatenated constructs are considered leftmost-first. The match that will be
- Xchosen is the one that uses the earliest possibility in the first choice that
- Xhas to be made. If there is more than one choice, the next will be made in the
- Xsame manner (earliest possibility) subject to the decision on the first
- Xchoice. And so forth.
- X
- XFor example, '(ab|a)b*c' could match 'abc' in one of two ways. The first
- Xchoice is between 'ab' and 'a'; since 'ab' is earlier, and does lead to a
- Xsuccessful overall match, it is chosen. Since the 'b' is already spoken for,
- Xthe 'b*' must match its last possibility, the empty string, since it must
- Xrespect the earlier choice.
- X
- XIn the particular case where no |'s are present and there is only one *, +, or
- X?, the net effect is that the longest possible match will be chosen. So 'ab*',
- Xpresented with 'xabbbby', will match 'abbbb'. Note that if 'ab*' is tried
- Xagainst 'xabyabbbz', it will match 'ab' just after 'x', due to the
- Xbegins-earliest rule. (In effect, the decision on where to start the match is
- Xthe first choice to be made, hence subsequent choices must respect it even if
- Xthis leads them to less-preferred alternatives.
- X
- XREGULAR EXPRESSION SUBSTITUTION
- X===============================
- XSubstitutions are made according to the most recent RE search. Each instance
- Xof '$&' in the paste buffer is replaced by the string that matched the whole
- Xregular expression. Each instance of '$n', where n is a digit between 1 and 9,
- Xis replaced by the substrings that matched parenthesized expressions within
- Xthe regular expression, with parenthesized expressions numbered in
- Xleft-to-right order of their opening parentheses. To get a literal '$' or '\'
- Xinto dest, prefix it with '\'.
- X
- END_OF_FILE
- if test 3706 -ne `wc -c <'regexp.doc'`; then
- echo shar: \"'regexp.doc'\" unpacked with wrong size!
- fi
- # end of 'regexp.doc'
- fi
- if test -f 'regexp.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'regexp.h'\"
- else
- echo shar: Extracting \"'regexp.h'\" \(3886 characters\)
- sed "s/^X//" >'regexp.h' <<'END_OF_FILE'
- X/*
- X * version 1.8
- X * Regexp is a class that encapsulates the Regular expression
- X * stuff. Hopefully this means I can plug in different regexp
- X * libraries without the rest of my code needing to be changed.
- X * Written by Jim Morris, jegm@sgi.com
- X */
- X#ifndef _REGEXP_H
- X#define _REGEXP_H
- X#include <iostream.h>
- X#include <stdlib.h>
- X#include <malloc.h>
- X#include <string.h>
- X#include <assert.h>
- X#include <ctype.h>
- X
- X#include "regex.h"
- X
- X/*
- X * Note this is an inclusive range where it goes
- X * from start() to, and including, end()
- X */
- Xclass Range
- X{
- Xprivate:
- X int st, en, len;
- X
- Xpublic:
- X Range()
- X {
- X st=0; en= -1; len= 0;
- X }
- X
- X Range(int s, int e)
- X {
- X st= s; en= e; len= (en - st) + 1;
- X assert(st <= en && st >= 0);
- X }
- X
- X // test validity of the range
- X operator void *() { return (st <= en && st >= 0)? this : 0;}
- X int start(void) const { return st;}
- X int end(void) const { return en;}
- X int length(void) const { return len;}
- X
- X void set(int a, int b)
- X {
- X st= a; en= b; len= (en - st) + 1;
- X assert(st <= en && st >= 0);
- X }
- X
- X int operator<(const Range& r) const // for sorting
- X {
- X return ((st == r.st) ? (en < r.en) : (st < r.st));
- X }
- X
- X // x++ operator extends end of range by one
- X void operator++(int){ en++; len++; }
- X
- X // ++x operator extends start of range by one
- X void operator++(void){ st++; len--; }
- X
- X#if 0
- X // Don't need these yet
- X Range operator&(const Range& r) const // returns intersection of two ranges
- X {
- X Range ret;
- X if(en >= 0 && r.en >= 0 && (st <= r.en) && (en >= r.st)){ // if any overlap
- X ret.st= (st > r.st) ? st : r.st;
- X ret.en= (en < r.en) ? en : r.en;
- X }
- X return ret;
- X }
- X
- X Range operator|(const Range& r) const // returns union of two ranges if consecutive
- X {
- X Range ret;
- X if(en >= 0 && r.en >= 0 && (st <= r.en+1) && (en >= r.st-1)){ // if any overlap or contiguous
- X ret.st= (st < r.st) ? st : r.st;
- X ret.en= (en > r.en) ? en : r.en;
- X }
- X return ret;
- X }
- X#endif
- X
- X friend ostream& operator<<(ostream& os, const Range& r)
- X {
- X os << r.st << " - " << r.en << " (" << (r.en - r.st)+1 << ")";
- X return os;
- X }
- X};
- X
- Xclass Regexp
- X{
- Xpublic:
- X enum options {def=0, nocase=1};
- X
- Xprivate:
- X regexp *repat;
- X const char *target; // only used as a base address to get an offset
- X int res;
- X int iflg;
- X#ifndef __TURBOC__
- X void strlwr(char *s)
- X {
- X while(*s){
- X *s= tolower(*s);
- X s++;
- X }
- X }
- X#endif
- Xpublic:
- X Regexp(const char *rege, int ifl= 0)
- X {
- X iflg= ifl;
- X if(iflg == nocase){ // lowercase fold
- X char *r= new char[strlen(rege)+1];
- X strcpy(r, rege);
- X strlwr(r);
- X if((repat=regcomp(r)) == NULL){
- X cerr << "regcomp() error" << endl;
- X exit(1);
- X }
- X delete [] r;
- X }else{
- X if((repat=regcomp (rege)) == NULL){
- X cerr << "regcomp() error" << endl;
- X exit(1);
- X }
- X }
- X }
- X
- X ~Regexp()
- X {
- X free(repat);
- X }
- X
- X int match(const char *targ)
- X {
- X int res;
- X if(iflg == nocase){ // fold lowercase
- X char *r= new char[strlen(targ)+1];
- X strcpy(r, targ);
- X strlwr(r);
- X res= regexec(repat, r);
- X target= r; // looks bad but is really ok, really
- X delete [] r;
- X }else{
- X res= regexec(repat, targ);
- X target= targ;
- X }
- X
- X return ((res == 0) ? 0 : 1);
- X }
- X
- X int groups(void) const
- X {
- X int res= 0;
- X for (int i=0; i<NSUBEXP; i++) {
- X if(repat->startp[i] == NULL) break;
- X res++;
- X }
- X return res;
- X }
- X
- X Range getgroup(int n) const
- X {
- X assert(n < NSUBEXP);
- X return Range((int)(repat->startp[n] - (char *)target),
- X (int)(repat->endp[n] - (char *)target) - 1);
- X }
- X};
- X#endif
- END_OF_FILE
- if test 3886 -ne `wc -c <'regexp.h'`; then
- echo shar: \"'regexp.h'\" unpacked with wrong size!
- fi
- # end of 'regexp.h'
- fi
- if test -f 'regmagic.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'regmagic.h'\"
- else
- echo shar: Extracting \"'regmagic.h'\" \(153 characters\)
- sed "s/^X//" >'regmagic.h' <<'END_OF_FILE'
- X/*
- X * The first byte of the regexp internal "program" is actually this magic
- X * number; the start node begins in the second byte.
- X */
- X#define MAGIC 0234
- END_OF_FILE
- if test 153 -ne `wc -c <'regmagic.h'`; then
- echo shar: \"'regmagic.h'\" unpacked with wrong size!
- fi
- # end of 'regmagic.h'
- fi
- if test -f 'slicetst.c++' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'slicetst.c++'\"
- else
- echo shar: Extracting \"'slicetst.c++'\" \(1927 characters\)
- sed "s/^X//" >'slicetst.c++' <<'END_OF_FILE'
- X#ifdef TEST
- X
- X#include <iostream.h>
- X
- X#include "splash.h"
- X
- Xtypedef int INT;
- X
- Xtemplate <class T>
- Xostream& operator<<(ostream& os, const SubList<T>& sl)
- X{
- X os << SPList<T>(sl) << endl;
- X return os;
- X}
- X
- Xint main()
- X{
- X#if 1
- X Slice sl1;
- X
- X sl1.add(1); sl1.add(2);
- X cout << "1,2 " << sl1 << endl;
- X
- X Slice sl2(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1);
- X cout << "1,2,3,4,5,6,7,8,9,10 " << sl2 << endl;
- X
- X sl1.add(5); sl1.add(10);
- X cout << "1,2,5,10 " << sl1 << endl;
- X
- X Slice sl3(39, 1, 38, 2, 4, 5, 37, 7, 8, 9, 20, 22, -1);
- X cout << "39,1,38,2,4,5,37,7,8,9,20,22 " << sl3 << endl;
- X
- X SPList<INT> ix1, ix2;
- X ix1.push(1); ix1.push(2); ix1.push(3); ix1.push(4);
- X ix2.push(22); ix2.push(33);
- X cout << "ix1= " << ix1 << endl << "ix2= " << ix2 << endl;
- X
- X ix1(1, 2)= ix2;
- X
- X cout << "ix1(1, 2)= ix2: ix1= " << ix1 << endl;
- X
- X SPList<INT> tl(ix1(2, 3));
- X
- X cout << "tl ctor(ix1(2, 3)): tl= " << tl << endl;
- X
- X SPList<INT> tl2;
- X
- X tl2.push(0); tl2.push(1); tl2.push(2); tl2.push(3); tl2.push(4);
- X cout << "tl2= " << tl2 << endl;
- X
- X cout << "tl2(2, 3)= " << tl2(2, 3) << endl;
- X cout << "tl2(Slice(1, 2, 4, -1))= " << tl2(Slice(1, 2, 4, -1)) << endl;
- X
- X tl= tl2(Range(2, 4));
- X cout << "tl= tl2(Range(2, 4)): tl= " << tl << endl;
- X
- X tl2(Slice(1, 2, -1))= ix2;
- X
- X cout << "tl2(Slice(1, 2, -1))= ix2: tl2 = " << tl2 << endl;
- X
- X SPList<INT> tl3;
- X
- X tl3= tl2(1, 4);
- X
- X cout << "tl3= tl2(1, 4): tl3 = " << tl3 << endl;
- X
- X tl3.push(tl2(1, 2));
- X
- X cout << "tl3.push(tl2(1, 2)): tl3= " << tl3 << endl;
- X
- X cout << "tl3(Slice(4, 1, -1))= " << tl3(Slice(4, 1, -1)) << endl;
- X
- X cout << "tl3(Slice(2, 1, -1))= " << tl3(Slice(2, 1, -1)) << endl;
- X#endif
- X SPList<int> tl4;
- X for(int i=0;i<40;i++) tl4.push(i);
- X
- X cout << "tl4(\"1..3,6,10-22,30,31,35,37\") = " << tl4("1..3,6,10-22,30,31,35,37") << endl;
- X
- X
- X
- X}
- X#endif
- END_OF_FILE
- if test 1927 -ne `wc -c <'slicetst.c++'`; then
- echo shar: \"'slicetst.c++'\" unpacked with wrong size!
- fi
- # end of 'slicetst.c++'
- fi
- if test -f 'splash.v' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'splash.v'\"
- else
- echo shar: Extracting \"'splash.v'\" \(6620 characters\)
- sed "s/^X//" >'splash.v' <<'END_OF_FILE'
- Xx is empty
- Xx.isempty() is true
- Xx is not empty
- Xx.isempty() is false
- Xx.split(a b c d e f)= 6: [0](1)"a"
- X[1](1)"b"
- X[2](1)"c"
- X[3](1)"d"
- X[4](1)"e"
- X[5](1)"f"
- X
- Xx[0] = (1)"a"
- Xz= x; z[0]="x" z: [0](1)"x"
- X[1](1)"b"
- X[2](1)"c"
- X[3](1)"d"
- X[4](1)"e"
- X[5](1)"f"
- X
- Xss= (19)"1.2.3.4.5.6.7.8.9.0", y= ss.split("\."), y=
- X[0](1)"1"
- X[1](1)"2"
- X[2](1)"3"
- X[3](1)"4"
- X[4](1)"5"
- X[5](1)"6"
- X[6](1)"7"
- X[7](1)"8"
- X[8](1)"9"
- X[9](1)"0"
- X
- Xy.join(" ")(19)"1 2 3 4 5 6 7 8 9 0"
- X(15)"a b c
- Xd e f g"
- Xxx.split()= [0](1)"a"
- X[1](1)"b"
- X[2](1)"c"
- X[3](1)"d"
- X[4](1)"e"
- X[5](1)"f"
- X[6](1)"g"
- X
- X(13)"a b c d e f g"
- Xxx.split(",")= [0](13)"a b c d e f g"
- X
- X(20)" a b c d e f g hi "
- Xxx.split("")= [0](1)" "
- X[1](1)" "
- X[2](1)"a"
- X[3](1)" "
- X[4](1)"b"
- X[5](1)" "
- X[6](1)"c"
- X[7](1)" "
- X[8](1)"d"
- X[9](1)" "
- X[10](1)"e"
- X[11](1)" "
- X[12](1)"f"
- X[13](1)" "
- X[14](1)"g"
- X[15](1)" "
- X[16](1)"h"
- X[17](1)"i"
- X[18](1)" "
- X[19](1)" "
- X
- X(18)"a,b,c,d,,e,f,g,,,,"
- Xxx.split(",")= [0](1)"a"
- X[1](1)"b"
- X[2](1)"c"
- X[3](1)"d"
- X[4](0)""
- X[5](1)"e"
- X[6](1)"f"
- X[7](1)"g"
- X
- X(16)"a,b,c,d,,e,f,g,,"
- Xxx.split(",", 5)= [0](1)"a"
- X[1](1)"b"
- X[2](1)"c"
- X[3](1)"d"
- X[4](8)",e,f,g,,"
- X
- X(16)" a b c d e f g "
- Xxx.split(" ")= [0](0)""
- X[1](1)"a"
- X[2](1)"b"
- X[3](1)"c"
- X[4](1)"d"
- X[5](1)"e"
- X[6](1)"f"
- X[7](1)"g"
- X
- X(13)"a b c d,e,f g"
- Xxx.split("([ ,])+")= [0](1)"a"
- X[1](1)" "
- X[2](1)"b"
- X[3](1)" "
- X[4](1)"c"
- X[5](1)" "
- X[6](1)"d"
- X[7](1)","
- X[8](1)"e"
- X[9](1)","
- X[10](1)"f"
- X[11](1)" "
- X[12](1)"g"
- X
- X(4)",,,,"
- Xxx.split(",")=
- X(0)""
- Xxx.split(",")=
- X(23)" a b c d e
- Xf g "
- Xxx.split("' '")= [0](1)"a"
- X[1](1)"b"
- X[2](1)"c"
- X[3](1)"d"
- X[4](1)"e"
- X[5](1)"f"
- X[6](1)"g"
- X
- Xx = [0](1)"a"
- X[1](1)"b"
- X[2](1)"c"
- X[3](1)"d"
- X[4](1)"e"
- X[5](1)"f"
- X
- Xx.pop() : (1)"f", (1)"e"
- Xx= [0](1)"a"
- X[1](1)"b"
- X[2](1)"c"
- X[3](1)"d"
- X
- Xx.shift() : (1)"a", (1)"b"
- Xx= [0](1)"c"
- X[1](1)"d"
- X
- Xx.unshift(y): [0](1)"1"
- X[1](1)"2"
- X[2](1)"3"
- X[3](1)"4"
- X[4](1)"5"
- X[5](1)"6"
- X[6](1)"7"
- X[7](1)"8"
- X[8](1)"9"
- X[9](1)"0"
- X[10](1)"c"
- X[11](1)"d"
- X
- Xil is empty
- Xil is not empty
- Xil(1, 2, 3, 4) : [0]1 [1]2 [2]3 [3]4
- X
- Xil3= il; il3[0]= 9999; il3 = [0]9999 [1]2 [2]3 [3]4
- X
- Xil= [0]1 [1]2 [2]3 [3]4
- X
- Xil.reverse: [0]4 [1]3 [2]2 [3]1
- X
- Xil1.sort(): [0]1 [1]2 [2]3 [3]4
- X
- Xy =
- X[0](3)"one"
- X[1](3)"two"
- X[2](5)"three"
- X[3](4)"four"
- Xy.reverse() [0](4)"four" [1](5)"three" [2](3)"two" [3](3)"one"
- X
- Xy.sort() [0](4)"four" [1](3)"one" [2](5)"three" [3](3)"two"
- X
- Xy.sort().reverse() [0](3)"two" [1](5)"three" [2](3)"one" [3](4)"four"
- X
- Xil2.push(3, 4) : [0]3 [1]4
- X
- Xil.push(il2) : [0]1 [1]2 [2]3 [3]4 [4]3 [5]4
- X
- Xil.pop() : 4, 3
- Xil.unshift(il2) : [0]3 [1]4 [2]1 [3]2 [4]3 [5]4
- X
- Xil.shift() : 3, 4
- Xtesting splice:
- Xx = [0](1)"a"
- X[1](1)"b"
- X[2](1)"c"
- X[3](1)"d"
- X[4](1)"e"
- X[5](1)"f"
- X[6](1)"g"
- X[7](1)"h"
- X[8](1)"i"
- X
- Xz= x.splice(2, 3): z= [0](1)"c"
- X[1](1)"d"
- X[2](1)"e"
- X
- Xx = [0](1)"a"
- X[1](1)"b"
- X[2](1)"f"
- X[3](1)"g"
- X[4](1)"h"
- X[5](1)"i"
- X
- Xx.splice(2, 0, z):
- Xx= [0](1)"a"
- X[1](1)"b"
- X[2](1)"c"
- X[3](1)"d"
- X[4](1)"e"
- X[5](1)"f"
- X[6](1)"g"
- X[7](1)"h"
- X[8](1)"i"
- X
- Xz.splice(1, 1, x): [0](1)"d"
- Xz= [0](1)"c"
- X[1](1)"a"
- X[2](1)"b"
- X[3](1)"c"
- X[4](1)"d"
- X[5](1)"e"
- X[6](1)"f"
- X[7](1)"g"
- X[8](1)"h"
- X[9](1)"i"
- X[10](1)"e"
- X
- Xx= [0](1)"a"
- X[1](1)"b"
- X[2](1)"c"
- X[3](1)"d"
- X[4](1)"e"
- X[5](1)"f"
- X[6](1)"g"
- X[7](1)"h"
- X[8](1)"i"
- X
- Xz.splice(20, 1, x):
- Xz= [0](1)"c"
- X[1](1)"a"
- X[2](1)"b"
- X[3](1)"c"
- X[4](1)"d"
- X[5](1)"e"
- X[6](1)"f"
- X[7](1)"g"
- X[8](1)"h"
- X[9](1)"i"
- X[10](1)"e"
- X[11](1)"a"
- X[12](1)"b"
- X[13](1)"c"
- X[14](1)"d"
- X[15](1)"e"
- X[16](1)"f"
- X[17](1)"g"
- X[18](1)"h"
- X[19](1)"i"
- X
- X4, 3
- X101, 5678, 1234
- XIndex check done
- X201, 0, 200
- X
- Xtesting regexp stuff:
- Xx.m(".*X((...)...(...))", "12345Xabcxyzdef") returns 4
- Xsubs matched = [0](15)"12345Xabcxyzdef"
- X[1](9)"abcxyzdef"
- X[2](3)"abc"
- X[3](3)"def"
- X
- Xrst.m(rexp) returns 1
- X
- Xtesting grep:
- Xx:
- X[0](4)"abcd"
- X[1](5)"a2345"
- X[2](5)"X2345"
- X[3](6)"Xaaaaa"
- X[4](5)"aaaaa"
- X
- Xgrep(^a.*)
- XExpect 3 matches:
- X[0](4)"abcd"
- X[1](5)"a2345"
- X[2](5)"aaaaa"
- X
- Xs1= (6)"abcdef", s1.m("^cde") : 0
- Xs1= (6)"abcdef", s1.m("^..cde") : 1
- Xsl = m("(..) (..)", "ab cd ef"); sl =
- X[0](2)"ab"
- X[1](2)"cd"
- X
- Xs= (3)"ABC": s.m(ncr)= 1
- Xs= (3)"ABC": s.m(cr)= 0
- Xs.m("abc", "i")= 1
- Xs.m("abc")= 0
- Xtest string stuff:
- XEmpty string: (0)"" length= 0, strlen(s2) = 0
- Xs1:(7)"string1"
- Xs[0]= s, s[5]= g
- Xconst char *s= s1: s= string1
- Xs2=s1, s2:(7)"string1"
- Xs1.chop()(6)"string"
- Xs3= s: s3 = (6)"string"
- Xindex("ri") in (6)"string": 2
- Xindex((1)"1") in (6)"string": -1
- Xrindex(abc) in(9)"abcabcabc": 6
- Xrindex(abc, 5) in(9)"abcabcabc": 3
- Xsubstr(5, 3) in (9)"abcabcabc": (3)"cab"
- Xs3.substr(5, 3) = "XXX"(9)"abcabXXXc"
- Xs3.substr(5, 3) = s1(12)"abcabstringc"
- Xs3.substr(5, 3) = s1.substr(1, 3)(12)"abcabtriingc"
- Xs3.substr(0, 6) = s1.substr(0, 3)(9)"strriingc"
- Xs3.substr(-3, 2) = s1.substr(0, 2)(9)"strriistc"
- Xs1 = (10)"1234567890"
- Xs1.substr(0, 10)= s1.substr(1, 9) (9)"234567890"
- Xs1 = (10)"1234567890"
- Xs1.substr(1, 9)= s1.substr(0, 10) (11)"11234567890"
- Xs1.substr(7, 10)= "abcdefghij" (17)"1234567abcdefghij"
- Xs1.substr(10, 5)= "abcdefghij" (20)"1234567890abcdefghij"
- Xs1.substr(20, 1)= "abcdefghij" (20)"1234567890abcdefghij"
- X(6)"abcdef" + (6)"123456": (12)"abcdef123456"
- X(6)"abcdef" + "hello"= (11)"abcdefhello"
- X"hello" + (6)"abcdef"= (11)"helloabcdef"
- X(6)"abcdef" + 'x' = (7)"abcdefx"
- X(3)"abc" == (3)"def": 0
- X(3)"abc" != (3)"def": 1
- X(3)"abc" == (3)"abc": 1
- X(3)"abc" != (3)"abc": 0
- X(3)"abc" < (3)"def": 1
- X(3)"abc" > (3)"def": 0
- X(3)"abc" <= (3)"def": 1
- X(3)"abc" >= (3)"abc": 1
- X(3)"abc" == abc:1
- Xabc == (3)"abc"1
- X(3)"abc" != abc:0
- Xabc != (3)"abc"0
- Xs1 = (9)"abcdefghi", s1.tr("ceg", "123") = 3, s1 = (9)"ab1d2f3hi"
- Xs1.tr("a-z", "A-Z") = 9, s1 = (9)"ABCDEFGHI"
- Xs1.tr("efg", "") = 3, s1 = (9)"abcdefghi"
- Xs1.tr("ac-e", "X") = 4, s1 = (9)"XbXXXfghi"
- Xs1 = (12)"abcdefghiiii", s1.tr("ac-e", "X", "s") = 4, s1 = (10)"XbXfghiiii"
- Xs1.tr("ac-e", "", "d") = 4, s1 = (5)"bfghi"
- Xs1.tr("ac-e", "d", "d") = 4, s1 = (6)"dbfghi"
- Xs1.tr("ac-e", "", "cd") = 5, s1 = (4)"acde"
- X(10)"bookkeeper": s1.tr("a-zA-Z", "", "s") = 10, s1 = (7)"bokeper"
- X(15)"abc123def456ghi": s1.tr("a-zA-Z", " ", "c") = 6, s1 = (15)"abc def ghi"
- X(21)"abc123def456ghi789aaa": s1.tr("a-zA-Z", " ", "cs") = 9, s1 = (15)"abc def ghi aaa"
- X(12)"abcdddaaaxxx": s1.tr("a", "d", "s") = 4, s1 = (9)"dbcdddxxx"
- X(9)"abcdefghi" s1.s("def", "FED") = 1, s1= (9)"abcFEDghi"
- X(9)"abcDEFghi" s1.s("def", "FED") = 0, s1= (9)"abcDEFghi"
- X(9)"abcDEFghi" s1.s("def", "FED", "i") = 1, s1= (9)"abcFEDghi"
- X(9)"abcdefghi" s1.s("(...)(...)", "\$,$&,$2 $1") = 1, s1= (19)"$,abcdef,def abcghi"
- X(15)"abcdefabcghiabc" s1.s("abc", "XabcX", "g") = 3, s1= (21)"XabcXdefXabcXghiXabcX"
- X(15)"abcdefabcghiabc" s1.s("abc", "X", "g") = 3, s1= (9)"XdefXghiX"
- X(15)"abcdefabcghiabc" s1.s("abc(.)", "X$1abcX$1", "g") = 2, s1= (21)"XdabcXdefXgabcXghiabc"
- X(15)"abcdefabcghiabc" s1.s("(.)abc", "$1X$1abcX", "g") = 2, s1= (21)"abcdefXfabcXghiXiabcX"
- X(10)"1234567890" s1.s("(.)(.)", "$2$1", "g") = 5, s1= (10)"2143658709"
- END_OF_FILE
- if test 6620 -ne `wc -c <'splash.v'`; then
- echo shar: \"'splash.v'\" unpacked with wrong size!
- fi
- # end of 'splash.v'
- fi
- echo shar: End of archive 3 \(of 3\).
- cp /dev/null ark3isdone
- MISSING=""
- for I in 1 2 3 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 3 archives.
- rm -f ark[1-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-