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 librararies 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.
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #define X_INCLUDE_DIRENT_H
36 #define XOS_USE_XT_LOCKING
37 #include <X11/Xos_r.h>
38 #include <codelibs/stringx.h>
39 #include <codelibs/nl_hack.h>
41 #include "DtSvcLock.h"
44 # define MAXPATHLEN 1024
49 extern void XtProcessLock(void);
50 extern void XtProcessUnlock(void);
57 long offset; // subscript in path buffer
58 char *ptr; // pointer into path buffer
61 declare_array(_SHXcomponents, _SHXcomponent, 4)
63 // recursive routine to expand the wildcard path represented in stack into
64 // all possible expansions. The expansions are appended to _SHXbuf::vec.
65 // filebuf is a scratch buffer passed in by the caller and is used to build
66 // intermediate paths. end is a pointer to the position in filebuf where
67 // the calling routine left off.
69 _SHXbuf::expand(_SHXcomponents &stack,
70 char *const filebuf, char *end, int compnum)
74 if (compnum == stack.size())
77 _SHXcomponent &comp = stack[compnum];
80 if (comp.ptr[0] == '\0')
82 if (compnum + 1 == stack.size())
83 append(filebuf, EXPANDQUOTE);
87 expand(stack, filebuf, end, compnum + 1);
92 // performance optimization: if this path component
93 // doesn't contain a wildcard, avoid doing an opendir()
96 strcpy(end, comp.ptr);
97 if (compnum + 1 == stack.size())
99 // last component, just see if the path really points to something
100 if (access(filebuf, F_OK) != -1)
101 append(filebuf, EXPANDQUOTE);
105 // intermediate directory just append this component and keep going
106 char *end2 = strend(end);
108 expand(stack, filebuf, end2, compnum + 1);
113 // We have a wildcard component, open and scan its parent directory
114 // and look for matches.
115 DIR *dir = opendir(filebuf[0] == '\0' ? "." : filebuf);
119 _Xreaddirparams dir_buf;
122 memset((char*) &dir_buf, 0, sizeof(_Xreaddirparams));
123 while ((ent = _XReaddir(dir, dir_buf)) != NULL)
126 if (ent->d_ino == 0 || ent->d_name[0] == '\0')
132 wchar_t __nlh_char[1];
134 // Must have explicit match for leading '.'
135 if (CHARAT(ent->d_name) == '.' && CHARAT(comp.ptr) != '.')
138 if (strwcmp(comp.ptr, ent->d_name) != 0)
141 else if (strcmp(comp.ptr, ent->d_name) != 0)
144 strcpy(end, ent->d_name);
145 if (compnum + 1 == stack.size())
146 append(filebuf, EXPANDQUOTE);
149 char *end2 = end + strlen (ent->d_name);
151 expand(stack, filebuf, end2, compnum + 1);
159 //extern "C" { void qsort(void *, unsigned, int, ...); };
164 //compar(int &v1, int &v2)
165 compar(const void *v1, const void *v2)
170 result = strcmp(&bufptr[*(int*)v1], &bufptr[*(int*)v2]);
171 _DtSvcProcessUnlock();
178 privbuf_charbuf path;
179 _SHXcomponents stack;
181 long vecstart = vec.size() - 1;
185 long bufstart = long(vec[vecstart]);
187 // Parse the file path, breaking it up into individual components.
188 // Each component is marked as being either a wildcard component
189 // or not. The wildcard components will have a '\' placed before
190 // any quoted wildcard characters. The non-wildcard components
191 // will be left unchanged.
192 int bufpos = (int) bufstart;
193 while (bufpos < buf.size())
195 _SHXcomponent & comp = stack[stack.size()];
196 comp.is_pattern = FALSE;
197 comp.offset = path.size();
199 int startpos = bufpos;
213 if (flags[bufpos] == NOQUOTE)
214 comp.is_pattern = TRUE;
216 path[path.size()] = '\\';
220 path[path.size()] = ch;
222 } while (ch != '\0');
224 // Add a '*' to the end of the last component if needed
226 if (bufpos >= buf.size()) // last component?
227 if (bufpos > bufstart + 1) // non-null string?
228 if (completion && !is_pattern)
230 path[path.size() - 1] = '*';
231 path[path.size()] = '\0';
232 comp.is_pattern = TRUE;
236 // If it wasn't a pattern, remove all of the '\' characters
238 if (!comp.is_pattern)
240 int len = bufpos - startpos - 1;
241 strncpy(&path[comp.offset], &buf[startpos], len);
242 path[comp.offset + len] = '\0';
246 // Fill in the character pointer values for all of the components.
247 // We couldn't do this in the first pass because path is a
249 char *pathbuf = path.getarr();
250 for (int i = 0; i < stack.size(); i++)
251 stack[i].ptr = &pathbuf[stack[i].offset];
253 // Remove the token that we just copied from the return vector
254 // so that we can replace it with its expansion.
257 char filebuf[MAXPATHLEN];
258 expand(stack, filebuf, filebuf, 0);
260 if (vec.size() == vecstart) // no matches?
262 vec[vecstart] = (char *)bufstart; // restore orig. token
266 // alphabetize the expansion to make it look pretty like ksh does.
268 bufptr = buf.getarr();
269 qsort(&vec[vecstart], (unsigned int)(vec.size() - vecstart),
270 sizeof (char *), compar);
272 // Find the longest match if we are doing completion:
275 // compare all entries to a copy of the first entry
276 strcpy(filebuf, &bufptr[long(vec[0])]);
278 for (long i = 1; i < vec.size(); i++)
280 register char *ref = filebuf;
281 register char *ptr = &bufptr[long(vec[i])];
282 while (*ref == *ptr && *ref != '\0' && *ptr != '\0')
285 *ref = '\0'; // shorten the reference copy
288 // Now store the best match as the first token. We will
289 // have to shift the expansion vector down by one to
291 for (i = vec.size(); i > 0; --i)
293 register char *val = vec[i - 1];
296 vec[0] = (char *)buf.size();
297 append(filebuf, EXPANDQUOTE);
298 vec.reset(vec.size() - 1); // adjust for the append
300 _DtSvcProcessUnlock();
303 implement_array(_SHXcomponents, _SHXcomponent, 4)