/*
 * CDE - Common Desktop Environment
 *
 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these libraries and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
 */
/* $XConsortium: fileIo.c /main/4 1996/10/04 17:24:28 drk $ */
/**********************************<+>*************************************
***************************************************************************
**
**  File:        fileIo.c
**
**  Project:     DT dtpad, a memo maker type editor based on the Dt Editor
**               widget.
**
**  Description:
**  -----------
**
*******************************************************************
**  (c) Copyright Hewlett-Packard Company, 1991, 1992.  All rights are
**  reserved.  Copying or other reproduction of this program
**  except for archival purposes is prohibited without prior
**  written consent of Hewlett-Packard Company.
********************************************************************
**
********************************************************************
**  (c) Copyright 1993, 1994 Hewlett-Packard Company
**  (c) Copyright 1993, 1994 International Business Machines Corp.
**  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
**  (c) Copyright 1993, 1994 Novell, Inc.
********************************************************************
**
**  ToDo:	roll in fixes for 10.0 ivepad
**
**
**************************************************************************
**********************************<+>*************************************/
#include "dtpad.h"
#include <Xm/TextP.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <Xm/TextF.h>
#include <Xm/LabelG.h>
#include <Dt/HourGlass.h>


/************************************************************************
 * LoadFile - Opens the specified file and loads its contents to the
 *	DtEditor widget.
 *
 *	The filename is specified either by pPad->fileStuff.fileName or
 *	the 'include' argument.  If the filename is specified via include,
 *	the file is inserted at the current cursor location.  In both
 *	instances, the filename is assumed to be relative to the local host
 *	where dtpad is running.
 *	
 ************************************************************************/
/* [SuG 5/18/95] Done
   The NOT_SAMPLE warnings/errors need to be added to the message
   catalog. Removed ifdefs.*/

void 
LoadFile(
	Editor *pPad,
        char *include)
{
    char *		localName;
    DtEditorErrorCode	errorCode;
    DtEditorContentRec	contentRec;
    Boolean		fileLoaded = False;
    Boolean		fileLoadError = False;


    if (include != (char *)NULL) {
	localName = include; 
    } else { 
        localName = pPad->fileStuff.fileName; 
	pPad->fileStuff.readOnly = False;
    } 

    if (localName && *localName) {
	/* try to load the file to the Dt Editor widget */ 
        _DtTurnOnHourGlass(pPad->app_shell);
        XSync(XtDisplay(pPad->editor), False);
	if (include != (char *) NULL) {
	    errorCode = DtEditorInsertFromFile(
				pPad->editor,
				localName);
	} else {
	    pPad->fileStuff.fileExists = True;
	    errorCode = DtEditorSetContentsFromFile(
				pPad->editor,
				localName);
	}
        _DtTurnOffHourGlass(pPad->app_shell);
	switch (errorCode) {
	    case DtEDITOR_NO_ERRORS:	/* file is read/writeable */
		fileLoaded = True;
		break;
	    case DtEDITOR_READ_ONLY_FILE:
		fileLoaded = True;
		if (include == (char *) NULL) {
		    pPad->fileStuff.readOnly = True;
		    if (pPad->xrdb.readOnlyWarning &&
		      ! pPad->xrdb.statusLine &&
		      ! pPad->xrdb.viewOnly) { 
			Warning(pPad, (char *) GETMESSAGE(6, 1,
			  "This file has been opened for reading only."),
			  XmDIALOG_WARNING);
		    }
		}
		break;
	    case DtEDITOR_NONEXISTENT_FILE:
		if (include != (char *) NULL ) {
		    Warning(pPad, (char *) GETMESSAGE(6, 2,
			    "This file does not exist."),
			XmDIALOG_ERROR);
		    fileLoadError = True;
		} else if (pPad->xrdb.viewOnly) {
		    Warning(pPad, (char *) GETMESSAGE(6, 2,
			    "This file does not exist."),
			XmDIALOG_ERROR);
		} else if (pPad->xrdb.missingFileWarning) {
		    Warning(pPad, (char *) GETMESSAGE(6, 2,
			    "This file does not exist."),
			XmDIALOG_WARNING);
		}
		break;
	    case DtEDITOR_DIRECTORY:
		Warning(pPad, (char *) GETMESSAGE(6, 3,
			    "Unable to edit a Directory."),
			XmDIALOG_ERROR);
		fileLoadError = True;
		break;
	    case DtEDITOR_CHAR_SPECIAL_FILE:
		Warning(pPad, (char *) GETMESSAGE(6, 4,
			    "Unable to edit a character special device file."),
			XmDIALOG_ERROR);
		fileLoadError = True;
		break;
	    case DtEDITOR_BLOCK_MODE_FILE:
		Warning(pPad, (char *) GETMESSAGE(6, 5,
			    "Unable to edit a block mode device file."),
			XmDIALOG_ERROR);
		fileLoadError = True;
		break;
	    case DtEDITOR_NULLS_REMOVED:
		Warning(pPad, (char *) GETMESSAGE(6, 6,
			    "Embedded Nulls stripped from file."),
			XmDIALOG_WARNING);
		fileLoaded = True;
		break;
	    case DtEDITOR_INSUFFICIENT_MEMORY:
		Warning(pPad, (char*) GETMESSAGE(6, 7,
			    "Unable to load file (insufficient memory)."),
			XmDIALOG_ERROR);
		fileLoadError = True;
		break;
	    case DtEDITOR_NO_FILE_ACCESS:
		Warning(pPad,  (char *) GETMESSAGE(6, 8,
			    "Unable to access file (can't determine its status)."),
			XmDIALOG_ERROR);
		fileLoadError = True;
		break;
	    case DtEDITOR_UNREADABLE_FILE:
		Warning(pPad, (char *) GETMESSAGE(6, 9,
			    "Unable to read from the file (probably no read permission)."),
			XmDIALOG_ERROR);
		fileLoadError = True;
		break;
	    default:
		Warning(pPad, (char *) GETMESSAGE(6, 12,
			    "Unable to read from the file (unknown reason)."),
			XmDIALOG_ERROR);
		fileLoadError = True;
		break;
	} /* switch (errorCode) */
    } /* file name specified */
    
    if (include != (char *)NULL)
	return; 

    /*
     * We only get this far if the current file was to be changed
     * (i.e. the file was not included)
     */ 
    SetStatusLineMsg(pPad);	/* set readOnly/viewOnly in status line msg */
 
    if (fileLoaded) {
	pPad->fileStuff.fileExists = True;
    } else {
	pPad->fileStuff.fileExists = False;

	/* null out Editor widget */
	contentRec.type = DtEDITOR_TEXT;
	contentRec.value.string = "";
	errorCode = DtEditorSetContents(pPad->editor, &contentRec);
	if (errorCode != DtEDITOR_NO_ERRORS)
	    Warning(pPad,"Internal Error: Unable to NULL Editor Widget.",XmDIALOG_ERROR);

	/* clear stale file stuff */
	if (fileLoadError) {
	    if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName)
		XtFree(pPad->fileStuff.fileName);
	    pPad->fileStuff.fileName = NULL;
	    ChangeMainWindowTitle(pPad);
	    return;
	}

	/* set the pathDir and fileName */
	if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName) {
	    char *lastSlash;

	    strcpy(pPad->fileStuff.pathDir, pPad->fileStuff.fileName);
	    if ((lastSlash = MbStrrchr(pPad->fileStuff.pathDir, '/')) != 
		                                             (char *)NULL) {
	       *(lastSlash + 1) = (char)'\0';
	    }

	    lastSlash = MbStrrchr(pPad->fileStuff.fileName, '/');
	    if (lastSlash != (char *)NULL) {
	        lastSlash++;
	    } else {
	        lastSlash = pPad->fileStuff.fileName;
	    }
	    if (*lastSlash == (char)'-' || *lastSlash == (char)'*') {
	        XtFree(pPad->fileStuff.fileName);
	        pPad->fileStuff.fileName = (char *)NULL;
	    }
	}
    } /* ! fileLoaded */
}


/************************************************************************
 * GetTempFile - generates a file name for a temporary file that can be
 *	used for writing.
 ************************************************************************/
char *
GetTempFile(void)
{
    char *tempname = (char *)XtMalloc(L_tmpnam); /* Temporary file name. */
    FILE *tfp;

    (void)tmpnam(tempname);
    if ((tfp = fopen(tempname, "w")) == NULL)
    {
        pid_t pid;
        /*
         * If tmpnam fails, then try to create our own temp name.
         * Try a couple of different names if necessary.
         */
        XtFree(tempname);
        tempname = XtMalloc(256);
        pid = getpid();
        sprintf(tempname, "/usr/tmp/editor%ld", (long)pid);
        if ((tfp = fopen(tempname, "w")) == NULL)
        {
            sprintf(tempname, "/tmp/editor%ld", (long)pid);
            if ((tfp = fopen(tempname, "w")) == NULL)
            {
                XtFree(tempname);
                return (char *)NULL;
            }
        }
    }
    fclose(tfp);
    return tempname;
}


extern Editor *pPadList;    /* declared/set in main.c */


/************************************************************************
 * AddPound - add a "#" character to the beginning of the base name of
 *	the file name passed in the nameBuf parameter.	A pointer to the
 *	new name is returned.  The name is constructed in a static buffer.
 *	If nameBuf is empty, it returns the file name "#UNTITLED#".
 ************************************************************************/
static char * 
AddPound(
        char *nameBuf)
{
    char tempBuf[512];
    static char returnBuf[512];

    if (nameBuf != (char *)NULL && nameBuf[0] != (char) '\0') {
        char *baseName;
	strcpy(tempBuf, nameBuf);
        baseName = MbStrrchr(tempBuf, '/');
	if (baseName != (char *)NULL) {
		strncpy(returnBuf, tempBuf, (baseName - tempBuf) + 1);
		returnBuf[(baseName - tempBuf) + 1] = (char)'\0';
		baseName++;
		strcat(returnBuf, "#");
		strcat(returnBuf, baseName);
	        if (returnBuf[strlen(returnBuf) - 1] != (char)'#')
		    strcat(returnBuf, "#");
	} else {
	    snprintf(returnBuf, sizeof(returnBuf), "#%s", tempBuf);
	    if(strlen(returnBuf) && returnBuf[strlen(returnBuf) - 1] != (char)'#')
		strcat(returnBuf, "#");
	}
    } else {
	sprintf(returnBuf, "#%s#", GETMESSAGE(5, 21, "UNTITLED"));
    }
    return returnBuf;
}


/************************************************************************
 * PanicSave - immediately saves the text for each edit session handled
 *	by the text editor to #[#]<filename>.
 ************************************************************************/
void 
PanicSave(void)
{
    Editor *pPad;
    struct stat statbuf;        /* Information on a file. */
    Boolean addNewLines;
    DtEditorErrorCode errorCode;

    for (pPad = pPadList; pPad != (Editor *)NULL; pPad = pPad->pNextPad) {
	char *fileName = pPad->fileStuff.fileName;
	if (pPad->inUse != True || pPad->editor == NULL || 
		(! DtEditorCheckForUnsavedChanges(pPad->editor)))
	    continue;
	/* -----> Try to cook up a name for a file that doesn't already exist */
	fileName = AddPound(pPad->fileStuff.fileName);
	if (stat(fileName, &statbuf) == 0) {
	    fileName = AddPound(fileName);
	    if (stat(fileName, &statbuf) == 0) {
	        fileName = AddPound(fileName);
	        if (stat(fileName, &statbuf) == 0) {
		    /* Give up. We've tried enough names.  The user loses. */
	            continue;
		}
	    }
	}
	addNewLines = pPad->xrdb.wordWrap == True &&
			  pPad->fileStuff.saveWithNewlines == True;
	errorCode = DtEditorSaveContentsToFile(
			pPad->editor,
			fileName,
			False,		/* don't overwrite existing file */
			addNewLines,	/* replace soft line feeds? */
			False);		/* don't mark contents as saved */

	/* don't really care about errorCode since we're in a hurry and
	 * can't do anything about it anyway */
    }
    exit(1);
}


/************************************************************************
 * SetStatusLineMsg - sets the message (XmTextField) portion of the
 *	DtEditor widget's status line based on whether the pad is in
 *	viewOnly mode or the file being edited/displayed is readOnly.
 ************************************************************************/
/* ARGSUSED */
void
SetStatusLineMsg(
	Editor *pPad)
{
    char *message="";

    if (pPad->xrdb.viewOnly) {
	message = (char *) GETMESSAGE(6, 10, "View Only");
    } else if (pPad->fileStuff.readOnly) {
	message = (char *) GETMESSAGE(6, 11, "Read Only");
    }
    
    XmTextFieldSetString(pPad->statusLineMsg, message);
}
