Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtpad / fileIo.c
1 /* $XConsortium: fileIo.c /main/4 1996/10/04 17:24:28 drk $ */
2 /**********************************<+>*************************************
3 ***************************************************************************
4 **
5 **  File:        fileIo.c
6 **
7 **  Project:     DT dtpad, a memo maker type editor based on the Dt Editor
8 **               widget.
9 **
10 **  Description:
11 **  -----------
12 **
13 *******************************************************************
14 **  (c) Copyright Hewlett-Packard Company, 1991, 1992.  All rights are
15 **  reserved.  Copying or other reproduction of this program
16 **  except for archival purposes is prohibited without prior
17 **  written consent of Hewlett-Packard Company.
18 ********************************************************************
19 **
20 ********************************************************************
21 **  (c) Copyright 1993, 1994 Hewlett-Packard Company
22 **  (c) Copyright 1993, 1994 International Business Machines Corp.
23 **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
24 **  (c) Copyright 1993, 1994 Novell, Inc.
25 ********************************************************************
26 **
27 **  ToDo:       roll in fixes for 10.0 ivepad
28 **
29 **
30 **************************************************************************
31 **********************************<+>*************************************/
32 #include "dtpad.h"
33 #include <Xm/TextP.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <Xm/TextF.h>
37 #include <Xm/LabelG.h>
38
39
40 /************************************************************************
41  * LoadFile - Opens the specified file and loads its contents to the
42  *      DtEditor widget.
43  *
44  *      The filename is specified either by pPad->fileStuff.fileName or
45  *      the 'include' argument.  If the filename is specified via include,
46  *      the file is inserted at the current cursor location.  In both
47  *      instances, the filename is assumed to be relative to the local host
48  *      where dtpad is running.
49  *      
50  ************************************************************************/
51 /* [SuG 5/18/95] Done
52    The NOT_SAMPLE warnings/errors need to be added to the message
53    catalog. Removed ifdefs.*/
54
55 void 
56 LoadFile(
57         Editor *pPad,
58         char *include)
59 {
60     char *              localName;
61     DtEditorErrorCode   errorCode;
62     DtEditorContentRec  contentRec;
63     Boolean             fileLoaded = False;
64     Boolean             fileLoadError = False;
65
66
67     if (include != (char *)NULL) {
68         localName = include; 
69     } else { 
70         localName = pPad->fileStuff.fileName; 
71         pPad->fileStuff.readOnly = False;
72     } 
73
74     if (localName && *localName) {
75         /* try to load the file to the Dt Editor widget */ 
76         _DtTurnOnHourGlass(pPad->app_shell);
77         XSync(XtDisplay(pPad->editor), False);
78         if (include != (char *) NULL) {
79             errorCode = DtEditorInsertFromFile(
80                                 pPad->editor,
81                                 localName);
82         } else {
83             pPad->fileStuff.fileExists = True;
84             errorCode = DtEditorSetContentsFromFile(
85                                 pPad->editor,
86                                 localName);
87         }
88         _DtTurnOffHourGlass(pPad->app_shell);
89         switch (errorCode) {
90             case DtEDITOR_NO_ERRORS:    /* file is read/writeable */
91                 fileLoaded = True;
92                 break;
93             case DtEDITOR_READ_ONLY_FILE:
94                 fileLoaded = True;
95                 if (include == (char *) NULL) {
96                     pPad->fileStuff.readOnly = True;
97                     if (pPad->xrdb.readOnlyWarning &&
98                       ! pPad->xrdb.statusLine &&
99                       ! pPad->xrdb.viewOnly) { 
100                         Warning(pPad, (char *) GETMESSAGE(6, 1,
101                           "This file has been opened for reading only."),
102                           XmDIALOG_WARNING);
103                     }
104                 }
105                 break;
106             case DtEDITOR_NONEXISTENT_FILE:
107                 if (include != (char *) NULL ) {
108                     Warning(pPad, (char *) GETMESSAGE(6, 2,
109                             "This file does not exist."),
110                         XmDIALOG_ERROR);
111                     fileLoadError = True;
112                 } else if (pPad->xrdb.viewOnly) {
113                     Warning(pPad, (char *) GETMESSAGE(6, 2,
114                             "This file does not exist."),
115                         XmDIALOG_ERROR);
116                 } else if (pPad->xrdb.missingFileWarning) {
117                     Warning(pPad, (char *) GETMESSAGE(6, 2,
118                             "This file does not exist."),
119                         XmDIALOG_WARNING);
120                 }
121                 break;
122             case DtEDITOR_DIRECTORY:
123                 Warning(pPad, (char *) GETMESSAGE(6, 3,
124                             "Unable to edit a Directory."),
125                         XmDIALOG_ERROR);
126                 fileLoadError = True;
127                 break;
128             case DtEDITOR_CHAR_SPECIAL_FILE:
129                 Warning(pPad, (char *) GETMESSAGE(6, 4,
130                             "Unable to edit a character special device file."),
131                         XmDIALOG_ERROR);
132                 fileLoadError = True;
133                 break;
134             case DtEDITOR_BLOCK_MODE_FILE:
135                 Warning(pPad, (char *) GETMESSAGE(6, 5,
136                             "Unable to edit a block mode device file."),
137                         XmDIALOG_ERROR);
138                 fileLoadError = True;
139                 break;
140             case DtEDITOR_NULLS_REMOVED:
141                 Warning(pPad, (char *) GETMESSAGE(6, 6,
142                             "Embedded Nulls stripped from file."),
143                         XmDIALOG_WARNING);
144                 fileLoaded = True;
145                 break;
146             case DtEDITOR_INSUFFICIENT_MEMORY:
147                 Warning(pPad, (char*) GETMESSAGE(6, 7,
148                             "Unable to load file (insufficient memory)."),
149                         XmDIALOG_ERROR);
150                 fileLoadError = True;
151                 break;
152             case DtEDITOR_NO_FILE_ACCESS:
153                 Warning(pPad,  (char *) GETMESSAGE(6, 8,
154                             "Unable to access file (can't determine its status)."),
155                         XmDIALOG_ERROR);
156                 fileLoadError = True;
157                 break;
158             case DtEDITOR_UNREADABLE_FILE:
159                 Warning(pPad, (char *) GETMESSAGE(6, 9,
160                             "Unable to read from the file (probably no read permission)."),
161                         XmDIALOG_ERROR);
162                 fileLoadError = True;
163                 break;
164             default:
165                 Warning(pPad, (char *) GETMESSAGE(6, 12,
166                             "Unable to read from the file (unknown reason)."),
167                         XmDIALOG_ERROR);
168                 fileLoadError = True;
169                 break;
170         } /* switch (errorCode) */
171     } /* file name specified */
172     
173     if (include != (char *)NULL)
174         return; 
175
176     /*
177      * We only get this far if the current file was to be changed
178      * (i.e. the file was not included)
179      */ 
180     SetStatusLineMsg(pPad);     /* set readOnly/viewOnly in status line msg */
181  
182     if (fileLoaded) {
183         pPad->fileStuff.fileExists = True;
184     } else {
185         pPad->fileStuff.fileExists = False;
186
187         /* null out Editor widget */
188         contentRec.type = DtEDITOR_TEXT;
189         contentRec.value.string = "";
190         errorCode = DtEditorSetContents(pPad->editor, &contentRec);
191         if (errorCode != DtEDITOR_NO_ERRORS)
192             Warning(pPad,"Internal Error: Unable to NULL Editor Widget.",XmDIALOG_ERROR);
193
194         /* clear stale file stuff */
195         if (fileLoadError) {
196             if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName)
197                 XtFree(pPad->fileStuff.fileName);
198             pPad->fileStuff.fileName = NULL;
199             ChangeMainWindowTitle(pPad);
200             return;
201         }
202
203         /* set the pathDir and fileName */
204         if (pPad->fileStuff.fileName && *pPad->fileStuff.fileName) {
205             char *lastSlash;
206
207             strcpy(pPad->fileStuff.pathDir, pPad->fileStuff.fileName);
208             if ((lastSlash = MbStrrchr(pPad->fileStuff.pathDir, '/')) != 
209                                                              (char *)NULL) {
210                *(lastSlash + 1) = (char)'\0';
211             }
212
213             lastSlash = MbStrrchr(pPad->fileStuff.fileName, '/');
214             if (lastSlash != (char *)NULL) {
215                 lastSlash++;
216             } else {
217                 lastSlash = pPad->fileStuff.fileName;
218             }
219             if (*lastSlash == (char)'-' || *lastSlash == (char)'*') {
220                 XtFree(pPad->fileStuff.fileName);
221                 pPad->fileStuff.fileName = (char *)NULL;
222             }
223         }
224     } /* ! fileLoaded */
225 }
226
227
228 /************************************************************************
229  * GetTempFile - generates a file name for a temporary file that can be
230  *      used for writing.
231  ************************************************************************/
232 char *
233 GetTempFile(void)
234 {
235     char *tempname = (char *)XtMalloc(L_tmpnam); /* Temporary file name. */
236     FILE *tfp;
237
238     (void)tmpnam(tempname);
239     if ((tfp = fopen(tempname, "w")) == NULL)
240     {
241         pid_t pid;
242         /*
243          * If tmpnam fails, then try to create our own temp name.
244          * Try a couple of different names if necessary.
245          */
246         XtFree(tempname);
247         tempname = XtMalloc(256);
248         pid = getpid();
249         sprintf(tempname, "/usr/tmp/editor%ld", (long)pid);
250         if ((tfp = fopen(tempname, "w")) == NULL)
251         {
252             sprintf(tempname, "/tmp/editor%ld", (long)pid);
253             if ((tfp = fopen(tempname, "w")) == NULL)
254             {
255                 XtFree(tempname);
256                 return (char *)NULL;
257             }
258         }
259     }
260     fclose(tfp);
261     return tempname;
262 }
263
264
265 extern Editor *pPadList;    /* declared/set in main.c */
266
267
268 /************************************************************************
269  * AddPound - add a "#" character to the beginning of the base name of
270  *      the file name passed in the nameBuf parameter.  A pointer to the
271  *      new name is returned.  The name is constructed in a static buffer.
272  *      If nameBuf is empty, it returns the file name "#UNTITLED#".
273  ************************************************************************/
274 static char * 
275 AddPound(
276         char *nameBuf)
277 {
278     char tempBuf[512];
279     static char returnBuf[512];
280
281     if (nameBuf != (char *)NULL && nameBuf[0] != (char) '\0') {
282         char *baseName;
283         strcpy(tempBuf, nameBuf);
284         baseName = MbStrrchr(tempBuf, '/');
285         if (baseName != (char *)NULL) {
286                 strncpy(returnBuf, tempBuf, (baseName - tempBuf) + 1);
287                 returnBuf[(baseName - tempBuf) + 1] = (char)'\0';
288                 baseName++;
289                 strcat(returnBuf, "#");
290                 strcat(returnBuf, baseName);
291                 if (returnBuf[strlen(returnBuf) - 1] != (char)'#')
292                     strcat(returnBuf, "#");
293         } else {
294             sprintf(returnBuf, "#%s", tempBuf);
295             if(returnBuf[strlen(returnBuf) - 1] != (char)'#')
296                 strcat(returnBuf, "#");
297         }
298     } else {
299         sprintf(returnBuf, "#%s#", GETMESSAGE(5, 21, "UNTITLED"));
300     }
301     return returnBuf;
302 }
303
304
305 /************************************************************************
306  * PanicSave - immediately saves the text for each edit session handled
307  *      by the text editor to #[#]<filename>.
308  ************************************************************************/
309 void 
310 PanicSave(void)
311 {
312     Editor *pPad;
313     struct stat statbuf;        /* Information on a file. */
314     Boolean addNewLines;
315     DtEditorErrorCode errorCode;
316
317     for (pPad = pPadList; pPad != (Editor *)NULL; pPad = pPad->pNextPad) {
318         char *fileName = pPad->fileStuff.fileName;
319         if (pPad->inUse != True || pPad->editor == NULL || 
320                 (! DtEditorCheckForUnsavedChanges(pPad->editor)))
321             continue;
322         /* -----> Try to cook up a name for a file that doesn't already exist */
323         fileName = AddPound(pPad->fileStuff.fileName);
324         if (stat(fileName, &statbuf) == 0) {
325             fileName = AddPound(fileName);
326             if (stat(fileName, &statbuf) == 0) {
327                 fileName = AddPound(fileName);
328                 if (stat(fileName, &statbuf) == 0) {
329                     /* Give up. We've tried enough names.  The user loses. */
330                     continue;
331                 }
332             }
333         }
334         addNewLines = pPad->xrdb.wordWrap == True &&
335                           pPad->fileStuff.saveWithNewlines == True;
336         errorCode = DtEditorSaveContentsToFile(
337                         pPad->editor,
338                         fileName,
339                         False,          /* don't overwrite existing file */
340                         addNewLines,    /* replace soft line feeds? */
341                         False);         /* don't mark contents as saved */
342
343         /* don't really care about errorCode since we're in a hurry and
344          * can't do anything about it anyway */
345     }
346     exit(1);
347 }
348
349
350 /************************************************************************
351  * SetStatusLineMsg - sets the message (XmTextField) portion of the
352  *      DtEditor widget's status line based on whether the pad is in
353  *      viewOnly mode or the file being edited/displayed is readOnly.
354  ************************************************************************/
355 /* ARGSUSED */
356 void
357 SetStatusLineMsg(
358         Editor *pPad)
359 {
360     char *message="";
361
362     if (pPad->xrdb.viewOnly) {
363         message = (char *) GETMESSAGE(6, 10, "View Only");
364     } else if (pPad->fileStuff.readOnly) {
365         message = (char *) GETMESSAGE(6, 11, "Read Only");
366     }
367     
368     XmTextFieldSetString(pPad->statusLineMsg, message);
369 }