Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / lib / DtSvc / DtCodelibs / filegen.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 /*
24  * File:        filegen.C $TOG: filegen.C /main/7 1999/10/14 15:05:25 mgreess $
25  *
26  * (c) Copyright 1993, 1994 Hewlett-Packard Company
27  * (c) Copyright 1993, 1994 International Business Machines Corp.
28  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
29  * (c) Copyright 1993, 1994 Novell, Inc.
30  */
31 #include <stdio.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #define X_INCLUDE_DIRENT_H
37 #define XOS_USE_XT_LOCKING
38 #include <X11/Xos_r.h>
39 #include <codelibs/stringx.h>
40 #include <codelibs/nl_hack.h>
41 #include "buf.h"
42 #include "DtSvcLock.h"
43
44 #ifndef MAXPATHLEN
45 # define MAXPATHLEN 1024
46 #endif
47
48 #ifdef XTHREADS
49 extern "C" {
50     extern void XtProcessLock(void);
51     extern void XtProcessUnlock(void);
52 }
53 #endif
54
55 struct _SHXcomponent
56 {
57     boolean is_pattern;
58     long offset;                // subscript in path buffer
59     char *ptr;                  // pointer into path buffer
60 };
61
62 declare_array(_SHXcomponents, _SHXcomponent, 4)
63
64 // recursive routine to expand the wildcard path represented in stack into
65 // all possible expansions.  The expansions are appended to _SHXbuf::vec.
66 // filebuf is a scratch buffer passed in by the caller and is used to build
67 // intermediate paths.  end is a pointer to the position in filebuf where
68 // the calling routine left off.
69 void
70 _SHXbuf::expand(_SHXcomponents &stack,
71         char *const filebuf, char *end, int compnum)
72 {
73     *end = '\0';
74
75     if (compnum == stack.size())
76         return;
77
78     _SHXcomponent &comp = stack[compnum];
79
80     // double-slash?
81     if (comp.ptr[0] == '\0')
82     {
83         if (compnum + 1 == stack.size())
84             append(filebuf, EXPANDQUOTE);
85         else
86         {
87             *end++ = '/';
88             expand(stack, filebuf, end, compnum + 1);
89         }
90         return;
91     }
92
93     // performance optimization:  if this path component
94     // doesn't contain a wildcard, avoid doing an opendir()
95     if (!comp.is_pattern)
96     {
97         strcpy(end, comp.ptr);
98         if (compnum + 1 == stack.size())
99         {
100             // last component, just see if the path really points to something
101             if (access(filebuf, F_OK) != -1)
102                 append(filebuf, EXPANDQUOTE);
103         }
104         else
105         {
106             // intermediate directory just append this component and keep going
107             char *end2 = strend(end);
108             *end2++ = '/';
109             expand(stack, filebuf, end2, compnum + 1);
110         }
111         return;
112     }
113
114     // We have a wildcard component, open and scan its parent directory
115     // and look for matches.
116     DIR *dir = opendir(filebuf[0] == '\0' ? "." : filebuf);
117     if (dir == NULL)
118         return;
119
120     _Xreaddirparams dir_buf;
121     struct dirent *ent;
122
123     memset((char*) &dir_buf, 0, sizeof(_Xreaddirparams));
124     while ((ent = _XReaddir(dir, dir_buf)) != NULL)
125     {
126         // deleted file?
127         if (ent->d_ino == 0 || ent->d_name[0] == '\0')
128             continue;
129
130         // right name?
131         if (comp.is_pattern)
132         {
133             wchar_t __nlh_char[1];
134
135             // Must have explicit match for leading '.'
136             if (CHARAT(ent->d_name) == '.' && CHARAT(comp.ptr) != '.')
137                 continue;
138
139             if (strwcmp(comp.ptr, ent->d_name) != 0)
140                 continue;
141         }
142         else if (strcmp(comp.ptr, ent->d_name) != 0)
143             continue;
144
145         strcpy(end, ent->d_name);
146         if (compnum + 1 == stack.size())
147             append(filebuf, EXPANDQUOTE);
148         else
149         {
150             char *end2 = end + strlen (ent->d_name);
151             *end2++ = '/';
152             expand(stack, filebuf, end2, compnum + 1);
153         }
154     }
155
156     closedir(dir);
157 }
158
159
160 //extern "C" { void qsort(void *, unsigned, int, ...); };
161
162 static char *bufptr;
163
164 static int
165 //compar(int &v1, int &v2)
166 compar(const void *v1, const void *v2)
167 {
168     int result;
169
170     _DtSvcProcessLock();
171     result = strcmp(&bufptr[*(int*)v1], &bufptr[*(int*)v2]);
172     _DtSvcProcessUnlock();
173     return (result);
174 }
175
176 void
177 _SHXbuf::filegen()
178 {
179     privbuf_charbuf path;
180     _SHXcomponents stack;
181
182     long vecstart = vec.size() - 1;
183     if (vecstart < 0)
184         return;
185
186     long bufstart = long(vec[vecstart]);
187
188     // Parse the file path, breaking it up into individual components.
189     // Each component is marked as being either a wildcard component
190     // or not.  The wildcard components will have a '\' placed before
191     // any quoted wildcard characters.  The non-wildcard components
192     // will be left unchanged.
193     int bufpos = (int) bufstart;
194     while (bufpos < buf.size())
195     {
196         _SHXcomponent & comp = stack[stack.size()];
197         comp.is_pattern = FALSE;
198         comp.offset = path.size();
199         comp.ptr = NULL;
200         int startpos = bufpos;
201
202         int ch;
203         do
204         {
205             ch = buf[bufpos];
206             switch (ch)
207             {
208             case '/': 
209                 ch = '\0';
210                 break;
211             case '*': 
212             case '?': 
213             case '[': 
214                 if (flags[bufpos] == NOQUOTE)
215                     comp.is_pattern = TRUE;
216                 else
217                     path[path.size()] = '\\';
218                 break;
219             }
220
221             path[path.size()] = ch;
222             bufpos++;
223         } while (ch != '\0');
224
225         // Add a '*' to the end of the last component if needed
226         // for completion.
227         if (bufpos >= buf.size())   // last component?
228             if (bufpos > bufstart + 1)  // non-null string?
229                 if (completion && !is_pattern)
230                 {
231                     path[path.size() - 1] = '*';
232                     path[path.size()] = '\0';
233                     comp.is_pattern = TRUE;
234                     break;
235                 }
236
237         // If it wasn't a pattern, remove all of the '\' characters
238         // that were added.
239         if (!comp.is_pattern)
240         {
241             int len = bufpos - startpos - 1;
242             strncpy(&path[comp.offset], &buf[startpos], len);
243             path[comp.offset + len] = '\0';
244         }
245     }
246
247     // Fill in the character pointer values for all of the components.
248     // We couldn't do this in the first pass because path is a
249     // dynamic array.
250     char *pathbuf = path.getarr();
251     for (int i = 0; i < stack.size(); i++)
252         stack[i].ptr = &pathbuf[stack[i].offset];
253
254     // Remove the token that we just copied from the return vector
255     // so that we can replace it with its expansion.
256     vec.reset(vecstart);
257
258     char filebuf[MAXPATHLEN];
259     expand(stack, filebuf, filebuf, 0);
260
261     if (vec.size() == vecstart) // no matches?
262     {
263         vec[vecstart] = (char *)bufstart;   // restore orig. token
264         return;
265     }
266
267     // alphabetize the expansion to make it look pretty like ksh does.
268     _DtSvcProcessLock();
269     bufptr = buf.getarr();
270     qsort(&vec[vecstart], (unsigned int)(vec.size() - vecstart),
271             sizeof (char *), compar);
272
273     // Find the longest match if we are doing completion:
274     if (completion)
275     {
276         long i;
277         // compare all entries to a copy of the first entry
278         snprintf(filebuf, sizeof(filebuf), "%s", &bufptr[long(vec[0])]);
279
280         for (i = 1; i < vec.size(); i++)
281         {
282             char *ref = filebuf;
283             char *ptr = &bufptr[long(vec[i])];
284             while (*ref == *ptr && *ref != '\0' && *ptr != '\0')
285                 ref++, ptr++;
286
287             *ref = '\0';        // shorten the reference copy
288         }
289
290         // Now store the best match as the first token.  We will
291         // have to shift the expansion vector down by one to
292         // make room.
293         for (i = vec.size(); i > 0; --i)
294         {
295             char *val = vec[i - 1];
296             vec[i] = val;
297         }
298         vec[0] = (char *)buf.size();
299         append(filebuf, EXPANDQUOTE);
300         vec.reset(vec.size() - 1);  // adjust for the append
301     }
302     _DtSvcProcessUnlock();
303 }
304
305 implement_array(_SHXcomponents, _SHXcomponent, 4)