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