2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
24 * File: filegen.C $TOG: filegen.C /main/7 1999/10/14 15:05:25 mgreess $
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.
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>
42 #include "DtSvcLock.h"
45 # define MAXPATHLEN 1024
50 extern void XtProcessLock(void);
51 extern void XtProcessUnlock(void);
58 long offset; // subscript in path buffer
59 char *ptr; // pointer into path buffer
62 declare_array(_SHXcomponents, _SHXcomponent, 4)
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.
70 _SHXbuf::expand(_SHXcomponents &stack,
71 char *const filebuf, char *end, int compnum)
75 if (compnum == stack.size())
78 _SHXcomponent &comp = stack[compnum];
81 if (comp.ptr[0] == '\0')
83 if (compnum + 1 == stack.size())
84 append(filebuf, EXPANDQUOTE);
88 expand(stack, filebuf, end, compnum + 1);
93 // performance optimization: if this path component
94 // doesn't contain a wildcard, avoid doing an opendir()
97 strcpy(end, comp.ptr);
98 if (compnum + 1 == stack.size())
100 // last component, just see if the path really points to something
101 if (access(filebuf, F_OK) != -1)
102 append(filebuf, EXPANDQUOTE);
106 // intermediate directory just append this component and keep going
107 char *end2 = strend(end);
109 expand(stack, filebuf, end2, compnum + 1);
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);
120 _Xreaddirparams dir_buf;
123 memset((char*) &dir_buf, 0, sizeof(_Xreaddirparams));
124 while ((ent = _XReaddir(dir, dir_buf)) != NULL)
127 if (ent->d_ino == 0 || ent->d_name[0] == '\0')
133 wchar_t __nlh_char[1];
135 // Must have explicit match for leading '.'
136 if (CHARAT(ent->d_name) == '.' && CHARAT(comp.ptr) != '.')
139 if (strwcmp(comp.ptr, ent->d_name) != 0)
142 else if (strcmp(comp.ptr, ent->d_name) != 0)
145 strcpy(end, ent->d_name);
146 if (compnum + 1 == stack.size())
147 append(filebuf, EXPANDQUOTE);
150 char *end2 = end + strlen (ent->d_name);
152 expand(stack, filebuf, end2, compnum + 1);
160 //extern "C" { void qsort(void *, unsigned, int, ...); };
165 //compar(int &v1, int &v2)
166 compar(const void *v1, const void *v2)
171 result = strcmp(&bufptr[*(int*)v1], &bufptr[*(int*)v2]);
172 _DtSvcProcessUnlock();
179 privbuf_charbuf path;
180 _SHXcomponents stack;
182 long vecstart = vec.size() - 1;
186 long bufstart = long(vec[vecstart]);
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())
196 _SHXcomponent & comp = stack[stack.size()];
197 comp.is_pattern = FALSE;
198 comp.offset = path.size();
200 int startpos = bufpos;
214 if (flags[bufpos] == NOQUOTE)
215 comp.is_pattern = TRUE;
217 path[path.size()] = '\\';
221 path[path.size()] = ch;
223 } while (ch != '\0');
225 // Add a '*' to the end of the last component if needed
227 if (bufpos >= buf.size()) // last component?
228 if (bufpos > bufstart + 1) // non-null string?
229 if (completion && !is_pattern)
231 path[path.size() - 1] = '*';
232 path[path.size()] = '\0';
233 comp.is_pattern = TRUE;
237 // If it wasn't a pattern, remove all of the '\' characters
239 if (!comp.is_pattern)
241 int len = bufpos - startpos - 1;
242 strncpy(&path[comp.offset], &buf[startpos], len);
243 path[comp.offset + len] = '\0';
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
250 char *pathbuf = path.getarr();
251 for (int i = 0; i < stack.size(); i++)
252 stack[i].ptr = &pathbuf[stack[i].offset];
254 // Remove the token that we just copied from the return vector
255 // so that we can replace it with its expansion.
258 char filebuf[MAXPATHLEN];
259 expand(stack, filebuf, filebuf, 0);
261 if (vec.size() == vecstart) // no matches?
263 vec[vecstart] = (char *)bufstart; // restore orig. token
267 // alphabetize the expansion to make it look pretty like ksh does.
269 bufptr = buf.getarr();
270 qsort(&vec[vecstart], (unsigned int)(vec.size() - vecstart),
271 sizeof (char *), compar);
273 // Find the longest match if we are doing completion:
277 // compare all entries to a copy of the first entry
278 snprintf(filebuf, sizeof(filebuf), "%s", &bufptr[long(vec[0])]);
280 for (i = 1; i < vec.size(); i++)
283 char *ptr = &bufptr[long(vec[i])];
284 while (*ref == *ptr && *ref != '\0' && *ptr != '\0')
287 *ref = '\0'; // shorten the reference copy
290 // Now store the best match as the first token. We will
291 // have to shift the expansion vector down by one to
293 for (i = vec.size(); i > 0; --i)
295 char *val = vec[i - 1];
298 vec[0] = (char *)buf.size();
299 append(filebuf, EXPANDQUOTE);
300 vec.reset(vec.size() - 1); // adjust for the append
302 _DtSvcProcessUnlock();
305 implement_array(_SHXcomponents, _SHXcomponent, 4)