]> git.donarmstrong.com Git - lilypond.git/commitdiff
release: 0.0.1 release/0.0.1
authorHan-Wen Nienhuys <hanwen@xs4all.nl>
Wed, 9 Oct 1996 12:04:47 +0000 (14:04 +0200)
committerHan-Wen Nienhuys <hanwen@xs4all.nl>
Wed, 9 Oct 1996 12:04:47 +0000 (14:04 +0200)
113 files changed:
Makefile [new file with mode: 0644]
Sources.make [new file with mode: 0644]
boxes.cc [new file with mode: 0644]
boxes.hh [new file with mode: 0644]
break.cc [new file with mode: 0644]
calcideal.cc [new file with mode: 0644]
choleski.cc [new file with mode: 0644]
choleski.hh [new file with mode: 0644]
cols.cc [new file with mode: 0644]
cols.hh [new file with mode: 0644]
command.cc [new file with mode: 0644]
command.hh [new file with mode: 0644]
const.hh [new file with mode: 0644]
debug.cc [new file with mode: 0644]
debug.hh [new file with mode: 0644]
depend [new file with mode: 0644]
dstream.cc [new file with mode: 0644]
dstream.hh [new file with mode: 0644]
flower/Makefile [new file with mode: 0644]
flower/assoc.hh [new file with mode: 0644]
flower/compare.hh [new file with mode: 0644]
flower/cursor.cc [new file with mode: 0644]
flower/cursor.hh [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/handle.hh [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/string.cc [new file with mode: 0644]
flower/string.hh [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]
flower/unionfind.cc [new file with mode: 0644]
flower/unionfind.hh [new file with mode: 0644]
flower/vray.hh [new file with mode: 0644]
glob.hh [new file with mode: 0644]
globvars.hh [new file with mode: 0644]
item.cc [new file with mode: 0644]
item.hh [new file with mode: 0644]
keyword.cc [new file with mode: 0644]
keyword.hh [new file with mode: 0644]
lexer.hh [new file with mode: 0644]
lexer.l [new file with mode: 0644]
lilyponddefs.tex [new file with mode: 0644]
line.cc [new file with mode: 0644]
line.hh [new file with mode: 0644]
linespace.cc [new file with mode: 0644]
linespace.hh [new file with mode: 0644]
linestaff.cc [new file with mode: 0644]
linestaff.hh [new file with mode: 0644]
main.cc [new file with mode: 0644]
make_version [new file with mode: 0755]
matrix.cc [new file with mode: 0644]
matrix.hh [new file with mode: 0644]
misc.cc [new file with mode: 0644]
misc.hh [new file with mode: 0644]
molecule.cc [new file with mode: 0644]
molecule.hh [new file with mode: 0644]
mtime.hh [new file with mode: 0644]
note.cc [new file with mode: 0644]
notename.cc [new file with mode: 0644]
notename.hh [new file with mode: 0644]
parseconstruct.hh [new file with mode: 0644]
parser.y [new file with mode: 0644]
proto.hh [new file with mode: 0644]
pscore.cc [new file with mode: 0644]
pscore.hh [new file with mode: 0644]
pstaff.cc [new file with mode: 0644]
pstaff.hh [new file with mode: 0644]
qlp.cc [new file with mode: 0644]
qlp.hh [new file with mode: 0644]
qlpsolve.cc [new file with mode: 0644]
qlpsolve.hh [new file with mode: 0644]
real.hh [new file with mode: 0644]
request.cc [new file with mode: 0644]
request.hh [new file with mode: 0644]
rhythmstaf.cc [new file with mode: 0644]
rhythmstaf.hh [new file with mode: 0644]
score.cc [new file with mode: 0644]
score.hh [new file with mode: 0644]
smat.cc [new file with mode: 0644]
smat.hh [new file with mode: 0644]
staff.cc [new file with mode: 0644]
staff.hh [new file with mode: 0644]
suzan.ly [new file with mode: 0644]
symbol.cc [new file with mode: 0644]
symbol.ini [new file with mode: 0644]
symtable.cc [new file with mode: 0644]
symtable.hh [new file with mode: 0644]
table.cc [new file with mode: 0644]
template.cc [new file with mode: 0644]
template2.cc [new file with mode: 0644]
test.tex [new file with mode: 0644]
tex.cc [new file with mode: 0644]
tex.hh [new file with mode: 0644]
tstream.cc [new file with mode: 0644]
tstream.hh [new file with mode: 0644]
vector.cc [new file with mode: 0644]
vector.hh [new file with mode: 0644]
version.cc [new file with mode: 0644]
voice.cc [new file with mode: 0644]
voice.hh [new file with mode: 0644]
vsmat.hh [new file with mode: 0644]
warn.cc [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..eae32f8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,78 @@
+MAJVER=0
+MINVER=0
+PATCHLEVEL=1
+
+# 
+#
+
+include Sources.make
+progdocs=$(hdr) $(mycc)
+gencc=parser.cc lexer.cc
+cc=$(mycc) $(gencc)
+obs=$(cc:.cc=.o)
+
+
+#dist
+
+DOCDIR=docdir
+VERSION=$(MAJVER).$(MINVER).$(PATCHLEVEL)
+PACKAGENAME=lilypond
+DNAME=$(PACKAGENAME)-$(VERSION)
+othersrc=lexer.l parser.y
+OFILES=Makefile Sources.make symbol.ini suzan.ly depend lilyponddefs.tex test.tex make_version
+DFILES=$(hdr) $(mycc) $(othersrc) $(OFILES)
+
+#compiling
+LOADLIBES=-L$(FLOWERDIR) -lflower
+FLOWERDIR=../flower
+CXXFLAGS=-I$(FLOWERDIR) -pipe -Wall -g
+
+exe=$(PACKAGENAME)
+
+
+
+$(exe): $(obs)
+       $(CXX) -o $(exe) $(obs) $(LOADLIBES)
+clean:
+       rm -f $(exe) *.o $(DOCDIR)/* TAGS
+
+all: kompijl doc
+
+# doc++ documentation of classes
+doc:
+       -mkdir $(DOCDIR)
+       doc++ -p -I -d $(DOCDIR) $(progdocs)
+
+back:
+       zip -u ~/backs/spacer *cc *hh
+
+depend: Sources.make 
+       $(CXX) $(CXXFLAGS) -MM $(cc) > depend
+
+include depend
+
+parser.cc: parser.y
+       bison -d $<
+       mv parser.tab.h parser.hh
+       mv parser.tab.c parser.cc
+
+parser.hh: parser.cc
+
+version.o: $(obs) version.hh
+
+version.hh: Makefile make_version
+       make_version $(MAJVER) $(MINVER) $(PATCHLEVEL)  > version.hh
+
+lexer.cc: lexer.l
+       flex -+ -t lexer.l > lexer.cc
+
+DDIR=$(DNAME)
+dist:
+       -mkdir $(DDIR)
+       ln $(DFILES) $(DDIR)/
+       tar cfz $(DNAME).tar.gz $(DDIR)/*
+       rm -rf $(DDIR)/
+
+
+TAGS: $(mycc) $(hdr) Sources.make
+       etags -CT $(mycc) $(hdr) 
diff --git a/Sources.make b/Sources.make
new file mode 100644 (file)
index 0000000..8c6744f
--- /dev/null
@@ -0,0 +1,20 @@
+hdr=matrix.hh    qlp.hh       smat.hh      vsmat.hh\
+       linespace.hh   qlpsolve.hh  vector.hh\
+       cols.hh   proto.hh pstaff.hh  line.hh\
+       const.hh glob.hh molecule.hh  boxes.hh pscore.hh item.hh tex.hh\
+       request.hh voice.hh command.hh staff.hh  linestaff.hh \
+        tstream.hh dstream.hh mtime.hh rhythmstaf.hh\
+       parseconstruct.hh real.hh debug.hh globvars.hh keyword.hh\
+       misc.hh score.hh notename.hh lexer.hh symtable.hh\
+       choleski.hh
+
+mycc=smat.cc matrix.cc choleski.cc  qlp.cc qlpsolve.cc \
+        break.cc linespace.cc molecule.cc line.cc\
+       pscore.cc tex.cc item.cc cols.cc staff.cc rhythmstaf.cc\
+       score.cc note.cc dstream.cc main.cc misc.cc \
+       symbol.cc request.cc notename.cc  voice.cc\
+       keyword.cc linestaff.cc table.cc command.cc\
+       warn.cc debug.cc symtable.cc boxes.cc\
+       pstaff.cc vector.cc tstream.cc version.cc\
+       calcideal.cc\
+       template.cc template2.cc 
diff --git a/boxes.cc b/boxes.cc
new file mode 100644 (file)
index 0000000..e042c25
--- /dev/null
+++ b/boxes.cc
@@ -0,0 +1,22 @@
+#include "boxes.hh"
+#include "const.hh"
+
+void
+Interval:: set_empty() {
+       min = INFTY;
+       max = -INFTY;
+}
+
+Box::Box(svec<Real> s)
+{
+    assert(s.sz() == 4);
+    x.min = s[0];
+    x.max = s[1];
+    y.min = s[2];
+    y.max = s[3];
+}
+
+Box::Box()
+{
+    
+}
diff --git a/boxes.hh b/boxes.hh
new file mode 100644 (file)
index 0000000..4413169
--- /dev/null
+++ b/boxes.hh
@@ -0,0 +1,82 @@
+/*
+    some 2D geometrical concepts
+*/
+
+#ifndef BOXES_HH
+#define BOXES_HH
+
+#include "textdb.hh"
+#include "real.hh"
+#include "vray.hh"
+
+/// 2d vector 
+struct Offset {
+    Real x,y;
+
+    Offset operator+(Offset o)const {
+       Offset r(*this);
+       r+=o;
+       return r;
+    }
+    
+    Offset operator+=(Offset o) {
+       x+=o.x;
+       y+=o.y;
+       return *this;
+    }
+    Offset(Real ix , Real iy) {
+       x=ix;
+       y=iy;
+    }
+    Offset() {
+       x=0.0;
+       y=0.0;
+    }
+};
+
+/// a Real interval
+struct Interval {
+    Real min, max;
+
+    void translate(Real t) {
+       min += t;
+       max += t;
+    }
+
+    void unite(Interval h) {
+       if (h.min<min)
+           min = h.min;
+       if (h.max>max)
+           max = h.max;
+    }
+    
+    void set_empty() ;
+    bool empty() { return min > max; }
+    Interval() {
+       set_empty();
+    }
+    Interval(Real m, Real M) {
+       min =m;
+       max = M;
+    }
+};
+
+
+/// a 4-tuple of #Real#s
+struct Box {
+    Interval x, y;
+    
+    void translate(Offset o) {
+       x.translate(o.x);
+       y.translate(o.y);
+    }
+    void unite(Box b) {
+       x.unite(b.x);
+       y.unite(b.y);
+    }
+    Box(svec<Real> );
+    Box();
+};
+
+
+#endif
diff --git a/break.cc b/break.cc
new file mode 100644 (file)
index 0000000..8f76d13
--- /dev/null
+++ b/break.cc
@@ -0,0 +1,106 @@
+/*
+    do calculations for breaking problem
+    
+    */
+
+#include "linespace.hh"
+#include "debug.hh"
+#include "line.hh"
+#include "pscore.hh"
+
+// construct an appropriate Spacing_problem and solve it. 
+svec<Real>
+PScore::solve_line(svec<const PCol *> curline) const
+{
+   Spacing_problem sp;
+   //   mtor << "line of " << curline.sz() << " cols\n";
+   sp.add_column(curline[0], true, 0.0);
+   for (int i=1; i< curline.sz()-1; i++)
+       sp.add_column(curline[i]);
+   sp.add_column(curline.last(), true, linewidth);
+
+   // misschien  moeven uit Spacing_problem? 
+   for (PCursor<Idealspacing *> i(suz); i.ok(); i++) {
+       sp.add_ideal(i);
+   }
+   svec<Real> the_sol=sp.solve();
+   return the_sol;
+}
+
+
+void
+PScore::problem_OK() 
+{
+    if (!cols.size())
+       error("PScore::problem_OK(): Score does not have any columns");
+    PCursor<PCol *> start(cols);
+    PCursor<PCol *> end (cols.bottom());
+    
+    assert(start->breakable);    
+    assert(end->breakable);
+}
+
+struct Col_configuration {
+    svec<const PCol*> line;
+    svec<Real> config;
+    Real energy;
+
+    Col_configuration() {
+       energy = INFTY;
+    }
+    void add(const PCol*c) { line.add(c);}
+    void setsol(svec<Real> sol) {
+       config = sol;
+       energy = config.last();
+       config.pop();
+    }
+};
+
+/// wordwrap type algorithm
+/* el stupido. This should be optimised...
+    */
+
+void
+PScore::calc_breaking()
+{
+    problem_OK();
+    PCursor<PCol *> curcol(cols);
+           
+    svec<const PCol *> breakpoints(find_breaks());
+    assert(breakpoints.sz()>=2);
+    for (int i=0 ; i < breakpoints.sz() -1; ) {
+       Col_configuration minimum;
+       Col_configuration current;
+
+        // do  another line 
+       current.add(breakpoints[i]->postbreak );
+       curcol++;               // skip the breakable.
+       i++;
+
+       while (i < breakpoints.sz()) {
+
+           // add another measure.
+           while(breakpoints[i] !=curcol){
+               
+               current.add(curcol);
+               curcol++;
+           }
+           current.add(breakpoints[i]->prebreak );
+           current.setsol(solve_line(current.line));
+
+           
+           if (current.energy < minimum.energy) {
+               minimum = current;
+           } else {
+               break;
+           }
+       
+           current.line.last()=breakpoints[i];
+           curcol ++;
+           i++;
+       }
+
+       add_line(minimum.line, minimum.config); 
+    }
+}
+
diff --git a/calcideal.cc b/calcideal.cc
new file mode 100644 (file)
index 0000000..b1410ae
--- /dev/null
@@ -0,0 +1,64 @@
+#include "tstream.hh"
+#include "score.hh"
+#include "pscore.hh"
+#include "staff.hh"
+#include "misc.hh"
+#include "debug.hh"
+
+
+void
+Score::do_connect(PCol *c1, PCol *c2, Real d)
+{
+    Idealspacing*sp=pscore_->get_spacing(c1,c2);
+       
+    if (!sp->hooke){
+       sp->hooke = 1.0;
+       sp->space =d;
+    }
+}
+
+void
+Score::connect_nonmus(PCol* c1, PCol *c2, Real d)
+{
+    if (c2->used && c1->used) {
+       do_connect(c1,c2,d);
+
+       // alert! this is broken!
+       if (c1->breakable) {
+           do_connect(c1->postbreak, c2,d);
+       }
+       if (c2->breakable) {
+           do_connect(c1, c2->prebreak,d);
+       }
+       if (c1->breakable &&c2->breakable) {
+           do_connect(c1->postbreak, c2->prebreak,d);      
+       }       
+    }
+}
+/* this needs A LOT of rethinking.
+
+    generate springs between columns.
+    */
+void
+Score::calc_idealspacing()
+{
+    PCursor<Score_column*> sc(cols_);
+
+    for (; sc.ok(); sc++) {
+       if (sc->musical)
+           for (int i=0; i < sc->durations.sz(); i++) {
+               Mtime d = sc->durations[i];
+               Real dist = duration_to_idealspace(d);
+               PCol * c2 = find_col(sc->when + d,true)->pcol;
+               connect_nonmus(sc->pcol, c2, dist);
+               c2 = find_col(sc->when + d,false)->pcol;
+               connect_nonmus(sc->pcol, c2,  dist);
+           }
+       else if (sc->used()) {  // ignore empty columns
+           PCol * c2 = find_col(sc->when,true)->pcol;
+           connect_nonmus(sc->pcol,c2,0.0);
+       }
+    }          
+}
+
+
diff --git a/choleski.cc b/choleski.cc
new file mode 100644 (file)
index 0000000..db3fe82
--- /dev/null
@@ -0,0 +1,85 @@
+#include "choleski.hh"
+
+Vector
+Choleski_decomposition::solve(Vector rhs)const
+{
+    int n= rhs.dim();
+    assert(n == L.dim());
+    Vector y(n);
+
+    // forward substitution
+    for (int i=0; i < n; i++) {
+       Real sum(0.0);
+       for (int j=0; j < i; j++)
+           sum += y(j) * L(i,j);
+       y(i) = (rhs(i) - sum)/L(i,i);
+    }
+    for (int i=0; i < n; i++) {
+       assert(D(i));
+       y(i) /= D(i);
+    }
+    Vector x(n);
+    for (int i=n-1; i >= 0; i--) {
+       Real sum(0.0);
+       for (int j=i+1; j < n; j++)
+           sum += L(j,i)*x(j);
+       x(i) = (y(i) - sum)/L(i,i);
+    }
+    return x;
+}
+
+Choleski_decomposition::Choleski_decomposition(Matrix P)
+    : L(P.dim()), D(P.dim())
+{
+    int n = P.dim();
+    assert((P-P.transposed()).norm() < EPS);
+    L.unit();
+    for (int k= 0; k < n; k++) {
+       for (int j = 0; j < k; j++){
+           Real sum(0.0);
+           for (int l=0; l < j; l++)
+               sum += L(k,l)*L(j,l)*D(l);
+           L(k,j) = (P(k,j) - sum)/D(j);
+       }
+       Real sum=0.0;
+       
+       for (int l=0; l < k; l++)
+           sum += sqr(L(k,l))*D(l);
+       Real d = P(k,k) - sum;
+       D(k) = d;
+    }
+
+    #ifdef NDEBUG
+    assert((original()-P).norm() < EPS);
+    #endif
+}
+     
+Matrix
+Choleski_decomposition::original() const
+{
+    Matrix T(L.dim());
+    T.set_diag(D);
+    return L*T*L.transposed();
+}
+
+Matrix
+Choleski_decomposition::inverse() const
+{
+    int n=L.dim();
+    Matrix invm(n);
+    Vector e_i(n);
+    for (int i = 0; i < n; i++) {
+       e_i.set_unit(i);
+       Vector inv(solve(e_i));
+       for (int j = 0 ; j<n; j++)
+           invm(i,j) = inv(j);
+    }
+    
+#ifdef NDEBUG
+    Matrix I1(n), I2(original());
+    I1.unit();
+    assert((I1-original()*invm).norm() < EPS);
+    #endif
+    
+    return invm;
+}
diff --git a/choleski.hh b/choleski.hh
new file mode 100644 (file)
index 0000000..c6cb917
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef CHOLESKI_HH
+#define CHOLESKI_HH
+
+#include "matrix.hh"
+
+struct Choleski_decomposition {
+
+    /// lower triangle of Choleski decomposition
+    Matrix L;
+
+    /// diagonal 
+    Vector D;
+    ///Create decomposition of P
+    Choleski_decomposition(Matrix P);
+    /**
+    PRE
+    P needs to be symmetric positive definite
+    */
+    
+    Vector solve(Vector rhs) const;
+    Vector operator * (Vector rhs) const { return solve (rhs); }
+    /**
+    solve Px = rhs
+    */
+
+    Matrix inverse() const;
+    /**
+    return the inverse of the matrix P.
+    */
+
+    Matrix original() const;
+    /**
+    return P,  calc'ed from L and D
+    */
+        
+};
+/**
+    structure for using the LU decomposition of a positive definite .
+
+    #P# is split  into
+
+    LD transpose(L)
+    */
+    
+
+#endif
diff --git a/cols.cc b/cols.cc
new file mode 100644 (file)
index 0000000..e2a13f3
--- /dev/null
+++ b/cols.cc
@@ -0,0 +1,77 @@
+#include "cols.hh"
+#include "pstaff.hh"
+
+Idealspacing::Idealspacing(const PCol * l,const PCol * r)
+{
+    space = 0.0;
+    hooke = 0.0;
+    left = l;
+    right = r;
+}
+void
+Idealspacing::OK() const
+{
+    assert(hooke >= 0 && left  && right);
+}
+
+Interval
+PCol::width() const
+{
+    Interval w;
+
+    for (PCursor<const Item *> ic(its); ic.ok(); ic++)
+       w.unite(ic->width());
+    if (w.empty())
+       w.unite(Interval(0,0));
+    return w;
+}
+/****************************************************************/
+
+int
+PCol::compare(const PCol &c1, const PCol &c2)
+{
+    assert(false);
+}
+
+void
+PCol::OK () const
+{
+    if (prebreak || postbreak ) {
+       assert(breakable);
+    }
+}
+
+void
+PCol::set_breakable()
+{
+    if (breakable)
+       return;
+
+    prebreak = new PCol(this);
+    postbreak = new PCol(this);
+    breakable = true;
+    used = true;
+}
+
+PCol::PCol(PCol *parent) {
+    daddy = parent;
+    prebreak=0;
+    postbreak=0;
+    breakable=false;
+    line=0;
+    used  = false;
+}
+
+PCol::~PCol()
+{
+    delete prebreak;
+    delete postbreak;  
+}
+
+void
+PCol::add(const Item *i)
+{
+    its.bottom().add(i);
+    used = true;
+}
+
diff --git a/cols.hh b/cols.hh
new file mode 100644 (file)
index 0000000..e51e2d5
--- /dev/null
+++ b/cols.hh
@@ -0,0 +1,96 @@
+#ifndef COLS_HH
+#define COLS_HH
+
+#include "glob.hh"
+#include "boxes.hh"
+#include "list.hh"
+#include "item.hh"
+
+/// stuff grouped vertically.
+struct PCol {
+    List<const Item*> its;
+    List<const Spanner*> stoppers, starters;
+    
+    /// Can this be broken? true eg. for bars. 
+    bool breakable;
+
+    /// does this column have items, does it have spacings attached?
+    bool used;
+
+    /// prebreak is put before end of line.
+    PCol *prebreak;
+    /**
+    if broken here, then (*this) column is discarded, and prebreak
+    is put at end of line, owned by Col
+    */
+
+    /// postbreak at beginning of the new line
+    PCol *postbreak;
+    /**  \See{prebreak}
+    */
+    PCol *daddy;
+    /*
+    if this column is pre or postbreak, then this field points to the parent.
+    */
+    /// if lines are broken then this column is in #line#
+    const Line_of_score *line;
+
+    /// if lines are broken then this column x-coord #hpos#
+    Real hpos;
+
+
+    /****************************************************************/
+
+    void add(const Item*i);
+
+    Interval width() const;
+    ~PCol();
+    PCol(PCol * parent);
+    /// initialize the prebreak and postbreak fields
+    setup_breaks();
+    
+    /// which col comes first?
+    static int compare(const PCol &c1, const PCol &c2);
+    /**
+    signed compare on columns.
+
+    return < 0 if c1 < c2.
+    */
+
+    void OK() const;
+    void set_breakable();
+
+};
+/**
+    This is a class to address items vertically. It contains the data for:
+    \begin{itemize}
+    \item
+    unbroken score
+    \item
+    broken score
+    \item
+    the linespacing problem
+    \end{itemize}
+  */
+
+#include "compare.hh"
+instantiate_compare(const PCol &, PCol::compare);
+     
+
+/// ideal spacing between two columns
+struct Idealspacing {
+
+    /// the ideal distance
+    Real space;
+
+    /// Hooke's constant: how strong are the "springs" attached to columns
+    Real hooke;
+
+    /// the two columns
+    const PCol *left, *right;
+
+    void OK() const ;
+    Idealspacing(const PCol *left,const PCol *right);
+};
+
+#endif
diff --git a/command.cc b/command.cc
new file mode 100644 (file)
index 0000000..bb86e4f
--- /dev/null
@@ -0,0 +1,13 @@
+#include "string.hh"
+#include "command.hh"
+
+
+Command*
+get_bar_command(Real w)
+{
+    Command*c = new Command;
+    c->when = w;
+    c->code = TYPESET;
+    c->args.add( "|");
+    return c;
+}
diff --git a/command.hh b/command.hh
new file mode 100644 (file)
index 0000000..353bf5d
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef COMMAND_HH
+#define COMMAND_HH
+#include "glob.hh"
+#include "mtime.hh"
+#include "vray.hh"
+enum Commandcode {
+       NOP,
+       INTERPRET,
+       TYPESET,
+       BREAK_PRE,BREAK_MIDDLE, BREAK_POST, BREAK_END, 
+};
+/// set a nonrythmical symbol
+struct Command {
+    Commandcode code;
+
+    Mtime when;
+    /// analogous to argv[]
+    svec<String> args;
+};
+
+/**
+    A nonrhythmical "thing" in a  staff is called a "command".
+    Commands have these properties:
+
+    \begin{itemize}
+    \item They are \bf{not} rhythmical, i.e. they do not have  a duration
+    \item They have a staff-wide impact, i.e. a command cannot be targeted at
+    only one voice in the staff: two voices sharing a staff can't have
+    different clefs
+    \item Commands are ordered, that is, when from musical point of view the
+    commands happen simultaneously, the order in which Staff receives the
+    commands can still make a difference in the output
+    \item Some commands are actually score wide, so Score has to issue these
+    commands to the Staff, eg. BREAK commands
+    \end{itemize}
+
+    At this moment we have three classes of commands:
+    \begin{description}
+    INTERPRET commands are not grouped.
+    \item[TYPESET] These commands instruct the Staff to
+    typeset symbols on the output, eg meter/clef/key changes
+    \item[INTERPRET] These commands do not produce output, instead,
+    they change the interpretation of other commands or requests. 
+    example: shift output vertically, set the key.
+    \item[BREAK_XXX] These commands group TYPESET commands in
+    prebreak and postbreak commands. \See{Col}.    
+    Staff can insert additional commands in a sequence of BREAK_XXX
+    commands, eg. key change commands
+
+    \end{description}
+    
+    These commands are generated by Score, since they have to be the
+    same for the whole score.
+    
+
+    \begin{description}
+    \item[BREAK_PRE]
+    \item[BREAK_MIDDLE]
+    \item[BREAK_POST]
+    \item[BREAK_END]
+    \item[TYPESET] METER,BAR
+    \end{description}
+
+    Commands can be freely copied, they do not have virtual methods.
+    */
+
+
+#endif
diff --git a/const.hh b/const.hh
new file mode 100644 (file)
index 0000000..5a989e2
--- /dev/null
+++ b/const.hh
@@ -0,0 +1,11 @@
+/*
+    global constants
+    */
+
+
+const Real CM_TO_PT=72/2.54;
+const Real VERT_TO_PT=CM_TO_PT;        // tex output
+const Real HOR_TO_PT=CM_TO_PT; // tex output
+const Real EPS=1e-7;           // qlpsolve.hh
+const int MAXITER=100;         // qlpsolve.hh
+const Real INFTY=1e8;
diff --git a/debug.cc b/debug.cc
new file mode 100644 (file)
index 0000000..548a76c
--- /dev/null
+++ b/debug.cc
@@ -0,0 +1,15 @@
+#include "debug.hh"
+int debug_flags;
+
+void
+set_debug(String s)
+{
+    if (s.pos ('t')) {
+       debug_flags |= DEBUGTOKEN;
+       mtor << " Turning on token debug\n";
+    }
+    if (s.pos ('p')){
+       debug_flags |= DEBUGPARSER;
+       mtor << "Turning on parser debugger\n";
+    }
+}
diff --git a/debug.hh b/debug.hh
new file mode 100644 (file)
index 0000000..fce60a9
--- /dev/null
+++ b/debug.hh
@@ -0,0 +1,25 @@
+#ifndef DEBUG_HH
+#define DEBUG_HH
+#include <assert.h>
+#include <iostream.h>
+#include "dstream.hh"
+
+
+
+#define WARN warnout << "warning: "<<__FUNCTION__ << ": "
+extern ostream &warnout ;
+extern ostream *mlog;  
+extern dstream mtor; // monitor
+
+void error(String s);
+void warning(String s);
+
+extern int debug_flags;
+
+void
+set_debug(String s);
+const int DEBUGPARSER = 0x01;
+const int DEBUGTOKEN = 0x02;
+const int DEBUGITEMS = 0x04;
+
+#endif
diff --git a/depend b/depend
new file mode 100644 (file)
index 0000000..fdb5ace
--- /dev/null
+++ b/depend
@@ -0,0 +1,179 @@
+smat.o: smat.cc smat.hh ../flower/vray.hh vsmat.hh real.hh
+matrix.o: matrix.cc matrix.hh vsmat.hh ../flower/vray.hh real.hh \
+ vector.hh glob.hh proto.hh const.hh ../flower/string.hh \
+ ../flower/stringutil.hh debug.hh dstream.hh
+choleski.o: choleski.cc choleski.hh matrix.hh vsmat.hh \
+ ../flower/vray.hh real.hh vector.hh glob.hh proto.hh const.hh
+qlp.o: qlp.cc debug.hh dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh qlp.hh matrix.hh vsmat.hh ../flower/vray.hh \
+ real.hh vector.hh glob.hh proto.hh const.hh choleski.hh
+qlpsolve.o: qlpsolve.cc qlpsolve.hh qlp.hh matrix.hh vsmat.hh \
+ ../flower/vray.hh real.hh vector.hh glob.hh proto.hh const.hh \
+ debug.hh dstream.hh ../flower/string.hh ../flower/stringutil.hh \
+ choleski.hh
+break.o: break.cc linespace.hh glob.hh real.hh proto.hh const.hh \
+ ../flower/list.hh ../flower/list.inl ../flower/cursor.hh \
+ ../flower/link.hh ../flower/link.inl ../flower/cursor.inl \
+ ../flower/vray.hh cols.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/string.hh ../flower/stringutil.hh \
+ item.hh tex.hh ../flower/compare.hh matrix.hh vsmat.hh vector.hh \
+ debug.hh dstream.hh line.hh pstaff.hh pscore.hh
+linespace.o: linespace.cc linespace.hh glob.hh real.hh proto.hh \
+ const.hh ../flower/list.hh ../flower/list.inl ../flower/cursor.hh \
+ ../flower/link.hh ../flower/link.inl ../flower/cursor.inl \
+ ../flower/vray.hh cols.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/string.hh ../flower/stringutil.hh \
+ item.hh tex.hh ../flower/compare.hh matrix.hh vsmat.hh vector.hh \
+ debug.hh dstream.hh qlp.hh ../flower/unionfind.hh
+molecule.o: molecule.cc glob.hh real.hh proto.hh const.hh \
+ ../flower/string.hh ../flower/stringutil.hh molecule.hh \
+ ../flower/list.hh ../flower/list.inl ../flower/cursor.hh \
+ ../flower/link.hh ../flower/link.inl ../flower/cursor.inl boxes.hh \
+ ../flower/textdb.hh ../flower/textstr.hh ../flower/vray.hh item.hh \
+ tex.hh
+line.o: line.cc line.hh real.hh ../flower/list.hh ../flower/list.inl \
+ ../flower/cursor.hh ../flower/link.hh ../flower/link.inl \
+ ../flower/cursor.inl ../flower/vray.hh glob.hh proto.hh const.hh \
+ pstaff.hh item.hh boxes.hh ../flower/textdb.hh ../flower/textstr.hh \
+ ../flower/string.hh ../flower/stringutil.hh tex.hh cols.hh \
+ ../flower/compare.hh pscore.hh
+pscore.o: pscore.cc debug.hh dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh line.hh real.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl ../flower/vray.hh glob.hh \
+ proto.hh const.hh pstaff.hh item.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh tex.hh pscore.hh cols.hh ../flower/compare.hh \
+ tstream.hh
+tex.o: tex.cc tex.hh ../flower/string.hh ../flower/stringutil.hh \
+ boxes.hh ../flower/textdb.hh ../flower/textstr.hh ../flower/vray.hh \
+ real.hh const.hh
+item.o: item.cc line.hh real.hh ../flower/list.hh ../flower/list.inl \
+ ../flower/cursor.hh ../flower/link.hh ../flower/link.inl \
+ ../flower/cursor.inl ../flower/vray.hh glob.hh proto.hh const.hh \
+ pstaff.hh item.hh boxes.hh ../flower/textdb.hh ../flower/textstr.hh \
+ ../flower/string.hh ../flower/stringutil.hh tex.hh cols.hh \
+ ../flower/compare.hh
+cols.o: cols.cc cols.hh glob.hh real.hh proto.hh const.hh boxes.hh \
+ ../flower/textdb.hh ../flower/textstr.hh ../flower/string.hh \
+ ../flower/stringutil.hh ../flower/vray.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl item.hh tex.hh \
+ ../flower/compare.hh
+staff.o: staff.cc staff.hh score.hh ../flower/vray.hh cols.hh glob.hh \
+ real.hh proto.hh const.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/string.hh ../flower/stringutil.hh \
+ ../flower/list.hh ../flower/list.inl ../flower/cursor.hh \
+ ../flower/link.hh ../flower/link.inl ../flower/cursor.inl item.hh \
+ tex.hh ../flower/compare.hh mtime.hh command.hh voice.hh request.hh \
+ debug.hh dstream.hh pscore.hh pstaff.hh
+rhythmstaf.o: rhythmstaf.cc request.hh glob.hh real.hh proto.hh \
+ const.hh ../flower/string.hh ../flower/stringutil.hh mtime.hh \
+ debug.hh dstream.hh linestaff.hh pstaff.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl item.hh boxes.hh \
+ ../flower/textdb.hh ../flower/textstr.hh ../flower/vray.hh tex.hh \
+ staff.hh score.hh cols.hh ../flower/compare.hh command.hh voice.hh \
+ pscore.hh molecule.hh rhythmstaf.hh
+score.o: score.cc tstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh score.hh ../flower/vray.hh cols.hh glob.hh \
+ real.hh proto.hh const.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/list.hh ../flower/list.inl \
+ ../flower/cursor.hh ../flower/link.hh ../flower/link.inl \
+ ../flower/cursor.inl item.hh tex.hh ../flower/compare.hh mtime.hh \
+ command.hh pscore.hh pstaff.hh staff.hh voice.hh request.hh misc.hh \
+ debug.hh dstream.hh
+note.o: note.cc ../flower/string.hh ../flower/stringutil.hh real.hh \
+ debug.hh dstream.hh request.hh glob.hh proto.hh const.hh mtime.hh \
+ voice.hh ../flower/list.hh ../flower/list.inl ../flower/cursor.hh \
+ ../flower/link.hh ../flower/link.inl ../flower/cursor.inl notename.hh
+dstream.o: dstream.cc dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh
+main.o: main.cc ../flower/lgetopt.hh misc.hh mtime.hh real.hh debug.hh \
+ dstream.hh ../flower/string.hh ../flower/stringutil.hh score.hh \
+ ../flower/vray.hh cols.hh glob.hh proto.hh const.hh boxes.hh \
+ ../flower/textdb.hh ../flower/textstr.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl item.hh tex.hh \
+ ../flower/compare.hh command.hh globvars.hh
+misc.o: misc.cc misc.hh mtime.hh real.hh glob.hh proto.hh const.hh
+symbol.o: symbol.cc tex.hh ../flower/string.hh ../flower/stringutil.hh \
+ boxes.hh ../flower/textdb.hh ../flower/textstr.hh ../flower/vray.hh \
+ real.hh
+request.o: request.cc request.hh glob.hh real.hh proto.hh const.hh \
+ ../flower/string.hh ../flower/stringutil.hh mtime.hh
+notename.o: notename.cc glob.hh real.hh proto.hh const.hh \
+ ../flower/string.hh ../flower/stringutil.hh
+voice.o: voice.cc debug.hh dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh voice.hh mtime.hh real.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl request.hh glob.hh proto.hh \
+ const.hh
+keyword.o: keyword.cc glob.hh real.hh proto.hh const.hh lexer.hh
+linestaff.o: linestaff.cc linestaff.hh pstaff.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl item.hh glob.hh real.hh \
+ proto.hh const.hh boxes.hh ../flower/textdb.hh ../flower/textstr.hh \
+ ../flower/string.hh ../flower/stringutil.hh ../flower/vray.hh tex.hh
+table.o: table.cc glob.hh real.hh proto.hh const.hh \
+ ../flower/string.hh ../flower/stringutil.hh keyword.hh parser.hh
+command.o: command.cc ../flower/string.hh ../flower/stringutil.hh \
+ command.hh glob.hh real.hh proto.hh const.hh mtime.hh \
+ ../flower/vray.hh
+warn.o: warn.cc debug.hh dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh
+debug.o: debug.cc debug.hh dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh
+symtable.o: symtable.cc misc.hh mtime.hh real.hh debug.hh dstream.hh \
+ ../flower/string.hh ../flower/stringutil.hh tex.hh boxes.hh \
+ ../flower/textdb.hh ../flower/textstr.hh ../flower/vray.hh \
+ ../flower/assoc.hh symtable.hh const.hh
+boxes.o: boxes.cc boxes.hh ../flower/textdb.hh ../flower/textstr.hh \
+ ../flower/string.hh ../flower/stringutil.hh ../flower/vray.hh real.hh \
+ const.hh
+pstaff.o: pstaff.cc pstaff.hh ../flower/list.hh ../flower/list.inl \
+ ../flower/cursor.hh ../flower/link.hh ../flower/link.inl \
+ ../flower/cursor.inl item.hh glob.hh real.hh proto.hh const.hh \
+ boxes.hh ../flower/textdb.hh ../flower/textstr.hh ../flower/string.hh \
+ ../flower/stringutil.hh ../flower/vray.hh tex.hh
+vector.o: vector.cc debug.hh dstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh vector.hh glob.hh real.hh proto.hh const.hh \
+ ../flower/vray.hh
+tstream.o: tstream.cc tex.hh ../flower/string.hh \
+ ../flower/stringutil.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/vray.hh real.hh tstream.hh debug.hh \
+ dstream.hh
+version.o: version.cc ../flower/string.hh ../flower/stringutil.hh
+calcideal.o: calcideal.cc tstream.hh ../flower/string.hh \
+ ../flower/stringutil.hh score.hh ../flower/vray.hh cols.hh glob.hh \
+ real.hh proto.hh const.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/list.hh ../flower/list.inl \
+ ../flower/cursor.hh ../flower/link.hh ../flower/link.inl \
+ ../flower/cursor.inl item.hh tex.hh ../flower/compare.hh mtime.hh \
+ command.hh pscore.hh pstaff.hh staff.hh voice.hh request.hh misc.hh \
+ debug.hh dstream.hh
+template.o: template.cc line.hh real.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl ../flower/vray.hh glob.hh \
+ proto.hh const.hh pstaff.hh item.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/string.hh ../flower/stringutil.hh \
+ tex.hh cols.hh ../flower/compare.hh request.hh mtime.hh score.hh \
+ command.hh staff.hh voice.hh ../flower/list.cc ../flower/cursor.cc
+template2.o: template2.cc line.hh real.hh ../flower/list.hh \
+ ../flower/list.inl ../flower/cursor.hh ../flower/link.hh \
+ ../flower/link.inl ../flower/cursor.inl ../flower/vray.hh glob.hh \
+ proto.hh const.hh pstaff.hh item.hh boxes.hh ../flower/textdb.hh \
+ ../flower/textstr.hh ../flower/string.hh ../flower/stringutil.hh \
+ tex.hh voice.hh mtime.hh request.hh molecule.hh staff.hh score.hh \
+ cols.hh ../flower/compare.hh command.hh ../flower/list.cc \
+ ../flower/cursor.cc
+parser.o: parser.cc lexer.hh proto.hh real.hh staff.hh score.hh \
+ ../flower/vray.hh cols.hh glob.hh const.hh boxes.hh \
+ ../flower/textdb.hh ../flower/textstr.hh ../flower/string.hh \
+ ../flower/stringutil.hh ../flower/list.hh ../flower/list.inl \
+ ../flower/cursor.hh ../flower/link.hh ../flower/link.inl \
+ ../flower/cursor.inl item.hh tex.hh ../flower/compare.hh mtime.hh \
+ command.hh voice.hh request.hh keyword.hh globvars.hh debug.hh \
+ dstream.hh parseconstruct.hh
+lexer.o: lexer.cc glob.hh real.hh proto.hh const.hh \
+ ../flower/string.hh ../flower/stringutil.hh lexer.hh keyword.hh \
+ ../flower/vray.hh parser.hh debug.hh dstream.hh
diff --git a/dstream.cc b/dstream.cc
new file mode 100644 (file)
index 0000000..197e530
--- /dev/null
@@ -0,0 +1,46 @@
+// implementation of debug/TeX stream.
+#include <fstream.h>
+
+#include "dstream.hh"
+#include "string.hh"
+
+
+
+dstream mtor(cout);
+
+///
+dstream &
+dstream::operator<<(String s)
+{       
+    for (const char *cp = s  ; *cp; cp++)
+       switch(*cp) 
+           {
+           case '{':
+           case '[':
+           case '(': indentlvl += INDTAB;
+               *os << *cp;             
+               break;
+               
+           case ')':
+           case ']':
+           case '}':
+               indentlvl -= INDTAB;
+               *os << *cp              ;
+               
+               if  (indentlvl<0) indentlvl = 0;
+               break;
+               
+           case '\n':
+               *os << '\n' << String (' ', indentlvl) << flush;
+               break;        
+           default:
+               *os << *cp;
+               break;
+           }
+    return *this;
+    
+}
+
+/** only output possibility. Delegates all conversion to String class.
+ */
+
diff --git a/dstream.hh b/dstream.hh
new file mode 100644 (file)
index 0000000..3a47a84
--- /dev/null
@@ -0,0 +1,29 @@
+// debug_stream
+
+#ifndef DSTREAM_HH
+#define DSTREAM_HH
+
+#include "string.hh"
+
+const char eol= '\n';
+
+/// debug stream
+class dstream
+{
+    ostream *os;
+    int indentlvl;
+
+    /// indent of each level 
+    const INDTAB = 3;
+public:
+    dstream(ostream &r){
+       os = &r;
+       indentlvl = 0;  
+    }
+    dstream &operator << (String s);
+};
+ /**
+   a class for providing debug output of nested structures,
+   with indents according to \{\}()[]
+  */     
+#endif
diff --git a/flower/Makefile b/flower/Makefile
new file mode 100644 (file)
index 0000000..5fb4f2a
--- /dev/null
@@ -0,0 +1,43 @@
+MAJVER=1
+MINVER=0
+PATCHLEVEL=1
+
+PACKAGENAME=flower
+VERSION=$(MAJVER).$(MINVER).$(PATCHLEVEL)
+DNAME=$(PACKAGENAME)-$(VERSION)
+CXXFLAGS+=-g -Wall
+
+cc=lgetopt.cc   string.cc dataf.cc textdb.cc unionfind.cc 
+
+templatecc=cursor.cc list.cc 
+inl=findcurs.inl link.inl list.inl
+hh=cursor.hh cursor.inl lgetopt.hh link.hh list.hh \
+       string.hh stringutil.hh vray.hh textdb.hh textstr.hh  assoc.hh\
+       findcurs.hh unionfind.hh compare.hh handle.hh
+
+
+
+obs=$(cc:.cc=.o)
+staticlib=libflower.a
+$(staticlib): $(obs)
+       ar cr libflower.a $(obs)
+
+include depend
+
+depend: Makefile
+       $(CXX) -MM $(cc) > depend
+
+
+clean:
+       rm depend $(obs) $(staticlib)
+
+DFILES=$(hh) $(cc) $(inl) $(templatecc) Makefile
+DDIR=$(DNAME)
+
+dist:
+       -mkdir $(DDIR)
+       ln $(DFILES) $(DDIR)/
+       tar cfz $(DNAME).tar.gz $(DDIR)/*
+       rm -rf $(DDIR)/
+
+       
diff --git a/flower/assoc.hh b/flower/assoc.hh
new file mode 100644 (file)
index 0000000..a217302
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef ASSOC_HH
+#define ASSOC_HH
+
+#include "vray.hh"
+
+template<class K,class V>
+struct Assoc_ent_ {
+    bool free;
+    K key;
+    V val;
+};
+
+template<class K, class V>
+struct Assoc {
+    svec< Assoc_ent_<K,V> > arr;
+
+    /****************/
+    
+    int find(K key) const {
+       for (int i = 0; i < arr.sz(); i++) {
+           if (!arr[i].free && key == arr[i].key)
+               return i;
+       }
+       return -1;
+    }
+    int find_creat(K key) {
+       int free = -1;
+       for (int i = 0; i < arr.sz(); i++) {
+           if (key == arr[i].key) {            
+               return i;
+           } else if (arr[i].free ) {
+               free = i;
+           }
+       }
+       if (free >= 0){
+           arr[free].free = false;
+           arr[free].key = key;
+           return free;
+       }
+
+       Assoc_ent_<K,V> ae;
+       ae.free = false;
+       ae.key = key;
+       arr.add(ae);
+       return arr.sz() -1;
+    }
+public:
+    bool elt_query(K key) const {
+       return find(key) >= 0;
+    }
+    void del(K key) {
+       assert(elt_query(key));
+       int i= find(key);
+       arr[i].free = true;
+    }
+    void
+    add(K key, V val) {
+       int i = find_creat(key);
+       arr[i].val = val;
+    }
+    /**
+    should create "set" template
+    */
+    V& operator[](K key) {
+       return arr[find_creat(key)].val;
+    }
+    const V& operator[](K key) const {
+       assert(elt_query(key));
+       return arr[find(key)].val;
+    }
+
+};
+#endif
diff --git a/flower/compare.hh b/flower/compare.hh
new file mode 100644 (file)
index 0000000..05b6e89
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef COMPARE_HH
+#define COMPARE_HH
+
+/// handy notations for a signed comparison
+#define instantiate_compare(type, function)                            \
+inline bool operator>(type t1, type t2) { return function(t1, t2) > 0; }       \
+ inline bool operator>=(type t1, type t2) { return function(t1, t2) >= 0; }    \
+ inline bool operator==(type t1, type t2) { return function(t1, t2) == 0; }    \
+ inline bool operator<=(type t1, type t2) { return function(t1, t2) <= 0; }    \
+ inline bool operator<(type t1, type t2) { return function(t1, t2) < 0; } \
+ inline type MAX(type t1, type t2) {  return (t1 > t2 )? t1 : t2; }\
+ inline type MIN(type t1, type t2) {  return (t1 < t2 )? t1 : t2; }\
+  \
+  bool operator<(type t1, type t2) /* stupid fix to allow ; */
+     /**
+    make the operators{<,<=,==,>=,>} and the MAX and MIN of two.
+    Please fill a & in the type argument if necessary.    
+    */
+
+     
+
+     
+#endif
+     
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.hh b/flower/cursor.hh
new file mode 100644 (file)
index 0000000..b053591
--- /dev/null
@@ -0,0 +1,125 @@
+// cursor.hh
+
+#ifndef __CURSOR_HH
+#define __CURSOR_HH
+
+#include "link.hh"
+template<class T> class List;
+
+///
+template<class T>
+class Cursor 
+{
+ public:
+    Cursor( List<T>& list, Link<T>* pointer = 0 );
+    Cursor( const Cursor<T>& cursor );
+    
+    /// return current T
+    T& operator *();           
+    operator T() { return  *(*this); }
+    Cursor<T> operator =( const Cursor<T>& c );
+
+    /// make cursor with #no# items back
+    Cursor<T> operator -( int no) const;
+
+    /// make cursor with #no# items further
+    Cursor<T> operator +( int no) const;
+
+    Cursor<T> operator -=(int);
+    Cursor<T> operator +=(int);
+    
+    /// return current and move one down
+    Cursor<T> operator ++( int );
+    
+    /// return current and move one up
+    Cursor<T> operator --( int ); 
+
+    /// point to link?
+    bool ok();                  
+
+    /// ++ items left?
+    bool forward();            
+
+    /// -- items left?
+    bool backward();
+
+    /// put (copy) after me in List
+    void add( const T& thing );
+    /**
+      analogously to editor. ok() interpreted as at end
+      of line.
+
+      PRE: !ok, POST: added to bottom()
+
+      PRE: ok, POST: added after me
+
+      cursor points to same object, cursor.next() is newly added
+      object.
+      */
+
+    /// put (copy) before me in List
+    void insert( const T& thing );
+    /**
+      analogously to editor. ok() interpreted as at begin of
+      line.
+      
+      PRE: !ok, POST: add to top()
+
+      PRE: ok, POST: add before me
+
+      cursor points to same object, cursor.previous()
+      is newly inserted object.
+      */
+    /// remove and cleanup Link // HWN: backspace or del?
+    void remove();             
+
+    /// access the list this came from
+    const List<T>& list() const ;
+    Link<T>* pointer();
+    
+private:
+    List<T>& list_;
+    Link<T>* pointer_;
+};
+
+
+/** 
+  add and insert extend the list
+  items are always stored as copies in List, but:
+  List<String> :  copies of String stored 
+  List<String*> : copies of String* stored!
+
+    the operations add and insert actually delegate the work to List class.
+ */
+
+
+
+/// cursor which feels like a pointer
+template<class T>
+struct PCursor : public Cursor<T> {
+
+    /// make cursor with #no# items back
+    PCursor<T> operator -( int no) const {
+       return PCursor<T> (Cursor<T>::operator-(no));
+    }
+
+    /// make cursor with #no# items further
+    PCursor<T> operator +( int no) const {
+       return PCursor<T> (Cursor<T>::operator+(no));
+    }
+    PCursor(List<T> & l) : Cursor<T> (l) {}
+
+    PCursor( const Cursor<T>& cursor ) : Cursor<T>(cursor) { }
+    T operator ->() { return  *(*this); }
+
+};
+/**
+ HWN: I'd like an operator->(), so here it is.
+
+ Cursor to go with pointer list.
+ */
+
+#include "list.hh"
+#include "cursor.inl"
+
+#endif // __CURSOR_HH //
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/handle.hh b/flower/handle.hh
new file mode 100644 (file)
index 0000000..3257399
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef HANDLE_HH
+#define HANDLE_HH
+/// reference counting handle
+template<class T>
+class Handle {
+    T *obj;
+    int *refs;
+
+    /// let go of ref. Delete if necessary
+    void down() {
+       if (!(*refs--)) {
+           delete obj;
+           delete refs;
+       }
+       obj = 0;
+       refs = 0;
+    }
+    /// point to new object. 
+    void up(T *t, int *r=0) {
+       if (!r) {
+           refs = new int;
+           *refs = 1;
+       } else {
+           refs =r;
+           *refs++;
+       }
+       obj = t;
+    }
+    /// POST: *refs == 1
+    void copy() {
+       if(*refs != 1){
+           T * newobj = new T(*obj );
+           down();
+           up(newobj);
+       }
+    }
+    Handle(Handle const &src) {
+       up(src.obj, src.refs);
+    }
+    Handle(T & o) {
+       up (&o);
+    }
+    void operator=(Handle const& src) {
+       if (this == &src)
+           return;
+       down();
+       up(src.o, src.refs);
+    }
+    operator const T&() {
+       return *obj;
+    }
+    operator T&() {
+       copy();
+       return *obj;
+    }
+}
+#endif
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/string.cc b/flower/string.cc
new file mode 100644 (file)
index 0000000..da4941d
--- /dev/null
@@ -0,0 +1,395 @@
+/****************************************************************************
+  PROJECT: FlowerSoft C++ library
+  FILE   : string.cc
+
+  Rehacked by HWN 3/nov/95
+  removed String &
+  introduced Class String_handle
+--*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+//#include "globals.hh"
+#include "string.hh"
+
+char* strlwr( char* s )
+{
+    char* p = s;
+
+    while( *p )
+        {
+        *p = tolower( *p );    /* a macro on some compilers */
+        p++;
+        }
+    return s;
+}
+
+char* strupr( char* s )
+{
+    char* p = s;
+
+    while( *p )
+        {
+        *p = toupper( *p );    /* a macro on some compilers */
+        p++;
+        }
+    return s;
+}
+
+// return array, alloced with new.
+char *
+String::copy_array() const
+{
+    const char *src = data;
+    char *dest = new char[data.len() + 1];
+    strcpy(dest, src);
+    return dest;    
+}
+
+void
+String::printOn(ostream& os) const
+{
+    os << (const char*) data;
+}
+
+String::String (bool b)
+{
+    *this = (const char *) (b ? "true" : "false");
+}
+String::String( const char* source )
+{   
+    assert(source);    
+    data = source;    
+}
+
+void
+String::operator +=(String s)
+{
+    *this += (const char *) s;
+}
+
+int
+String::len() const
+{
+    return data.len();
+}
+
+String::String(char c,  int n)
+{
+    int l = n;
+    assert(n >= 0 && n <= 80); // what the fuck is 80?
+//min(max( n, 0 ), 80); 
+    char s[81];
+    memset(s, c, l);
+    s[l] = 0;
+    data = s;
+}
+
+String::String(int i)
+{
+    char digits[ 81 ];             // who the FUCK is 80???
+    digits[ 0 ] = '\0';
+    sprintf(digits, "%d", i );     // assume radix 10
+    data = digits;
+}
+
+String::String( const int i, const int n, const char c )
+{
+    char fillChar = c;
+    if ( fillChar)
+        fillChar = '0';
+
+    String v( i );
+    
+    data = String( fillChar, n - v.len() ) + String( v );
+    // String convd to const char *
+}
+
+ const char*
+String::ptr() const
+{
+    return data;
+}
+
+
+
+#ifdef CENTRAL_OBJECT // everything derived from Sortable object
+// comparisons.
+int
+String::operator ==( const Sortable& test ) const
+{
+    const String *s = (const String *) &test; 
+    return *this == *s;
+}
+
+int
+String::operator &&(const Object& test) const
+{
+    const String *s = (const String *) &test;
+    
+    int i = min( len(), s->len() );
+    return ( i > 0 ) ?
+        ( !strncmp( data, s->data, i ) ) : 0;
+}
+
+int
+String::operator >( const Sortable& test ) const
+{
+    const String *s = (const String *) &test;
+    return strcmp( data, s->data ) > 0;
+}
+#endif
+
+// signed comparison,  analogous to strcmp;
+int
+String::compare( const char* test ) const
+{
+    if (test == (const char *) data)
+       return 0;
+
+    return strcmp(data, test);
+}
+
+
+int
+String::lastPos( const char c ) const
+{
+    const char *me = data;
+    int pos = 0;
+    if ( len() )
+        {
+       const char* p = strrchr(me, c );
+        if ( p )
+            pos = p - me + 1;
+        }
+    return pos;
+}
+
+int
+String::lastPos( const char* string ) const
+{
+    int pos = 0;
+    int length = strlen( string );
+    if ( len() && length )
+        {
+        int nextpos = this->pos( string );
+        while( nextpos )
+            {
+            pos += nextpos;
+            nextpos = right( len() - pos - length + 1 ).pos( string );
+            }
+        }
+    return pos;
+}
+
+// find c
+// return 0 if not found. 
+
+// ? should return len()?, as in string.left(pos(delimiter))
+int
+String::pos(char c ) const
+{
+    const char *me = data;
+    int pos = 0;
+    if ( len() )
+        {
+       const char* p = strchr( me, c );
+        if ( p )
+            pos = p - me + 1;
+        }
+    return pos;
+}
+
+// find searchfor. (what if this == "" && searchfor == "") ???
+int
+String::pos( const char* searchfor ) const
+{
+    const char *me = data;
+    int pos = 0;
+    if ( len() && searchfor)
+        {
+       const char* p = strstr(me, searchfor);
+        if ( p )
+           pos = p - me + 1;
+        }
+    return pos;
+}
+
+// find chars of a set.
+int
+String::posAny( const char* string ) const
+{
+    int pos = 0;
+    const char *s = (const char *)data;
+    if ( len() && string )
+        {
+       const char* p = strpbrk( s, string );
+        if ( p )
+           pos = p - s + 1;
+        }
+    return pos;
+}
+
+String
+String::left( int n ) const
+{
+    if (n >= len())
+       return *this;
+
+    String retval;     
+    if (n < 1)
+        return retval;
+    
+    retval = *this;
+    retval.data.trunc(n);
+    return retval;
+}
+
+
+// n rightmst chars
+String
+String::right( int n ) const
+{
+    if (n > len())
+       return *this;
+    
+    String retval;
+    if ( n < 1)
+        return retval;
+    
+    const char *src = (const char *)data + len() - n; 
+    retval += src;
+
+    return retval;
+}
+
+
+String
+String::nomid( const int pos, const int n ) const
+{
+    String retval;
+        
+    if ( pos < 1 )
+        return String("");
+    if ( pos > len())
+       return *this;
+    
+    return String( String( left( pos - 1 ) ) + right( len() - pos - n + 1 ));
+}
+
+
+String
+String::mid( int pos, int n ) const
+{
+    String retval;
+
+    // HWN. This SUX:
+    // pos 1 == data->string[ 0 ];
+    // pos 0 allowed for convenience
+    if ( !len() || ( pos < 0 ) || ( pos > len() ) && ( n < 1 ) )
+        return retval;
+
+    retval = ((const char *) data) + pos -1;
+    if (n > retval.len())
+       n =retval.len();
+    retval.data.trunc(n);
+    return retval;
+}
+
+
+// to  uppercase
+String
+String::upper()
+{
+    char *s = data.array_for_modify();
+    strupr(s );
+    return *this;
+}
+
+
+// to lowercase
+String String::lower()
+{
+    char  *s = data.array_for_modify();
+    strlwr(s);
+    return *this;
+}
+
+String::String (double f, const char *fmt)
+{
+    char buf[100]; // ugly
+    if (!fmt)
+       sprintf(buf, "%f", f);
+    else
+       sprintf(buf, fmt,f);
+    *this = buf;
+}
+
+long
+String::value() const
+{
+    long l =0;
+    if (len()) {
+       int conv = sscanf(data, "%ld", &l);
+       assert(conv);
+    }
+    return l;
+}
+
+double
+String::fvalue() const
+{
+    double d =0;
+    if (len()) {
+       int conv = sscanf(data, "%lf", &d);
+       assert(conv);
+    }
+    return d;
+}
+
+
+String quoteString( String msg, String quote)
+{
+    return msg + " `" + quote  + "' ";
+}
+
+
+char *strrev(char *s)
+{
+  char c;
+  char *p = s;
+  char *q = s + strlen(s) - 1;
+
+  while (q > p) {
+    c = *p;
+    *p++ = *q;
+    *q-- = c;
+  }
+  return s;
+}
+
+
+String 
+String::reversed() const
+{
+    String retval=*this;
+    char  *s = retval.data.array_for_modify();
+    strrev(s);
+    return retval;    
+}
+bool
+String::to_bool() const
+{
+    if (!len())
+       return false;
+    if (*this == "0")
+       return false;
+    String u (*this);
+    u.upper();
+    if (u== "FALSE")
+       return false;
+    return true;
+}
diff --git a/flower/string.hh b/flower/string.hh
new file mode 100644 (file)
index 0000000..d3d2774
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+
+  FILE   : string.hh -- implement String inline helper classes,
+   and declare stringclass.
+  Rehacked by HWN 3/nov/95
+  removed String & 's
+  introduced Class String_handle
+ */
+
+#ifndef STRING_HH
+#define STRING_HH
+
+
+#include <string.h>
+#include <iostream.h>
+
+
+#include "stringutil.hh"
+
+/// the smart string class.
+class String
+{
+protected:
+    String_handle data; // should derive String from String_handle?
+
+public:
+    /// init to ""
+    String() {  }                  
+    /** needed because other constructors are provided.*/
+
+    /// String s = "abc";
+    String( const char* source ); 
+    
+    /// "ccccc"
+    String( char c, int n = 1 );
+
+    /// String s( 10 );
+    String( int i );
+
+    /// 'true' or 'false'
+    String(bool );
+
+    /// String s( 3.14, 6, '#' );
+    String ( double f , const char *fmt =0);
+    String(  int i,  int n,  char c = ' ' );
+
+    ///  return a "new"-ed copy of contents
+    char *copy_array() const; //  return a "new"-ed copy of contents
+
+    const char *ptr() const;
+    /// return the data. Don't use for writing the data.
+    operator const char *() const { return ptr(); }
+    
+    String operator =( const String & source ) { data = source.data; return *this; }
+
+    /// concatenate s
+    void operator += (const char *s) { data += s; }
+    void operator += (String s);
+
+    char operator []( int n ) const { return data[n]; }
+
+    /// return n leftmost chars
+    String left( int n ) const;
+
+    /// return n rightmost chars
+    String right( int n ) const;
+
+    /// convert this to upcase
+    String upper();
+
+    /// convert this to downcase
+    String lower(); // & ??
+
+    /// return the "esrever" of *this
+    String reversed() const;
+
+
+    /// return a piece starting at pos (first char = pos 1), length n
+    String mid(int pos,  int n ) const;
+
+    /// cut out a middle piece, return remainder
+    String nomid(int pos, int n ) const;
+
+    /// signed comparison,  analogous to strcmp;
+    int  compare( const char* s ) const;
+
+    /// index of rightmost c 
+    int lastPos( char c) const;
+    /// index of rightmost element of string 
+    int lastPos( const char* string ) const;
+
+    /// index of leftmost c
+    int pos(char c ) const;
+    /**
+    RETURN:
+    0 if not found, else index + 1
+    */
+    int pos(const char* string ) const;
+    int posAny(const char* string ) const;
+
+
+    /// provide Stream output
+    void printOn(ostream& os) const;
+
+    /// convert to an integer
+    long value() const;
+
+    /// convert to a double
+    double fvalue() const;
+    
+    /// the length of the string
+    int len() const;
+
+    /// DO NOT MAKE THIS INTO AN OPERATOR
+    bool to_bool() const;
+    /** perl -like string to bool conversion
+     */
+};
+/** 
+
+  Intuitive string class. provides 
+
+  ref counting thru #String_handle#
+
+  conversion from bool, int, double, char *, char.
+
+  conversion to int, upcase, downcase
+
+
+  printable. 
+
+  indexing (pos, posAny, lastPos)
+
+  cutting (left, right, mid)
+
+  concat (+=, +)
+
+  signed comparison (<, >, ==, etc)
+
+  No operator[] is provided, since this would be enormously  slow. If needed,
+  convert to const char *. 
+*/
+
+
+// because const char* also has an operator ==, this is for safety:
+inline bool operator==(String s1, String s2){    return !(s1.compare(s2));}
+inline bool operator==(String s1, const char *s2){ return !(s1.compare(s2));}
+inline bool operator==(const char *s1, String s2){ return !(s2.compare(s1));}
+inline bool operator!=(String s1, const char *s2  ) {    return s1.compare(s2);}
+inline bool operator!=(const char *s1,String s2) {    return s2.compare(s1);}
+inline bool operator!=(String s1, String s2  ) {    return s1.compare(s2);}
+
+inline String
+operator  + (String s1, String  s2)
+{
+    s1 += s2;
+    return s1;
+}
+
+inline ostream &
+operator << ( ostream& os, String d )
+{
+    d.printOn(os);
+    return os;
+}
+
+
+String quoteString(String message, String quote);
+
+#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..4c10139
--- /dev/null
@@ -0,0 +1,48 @@
+#include "textdb.hh"
+bool
+Text_db::eof()
+{
+    Data_file::gobble_leading_white();
+    return  Data_file::eof();
+}
+
+void
+Text_db::gobble_leading_white()
+{
+    while (1) {
+       Data_file::gobble_leading_white();
+       if (eof())
+           return ;
+       char c;
+       if  ((c = data_get()) !='\n'){
+           data_unget (c);
+           return ;
+       }       
+    }  
+}
+
+
+Text_record
+Text_db::get_record() 
+{
+   while (1) {
+       String s;
+       svec<String> fields;
+       assert(!eof());
+       
+       while ((s = get_word()) != "")
+           {
+           fields.add(s);      
+           gobble_white();
+           }
+            
+
+       if (get_line() != "")
+           assert(false);
+      
+       assert (fields.sz());
+       return Text_record(fields, get_name(), line());
+   }
+}
+
+
diff --git a/flower/textdb.hh b/flower/textdb.hh
new file mode 100644 (file)
index 0000000..bea0c45
--- /dev/null
@@ -0,0 +1,57 @@
+#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
+{
+    void gobble_leading_white();
+public:
+    /// get a line with records
+    Text_record    get_record();
+
+    Text_db(String fn):Data_file(fn) { }
+    Data_file::error;
+    bool 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);    
+    }
+};
diff --git a/flower/unionfind.cc b/flower/unionfind.cc
new file mode 100644 (file)
index 0000000..e7b0831
--- /dev/null
@@ -0,0 +1,35 @@
+#include "unionfind.hh"
+/*
+    see a book on data structures
+    */
+
+Union_find::Union_find(int n)
+{
+    classes.set_size(n);
+
+    for (int i=0; i < n; i++) {
+       classes[i] = i;
+    }
+}
+
+int
+Union_find::find(int i)
+{
+    int rep = i;
+    while (classes[rep] != rep)
+       rep = classes[rep];
+    while (classes[i] != rep) {
+       int next =classes[i];
+       classes[i] = rep;
+       i = next;
+    }
+    return rep;
+}
+
+void
+Union_find::connect(int i, int j)
+{
+    i = find(i);
+    j = find(j);
+    classes[i] = j;    
+}
diff --git a/flower/unionfind.hh b/flower/unionfind.hh
new file mode 100644 (file)
index 0000000..8fcc6b4
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef UNIONFIND_HH
+#define UNIONFIND_HH
+#include "vray.hh"
+
+/// which points of a graph are connected?
+struct Union_find {    
+    void connect(int i, int j);
+    int find(int i);
+    bool equiv(int i, int j) { return find(i) == find(j); }
+    Union_find(int sz);
+
+private:
+    svec<int> classes;
+
+};
+/*
+    Union find, a standard algorithm:
+
+    Union_find represents an undirected graph of N points. You can
+    connect two points using #connect()#. #find(i)# finds a uniquely
+    determined representant of the equivalence class of points
+    connected to #i#.
+    
+    */
+#endif
diff --git a/flower/vray.hh b/flower/vray.hh
new file mode 100644 (file)
index 0000000..d56cad0
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+  (c) Han-Wen Nienhuys 1995,96
+
+  Distributed under GNU GPL  
+*/
+
+#ifndef SVEC_H
+#define SVEC_H
+#include <assert.h>
+
+/// copy a bare (C-)array from #src# to #dest# sized  #count#
+template<class T>
+inline void arrcpy(T*dest, T*src, int count) {
+    for (int i=0; i < count ; i++)
+       *dest++ = *src++;
+}
+
+///scaleable array template, for T with def ctor.
+template<class T>
+class svec {
+protected:
+    
+    int max;
+
+    /// the data itself
+    T *thearray;
+
+    /// stretch or shrink  array.
+    void remax(int newmax) {    
+       T* newarr = new T[newmax];
+       size = (newmax < size) ? newmax : size;
+       arrcpy(newarr, thearray, size);
+       
+       delete[] thearray;
+       thearray = newarr;
+       max = newmax;
+    }
+    int size;
+
+public:
+    /// check invariants
+    void OK() const {
+       assert(max >= size && size >=0);
+       if (max) assert(thearray);
+    }
+    /// report the size. See {setsize}
+    int sz() const  { return size; }
+
+    /// POST: sz() == 0
+    void clear() { size = 0; }
+
+    svec() { thearray = 0; max =0; size =0; }
+    /// set the size to #s#
+    void set_size(int s) {
+       if (s >= max) remax(s);
+       size = s;    
+    }
+    /** POST: sz() == s.
+    Warning: contents are unspecified */
+    
+    ~svec() { delete[] thearray; }
+
+    /// return a  "new"ed copy of array 
+    T* copy_array() const {
+       T* Tarray = new T[size];
+       arrcpy(Tarray, thearray, size);
+       return Tarray;
+    }
+    // depracated
+    operator T* () const {
+       return copy_array();    
+    }
+    void operator=(svec const & src) {
+       set_size (src.size);
+       arrcpy(thearray,src.thearray, size);
+    }
+    svec(const svec & src) {
+       thearray = src.copy_array();
+       max = size = src.size;  
+    }
+
+    /// tighten array size.
+    void precompute () { remax(size); }
+
+    /// this makes svec behave like an array
+    T &operator[] (const int i) const {
+       assert(i >=0&&i<size);
+       return ((T*)thearray)[i];       
+    }
+
+    /// add to the end of array
+    void add(T x) {
+       if (size == max)
+           remax(2*max + 1);
+
+       // T::operator=(T &) is called here. Safe to use with automatic
+       // vars
+       thearray[size++] = x;
+    }
+
+    /// junk last entry.
+    void pop() { size -- ; }
+
+    /// return last entry
+    T& last(int j=0) {
+       return (*this)[size-j-1];
+    }
+    void swap (int i,int j) {
+       T t((*this)[i]);
+       (*this)[i]=(*this)[j];
+       (*this)[j]=t;
+    }
+    bool empty() { return !size; }
+    void insert(T&k, int j) {
+       assert(j >=0 && j<= size);
+       set_size(size+1);
+       for (int i=size-1; i > j; i--)
+           thearray[i] = thearray[i-1];
+       thearray[j] = k;
+    }
+    void del(int i) {
+       assert(i >=0&& i < size);
+       arrcpy(thearray+i, thearray+i+1, size-i-1);
+       size--;
+    }
+    // quicksort.
+    void sort (int (*compare)(T& , T& ),
+              int lower = -1, int upper = -1 ) {
+       if (lower < 0) {
+           lower = 0 ;
+           upper = sz();
+       }
+       if (lower >= upper)
+           return;
+       swap(lower, (lower+upper)/2);
+       int last = lower;
+       for (int i= lower +1; i <= upper; i++)
+           if (compare(thearray[i], thearray[lower]) < 0 )
+               swap( ++last,i);
+       swap(lower, last);
+       sort(compare, lower, last-1);
+       sort(compare, last+1, lower);
+    }
+};
+/**
+
+  This template implements a scaleable vector. With (or without) range
+  checking. It may be flaky for objects with complicated con- and
+  destructors. The type T should have a default constructor. It is
+  best suited for simple types, such as int, double or String
+
+  */
+
+/// A simple stack based on svec.
+template<class T>
+class sstack : svec<T> {
+ public:
+    T top() { return last(); }
+    T pop() {
+       assert(!empty());
+       T l = last();
+        svec<T>::pop();
+       return l;
+    }
+    void push(T l) { add(l); }
+    bool empty() { return svec<T>::empty(); } 
+};
+/**
+  Same as for #svec# goes here.
+*/
+#endif
diff --git a/glob.hh b/glob.hh
new file mode 100644 (file)
index 0000000..7b8bb55
--- /dev/null
+++ b/glob.hh
@@ -0,0 +1,9 @@
+#ifndef GLOB_HH
+#define GLOB_HH
+#include <assert.h>
+#include <math.h>
+#include "real.hh"
+
+#include "proto.hh"
+#include "const.hh"
+#endif
diff --git a/globvars.hh b/globvars.hh
new file mode 100644 (file)
index 0000000..c79e017
--- /dev/null
@@ -0,0 +1 @@
+extern Score *the_score;
diff --git a/item.cc b/item.cc
new file mode 100644 (file)
index 0000000..5856156
--- /dev/null
+++ b/item.cc
@@ -0,0 +1,49 @@
+#include "line.hh"
+
+
+#include "cols.hh"
+String
+Spanner::TeXstring() const
+{
+    assert(right->line);
+    Real w = left->hpos - right->hpos;
+    return (*strets)(w);
+}
+
+Spanner *
+Spanner::broken_at(const PCol *c1, const PCol *c2) const
+{
+    Spanner *sp = new Spanner(*this);
+    sp->left = c1;
+    sp->right = c2;
+    return sp;
+}
+
+Spanner::Spanner()
+{
+    pstaff_=0;
+    strets=0;
+    left = right = 0;
+}
+
+/****************************************************************/
+String
+Item::TeXstring() const
+{
+    return output->TeXstring();
+}
+
+Interval
+Item::width() const
+{
+    return output->extent().x;
+}
+
+/****************************************************************/
+
+Item::Item()
+{
+    col = 0;
+    output = 0;
+    pstaff_ = 0;
+}
diff --git a/item.hh b/item.hh
new file mode 100644 (file)
index 0000000..15a8e88
--- /dev/null
+++ b/item.hh
@@ -0,0 +1,47 @@
+#ifndef ITEM_HH
+#define ITEM_HH
+
+#include "glob.hh"
+#include "boxes.hh"
+#include "string.hh"
+#include "tex.hh"
+
+/// a symbol which is attached between two columns.
+struct Spanner {
+    const PCol *left, *right;
+    Stretchable_symbol *strets;
+    PStaff * pstaff_;
+    ///      clone a piece of  this spanner.
+    Spanner *broken_at(const PCol *c1, const PCol *c2) const; 
+    /**
+    PRE
+    c1 >= start, c2  <= stop
+    */
+    String TeXstring () const ;
+    Spanner();
+};
+/** Spanner should know about the items which it should consider:
+    e.g. slurs should be steep enough to "enclose" all those items. This
+    is absolutely necessary for beams, since they have to adjust the
+    length of stems of notes they encompass.
+
+    */
+    
+/// a fixed size element of the score
+struct Item {
+    virtual Interval width() const;    
+
+    const PCol * col;
+    Output *output;
+    
+    PStaff *pstaff_;
+    /** needed for knowing at which staff to output this item
+    */
+    String TeXstring () const ;
+    Item();
+};
+/** An item must be part of a Column
+*/
+
+#endif
diff --git a/keyword.cc b/keyword.cc
new file mode 100644 (file)
index 0000000..14903cf
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+  keyword.cc -- keywords and identifiers
+ */
+
+#include <stdlib.h>
+
+#include "glob.hh"
+#include "lexer.hh"
+//#include "mudobs.hh"
+//#include "gram.hh"
+
+/* for the keyword table */
+struct Keyword_ent
+{
+    const char   *name;
+    int     tokcode;
+};
+
+struct Keyword_table
+{
+    Keyword_ent *table;
+    int     maxkey;
+    Keyword_table(Keyword_ent *);
+    int     lookup(const char *s) const;
+};
+
+
+/* for qsort */
+int
+        tabcmp(const void * p1, const void * p2)
+{
+    return strcmp(((const Keyword_ent *) p1)->name,
+                  ((const Keyword_ent *) p2)->name);
+}
+
+Keyword_table::Keyword_table(Keyword_ent *tab)
+{
+    table = tab;
+
+    /* count keywords */
+    for (maxkey = 0; table[maxkey].name; maxkey++);
+
+    /* sort them */
+    qsort(table, maxkey, sizeof(Keyword_ent), tabcmp);
+}
+
+/*
+  lookup with binsearch, return tokencode.
+*/
+int
+Keyword_table::lookup(const char *s)const
+{
+    int     lo,
+            hi,
+            cmp,
+            result;
+    lo = 0;
+    hi = maxkey;
+
+    /* binary search */
+    do
+    {
+        cmp = (lo + hi) / 2;
+
+        result = strcmp(s, table[cmp].name);
+
+        if (result < 0)
+            hi = cmp;
+        else
+            lo = cmp;
+    }
+    while (hi - lo > 1);
+    if (!strcmp(s, table[lo].name))
+    {
+        return table[lo].tokcode;
+    } else
+        return -1;              /* not found */
+}
+
diff --git a/keyword.hh b/keyword.hh
new file mode 100644 (file)
index 0000000..aa87a8d
--- /dev/null
@@ -0,0 +1,17 @@
+/* for the keyword table */
+struct Keyword_ent
+{
+    const char   *name;
+    int     tokcode;
+};
+
+struct Keyword_table
+{
+    Keyword_ent *table;
+    int     maxkey;
+    Keyword_table(Keyword_ent *);
+    int     lookup(const char *s) const;
+};
+
+struct Identifier{
+};
diff --git a/lexer.hh b/lexer.hh
new file mode 100644 (file)
index 0000000..2875360
--- /dev/null
+++ b/lexer.hh
@@ -0,0 +1,14 @@
+#ifndef LEXER_HH
+#define LEXER_HH
+
+#include "proto.hh"
+
+void new_input(String s);
+bool close_input();
+int yylex();
+void yyerror(char *s);
+
+int lookup_keyword(String s);
+Identifier* lookup_identifier(String s);
+
+#endif
diff --git a/lexer.l b/lexer.l
new file mode 100644 (file)
index 0000000..0063227
--- /dev/null
+++ b/lexer.l
@@ -0,0 +1,184 @@
+%{ // -*-Fundamental-*-
+
+#include <fstream.h>
+#include <stdio.h>
+#include "glob.hh"
+#include "string.hh"
+
+#include "lexer.hh"
+#include "keyword.hh"
+#include "vray.hh"
+#include "parser.hh"
+#include "debug.hh"
+
+sstack<istream *> include_stack;
+static int last_print;
+const int DOTPRINT=50; // every 50 lines dots
+%}
+
+%option c++
+%option noyywrap
+%option nodefault
+%option yylineno
+%option debug
+%x notes
+%x incl
+
+OPTSIGN                !?
+NOTENAMEI       A|B|C|D|E|F|G|As|Bes|Ces|Des|Es|Fes|Ges|Ais|Bis|Cis|Dis|Eis|Fis|Gis
+NOTENAMEII     a|b|c|d|e|f|g|as|bes|ces|des|es|fes|ges|ais|bis|cis|dis|eis|fis|gis
+NOTENAMEIII      Ases|Beses|Ceses|Deses|Eses|Feses|Geses|Aisis|Bisis|Cisis|Disis|Eisis|Fisis|Gisis
+NOTENAMEIIII      ases|beses|ceses|deses|eses|feses|geses|aisis|bisis|cisis|disis|eisis|fisis|gisis
+RESTNAME        r|s
+NOTENAME        {NOTENAMEI}|{NOTENAMEII}|{NOTENAMEIII}|{NOTENAMEIIII}
+PITCH          ['`]*{OPTSIGN}{NOTENAME}
+DURNAME                1|2|4|8|16|32
+DURATION       {DURNAME}\.*
+FULLNOTE       {PITCH}{DURATION}?
+WORD           [a-zA-Z]+
+REAL           [0-9]+(\.[0-9]*)?
+
+%%
+
+\$             {
+       BEGIN(notes); return '$';
+}
+
+<notes>{RESTNAME}      {
+       const char *s = YYText();
+       yylval.string = new String (s);
+       if (debug_flags & DEBUGTOKEN)
+               mtor << "rest:"<< yylval.string;
+       return RESTNAME;
+}
+<notes>{PITCH} {
+       const char *s = YYText();
+       yylval.string = new String (s);
+       if (debug_flags & DEBUGTOKEN)
+               mtor << "pitch:"<< yylval.string;
+       return PITCH;
+}
+<notes>{DURATION}      {
+       yylval.string = new String (YYText());
+       return DURATION;
+}
+<notes>[:space:]+              {
+}
+<notes>[ \t\n]+                {
+}
+<notes>%.*             {
+
+}
+<notes>\$      {
+       BEGIN(INITIAL); return '$';
+}
+<notes>.       {
+         cout << "SCANNER <notes> HOLE `" << YYText()<<'\''<<endl; 
+         return YYText()[0];
+}
+<<EOF>> {
+       if(!close_input())
+               yyterminate();
+}
+{WORD}         {
+       int l = lookup_keyword(YYText());
+       if (l == -1){
+            yylval.id = lookup_identifier(YYText());
+           return IDENTIFIER;
+        } else
+            return l;
+}
+
+{REAL}         {
+       Real r;
+       sscanf (YYText(), "%lf", &r);
+       yylval.real = r;
+       return REAL;
+}
+
+[\{\}\[\]\(\)] {
+       if (debug_flags & DEBUGTOKEN)
+           cout << "parens\n";
+       return YYText()[0];
+}
+[ \t\n]+       {
+       
+}
+%.*            {
+       //ignore
+}
+.              {
+       error("lexer error: illegal character '"+String(YYText()[0])+
+         "' encountered");
+       return YYText()[0];
+}
+
+%%
+
+yyFlexLexer *lexer=0;
+
+// set the  new input to s, remember old file.
+void
+new_input(String s)
+{    
+    istream *newin ;
+    
+    if (s=="")
+       newin = &cin;
+    else
+       newin = new ifstream( s ); //
+    
+   if ( ! *newin)
+      error("cant open "  + s);
+   cout << "["<<s<<flush;
+   
+   include_stack.push(newin);
+
+   if (!lexer) {
+       lexer = new yyFlexLexer;
+       lexer->set_debug( bool(debug_flags & DEBUGPARSER));
+   }           
+   
+   lexer->switch_streams(newin);
+}
+
+
+// pop the inputstack.
+bool
+close_input()
+{
+
+  istream *closing= include_stack.pop();
+  if (closing != &cin)
+      delete closing;
+  
+  cout << "]" << flush;
+  
+  if (include_stack.empty())
+      return false ;  
+  else 
+      lexer->switch_streams(include_stack.top());  
+  return true;  
+}
+
+int
+yylex() {
+       return lexer->yylex();
+}
+
+void
+yyerror(char *s)
+{
+  *mlog << "error in line " << lexer->lineno() <<  ": " << s << '\n';
+  exit(1);
+}
+
+
+#if 0
+
+<notes>{NOTENAME}      {
+       yylval.string = new String (YYText());
+       return NOTENAME;
+}
+
+#endif
\ No newline at end of file
diff --git a/lilyponddefs.tex b/lilyponddefs.tex
new file mode 100644 (file)
index 0000000..48d1e32
--- /dev/null
@@ -0,0 +1,29 @@
+
+
+\def\musixtwentydefs{
+       \font\musicfnt=musix20
+%      \hulplijnbreedte5pt
+       %\hlijnhoogte1pt
+       %\balkskip4pt
+}
+\musixtwentydefs
+\def\mdef#1#2{\def#1{{\musicfnt\char#2}}}
+\mdef\quartball{'007}
+\mdef\halfball{'010}
+\mdef\wholeball{'011}
+\mdef\wholerest{'074}
+\mdef\halfrest{'072}
+\mdef\quartrest{'076}
+\mdef\eighthrest{'077}
+\mdef\sixteenthrest{'078}
+\mdef\thirtysecondrest{'079}
+\mdef\sharp{'065}
+\mdef\flat{'063}
+\mdef\natural{'067}
+\mdef\singledot{'00}
+\mdef\doubledot{'01}
+\mdef\tripledot{'02}
+\def\maatstreep{\vrule height10pt width 1pt}
+\parindent0pt
+
+
diff --git a/line.cc b/line.cc
new file mode 100644 (file)
index 0000000..9311aeb
--- /dev/null
+++ b/line.cc
@@ -0,0 +1,94 @@
+#include "line.hh"
+#include "cols.hh"
+#include "pscore.hh"
+
+String
+Line_of_staff::TeXstring() const
+{
+    String s("%line_of_staff\n\\vbox to ");
+    s += String(height * VERT_TO_PT) +"pt{";
+
+    //make some room
+    s += vstrut(base* VERT_TO_PT);
+
+    // the staff itself: eg lines, accolades
+    s += "\\hbox{";
+    {
+       s+=(*pstaff_->stafsym)(scor->score->linewidth);
+       PCursor<const PCol *> cc(scor->cols);
+       Real lastpos=cc->hpos;
+
+       // all items in the current line & staff.
+       for (; cc.ok(); cc++) {
+           Real delta=cc->hpos - lastpos;
+           lastpos = cc->hpos;
+
+           // moveover
+           s +=String( "\\kern ") + HOR_TO_PT*delta + "pt ";
+
+           // now output the items.
+
+           for (PCursor<const Item *> ic(cc->its); ic.ok(); ic++) {
+               if (ic->pstaff_ == pstaff_)
+                   s += ic->TeXstring();
+           }
+           // spanners.
+           for (PCursor<const Spanner *> sc(cc->starters); sc.ok(); sc++)
+               if (sc->pstaff_ == pstaff_)
+                   s += sc->TeXstring();
+       }
+    }
+    s+="\\hss}}";
+    return s;
+}
+
+String
+Line_of_score::TeXstring() const
+{
+     String s("\\vbox{");
+     for (PCursor<Line_of_staff*> sc(staffs); sc.ok(); sc++)
+        s += sc->TeXstring();
+     s += "}";
+     return s;
+}
+
+/// testing this entry
+Line_of_score::Line_of_score(svec<const PCol *> sv,
+                            const PScore *ps)
+{
+    score = ps;
+    for (int i=0; i< sv.sz(); i++) {
+       PCol *p=(PCol *) sv[i];
+       cols.bottom().add(p);
+       p->line=this;
+    }
+
+    for (PCursor<PStaff*> sc(score->staffs); sc.ok(); sc++)
+       staffs.bottom().add(new Line_of_staff(this, sc));    
+}
+/** construct a line with the named columns. Make the line field
+    in each column point to this
+    
+    #sv# isn't really const!!
+    */
+
+Line_of_staff::Line_of_staff(Line_of_score * sc, PStaff*st)
+{
+    // [don't know how to calc dimensions yet.]
+   height = 0.0;
+   base =0.0;
+    scor=sc;
+    pstaff_=st;
+
+    const    PCol *linestart= sc->cols.top();
+    const PCol *linestop=sc->cols.bottom();
+    
+    for (PCursor<const Spanner*> sp(pstaff_->spans); sp.ok(); sp++) {
+       const PCol *brokenstart = &MAX(*linestart, *sp->left);
+       const PCol *brokenstop = &MIN(*linestop, *sp->right);
+
+       if (*brokenstop  < *brokenstart)
+           brokenspans.bottom().add(sp->broken_at(brokenstop, brokenstart));
+    }
+}
diff --git a/line.hh b/line.hh
new file mode 100644 (file)
index 0000000..cfa3b63
--- /dev/null
+++ b/line.hh
@@ -0,0 +1,52 @@
+#ifndef LINE_HH
+#define LINE_HH
+
+/*
+    horizontal structures for broken scores.
+*/
+
+#include "real.hh"
+#include "list.hh"
+#include "vray.hh"
+#include "glob.hh"
+#include "pstaff.hh"
+
+
+
+/// the columns of a score that form one line.
+struct
+Line_of_score {
+    List<const PCol *> cols;
+
+    // need to store height of each staff.
+    PointerList<Line_of_staff*> staffs;
+    const PScore * score;      // needed to generate staffs
+
+    /****************/
+    
+    Line_of_score(svec<const PCol *> sv, const PScore *);
+
+    String TeXstring() const;
+
+    // is #c# contained in #*this#?
+    bool element(const PCol *c);
+};
+
+/// one broken line of staff.
+struct Line_of_staff {
+    Real height;
+
+    /// y-pos of the baseline, measured from the top.
+    Real base;
+    
+    PointerList<Spanner *> brokenspans;    
+    Line_of_score const * scor;
+    const PStaff *pstaff_;
+
+    /****************/
+    
+    String TeXstring() const;
+    Line_of_staff(Line_of_score*, PStaff *);
+};
+
+#endif
diff --git a/linespace.cc b/linespace.cc
new file mode 100644 (file)
index 0000000..7892cef
--- /dev/null
@@ -0,0 +1,249 @@
+#include <math.h>
+#include "linespace.hh"
+#include "debug.hh"
+#include "qlp.hh"
+#include "unionfind.hh"
+
+const Real COLFUDGE=1e-3;
+//#define COLFUDGE 1e-3
+bool
+Spacing_problem::contains(const PCol *w)
+{
+    for (int i=0; i< cols.sz(); i++)
+       if (cols[i].col == w)
+           return true;
+    return false;
+}
+
+int 
+Spacing_problem::col_id(const PCol *w)const
+{
+    for (int i=0; i< cols.sz(); i++)
+       if (cols[i].col == w)
+           return i;
+    assert(false);
+}
+
+void
+Spacing_problem::OK() const
+{
+    Union_find connected(cols.sz());
+
+    for (int i=0; i < ideals.sz(); i++) {
+       assert(ideals[i]->hooke > 0);
+       int l = col_id(ideals[i]->left);
+       int r = col_id(ideals[i]->right);
+       connected.connect(l,r);         
+    }
+
+    for (int i = 0; i < cols.sz(); i++) {
+       assert( connected.equiv(0,i));
+    }
+}
+
+bool
+Spacing_problem::check_constraints(Vector v) const 
+{
+    int dim=v.dim();
+    // mtor << "checking solution " << v << '\n';
+    for (int i=0; i < dim; i++) {
+
+       if (cols[i].fixed&& ABS(cols[i].fixpos - v(i)) > COLFUDGE) {
+           return false;
+       }
+       if (!i) 
+           continue;
+       
+       Real mindist=cols[i-1].minright()
+           +cols[i].minleft();
+
+       // ugh... compares
+       Real dif =v(i) - v(i-1)- mindist;
+       bool b = (dif > - COLFUDGE);
+       
+
+#if 1
+       if (!b)
+           return false;
+
+#else
+       mtor << "dif= "<<dif<<" fudge= " << COLFUDGE<< " dif >fudge= "<<
+           b << "\n";
+       
+       /* fucks up for unknown reasons */
+       if (dif  < -COLFUDGE)
+           return false;
+#endif
+
+    }
+    return true;
+}
+
+bool
+Spacing_problem::check_feasible() const
+{
+    Vector sol(try_initial_solution());
+    return check_constraints(sol);     
+}
+
+// generate a solution which obeys the min distances and fixed positions
+Vector
+Spacing_problem::try_initial_solution() const
+{
+    int dim=cols.sz();
+    Vector initsol(dim);
+    for (int i=0; i < dim; i++) {
+       if (cols[i].fixed) {
+           initsol(i)=cols[i].fixpos;      
+       } else {
+           Real mindist=cols[i-1].minright()
+               +cols[i].minleft();
+           assert(mindist >= 0.0);
+           initsol(i)=initsol(i-1)+mindist;
+
+           //nog niet 
+           //if (i>0)
+           //  assert(initsol(i) > initsol(i-1));
+       }       
+    }
+
+    return initsol;
+}
+Vector
+Spacing_problem::find_initial_solution() const
+{
+    Vector v(try_initial_solution());     
+    assert(check_constraints(v));
+    return v;
+}
+// generate the matrices
+void
+Spacing_problem::make_matrices(Matrix &quad, Vector &lin) const
+{
+    quad.fill(0);
+    lin.fill(0);
+    for (int j=0; j < ideals.sz(); j++){
+       Idealspacing const*i=ideals[j];
+       int l = col_id(i->left);
+       int r = col_id(i->right);
+
+       quad(r,r) += i->hooke;
+       quad(r,l) -= i->hooke;
+       quad(l,r) -= i->hooke;
+       quad(l,l) += i->hooke;
+
+       lin(r) -= i->space*i->hooke;
+       lin(l) += i->space*i->hooke;
+    }
+}
+
+// put the constraints into the LP problem
+void
+Spacing_problem::make_constraints(Optimisation_problem& lp) const
+{    
+    for (int j=0; j < cols.sz(); j++) {
+       Colinfo *c=&(cols[j]);
+       int dim=cols.sz();
+               
+       if (c->fixed) {
+           lp.add_fixed_var(j,c->fixpos);
+           continue;
+       }else {
+
+           Vector c1(dim);
+           Vector c2(dim);
+           
+              
+           c1(j)=1.0 ;
+           c1(j-1)=-1.0 ;
+           lp.add_inequality_cons(c1, cols[j-1].minright() +
+                                  cols[j].minleft());
+
+           c2(j)=-1.0 ;
+           c2(j+1)=1.0;
+           lp.add_inequality_cons(c2,
+                                  cols[j+1].minleft() +
+                                  cols[j].minright());
+       }
+    }
+}
+
+svec<Real>
+Spacing_problem::solve() const
+{
+    OK();
+    assert(check_feasible());
+    //    print();
+    
+    /* optimalisatiefunctie */        
+    Optimisation_problem lp(cols.sz());
+    make_matrices(lp.quad,lp.lin);
+    make_constraints(lp);    
+    Vector start=find_initial_solution();    
+    Vector sol(lp.solve(start));
+    if (!check_constraints(sol)) {
+       error( "solution doesn't solve. Sorry");        
+    }
+       
+
+    svec<Real> posns(sol);
+    posns.add(lp.eval(sol));
+    return posns;
+}
+
+/*
+    add one column to the problem.
+*/    
+void
+Spacing_problem::add_column(const PCol *col, bool fixed, Real fixpos)
+{
+    Colinfo c;
+    c.fixed=fixed;
+    c.fixpos=fixpos;
+    c.col=col;
+    cols.add(c);
+}
+
+void
+Spacing_problem::add_ideal(const Idealspacing *i)
+{
+    const PCol *l =i->left;
+    const PCol *r= i->right;
+    
+    if (!contains(l) || !contains(r)) {
+       return;
+    }
+    ideals.add(i);
+}
+
+void
+Spacing_problem::print_ideal(const Idealspacing*id)const
+{
+    int l = col_id(id->left);
+    int r = col_id(id->right);
+
+    mtor << "idealspacing { between " << l <<","<<r<<'\n';
+    mtor << "distance "<<id->space<< " strength " << id->hooke << "}\n";
+}
+
+void
+Spacing_problem::print() const
+{
+    for (int i=0; i < cols.sz(); i++) {
+       mtor << "col " << i<<' ';
+       cols[i].print();
+    }
+    for (int i=0; i < ideals.sz(); i++) {
+       print_ideal(ideals[i]);
+    }
+}
+
+void
+Colinfo::print() const
+{
+    mtor << "column { ";
+    if (fixed)
+       mtor << "fixed at " << fixpos<<", ";
+    mtor << "[" << minleft() << ", " << minright() << "]";
+    mtor <<"}\n";
+}
diff --git a/linespace.hh b/linespace.hh
new file mode 100644 (file)
index 0000000..c2f8b52
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef PROBLEM_HH
+#define PROBLEM_HH
+
+#include "glob.hh"
+#include "list.hh"
+#include "vray.hh"
+#include "cols.hh"
+#include "matrix.hh"
+
+/// helper struct for #Spacing_problem#
+struct Colinfo {
+    const PCol *col;
+    bool fixed;
+    Real fixpos;
+    Colinfo() {
+       fixed=false;
+       col=0;
+    }
+    void print() const;
+    Real minright()const { return col->width().max; }
+    Real minleft()const { return -col->width().min; }
+};
+
+
+/// spacing for one line.
+class Spacing_problem {
+    svec<const Idealspacing*> ideals;
+    svec<Colinfo> cols;
+
+    /// the index of #c# in #cols#
+    int col_id(const PCol *c) const;
+
+    /// generate an (nonoptimal) solution
+    Vector find_initial_solution() const;
+
+    /// check if problem is too tight
+    bool check_feasible() const;
+    /// does #this# contain the column #w#? 
+    bool contains(const PCol *w);
+
+    /// make the energy function
+    void make_matrices(Matrix &quad, Vector &lin) const;
+
+    /// generate the LP constraints
+    void make_constraints(Optimisation_problem& lp) const;
+
+public:
+    /// solve the spacing problem
+    svec<Real> solve() const;
+    /**
+    return the column positions, and the energy (last element)
+    */
+    /// add a idealspacing to the problem.
+    void add_ideal(const Idealspacing *i);
+    
+    /**
+    One pair of columns can have no, one or more idealspacings,
+    since they can be "summed" if the columns to which #i# refers are
+    not in this problem, the spacing is ignored.
+    */
+    
+    
+    /// add a col to the problem
+    void add_column(const PCol *, bool fixed=false, Real fixpos=0.0);
+    /** columns have to be added left to right. The column contains
+      info on it's minimum width.
+    */
+
+
+    bool check_constraints(Vector v) const;
+
+    Vector try_initial_solution() const;
+    void OK() const;
+    void print() const;
+    void print_ideal(const Idealspacing*)const;
+};
+
+
+/** the problem, given by the columns (which include constraints) and
+    intercolumn spacing. The problem is:
+
+    Generate a spacing which
+    \begin{itemize}
+    \item
+    Satisfies spacing constraints (notes can't be printed through each other)
+    \item
+    Looks good, ie tries to conform to  an ideal spacing as much as possible.
+    \end{itemize}
+    This is converted by regarding idealspacing as "springs" attached
+    to columns. The equilibrium of one spring is the ideal
+    distance. The columns have a size, this imposes "hard" constraints
+    on the distances. This transforms the problem into a quadratic
+    programming problem with linear constraints.
+
+    The quality is given by the total potential energy in the
+    springs. The lower the energy, the better the configuration.
+*/
+#endif
diff --git a/linestaff.cc b/linestaff.cc
new file mode 100644 (file)
index 0000000..38fa40e
--- /dev/null
@@ -0,0 +1,9 @@
+#include "linestaff.hh"
+#include "tex.hh"
+
+Linestaff::Linestaff(int l)
+{
+    nolines = l;
+    stafsym = Stretchable_symbol::get_linestaff(l); 
+}
+
diff --git a/linestaff.hh b/linestaff.hh
new file mode 100644 (file)
index 0000000..7ca34f5
--- /dev/null
@@ -0,0 +1,8 @@
+#include "pstaff.hh"
+
+struct Linestaff : PStaff {
+    int nolines;
+    
+    Linestaff(int);
+    
+};
diff --git a/main.cc b/main.cc
new file mode 100644 (file)
index 0000000..3758840
--- /dev/null
+++ b/main.cc
@@ -0,0 +1,54 @@
+#include <iostream.h>
+#include "lgetopt.hh"
+#include "misc.hh"
+#include "debug.hh"
+#include "score.hh"
+#include "globvars.hh"
+
+extern void parse_file(String s);
+Score *the_score =0;
+
+long_option_init theopts[] = {
+    1, "debug", 'd',
+    1, "output", 'o',
+    0,0,0
+};
+
+
+String outfn="lelie.uit";
+
+void
+set_output(String s)
+{
+    outfn = s;
+}
+
+int
+main (int argc, char **argv)
+{
+    Getopt_long oparser(argc, argv,theopts);
+
+    cout << get_version() 
+       << "copyright 1996 Han-Wen Nienhuys\n";
+    
+    while (long_option_init * opt = oparser()) {
+       switch ( opt->shortname){
+       case 'd':
+           set_debug(oparser.optarg);
+           break;
+       case 'o':
+           set_output(oparser.optarg);
+           break;
+       default:
+           assert(false);
+           break;
+       }
+    }
+    char *arg = oparser.get_next_arg();
+
+    if (!arg) arg = "";
+    parse_file(arg);
+
+    the_score->process();
+    the_score->output(outfn);    
+}
diff --git a/make_version b/make_version
new file mode 100755 (executable)
index 0000000..5098f79
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+echo '#ifndef VERSION_HH'
+echo '#define VERSION_HH'
+echo '#define MAJORVERSION ' $1
+echo '#define MINORVERSION ' $2
+echo '#define PATCHLEVEL ' $3
+echo '#define VERSIONSTR "'$1.$2.$3'"'
+echo '#endif'
diff --git a/matrix.cc b/matrix.cc
new file mode 100644 (file)
index 0000000..ab59a87
--- /dev/null
+++ b/matrix.cc
@@ -0,0 +1,281 @@
+#include "matrix.hh"
+#include "string.hh"
+
+
+Real
+Matrix::norm() const
+{
+    Real r =0.0;
+    for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+       r += sqr(dat->elem(i,j));
+    return sqrt(r);
+}
+
+//inline
+Real
+Matrix::operator()(int i,int j) const
+{
+    assert(i >= 0 && j >= 0);
+    assert(i < rows() && j < cols());
+    return dat->elem(i,j);
+}
+
+//inline
+Real &
+Matrix::operator()(int i, int j)
+{
+    assert(i >= 0 && j >= 0);
+    assert(i < rows() && j < cols());
+    return dat->elem(i,j);
+}
+
+void
+Matrix::fill(Real r)
+{
+    for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+       dat->elem(i,j)=r;
+}
+
+void
+Matrix::set_diag(Real r)
+{
+    for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))   
+       dat->elem(i,j)=(i==j) ? r: 0.0;
+}
+
+void
+Matrix::set_diag(Vector d)
+{
+    for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))   
+       dat->elem(i,j)=(i==j) ? d(i): 0.0;
+}
+
+void
+Matrix::operator+=(const Matrix&m)
+{
+    assert(m.cols() == cols());
+    assert(m.rows() == rows());
+    for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+       dat->elem(i,j) += m(i,j);
+}
+void
+Matrix::operator-=(const Matrix&m)
+{
+    assert(m.cols() == cols());
+    assert(m.rows() == rows());
+    for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+       dat->elem(i,j) -= m(i,j);
+}
+
+
+void
+Matrix::operator*=(Real a)
+{
+    for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+       dat->elem(i,j) *= a;
+}
+
+void
+Matrix::operator=(const Matrix&m)
+{
+    if (&m == this)
+       return ;
+    delete dat;
+    dat = m.dat->clone();
+}
+    
+Matrix::Matrix(const Matrix &m)
+{
+    m.OK();
+    
+    dat = m.dat->clone();
+}
+
+
+Matrix::Matrix(int n, int m)
+{
+    dat = virtual_smat::get_full(n,m);
+    fill(0);
+}
+
+Matrix::Matrix(int n)
+{
+    dat = virtual_smat::get_full(n,n);
+    fill(0);
+}
+
+Matrix::Matrix(Vector v, Vector w)
+{   
+    dat = virtual_smat::get_full(v.dim(), w.dim());
+    for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+       dat->elem(i,j)=v(i)*w(j);
+}
+
+
+Vector
+Matrix::row(int k) const
+{
+    int n=cols();
+
+    
+    Vector v(n);
+    for(int i=0; i < n; i++)
+       v(i)=dat->elem(k,i);
+
+    return v;
+}
+
+Vector
+Matrix::col(int k) const
+{
+    int n=rows();
+    Vector v(n);
+    for(int i=0; i < n; i++)
+       v(i)=dat->elem(i,k);
+    return v;
+}
+
+Vector
+Matrix::left_multiply(const Vector& v) const
+{
+     Vector dest(v.dim());
+    assert(dat->cols()==v.dim());
+    for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+       dest(i)+= dat->elem(j,i)*v(j);
+    return dest;
+}
+
+Vector
+Matrix::operator *(const Vector& v) const
+{
+    Vector dest(rows());
+    assert(dat->cols()==v.dim());
+    for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j))
+       dest(i)+= dat->elem(i,j)*v(j);
+    return dest;
+}
+
+Matrix
+operator /(Matrix const& m1,Real a)
+{
+    Matrix m(m1);
+    m /= a;
+    return  m;
+}
+
+void
+Matrix::transpose()            // delegate to storage?
+{
+    for (int i=0, j=0; dat->mult_ok(i,j); dat->mult_next(i,j)) {
+       if (i >= j)
+           continue;
+       Real r=dat->elem(i,j);
+       dat->elem(i,j) = dat->elem(j,i);
+       dat->elem(j,i)=r;
+    }
+}
+
+Matrix
+Matrix::operator-() const
+{
+    OK();
+    Matrix m(*this);
+    m*=-1.0;    
+    return m;
+}
+
+Matrix
+Matrix::transposed() const
+{
+    Matrix m(*this);
+    m.transpose();
+    return m;
+}
+
+
+/* should do something smarter: bandmatrix * bandmatrix is also banded matrix.  */
+Matrix
+operator *(const Matrix &m1, const Matrix &m2)
+{
+    Matrix result(m1.rows(), m2.cols());
+    result.set_product(m1,m2);
+    return result;
+}
+
+void
+Matrix::set_product(const Matrix &m1, const Matrix &m2)
+{
+    assert(m1.cols()==m2.rows());
+    assert(cols()==m2.cols() && rows()==m1.rows());
+    
+    for (int i=0, j=0; dat->mult_ok(i,j);
+        dat->mult_next(i,j)) {
+       Real r=0.0;
+       for (int k = 0; k < m1.cols(); k++)
+           r += m1(i,k)*m2(k,j);
+       dat->elem(i,j)=r;
+    }
+}
+
+void
+Matrix::insert_row(Vector v, int k)
+{
+    assert(v.dim()==cols());
+    dat->insert_row(k);
+    for (int j=0; j < cols(); j++)
+       dat->elem(k,j)=v(j);
+}
+
+
+void
+Matrix::swap_columns(int c1, int c2)
+{
+    assert(c1>=0&& c1 < cols()&&c2 < cols() && c2 >=0);
+    for (int i=0; i< rows(); i++) {
+       Real r=dat->elem(i,c1);
+       dat->elem(i,c1) = dat->elem(i,c2);
+       dat->elem(i,c2)=r;
+    }
+}
+
+void
+Matrix::swap_rows(int c1, int c2)
+{
+    assert(c1>=0&& c1 < rows()&&c2 < rows() && c2 >=0);
+    for (int i=0; i< cols(); i++) {
+       Real r=dat->elem(c1,i);
+       dat->elem(c1,i) = dat->elem(c2,i);
+       dat->elem(c2,i)=r;
+    }
+}
+
+
+int
+Matrix::dim() const
+{
+    assert(cols() == rows());
+    return rows();
+}
+
+Matrix::operator String() const
+{
+    String s("matrix {\n");
+    for (int i=0; i< rows(); i++){
+       for (int j = 0; j < cols(); j++) {
+           s+= String(dat->elem(i,j), "%6f ");
+       }
+       s+="\n";
+    }
+    s+="}\n";
+    return s;
+}
+
+
+
+#include "debug.hh"
+void
+Matrix::print() const
+{
+    mtor << *this;
+}
diff --git a/matrix.hh b/matrix.hh
new file mode 100644 (file)
index 0000000..e092a5f
--- /dev/null
+++ b/matrix.hh
@@ -0,0 +1,141 @@
+#ifndef MATRIX_HH
+#define MATRIX_HH
+
+
+#include "vsmat.hh"
+#include "vector.hh"
+
+/// a Real matrix
+class Matrix {
+    virtual_smat *dat;
+    
+public:
+    void OK() const { dat->OK(); }
+    int cols() const { return dat->cols(); }
+    int rows() const { return dat->rows(); }
+
+    /// return the size of a matrix
+    int dim() const;
+    /**
+      PRE
+      the matrix needs to be square.
+    */
+     
+    // Matrix() { dat = 0; } 
+    ~Matrix() { delete dat; }
+
+    /// set entries to r 
+    void fill(Real r);
+
+    /// set diagonal to d
+    void set_diag(Real d);
+
+    void set_diag(Vector d);
+    /// set unit matrix
+    void unit() { set_diag(1.0); }
+
+    void operator+=(const Matrix&m);
+        void operator-=(const Matrix&m);    
+    void operator*=(Real a);
+    void operator/=(Real a) { (*this) *= 1/a; }
+    
+    /// add a row
+    void insert_row(Vector v,int k);
+    /**
+      add a row to the matrix before  row k
+
+      PRE
+      v.dim() == cols()
+      0 <= k <= rows()
+    */
+    ///
+    void delete_row(int k) { dat->delete_row(k); }
+    /**
+      delete a row from this matrix.
+
+      PRE
+      0 <= k < rows();
+    */
+    void delete_column(int k) { dat->delete_column(k); }
+    ///
+    Matrix(int n);
+    /**
+      square n matrix, initialised to null
+    */
+    ///
+    Matrix(int n, int m);
+    /**
+      n x m matrix, init to 0
+    */
+    Matrix(const Matrix &m);
+
+    /// dyadic product: v * w.transpose
+    Matrix(Vector v, Vector w);
+    void operator=(const Matrix&m);
+
+    /// access an element
+    Real operator()(int i,int j) const;
+
+    /// access an element
+    Real &operator()(int i, int j);
+
+    /// Matrix multiply with vec (from right)
+    Vector operator *(const Vector &v) const;
+
+    /// set this to m1*m2.
+    void set_product(const Matrix &m1, const Matrix &m2);
+
+
+    Vector left_multiply(Vector const &) const;
+    
+    Matrix operator-() const;
+    
+    /// transpose this.
+    void transpose();
+    
+    /// return a transposed copy.
+    Matrix transposed() const ;
+
+    Real norm() const;
+    /// swap
+    void swap_columns(int c1, int c2);
+    /**
+      PRE
+      0 <= c1,c2 < cols()
+    */
+
+    /// swap
+    void swap_rows(int c1, int c2);
+    /**
+      PRE
+      0 <= c1,c2 < rows()
+    */
+
+
+    Vector row(int ) const;
+    Vector col(int) const;
+
+    operator String() const;
+    void print() const;
+};
+
+/** This is a class for a nonsquare block of #Real#s.  The
+    implementation of sparse matrices is done in the appropriate #smat#
+    class. Matrix only does the mathematical actions (adding,
+    multiplying, etc.)
+
+    
+    TODO
+    implement ref counting?  */
+
+
+inline Vector
+operator *(Vector &v, const Matrix& m) { return m.left_multiply(v); }
+Matrix operator *(const Matrix& m1,const Matrix &m2);
+Matrix operator /(const Matrix &m1,Real a);
+inline Matrix operator -(Matrix m1,const Matrix m2)
+{
+    m1 -= m2;
+    return m1;
+}
+#endif
diff --git a/misc.cc b/misc.cc
new file mode 100644 (file)
index 0000000..d07c358
--- /dev/null
+++ b/misc.cc
@@ -0,0 +1,32 @@
+#include "misc.hh"
+#include "glob.hh"
+#include "mtime.hh"
+#include <math.h>
+
+int intlog2(int d) {
+    int i=0;
+    while (!(d&1)) {
+       d/= 2; i++;
+    }
+    assert(!(d/2));
+    return i;
+}
+
+double log2(double x) {
+    return log(x)  /log(2.0);
+}
+
+
+// golden ratio
+const Real PHI = (1+sqrt(5))/2;
+const double ENGRAVERS_SPACE = PHI;
+const double WHOLE_SPACE = 10.0;
+
+  
+Real
+duration_to_idealspace(Mtime d)
+{
+    // see  Roelofs, p. 57
+    return WHOLE_SPACE * pow(ENGRAVERS_SPACE, log2(d));
+}
diff --git a/misc.hh b/misc.hh
new file mode 100644 (file)
index 0000000..a0ce016
--- /dev/null
+++ b/misc.hh
@@ -0,0 +1,8 @@
+#ifndef MISC_HH
+#define MISC_HH
+#include "mtime.hh"
+int intlog2(int d);    
+Real duration_to_idealspace(Mtime d);
+class String;
+char *get_version();
+#endif
diff --git a/molecule.cc b/molecule.cc
new file mode 100644 (file)
index 0000000..96a21b9
--- /dev/null
@@ -0,0 +1,87 @@
+#include "glob.hh"
+#include "string.hh"
+#include "molecule.hh"
+
+String
+Atom::TeXstring() const
+{
+    // whugh.. Hard coded...
+    String s("\\raise");
+    s+= String(off.y * VERT_TO_PT)+"pt\\hbox to 0pt{\\kern ";
+    s+=String(off.x * HOR_TO_PT) + "pt" + sym->tex + "\\hss}";
+    return s;
+}
+
+/****************************************************************/
+
+String
+Molecule::TeXstring() const
+{
+    String s;
+    for(Cursor<Atom> c(ats); c.ok(); c++)
+       s+=(*c).TeXstring();
+    return s;
+}
+
+Box
+Molecule::extent() const
+{
+    Box b;
+    for(Cursor<Atom> c(ats); c.ok(); c++)
+       b.unite((*c).extent());
+    return b;
+}
+
+void
+Molecule::translate(Offset o)
+{
+    for(Cursor<Atom> c(ats); c.ok(); c++)
+       (*c).translate(o);
+}
+
+void
+Molecule::add(const Molecule &m)
+{
+    for (Cursor<Atom> c(m.ats); c.ok(); c++) {
+       Atom a(c);
+       ats.bottom().add(a);    
+    }
+}
+
+void
+Molecule::add_right(const Molecule &m)
+{
+    Real xof=extent().x.max - m.extent().x.min;
+    Molecule toadd(m);
+    toadd.translate(Offset(xof, 0.0));
+    add(toadd);
+}
+
+void
+Molecule::add_left(const Molecule &m)
+{
+    Real xof=extent().x.min - m.extent().x.max;
+    Molecule toadd(m);
+    toadd.translate(Offset(xof, 0.0));
+        add(toadd);
+}
+
+
+void
+Molecule::add_top(const Molecule &m)
+{
+    Real yof=extent().y.max - m.extent().y.min;
+    Molecule toadd(m);
+    toadd.translate(Offset(0,yof));
+        add(toadd);
+}
+
+void
+Molecule::add_bot(const Molecule &m)
+{
+    Real yof=extent().y.min- m.extent().y.max;
+    Molecule toadd(m);
+    toadd.translate(Offset(0,yof));
+    add(toadd);
+}
+
diff --git a/molecule.hh b/molecule.hh
new file mode 100644 (file)
index 0000000..c98cfe5
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef MOLECULE_HH
+#define MOLECULE_HH
+
+#include "list.hh"
+#include "boxes.hh"
+#include "item.hh"
+
+/// a symbol which can be translated, and freely copied
+struct Atom {
+    Offset off;
+    const Symbol * sym;
+
+    void translate(Offset o) {
+       off += o;
+    }
+    
+    /// how big is #this#?
+    Box extent() const {
+       Box b( sym->dim);
+       b.translate(off);
+       return b;
+    }
+    Atom(const Symbol*s) {
+       sym=s;
+    }
+    String TeXstring() const;
+};
+
+/// a group of #Atom#s
+struct Molecule : Output {
+    List<Atom> ats;
+
+    Molecule() { }
+    Molecule(Atom a) { ats.bottom().add(a); }
+    //    Molecule(Molecule const&src);
+    void add_right(const Molecule &m);
+    void add_left(const Molecule &m);
+    void add_top(const Molecule &m);
+    void add_bot(const Molecule &m);
+    void add(Molecule const &m);
+    void translate(Offset);
+
+    /// how big is #this#? 
+    Box extent() const;
+
+    String TeXstring() const;
+};
+/** a group of individually translated symbols. You can add molecules
+    to the top, to the right, etc.  */
+#endif
diff --git a/mtime.hh b/mtime.hh
new file mode 100644 (file)
index 0000000..f42c87b
--- /dev/null
+++ b/mtime.hh
@@ -0,0 +1,8 @@
+#ifndef MTIME_HH
+#define MTIME_HH
+
+#include "real.hh"
+
+typedef Real Mtime;
+
+#endif MTIME_HH
diff --git a/note.cc b/note.cc
new file mode 100644 (file)
index 0000000..538f26a
--- /dev/null
+++ b/note.cc
@@ -0,0 +1,130 @@
+#include <ctype.h>
+#include "string.hh"
+#include "real.hh"
+#include "debug.hh"
+#include "request.hh"
+#include "voice.hh"
+#include "notename.hh"
+
+int default_duration = 4;
+
+void
+parse_duration(const char *a, int &j, int &intdur, int &dots)
+{    
+    String durstr;    
+    while (isdigit(a[j])) 
+       {
+       durstr += a[j++];
+       }
+
+    dots=0;
+    
+    while (a[j] == '.') 
+       {
+       j++;
+       dots++;
+       }
+    intdur = (durstr.len()) ?
+       durstr.value():default_duration;
+
+    if (debug_flags & DEBUGTOKEN) 
+       mtor << "dur " << intdur << "dots " << dots<<eol;
+}
+
+
+void 
+parse_pitch( const char *a, int &j, int &oct, bool & overide_acc,
+            int & large, int & small)
+{
+    // octave
+ oct =0;
+    
+    while (1) 
+       {       
+       if (a[j] == '\'')
+           oct ++;
+       else    if (a[j] == '`')
+           oct --;
+       else
+           break;
+       j++;
+       
+       }
+    if (debug_flags & DEBUGTOKEN) mtor << "oct " << oct;
+       
+    // accidental
+    overide_acc = false;
+    
+    if (a[j] == '!')
+       {       
+       overide_acc = true;
+       j++;
+       }
+
+    if (debug_flags & DEBUGTOKEN)
+       mtor << "ov " << overide_acc;
+    
+    // notename.
+    String nm;
+    while (isalpha(a[j])) 
+       {
+       nm += a[j++];
+       }
+    if (isupper(nm[0]))
+       {
+       oct--;  
+       nm.lower();
+       }
+        
+
+    lookup_notename(large,small,nm);
+    if (debug_flags & DEBUGTOKEN)
+       mtor << "int "<< large <<" "<<small<<" ";    
+}
+
+
+Voice_element *
+get_note_element(String pitch, String durstr)
+{
+    Voice_element*v = new Voice_element;
+    int i=0;
+    
+    int dur, dots;
+    parse_duration(durstr, i, dur, dots);
+    i=0;
+
+    Note_req * rq = new Note_req( v);
+
+    int oct, pit, acc;
+    bool forceacc;
+    parse_pitch(pitch, i, oct, forceacc, pit, acc);
+
+    rq->octave = oct;
+    rq->accidental = acc;
+    rq->forceacc = forceacc;
+    rq->balltype = dur;
+    rq->dots = dots;
+    
+
+    v->add(rq);
+    return v;
+}
+
+Voice_element *
+get_rest_element(String type, String durstr)
+{    
+    Voice_element*v = new Voice_element;
+    int i=0;
+    
+    int dur, dots;
+    parse_duration(durstr, i, dur, dots);
+    i=0;
+
+    Rest_req * rq = new Rest_req(v);
+  
+    rq->balltype = dur;
+    rq->dots = dots;    
+
+    v->add(rq);
+    return v;
+}
diff --git a/notename.cc b/notename.cc
new file mode 100644 (file)
index 0000000..8ebc4df
--- /dev/null
@@ -0,0 +1,30 @@
+#include "glob.hh"
+#include "string.hh"
+
+
+/// change this along with lex file for other notenames.
+const char *notetab[] = 
+{
+"ceses", "ces", "c", "cis", "cisis",
+"deses", "des", "d", "dis", "disis",
+"eses", "es", "e", "eis", "eisis",
+"feses", "fes", "f", "fis", "fisis",
+"geses", "ges", "g", "gis", "gisis",
+"ases", "as", "a", "ais", "aisis",
+"beses", "bes", "b", "bis", "bisis",
+0
+};
+
+void
+lookup_notename(int &large, int &small, String s)
+{
+    int i;
+    for (i =0; notetab[i]; i++)
+       if (s == notetab[i]) 
+           {
+           large = i /5;
+           small = i %5 - 2;
+           return;         
+           }
+    assert(false);    
+}
diff --git a/notename.hh b/notename.hh
new file mode 100644 (file)
index 0000000..ef04a0d
--- /dev/null
@@ -0,0 +1,2 @@
+
+void lookup_notename(int &large, int &small, String s);
diff --git a/parseconstruct.hh b/parseconstruct.hh
new file mode 100644 (file)
index 0000000..820499c
--- /dev/null
@@ -0,0 +1,7 @@
+
+#include "proto.hh"
+
+Staff * get_new_rhythmstaff();
+Voice_element * get_note_element(String,String);
+Voice_element* get_rest_element(String,String);
+Command *  get_bar_command(Real);
diff --git a/parser.y b/parser.y
new file mode 100644 (file)
index 0000000..23987a2
--- /dev/null
+++ b/parser.y
@@ -0,0 +1,121 @@
+%{ // -*-Fundamental-*-
+#include <iostream.h>
+//#include "mudobs.hh"
+#include "lexer.hh"
+#include "staff.hh"
+#include "score.hh"
+#include "keyword.hh"
+#include "globvars.hh"
+#include "debug.hh"
+#include "parseconstruct.hh"
+#define YYDEBUG 1
+
+
+%}
+
+
+%union {
+     int i;    
+    Real real;
+    Command *command;
+    Identifier *id;    
+
+    Voice *voice;    
+    Voice_element *el; 
+    Staff *staff;    
+    String *string;
+    Score *score;    
+}
+
+%token VOICE STAFF SCORE TITLE RHYTHMSTAFF BAR NOTENAME
+
+%token <id> IDENTIFIER
+%token <string> PITCH DURATION RESTNAME
+%token <real> REAL
+
+
+%type <voice> voice_block voice_body voice_elts voice_elts_dollar
+%type <el> voice_elt
+%type <command> score_command
+%type <score> score_block score_body
+%type <staff> staff_block  rhythmstaff_block rhythmstaff_body
+
+%%
+
+mudela:
+       score_block { 
+               delete the_score; 
+               the_score = $1;
+       }
+       ;
+
+
+score_block: SCORE '{' score_body '}'  { $$ = $3; }
+       ;
+
+score_body:            { $$ = new Score; } 
+       | score_body staff_block        { $$->add($2); }
+       | score_body score_command      { $$->add($2); }
+       ;
+
+staff_block:
+       rhythmstaff_block
+       ;
+
+rhythmstaff_block:
+       RHYTHMSTAFF '{' rhythmstaff_body '}'    { $$ = $3; }
+       ;
+
+rhythmstaff_body:
+       /* empty */                     { $$ = get_new_rhythmstaff(); }
+       | rhythmstaff_body voice_block  { $$->add_voice($2); }  
+       ;
+
+voice_block:
+       VOICE '{' voice_body '}'        { $$ = $3; }
+       ;
+
+
+voice_body:
+       REAL voice_elts_dollar { $$ = $2; $$->start = $1; }
+       | voice_elts_dollar     { $$ = $1; }
+       ;
+
+voice_elts_dollar:
+       '$' voice_elts '$'  { $$ = $2; }
+       ;
+
+voice_elts:
+       /* empty */             {
+            $$ = new Voice;
+        }
+        | voice_elts voice_elt {
+            $$->add($2);
+        }
+       ;
+
+voice_elt:
+       PITCH DURATION                  { $$ = get_note_element(*$1, *$2);
+
+       }
+       |  RESTNAME DURATION            { $$ = get_rest_element(*$1, *$2);
+
+       }
+       ;
+
+score_command:
+       BAR REAL                        {
+               $$ = get_bar_command($2);
+       }
+       ;
+
+%%
+
+void
+parse_file(String s)
+{
+   *mlog << "Parsing ... ";
+   yydebug = debug_flags & DEBUGPARSER;
+   new_input(s);
+   yyparse();
+}
diff --git a/proto.hh b/proto.hh
new file mode 100644 (file)
index 0000000..0721e19
--- /dev/null
+++ b/proto.hh
@@ -0,0 +1,76 @@
+#include "real.hh"
+
+class Vector;
+class Matrix;
+class Line_of_score;
+class Line_of_staff;
+class PCol;
+class PStaff;
+class Staff;
+class Staff_column;
+class Score;
+class Score_column;
+class Voice;
+class Voice_element;
+class Voicegroup;
+class Request;
+class Command;
+class Request;
+class Stem_req;
+class Span_req;
+class Slur_req;
+class Decresc_req;
+class Cresc_req;
+class Bracket_req;
+class Script_req;
+class Rest_req;
+class Note_req;
+class Lyric_req;
+class Chord;
+class Absdynamic_req;
+struct Offset;
+struct Interval;
+struct Box;
+struct PCol;
+struct Idealspacing;
+struct Spanner;
+struct Item;
+struct Line_of_staff;
+struct Colinfo;
+struct Linestaff;
+struct Atom;
+struct Molecule;
+struct PScore;
+struct Request;
+struct Note_req;
+struct Lyric_req;
+struct Script_req;
+struct Rest_req;
+struct Chord;
+struct Stem_req;
+struct Span_req;
+struct Beam_req;
+struct Bracket_req;
+struct Slur_req;
+struct Dynamic;
+struct Cresc_req;
+struct Decresc_req;
+struct Absdynamic_req;
+struct Score_column;
+struct Score;
+struct Staff_column;
+struct Staff;
+struct Command;
+struct Symbol;
+struct Stretchable_symbol;
+struct Output;
+struct Text_gob;
+struct Voice;
+struct Voicegroup;
+struct Voice_element;
+struct String;
+struct Tex_stream;
+struct Identifier;
+struct Keyword;
+class Mixed_qp;
+typedef  Mixed_qp Optimisation_problem;
diff --git a/pscore.cc b/pscore.cc
new file mode 100644 (file)
index 0000000..dd8ae69
--- /dev/null
+++ b/pscore.cc
@@ -0,0 +1,99 @@
+// utility functions for PScore
+#include "debug.hh"
+#include "line.hh"
+#include "pscore.hh"
+#include "tstream.hh"
+
+void
+PScore::clean_cols()
+{
+    for (PCursor<PCol *> c(cols); c.ok(); c++)
+       if (!c->used) {
+           c.remove();
+           //mtor << "removing pcol\n";
+       }
+}
+       
+
+void
+PScore::add(PStaff *s)
+{
+    staffs.bottom().add(s);    
+}
+
+void
+PScore::typeset_item(Item *i, PCol *c, PStaff *s, int breakstat)
+{
+    assert(c && i && s);
+    if (breakstat == 1 ) {
+       typeset_item(i, c->prebreak, s, 0);
+    } if (breakstat == 3) 
+       typeset_item(i, c->prebreak, s, 0 );
+    else{
+       its.bottom().add(i);
+       s->add(i);
+       c->add(i);
+    }
+}
+
+void
+PScore::add_line(svec<const PCol *> curline, svec<Real> config)
+{    
+    Line_of_score *p = new Line_of_score(curline,this);
+    lines.bottom().add(p);     
+    for (int i=0; i < curline.sz(); i++){
+       PCol *c=(PCol *)curline[i]; // so, this isn't really const.
+       c->hpos= config[i];
+    }
+}
+
+Idealspacing*
+PScore::get_spacing(PCol*l, PCol*r)
+{
+    assert(l!=r);
+    for (PCursor<Idealspacing*> ic (suz); ic.ok(); ic++) {
+       if (ic->left == l && ic->right == r){
+           return ic;
+       }
+    }
+    
+    Idealspacing*ip =new Idealspacing(l,r);
+    suz.bottom().add(ip);
+    //    l->used = r->used = true;
+    return ip;
+}
+
+svec<const PCol *>
+PScore::find_breaks() const
+{
+    svec<const PCol *> retval;
+    for (PCursor<PCol *> c(cols); c.ok(); c++)
+       if (c->breakable)
+           retval.add(c);
+           
+    return retval;
+}
+
+void
+PScore::add(PCol *p)
+{
+    cols.bottom().add(p);
+}
+/*
+    todo: config of width
+    */
+PScore::PScore()
+{
+    linewidth = 15;            // in cm for now
+}
+
+void
+PScore::output(Tex_stream &ts)
+{
+    int l=1;
+    ts << "% linewidth " << linewidth * HOR_TO_PT << " pt\n";
+    for (PCursor<Line_of_score*> lic(lines); lic.ok(); lic++) {
+       ts << "% line of score no. " << l++ <<"\n";
+       ts << lic->TeXstring();
+    }  
+}
diff --git a/pscore.hh b/pscore.hh
new file mode 100644 (file)
index 0000000..75da46a
--- /dev/null
+++ b/pscore.hh
@@ -0,0 +1,80 @@
+// the breaking problem for a score.
+
+#ifndef PSCORE_HH
+#define PSCORE_HH
+
+
+#include "vray.hh"
+#include "cols.hh"
+#include "pstaff.hh"
+
+/// all stuff which goes onto paper
+struct PScore {
+    /// width of paper
+    Real linewidth;
+    
+    /// the columns, ordered left to right
+    PointerList<PCol *> cols;
+
+    /// the idealspacings, no particular order
+    PointerList<Idealspacing*> suz;
+
+    /// the staffs ordered top to bottom
+    PointerList<PStaff*> staffs;
+
+    /// all symbols in score. No particular order.
+    PointerList<Item*> its;
+
+    /// if broken, the different lines
+    PointerList<Line_of_score*> lines;
+
+    /// crescs etc; no particular order
+    PointerList<Spanner *> spanners;
+
+    /****************************************************************/
+    
+    void calc_breaking();
+    /**
+      calculate where the lines are to be broken.
+
+      POST
+    
+      lines contain the broken lines.
+     */
+
+    /// search all pcols which are breakable.
+    svec<const PCol *> find_breaks() const;
+
+    /// add a line to the broken stuff. Positions given in #config#
+    void add_line(svec<const PCol *> curline, svec<Real> config);
+
+    /// helper: solve for the columns in #curline#.
+    svec<Real> solve_line(svec<const PCol *> curline) const;
+
+    void add(PStaff *);
+    /// add item
+    void typeset_item(Item *,  PCol *,PStaff*,int);
+    ///    add to bottom of pcols
+    void add(PCol*);
+    /**
+
+    */
+    void output(Tex_stream &ts);
+
+    Idealspacing* get_spacing(PCol *, PCol *);
+    /*
+    get the spacing between c1 and c2, create one if necessary.
+    */
+
+
+    PCursor<PCol *> find_col(PCol *);
+    void clean_cols();
+    void problem_OK() ;
+
+    PScore();
+};
+/** notes, signs, symbols in a score can be grouped in two ways:
+    horizontally (staffwise), and vertically (columns). #PScore#
+    contains the items, the columns and the staffs.
+ */
+#endif
diff --git a/pstaff.cc b/pstaff.cc
new file mode 100644 (file)
index 0000000..c922fe9
--- /dev/null
+++ b/pstaff.cc
@@ -0,0 +1,13 @@
+#include "pstaff.hh"
+
+PStaff::PStaff()
+{
+    stafsym = 0;
+}
+
+void
+PStaff::add(Item *i )
+{
+    its.bottom().add(i);
+    i->pstaff_ = this;
+}
diff --git a/pstaff.hh b/pstaff.hh
new file mode 100644 (file)
index 0000000..de535a6
--- /dev/null
+++ b/pstaff.hh
@@ -0,0 +1,19 @@
+#ifndef PSTAFF_HH
+#define PSTAFF_HH
+
+#include "list.hh"
+#include "item.hh"
+
+/// items grouped vertically.
+class PStaff {
+public:
+    Stretchable_symbol *stafsym;
+    List<const Spanner*> spans;
+    List<Item*> its;
+
+    void add(Item*i);
+    PStaff();
+    virtual ~PStaff() {}
+};
+
+#endif
diff --git a/qlp.cc b/qlp.cc
new file mode 100644 (file)
index 0000000..21997f6
--- /dev/null
+++ b/qlp.cc
@@ -0,0 +1,137 @@
+#include "debug.hh"
+#include "qlp.hh"
+#include "choleski.hh"
+void
+Mixed_qp::add_equality_cons(Vector v, double r)
+{
+    assert(false);
+}
+void
+Mixed_qp::add_fixed_var(int i, Real r)
+{
+    
+   eq_cons.add(i);
+   eq_consrhs.add(r);
+}
+   void
+Ineq_constrained_qp::add_inequality_cons(Vector c, double r)
+{
+    cons.add(c);
+    consrhs.add(r);
+}
+
+Ineq_constrained_qp::Ineq_constrained_qp(int novars):
+    quad(novars),
+    lin(novars)
+{
+}
+
+void
+Ineq_constrained_qp::OK()const
+{
+    assert(cons.sz() == consrhs.sz());
+    Matrix Qdif= quad - quad.transposed();
+    assert(Qdif.norm() < EPS);
+}
+     
+
+Real
+Ineq_constrained_qp::eval (Vector v)
+{
+    return v * quad * v + lin * v ;
+}
+/*
+    eliminate appropriate variables, until we have a Ineq_constrained_qp
+    then solve that.
+
+    PRE
+    cons should be ascending
+    */
+Vector
+Mixed_qp::solve(Vector start) const 
+{
+
+    Ineq_constrained_qp pure(*this);
+    
+    for  (int i= eq_cons.sz()-1; i>=0; i--) {
+       pure.eliminate_var(eq_cons[i], eq_consrhs[i]);
+       start.del(eq_cons[i]);
+    }
+    Vector sol = pure.solve(start);
+    for (int i= 0; i < eq_cons.sz(); i++) {
+       sol.insert( eq_consrhs[i],eq_cons[i]);
+    }
+    return sol;
+}
+
+/*
+    assume x(idx) == value, and adjust constraints, lin and quad accordingly
+    */
+void
+Ineq_constrained_qp::eliminate_var(int idx, Real value)
+{
+    Vector row(quad.row(idx));
+    row*= value;
+
+    quad.delete_row(idx);
+
+    quad.delete_column(idx);
+
+    lin.del(idx);
+    row.del(idx);
+    lin +=row ;
+
+   for (int i=0; i < cons.sz(); i++) {
+      consrhs[i] -= cons[i](idx) *value;
+      cons[i].del(idx);
+   }
+}
+
+
+
+
+Mixed_qp::Mixed_qp(int n)
+    : Ineq_constrained_qp(n)
+{
+}
+
+void
+Mixed_qp::OK()const
+{
+    Ineq_constrained_qp::OK();
+    assert(eq_consrhs.sz() == eq_cons.sz());
+}
+void
+Ineq_constrained_qp::print() const
+{
+
+    mtor << "Quad " << quad;
+    mtor << "lin " << lin <<"\n";
+    for (int i=0; i < cons.sz(); i++) {
+       mtor << "constraint["<<i<<"]: " << cons[i] << " >= " << consrhs[i];
+       mtor << "\n";
+    }
+}
+void
+Mixed_qp::print() const
+{
+    Ineq_constrained_qp::print();
+    for (int i=0; i < eq_cons.sz(); i++) {
+       mtor << "eq cons "<<i<<": x["<<eq_cons[i]<<"] == " << eq_consrhs[i]<<"\n";
+    }
+}
+
+
+void
+Ineq_constrained_qp::assert_solution(Vector sol) const
+{
+    svec<int> binding;
+    for (int i=0; i < cons.sz(); i++) {
+       Real R=cons[i] * sol- consrhs[i];
+       assert(R> -EPS);
+       if (R < EPS)
+           binding.add(i);
+    }
+    // KKT check...
+    // todo
+}
diff --git a/qlp.hh b/qlp.hh
new file mode 100644 (file)
index 0000000..83938c9
--- /dev/null
+++ b/qlp.hh
@@ -0,0 +1,89 @@
+#ifndef QLP_HH
+#define QLP_HH
+
+#include "matrix.hh"
+
+/// inequality constrained quadratic program
+class Ineq_constrained_qp {
+    friend class Active_constraints;
+
+    svec<Vector> cons;
+    svec<Real> consrhs;
+public:
+    Matrix quad;
+    Vector lin;
+
+
+    ///
+    void assert_solution(Vector sol) const;
+    /**
+      use a KKT method to assert optimality of sol
+      */
+    /// solve the problem using a variable metric method
+    Vector solve(Vector start) const;
+    
+    int dim() const{
+       return lin.dim();
+    }
+    /** return the number of variables in the problem */
+    ///
+    void add_inequality_cons(Vector c, double r);
+    /**
+      add a constraint
+
+
+        c*vars >= r
+
+      PRE
+      c.dim() == dim();
+       
+      */
+    ///
+    Ineq_constrained_qp(int novars);
+    /** set up matrices to go with the problem. */
+
+    Real eval(Vector v);
+    /**
+    evaluate the quadratic function for input #v#
+    */
+
+    void eliminate_var(int idx, Real value);
+    void OK()const;
+    void print() const;
+
+};
+
+/// Quadratic programming with mixed linear constraints
+class Mixed_qp :public Ineq_constrained_qp {
+    svec<int> eq_cons;
+    svec<Real> eq_consrhs;
+public:
+    Mixed_qp(int n);
+    void OK() const;
+    void print() const;
+
+    Vector solve(Vector start) const;
+    void add_fixed_var(int i , Real value);
+    
+    ///
+    void add_equality_cons(Vector c, double r);
+    /**
+      add a constraint,
+
+        c*vars == r
+
+      PRE
+      c.dim()==dim();
+     */
+
+};
+/**
+  problem definition of a quadratic optimisation problem with linear
+  inequality and equality constraints
+
+
+    x^T QUAD x /2 + b^T x 
+*/
+
+typedef Mixed_qp Optimisation_problem;
+#endif
diff --git a/qlpsolve.cc b/qlpsolve.cc
new file mode 100644 (file)
index 0000000..0884223
--- /dev/null
@@ -0,0 +1,230 @@
+#include "qlpsolve.hh"
+#include "debug.hh"
+#include "choleski.hh"
+
+const Real TOL=1e-2;           // roughly 1/10 mm
+
+String
+Active_constraints::status() const
+{
+    String s("Active|Inactive [");
+    for (int i=0; i< active.sz(); i++) {
+       s += String(active[i]) + " ";
+    }
+
+    s+="|";
+    for (int i=0; i< inactive.sz(); i++) {
+       s += String(inactive[i]) + " ";
+    }
+    s+="]";
+
+    return s;
+}
+
+void
+Active_constraints::OK() {
+    H.OK();
+    A.OK();
+    assert(active.sz() +inactive.sz() == opt->cons.sz());
+    assert(H.dim() == opt->dim());
+    assert(active.sz() == A.rows());
+    svec<int> allcons;
+
+    for (int i=0; i < opt->cons.sz(); i++)
+       allcons.add(0);
+    for (int i=0; i < active.sz(); i++) {
+       int j = active[i];
+       allcons[j]++;
+    }
+    for (int i=0; i < inactive.sz(); i++) {
+       int j = inactive[i];
+       allcons[j]++;
+    }
+    for (int i=0; i < allcons.sz(); i++)
+       assert(allcons[i] == 1);
+}
+
+Vector
+Active_constraints::get_lagrange(Vector gradient)
+{
+    Vector l(A*gradient);
+
+    return l;
+}
+
+void
+Active_constraints::add(int k)
+{
+    // add indices
+    int cidx=inactive[k];
+    active.add(cidx);
+
+    inactive.swap(k,inactive.sz()-1);
+    inactive.pop();
+
+    Vector a( opt->cons[cidx] );
+    // update of matrices
+    Vector Ha = H*a;
+    Real aHa = a*Ha;
+
+    H -= Matrix(Ha , Ha)/(aHa);
+
+    Vector addrow(Ha/(aHa));
+    A -= Matrix(A*a, addrow);
+    A.insert_row(addrow,A.rows());        
+}
+
+void
+Active_constraints::drop(int k)
+{
+    int q=active.sz()-1;
+
+        // drop indices
+    inactive.add(active[k]);
+    active.swap(k,q);
+    A.swap_rows(k,q);
+    active.pop();
+
+    Vector a(A.row(q));
+    H += Matrix(a,a)/(a*opt->quad*a);
+    A -= A*opt->quad*Matrix(a,a)/(a*opt->quad*a);
+
+    Vector rem_row(A.row(q));
+    assert(rem_row.norm() < EPS);    
+    A.delete_row(q);
+}
+
+
+Active_constraints::Active_constraints(Ineq_constrained_qp const *op)
+    :       A(0,op->dim()),
+           H(op->dim()),
+           opt(op)
+{
+    for (int i=0; i < op->cons.sz(); i++)
+       inactive.add(i);
+    Choleski_decomposition chol(op->quad);
+    H=chol.inverse();
+}
+
+/* Find the optimum which is in the planes generated by the active
+    constraints.        
+    */
+Vector
+Active_constraints::find_active_optimum(Vector g)
+{
+    return H*g;
+}
+
+/****************************************************************/
+
+int
+min_elt_index(Vector v)
+{
+    Real m=INFTY; int idx=-1;
+    for (int i = 0; i < v.dim(); i++)
+       if (v(i) < m) {
+           idx = i;
+           m = v(i);
+       }
+    return idx;
+}
+
+///the numerical solving
+Vector
+Ineq_constrained_qp::solve(Vector start) const 
+{    
+    Active_constraints act(this);
+
+
+    act.OK();    
+
+    
+    Vector x(start);
+    Vector gradient=quad*x+lin;
+
+
+    Vector last_gradient(gradient);
+    int iterations=0;
+    
+    while (iterations++ < MAXITER) {
+       Vector direction= - act.find_active_optimum(gradient);
+               
+       //      mtor << "gradient "<< gradient<< "\ndirection " << direction<<"\n";
+       
+       if (direction.norm() > EPS) {
+           //  mtor << act.status() << '\n';
+           
+           Real minalf = INFTY;
+
+           Inactive_iter minidx(act);
+
+
+           /*
+    we know the optimum on this "hyperplane". Check if we
+    bump into the edges of the simplex
+    */
+    
+           for (Inactive_iter ia(act); ia.ok(); ia++) {
+
+               if (ia.vec() * direction >= 0)
+                   continue;
+               Real alfa= - (ia.vec()*x - ia.rhs())/
+                   (ia.vec()*direction);
+               
+               if (minalf > alfa) {
+                   minidx = ia;
+                   minalf = alfa;
+               }
+           }
+           Real unbounded_alfa = 1.0;
+           Real optimal_step = MIN(minalf, unbounded_alfa);
+
+           Vector deltax=direction * optimal_step;
+           x += deltax;            
+           gradient += optimal_step * (quad * deltax);
+           
+           //mtor << "step = " << optimal_step<< " (|dx| = " <<
+           //deltax.norm() << ")\n";       
+          
+           if (minalf < unbounded_alfa) {
+               /* bumped into an edge. try again, in smaller space. */
+               act.add(minidx.idx());
+               continue;
+           }
+           /*ASSERT: we are at optimal solution for this "plane"*/
+    
+    
+       }
+       
+       Vector lagrange_mult=act.get_lagrange(gradient);        
+       int m= min_elt_index(lagrange_mult);
+       
+       if (m>=0 && lagrange_mult(m) > 0) {
+           break;              // optimal sol.
+       } else if (m<0 && gradient.norm() < EPS) {
+           break;
+       }
+       
+       mtor << "dropping cons " << m<<'\n';
+       act.drop(m);
+    }
+    if (iterations >= MAXITER)
+       WARN<<"didn't converge!\n";
+    
+    //    mtor <<  ": found " << x<<" in " << iterations <<" iterations\n";
+    assert_solution(x);
+    return x;
+} 
+
+/** Mordecai Avriel, Nonlinear Programming: analysis and methods (1976)
+    Prentice Hall.
+
+    Section 13.3
+
+    This is a "projected gradient" algorithm. Starting
+    from a point x the next point is found in a direction determined by
+    projecting the gradient onto the active constraints.  */
+    
+/*
+    thoroughly hacked to barely living tiny pieces by HW
+    */
diff --git a/qlpsolve.hh b/qlpsolve.hh
new file mode 100644 (file)
index 0000000..4d29bcc
--- /dev/null
@@ -0,0 +1,78 @@
+#include "qlp.hh"
+#include "matrix.hh"
+
+
+class Active_constraints {
+    friend class Inactive_iter;
+    
+
+    Matrix A,H;
+    svec<int> active;
+    svec<int> inactive;                // actually this is a set, not an array.
+    const Ineq_constrained_qp *opt;
+
+public:
+    String status()const;
+    
+    Vector vec(int k) const { return opt->cons[k]; }
+    Real rhs(int k) const { return opt->consrhs[k]; }
+    
+    /// drop constraint
+    void drop (int k);
+    /** drop constraint k from the active set. k is the index of the
+    constraint in #active#
+    
+    */
+    
+    ///     add constraint j
+    void add(int j);
+    /**
+    add constraint j to the active set j is the index of the
+    constraint in #inactive#   
+    */
+
+    /// exchange in and out.
+    void exchange(int in, int out) { add(in); drop (out); }
+    
+    /// 
+    Vector find_active_optimum(Vector g);
+
+    /// get lagrange multipliers.
+    Vector get_lagrange(Vector v);
+
+    Active_constraints(Ineq_constrained_qp const *op);
+    /** construct: no constraints active, n vars. Put the equalities
+     into the constraints.  */
+
+    /// check invariants
+    void OK();
+};
+
+/**
+    This class represents the set of active (binding) constraints
+    which can be active while the QLP algorithm is in a feasible
+    point. The active constraints are numbered.
+    If the constraints are of the form
+
+      A^T*x >= b
+
+    then the binding constraints are those where the >= is equality.
+    
+  */
+
+///
+class Inactive_iter {
+    int j;
+    Active_constraints const* ac;
+public:
+    Inactive_iter(Active_constraints const &c) { ac=&c; j=0; }
+    int idx() const { return j; }
+    void operator ++(int) { j++; }
+    int constraint_id() const { return ac->inactive[j]; }
+    Vector vec() const { return ac->vec(constraint_id()); }
+    Real rhs() const { return ac->rhs(constraint_id()); }
+    bool ok() const { return j < ac->inactive.sz(); }
+};
+/**
+    loop through the inactive constraints.
+  */
diff --git a/real.hh b/real.hh
new file mode 100644 (file)
index 0000000..1f2187c
--- /dev/null
+++ b/real.hh
@@ -0,0 +1,25 @@
+#ifndef REAL_HH
+#define REAL_HH
+typedef double Real;
+inline Real sqr(Real x){
+    return x*x;
+}
+inline Real MIN(Real x, Real y) {
+    return (x < y)? x : y;
+}
+
+inline Real MAX(Real x, Real y) {
+    return (x > y) ? x : y;
+}
+
+inline Real ABS(Real x)
+{
+    return (x>0)? x:-x;
+}
+inline
+int sgn(Real x) {
+    if (!x)return 0;
+    return (x > 0) ?1: -1;
+}
+
+#endif
diff --git a/request.cc b/request.cc
new file mode 100644 (file)
index 0000000..27029ba
--- /dev/null
@@ -0,0 +1,70 @@
+#include "request.hh"
+Request::Request(Voice_element*v)
+{
+    elt = v;
+    tag = UNKNOWN;
+}
+
+Note_req::Note_req(Voice_element*v):
+    Request(v)
+{
+    name = 'c';
+    octave = 0;
+    accidental = 0;
+    forceacc = false;
+    balltype = 1;
+    dots = 0;
+    tag = NOTE;
+}
+
+Rest_req::Rest_req(Voice_element*v)
+     :Request(v)
+{
+    balltype = 1;
+    dots = 0;
+    tag =REST;    
+}
+
+Request::Request()
+{
+    elt = 0;
+    tag = UNKNOWN;    
+}
+
+Note_req*
+Request::note()
+{
+    assert(tag == NOTE);
+    return (Note_req*)this;
+}
+
+Rest_req*
+Request::rest()
+{
+    assert(tag == REST);
+    return (Rest_req*)this;
+}
+
+
+Real
+wholes(int dur, int dots)
+{
+    Real f = 1.0/Real(dur);
+    Real delta = f;
+
+    while (dots--) {
+       delta /= 2.0;
+       f += delta;
+    }
+    return f;    
+}
+
+Real
+Note_req::duration() const {    
+    return wholes( balltype,dots);
+}
+Real
+Rest_req::duration() const{
+    return wholes( balltype,dots);
+}
+
diff --git a/request.hh b/request.hh
new file mode 100644 (file)
index 0000000..0cd0fe0
--- /dev/null
@@ -0,0 +1,195 @@
+// mpp96's second egg of columbus!
+#ifndef REQUEST_HH
+#define REQUEST_HH
+
+#include "glob.hh"
+#include "string.hh"
+#include "mtime.hh"
+struct Request {
+    Voice_element*elt;
+    enum {
+       UNKNOWN, NOTE, REST, LYRIC, SCRIPT, CHORD, BEAM,
+       BRACKET, STEM, SLUR, CRESC, DECRESC, ABSDYNAMIC
+    } tag;
+
+    Note_req *note();
+    Rest_req *rest();
+    Request(Voice_element*);
+    Request();
+    virtual Real duration() const { return 0.0; }
+};
+
+/**
+    Any Voice_element can do a number of requests. A request is done
+    to the #Staff# which contains the #Voice_element#. The staff decides
+    whether to to honor the request, ignore it, or merge it with other
+    requests. Merging of requests is preferably done with other
+    requests done by members of the same voicegroups (beams, brackets, stems) 
+
+    Please refer to the documentation of the Child classes of
+    #Request# for explanation of each request type.
+
+    The result of a request will be an #Item# or a #Spanner#, which
+    will be put on a #PStaff#. Note that the #PStaff# and the original
+    #Staff# need not have anything in common. For example, the
+    ``double'' piano Staff could interpret commands which juggle
+    melodies across the left and right hand, and may put the result in
+    two five-line PStaffs (maybe with extra PStaffs to carry the dynamic
+    signs and any lyric.
+
+    The class #Staff# should be thought as a container for the
+    #Voice#s, and an interpreter for #Request#s and #Command#s.
+    Different staffs can produce different outputs; a melodious voice
+    which is put into a percussion-Staff, will be typeset as the rythm of
+    that voice.
+
+    After #Staff# made up her mind (Would #Staff# be a smart
+    name? How about #struct Lily {}# :-), the resultant items and
+    spanners are put on the PScore, and pointers to these items are
+    stored in the #Voice_element#. This construction enables the
+    beams/stems to look up the balls it has to connect to.  */
+       
+
+    
+/// Put a note of specified type, height, and with accidental on the staff.
+struct Note_req : Request {
+    char name;
+    int octave;
+    int accidental;
+    bool forceacc;
+    int balltype;
+    int dots;
+    
+    Real duration() const;
+    Note_req(Voice_element*v);
+};
+/**
+Staff has to decide if the ball should be hanging left or right. This
+influences the horizontal dimensions of a column, and this  is why
+request processing should be done before horizontal spacing.
+
+Other voices' frivolities may cause the need for accidentals, so this
+is also for the Staff to decide. The Staff can decide on positioning
+based on ottava commands and the appropriate clef.
+*/
+
+///Put a lyric above or below (?) this staff.
+struct Lyric_req : Request {
+    String text;
+};
+
+
+///Put a script above or below this ``note''    
+struct Script_req : Request {
+    int orientation;
+    Symbol *sym;
+};
+/**
+eg upbow, downbow. Why a request? These symbols may conflict with slurs and brackets, so this
+also a request
+*/
+
+
+///Put a rest on the staff.
+struct Rest_req : Request {
+    int balltype;
+    int dots;
+    Rest_req(Voice_element*);
+    Real duration() const;
+};
+/**
+Why a request? It might be a good idea to not typeset the rest, if the paper is too crowded.
+*/
+
+
+
+///Draw a (Guitar) chord above or below this ``note''
+struct Chord : Request {
+       // don't know how this looks.
+};
+/**
+Why a request?
+Because everything else is done in requests.
+*/
+
+
+/// for absolute dynamics
+enum Loudness {
+    FFF, FF, F, MF, MP, P, PP, PPP
+} ;
+
+/// attach a stem to the noteball
+struct Stem_req : Request {
+    /// 4,8,16, ..
+    int stem_number ;
+};
+/// requests to start or stop something.
+struct Span_req : Request {
+    /// should the spanner start or stop, or is it unwanted?
+    enum {
+       NOSPAN, START, STOP
+    } spantype ;
+};
+/**
+ This type of request typically results in the creation of a #Spanner#
+*/
+
+
+///Start / stop a beam at this note.
+struct Beam_req : Span_req {
+    int nplet;
+};
+/** Staff will have to combine this with the stem_request, since the
+    number of flags that a stem wants to carry will determine the
+    number of beams.  if #nplet# is set, the staff will try to put an
+    appropriate number over the beam
+
+    [what to do  if the nplet fields of start and stop conflict?]
+    */
+
+///Start / stop a slur or a bracket.
+struct Bracket_req : Span_req {
+    int nplet;
+};
+/**
+Start/stop a bracket at this note. if #nplet# is set, the staff will
+try to put an appropriate number over the bracket
+*/
+
+/// a slur
+struct Slur_req : Span_req {
+    
+};
+
+/// helper in the hierarchy
+struct Dynamic {
+    Mtime subtime;
+};
+/** Each dynamic is bound to one note ( a crescendo spanning multiple
+    notes is thought to be made of two "dynamics": a start and a stop).
+    Dynamic changes can occur in a smaller time than the length of its
+    note, therefore fore each Dynamic request carries a time, measured
+    from the start of its note.
+
+    This subfield would come in handy, if mpp96 was adapted for midi
+    support.
+    
+    Dynamic should have been derived from request, but I don't want to
+    fuss with virtual baseclasses.  */
+
+/// do a crescendo
+struct Cresc_req : Span_req, Dynamic {
+    
+};
+
+/// do a decrescendo
+struct Decresc_req : Span_req, Dynamic {
+    
+};
+
+/// do a dynamic like "fff" or "mp"
+struct Absdynamic_req : Request, Dynamic {
+        Loudness loudness;
+};
+
+#endif
diff --git a/rhythmstaf.cc b/rhythmstaf.cc
new file mode 100644 (file)
index 0000000..61eca84
--- /dev/null
@@ -0,0 +1,150 @@
+#include "request.hh"
+#include "debug.hh"
+#include "linestaff.hh"
+#include "staff.hh"
+#include "pstaff.hh"
+#include "pscore.hh"
+#include "command.hh"
+#include "molecule.hh"
+#include "rhythmstaf.hh"
+
+
+Rhythmic_column::Rhythmic_column(Score_column*s, Rhythmic_staff *rs)
+    : Staff_column(s)
+{
+    the_note = 0;
+    staff_ = rs;
+}
+
+
+void
+Rhythmic_staff::set_output(PScore* ps )
+{
+    theline = new Linestaff(1);
+    pscore_ = ps;
+    pscore_->add(theline);
+}
+
+// should integrate handling of BREAK commands into Staff_column
+void
+Rhythmic_column::process_commands( )
+{
+    int breakstat = BREAK_END;
+    for (int i = 0 ; i < s_commands.sz(); i++) {
+       Command *com = s_commands[i];
+       switch (com->code){
+       case INTERPRET:
+           break;
+       case BREAK_PRE:
+       case BREAK_MIDDLE:
+       case BREAK_POST:
+       case BREAK_END:
+           score_column->set_breakable();
+           breakstat = com->code;
+           break;
+           
+       case TYPESET:
+           typeset_command ( com , breakstat);
+           break;
+       default :
+           break;
+       }
+       
+    }
+}
+/**
+ accept:
+
+    BREAK: all
+    TYPESET: bar, meter
+
+    */
+
+
+
+void
+Rhythmic_column::process_requests()
+{
+    for (int i = 0 ; i < v_elts.sz(); i ++)
+       for (PCursor<Request *> rqc(v_elts[i]->reqs); rqc.ok(); rqc++) {
+           Request *rq= rqc;
+           switch(rq->tag){
+           case Request::NOTE:
+           case Request::REST:
+               if (the_note){
+                   WARN << "too many notes.\n";
+                   return;
+               }
+               the_note = rq;
+               break;
+               
+           default:
+               return;
+           }
+       }
+    
+}
+
+
+void
+Rhythmic_column::typeset_command(Command *com, int breakst)
+{
+    Item *i = new Item;
+    const Symbol*s=0;
+
+    if (com -> args[0] ==  "|" ) {
+       s = Symbol::find_bar("|");      
+    } else
+       assert(false);
+    
+    i->output=new Molecule(Atom(s));
+    staff_->pscore_->typeset_item(i, score_column->pcol,
+                                 staff_->theline,breakst);
+}
+
+void
+Rhythmic_column::typeset_req(Request *rq)
+{
+    Item *i = new Item;
+    const Symbol*s=0;
+
+    switch(rq->tag){
+    case Request::NOTE:
+       s = Symbol::find_ball(rq->note()->balltype);
+       break;
+    case Request::REST:
+       s = Symbol::find_rest(rq->rest()->balltype);
+       break;
+    default:
+       assert(false);
+       break;
+    }  
+    i->output = new Molecule(Atom(s));
+
+    staff_->pscore_->typeset_item(i, score_column->pcol, staff_->theline,0 );  
+}
+
+void
+Rhythmic_staff::grant_requests()
+{
+    for  (PCursor<Staff_column*> cc(cols); cc.ok(); cc++) {
+       Rhythmic_column *rp = (Rhythmic_column*)*cc;
+       if (rp->the_note)
+           rp->typeset_req( rp->the_note);
+    }
+}
+
+Staff_column*
+Rhythmic_staff::create_col(Score_column*s)
+{
+    Rhythmic_column *rc = new Rhythmic_column(s,this);
+
+    return rc;
+}
+
+Staff *
+get_new_rhythmstaff()
+{
+    return new Rhythmic_staff;
+}
diff --git a/rhythmstaf.hh b/rhythmstaf.hh
new file mode 100644 (file)
index 0000000..1e56355
--- /dev/null
@@ -0,0 +1,31 @@
+struct Rhythmic_staff;
+
+/// column of Rhythmic_staff
+struct Rhythmic_column : Staff_column {
+    // mega-stupido. only do notes, one at a time
+    Request *the_note;
+    Rhythmic_staff* staff_;
+
+    /****************/
+    
+    void typeset_req(Request *rq);
+    void take_request(Request *rq);
+    void typeset_command(Command *, int brs);
+    void process_commands( );
+    void process_requests();
+
+    Rhythmic_column(Score_column*s,Rhythmic_staff*rs);
+};
+
+
+/// simple percussion staff
+struct Rhythmic_staff : Staff {
+    /// indirection to the PStaff.
+    PStaff *theline;
+    void set_output(PScore *);
+    void process_commands( PCursor<Command*> &where);
+
+    void grant_requests();
+    Staff_column * create_col(Score_column*);
+};
+
diff --git a/score.cc b/score.cc
new file mode 100644 (file)
index 0000000..543aca0
--- /dev/null
+++ b/score.cc
@@ -0,0 +1,258 @@
+#include <time.h>
+#include "tstream.hh"
+#include "score.hh"
+#include "pscore.hh"
+#include "staff.hh"
+#include "misc.hh"
+#include "debug.hh"
+
+void
+Score::add(Command *c)
+{
+    commands_.bottom().add(new Command(*c));
+}
+
+void
+Score::add(Staff*s)
+{
+    s->score_ = this;
+    staffs_.bottom().add(s);    
+}
+
+
+void
+Score::do_pcols()
+{
+    PCursor<Score_column*> sc(cols_);
+    for (;sc.ok(); sc++) {
+       pscore_->add(sc->pcol);
+    }
+}
+/*
+    this sux. Really makeshift.
+    */
+void
+Score::do_miscs()
+{
+    Command c;
+
+    c.when = 0.0;
+    
+    c.code = BREAK_END;
+    commands_.top().insert(new Command(c));    
+    c.code = BREAK_POST;
+    commands_.top().insert(new Command(c));
+    c.code = BREAK_MIDDLE;
+    commands_.top().insert(new Command(c));
+    c.code = BREAK_PRE;
+    commands_.top().insert(new Command(c));
+
+    PCursor<Command*> bot(commands_.bottom());
+    c.when = last();    
+    while (bot.ok() && bot->when > c.when) {
+//       mtor <<"removing "<< bot->code <<" at " << bot->when<<'\n';
+       bot.remove();
+       bot = commands_.bottom();
+    }
+   
+    c.code = BREAK_PRE;
+    bot.add(new Command(c));
+    bot++;
+    c.code = BREAK_MIDDLE;
+    bot.add(new Command(c));
+   bot++;
+    c.code = BREAK_POST;
+    bot.add(new Command(c));
+   bot++;
+   c.code = BREAK_END;
+    bot.add(new Command(c));
+    
+   commands_.OK();
+}
+
+Mtime
+Score::last() const
+{    
+    Mtime l = 0;
+    for (PCursor<Staff*> stc(staffs_); stc.ok(); stc++) {
+       l = MAX(l, stc->last());
+    }
+    return l;
+}
+void
+Score::clean_commands() 
+{
+    Mtime l= last();
+    for (PCursor<Command*> cc(commands_); cc.ok(); cc++) {
+       if (cc->when > l){
+          mtor << "remming \n";
+           cc.remove();
+       }
+    }
+}
+void
+Score::process()
+{
+     do_miscs();
+    
+    /// distribute commands to disciples
+    distribute_commands();
+    
+    pscore_ = new PScore;
+    for (PCursor<Staff*> sc(staffs_); sc.ok(); sc++) {
+       sc->set_output(pscore_);
+       sc->process();
+    }
+    do_pcols();
+    calc_idealspacing();
+    clean_cols();
+    OK();
+    //    print();
+    pscore_->calc_breaking();
+}
+
+// remove empty cols with no spacing attached.
+/* should rethink ownership of cols
+    */
+void
+Score::clean_cols()
+{
+    for (PCursor<Staff * > sc(staffs_); sc.ok(); sc++)
+       sc->clean_cols();
+    for (PCursor<Score_column*> c(cols_); c.ok(); c++) {
+       if (!c->pcol->used) {
+//         mtor << "removing : "; c->print();
+           c.remove();
+       }
+    }
+    
+    pscore_->clean_cols();
+}
+/* this sux.  We should have Score_column create the appropriate PCol.
+    Unfortunately, PCols don't know about their position.    
+    */
+// todo
+PCursor<Score_column*>
+Score::create_cols(Mtime w)
+{
+    Score_column* c1 = new Score_column(w);
+    Score_column* c2 = new Score_column(w);
+    
+    c1->musical = false;
+    c2->musical = true;
+    
+    PCursor<Score_column*> scc(cols_);
+
+    for (; scc.ok(); scc++) {
+       assert(scc->when != w);
+       if (scc->when > w)
+           break;
+    }
+
+    if (!scc.ok()) {
+       cols_.bottom().add(c1);
+       cols_.bottom().add(c2);
+       scc = cols_.bottom();
+       scc --;
+    } else {
+       scc.insert(c1);
+       scc.insert(c2);
+       scc -= 2;
+    }
+    return scc;
+}
+
+Score_column*
+Score::find_col(Mtime w,bool mus)
+{
+    PCursor<Score_column*> scc(cols_);
+    for (; scc.ok(); scc++) {
+       if (scc->when == w && scc->musical == mus)
+           return scc;
+       if (scc->when > w)
+           break;
+    }
+    scc = create_cols(w);
+    if (mus)
+       scc++;
+    return scc;
+}
+
+void
+Score::distribute_commands(void)
+{
+    for (PCursor<Staff*> sc(staffs_); sc.ok(); sc++) {
+       sc->add_commands(commands_);
+    }
+}
+
+
+void
+Score::output(String s)
+{
+    OK();
+    mtor << "output to " << s << "...\n";
+
+    Tex_stream the_output(s);
+    the_output << "% Automatically generated by LilyPond 0.0 at";
+    time_t t(time(0));
+    the_output << ctime(&t)<<"\n";
+    the_output << "% from input file ..\n";
+    pscore_->output(the_output);
+}
+
+void
+Score::OK() const
+{
+    for (PCursor<Staff*> sc(staffs_); sc.ok(); sc++) {
+       sc->OK();
+       assert(sc->score_ == this);
+    }
+    staffs_.OK();
+    cols_.OK();
+    for (PCursor<Score_column*> cc(cols_); cc.ok() && (cc+1).ok(); cc++) {
+       assert(cc->when <= (cc+1)->when);
+    }
+    for (PCursor<Command*> cc(commands_); cc.ok() && (cc+1).ok(); cc++) {
+       assert(cc->when <= (cc+1)->when);
+    }
+    
+}
+
+void
+Score::print() const
+{
+    mtor << "score {\n"; 
+    for (PCursor<Staff*> sc(staffs_); sc.ok(); sc++) {
+       sc->print();
+    }
+    for (PCursor<Score_column*> sc(cols_); sc.ok(); sc++) {
+       sc->print();
+    }
+    mtor << "}\n";
+}
+
+/****************************************************************/
+
+Score_column::Score_column(Mtime w)
+{
+    when = w;
+    pcol = new PCol(0);
+    musical = false;
+}
+
+bool
+Score_column::used() {
+    return pcol->used;
+}
+
+void
+Score_column::print() const
+{
+    mtor << "Score_column { mus "<< musical <<" at " <<  when<<'\n';
+    mtor << " # symbols: " << pcol->its.size() << "\n";
+    mtor << "durations: [" ;
+    for (int i=0; i < durations.sz(); i++)
+       mtor << durations[i] << " ";
+    mtor << "]\n}\n";
+}
diff --git a/score.hh b/score.hh
new file mode 100644 (file)
index 0000000..3e65d50
--- /dev/null
+++ b/score.hh
@@ -0,0 +1,83 @@
+#ifndef SCORE_HH
+#define SCORE_HH
+
+#include "vray.hh"
+#include "cols.hh"
+#include "mtime.hh"
+#include "command.hh"
+
+struct Score_column {
+    PCol * pcol;
+    svec<Mtime> durations;
+    Mtime when;
+
+    /// 
+    bool musical;
+    
+
+    Score_column(Mtime when);
+
+    static int compare(Score_column & c1, Score_column &c2) {
+       return sgn(c1.when - c2.when);
+    }
+    void set_breakable() {
+        pcol->set_breakable();
+    }
+    bool used();
+    void print() const;
+};
+/**
+
+    When typesetting hasn't started on PScore yet, the columns which
+    contain data have a rhythmical position. Score_column is the type
+    with a rhythmical time attached to it. The calculation of
+    idealspacing is done with data in these columns. (notably: the
+    #durations# field)
+
+    */
+
+instantiate_compare(Score_column&, Score_column::compare);
+
+
+/// the total music def of one movement
+struct Score {
+    /// staffs_ and commands_ form the problem definition.
+    PointerList<Staff *> staffs_;
+    PointerList<Command*> commands_;
+    
+    /// "runtime" fields for setting up spacing    
+    PointerList<Score_column*> cols_;
+    PScore *pscore_;
+
+    /****************************************************************/
+    
+    /// add #Idealspacings# to #pscore_#
+    void calc_idealspacing();
+    void process();
+
+    /// construction
+    void add_staff(Staff *st);
+
+    void distribute_commands();
+    /** add the score wide commands (bars, breaks) to each staff so
+    they can process (typeset) them if needed */
+    void OK() const;
+    Score_column *find_col(Mtime,bool);
+    void do_pcols();
+    void add(Command *);
+    void add(Staff*);
+    void output(String fn);
+    PCursor<Score_column*> create_cols(Mtime);
+    void print() const;
+    void do_miscs() ;
+    Mtime last() const;
+    void clean_cols();
+    void clean_commands();
+
+    void do_connect(PCol *c1, PCol *c2, Real d);
+    void connect_nonmus(PCol* c1, PCol *c2, Real d);
+};
+/**
+        
+    */
+#endif
diff --git a/smat.cc b/smat.cc
new file mode 100644 (file)
index 0000000..3830fd6
--- /dev/null
+++ b/smat.cc
@@ -0,0 +1,187 @@
+#include "smat.hh"
+
+void
+Full_storage::operator=(Full_storage const &fs)
+{
+    resize(fs.h, fs.w);
+    OK();
+    fs.OK();
+    for (int i=0; i<h; i++)
+       for (int j=0; j<w; j++)
+           els[i][j]= fs.els[i][j];
+}
+
+void
+Full_storage::OK() const
+{
+    //    static Real dummy;           
+    assert(maxh >= h && maxw >= w);
+    assert(h >= 0 && w >= 0);
+    assert(els||!maxh);
+    if (maxh>0) {              // access outer elts.
+       Real *r = els[maxh -1];
+       if (maxw>0) {
+           assert(r);
+           Real s = r[maxw -1];
+           s = sin(s);
+       }
+    }
+}
+void
+Full_storage::resize_cols(int newh)
+{
+    if (newh <= maxh) {
+       h=newh;
+       return;
+    }
+   
+    Real ** newa=new Real*[newh];
+    int j=0;
+    for (; j < h; j++)
+       newa[j] = els[j];
+    for (; j < newh; j++)
+       newa[j] = new Real[maxw];
+    delete[] els;
+    els=newa;
+
+    h = maxh = newh;
+}
+
+void
+Full_storage::resize_rows(int neww)
+{
+    if (neww <= maxw) {
+       w=neww;
+       return;
+    }
+    for (int i=0; i < maxh ; i++) {
+       Real* newa=new Real[neww];
+       for (int k=0; k < w; k++)
+           newa[k] = els[i][k];
+
+       delete[] els[i];
+       els[i] = newa;
+    }
+    w = maxw = neww;   
+}
+
+Full_storage::~Full_storage() {
+    for (int i=0; i < maxh; i++)
+       delete [] els[i];
+    delete[] els;
+}
+
+void
+Full_storage::resize(int rows, int cols)
+{
+    OK();
+    resize_cols(rows);
+    resize_rows(cols);
+
+}
+
+
+bool
+Full_storage::mult_ok(int i, int j) const
+{
+    return valid(i,j);
+}
+
+bool
+Full_storage::trans_ok(int i, int j) const
+{
+       return valid(i,j);
+} 
+
+
+void
+Full_storage::trans_next(int &i, int &j) const
+{
+    assert(trans_ok(i,j));
+    i++;
+    if (i >= h) {
+       i=0;
+       j ++;
+    }
+}
+
+void
+Full_storage::mult_next(int &i, int &j) const
+{
+    assert(mult_ok(i,j));
+    j++;
+    if (j >= w) {
+       j=0;
+       i++;
+    }
+}
+
+void
+Full_storage::delete_column(int k)
+{
+    assert(0 <= k &&k<w);    
+    for (int i=0; i< h ; i++)
+       for (int j=k+1; j <w; j++)
+           els[i][j-1]=els[i][j];
+    w--;
+}
+void
+Full_storage::delete_row(int k)
+{
+    assert(0 <= k &&k<h);
+    for (int i=k+1; i < h ; i++)
+       for (int j=0; j < w; j++)
+           els[i-1][j]=els[i][j];
+    h--;
+}
+
+
+void
+Full_storage::insert_row(int k)
+{
+    assert(0 <= k&& k <=h);
+    resize_cols(h+1);
+    for (int i=h-1; i > k ; i--)
+       for (int j=0; j <w; j++)
+           els[i][j]=els[i-1][j];
+
+}
+
+
+svec<Real>
+Full_storage::row(int n) const
+{
+    svec<Real> r;
+    for (int j = 0; j < w; j++)
+       r.add(els[n][j]);
+    return r;
+}
+
+svec<Real>
+Full_storage::column(int n) const
+{
+    
+    svec<Real> r;
+    for (int i = 0; i<h; i++)
+       r.add(els[i][n]);
+    return r;
+}
+
+
+Full_storage::Full_storage(Full_storage&s)
+{
+    init();
+    (*this) = s;
+}
+virtual_smat*
+Full_storage::clone()
+{
+    return new Full_storage(*this);
+}
+/****************************************************************/
+
+virtual_smat *
+virtual_smat::get_full(int n, int m)
+{
+    return new Full_storage(n,m);
+}
diff --git a/smat.hh b/smat.hh
new file mode 100644 (file)
index 0000000..c05d032
--- /dev/null
+++ b/smat.hh
@@ -0,0 +1,93 @@
+#ifndef SMAT_HH
+#define SMAT_HH
+#include "vray.hh"
+#include "vsmat.hh"
+#include "real.hh"
+/// simplest matrix storage. refer to its baseclass for the doco.
+class Full_storage : public virtual_smat
+{
+    /// height, width
+    int h,w;
+    /// maxima.
+    int maxh, maxw;
+    
+    /// the storage
+    Real** els;
+    void
+    init() {
+       els=0;
+       h=w=maxh=maxw=0;
+
+    }
+    
+    bool valid(int i, int j) const {
+       return (i>=0 && i < h)
+           && (j < w && j >=0);
+    }
+    
+
+    void resize_rows(int);
+    void resize_cols(int);
+
+public:
+    virtual int rows() const {
+       return h;
+    }
+    virtual int cols() const {
+       return w;
+    }
+    
+    
+    virtual void set_size(int i, int j)
+    {
+       resize(i,j); //this could be more efficient.
+    }
+    
+    virtual void set_size(int i) {
+       set_size(i,i);
+    }
+    virtual void resize(int i, int j);
+    virtual void resize(int i) {
+       resize(i,i);
+    }
+    
+    virtual Real& elem(int i,int j) {
+       assert(valid(i,j));
+       return els[i][j];
+    }
+    virtual const Real& elem(int i, int j) const {
+       assert(valid(i,j));
+       return els[i][j];
+    }
+    virtual svec<Real> row(int i) const;
+    virtual svec<Real> column(int j) const;
+
+    Full_storage() {
+       init();
+    }
+    Full_storage(int i, int j) {
+       init();
+       set_size(i,j);
+    }
+    Full_storage(Full_storage&);
+    Full_storage(int i) {
+       init();
+       set_size(i);
+    }
+    void OK() const;
+    void operator=(Full_storage const &);
+    
+    virtual void insert_row(int k);
+    virtual void delete_row(int k);
+    virtual void delete_column(int k);
+
+    
+    ~Full_storage();
+    virtual bool mult_ok(int i, int j)const;
+    virtual void mult_next(int &i, int &j) const ;
+    virtual bool trans_ok(int i, int j) const;
+    virtual void trans_next(int &i, int &j) const;
+    virtual virtual_smat * clone();
+};
+
+#endif
diff --git a/staff.cc b/staff.cc
new file mode 100644 (file)
index 0000000..61699dc
--- /dev/null
+++ b/staff.cc
@@ -0,0 +1,179 @@
+#include "staff.hh"
+#include "debug.hh"
+#include "pscore.hh"
+
+void
+Staff::clean_cols()
+{
+    PCursor<Staff_column *> stc(cols);
+    for(; stc.ok(); stc++){
+       if (!stc->score_column->used())
+           stc.remove();
+    }
+}
+
+/*
+    maak een staff column, met specs in args.
+
+    (sorry wat is het vroeg vandaag..)
+    */
+Staff_column *
+Staff::get_col(Mtime w, bool mus)
+{
+    Score_column* sc = score_->find_col(w,mus);
+    assert(sc->when == w);
+    PCursor<Staff_column *> stc(cols);
+    for (; stc.ok(); stc++) {
+       if (*sc  < *stc->score_column)
+           break;
+       if (sc == stc->score_column)
+           return stc;
+    }
+    Staff_column* newst = create_col(sc);
+
+    if (!stc.ok()) {
+       cols.bottom().add(newst);
+       return cols.bottom();
+    }
+    
+    if (mus) {
+       stc.insert(newst);
+       return newst;
+    }
+
+    if ((stc-1)->when() == newst->when()) {
+       stc--;
+    }
+
+    stc.insert(newst);
+    
+    return newst;
+}
+
+
+void
+Staff::add_voice(Voice *v)
+{
+    voices.bottom().add(v);
+}
+
+/*
+    put all stuff grouped vertically in the Staff_cols
+    */
+void
+Staff::setup_staffcols()
+{
+    
+    for (PCursor<Voice*> vc(voices); vc.ok(); vc++) {
+
+       Mtime now = vc->start;
+       for (PCursor<Voice_element *> ve(vc->elts); ve.ok(); ve++) {
+
+           Staff_column *sc=get_col(now,true);
+           sc->add(ve);
+           now += ve->duration;            
+       }       
+    }
+
+    for (PCursor<Command*> cc(commands); cc.ok(); cc++) {
+       Staff_column *sc=get_col(cc->when,false);
+       sc->s_commands.add(cc);
+    }
+}
+
+/// merge commands from score
+void
+Staff::add_commands(PointerList<Command*> const &cl)
+{
+    PCursor<Command*> score_c(cl);
+    PCursor<Command*> cc(commands);
+    
+    while (score_c.ok()) {
+       while (cc.ok() && cc->when <= score_c->when)
+           cc++;
+       
+       Command*nc = new Command (*(* score_c));
+       if (cc.ok()) {
+           // cc->when > score_c->when
+           cc.insert( nc );
+       } else {
+           commands.bottom().add( nc);
+           cc = commands.bottom();
+       }
+       score_c++;
+    }
+
+    // now integrate break commands with other commands.
+    // may be do this in derived functions.
+}
+
+void
+Staff::process()
+{
+    setup_staffcols();
+    OK();
+    for (PCursor<Staff_column*> sc(cols); sc.ok(); sc++) {
+       sc->process_commands();
+       sc->process_requests();
+    }
+    grant_requests();
+}
+
+void
+Staff::OK() const
+{
+    cols.OK();
+    commands.OK();
+    voices.OK();
+    assert(score_);
+    
+}
+
+
+Mtime
+Staff::last() const {
+    Mtime l = 0.0;
+    for (PCursor<Voice*> vc(voices); vc.ok(); vc++) {
+       l = MAX(l, vc->last());
+    }
+    return l;
+}
+
+
+void
+Staff::print() const
+{
+    mtor << "Staff {\n";
+    for (PCursor<Voice*> vc(voices); vc.ok(); vc++) {
+       vc->print();
+       
+    }
+    mtor <<"}\n";
+}
+
+/****************************************************************/
+
+bool
+Staff_column::mus() const
+{
+    return score_column->musical;
+}
+
+Mtime
+Staff_column::when() const
+{
+    return score_column->when;
+}
+void
+Staff_column::add(Voice_element*ve)
+{
+    Mtime d= ve->duration;
+    if (d){
+       score_column->durations.add(d);
+    }
+       
+    v_elts.add(ve);
+}
+Staff_column::Staff_column(Score_column*s) {
+    score_column = s;
+}
diff --git a/staff.hh b/staff.hh
new file mode 100644 (file)
index 0000000..49439f3
--- /dev/null
+++ b/staff.hh
@@ -0,0 +1,78 @@
+#ifndef STAFF_HH
+#define STAFF_HH
+
+#include "score.hh"
+#include "voice.hh"
+#include "command.hh"
+
+struct Staff_column {
+    Score_column *score_column;
+
+    /// fields to collect data vertically.
+    svec<Voice_element *> v_elts;
+    svec<Command *> s_commands;
+    
+    Staff_column(Score_column*s); 
+    bool mus() const ;
+    Mtime when() const;
+    void add(Voice_element*ve);
+    /****************************************************************
+      VIRTUAL
+    ****************************************************************/
+    virtual void process_requests()=0;
+    virtual void process_commands()=0;
+    virtual ~Staff_column() { }
+};
+
+
+/// base class for a collection of voices.
+struct Staff {
+    /// synchronous horizontal stuff
+    PointerList<Voice*> voices;
+
+    /// commands in chronological order
+    PointerList<Command *> commands;
+    PointerList<Staff_column*> cols;
+
+    /// indirections to the Score and PScore
+    Score *score_;
+    PScore *pscore_;
+
+    void add_voice(Voice *v);
+    void add_staff_column(Staff_column *sp);
+
+        
+    /// interpret all requests and add items to #destination#.
+    void process();
+    /**
+    This routines calls virtual functions from Staff, to delegate the
+    interpretation of requests to a derived class of Staff */
+
+    
+    /****************************************************************
+      VIRTUALS
+    ****************************************************************/
+    
+    void setup_staffcols();
+
+    virtual void set_output(PScore * destination)=0;
+    virtual void grant_requests()=0;
+    
+    Staff_column * get_col(Mtime,bool);
+
+    void add_commands(PointerList<Command* >const & sv);
+    /**
+    add all commands from sv.
+
+    PRE
+    sv is time-ordered.
+    */
+    virtual Staff_column * create_col(Score_column * )=0;
+
+    void OK() const;
+    void print() const;
+    Mtime last() const;
+    void clean_cols() ;
+    virtual ~Staff() { } 
+};
+#endif
diff --git a/suzan.ly b/suzan.ly
new file mode 100644 (file)
index 0000000..5dc5ca3
--- /dev/null
+++ b/suzan.ly
@@ -0,0 +1,14 @@
+% testje
+
+score{
+       rhythmstaff {
+               voice { $ c4 c2 c4 $ }
+       }
+       rhythmstaff {
+               voice { $ c2  c2 $ }
+       }
+       rhythmstaff {
+               voice { $ c4  c4 c4 c4 $ }
+       }
+       bar 2
+}
diff --git a/symbol.cc b/symbol.cc
new file mode 100644 (file)
index 0000000..9a3e8cd
--- /dev/null
+++ b/symbol.cc
@@ -0,0 +1,7 @@
+#include "tex.hh"
+
+Symbol::Symbol(String s, Box b)
+    : tex(s), dim(b)
+{
+}
+
diff --git a/symbol.ini b/symbol.ini
new file mode 100644 (file)
index 0000000..b66dbe1
--- /dev/null
@@ -0,0 +1,20 @@
+# TeXstring,   xmin xmax ymin ymax
+
+table balls
+       1       \wholeball      -1      1       -1      1
+       2       \halfball       -1      1       -1      1
+       4       \quartball      -1      1       -1      1       
+end
+
+table bars
+       |       \maatstreep     0       1       0       10
+end
+
+table rests
+       1       \wholerest              -1      1       -1      1
+       2       \halfrest               -1      1       -1      1
+       4       \quartrest              -1      1       -1      1
+       8       \eighthrest             -1      1       -1      1
+       16      \sixteenthrest          -1      1       -1      1
+       32      \thirtysecondrest       -1      1       -1      1
+end
\ No newline at end of file
diff --git a/symtable.cc b/symtable.cc
new file mode 100644 (file)
index 0000000..a63bc19
--- /dev/null
@@ -0,0 +1,109 @@
+#include "misc.hh"
+#include "debug.hh"
+#include "real.hh"
+#include "tex.hh"
+#include "assoc.hh"
+#include "symtable.hh"
+#include "const.hh"
+
+Symtable* 
+Symtables::operator()(String s) 
+{
+    if (!done_reading){        // read on demand
+       *mlog << '(' << fname ;
+       read();
+       done_reading = true;
+       *mlog << ")\n";
+    }
+    return Assoc<String, Symtable*>::operator[](s);
+} 
+
+void
+Symtables::read()
+{
+     Text_db symini(fname);
+     while (1) {
+        if (symini.eof())
+            break;
+        Text_record  r(  symini++);
+        if (!r.sz())
+            continue;
+
+        assert (r[0] == "table");
+        
+        String tabnam = r[1];
+        Symtable * sp = new Symtable;
+        while (1) {
+            r = symini++;
+            if (!r.sz())
+                continue;
+            if (r[0] == "end")
+                break;
+            
+            assert(r.sz() == 6);
+            int i=0;
+            String id=r[i++];
+            String tex=r[i++];
+            svec<Real> dims;
+            for (int j=0; j < 4; j++)
+                dims.add( r[i++].fvalue() *1.0/CM_TO_PT);
+            
+            Symbol s(tex, Box(dims));
+            (*sp)[id] = s;
+        }
+        (*this)[tabnam] = sp;           
+     }
+}
+
+Symtables the_sym_tables("symbol.ini");
+
+
+const Symbol*
+Symbol::find_ball(int i)
+{
+    int j = intlog2(i);
+    if (j > 4) j = 4;
+    Symtable * st = the_sym_tables("balls");
+    return &(*st)[String(j)];
+
+}
+
+const Symbol*
+Symbol::find_rest(int i)
+{
+    int j = intlog2(i);
+    return &(*the_sym_tables("rests"))[String(j)];
+}
+const Symbol*
+Symbol::find_bar(String s)
+{
+    return &(*the_sym_tables("bars"))[s];  
+}
+/****************************************************************/
+// bare bones.
+
+struct Linestaf_symbol : Stretchable_symbol {
+    int lines;
+    String operator ()(Real w);
+    Linestaf_symbol(int n) { lines = n;}
+};
+// should be done in TeX
+String
+Linestaf_symbol::operator()(Real w)
+{
+    String s;
+    s += "\\hbox to 0pt{";
+    s+= "\\vbox to 0pt{";
+    for (int i=0; i<lines; i++) {
+       if (i) s+= "\\vskip1pt";
+       s+= "\\hrule width " + String(w* HOR_TO_PT) +"pt";
+    }
+    s+="\\vss}\\hss}";
+    return s;
+}
+
+const Stretchable_symbol *
+Stretchable_symbol::get_linestaff(int n)
+{
+    return new Linestaf_symbol(n);
+}
diff --git a/symtable.hh b/symtable.hh
new file mode 100644 (file)
index 0000000..20cd450
--- /dev/null
@@ -0,0 +1,16 @@
+struct  Symtable : public Assoc<String, Symbol> {
+    
+};
+
+
+struct Symtables : private Assoc<String, Symtable*> {
+    String fname;
+    bool done_reading;
+    Symtables(String s) : fname (s) {
+       done_reading = false;
+    }
+    void read() ;
+    Symtable* operator()(String s);
+
+};
+
diff --git a/table.cc b/table.cc
new file mode 100644 (file)
index 0000000..45e6f4a
--- /dev/null
+++ b/table.cc
@@ -0,0 +1,27 @@
+#include "glob.hh"
+#include "string.hh"
+#include "keyword.hh"
+#include "parser.hh"
+
+static Keyword_ent  the_key_tab[]={
+    "voice", VOICE,
+    "rhythmstaff", RHYTHMSTAFF,
+    "score", SCORE,
+    "bar", BAR,
+    0,0
+} ;
+
+
+int
+lookup_keyword(String s)
+{
+    static Keyword_table table(the_key_tab);
+    return table.lookup(s);
+}
+
+Identifier*
+lookup_identifier(String s)
+{
+    assert(false);
+    return 0;
+}
diff --git a/template.cc b/template.cc
new file mode 100644 (file)
index 0000000..6d45473
--- /dev/null
@@ -0,0 +1,26 @@
+#include "line.hh"
+
+#include "list.hh"
+#include "cols.hh"
+#include "item.hh"
+#include "request.hh"
+#include "score.hh"
+#include "command.hh"
+#include "staff.hh"
+
+#include "list.cc"
+#include "cursor.cc"
+
+
+PL_instantiate(Line_of_staff);
+PL_instantiate(Item);
+PL_instantiate(Line_of_score);
+PL_instantiate(Request);
+PL_instantiate(Spanner);
+PL_instantiate(PStaff);
+PL_instantiate(Idealspacing);
+PL_instantiate(PCol);
+PL_instantiate(Command);
+PL_instantiate(Score_column);
+
+
diff --git a/template2.cc b/template2.cc
new file mode 100644 (file)
index 0000000..21e24f0
--- /dev/null
@@ -0,0 +1,16 @@
+#include "line.hh"
+#include "voice.hh"
+#include "molecule.hh"
+#include "staff.hh"
+
+
+
+
+#include "list.cc"
+#include "cursor.cc"
+PL_instantiate(Staff_column);
+PL_instantiate(Staff);
+PL_instantiate(Voice_element);
+PL_instantiate(Voice);
+L_instantiate(Atom);
+
diff --git a/test.tex b/test.tex
new file mode 100644 (file)
index 0000000..b6bcb4f
--- /dev/null
+++ b/test.tex
@@ -0,0 +1,3 @@
+\input lilyponddefs
+\input lelie.uit
+\vfil\bye
\ No newline at end of file
diff --git a/tex.cc b/tex.cc
new file mode 100644 (file)
index 0000000..db789e4
--- /dev/null
+++ b/tex.cc
@@ -0,0 +1,26 @@
+#include "tex.hh"
+#include "const.hh"
+/*
+    #TeXstring# should generate a TeX string to typeset the object in
+  a hbox or vbox of exactly the objects' dimension.
+*/
+
+
+/// #h# is in points
+String
+vstrut(Real h)
+{
+    return String("\\vrule height ") + h + "pt depth 0pt width 0pt";
+}
+
+
+/// the staff with five lines.
+ struct  Fiveline_staff: Stretchable_symbol {
+     String operator()(Real width) {
+       String s("\\normalebalk{ ");
+       s+=width * HOR_TO_PT;
+       s+= "pt}";
+       return s;
+    }    
+};
+
diff --git a/tex.hh b/tex.hh
new file mode 100644 (file)
index 0000000..04090aa
--- /dev/null
+++ b/tex.hh
@@ -0,0 +1,54 @@
+#ifndef TEX_HH
+#define TEX_HH
+#include "string.hh"
+#include "boxes.hh"
+
+struct Symbol {
+    String tex;
+    Box dim;
+
+    Symbol (String, Box );
+    static const Symbol*find_ball(int);
+    static const Symbol*find_rest(int);
+    static const Symbol*find_bar(String);
+    Symbol() { }
+};
+
+/// a symbol with a variable width
+struct Stretchable_symbol {
+public:
+
+    /// return a string for a symbol in this width.
+    virtual String operator ()(Real width)=0;
+
+    static const Stretchable_symbol* get_linestaff(int n);
+};
+
+/// anything which can be output
+struct Output {
+    virtual String TeXstring() const=0;
+    /** generate a TeX string, which typesets the symbol. Vertical
+     base position is the "origin" of the staff
+    */
+    virtual Box extent() const=0;
+};
+/**
+  any output should (at least) be outputtable for TeX, and have a
+  dimension
+*/
+
+
+/// an idea
+struct Text_gob : Output {
+    String text;
+    // fonts, sizes, etc?
+    virtual String TeXstring() const;
+    virtual Box extent() const;
+};
+
+
+/// #h# is in points
+String vstrut(Real h);
+
+
+#endif
diff --git a/tstream.cc b/tstream.cc
new file mode 100644 (file)
index 0000000..78c9a72
--- /dev/null
@@ -0,0 +1,64 @@
+#include <fstream.h>
+#include "tex.hh"
+#include "tstream.hh"
+#include "debug.hh"
+
+Tex_stream::Tex_stream(String filename) 
+{
+    
+    os = new ofstream(filename);
+    if (!*os)
+       error("can't open " + filename);
+    nest_level = 0;
+    outputting_comment=false;
+}
+
+Tex_stream::~Tex_stream()
+{
+    assert(nest_level == 0);
+    delete os;
+}
+
+// print string. don't forget indent.
+Tex_stream &
+Tex_stream::operator<<(String s)
+{       
+    for (const char *cp = s; *cp; cp++) {
+       if (outputting_comment) {
+           *os << *cp;
+           if (*cp == '\n') {
+               outputting_comment=false;
+
+           }
+           continue;
+       }
+       switch(*cp) 
+           {
+           case '%':
+               outputting_comment = true;
+               *os << *cp;
+               break;
+           case '{':
+               nest_level++;
+               *os << *cp;             
+               break;
+           case '}':
+               nest_level--;           
+               *os << *cp;
+               assert (nest_level >= 0);
+               /* FALL THROUGH */
+               
+           case '\n':
+               *os << "%\n";
+               *os << String(' ', nest_level);
+               break;        
+           default:
+               *os << *cp;
+               break;
+           }
+    }
+    return *this;
+}
+
+
+/****************************************************************/
diff --git a/tstream.hh b/tstream.hh
new file mode 100644 (file)
index 0000000..07be0c1
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef TSTREAM__HH
+#define TSTREAM__HH
+
+#include <iostream.h>
+#include "string.hh"
+
+/// TeX output
+struct Tex_stream {
+    bool outputting_comment;
+    ostream *os;
+    int nest_level;
+    
+    /// open a file for writing
+    Tex_stream(String filename);
+    
+    /// delegate conversion to string class.
+    Tex_stream &operator<<(String);
+
+    /// close the file
+    ~Tex_stream();
+};
+/**
+  Use this class for writing to a TeX file.
+  It counts braces to prevent nesting errors, and
+  it will add a comment sign before each newline.
+  */
+#endif
diff --git a/vector.cc b/vector.cc
new file mode 100644 (file)
index 0000000..be24232
--- /dev/null
+++ b/vector.cc
@@ -0,0 +1,41 @@
+#include "debug.hh"
+#include "vector.hh"
+#include "string.hh"
+
+Vector::Vector(const Vector&n)
+          :dat(n.dat)
+     // this makes GCC 272 barf
+{
+    //dat = n.dat;
+}    
+
+Vector::operator String() const
+{
+    int i=0;
+    String s("vector [");
+    for (; i < dim(); i++) {
+       s += String(dat[i], "%6f") + ' ';
+    }
+    s+="]";
+    return s;
+}
+
+
+void
+Vector::print() const
+{
+    mtor << *this<<'\n';
+}
+
+Vector
+Vector::operator-() const
+{
+    Vector v(*this); v*=-1; return v;
+}
+
+void
+Vector::set_unit(int j)
+{
+    fill(0.0);
+    dat[j] = 1.0;
+}
diff --git a/vector.hh b/vector.hh
new file mode 100644 (file)
index 0000000..5be792c
--- /dev/null
+++ b/vector.hh
@@ -0,0 +1,106 @@
+#ifndef VECTOR_HH
+#define VECTOR_HH
+
+#include "glob.hh"
+#include "vray.hh"
+
+/// a row of numbers
+class Vector  {
+    svec<Real> dat;
+public:
+    void OK() const { dat.OK();}
+    int dim() const { return dat.sz(); }
+    Vector() { }
+    Vector(const Vector&n);
+    Vector(int n) {
+       dat.set_size(n);
+       fill(0);
+    }
+    void insert(Real v, int i) {
+       dat.insert(v,i);
+    }
+    void del(int i) { dat.del(i); }
+    operator String() const;
+    void fill(Real r) {
+       for (int i=0; i < dim(); i++)
+           dat[i] =r;
+    }
+
+    void operator +=(Vector v) {
+       assert(v.dim() == dim());
+       for (int i=0; i < dim(); i++)
+           dat[i] += v.dat[i];
+    }
+    
+    void operator /=(Real a) {
+       (*this) *= 1/a;
+    }
+
+    void operator *=(Real a) {
+       for (int i=0; i < dim(); i++)
+           dat[i] *= a;
+    }
+
+    void operator -=(Vector v) {
+       assert(v.dim() == dim());
+       for (int i=0; i < dim(); i++)
+           dat[i] -= v(i);     
+    }
+
+    Real &operator()(int i) { return dat[i]; }
+    Real operator()(int i) const { return dat[i]; }
+    Real elem(int i) { return dat[i]; }
+    Real operator *(Vector v) const {
+       Real ip=0;
+       assert(v.dim() == dim());
+       for (int i=0; i < dim(); i++)
+           ip += dat[i] *v(i);
+       return ip;
+    }
+    Vector operator-() const;
+    Real norm() {
+       return sqrt(norm_sq() );
+    }
+    Real norm_sq() {
+       return ((*this) * (*this));
+    }
+    operator svec<Real> () { return dat; }
+    void print() const;
+    /// set to j-th element of unit-base
+    void set_unit(int j) ;
+};
+/**
+    a vector. Storage is handled in svec, Vector only does the mathematics.
+ */
+
+inline Vector
+operator+(Vector a, Vector const &b) {
+    a += b;
+    return a;
+}
+
+inline Vector
+operator-(Vector a, Vector const &b) {
+    a -= b;
+    return a;
+}
+
+inline Vector
+operator*(Vector v, Real a) {
+    v *= a;
+    return v;
+}
+
+inline Vector
+operator*( Real a,Vector v) {
+    v *= a;
+    return v;
+}
+
+inline Vector
+operator/(Vector v,Real a) {
+    v *= 1/a;
+    return v;
+}
+
+#endif
diff --git a/version.cc b/version.cc
new file mode 100644 (file)
index 0000000..5a14bb4
--- /dev/null
@@ -0,0 +1,9 @@
+#include "version.hh"
+
+static char *s = "LilyPond version " VERSIONSTR " compiled on " __DATE__ " at " __DATE__ "\n";
+
+char *
+get_version()
+{
+   return s;
+}
diff --git a/voice.cc b/voice.cc
new file mode 100644 (file)
index 0000000..ac6d331
--- /dev/null
+++ b/voice.cc
@@ -0,0 +1,56 @@
+#include "debug.hh"
+#include "voice.hh"
+
+void
+Voice_element::add(Request*r)
+{
+    if (r->tag == Request::NOTE ||r->tag == Request::REST) {
+       assert (!duration);         
+       duration = r->duration();
+    }
+    reqs.bottom().add(r);
+}
+
+Voice::Voice()
+{
+    start = 0.0;
+}
+
+void
+Voice::add(Voice_element*v)
+{
+    elts.bottom().add(v);
+}
+
+Voice_element::Voice_element()
+{
+    voice = 0;
+    group = 0;
+    duration = 0.0;
+}
+
+void
+Voice::print() const
+{
+    mtor << "start: "<< start<<eol;
+    for (PCursor<Voice_element*> vec(elts); vec.ok(); vec++)
+       vec->print();
+}
+void
+Voice_element::print() const
+{
+    mtor << "voice_element { dur :"<< duration <<"\n";
+    for (PCursor<Request*> rc(reqs); rc.ok(); rc++) {
+       mtor << "reqtag: " << rc->tag<<eol;
+    }
+    mtor << "}\n";
+}
+
+Mtime
+Voice::last() const
+{
+    Mtime l =start;
+    for (PCursor<Voice_element*> vec(elts); vec.ok(); vec++)
+       l  += vec->duration;
+    return l;
+}
diff --git a/voice.hh b/voice.hh
new file mode 100644 (file)
index 0000000..3553752
--- /dev/null
+++ b/voice.hh
@@ -0,0 +1,49 @@
+#ifndef VOICE_HH
+#define VOICE_HH
+
+#include "mtime.hh"
+#include "list.hh"
+#include "request.hh"
+
+/// class for  horizontal stuff.
+struct Voice {
+    PointerList<Voice_element *> elts;
+    Mtime start;
+
+    /****************/
+    Mtime when(const Voice_element*)const;
+    Mtime last() const;
+    Voice();
+    void add(Voice_element*);
+    void print() const;
+};
+/**
+
+    Voice is a ordered row of Voice_elements. It is strictly horizontal:
+    you cannot have two rhythmic elements running parallel in a Voice
+
+    */
+
+struct Voicegroup {
+    /// don't know how to identify these.
+};
+
+/// 
+struct Voice_element {
+    Mtime duration;
+    const Voicegroup *group;
+    const Voice *voice;
+    PointerList<Request*> reqs;
+
+    List<const Item *> granted_items;
+    List<const Spanner *> granted_spanners;
+    void add(Request*);
+    Voice_element();
+
+    void print ()const;
+};
+/** Apart from being a container for the requests, Voice_element is
+    glue between related items and spanners, between requests and
+    (voice)groups
+    */
+#endif
diff --git a/vsmat.hh b/vsmat.hh
new file mode 100644 (file)
index 0000000..4e1ea79
--- /dev/null
+++ b/vsmat.hh
@@ -0,0 +1,141 @@
+#ifndef VSMAT_HH
+#define VSMAT_HH
+#include "vray.hh"
+#include "real.hh"
+/// a  matrix storage baseclass.
+class virtual_smat {
+    
+
+public:
+    /// check invariants
+    virtual void OK() const=0;
+    
+    /// height of matrix
+    virtual int rows() const = 0;
+
+    /// width of matrix
+    virtual int cols() const = 0;
+    
+    /// set the size. contents lost
+    virtual void set_size(int i, int j) = 0;
+    /**      
+      PRE
+      i >=0, j>=0
+    */
+    
+    /// set the size to square dimen. contents lost
+    virtual void set_size(int i) = 0;
+    /**
+      PRE
+      i>=0
+    */
+    /// set the size to i
+    virtual void resize(int i, int j) = 0;
+    /**
+
+      keep contents. If enlarged contents unspecified
+        
+      PRE
+      i>=0, j>=0
+    
+    */
+
+    /// set the size to square dimen. contents kept
+    virtual void resize(int i) = 0;
+    /**    
+    Keep contents. If enlarged contents are unspecified
+    
+    PRE
+    i>=0  
+    */
+    
+    /// access an element
+    virtual Real& elem(int i,int j) = 0;
+    /**
+    access an element.
+
+    Generate an errormessage, if this happens
+    in the 0-part of a sparse matrix.
+    */
+
+    /// access a element, no modify
+    virtual const Real& elem(int i, int j) const = 0;
+
+#if 1
+    virtual svec<Real> row(int i) const = 0;
+    virtual svec<Real> column(int j) const = 0;
+#endif
+
+    /// add a row
+    virtual void insert_row(int k)=0;
+    /**
+    add a row to the matrix before  row k. Contents
+    of added row are unspecified
+
+      0 <= k <= rows()
+    */
+
+    /// delete a row 
+    virtual void delete_row(int k)=0;
+      /**
+      delete a row from this matrix.
+
+      PRE
+      0 <= k < rows();
+    */
+        virtual void delete_column(int k)=0;
+    virtual ~virtual_smat() { }
+    virtual virtual_smat *clone()=0;
+
+
+    /// is there a next?
+    virtual bool mult_ok(int i, int j) const=0;
+    /**
+      at end of matrix? when doing loop
+
+      for(i=0; i<h; i++)
+        for(j=0; j<w; j++)
+          ...
+
+    */
+    /// iterate
+    virtual void mult_next(int &i, int &j) const  = 0;
+    /**
+      walk through matrix (regular multiply)
+      get next j for row i, or get next row i and reset j.
+      this will make sparse matrix implementation easy.
+    
+      PRE
+      mult_ok(i,j)
+     */
+    virtual bool trans_ok(int i, int j) const=0;
+    /**
+      valid matrix entry. return false if at end of row
+    */
+    virtual void trans_next(int &i, int &j) const  = 0;
+    /**
+      walk through matrix (transposed multiply).
+      Get next i (for column j)
+    
+      PRE
+      ver_ok(i,j)
+     */
+
+    /// generate a "Full_storage" matrix    
+    static virtual_smat *get_full(int n, int m);
+
+};
+    
+/** base class for interface with matrix storageclasses.  There are no
+    iterators for matrixclasses, since matrices are (like arrays)
+    explicitly int-indexed.
+
+    Iteration is provided by *_next, *_ok, which update and check both
+    index variables simultaneously.
+
+    TODO
+    determine type of product matrix.
+
+*/
+
+#endif
diff --git a/warn.cc b/warn.cc
new file mode 100644 (file)
index 0000000..426173e
--- /dev/null
+++ b/warn.cc
@@ -0,0 +1,18 @@
+#include "debug.hh"
+ ostream &warnout (cerr);
+ ostream *mlog(&cerr);
+
+
+
+void warning(String s)
+{
+    WARN << s;
+}
+
+
+void error(String s)
+{
+    cerr << "\n" << s << "\nexiting..\n";
+    exit(1);
+}
+