// This may look like C code, but it is really -*- C++ -*-
// 
// <copyright> 
//  
//  Copyright (c) 1996
//  Institute for Information Processing and Computer Supported New Media (IICM), 
//  Graz University of Technology, Austria. 
//  
// </copyright> 
// 
// 
// <file> 
// 
// Name:        dbcontr.C
// 
// Purpose:     
// 
// Created:     7 Aug 1996   Joerg Faschingbauer
// 
// Modified:    
// 
// Description: 
// 
// $Id: dbcontr.C,v 1.7 1997/02/17 13:42:21 gmesaric Exp $
// 
// $Log: dbcontr.C,v $
// Revision 1.7  1997/02/17 13:42:21  gmesaric
// Outcommented line param.toUpper();
// Parameters have to be case sensitive (e.g. custom index fields)
//
// Revision 1.6  1997/01/23 11:20:50  jfasch
// toUpper() of scope, var, param (NOT value!!)
//
// Revision 1.5  1997/01/13 12:10:16  jfasch
// bug fixed in regexp
//
// Revision 1.4  1996/09/11 15:31:11  jfasch
// substitute $HOME in a value with the env. var.
//
// Revision 1.3  1996/08/08 15:41:24  jfasch
// bug fix (matching parameterized lines)
//
// Revision 1.2  1996/08/07 12:56:21  jfasch
// added lineno. to set_()
//
// Revision 1.1  1996/08/07 12:33:37  jfasch
// Initial revision
//
// 
// </file> 
#include "dbcontr.h"

#include <hyperg/utils/hgregexp.h>
#include <hyperg/utils/environ.h>

// --------------------------------------------------------------------
Verbose DbContrRC :: verbose ;
const char* DbContrRC :: version1 = "$Id: dbcontr.C,v 1.7 1997/02/17 13:42:21 gmesaric Exp $" ;

void DbContrRC :: parse (istream& is) {
   RString line ;
   int lineno = 0 ;
   HgRegexp re_cont ("^([^\\]*)\\\\[ \t]*$") ;
   HgRegexp re_comment ("^[ \t]*#") ;
   HgRegexp re_var ("^[ \t]*([^=]+)[ \t]*$") ;
   HgRegexp re_var_val ("^[ \t]*([^=]+)[ \t]*=[ \t]*(.*)[ \t]*$") ;
   HgRegexp re_scope_var ("^[ \t]*([^ \t]+)[ \t]*::[ \t]*([^ \t]+)[ \t]*$") ;
   HgRegexp re_noparam ("^[ \t]*[^][]*$") ;
   HgRegexp re_param ("^[ \t]*([^[ \t]+)[ \t]*([[])[ \t]*([^] \t]+)[ \t]*]") ;

   // have to substitue "$HOME" with the content of HOME env. in the
   // values of the configuration parameters to be read. check out the
   // home.
   RString home ;
   bool havehome = false ;
   if (Environ::getEnv ("HOME", home))
      havehome = true ;

   for (;;) {
      RString nextline ;
      nextline.gLine (is) ;
      if (is.eof()) {
         if (line.length()) {
            // a continued line expected
            DEBUGNL ("DbContrRC::parse(): unexpected eof, line "<<lineno) ;
            error_("unexpected end of file", lineno) ;
         }
         break ;
      }
      lineno++ ;
      DEBUGNL ("DbContrRC::parse(): line #"<<lineno<<" is: "<<nextline.string()) ;
      if (0 < re_comment.Match (nextline, nextline.length(), 0)) {
         DEBUGNL ("DbContrRC::parse(): comment, line "<<lineno) ;
         continue ;
      }
      if (line.length())
         line += nextline ;
      else 
         line = nextline ;
      
      if (0 < re_cont.Match (line, line.length(), 0)) {
         DEBUGNL ("DbContrRC::parse(): to be continued, line "<<lineno) ;
         line = RString (line.string()+re_cont.BeginningOfMatch(1), 
                         re_cont.EndOfMatch(1) - re_cont.BeginningOfMatch(1)) ;
         continue ;
      }
      
      // got a full line at this point. split it.
      {
         DEBUGNL ("DbContrRC::parse(): got a full line: "<<line.string()) ;

         RString scope ;
         RString var ;
         RString param ;
         RString val ;
         RString error ;

         if (0 < re_var_val.Match (line, line.length(), 0)) {
            DEBUGNL ("DbContrRC::parse(): variable=value") ;
            var = RString (line.string() + re_var_val.BeginningOfMatch(1),
                           re_var_val.EndOfMatch(1) - re_var_val.BeginningOfMatch(1)) ;
            val = RString (line.string() + re_var_val.BeginningOfMatch(2),
                           re_var_val.EndOfMatch(2) - re_var_val.BeginningOfMatch(2)) ;
         }
         else if (re_var.Match (line, line.length(), 0)) {
            DEBUGNL ("DbContrRC::parse(): only a variable, no value") ;
            var = RString (line.string() + re_var.BeginningOfMatch(1),
                           re_var.EndOfMatch(1) - re_var.BeginningOfMatch(1)) ;
         }
         else {
            DEBUGNL ("DbContrRC::parse(): neither var-value nor var alone (?)") ;
            error = RString ("invalid config line") ;
         }

         if (! error.length()) {
            if (0 < re_scope_var.Match (var, var.length(), 0)) {
               // extract scope and leave rest in var
               DEBUGNL ("DbContrRC::parse(): scoped variable, line "<<lineno) ;
               scope = RString (var.string() + re_scope_var.BeginningOfMatch(1),
                                re_scope_var.EndOfMatch(1) - re_scope_var.BeginningOfMatch(1)) ;
               var = RString (var.string() + re_scope_var.BeginningOfMatch(2),
                              re_scope_var.EndOfMatch(2) - re_scope_var.BeginningOfMatch(2)) ;
            }

            DEBUGNL ("DbContrRC::parse(): var is up to now: "<<var.string()) ;
            if (0 < re_param.Match (var, var.length(), 0)) {
               DEBUGNL ("DbContrRC::parse(): parameterized variable, line "<<lineno) ;
               RString tmpvar (var.string() + re_param.BeginningOfMatch(1),
                               re_param.EndOfMatch(1) - re_param.BeginningOfMatch(1)) ;
               param = RString (var.string() + re_param.BeginningOfMatch(3),
                                re_param.EndOfMatch(3) - re_param.BeginningOfMatch(3)) ;
               DEBUGNL ("DbContrRC::parse(): var: "<<var.string()<<", param: "<<param.string()) ;
               var = tmpvar ;
            }
            else if (0 > re_noparam.Match (var, var.length(), 0)) {
               DEBUGNL ("DbContrRC::parse(): angle bracketing error, line "<<lineno) ;
               error = "invalid angle bracketing" ;
            }
            else {
               // noparam
               DEBUGNL ("DbContrRC::parse(): non-parameterized variable, line "<<lineno) ;
            }
         }
         
         if (error.length())
            error_(error, lineno) ;
         else {
            // substitute "$HOME" in val with the content of env. HOME
            if (val.indexa("$HOME") >= 0)
               if (! havehome)
                  error_("cannot substitute $HOME in configuration value (seem to be homeless)",
                         lineno) ;
               else {
                  DEBUGNL ("DbContrRC::parse(): substituting $HOME with "<<home.string()) ;
                  val.subst ("$HOME", home) ;
                  scope.toUpper() ;
                  var.toUpper() ;
                  // param.toUpper() ;
                  set_(scope, var, param, val, lineno) ;
               }
            else {
               scope.toUpper() ;
               var.toUpper() ;
               // param.toUpper() ;
               set_(scope, var, param, val, lineno) ;
            }
         }
      }
      
      line = RString() ;
   }
}
