#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>  
#include <yafl_rnt.h>
#include "dbx_rnt.h"
#include "dbx_file.h"
#include "dbx_stri.h"
#include "dbx_worl.h"

/* this module is used to allow the debugger to show the YAFL source lines */
/* of the debugged modules */
/* a simple cache scheme is used to speed up the system */
/* at most one source file is open at any given time */
/* the cache stores a number of contiguous lines of this file */

#define LINE_CACHE_SIZE 64
#define LINE_BUFFER_SIZE 255

#define MAX_WORLDS 99


static char file_name2[80];
static FILE *open_file = NULL;
static char line_buffer[LINE_BUFFER_SIZE];
static char line_cache[LINE_CACHE_SIZE] [LINE_BUFFER_SIZE];
static unsigned  position; /* next line to be read on sequential file */
static unsigned line; /* first line in cache */
static unsigned count = 0; /* number of valid lines in cache */

static char delimiters[] = ":;";

/* caution: this constant is machine-dependant */
static char separator[] = "/";

static int in_cache YPARAMS2(unsigned,  line_number)
{
  return (line_number >= line) && (line_number < line + count);
}

static char *try_in_paths YPARAMS4(char *, list_of_paths,
                                  char *, file_name)
{
  char *path_name;
  char *p;
  char *absolute_name;
  assertp (file_name);
  if (list_of_paths)
  {
    p = strclone(list_of_paths);  
    path_name = strtok(p, delimiters);
    while (path_name)
    {              
      absolute_name = strjoin3(path_name, separator, file_name);
      if (fexists(absolute_name))
      {
        free(p);
        return(absolute_name);
      }
      free(absolute_name);
      path_name = strtok(NULL,delimiters);
    }
    free(p);
    return NULL;
  }
  else
  {
    return NULL;
  }
}        

/* this function will try to find a file in various places;if succesful */
/* it returns the complete file name,or just the file name if the file */
/* was found in the current directory ;if research fails NULL is returned */
/* first we try in the current directory */
/* then we try in the directories given by the YWORLDS environment variable */
/* then try in the directories given by further YWORLD environment variables */
/* these variables are named YWORLD 0 through MAX_WORLDS - 1 */
char *try_open YPARAMS2(char *,  file_name)
{
  char *list_of_paths;
  char environ_name[128];
  char *name;
  assertp(file_name); 
  if (fexists(file_name))
  {
    name = strclone(file_name);
  }
  else
  {
    name = try_in_paths(getenv("YWORLDS"), file_name);
    if (!name)
    {
      int i;
      i = 0;
      while (i < MAX_WORLDS)
      {
        sprintf(environ_name,"YWORLD%d",i);
        name = try_in_paths(getenv(environ_name), file_name);
        if (name)
          i = MAX_WORLDS;
        else
          i++;
      }
    }
  }
  return name;
}




/*
  The read_line function reads a line from the input stream,
  forces the 0 termination, and eventually erases the terminating
  newline character.
*/
static void read_line YPARAMS4(char *,  line,
                              FILE *,  stream)
{
   char *p;
   int i;

   for (i = 0; i <= LINE_BUFFER_SIZE - 1; i++)
     line[i] = 0;   
   fgets(line,LINE_BUFFER_SIZE - 1,stream);
   line[LINE_BUFFER_SIZE - 1] = 0;
   p = line + strlen(line) - 1;
   while ((p >= line) && ((*p == ' ') || (*p == '\t') || (*p == '\n')))
     {
     *p = 0;
     p--;
     } 
}

/* get a line of the given file,which can be found in the cache or will be */
/* read on the disk;in this case a number of the next lines will also be */
/* read and will replace the current content of the cache */
char *get_source_line YPARAMS4(char *,   file_name,
                              unsigned, line_number)
{
   int i;
   char wk_line_buffer[LINE_BUFFER_SIZE];
   assertp(file_name);
   assert(line_number >= 1);
   if (strdif(file_name,file_name2))
   {
     if (open_file)
       fclose(open_file);
     open_file = fopen(file_name,"r");
     if (!open_file)
       return(NULL); /* return empty string if file cannot be found */
     strcpy(file_name2,file_name);
     position = 1; /* before first line of the file */
     count = 0; /* no line read yet */
   }
   if (!in_cache(line_number))
   {
     if (line_number < position)
     {
       fseek(open_file,0L,0);
       position = 1;
     }
     while (position < line_number)
     {
       read_line (line_buffer, open_file);
       position++;
     }
     line = line_number;
     for (i = 1;i <= LINE_CACHE_SIZE;i++)
     {
       read_line(wk_line_buffer, open_file);
       strcpy(line_cache[i-1], wk_line_buffer);
       position++;
     }
     count = LINE_CACHE_SIZE;
   }
   return (line_cache[line_number - line]);
}

/* at the start of the system the cache does not contain valid data */
/* an empty name is set so that no name will match it,thus forcing */
/* reading on file */
void init_dbx_file YPARAMS0
{
  strcpy(file_name2,"");
}

/* close the file if one was open */
void term_dbx_file YPARAMS0
{
  if (open_file)
    fclose(open_file);
  strcpy(file_name2,"");
}

