diff --git a/TODO b/TODO
index c182f37446056e3b2c68c566bfb72dec1515da64..d714d45cb420c84cd871d52ade65ad3144ebcd70 100644
--- a/TODO
+++ b/TODO
@@ -23,7 +23,6 @@ WISHLIST JWu
 - convolution with fits ? splines ?
 CHECK - gd: commandos -> gnuplot (für Fanni)
 - convolutand must not be defined over full energy range
-- private ini file to overwrite generic one
 - mfj remove redundant doc lines
 - dp output for #spec>1 is obfuscated
 
@@ -32,6 +31,9 @@ CHECK - gd: commandos -> gnuplot (für Fanni)
   - private ini file
   - additional settings: graph mode
 
+- distinguish opr-functions (for modifications, with error propagation) and
+  and fit functions (allowing for ad-hoc additions)
+
 SEBASTIAN
 
 = erledigt =
diff --git a/pub/src/edif.cpp b/pub/src/edif.cpp
index b92e385dd37079fc299d378c9d9e994c787c265b..3f4a2253f43a15b0c4d9791b46b7a7ddcbe2b513 100644
--- a/pub/src/edif.cpp
+++ b/pub/src/edif.cpp
@@ -368,8 +368,8 @@ void NEdif::EditCoord( string which )
     NOlm::SelAssert();
 
     NOlm::IterateO fiter;
-    CRef cref( which );
-    if ( !cref.defined() ) {
+    CVariable cvar( which );
+    if ( !cvar.defined() ) {
         printf( "! invalid coordinate %s\n", which.c_str() );
         return;
     }
@@ -380,20 +380,20 @@ void NEdif::EditCoord( string which )
     while( fin = fiter() ) {
         POlo fout = fin;
                               
-        if        ( cref.var==CRef::_X ) {
+        if        ( cvar.typ==CVariable::_X ) {
             old_co = fin->xco;
             fout->xco = new_co;
-        } else if ( cref.var==CRef::_Y ) {
+        } else if ( cvar.typ==CVariable::_Y ) {
             old_co = fin->yco;
             fout->yco = new_co;
-        } else if ( cref.var==CRef::_Z ) {
-            if( cref.num >= fin->nZ() ){
+        } else if ( cvar.typ==CVariable::_Z ) {
+            if( cvar.num >= fin->nZ() ){
                 printf( "! not all files in selection have %s, use oz+\n",
                         which.c_str() );
                 return;
             }
-            old_co = fin->ZCo[cref.num];
-            fout->ZCo[cref.num] = new_co;
+            old_co = fin->ZCo[cvar.num];
+            fout->ZCo[cvar.num] = new_co;
         }
         fout->lDoc.push_back( "ec"+string(which)+" "+new_co.str()+
                               " # old: " + old_co.str() );
diff --git a/pub/src/expr.cpp b/pub/src/expr.cpp
index 0de1884bb2d0b142e8af34a091483f6d99f4efaf..f0454ff7965e75c35b2a52a0e4d0ba8199daf17d 100644
--- a/pub/src/expr.cpp
+++ b/pub/src/expr.cpp
@@ -81,13 +81,14 @@ string CContext::info() const
     return ret;
 }
 
+
 //***************************************************************************//
-//* class CRef                                                              *//
-//* (references, typically used as endpoints of CTree's)                    *//
+//* class CVariable                                                         *//
 //***************************************************************************//
 
+//! Variables may be unnumbered (x,y,i,j,k,f,...) or numbered (z0,p0,...).
 
-CRef::CRef( string s, PTree _tk, PTree _tj, PTree _ti )
+CVariable::CVariable( string s )
     // NOTE: As long as this constructor is called by the parser and not
     // by the lexical analyzer, string s may contain more than just the
     // parameter name. Everything after the parameter name must be ignored.
@@ -95,55 +96,103 @@ CRef::CRef( string s, PTree _tk, PTree _tj, PTree _ti )
     num = 0;
     int isub;
     char c;
-    int nsub = sscanf(s.c_str(), "%c%d", &c, &isub);
-    if (s.substr(0,2)=="fm" && sscanf(s.substr(2).c_str(), "%d", &isub)==1 ) {
-        var = _FM; // fit metric
+    int nsub = sscanf( s.c_str(), "%c%d", &c, &isub );
+    if ( s.substr(0,2)=="fm" && sscanf(s.substr(2).c_str(), "%d", &isub)==1 ) {
+        typ = _FM; // fit metric
         num = isub;
-    } else if (nsub==2 && c=='p') {
-        var = _FP; // fit parameter
+    } else if ( nsub==2 && c=='p' ) {
+        typ = _FP; // fit parameter
         num = isub;
-    } else if (s.substr(0,2)=="z+") {
-        var = _Z; // new z value
+    } else if ( s.substr(0,2)=="z+" ) {
+        typ = _Z; // new z value
         num = -1;
-    } else if (nsub==2 && c=='z') {
-        var = _Z;  // z value
+    } else if ( nsub==2 && c=='z' ) {
+        typ = _Z;  // z value
         num = isub;
-    } else if (s.substr(0,2)=="nj") {
-        var = _NJ; // number of spectra in file
-    } else if (s.substr(0,2)=="ni") {
-        var = _NI; // number of points in spectrum
-    } else if (nsub==1 && c=='x') {
-        var = _X;  // x value
-    } else if (nsub==1 && c=='y') {
-        var = _Y;  // y value
-    } else if (nsub==1 && c=='f') {
-        var = _FC; // fit curve
-    } else if (nsub==1 && c=='k') {
-        var = _K;  // internal file index
-    } else if (nsub==1 && c=='j') {
-        var = _J;  // index of current spectrum
-    } else if (nsub==1 && c=='i') {
-        var = _I;  // index of current point
+    } else if ( s.substr(0,2)=="nj" ) {
+        typ = _NJ; // number of spectra in file
+    } else if ( s.substr(0,2)=="ni" ) {
+        typ = _NI; // number of points in spectrum
+    } else if ( nsub==1 && c=='x' ) {
+        typ = _X;  // x value
+    } else if ( nsub==1 && c=='y' ) {
+        typ = _Y;  // y value
+    } else if ( nsub==1 && c=='f' ) {
+        typ = _FC; // fit curve
+    } else if ( nsub==1 && c=='k' ) {
+        typ = _K;  // internal file index
+    } else if ( nsub==1 && c=='j' ) {
+        typ = _J;  // index of current spectrum
+    } else if ( nsub==1 && c=='i' ) {
+        typ = _I;  // index of current point
     } else {
-        var = _NOREF;
+        typ = _NOREF;
     }
-    // newly constructed CRef takes over responsability to destroy CTree's
-    tk = _tk;
-    tj = _tj;
-    ti = _ti;
-    if (isindex() && indexed())
-        throw string( "invalid cross reference: index cannot be indexed" );
+}
+
+
+//! Convert to text.
+
+string CVariable::var_info() const
+{
+    string ret;
+    switch (typ) {
+    case _X:
+        ret = "x";  break;
+    case _Y:
+        ret = "y";  break;
+    case _FC:
+        ret = "f";  break;
+    case _Z:
+        ret = "z";  break;
+    case _FP:
+        ret = "p";  break;
+    case _FM:
+        ret = "fm"; break;
+    case _K:
+        ret = "k";  break;
+    case _J:
+        ret = "j";  break;
+    case _I:
+        ret = "i";  break;
+    case _NJ:
+        ret = "nj"; break;
+    case _NI:
+        ret = "ni"; break;
+    default:
+        throw string( "BUG: no info available for unexpected variable typ" );
+    }
+    if ( numbered() )
+        ret += strg(num);
+    return ret;
+}
+
+
+//***************************************************************************//
+//* class CRef                                                              *//
+//* (references, typically used as endpoints of CTree's)                    *//
+//***************************************************************************//
+
+
+CRef::CRef( string s, PTree _tk, PTree _tj, PTree _ti )
+    // NOTE: As long as this constructor is called by the parser and not
+    // by the lexical analyzer, string s may contain more than just the
+    // parameter name. Everything after the parameter name must be ignored.
+    : CVariable( s ), tk( _tk ), tj ( _tj ), ti (_ti )
+{
+    if (isindex() && ( ti || tj || tk ) )
+        throw string( "BUG: invalid cross reference: index cannot be indexed" );
 }
 
 void CRef::ref_val( CTOut *ret, const CContext *ctx ) const
 {
    // Plain index reference ?
     if ( isindex() ) {
-        if     ( var == _K )
+        if     ( typ == _K )
             ret->set_u( ctx->k );
-        else if ( var == _J )
+        else if ( typ == _J )
             ret->set_u( ctx->j );
-        else if ( var == _I ) {
+        else if ( typ == _I ) {
             if        ( ctx->dim_1() ) {
                 if ( ctx->i==-1 )
                     throw string ( "index i not defined in present context" );
@@ -153,9 +202,9 @@ void CRef::ref_val( CTOut *ret, const CContext *ctx ) const
                 for ( uint i=0; i<ctx->nv; ++i )
                     ret->vd[i] = i;
             } else
-                throw string( "BUG ref_val(i) unforeseen reqDim" );
+                throw string( "BUG: ref_val(i) unforeseen reqDim" );
         } else
-            throw string( "BUG ref_val(index)" );
+            throw string( "BUG: ref_val(index)" );
         return;
     }
 
@@ -185,16 +234,16 @@ void CRef::ref_val( CTOut *ret, const CContext *ctx ) const
         if ( j>=f->nJ() )
             throw string( "ref_val: invalid spectrum index j=" + strg(j) );
     } else if ( tj )
-        throw string( "ref_val: j=" + ref_info() + 
+        throw string( "ref_val: j=" + var_info() + 
                       " provided though operarion is not specwise" );
 
     // check i:
     if ( !pointwise() && ti )
-        throw string( "ref_val: i=" + ref_info() + 
+        throw string( "ref_val: i=" + var_info() + 
                       " provided though operarion is not pointwise" );
 
     // Reference for any file type ?
-    if ( var==CRef::_NJ ) {
+    if ( typ==CRef::_NJ ) {
         ret->set_u( f->nJ() );
         return;
     }
@@ -203,7 +252,7 @@ void CRef::ref_val( CTOut *ret, const CContext *ctx ) const
     POld fd = P2D( f );
     POlc fc = P2C( f );
     if ( fd ) {
-        if        ( var == _X || var == _Y ) {
+        if        ( typ == _X || typ == _Y ) {
             // cout << "CTX " << ctx->info() << "\n";
             if        ( ctx->dim_1() ) {
                 // get point index i:
@@ -218,9 +267,9 @@ void CRef::ref_val( CTOut *ret, const CContext *ctx ) const
                 }
                 if( i>= fd->VS(j)->size() )
                     throw string( "i out of range" );
-                if       ( var == _X )
+                if       ( typ == _X )
                     ret->set_d( fd->VS(j)->x[i] );
-                else if ( var == _Y )
+                else if ( typ == _Y )
                     ret->set_d( fd->VS(j)->y[i] );
             } else if ( ctx->dim_vi() ) {
                 ret->preset_vd( ctx->nv );
@@ -233,62 +282,62 @@ void CRef::ref_val( CTOut *ret, const CContext *ctx ) const
                         ti->tree_uival( &i, &myctx );
                         if( i >= fd->VS(j)->size() )
                             throw string( "i out of range" );
-                        if      ( var == _X )
+                        if      ( typ == _X )
                             ret->vd[ii] = fd->VS(j)->x[i];
-                        else if ( var == _Y )
+                        else if ( typ == _Y )
                             ret->vd[ii] = fd->VS(j)->y[i];
                     }
                 } else {
                     if ( ctx->nv != fd->VS(j)->size() )
-                        throw "ref_val " + ref_info() + ": requested vec(" +
+                        throw "ref_val " + var_info() + ": requested vec(" +
                             strg(ctx->nv) + "), found vec(" +
                             strg( fd->VS(j)->size() );
-                    if      ( var == _X )
+                    if      ( typ == _X )
                         ret->vd = fd->VS(j)->x;
-                    else if ( var == _Y )
+                    else if ( typ == _Y )
                         ret->vd = fd->VS(j)->y;
                 }
             }
-        } else if ( var == _Z ) {
+        } else if ( typ == _Z ) {
             if ( num>= fd->nZ() )
-                throw( "invalid z ref(" + ref_info() + ") in data file" );
+                throw( "invalid z ref(" + var_info() + ") in data file" );
             ret->set_d( fd->VS(j)->z[num] );
-        } else if ( var == _NI ) {
+        } else if ( typ == _NI ) {
             ret->set_d( fd->VS(j)->size() );
         } else
-            throw( "invalid ref(" + ref_info() + ") in data file" );
+            throw( "invalid ref(" + var_info() + ") in data file" );
     } else if ( fc ) {
-        if       ( var == _FP ) {
+        if       ( typ == _FP ) {
             if ( num>= fc->nPar() )
-                throw( "invalid p ref(" + ref_info() + ") in curve file" );
+                throw( "invalid p ref(" + var_info() + ") in curve file" );
             ret->set_d( fc->VC(j)->P[num] );
-        } else if ( var == _FM ) {
+        } else if ( typ == _FM ) {
             if ( num>= CCurve::mQuality )
-                throw( "invalid fm ref(" + ref_info() + ") in curve file" );
+                throw( "invalid fm ref(" + var_info() + ") in curve file" );
             ret->set_d( fc->VC(j)->Quality[num] );
-        } else if ( var == _Z ) {
+        } else if ( typ == _Z ) {
             if ( num>= fc->nZ() )
-                throw( "invalid z ref(" + ref_info() + ") in curve file" );
+                throw( "invalid z ref(" + var_info() + ") in curve file" );
             ret->set_d( fc->VC(j)->z[num] );
-        } else if ( var == _FC ) {
+        } else if ( typ == _FC ) {
             ret->set_cr( fc, k, j );
         } else 
-            throw( "invalid ref(" + ref_info() + ") in curve file" );
+            throw( "invalid ref(" + var_info() + ") in curve file" );
     } else
-        throw string( "BUG ref->eval unexpected else" );
+        throw string( "BUG: ref->eval unexpected else" );
 }
 
 void CRef::coord( CCoord *ret, uint k_in ) const
 {
     if (isindex()) {
-        if     ( var == _K )
+        if     ( typ == _K )
             *ret = CCoord("k","");
-        else if ( var == _J )
+        else if ( typ == _J )
             *ret = CCoord("j","");
-        else if ( var == _I )
+        else if ( typ == _I )
             *ret = CCoord("i","");
         else
-            throw string( "BUG coord(index)" );
+            throw string( "BUG: coord(index)" );
         return;
     }
 
@@ -313,73 +362,40 @@ void CRef::coord( CCoord *ret, uint k_in ) const
     POlc fc = P2C( f );
     if         ( fd ) {
         if (!indatafile())
-            throw( "coord: ref " + ref_info() +
+            throw( "coord: ref " + var_info() +
                    " not allowed in data file " + strg(k) );
-        if       ( var == _X )
+        if       ( typ == _X )
             *ret = fd->xco;
-        else if  ( var == _Y )
+        else if  ( typ == _Y )
             *ret = fd->yco;
-        else if  ( var == _Z ) {
+        else if  ( typ == _Z ) {
             if (num>=fd->ZCo.size())
                 throw( "coord: " + strg(num) + " undefined" );
             *ret = fd->ZCo[num];
-        } else if ( var == _NJ )
+        } else if ( typ == _NJ )
             *ret = CCoord("#spectra", "");
-        else if  ( var == _NI )
+        else if  ( typ == _NI )
             *ret = CCoord("#points", "");
         else
-            throw( "coord: data:ref(" + ref_info() + ") nyi" );
+            throw( "coord: data:ref(" + var_info() + ") nyi" );
     } else if ( fc ) {
         if (!incurvefile())
-            throw( "coord: ref " + ref_info() +
+            throw( "coord: ref " + var_info() +
                    " not allowed in curve file " + strg(k) );
-        if     ( var == _FP )
+        if     ( typ == _FP )
             *ret = fc->PCo[num];
-        else if ( var == _FM )
+        else if ( typ == _FM )
             *ret = CCoord("fqi_"+strg(num), ""); // fit quality indicator
-        else if ( var == _Z )
+        else if ( typ == _Z )
             *ret = fc->ZCo[num];
-        else if ( var == _FC )
+        else if ( typ == _FC )
             *ret = CCoord(fc->expr,"");
-        else if ( var == _NJ )
+        else if ( typ == _NJ )
             *ret = CCoord("#spectra", "");
         else
-            throw( "coord: curv:ref " + ref_info() + " nyi" );
+            throw( "coord: curv:ref " + var_info() + " nyi" );
     } else
-        throw string( "BUG ref->coord unexpected else" );
-}
-
-string CRef::ref_info(void) const
-{
-    string s;
-    switch (var) {
-    case _X:
-        s = "x";  break;
-    case _Y:
-        s = "y";  break;
-    case _FC:
-        s = "f";  break;
-    case _Z:
-        s = "z";  break;
-    case _FP:
-        s = "p";  break;
-    case _FM:
-        s = "fm"; break;
-    case _K:
-        s = "k";  break;
-    case _J:
-        s = "j";  break;
-    case _I:
-        s = "i";  break;
-    case _NJ:
-        s = "nj"; break;
-    case _NI:
-        s = "ni"; break;
-    default:
-        s = "?";  break;
-    }
-    if (numbered()) s += strg(num);
-    return s;
+        throw string( "BUG: ref->coord unexpected else" );
 }
 
 
@@ -951,9 +967,9 @@ string CTree::tree_info() const
     else if ( typ == _VAL )
         return "val[" + strg(val) + "]";
     else if ( typ == _REF )
-        return "ref[" + ref->ref_info() + "]";
+        return "ref[" + ref->var_info() + "]";
     else if ( typ == _FRF )
-        return "frf[" + ref->ref_info() + "]";
+        return "frf[" + ref->var_info() + "]";
     else if ( typ == _FARG )
         return "farg";
     else
@@ -978,7 +994,7 @@ void CTree::npar_exec( uint *np ) const
     else if ( typ == _VAL || typ == _FARG || typ == _FRF )
         ; // do nothing ( leave preset value 0 ? )
     else if ( typ == _REF ) {
-        if ( ref->var==CRef::_FP ) {
+        if ( ref->typ==CRef::_FP ) {
             if (ref->numbered())
                 *np = max (*np, ref->num+1);
             else
diff --git a/pub/src/expr.h b/pub/src/expr.h
index 8cee07c1c8d240f69ba95dbbe499392c0c5eb7df..8ddd6688afc58716576c94732209d8f101115701 100644
--- a/pub/src/expr.h
+++ b/pub/src/expr.h
@@ -73,54 +73,60 @@ class CTOut {
 };
 
 
-//! References to data points, indices, ...; used as endpoints of CTree's.
+//! Type of reference.
 
-class CRef {
+class CVariable {
  public:
-    enum TVar { _NOREF=0,
+    enum TTyp { _NOREF=0,
                 _X, _Y, _Z,    // data
                 _FC, _FP, _FM, // "fit curve", function par's, fit metrics
                 _K, _J, _I,    // indices for file, spectrum, point   
                 _NJ, _NI       // number of spectra in file, points in spectrum
     };
-    TVar var;
+    TTyp typ;
     uint num;
-    PTree tk;
-    PTree tj;
-    PTree ti;
 
-    CRef( const string s="",
-          PTree _tk=PTree(), PTree _tj=PTree(), PTree _ti=PTree());
+    CVariable( const string s="" );
 
     bool defined() const {
-        return var!=_NOREF; };
+        return typ!=_NOREF; };
     bool isindex() const {
-        return var==_K || var==_J || var==_I; };
+        return typ==_K || typ==_J || typ==_I; };
     bool issize() const {
-        return var==_NJ || var==_NI; };
+        return typ==_NJ || typ==_NI; };
     bool pointwise() const { 
-        return var==_X || var==_Y || var==_I; };
+        return typ==_X || typ==_Y || typ==_I; };
     bool specwise() const {
-        return pointwise() || var==_Z || var==_FP || var==_FM || var==_J ||
-            var==_NI || var==_FC; };
+        return pointwise() || typ==_Z || typ==_FP || typ==_FM || typ==_J ||
+            typ==_NI || typ==_FC; };
     bool unspecific() const { 
         return isindex() || issize(); };
     bool indatafile() const {
-        return unspecific() || var==_X || var==_Y || var==_Z; };
+        return unspecific() || typ==_X || typ==_Y || typ==_Z; };
     bool incurvefile() const {
         return (unspecific() && !pointwise())
-            || var==_FC || var==_FP || var==_FM || var==_Z ; };
+            || typ==_FC || typ==_FP || typ==_FM || typ==_Z ; };
     bool numbered() const {
-        return var==_FP || var==_FM || var==_Z; };
+        return typ==_FP || typ==_FM || typ==_Z; };
     bool assignable() const {
         return defined() && !unspecific(); };
-    bool indexed() const {
-        return ti || tj || tk; };
+
+    string var_info() const;
+};
+
+//! References to data points, indices, ...; used as endpoints of CTree's.
+
+class CRef: public CVariable {
+ public:
+    PTree tk;
+    PTree tj;
+    PTree ti;
+
+    CRef( const string s="",
+          PTree _tk=PTree(), PTree _tj=PTree(), PTree _ti=PTree());
     
     void ref_val( CTOut* ret, const CContext *ctx ) const;
     void coord( CCoord *ret, uint k ) const;
-    string ref_info() const;
-    const char* ref_cstr() const { return ref_info().c_str(); };
 };
 
 
@@ -170,8 +176,6 @@ class CTree {
     void coord( CCoord *ret, uint k=(uint)-1 ) const;
     uint npar() const;
     string tree_info() const;
-    const char* tree_cstr() const {
-        return tree_info().c_str(); };
 
     void tree_val( CTOut *ret, const CContext *ctx ) const;
     static uint setConvK( uint k );
diff --git a/pub/src/opr.cpp b/pub/src/opr.cpp
index 1b34d939f19016f85ae9815920738835f79954a5..5e53b23e9eb7a5a1f8f09e1d9f75e5c85b2dbf63 100644
--- a/pub/src/opr.cpp
+++ b/pub/src/opr.cpp
@@ -151,7 +151,7 @@ void NOperate::Pointwise( string llabel )
 {
     NOlm::SelAssert();
 
-    CRef lref(llabel);
+    CVariable lref(llabel);
     if ( !lref.defined() )
         throw "invalid left-hand side " + llabel;
 
@@ -169,26 +169,26 @@ void NOperate::Pointwise( string llabel )
 
         POlo fout( fin->new_olo() );
 
-        if( lref.var!=CRef::_FP )
-            fout->lDoc.push_back( "o" + lref.ref_info() + " " + expr);
+        if( lref.typ!=CVariable::_FP )
+            fout->lDoc.push_back( "o" + lref.var_info() + " " + expr);
         
         if ( lref.pointwise() && !fd )
             throw string( "no pointwise operation on curve" );
 
         CCoord co;
         T->coord( &co, k );
-        if        ( lref.var==CRef::_X ) {
+        if        ( lref.typ==CVariable::_X ) {
             fout->xco = co;
-        } else if ( lref.var==CRef::_Y ) {
+        } else if ( lref.typ==CVariable::_Y ) {
             fout->yco = co;
-        } else if ( lref.var==CRef::_Z ) {
+        } else if ( lref.typ==CVariable::_Z ) {
             if( lref.num==-1 )
                 fout->ZCo.push_back( co );
             else if( lref.num>= fin->ZCo.size() )
                 throw string( "no such z coordinate to operate on" );
             else
                 fout->ZCo[lref.num] = co;
-        } else if ( lref.var==CRef::_FP ) {
+        } else if ( lref.typ==CVariable::_FP ) {
             if( !fc )
                 continue; // just ignore op operations on data files
             if( lref.num>=fc->nPar() )
@@ -205,18 +205,18 @@ void NOperate::Pointwise( string llabel )
                 PSpec eout( new CSpec( *(fd->VS(j)) ) );
                 vector<double> vout( fd->nPts(j) );
                 T->tree_vec_val( &vout, k, j );
-                if (lref.var==CRef::_X)
+                if (lref.typ==CVariable::_X)
                     (P2D(fout))->VS(j)->x = vout;
                 else
                     (P2D(fout))->VS(j)->y = vout;
-            } else if (lref.var==CRef::_Z) {
+            } else if (lref.typ==CVariable::_Z) {
                 double dout;
                 T->tree_point_val( &dout, k, j );
                 if ( lref.num==-1 )
                     fout->V[j]->z.push_back( dout );
                 else
                     fout->V[j]->z[lref.num] = dout;
-            } else if (lref.var==CRef::_FP) {
+            } else if (lref.typ==CVariable::_FP) {
                 double dout;
                 T->tree_point_val( &dout, k, j );
                 (P2C(fout))->VC(j)->P[lref.num] = dout;