/* file_rw.c  -  consist of ReadFile and WriteFile procedures to be used
		 together with Motif applications.
		 (C) A. Stochniol,  1991 - 1993
		 Last revision: 15.01.1993
*/


#ifdef AMIGA
#include "amiga.h"
#endif

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <X11/Xatom.h>

#include <Xm/Xm.h>




/****************************  ReadFile  ***********************************
**
**		Open the specified file and reads its contents.
**		Returns a pointer to the file contents  if file exists and
**		open is sucessful (otherwise returns NULL).
**		If the file was opened in the read only mode
**		*read_only is True.
*/
#ifdef _NO_PROTO
char * ReadFile(file_name, read_only)
   char *file_name;
   Boolean *read_only;
#else  /* _NO_PROTO */

char * ReadFile(char *file_name, Boolean *read_only)
#endif
{
   struct stat statbuf;		/* Information on a file. */
   long file_length;		/* Length of file. 	  */
   FILE *fp = NULL;		/* Pointer to open file   */
   static char *file_string; /* pointer to the file contents */
   long n_read_items;		/* how many items (here bytes) were read in */

   *read_only = False;

   /* make sure the file is a regular text file and open it */
   if(stat(file_name, &statbuf) == 0  &&
	(statbuf.st_mode & S_IFMT) != S_IFREG )
   {
	fprintf(stderr, "\n%s: not a regular file.", file_name);
	return(NULL);
   }
   if ((fp = fopen(file_name, "r+")) == NULL)
	if ((fp = fopen(file_name, "r")) != NULL)
	{
		    fprintf(stderr, "Warning: file opened read only.\n");
		    *read_only = True;
	}
	else    return(NULL);


   if (stat(file_name, &statbuf) == 0)
	 file_length = statbuf.st_size;
   else
	 file_length = 500000L; /* arbitrary file length */

   /* read the file string */
   file_string = XtMalloc((unsigned)(file_length+1));	/* +1 for NULL character */

   n_read_items = fread(file_string, sizeof(char), file_length, fp);
   file_string[n_read_items]=NULL;	/* adding the NULL character to the end
					   of the file_string */
   /* n_read_items was specially introduced because the file string should be
      null terminated. For DOS file file_length takes into account both line feed
      and carriege return, but during read operation they are translated into
      a single line feed character!!! (so n_read_items is smaller than file_length
      for the DOS file !!!) */

   /* close up the file */
   if (fclose(fp) != NULL) fprintf(stderr, "Warning: unable to close file.\n");

   return(file_string);

}  /* ReadFile */

/***
	currently (Release 1.1) a user decide about BACKUP_FILE_SUFFIX
	in the Imakefile file so I commented my original (Rel. 0.9) declaration
#define BACKUP_FILE_SUFFIX	".bak"

******/

#ifdef AMIGA
#define BACKUP_FILE_SUFFIX	".bak"
#endif

/****************************  WriteFile  **********************************
	WriteFile  - writes a text pointed to by *file_string to the file
	file_name. To preserve hard links no intermediate temporary file is used for save result.
	If the file already exist it is overwritten without any message
	(this procedure is used mainly for saving option. If successful
	returns True.)
*/
#ifdef _NO_PROTO
Boolean WriteFile(file_name, file_string)
    char *file_name;
    char *file_string;
#else  /* _NO_PROTO */

Boolean WriteFile(char *file_name, char *file_string)
#endif
{
    FILE *fp;				/* Pointer to an open file. */
    FILE *tfp;           		/* Pointer to open temporary file. */
    Boolean result;
    int status;
    char system_call_buf[BUFSIZ];

    char tempname[25];	 /* Temporary file name.         */

    /* to preserve hard links we are not using rename command any more; instead
       of that we are using copy command 
    */
#ifndef AMIGA
    strcpy(tempname, mktemp("/tmp/aseditXXXXXX"));
#else
    strcpy(tempname, "t:aseditXXXXXX");
#endif

    if ((tfp = fopen(tempname, "w")) == NULL) {
       fprintf(stderr, "Warning: unable to open temp file '%s', text not saved.\n", tempname);
       return(False);
    }


    /* check if the file_name already existed, if yes make a backup of it (make the backup when user requested it by defining BACKUP_FILE_SUFFIX) */
    if ((fp = fopen(file_name, "r")) != NULL)
    {
	/* Backup  file name.    */
	char *backname = XtMalloc(strlen(file_name) + strlen(BACKUP_FILE_SUFFIX) +1);

	fclose(fp);
	strcpy(backname, file_name);
	if(strlen(BACKUP_FILE_SUFFIX))
        {    /* make the backup of the file */
             strcat(backname,BACKUP_FILE_SUFFIX);
	     /* to preserve any possible hard link we copy the old file onto
	        the backup (instead of moving it)  */
	     /* unfortunately we lose the old date/time but we might set
		that properly in the future if needed
	     */
#ifdef AMIGA
  	     sprintf (system_call_buf, "copy %s %s\0", file_name , backname);
#else
  	     sprintf (system_call_buf, "cp %s %s\0", file_name , backname);
#endif
  	     status = system(system_call_buf);
  	     if (status != 0)
	     {
	        fprintf(stderr, "Warning: unable to create backup file '%s'.\nFollowing file not safed: '%s'.\n", 
			backname, file_name);
	        XtFree(backname);
	        return(False);
	     }
	     XtFree(backname);
	}
    }

    /* write to a temp file */
    fwrite(file_string, sizeof(char), strlen(file_string) , tfp);

    /* because asedit might be used to edit programs we are checking
       if the last line is a complete line (if it is not we add the line
       feed there to avoid any problems during compilation of the program,
       especially true for FORTRAN programs;
       it is the same what vi probably does)
    */
    if(file_string[strlen(file_string)-1] != '\n')
	fwrite("\n", sizeof(char), 1, tfp);

    result = True;
    /* flush and close the file */
    if (fflush(tfp) != NULL)
	{ result=False;  fprintf(stderr,"Warning: unable to flush file.\n"); }
    if (fclose(tfp) != NULL)
	{ result=False;  fprintf(stderr,"Warning: unable to close file.\n"); }

    if(!result) return(result);

    /* Move the tempname to the saved file, but do it independent
     of filesystem boundaries; on some modern operating systems the move/rename command is
     not supported accross different file systems!! (e.g. IBM RS/6000) (/tmp probably lies
     in a different file system than the user data files)  */

#ifdef AMIGA
    sprintf (system_call_buf, "copy %s %s\0", tempname, file_name);
#else
    sprintf (system_call_buf, "cp %s %s\0", tempname, file_name);
#endif
    status = system(system_call_buf);
    unlink (tempname);
    if (status == 0) 	result = True;
    else
    {
        fprintf(stderr, "Warning: unable to save file.\n");
	result = False;
    }
    return(result);

}   /* WriteFile */
