
/**---------------------------------------------------------------------------
 ** 
 ** io.c -- Miscellaneous I/O functions
 ** 
 ** Author          : Pierre Jaccard
 ** Created On      : 1999/07/15 12:15:13
 ** Last Modified By: Pierre Jaccard
 ** Last Modified On: 1999/07/16 21:24:08
 ** Update Count    : 5
 ** Directory       : /home/pego/pcd1/codas3c/gfi/src/libs/misc/
 ** Version         : 0.0
 ** Status          : Unknown
 ** ---------------------------------------------------------------------- ** 
 ** DESCRIPTION: 
 ** 
 **    This file provide I/O functions that do not fit yet elsewhere.
 ** 
 ** ---------------------------------------------------------------------- ** 
 ** REVISIONS: 
 ** ---------------------------------------------------------------------- ** 
 ** CHANGES: 
 **------------------------------------------------------------------------**/

#include "io.h"

/* ------------------------------------------------------------------
   This functions moves the pointer of a file until n characters c
   have been read. If c is 0, then just moves over the n next
   characters. If n is negative, move backwards.

   On output, if c was not specified, the file is positionned n characters
   from input position. If c was specified, the file is positionned just
   after the nth character c from from input position.

   RETURNS: non-zero on error, EOF if end or begining of file occured
   ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int move_nchar(/* File descriptor */
               FILE *fp, 
               /* Character to count */
               char c, 
               /* Number of characters */
               int n)
#else
     int move_nchar(fp, c, n)
     FILE *fp;
     char c;
     int n;
#endif
{
	char func[]="getnchar";

	int m=0, done, ic, inc;
	long pos;

	/* Initialize increment */
	inc = (n > 0) ? 1 : -1;

	/* Take character values into consideration */
	if(c != 0){
		/* Loop through the characters */
		done = 0;
		pos = ftell(fp) + inc;
		while(!done){
			/* Test value of file position */
			if(pos < 0)
				return(EOF);
			if(!done){
				/* Go to new file position */
				if( fseek(fp, pos, SEEK_SET) ){
					if(feof(fp))
						return(EOF);
					else{
						error_msg(func, "While moving to next character");
						return(READ_ERROR);
					}
				}
				/* Get next character */
				ic = fgetc(fp);
				if(ic == EOF){
					if(feof(fp))
						return(EOF);
					else{
						error_msg(func, "While reading next character");
						return(READ_ERROR);
					}
				}
				/* Update number of matching characters */
				m += ((char) ic == c) ? 1 : 0;
				/* Loop exit flagg */
				done = (m >= abs_val(n));
				/* Update position in file */
				pos += inc;
			}
		}
	}		
	else{
		/* Just move n characters */
		pos = ftell(fp) + n;
	}

	return(0);
}
	
/* ------------------------------------------------------------------
   Gets the next data filename from alist of files. The current data file is
   closed, the data file information structure is initialized with the new
   file settings, which is in turn initialized.

	 RETURNS: EOF if there is no more files in the list, or non-zero on error
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int next_data_file(/* List of file names */
                   FILE *fp, 
                   /* Information structure about current data file */
                   DATA_FILE_INFO_TYPE *fi)
#else
int next_data_file(fp, finfo)
FILE *fp;
DATA_FILE_INFO_TYPE *fi;
#endif
{

	char func[]="next_data_file";

	DATA_FILE_INFO_TYPE backup;
	int error=0, n;

	/* Copy current ping state */
  /* 2001/01/02 PJ
     Since backup has been removed, the next line has no effect

     memcpy((void *) &backup, (void *) fi, sizeof(DATA_FILE_INFO_TYPE));
  */

	/* Close current data file */
	if(fi->fp != NULL){
		fclose(fi->fp);
		fi->fp = NULL;
	}
		
	/* Read next file name */
	n = getword_nc(fp, (char *) fi->name, (int) sizeof(FILE_NAME_TYPE));
	if(feof(fp))
		error = EOF;
	else if(n < 1){
		error_msg(func, "while reading next file name");
		error=READ_ERROR;
	}

	/* Initialize next file */
	if(!error){
		if(strlen(fi->mode) > 0){
			fi->fp = check_fopen((char *) fi->name, (char *) fi->mode);
			rewind(fi->fp);
		}
		else{
			error_msg(func, "No mode defined for data file");
			error=READ_ERROR;
		}
		/* Update data file structure */
		fi->list_pos = (ULONG) ftell(fp);
		fi->data_pos = (ULONG) ftell(fi->fp);
	}
	else{
		if(error != EOF)
			error_msg(func, "While getting next data file");
    /* 2000/12/03 PJ Removed backup of data */
    if(0){
      /* Restore old values in structure */
      memcpy((void *) fi, (void *) &backup, sizeof(DATA_FILE_INFO_TYPE));
      /* Position back to previous position */
      fseek(fp, (long) fi->list_pos, SEEK_SET);
      fi->fp = check_fopen((char *) fi->name, (char *) fi->mode);      
      fseek(fi->fp, (long) fi->data_pos, SEEK_SET);
    }
		return(error);
	}

	return(0);

}

/* ------------------------------------------------------------------
   This function is similar to function next_data_file(), except that parsing
   of data files is carried out in the reverse order. 

	 RETURN: EOF if beginning of list is reached, or non-zero on error
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int prev_data_file(/* List of data filenames */
                   FILE *fp, 
                   /* Information structure about current data file */
                   DATA_FILE_INFO_TYPE *fi)
#else
int prev_data_file(fp, fi)
FILE *fp;
DATA_FILE_INFO_TYPE *fi;
#endif
{

	char func[]="prev_data_file";

	DATA_FILE_INFO_TYPE backup;
	int error=0;
	long pos;

	/* Copy current ping state */
	memcpy((void *) &backup, (void *) fi, sizeof(DATA_FILE_INFO_TYPE));

	/* Check if beginning of list */
	if(fi->list_pos == 0)
		return(EOF);

	pos = (long) fi->list_pos;
	
	/* Loop until previous file is found, or beginning of file */
	while((fi->list_pos == backup.list_pos) && !error){
		
		/* Position file at pos */
		if(fseek(fp, pos, SEEK_SET))
			error = SEEK_ERROR;

		/* Position in list of files to previous file name */
		if(!error){
			error = move_nchar(fp, '\n',  -2);
			/* Save new start position */
			pos = ftell(fp);
		}
			
		/* Read next file name and initialize it */
		if(!error)
			error = next_data_file(fp, fi);
	}
		
	/* Message if error */
	if(error){
		/* Restore old values in structure */
		memcpy((void *) fi, (void *) &backup, sizeof(DATA_FILE_INFO_TYPE));
		/* Position back to previous position */
		fseek(fp, (long) fi->list_pos, SEEK_SET);
		fseek(fi->fp, (long) fi->data_pos, SEEK_SET);
		/* Message */
		if(error != EOF)
			error_msg(func, "While initilaizing previous data file");
		return(error);
	}

	return(0);
	
}

/* ------------------------------------------------------------------
   Initialize information structure about data files. If pointer to list of
   data file names is not NULL, then initialize the structure with the first
   data file. 

	 RETURN: non-zero on error
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int init_file_info(/* Pointer to list of data file names */
                   FILE *fp, 
                   /* Information structure about current data file */
                   DATA_FILE_INFO_TYPE *fi, 
                   /* Format to use when openeing files */
                   char *format)
#else
     int init_file_info(fp, fi, format)
     FILE *fp;
     DATA_FILE_INFO_TYPE *fi;
     char *format
#endif
{

	char func[]="init_file_info";

	int error;

	strcpy((char *) fi->name, "");
	strcpy(fi->mode, format);
	fi->list_pos = 0;
	fi->data_pos = 0;
	fi->fp = NULL;

	/* Initialize data with first ensemble */
	if(fp != NULL){
		/* Get first ping file name */
		error = next_data_file(fp, fi);
		if(error){
			error_msg(func, "while searching first ping file name");
			return(error);
		}
	}

	return(0);

}

/* ------------------------------------------------------------------
	 This function reports if a file change occured.

   RETURNS: 0
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int report_file_change(/* Previous file name */
                       FILE_NAME_TYPE prev, 
                       /* Current file name */
                       FILE_NAME_TYPE curr)
#else
     int report_file_change(prev, curr)
     FILE_NAME_TYPE prev;
     FILE_NAME_TYPE curr;
#endif
{

	FILE_NAME_TYPE p1, p2, n1, n2;
	char msg[200];

	if(strcmp((char *) prev, (char *) curr)){
		split_file_path((char *) prev, (char *) p1, (char *) n1);
		split_file_path((char *) curr, (char *) p2, (char *) n2);
		sprintf(msg, "\n%%%%%% FILE CHANGE FROM %s TO %s\n", n1, n2);
		report_msg(msg);
	}

	return(0);

}
