/*                                                               -*- C -*-
 *  FLIST.C
 *
 *  (c)Copyright 1992-93 by Tobias Ferber,  All Rights Reserved.
 */

#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "cvt.h"

/*** / GLOBALS / ***/

int global_numfiles= 0;
fnode_t *flist= NIL(fnode_t);


int chain_fname(char *host, char *fname)
{
  static fnode_t *tail= NIL(fnode_t);
  fnode_t *fn;

  if( fn= (struct fnode *)malloc(sizeof(struct fnode)) )
  {
    if( fn->filename= (char *)malloc((strlen(fname)+1)*sizeof(char)) )
    {
      strcpy(fn->filename, fname);
      fn->hostname= host;
      fn->next= NIL(fnode_t);

      if(!flist)
        flist= fn;

      if(tail)
        tail->next= fn;

      tail= fn;
      ++global_numfiles;
    }
    else
    {
      free(fn);
      fn= NIL(fnode_t);
    }
  }
  return fn ? 0:1;
}


void purge_flist(void)
{
  while(flist)
  {
    fnode_t *t= flist;
    flist= flist->next;

    if(t->filename)
      free(t->filename);
    free(t);
  }
  global_numfiles= 0;
}


int get_fname(FILE *fp, char *fname)
{
  int c, n=0;
  static int line= 1;

  typedef enum { outer_mode,
                 word_mode,
                 string_mode,
                 return_mode,
                 error_mode
               } smode_t;

  smode_t smode= outer_mode;

  while( smode != return_mode && smode != error_mode && !feof(fp) )
  {
    c= fgetc(fp);

    if(feof(fp) && c!=EOF)
      c= EOF;

    switch(c)
    {
      case ' ': case '\t':
        switch(smode)
        {
          case word_mode:
            fname[n++]= '\0';
            smode= return_mode;
            break;

          case string_mode:
            fname[n++]= c;
            break;
        }
        break;

      case '\n': case '\r':
        switch(smode)
        {
          case word_mode:
            fname[n++]= '\0';
            smode= return_mode;
            break;

          case string_mode:
            sprintf(fname,"%d: unterminated string at EOL; missing quotes",line);
            smode= error_mode;
            break;
        }
        line++;

        { int d= fgetc(fp);
          if( !(c=='\n' && d=='\r' || c=='\r' && d=='\n') )
            ungetc(d,fp);
        }
        break;

      case '\"':
        switch(smode)
        {
          case outer_mode:
            smode= string_mode;
            break;

          case string_mode:
            fname[n++]= '\0';
            smode= return_mode;
            break;

          case word_mode:
            fname[n++]= '\0';
            ungetc(c,fp);
            smode= return_mode;
            break;
        }
        break;

      case EOF:
        switch(smode)
        {
          case word_mode:
            if( feof(fp) )
            {
              fname[n++]= '\0';
              smode= return_mode;
            }
            else fname[n++]= c;
            break;

          case string_mode:
            if( feof(fp) )
            {
              sprintf(fname,"%d: unterminated string at EOF",line);
              smode= error_mode;
            }
            else fname[n++]= c;
            break;
        }
        break;

      default:
        switch(smode)
        {
          case outer_mode:
            smode= word_mode;
            /* fall through */

          case word_mode:
          case string_mode:
            fname[n++]= c;
            break;
        }
        break;
    }

    if(n >= MAXIMUM_PATHNAME_LENGTH)
    {
      sprintf(fname,"%d: line too long",line);
      smode= error_mode;
    }
  }

  fname[n]= '\0';
  return (smode == error_mode) ? 0 : line;
}


int read_flist(char *host)
{
  char *fname;

  if( fname= (char *)malloc(MAXIMUM_PATHNAME_LENGTH * sizeof(char)) )
  {
    FILE *fp, *tf;

    if( fp= fopen(host, "r") )
    {
      int line= 1;

      while( line > 0 && !feof(fp) && !ferror(fp) )
      {
        line= get_fname(fp, fname);

        if(*fname)
        {
          if(line > 0)
          {
            if( global_checkexists )
            {
              if( tf= fopen(fname,"r") )
                fclose(tf);

              else
              { echo("In file `%s' line %d:",host,line);
                perror(fname);
                return 3;
              }
            }

            if( chain_fname(host,fname) )
            { echo("%s: ran out of memory in line %d",host,line);
              return 4;
            }
          }
          else
          { echo("%s: %s",host,fname);
            return 2;
          }
        }
        /* else feof(fp) ?! */
      }
      fclose(fp);
    }
    free(fname);
    return 0;
  }
  perror(host);
  return 1;
}


#ifdef DEBUG
void print_flist(void)
{
  fnode_t *fn= flist;

  if(fn)
  {
    int n;
    printf("list of input files:\n");

    for(n=0; fn; n++, fn= fn->next)
      printf("\t%s: \"%s\"\n", (fn->hostname ? fn->hostname
                                             : "command-line"), fn->filename);
  }
  else printf("no input files specified.\n");
}
#endif /* DEBUG */
