/*
    Numdiff - compare putatively similar files, 
    ignoring small numeric differences
    Copyright (C) 2005-2007  Ivano Primi  <ivprimi@libero.it>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    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 GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"numdiff.h"

#ifdef _DMALLOC_
#include <dmalloc.h> /* Useful only for the debugging */
#endif

int open_files (const char* file1, const char* file2, FILE** fpp1, FILE** fpp2)
{
  /* Open file1 and file2 */
  if ( strcmp (file1, file2) == 0 )
    {
      fputs (_("\n***  Cannot compare a file with itself\n\n"), stderr);
      return -1;
    }
  if ( strcmp (file1, "-") == 0 )
    *fpp1 = stdin;
  else
    {
      if ( !(*fpp1 = fopen (file1, "r")) )
	{
	  fprintf (stderr, _("\n***  Cannot open file \"%s\"\n"), file1);
	  return -1;
	}	
    }
  if ( strcmp (file2, "-") == 0 )
    *fpp2 = stdin;
  else
    {
      if ( !(*fpp2 = fopen (file2, "r")) )
	{
	  fprintf (stderr, _("\n***  Cannot open file \"%s\"\n"), file2);
	  return -1;
	}	
    }
  return 0;
} 

char* read_line (FILE* pf, int* errcode)
{
  char buffer[BUFF_SIZE];
  char *ptr, *line = NULL;
  size_t lline = 0;

  while ((ptr = fgets (buffer, BUFF_SIZE,pf)))
    {
      lline += strlen (buffer);
      if (!line)
	ptr = (char*) calloc (lline + 1, sizeof(char));
      else
	ptr = (char*) realloc ((void*)line, (lline + 1) * sizeof(char));
      if (!ptr)
	{
	  if ((line))
	    free ((void*)line);
	  *errcode = OUT_OF_MEMORY;
	  return NULL;
	}
      else
	{
	  line = ptr;
	  strcat (line, buffer);
	}
      if (lline > 0 && line[lline-1] == '\n')
	break;
    }
  if (!ptr)
    {
      if ( (ferror(pf)) )
	*errcode = READING_ERROR;
      else if (lline > 0)
	*errcode = LINE_INTERR;
      else
	*errcode = EOF_REACHED; 
    }
  else
    *errcode = OK;
  return line;
} 

static
void print_head (const char* str, size_t length)
{
  const char* t;

  for (t = str; t - str < length; putchar(*t), t++);
}

static
void print_ws (unsigned n)
{
  while ((n--))
    putchar (' ');
}

static
void writeln (const char* line, int addemptyline)
{
  const char *ptr;

  for (ptr = line; *ptr != '\0'; putchar(*ptr), ptr++);
  if (ptr == line || *(ptr-1) != '\n')
    puts (EOF_INDICATOR);
  if ((addemptyline))
    putchar('\n');
}

/*
  This function assumes that at least one between line1 and line2 is
  not empty (!NULL).
*/
void print_lines (const char* line1, const char* line2, 
		  unsigned long lineno, int delimiter_only)
{
  puts (LINE_SEP); 
  if (!delimiter_only)
    {
      if (!line1)
	{
	  printf ("##%-7lu <==\n          ==> ", lineno);
	  writeln (line2, 1);
	}
      else if (!line2)
	{
	  printf ("##%-7lu <== ", lineno);
	  writeln (line1, 0);
	  printf ("          ==>\n\n");
	}
      else
	{
	  printf ("##%-7lu <== ", lineno);
	  writeln (line1, 0);
	  printf ("          ==> ");
	  writeln (line2, 1);
	}
    }
}

/*
  This function assumes that at least one between field1 and field2 is
  not empty.
*/
void print_fields (const char* field1, const char* field2,
		   size_t l1, size_t l2, 
		   unsigned long lineno, unsigned long fieldno)
{
  fieldno++; /* The field number must start from 1, not from 0 */
  if (*field1 == '\0')
    {
      printf ("##%-7lu #>%-3lu <==\n", lineno, fieldno);
      print_ws (6+10);
      /* 6 = size("## #: "), 10 = 7+3 */
      fputs ("==> ", stdout);
      writeln (field2, 0);
    }
  else if (*field2 == '\0')
    {
      printf ("##%-7lu #>%-3lu <== ", lineno, fieldno);
      writeln (field1, 0);
      print_ws (6+10);
      /* 6 = size("## #: "), 10 = 7+3 */
      puts ("==>");
    }
  else
    {
      printf ("##%-7lu #:%-3lu ", lineno, fieldno);
      fputs ("<== ", stdout);
      print_head (field1, l1);
      putchar ('\n');
      print_ws (6+10);
      /* 6 = size("## #: "), 10 = 7+3 */
      fputs ("==> ", stdout);
      print_head (field2, l2);
      putchar ('\n');
    }
}

void print_errors (Real abserr, Real relerr)
{
  fputs (_("@ Absolute error = "), stdout);
  printno (abserr, DEF_LIM);
  fputs (_(", Relative error = "), stdout);
  printno (relerr, DEF_LIM); 
  putchar ('\n');
}

void print_separator (void)
{
  putchar ('@');
  print_ws (53);
  puts ("@@");
}


syntax highlighted by Code2HTML, v. 0.9.1