]> git.donarmstrong.com Git - lilypond.git/commitdiff
Import of flower-1.0.0
authorfred <fred>
Thu, 26 Sep 1996 10:34:54 +0000 (10:34 +0000)
committerfred <fred>
Thu, 26 Sep 1996 10:34:54 +0000 (10:34 +0000)
16 files changed:
flower/cursor.cc [new file with mode: 0644]
flower/cursor.inl [new file with mode: 0644]
flower/dataf.cc [new file with mode: 0644]
flower/findcurs.hh [new file with mode: 0644]
flower/findcurs.inl [new file with mode: 0644]
flower/lgetopt.cc [new file with mode: 0644]
flower/lgetopt.hh [new file with mode: 0644]
flower/link.hh [new file with mode: 0644]
flower/link.inl [new file with mode: 0644]
flower/list.cc [new file with mode: 0644]
flower/list.hh [new file with mode: 0644]
flower/list.inl [new file with mode: 0644]
flower/stringutil.hh [new file with mode: 0644]
flower/textdb.cc [new file with mode: 0644]
flower/textdb.hh [new file with mode: 0644]
flower/textstr.hh [new file with mode: 0644]

diff --git a/flower/cursor.cc b/flower/cursor.cc
new file mode 100644 (file)
index 0000000..10e90de
--- /dev/null
@@ -0,0 +1,75 @@
+// cursor.cc
+#ifndef CURSOR_CC
+#define CURSOR_CC
+
+#include "cursor.hh"
+//#define inline
+//#include "cursor.inl"
+#include <assert.h>
+
+template<class T>
+Cursor<T> 
+Cursor<T>::operator ++( int )    
+{
+    Cursor<T> r = *this;
+    assert( pointer_ );
+    pointer_ = pointer_->next();
+    return r;
+}
+template<class T>
+Cursor<T> 
+Cursor<T>::operator -=( int j )    
+{
+    while (j--)
+       (*this)--;
+    return *this;
+}
+template<class T>
+Cursor<T> 
+Cursor<T>::operator +=( int j )    
+{
+    while (j++)
+       (*this)++;
+    return *this;
+}
+
+template<class T>
+Cursor<T>
+Cursor<T>::operator --( int )
+{
+    Cursor<T> r = *this;
+    assert( pointer_ );
+    pointer_ = pointer_->previous();
+    return r;
+}
+
+template<class T>
+Cursor<T> 
+Cursor<T>::operator +( int i ) const    
+{
+    Cursor<T> r = *this;
+
+    if (i<0)
+       return r -(-i);
+
+    while (i--)
+       r++;
+
+    return r;
+}
+
+template<class T>
+Cursor<T>
+Cursor<T>::operator -( int i ) const
+{
+    Cursor<T> r = *this;
+    if (i<0)
+       return r +(-i);
+
+    while (i--)
+       r--;
+    
+    return r;
+}
+
+#endif
diff --git a/flower/cursor.inl b/flower/cursor.inl
new file mode 100644 (file)
index 0000000..0243d14
--- /dev/null
@@ -0,0 +1,100 @@
+ // cursor.inl
+#ifndef CURSOR_INL
+#define CURSOR_INL
+#include <assert.h>
+//#include "list.hh"
+
+template<class T>
+inline
+Cursor<T>::Cursor( List<T>& list, Link<T>* pointer ) : 
+    list_( list )
+{
+    if ( list.size() )
+        pointer_ = pointer ? pointer : list.top().pointer_;
+    else
+        pointer_ = pointer;
+}
+
+template<class T>
+inline
+Cursor<T>::Cursor( const Cursor<T>& cursor ) :
+    list_( cursor.list_ )
+{
+    pointer_ = cursor.pointer_;
+}
+
+template<class T>
+inline T&
+Cursor<T>::operator *()
+{
+    assert( pointer_ );
+    return pointer_->thing();
+}
+
+template<class T>
+Cursor<T>
+Cursor<T>::operator =( const Cursor<T>& c )
+{   
+    assert( &list_ == &c.list_ );
+    pointer_ = c.pointer_;
+    return *this;
+}
+
+template<class T>
+inline void
+Cursor<T>::add( const T& thing )
+{
+    list_.add( thing, *this );
+}
+
+template<class T>
+inline void
+Cursor<T>::insert( const T& thing )
+{
+    list_.insert( thing, *this );
+}
+
+template<class T>
+inline void
+Cursor<T>::remove()
+{
+    assert( pointer_ );
+    list_.remove( *this );
+}
+
+template<class T>
+inline const List<T>&
+Cursor<T>::list() const
+{
+    return list_;
+}
+
+template<class T>
+inline Link<T>*
+Cursor<T>::pointer()
+{
+    return pointer_;
+}
+
+template<class T>
+inline bool
+Cursor<T>::backward()
+{
+    return ( pointer_ != 0 );
+}
+
+template<class T>
+inline bool
+Cursor<T>::forward()
+{
+    return ( pointer_ != 0 );
+}
+
+template<class T>
+inline bool
+Cursor<T>::ok()
+{
+    return ( pointer_ != 0 );
+}
+
+#endif
\ No newline at end of file
diff --git a/flower/dataf.cc b/flower/dataf.cc
new file mode 100644 (file)
index 0000000..e53c716
--- /dev/null
@@ -0,0 +1,125 @@
+#include <fstream.h>
+#include <ctype.h>
+
+#include "textstr.hh"
+Text_stream::Text_stream(String fn)
+{      
+        if (fn == "") 
+           {
+           name = "<STDIN>";       
+           f = stdin;
+           }
+       
+       else 
+           {
+           name = fn;      
+           f = fopen(fn, "r");
+           }
+       
+       if (!f) {
+           cerr <<__FUNCTION__<< ": can't open `" << fn << "'\n";
+           exit(1);
+       }
+
+       line_no = 1;
+    }
+
+void
+Text_stream::message(String s)
+{
+    cerr << "\n"<<get_name() << ": " << line()<<": "<<s<<endl;
+}
+
+void 
+Data_file::gobble_white()
+{
+    char c;
+    
+    while ((c=data_get()) == ' ' ||c == '\t')
+       if (eof()) 
+           break;
+
+    data_unget(c);
+}
+
+String
+Data_file::get_word() 
+{// should handle escape seq's
+    String s;
+
+    while (1) 
+       {
+       char    c  = data_get();
+       
+       if (isspace(c) || eof()) 
+           {
+           data_unget(c);
+           break;
+           }
+       
+       
+       if (c == '\"')
+           {
+           rawmode= true;
+
+           while ((c  = data_get()) != '\"')
+               if (eof())
+                   error("EOF in a string");           
+               else
+                   s += c;
+           
+
+           rawmode= false;
+           }       
+       else
+           s += c;             
+       }
+    
+    return s;        
+}
+
+/// get a char.
+char
+Data_file::data_get() {
+    char c =  get(); 
+    if (!rawmode && c == '#') // gobble comment
+       {       
+       while ((c = get()) != '\n' && !eof()) 
+           ;
+           return '\n';
+       }    
+
+    return c;
+}
+/**
+   Only class member who uses text_file::get
+   */
+
+/// read line, gobble '\n'    
+String Data_file::get_line()     
+{
+    char c; 
+    String s;
+
+    while ((c  = data_get()) != '\n' && !eof())
+       s += c;
+    return s;  
+}
+
+/// gobble stuff before first entry on a line.    
+void
+Data_file::gobble_leading_white() 
+{
+    char c;
+    
+    // eat blank lines.
+    while (!eof()) 
+       {
+       c = data_get();             
+       if (!isspace(c))
+           break;
+       }
+    data_unget(c);
+}
+
+
diff --git a/flower/findcurs.hh b/flower/findcurs.hh
new file mode 100644 (file)
index 0000000..e46b64d
--- /dev/null
@@ -0,0 +1,12 @@
+template<class T, class U>
+class FindCursor : public Cursor<T>
+{
+public:
+    FindCursor( List<T>& list, Link<T>* pointer = 0 );
+    FindCursor( const Cursor<T>& cursor );
+    
+    Cursor<T> operator =( const Cursor<T>& c );
+    FindCursor<T, U> find( const T& thing );
+};
+
+#include "findcurs.inl"
diff --git a/flower/findcurs.inl b/flower/findcurs.inl
new file mode 100644 (file)
index 0000000..593d4aa
--- /dev/null
@@ -0,0 +1,37 @@
+template<class T, class U>
+inline
+FindCursor<T, U>::FindCursor( List<T>& list, Link<T>* pointer ) : 
+    Cursor<T>( list, pointer )
+{
+}
+
+template<class T, class U>
+inline
+FindCursor<T, U>::FindCursor( const Cursor<T>& cursor ) :
+    Cursor<T>( cursor )
+{
+}
+
+template<class T, class U>
+Cursor<T>
+FindCursor<T, U>::operator =( const Cursor<T>& c )
+{   
+    ( (Cursor<T>&)*this ) = c;
+    return *this;
+}
+
+template<class T, class U>
+inline FindCursor<T, U>
+FindCursor<T, U>::find( const T& thing )
+{
+    Cursor<T> c( *this );
+    while( c.forward() )
+       {
+       T& look = *c;
+       if ( U::equal( look, thing ) )
+           return c;
+       c++;
+       }
+
+    return FindCursor( *this ); // cursor is not .ok()
+}
diff --git a/flower/lgetopt.cc b/flower/lgetopt.cc
new file mode 100644 (file)
index 0000000..ac9a12d
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+   process command line, GNU style.
+
+
+   this is (Copyleft) 1996, Han-Wen Nienhuys, <hanwen@stack.urc.tue.nl>
+ */
+#include <stdio.h>
+#include <iostream.h>
+#include <assert.h>
+#include "lgetopt.hh"
+
+long
+Getopt_long::intarg() {
+    long l;
+    if (sscanf(optarg, "%ld", &l) != 1)
+       report(E_ILLEGALARG);
+    
+    return l;
+}
+long_option_init *
+Getopt_long::parselong() {
+    const char *optnm = argv[optind] + 2 ;
+    assert(*optnm);
+    
+    char *endopt = strchr(optnm, '=');
+    int searchlen  = (endopt) ? endopt - optnm : strlen(optnm);
+    
+    beet=0;
+    for (int i=0; i< table_len; i++) {
+       const char *ln = the_opts[i].longname;
+
+       if (ln && !strncmp(ln, optnm, searchlen)) {
+           beet = the_opts+i;
+           break;
+       }
+    }  
+
+    if (!beet) {
+       report(E_UNKNOWNOPTION);
+       return 0;
+    }
+    optind++;
+    optindind = 0;
+
+    
+    if (beet->take_arg) {
+       if (endopt)
+           optarg = endopt +1; // a '='
+       else {
+           optarg = argv[optind];
+           optind++;
+       }
+       if (!optarg)
+           report(E_ARGEXPECT);
+
+    } else {
+       optarg = 0;
+       if (endopt)
+           report(E_NOARGEXPECT);
+    }
+    
+    return beet;
+}
+
+
+ostream &
+long_option_init::printon(ostream &errorout)
+{
+    if (shortname)     
+       errorout <<"-" << shortname;
+    if (shortname && longname)
+       errorout << ", ";
+    if (longname)      
+       errorout << "`--" << longname << "'";
+    return errorout;
+}
+
+// report an error, GNU style.
+void
+Getopt_long::report(Errorcod c)
+{
+    error = c;
+    if (!errorout)
+       return;
+
+    *errorout << argv[0] << ": ";
+    switch (c) {
+    case E_ARGEXPECT:
+       *errorout<< "option ";
+       beet->printon(*errorout);
+       *errorout << "requires an argument"<<endl;
+       break;
+    case  E_NOARGEXPECT:
+       *errorout << "option `--" << beet->longname << "' does not allow an argument"<<endl;
+       break;
+       
+    case E_UNKNOWNOPTION:
+       *errorout << "unrecognized option ";
+       if (optindind)
+           *errorout << "-" << argv[optind][optindind] << endl;
+       else
+           *errorout << argv[optind] << endl;
+
+       break;
+    case E_ILLEGALARG:
+       *errorout << "illegal argument `" << optarg << "\'to option ";
+       beet->printon(*errorout);
+       *errorout << '\n';
+    default:
+       assert(false);
+    }
+    exit(2); 
+}
+    
+long_option_init *
+Getopt_long::parseshort() {
+    char c=argv[optind][optindind];
+    beet=0;
+    assert(c);
+    
+    for (int i=0; i < table_len; i++)
+       if (the_opts[i].shortname == c) {
+           beet  = the_opts+i;
+           break;
+       }
+
+    if (!beet){
+       report(E_UNKNOWNOPTION);
+       return 0;
+    }
+
+    optindind++;
+    if (!beet->take_arg){
+       optarg = 0;
+       return beet;
+    }
+    optarg = argv[optind] + optindind;
+
+    optind ++;
+    optindind = 0;
+    
+    if (!optarg[0]) {
+       optarg = argv[optind];
+       optind ++;
+    }
+    if (!optarg) {
+       report(E_ARGEXPECT);
+    }
+    
+    return beet;
+}
+
+long_option_init *
+Getopt_long::operator()() {
+    if (!next())
+       return 0;
+    
+    if (optindind)
+       return parseshort();
+    
+    if (argv[optind][0] != '-')
+       return 0;
+
+    if (argv[optind][1] == '-') {// what to do with "command  --  bla"
+       return parselong();
+    } else {
+       optindind = 1;
+       return parseshort();
+    }
+}
+
+Getopt_long::Getopt_long(int c, char **v, long_option_init *lo) {
+    the_opts = lo;
+    errorout = &cerr;
+    argv = v;
+    argc = c;
+    optind = 1;
+    optindind = 0;
+
+    //    reached end of option table?
+    int i;
+    for (i = 0;  the_opts[i].longname ||the_opts[i].shortname; i++)
+       ;
+    table_len = i;
+}
+
+bool Getopt_long::next() {
+    error = E_NOERROR;
+    while (optind < argc && !argv[optind][optindind]) {
+       optind++;
+       optindind = 0;
+    }
+    return (optind < argc);
+}
+   
+char *
+Getopt_long::current_arg()
+{
+    if (optind >= argc)
+       return 0;
+    char * a = argv[optind];
+    return a + optindind;
+}
+
+char *
+Getopt_long::get_next_arg()
+{
+    char * a = current_arg();
+    if ( a) {
+       optind ++;
+       optindind = 0;
+    }
+    return a;
+}
diff --git a/flower/lgetopt.hh b/flower/lgetopt.hh
new file mode 100644 (file)
index 0000000..0ff3e08
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef LGETOPT_HH
+#define LGETOPT_HH
+
+#include <string.h>
+
+
+class ostream;
+
+struct long_option_init {
+    bool take_arg;
+    const char* longname;
+    char        shortname;
+
+    ostream &printon(ostream &errorout);
+};
+
+
+///
+class Getopt_long {
+public:
+    ///
+    enum Errorcod { E_NOERROR = 0, E_ARGEXPECT, E_NOARGEXPECT, E_UNKNOWNOPTION,
+               E_ILLEGALARG } ;
+
+    /** errorcodes: no error, argument expected, no argument expected,
+      unknown option, illegal argument (eg. int expected).  */
+
+private:
+
+    /// the option info.
+    long_option_init *the_opts;
+    int table_len;
+    
+    /// if doing short option, argv[optind][optindind] is processed next.
+    int optindind;
+
+    /// the option found
+    long_option_init *beet;
+
+    /// get ready for processing next error.
+    bool next();
+    long_option_init *parselong();
+    long_option_init *parseshort();
+    
+    ostream *errorout;
+
+    /// report an error and abort
+    void report(Errorcod c);
+public:
+    /// what to do with  errors
+    void seterror(ostream *os);
+    /**
+       report messages on  #*os#, and abort.
+       if #os# is null, then do not report nor abort, just set #error#
+      */
+       
+    /// argument. Set to 0 if not present
+    char* optarg;
+
+
+    /// return an integer (with err. detect)
+    long intarg();
+    /// argv[optind] will be processed next.
+    int optind;
+
+    /// the arguments
+    char **argv;
+
+    /// the arg. count
+    int argc;
+    
+    /// construct: pass arguments and option info.
+    Getopt_long(int c,  char **v, long_option_init *lo);
+
+    /// get the next option
+    long_option_init *operator()();
+    /**
+      RETURN: pointer to next option found.
+      0 if error occurred, or next argument is no option.
+      */
+
+    char *current_arg();
+    char * get_next_arg();
+    Errorcod error;
+};
+/**
+  C++ for version of long_getopt. For processing GNU style command line arguments.
+  No pointer  (return values, arguments) contents are copied.
+  */
+#endif
diff --git a/flower/link.hh b/flower/link.hh
new file mode 100644 (file)
index 0000000..6f9c75a
--- /dev/null
@@ -0,0 +1,38 @@
+// link.hh
+
+#ifndef __LINK_HH
+#define __LINK_HH
+template<class T>
+class List;
+
+
+/// class for List 
+template<class T>
+class Link
+{
+//    friend class Cursor<T>;
+public:    
+    Link( const T& thing );
+    
+    Link<T>* previous();
+    Link<T>* next();
+
+    /// put new Link item after me in list
+    void add( const T& thing );
+    /// put new Link item before me in list
+    void insert( const T& thing );     
+    void remove(List<T> &l);
+    
+    T& thing();
+    void OK() const;
+private:    
+    Link( Link<T>* previous, Link<T>* next, const T& thing );
+
+    T thing_;
+    Link<T>* previous_;
+    Link<T>* next_;
+};
+
+#include "link.inl"
+
+#endif // __LINK_HH //
diff --git a/flower/link.inl b/flower/link.inl
new file mode 100644 (file)
index 0000000..e76caab
--- /dev/null
@@ -0,0 +1,100 @@
+// link.inl -*-c++-*-
+#ifndef LINK_INL
+#define LINK_INL
+#include <assert.h>
+template<class T>
+inline
+void
+Link<T>::OK() const
+{
+    if (previous_) {
+       assert(previous_->next_ == this);
+    }
+    if (next_) {
+       assert(next_->previous_ == this);
+    }
+}
+
+template<class T>
+inline
+Link<T>::Link( const T& thing ) : 
+    thing_( thing )
+{
+    previous_ = next_ = 0;
+}
+
+template<class T>
+inline
+Link<T>::Link( Link<T>* previous, Link<T>* next, const T& thing ) : 
+    thing_( thing )
+{
+    previous_ = previous;
+    next_ = next;
+}
+
+template<class T>
+inline
+Link<T>*
+Link<T>::next()
+{
+    return next_;
+}
+
+template<class T>
+inline
+Link<T>*
+Link<T>::previous()
+{
+    return previous_;
+}
+
+template<class T>
+inline
+void
+Link<T>::add( const T& thing )
+{
+    
+    Link<T>* l = new Link<T>( this, next_, thing );
+    if ( next_ )
+        next_->previous_ = l;
+    next_ = l;
+}
+
+template<class T>
+inline void
+Link<T>::insert( const T& thing )
+{
+    //    Link<T>* l = new Link<T>( next_, this, thing );
+                               // bugfix hwn 16/9/96
+    Link<T>* l = new Link<T>( previous_, this, thing );
+    if ( previous_ )
+        previous_->next_ = l;
+    previous_ = l;
+}
+
+/*
+    don't forget to adjust #l#'s top_ and bottom_.
+    */
+template<class T>
+inline void
+Link<T>::remove(List<T> &l)
+{
+    if ( previous_ ) 
+        previous_->next_ = next_;
+    else 
+       l.top_ = next_;
+
+    if ( next_ )
+        next_->previous_ = previous_;
+    else
+       l.bottom_ = previous_;
+}
+
+template<class T>
+inline
+T&
+Link<T>::thing()
+{
+    return thing_;
+}
+#endif
diff --git a/flower/list.cc b/flower/list.cc
new file mode 100644 (file)
index 0000000..f93352f
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef LIST_CC
+#define LIST_CC
+
+#include "list.hh"
+
+template<class T>
+void
+List<T>::OK() const
+{
+    int i = size_;
+    Link<T> *lp = top_;
+    while (i--) {
+       assert(lp);
+       lp->OK();
+       lp = lp->next();
+    }
+    assert(!lp);
+     i = size_;
+    lp = bottom_;
+    while (i--) {
+       assert(lp);
+       lp->OK();
+       lp = lp->previous();
+    }
+    assert(!lp);
+}
+
+template<class T>
+Cursor<T>
+List<T>::top()
+{
+
+    // ?? waarvoor is deze if ? 
+    if ( top_ )                        // equivalent: if ( size_ )
+       {
+       Link<T>* t = top_->previous();
+       assert( t != top_ );    // silly link
+       while ( t )
+           {
+           top_ = t;
+           t = top_->previous();
+           }
+       }
+                               // list empty: Cursor not ok()
+    return Cursor<T>( *this, top_ );
+}
+
+
+template<class T>
+Cursor<T>
+List<T>::bottom()
+{
+    /* wat is dit voor zooi? kan dit niet weg?
+
+    (invarianten!)
+    */
+    if ( bottom_ )             // equivalent: if ( size_ )
+       {
+       Link<T>* b = bottom_->next();
+       assert( b != bottom_ ); // silly link    
+       while ( b )
+           {
+           bottom_ = b;
+           b = bottom_->next();
+           }
+       }
+                               // list empty: Cursor not ok()
+    return Cursor<T>( *this, bottom_ );
+}
+
+
+// not inlined since it assumes knowledge of destructor.
+template<class T>
+inline void
+PointerList<T>::remove( Cursor<T> me )
+{
+    if ( me.ok() )
+       {
+
+       delete *me;
+        List<T>::remove( me ); 
+       }
+}
+
+
+
+
+#endif
diff --git a/flower/list.hh b/flower/list.hh
new file mode 100644 (file)
index 0000000..97e672f
--- /dev/null
@@ -0,0 +1,96 @@
+// list.hh
+
+#ifndef __LIST_HH
+#define __LIST_HH
+
+class ostream;
+template<class T> class Cursor;
+template<class T> class Link;
+
+/// all purpose list
+template<class T>
+class List
+{
+ public:
+     /// construct empty list                
+    List(); 
+
+    /// construct list from first item.  
+    List( const T& thing );
+    
+    virtual ~List();
+       
+    Cursor<T> bottom();
+
+    int size() const;
+    Cursor<T> top();
+    void OK() const; 
+ protected:
+    friend class Cursor<T>;
+    friend class Link<T>;
+    
+    /// add after after_me
+    void add( const T& thing, Cursor<T> after_me );
+
+    /// put thing before #before_me#
+    void insert( const T& thing, Cursor<T> before_me );
+    virtual void remove( Cursor<T> me );
+
+    int size_;
+    Link<T>* top_;
+    Link<T>* bottom_;
+};
+/**
+  a doubly linked list; 
+  List can be seen as all items written down on paper,
+  from top to bottom
+
+  class Cursor is used to extend List
+
+   items are always stored as copies in List, but:
+   #List<String># :  copies of #String# stored 
+   #List<String*># : copies of #String*# stored! 
+   (do not use, use \Ref{PointerList}#<String*># instead.)
+   {\bf note:} 
+   retrieving "invalid" cursors, i.e. 
+   #top()/bottom()# from empty list, #find()# without success,
+    results in a nonvalid Cursor ( #!ok()# )
+
+
+    INVARIANTEN!
+*/
+
+
+/// Use for list of pointers, e.g. PointerList<AbstractType*>.
+template<class T>
+class PointerList : public List<T>
+{
+ public:
+    PointerList();
+    PointerList( const T& thing );
+
+    ///
+    virtual ~PointerList();
+    /**
+      This function deletes deletes the allocated pointers of all links. 
+      #\Ref{~List}# is used to delete the links themselves.
+      */ 
+
+ protected:
+    virtual void remove( Cursor<T> me );
+};
+
+#include "list.inl"
+#include "cursor.hh"
+
+// instantiate a template:  explicit instantiation.
+#define L_instantiate(a)  template class List<a>; template class Cursor<a>; \
+  template class Link<a>
+#define PL_instantiate(a) L_instantiate(a *); template class PointerList<a*>
+
+#endif // __LIST_HH //
+    
+   
+
+
diff --git a/flower/list.inl b/flower/list.inl
new file mode 100644 (file)
index 0000000..54df457
--- /dev/null
@@ -0,0 +1,144 @@
+// -*-c++-*-
+#ifndef LIST_INL
+#define LIST_INL
+template<class T>
+inline
+List<T>::List()
+{
+    top_ = bottom_ = 0;
+    size_ = 0;
+}
+
+template<class T>
+inline
+List<T>::List( const T& thing )
+{
+    top_ = bottom_ = 0;
+    size_ = 0;
+    add( thing, Cursor<T>( *this, bottom_ ) );
+}
+
+template<class T>
+inline
+List<T>::~List()
+{
+    for ( Cursor<T> c( *this ); c.forward(); c++ )
+        remove( c );
+}
+
+template<class T>
+inline void
+List<T>::add( const T& thing, Cursor<T> after_me )
+{
+#if 0
+    if ( after_me.ok() )
+       after_me.pointer()->add( thing );
+    else if ( size_ )
+        bottom().pointer()->add( thing );
+    else
+        bottom_ = top_ = new Link<T>( thing );
+#endif
+    
+    if (!size_) {              // not much choice if list is empty
+        bottom_ = top_ = new Link<T>( thing );
+    } else {                   // add at aprioprate place
+       Link<T> *p =  ( after_me.ok() ) ?
+           after_me.pointer() : bottom().pointer();
+       p->add(thing);
+       if (p == bottom_)       // adjust bottom_ if necessary.
+           bottom_ = p->next();
+    }
+
+    size_++;
+}
+/** 
+
+  Procedure:
+  \begin{itemize}
+  \item if #after_me# is #ok()#, add after #after_me#, else
+  \item if list !empty simply add to bottom, else
+  \item list is empty: create first \Ref{Link} and initialize 
+  #bottom_# and #top_#.
+  \end{itemize}
+*/
+
+template<class T>
+inline void
+List<T>::insert( const T& thing, Cursor<T> before_me )
+{
+    if (!size_) {
+       bottom_ = top_ = new Link<T>( thing );
+    } else {
+       Link<T> *p = 
+           (before_me.ok())?
+           before_me.pointer() : top().pointer();
+
+       p->insert(thing);
+       if (p == top_)
+           top_ = p->previous();
+    }
+       
+    size_++;
+#if 0 // rewrite hwn 16/9              
+    if ( before_me.ok() )
+        before_me.pointer()->insert( thing );
+    else if ( size_ )
+       top().pointer()->insert( thing );
+    else
+       bottom_ = top_ = new Link<T>( thing );
+    size_++;
+#endif
+}
+
+template<class T>
+inline void
+List<T>::remove( Cursor<T> me )
+{
+    if ( me.ok() )
+       {
+       me.pointer()->remove(*this);
+       delete me.pointer();
+        size_--;
+       }
+}
+
+template<class T>
+inline int
+List<T>::size() const
+{ 
+    return size_;
+}
+
+template<class T>
+inline
+PointerList<T>::PointerList() :
+    List<T>()
+{
+}
+
+template<class T>
+inline
+PointerList<T>::PointerList( const T& thing ) :
+    List<T>( thing )
+{
+}
+
+template<class T>
+inline
+PointerList<T>::~PointerList()
+{
+    for ( Cursor<T> c( *this ); c.forward(); c++ )
+        remove( c );
+}
+
+template<class T>
+inline void
+PointerList_print( PointerList<T> const & l  ) 
+{
+    List<T>& promises_to_be_const = (List<T>&) l;
+    for ( Cursor<T> c( promises_to_be_const ); c.forward(); c++ )
+        (*c)->print();  
+}
+
+
+#endif
diff --git a/flower/stringutil.hh b/flower/stringutil.hh
new file mode 100644 (file)
index 0000000..b7503b7
--- /dev/null
@@ -0,0 +1,245 @@
+#ifndef STRINGUTIL_HH
+#define STRINGUTIL_HH
+#include <assert.h>
+
+#ifndef EVELYN
+#define NDEBUG BLONDE
+  // switching into "blonde" mode
+  // i trust stringclass nowadays.
+#endif
+
+class String_handle;
+/// Internal String struct
+class StringData {
+    // GNU malloc: storage overhead is 8 bytes anyway.
+    const int INITIALMAX = 8;  
+
+friend class String_handle;
+    int maxlen;        // maxlen is arraysize-1
+    
+    int length;
+    char* string;
+    int references;
+
+    /// init to ""
+    StringData() {
+       references=0;
+       maxlen = INITIALMAX;
+       string = new char[maxlen + 1];
+       string[0] = 0;
+       length = 0;
+    }
+
+    /// init from src. Conservative allocation.
+    StringData(StringData const &src) {
+       references=0;   
+       maxlen = length = src.length;           
+       string = new char[maxlen+1]; // should calc GNU 8byte overhead.         
+       strcpy(string, src.string);     
+    }
+    
+    ~StringData() {
+       assert(references == 0);
+       delete[] string;
+    }
+
+
+    void setmax(int j) {       
+       OKW();
+       if (j > maxlen) {
+           delete string;
+           maxlen = j;
+           string = new char[maxlen + 1];
+       
+           string[0] = 0;
+           length = 0;
+       }
+    }
+    /** POST: maxlen >= j.
+      IN: j, maximum stringlength.    
+      contents thrown away.
+    */
+    ///
+    void remax(int j) {
+       OKW();
+       if (j > maxlen) {
+           maxlen = j;
+           char *p = new char[maxlen + 1];         
+           strcpy(p,string);       
+           delete[] string;
+           string = p;
+       //    length = strlen(string);
+       }
+    }
+    /** POST: maxlen >= j.
+      IN: j, maximum stringlength.
+      contents are kept if it grows.
+      */    
+    /// check if writeable.
+    void OKW() {
+
+       assert (references == 1);
+
+    }
+
+    /// check state.
+    void OK() {
+       assert(strlen(string) == size_t(length));
+       assert(maxlen >= length);
+       assert(bool(string));
+       assert(references >= 1);
+    }
+
+    // needed?
+    void update() {
+       length  = strlen (string);
+    }
+
+    /// reduce memory usage.
+    void tighten() { // should be dec'd const
+       maxlen = length;
+       char *p = new char[maxlen + 1];     
+       strcpy(p,string);           
+       delete[] string;
+       string = p;             
+    }
+
+    // assignment.
+    void set(const char *s) {
+       OKW();
+
+       assert(s);
+
+       length = strlen (s);
+       remax(length);
+       strcpy(string,s);
+    }
+    
+    /// concatenation.
+    void operator += (const char *s) {
+       OK();
+       OKW();
+       int old = length;
+       
+       length += strlen(s);
+       remax (length);
+       strcpy(string + old, s);        
+    }
+
+    /// the array itself
+    operator const char *() const { return string; }
+
+    // idem, non const
+    char *array_for_modify() {
+       OKW();
+       return string;
+    }
+    void trunc(int j) {
+       OKW(); 
+       assert(j >= 0 && j <= length);
+       string[j] = 0;
+       length = j;
+    }
+
+    /** not really safe. Can alter length without StringData knowing it.
+      */
+    char &operator [](int j) {
+       assert(j >= 0 && j <= length);
+       return string[j] ; 
+    }
+
+    char operator [](int j) const {
+       assert(j >= 0 && j <= length);
+       return string[j]; 
+    }
+};
+
+/**
+   the data itself. Handles simple tasks (resizing, resetting)
+ */
+/****************************************************************/
+/// ref. counting for strings
+class String_handle {
+    StringData* data;
+    
+    /// decrease ref count. Named kind of like a Tanenbaum semafore 
+    void down() { if (!(--data->references)) delete data; data = 0; }
+
+    /// increase ref count
+    void up(StringData *d) { data=d; data->references ++; }
+    
+    /** make sure data has only one reference.      
+       POST: data->references == 1
+      */
+    void copy() {
+       if (data->references !=1){
+           StringData *newdata = new StringData(*data);
+           down();
+           up(newdata);
+       }
+    }
+    
+public:
+
+    String_handle() {
+       up(new StringData);
+    }
+    ~String_handle() { 
+       down();
+    }    
+    String_handle(String_handle const & src) { 
+       up(src.data);
+    }
+
+    /// retrieve the actual array.
+    operator const char *() const { return *data; }    
+    char *array_for_modify() {
+       copy();
+       return data->array_for_modify();
+    }
+    
+    void operator =(String_handle const &src) {
+       if (this == &src)
+           return;
+       down();
+       up(src.data);
+    }
+    
+    void operator += (const char *s) { 
+       copy();
+       *data += s;
+    }    
+
+    
+    char operator[](int j) const { return (*data)[j]; }
+
+    // !NOT SAFE!
+    // don't use this for loops. Use array_for_modify()
+    char &operator[](int j) {
+       copy();         // hmm. Not efficient
+       return data->array_for_modify()[j];
+    }
+
+    void operator = (char const *p) {
+       copy();
+       data->set(p);
+    }
+                              
+    void trunc(int j) { copy(); data->trunc(j); }
+    int len() const { return data->length; }
+};
+/**
+   handles ref. counting, and provides a very thin
+   interface using char *
+ */
+
+
+#ifdef NDEBUG
+#if (NDEBUG == BLONDE)
+#undef NDEBUG
+#endif
+#endif
+
+
+
+#endif // STRINGUTIL_HH
diff --git a/flower/textdb.cc b/flower/textdb.cc
new file mode 100644 (file)
index 0000000..4dfdc87
--- /dev/null
@@ -0,0 +1,23 @@
+#include "textdb.hh"
+
+Text_record
+Text_db::get_record() 
+{
+       String s;
+       svec<String> fields;
+       gobble_leading_white();
+       
+       while ((s = get_word()) != "")
+           {
+           fields.add(s);      
+           gobble_white();
+           }
+            
+
+       if (get_line() != "")
+           assert(false);
+       
+       return Text_record(fields, get_name(), line());
+}
+
+
diff --git a/flower/textdb.hh b/flower/textdb.hh
new file mode 100644 (file)
index 0000000..8f906b8
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef TEXTDB_HH
+#define TEXTDB_HH
+
+#include "textstr.hh"
+
+/**: do "#" comments, read quote enclosed  fields */
+
+/// a "const" svec. Contents can't be changed.
+class Text_record : svec<String>  
+{
+    int line_no;
+    String filename;
+    
+public:
+    Text_record() { } // needed because of other ctor
+
+    /// report an error in this line.
+    message(String s) {
+       cerr << '\n'<< filename << ": "<< line_no << s << "\n";
+    }         
+    String operator[](int j) {
+       return svec<String>::operator[](j);
+    }
+
+    Text_record(svec<String> s, String fn, int j) : svec<String>(s) { 
+       filename = fn; line_no = j; 
+    }
+    svec<String>::sz;           
+};
+
+/// abstraction for a datafile
+class Text_db : private Data_file
+{
+ public:
+    /// get a line with records
+    Text_record    get_record();
+
+    Text_db(String fn):Data_file(fn) { }
+    Data_file::error;
+    Data_file::eof;    
+    
+    /// get next line.
+    Text_record operator++(int) {
+       return get_record();
+    }
+    /// are we done yet?
+    operator bool() {
+       return !eof();
+    }
+};
+
+
+/**
+    add a subrec/fieldsep/record separator
+    */
+#endif
diff --git a/flower/textstr.hh b/flower/textstr.hh
new file mode 100644 (file)
index 0000000..41a979f
--- /dev/null
@@ -0,0 +1,114 @@
+#include <stdio.h>
+#include <ctype.h>
+
+//#include "globals.hh"
+#include "string.hh"
+#include "vray.hh"
+
+/// line counting input stream.
+class Text_stream
+{
+    int line_no;
+
+    // could just have used streams. 
+    FILE *f;  
+    sstack<char> pushback;
+    String name;
+    
+ public:
+    Text_stream(String fn);
+    String get_name() { return name; }
+    bool eof() {
+       return feof(f);
+    }
+    bool eol() {
+       return (peek() == '\n');
+    }
+    char peek() {
+       char c = get();
+       unget(c);
+       return c;
+    }
+    int line(){
+       return line_no;
+    }
+
+    char    get() {
+       char c;
+       
+       if (pushback.empty())
+           c = getc(f);        
+       else 
+           c = pushback.pop();
+
+       if (c =='\n')
+           line_no++;
+       return c;       
+    }
+    void unget(char c) {
+       if (c =='\n')
+           line_no--;
+       pushback.push(c);
+    }
+    ~Text_stream (){
+       if (!eof()) 
+           cerr <<__FUNCTION__<< ": closing unended file";
+    
+       fclose(f);
+    }
+
+    /// GNU format message.
+    void message(String s); 
+};
+/**
+ a stream for textfiles. linecounting. Thin interface getchar and
+ ungetchar.  (ungetc is unlimited) 
+
+ should protect get and unget against improper use
+*/
+
+
+/// read a data file
+class Data_file : private Text_stream
+{
+    
+ public:
+    bool rawmode;
+
+    Text_stream::line;    
+    Text_stream::eof;
+    Text_stream::get_name;    
+
+    char data_get();    
+    void data_unget(char c) {
+       unget(c);
+    }
+
+    /// read line, eat #\n#
+    String get_line();
+    
+    /// read a word till next space, leave space. Also does quotes
+    String get_word();
+
+    /// gobble horizontal white stuff.
+    void gobble_white();
+
+    /// gobble empty stuff before first field.
+    void gobble_leading_white();
+    Data_file(String s) : Text_stream(s) {
+       //*mlog << "(" << s << flush;   
+       rawmode=  false;        
+    }
+
+    ~Data_file()  {
+       //      *mlog << ")"<<flush;    
+    }    
+
+    warning(String s) {
+       message("warning: " + s);
+    }
+    error(String s){
+       message(s);
+       exit(1);    
+    }
+};