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