
/* file_act.c - part of asedit program */
/*
 * Copyright 1991 - 1994,  Andrzej Stochniol, London, UK
 *
 * ASEDIT text editor, both binary and source (hereafter, Software) is
 * copyrighted by Andrzej Stochniol (hereafter, AS) and ownership remains
 * with AS.
 *
 * AS grants you (hereafter, Licensee) a license to use the Software
 * for academic, research and internal business purposes only, without a
 * fee.  Licensee may distribute the binary and source code (if released)
 * to third parties provided that the copyright notice and this statement
 * appears on all copies and that no charge is associated with such copies.
 *
 * Licensee may make derivative works.  However, if Licensee distributes
 * any derivative work based on or derived from the Software, then
 * Licensee will:
 * (1) notify AS regarding its distribution of the derivative work, and
 * (2) clearly notify users that such derivative work is a modified version
 *      and not the original ASEDIT distributed by AS.
 *
 * Any Licensee wishing to make commercial use of the Software should
 * contact AS to negotiate an appropriate license for such commercial use.
 * Commercial use includes:
 * (1) integration of all or part of the source code into a product for sale
 *     or license by or on behalf of Licensee to third parties, or 
 * (2) distribution of the binary code or source code to third parties that
 *     need it to utilize a commercial product sold or licensed by or on
 *     behalf of Licensee.
 *
 * A. STOCHNIOL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS
 * SOFTWARE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR
 * IMPLIED WARRANTY.  IN NO EVENT SHALL A. STOCHNIOL BE LIABLE FOR ANY
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * By using or copying this Software, Licensee agrees to abide by the
 * copyright law and all other applicable laws, and the terms of this
 * license.
 * AS shall have the right to terminate this license immediately by
 * written notice upon Licensee's breach of, or non-compliance with, any
 * of its terms.  Licensee may be held legally responsible for any
 * copyright infringement that is caused or encouraged by Licensee's
 * failure to abide by the terms of this license.
 *
 *
 * 	Andrzej Stochniol	(A.Stochniol@ic.ac.uk)
 * 	30 Hatch Road
 * 	London SW16 4PN
 * 	UK
 */

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <Xm/Text.h>

#include "asedit.h"


#ifdef _NO_PROTO
void open_file_in_last_window(filename)
    char *filename;
#else  /* ! _NO_PROTO */

void open_file_in_last_window(char *filename)
#endif
{
    /* opens the specified file in the asedit last window or the default
       file (when filename is NULL)
    */
    char            *work;          /* work string */
    char            *error_open;
    int len;
    static int      as_def_names_count = 0;	/* counter for default names */

    if(filename != NULL && (len=strlen(filename)) )
    {
	 asedit_last_window->filename = XtMalloc(len+1);
	 strcpy(asedit_last_window->filename, filename);
    }
    else
    {
	 /* use the default name .... */
	 char *NoName = (char *)lstr.noname;
	 if(aseditWinCount == 1) as_def_names_count = 0;	/* reset the counter 
							when all windows were closed */
	 as_def_names_count ++;		/* increase the counter */
	 len = strlen(NoName) + 5;
	 asedit_last_window->filename = XtMalloc(len);
	 sprintf(asedit_last_window->filename,"%s%d", NoName ,as_def_names_count);

    }
    /* open file; if file can't be opened or created (e.g. irregular)
       show message and set name to NULL;  if file exists
       open it, if does not but can be created  set the empty text */
    if (!OpenFile(asedit_last_window, False))   /* OpenFile is called with
					only_existing_files = False */
    {
	error_open = (char *)lstr.fm_unable_to_open;
	work = XtMalloc(strlen(error_open) + strlen(asedit_last_window->filename) +1);
	/***** pre 1.3 version (did not care for German syntax)
	    strcpy(work, error_open);
	    strcat(work, asedit_last_window->filename);
	***** pre 1.3 version */
	sprintf(work, error_open, asedit_last_window->filename);
	show_error_message(asedit_last_window, work);
	XtFree(asedit_last_window->filename);   asedit_last_window->filename = NULL;
	XtFree(work);
    }

}   /* open_file_in_last_window */



/*****************************	OpenFile  ************************************
**
**	Calls ReadFile to read the file. Returns true if file
** 	exists and open is sucessful (for only_existing_files).
**	Parameter only_existing_files gives a way of using this
**	procedure for both file options: Load (only_existing_files=True)
**	and New (only_existing_files parameter should be False).
**	Adds file contents to the
**	appropriate widget, makes appropriate items sensitive etc.
**	Calls a procedure to set the title ot the main window (toplevel widget)
**      and the icon name.
*/
#ifdef _NO_PROTO
Boolean OpenFile(win, only_existing_files)
   aseditWindowStruct *win;
   Boolean only_existing_files;
#else  /* ! _NO_PROTO */

Boolean OpenFile(aseditWindowStruct *win, Boolean only_existing_files)
#endif
{
   char * file_string=NULL;	/* Contents of file. 	  */
   Boolean         read_only;		/* shows the file read only status */
   register int ac;			/* arg count		    */
   Arg al[10];				/* widget arg list	    */
   int i;

   /* make sure the file is a regular text file (if not return False
      immediately)*/
   if(!isFileRegular(win->filename))
   {
	/* first set the read only colour (we do that here to avoid flashing the background colour
	   in a healthy situation*/
	ac = 0;
	XtSetArg(al[ac], XmNbackground, text_read_only_background); ac++;/* set the read only colour */
	XtSetValues(win->edit_text1, al, ac);

	return(False);
   }

   if( (file_string = ReadFile(win->filename, &read_only)) != NULL  ||
		!only_existing_files)
   {
	   /***win->file_read_only = read_only; SEPT */
	   if(read_only) win->file_read_only = read_only;	/* 30 SEPT late change */

	   /**** SEPT version
	   if(!read_only)
	   {
	       |* file was read/write; check if the user hasn't requested
		  only view mode; if so set it to read only mode
	       *|
	       if(win->view_only_toggle!= NULL)		|* safety check *|
	       {
		   if(XmToggleButtonGetState(win->view_only_toggle))
				win->file_read_only = True;
	       }
	   }
	   ***** SEPT version ***/


	   ac = 0;
	   XtSetArg(al[ac], XmNeditable, !win->file_read_only); ac++; /* if file is read only
						editable is set to False & vice versa */
	   /* set appropriate colour for the text widget to distinguish between
	      editable and read-only files */
	   if(win->file_read_only) XtSetArg(al[ac], XmNbackground, text_read_only_background);
	   else		      XtSetArg(al[ac], XmNbackground, text_edit_background);
	   ac++;
	   XtSetArg(al[ac], XmNsensitive, True);	ac++;	/* make text sensitive */
	   XtSetValues(win->edit_text1, al, ac);

	   /* hack for Motif 1.2: when the string for the text widget is NULL text modify callback
	      is not generated; in that case we don't set the flag file_just_loaded;
	      if we do we lose the first action during editing !!!!
	   */
	   if(file_string != NULL && strlen(file_string))
					win->file_just_loaded = True;	/* reset the just loaded flag */
	   else				win->file_just_loaded = False;



	   /* we have to use XmTextSetString to set the string; when I use
	      XtSetArg(al[ac], XmNvalue, (char *) file_string); etc... it does not
	      work properly when file_string was empty and the rest was the same
	      probably;  it does not work occasionally during loading of a file (comments
	      from Kennan (i.e. the there is an inconsistent behaviour );
	   ****/
	   XmTextSetString(win->edit_text, (char *)file_string);  /* add the file string to the text widget */


	   /* free the memory associated with the file_string */
	   if(file_string != NULL) XtFree(file_string);

	   /* reinitialize the changes counter, reset undo/redo stacks */
	   win->changes_counter = 0L;
	   reset_undo_redo(win);
	   /* write appropriate info into changes_status widget */
	   if(!win->file_read_only)   write_ls(win->changes_status, charset, "%s", " ");
	   else 		 write_ls(win->changes_status, charset, "%s",
						(char *)lstr.read_only_marker);

	   /* make undo/redo buttons insensitive */
	   XtSetSensitive(win->menu_undo_button,  False);
	   XtSetSensitive(win->menu_redo_button,  False);
	   XFlush(display);		/* make sure that these buttons are
					   insensitive before processing any keyboard
					   actions (for very busy systems)*/



	   /* make appropriate items sensitive */
	   XtSetSensitive(win->menu_copy_button, True);
	   /* set the sensitivity of tools buttons */
	   for (i=0; i < win->nToolsSelNeeded; i++)
		XtSetSensitive(win->toolsSelNeeded[i], True);

	   /* set the sensitivity of buttons dependend only on read_only
	      status of the file (cut button, clear button, replace button)
	   */
	   if(!win->file_read_only)
	   {
		XtSetSensitive(win->menu_cut_button, 	True);
		XtSetSensitive(win->menu_clear_button, 	True);
		XtSetSensitive(win->menu_replace_button, 	True);
		XtSetSensitive(win->menu_insert_button, 	True);
	   }
	   else
	   {
		XtSetSensitive(win->menu_cut_button, 	False);
		XtSetSensitive(win->menu_clear_button, 	False);
		XtSetSensitive(win->menu_replace_button, 	False);
		XtSetSensitive(win->menu_insert_button, 	False);
	   }
	   /* set the sensitivity of the paste buttons */
	   if(!win->file_read_only && clipboard_filled)
	   {
		XtSetSensitive(win->menu_paste_button, True);
		XtSetSensitive(win->popup_paste_button, True);
	   }
	   else
	   {
	   	XtSetSensitive(win->menu_paste_button, False);
	   	XtSetSensitive(win->popup_paste_button, False);
	   }



	   /* set appropriate file buttons to sensitive */
	   XtSetSensitive(win->menu_close_button,	True);
	   XtSetSensitive(win->menu_save_as_button, 	True);
	   XtSetSensitive(win->menu_print_button,	True);
	   /* menu_save_button will be insensitive for read only files .... */
	   if(!win->file_read_only)	
	   {
		XtSetSensitive(win->menu_save_button,  True);
		XtSetSensitive(win->popup_save_button, True);
	   }
	   else		
	   {
		XtSetSensitive(win->menu_save_button,  False);
		XtSetSensitive(win->popup_save_button, False);
	   }


	   /* set appropriate search buttons to sensitive */
	   XtSetSensitive(win->menu_find_button,         True);
	   XtSetSensitive(win->menu_gotoline_button,     True);
	   XtSetSensitive(win->menu_mark_button,         True);
	   XtSetSensitive(win->menu_match_button,        True);

	   XtSetSensitive(win->menu_find_again_button,   True);

	   XtSetSensitive(win->menu_spell_button,        True);
	   XtSetSensitive(win->menu_commands_button,     True);

	   /* setting a new title of the main window and the icon name.
	       They include the name of the file just opened */
	   set_titles_mwindow_icon(win, win->filename, NULL);
	   return(True);
   }
   else
   {
	   /* setting a new title (name of the program only) */
	   set_titles_mwindow_icon(win, NULL, NULL);
	   return(False);
   }

}  /* OpenFile */




/*****************************  SaveFile  ************************************
**  	Save the currently edited file.
*/
#ifdef _NO_PROTO
Boolean SaveFile(win)
aseditWindowStruct *win;
#else  /* ! _NO_PROTO */

Boolean SaveFile(aseditWindowStruct *win)
#endif
{
    char * file_string = NULL;	   /* Contents of file.		      */
    Boolean	    result;


    /* get the text string */
    file_string = XmTextGetString(win->edit_text);


    result = WriteFile(win->filename, file_string);

    if (file_string != NULL)  XtFree(file_string); /* free the text string */

    if(result)
    {
	win->changes_counter = 0L;
	write_ls(win->changes_status, charset, "%s", " ");
	set_titles_mwindow_icon(win, win->filename, NULL);
	return(True);
    }
    else return(False);

}   /* SaveFile */


/*****************************  ResetAllMarks  ***********************************
**
**  	Reset all bookmarks and set the appropriate buttons to insensitive	
*/
#ifdef _NO_PROTO
void ResetAllMarks(win)
aseditWindowStruct *win;
#else  /* ! _NO_PROTO */

void ResetAllMarks(aseditWindowStruct *win)
#endif
{
    int i, nmarks = TOTAL_MARKS;
    /* we should really get the number of marks from the size of the appropriate
       pulldown !! 
    */

    for(i=0; i<nmarks; i++)
    {
	win->marks_used  = False;
	win->mark_set[i] = False;
	win->mark_pos[i] = 0;
	XtSetSensitive(win->menu_mark_go_button[i], False);
    }

}   /*  ResetAllMarks */


/*****************************  CloseFile  ***********************************
**
**  	Close the present file. Set sensitivity of appropriate menu items.
*/
#ifdef _NO_PROTO
void CloseFile(win)
aseditWindowStruct *win;
#else  /* ! _NO_PROTO */

void CloseFile(aseditWindowStruct *win)
#endif
{
    /* zero out the text string in the text widget.
       Warning: it causes a value changed callback. */
    Arg al[5];
    register int ac;
    int i;

    /* check if it is not called for a file already closed  */
    if (win->filename == NULL) return;		/* probable sequence was: File|Close, File|Exit */


    /* we use Motif convenience function  to zero out the text instead of setting the resources in one
       go  i.e. using additionally XtSetArg(al[ac], XmNvalue , "");  ac++; because we have some problems
       with the other method in the ReadFile procedure; so to be on a safe side .... */
    /* to avoid getting the flashing title (Changed) set the following */
    win->file_just_loaded = True;
    XmTextSetString(win->edit_text1, "");  


    ac = 0;
    XtSetArg(al[ac], XmNsensitive, False);	ac++;	/* set text to insensitive */
    /* set the colour of the text background to read only colour */
    XtSetArg(al[ac], XmNbackground, text_read_only_background);	ac++;
    XtSetValues(win->edit_text1, al, ac);


    /* reinitialize the changes counter, reset redo/undo stacks */
    win->changes_counter = 0L;  write_ls(win->changes_status, charset, "%s", " ");
    reset_undo_redo(win);


    /* free the file name */
    if (win->filename != NULL) { XtFree(win->filename);	win->filename = NULL; }

    /* blank the line & column number display  */
    write_ls(win->line_number,   charset, "%s", "     ");
    write_ls(win->column_number, charset, "%s", "    ");

    /* unmanage replace_dialog & save_as_dialog if they are active (they
       may be on the screen and they do not make any sense when no file is open) */
    if(win->replace_dialog != NULL) XtUnmanageChild( win->replace_dialog );
    if(win->save_as_dialog != NULL) XtUnmanageChild( win->save_as_dialog );


    /* set appropriate file buttons to insensitive */
    XtSetSensitive(win->menu_close_button,   False);
    XtSetSensitive(win->menu_save_button,    False);
    XtSetSensitive(win->menu_save_as_button, False);
    XtSetSensitive(win->menu_insert_button,  False);
    XtSetSensitive(win->menu_print_button,   False);

    XtSetSensitive(win->menu_undo_button,  False);
    XtSetSensitive(win->menu_redo_button,  False);
    XtSetSensitive(win->menu_cut_button,   False);
    XtSetSensitive(win->menu_copy_button,  False);
    XtSetSensitive(win->menu_paste_button, False);
    XtSetSensitive(win->menu_clear_button, False);

    XtSetSensitive(win->menu_find_button,         False);
    XtSetSensitive(win->menu_replace_button,      False);
    XtSetSensitive(win->menu_find_again_button,   False);
    XtSetSensitive(win->menu_gotoline_button,     False);
    XtSetSensitive(win->menu_mark_button,     False);
    XtSetSensitive(win->menu_match_button,    False);

    XtSetSensitive(win->popup_undo_button,   False);
    XtSetSensitive(win->popup_cut_button,    False);
    XtSetSensitive(win->popup_copy_button,   False);
    XtSetSensitive(win->popup_paste_button,  False);
    XtSetSensitive(win->popup_save_button,   False);

    /* set the sensitivity of tools buttons */
    for (i=0; i < win->nToolsSelNeeded; i++)
	XtSetSensitive(win->toolsSelNeeded[i], False);

    XtSetSensitive(win->menu_spell_button,    False);
    XtSetSensitive(win->menu_commands_button, False);


    /* setting a new title of the main window (name of the program only) */
    set_titles_mwindow_icon(win, NULL, NULL);

    /* reset all bookmarks */
    ResetAllMarks(win);

}   /* CloseFile */


/*****************************  InsertFile  ************************************
**
**      Inserts the specified file into the current edit_text widget.
**      Calls ReadFile to read the file. Returns true if file
**      exists and insert is sucessful.
*/
#ifdef _NO_PROTO
Boolean InsertFile(win, filename)
   aseditWindowStruct *win;
   char *filename;
#else  /* ! _NO_PROTO */

Boolean InsertFile(aseditWindowStruct *win, char *filename)
#endif
{
   char * file_string=NULL;     /* Contents of file.      */
   Boolean         read_only;           /* shows the file read only status */
   register int ac;                     /* arg count                */
   Arg al[10];                          /* widget arg list          */

   if( (file_string = ReadFile(filename, &read_only)) != NULL)
   {
	return(True);
   }
   else
   {
	   return(False);
   }

}  /* InsertFile */



/*** old: #ifdef M_LANG_STD ***/

/****************************  PrintString  **********************************
        PrintString  - prints a text pointed to by *text_string using *print_command
        (If successful returns True.)
*/
#ifdef _NO_PROTO
Boolean PrintString(text_string, print_command)
    char *text_string;
    char *print_command;
#else  /* _NO_PROTO */

Boolean PrintString(char *text_string, char *print_command)
#endif
{
    FILE *tfp;                          /* Pointer to a temporary file. */
    char work[256];
    Boolean result=True;
    int status;
    char system_call_buf[BUFSIZ];
    char *tempname;     /* Temporary file name .*/

    /* Note: errors here related to file operations shouldn't really happen, so
       just to simplify we leave them in English and write them out on stderr
       (they might happen when the temp dir is full, tmpDir (X) or TEMPDIR is set
        incorrectly etc.)
    */

    if(text_string == NULL || print_command == NULL) return(False);

    tempname = make_tmpnam();   /* use tmpnam function and consider tmpDir X resource
                                   or TMPDIR environmental variable (if set) */

    if ((tfp = fopen(tempname, "w")) == NULL) {
       fprintf(stderr, (char *)lstr.open_tmp_print_err, tempname);
       XtFree(tempname);
       return(False);
    }
    /* write to a temp file */
    fwrite(text_string, sizeof(char), strlen(text_string) , tfp);

    /* flush and close the file (note that if we are unlucky we use in both
       cases the same error message saying we are unable to close the file;
       the flush error is very unlikely here) */

    if (fflush(tfp))
        { result=False;  fprintf(stderr,(char *)lstr.close_tmp_err,tempname); }

    if (fclose(tfp))
        { result=False;  fprintf(stderr,(char *)lstr.close_tmp_err,tempname); }


    if(!result) { unlink(tempname); XtFree(tempname); return(result); }


#ifndef vax11c
    sprintf(work, "cat %s | %s", tempname, print_command);
#else
    /* VMS doesn't allow for I/O redirection at all (It's one major handicap).
       So let's setup the print command to just print the file.
    */
    sprintf(work, "%s %s", print_command, tempname);
#endif /* !vax11c */

#if defined(vax11c) || defined(__DECC)
    if (!(system(work)&1))  result=False;
#else
    if (system(work))  result=False;
#endif /* vax11c */

    unlink (tempname);
    XtFree (tempname);

    return(result);

}   /* PrintString */


