/*
   <p>Function to locate a configuration file.</p>

   <kbd>
   <b>environ - C programming support functions</b><br>
   Copyright (C) 2005  Martin C Gregorie
   
   This program is free software; you can redistribute it and/or
   modify it under the terms of the Lesser GNU General Public License.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the Lesser GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   </kbd>
  
   <p>Contact Martin Gregorie at <i>martin@gregorie.org</i></p>
*/

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <environ.h>

static int  debug;
static char *cfname;
static int  lineno; 

/*
   Open the configuration file. Search the current directory, /usr/local/etc
   and /etc in that order. <u>prog</u> is the name of the calling program,
   <u>name</u> is the basename of the configuration file and <u>d</u> is the
   debugging level. A value of 1 causes the name of the configuration file,
   significant configuration lines and configuration file closure
   to be traced. A value of 2 or greater will additionally cause the search
   for the configuration file to be traced. The debug level also applies to
   <i>config_close()</i> and <i>config_getline()</i>.

   <b>config_open</b> returns the <i>FILE*</i> pointer on success and null
   on failure.
*/
FILE *config_open(char *prog, char *name, int d)
{
   FILE  *cf;
   char  *dirlist[] = { "./", "/usr/local/etc/", "/etc/", "" };
   char  *path;
   int   i = 0;

   debug = d;
   lineno = 0;
   cfname = get_space(strlen(name)+1);
   strcpy(cfname, name);
   while (strlen(dirlist[i]) != 0)
   {
      path = (char*) get_space(strlen(name) + strlen(dirlist[i]) + 1);
      strcpy(path, dirlist[i]);
      strcat(path, name);
      if (debug > 1)
         logmsg("Trying: %s", path);
            
      cf = fopen(path, "r");
      if (cf)
      {
         if (debug)
            logmsg("Configuration: %s", path);
            
         break;
      }

      path = release_space(path);
      i++;
   }

   if (!cf)
      error(prog, "can't open configuration file:", name);

   return cf;
}

/*
   Close the configuration file <u>cf</u>.
*/
void config_close(FILE *cf)
{
   fclose(cf);

   if (debug)
      logmsg("Configuration file %s closed", cfname);

   cfname = release_space(cfname);
}

/*
   Read the next non-blank, non-comment
   line from the config file <u>cf</u> into the <u>line</u> buffer.
   <u>lth</u> contains the maximum length of <u>line</u>.
   Lines that are too long for the buffer are returned with
   truncation warnings. 

   Comment lines start with #. Trailing comments and
   blanks are stripped from the remaining lines.
   
   <b>config_getline</b> returns TRUE if a line with data was
   returned and FALSE when end of file is found.
   I/O errors are trapped and the run abandoned.

*/
int config_getline(FILE *cf, char *line, int lth)
{
   int   quit = FALSE;
   int   n;
   char  *cp;
   char  lnum[10];

   while (!quit)
   {
      if (fgets(line, lth, cf))
      {
         lineno++;
         n = strlen(line);
         if (line[n-1] != '\n' && n == lth - 1)
            warn(progname(), "truncated line ", itoa(lineno, lnum, 10));
         else
         {
            /*
               Remove the trailing n/l
            */
            if (line[n-1] == '\n')
               line[n-1] = 0;

            /*
               Check for comments and truncate the line
               at the last comment marker
            */
            cp = strrchr(line, '#');
            if (cp)
               *cp = 0;

            /*
               Remove trailing spaces and tabs
            */
            n = strlen(line);
            while (n > 0 && (line[n-1] == ' ' || line[n-1] == '\t'))
            {
               line[n-1] = 0;
               n--;
            }

            /*
               Measure what's left. If it is non-zero length
               and doesn't start with a comment marker its a keeper.
               Otherwise, go on reading.
            */
            n = strlen(line);
            if (n && line[0] != '#')
            {
               if (debug)
                  logmsg("%s %d: %s", cfname, lineno, line);
                  
               quit = TRUE;
            }
         }
      }
      else
      {
         /*
            i/o exception signalled.
            If no characters were read its an EOF, so return FALSE.
            Anything else is reported before bombing out.
         */
         if (strlen(line) == 0)
            return FALSE;
         else
            error(progname(), strerror(errno), "");
      }
   }

   return TRUE;
}
