filegen.C 7.6 KB

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