libDtHelp: Fix another regression caused by Coverity fix, clicking 'Help Manager...
[oweals/cde.git] / cde / programs / dtfile / Common.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 libraries 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 /* $TOG: Common.c /main/5 1998/05/07 13:27:44 rafi $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  *
27  *   FILE:           Common.c
28  *
29  *   COMPONENT_NAME: Desktop File Manager (dtfile)
30  *
31  *   DESCRIPTION:    Source file for some shared dialog code
32  *
33  *   FUNCTIONS: AddString
34  *              CancelOut
35  *              CvtStringListToString
36  *              CvtStringToStringList
37  *              VFTextChangeSpace
38  *
39  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
40  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
41  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
42  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
43  *
44  ****************************************************************************
45  ************************************<+>*************************************/
46
47 #include <stdio.h>
48 #include <time.h>
49 #include <limits.h>
50
51
52 #include <Xm/Xm.h>
53 #include <Xm/XmP.h>
54 #include <Xm/TextF.h>
55
56 #include <Dt/DtP.h>                     /* required for DtDirPaths type */
57
58 #include <codelibs/shellutils.h>
59
60 #include <Dt/DtNlUtils.h>
61 #include "Encaps.h"
62 #include "SharedProcs.h"
63
64 #include "FileMgr.h"
65 #include "Desktop.h"
66 #include "Main.h"
67 #include "Prefs.h"
68 #include "Common.h"
69
70
71 #define PADDING 10
72 static char * DELETE_SEPARATOR = "\n       ";
73
74
75 /************************************************************************
76  *
77  *  CvtStringToStringList()
78  *      Convert a resource string of format:
79  *
80  *           <item>, <item>, <item>, ...
81  *
82  *      into an array of strings.
83  *
84  ************************************************************************/ 
85
86 void
87 CvtStringToStringList(
88         String string,
89         String **listPtr,
90         int *countPtr )
91 {
92    int num_items = 0;
93    String * items = NULL;
94    int size_item_array = 0;
95    String ptr = (String)_DtStripSpaces(string);
96    String end;
97
98    while ((ptr != NULL) && (*ptr != '\0'))
99    {
100       if (num_items >= size_item_array)
101       {
102          size_item_array += 20;
103          items = (String *) 
104             XtRealloc((char *) items, sizeof(String) * size_item_array);
105       }
106
107       end = DtStrchr(ptr, ',');
108       if (end)
109          *end = '\0';
110
111       items[num_items] = strcpy(XtMalloc(strlen(ptr)+1), ptr);
112       num_items++;
113       if (end != NULL)
114          ptr = (String)_DtStripSpaces(end + 1);
115       else
116          break;
117    }
118
119    *countPtr = num_items;
120    *listPtr= items;
121 }
122
123
124 /************************************************************************
125  *
126  *  CvtStringListToString
127  *     Convert an array of strings into a single string, which can
128  *     then be written out to a resource file.
129  *
130  ************************************************************************/
131
132 String
133 CvtStringListToString(
134         String *list,
135         int count )
136 {
137    int i, offset;
138    int stringSize = 0;
139    String string = NULL;
140
141
142    /* 
143     * Function for writing an array of string values.
144     * Write all of the information out as a single string, which
145     * we'll parse when we read it back in at a later point in time.
146     * The format for this string is:
147     *
148     *    <item>, <item>, <item>, ...
149     */
150
151    if (count > 0)
152    {
153       for (i = 0, offset = 0; i < count; i++)
154       {
155          if ((offset + strlen(list[i]) + 3) >= stringSize)
156          {
157             /* Grow the buffer */
158             if ((strlen(list[i]) + 3) > 1024)
159                stringSize += strlen(list[i]) + 1024;
160             else
161                stringSize += 1024;
162             string = XtRealloc((char *) string, stringSize);
163          }
164          
165          if (i == 0)
166             (void) sprintf (string + offset, "%s", list[i]);
167          else
168             (void) sprintf (string + offset, ", %s", list[i]);
169          offset = strlen(string);
170       }
171    }
172
173    return(string);
174 }
175
176
177 /************************************************************************
178  *
179  * XtActionProc - VFTextChangeSpace() - this is the callback which gets
180  *        called when a user type 'Space' in a text widget which has
181  *        this translation tied to it.
182  *
183  ***********************************************************************/
184 void
185 VFTextChangeSpace(
186         Widget text,
187         XEvent *event,
188         XtPointer params,
189         XtPointer num_params)
190 {
191    char *value;
192    char *currentDirectoryText;
193    char path[MAX_PATH];
194    char *test;
195    char **temp;
196    int length, shortest, val = 0;
197    int i,j;
198    Boolean match;
199
200    /* get the current text from the widget */
201    value = (char *)XmTextFieldGetString(text);
202    currentDirectoryText = GetRestrictedDirectory(text);
203
204    /* Extract the path */
205    path[0] = '\0';
206
207    if(currentDirectoryText == NULL)
208    {
209       strcpy (path, value);
210    }
211    else
212    {
213       if (strcmp(currentDirectoryText, "/") == 0)
214          sprintf(path, "%s%s", currentDirectoryText, value);
215       else
216          sprintf(path, "%s/%s", currentDirectoryText, value);
217    }
218   
219    /* add a '*' at the end of the path so the shellscan will no to return
220     * all possible matches.
221     */
222    test = (char *)XtMalloc(strlen(path) + strlen("*") + 1);
223    sprintf(test, "%s%s", path, "*");
224
225    /* do a shellscan to get all possible matches to the path */
226    temp = (char **)shellscan(test, &val, 0);
227    if(val == 1 && strcmp(*temp, test) != 0)
228    {
229       /* there was one and only one match */
230       if(currentDirectoryText == NULL)
231          XmTextFieldSetString(text, *temp);
232       else
233          XmTextFieldSetString(text, *temp + strlen(currentDirectoryText));
234       XmTextFieldSetInsertionPosition(text, XmTextFieldGetLastPosition(text));
235    }
236    else if (val > 1)
237    {
238       /* more than one filename matches the path */
239       length = strlen(path);
240
241       /* first find the shortest of the matches */
242       shortest = strlen(temp[0]);
243       for(i = 1; i < val; i++)
244       {
245          j = strlen(temp[i]);
246          if(j < shortest)
247             shortest = j;
248       }
249             
250       /* find the most characters which will match in all patterns found.
251        * i.e. if I have /use, /user, /users, and /used, the most chars
252        * which match are /use
253        */
254       match = True;
255       for(i=0; i < shortest; i++)
256       {
257          for(j=0; j < val - 1; j++)
258          {
259             if(temp[j][length + i] != temp[j + 1][length + i])
260             {
261                match = False;
262                break;
263             }
264          }
265          if(match == False)
266             break;
267       }
268       temp[0][length + i] = '\0';
269
270       if(currentDirectoryText == NULL)
271          XmTextFieldSetString(text, *temp);
272       else
273          XmTextFieldSetString(text, *temp + strlen(currentDirectoryText));
274    
275       XmTextFieldSetInsertionPosition(text, XmTextFieldGetLastPosition(text));
276  
277       /* ring the bell so the users knows the filename is not complete */
278       XBell(XtDisplay(text), 100);
279    }
280    else
281       /* no matches found */
282       XBell(XtDisplay(text), 100);
283       
284    XtFree(test);
285 }
286
287 /************************************************************************
288  *
289  * XtActionProc - CancelOut() - this is the callback which gets
290  *        called when a user type 'Space' in a text widget which has
291  *        this translation tied to it.
292  *
293  ***********************************************************************/
294 void
295 CancelOut(
296         Widget widget,
297         XEvent *event,
298         XtPointer params,
299         XtPointer num_params)
300 {
301    FileMgrData *file_mgr_data;
302    FileMgrRec *file_mgr_rec;
303    Arg args[2];
304  
305    if(strcmp(widget->core.name, "nameChangeT") == 0)
306    {
307       FileViewData *fileViewData;
308
309       file_mgr_data = ReturnDesktopPtr(XtParent(widget));
310       XtUnmanageChild(widget);
311       XtDestroyWidget(widget);
312       file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
313       file_mgr_rec->menuStates |= RENAME;
314       if(file_mgr_data->selected_file_count == 1)
315       {
316          fileViewData = file_mgr_data->selection_list[0];
317          XmProcessTraversal(fileViewData->widget, XmTRAVERSE_CURRENT);
318       }
319    }
320    else if(strcmp(widget->core.name, "nameChangeT_DT") == 0)
321    {
322       UnpostDTTextField ();
323    }
324    else if(strcmp(widget->core.name, FAST_RENAME) == 0)
325    {
326       file_mgr_data =
327              ReturnDesktopPtr(XtParent(XtParent(XtParent(XtParent(widget)))));
328       file_mgr_rec = (FileMgrRec *)file_mgr_data->file_mgr_rec;
329
330       XmProcessTraversal(file_mgr_rec->file_window, XmTRAVERSE_CURRENT);
331       XtSetArg (args[0], XmNallowShellResize, False);
332       XtSetValues(file_mgr_rec->shell, args, 1);
333       XtUnmanageChild(file_mgr_rec->current_directory_text);
334       XtSetArg (args[0], XmNallowShellResize, True);
335       XtSetValues(file_mgr_rec->shell, args, 1);
336       file_mgr_data->fast_cd_enabled = False;
337    }
338 }
339
340
341 /*
342  * This is a convenience function used to build an error string, which
343  * is then passed to an error dialog creation function.  It will add
344  * the header string to the beginning, the first time this is called
345  * for a particular error string; i.e. when buf == NULL.  The string
346  * it creates is owned by the caller, and should be freed up when no
347  * longer needed.
348  */
349
350 void
351 AddString(
352         String *buf,
353         int *size,
354         String string,
355         String header )
356 {
357    int delta;
358    int buflen = 0;
359    Boolean addHeader = False;
360
361    delta = strlen(DELETE_SEPARATOR) + strlen(string) + 1;
362    if (*buf != NULL)
363       buflen = strlen(*buf);
364    if ((buflen + delta) >= *size)
365    {
366       if ((*buf == NULL) && header)
367          addHeader = True;
368       *size += delta + 512;
369       if (*buf == NULL)
370       {
371         *buf = XtMalloc(*size);
372         (*buf)[0]='\0';
373       }
374       else
375         *buf = XtRealloc(*buf, *size);
376
377       if (addHeader)
378          (void) strcpy(*buf, header);
379    }
380    (void) strcat(*buf, DELETE_SEPARATOR);
381    (void) strcat(*buf, string);
382 }