/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* * File: filegen.C $TOG: filegen.C /main/7 1999/10/14 15:05:25 mgreess $ * * (c) Copyright 1993, 1994 Hewlett-Packard Company * (c) Copyright 1993, 1994 International Business Machines Corp. * (c) Copyright 1993, 1994 Sun Microsystems, Inc. * (c) Copyright 1993, 1994 Novell, Inc. */ #include #include #include #include #include #define X_INCLUDE_DIRENT_H #define XOS_USE_XT_LOCKING #include #include #include #include "buf.h" #include "DtSvcLock.h" #ifndef MAXPATHLEN # define MAXPATHLEN 1024 #endif #ifdef XTHREADS extern "C" { extern void XtProcessLock(void); extern void XtProcessUnlock(void); } #endif struct _SHXcomponent { boolean is_pattern; long offset; // subscript in path buffer char *ptr; // pointer into path buffer }; declare_array(_SHXcomponents, _SHXcomponent, 4) // recursive routine to expand the wildcard path represented in stack into // all possible expansions. The expansions are appended to _SHXbuf::vec. // filebuf is a scratch buffer passed in by the caller and is used to build // intermediate paths. end is a pointer to the position in filebuf where // the calling routine left off. void _SHXbuf::expand(_SHXcomponents &stack, char *const filebuf, char *end, int compnum) { *end = '\0'; if (compnum == stack.size()) return; _SHXcomponent &comp = stack[compnum]; // double-slash? if (comp.ptr[0] == '\0') { if (compnum + 1 == stack.size()) append(filebuf, EXPANDQUOTE); else { *end++ = '/'; expand(stack, filebuf, end, compnum + 1); } return; } // performance optimization: if this path component // doesn't contain a wildcard, avoid doing an opendir() if (!comp.is_pattern) { strcpy(end, comp.ptr); if (compnum + 1 == stack.size()) { // last component, just see if the path really points to something if (access(filebuf, F_OK) != -1) append(filebuf, EXPANDQUOTE); } else { // intermediate directory just append this component and keep going char *end2 = strend(end); *end2++ = '/'; expand(stack, filebuf, end2, compnum + 1); } return; } // We have a wildcard component, open and scan its parent directory // and look for matches. DIR *dir = opendir(filebuf[0] == '\0' ? "." : filebuf); if (dir == NULL) return; _Xreaddirparams dir_buf; struct dirent *ent; memset((char*) &dir_buf, 0, sizeof(_Xreaddirparams)); while ((ent = _XReaddir(dir, dir_buf)) != NULL) { // deleted file? if (ent->d_ino == 0 || ent->d_name[0] == '\0') continue; // right name? if (comp.is_pattern) { wchar_t __nlh_char[1]; // Must have explicit match for leading '.' if (CHARAT(ent->d_name) == '.' && CHARAT(comp.ptr) != '.') continue; if (strwcmp(comp.ptr, ent->d_name) != 0) continue; } else if (strcmp(comp.ptr, ent->d_name) != 0) continue; strcpy(end, ent->d_name); if (compnum + 1 == stack.size()) append(filebuf, EXPANDQUOTE); else { char *end2 = end + strlen (ent->d_name); *end2++ = '/'; expand(stack, filebuf, end2, compnum + 1); } } closedir(dir); } //extern "C" { void qsort(void *, unsigned, int, ...); }; static char *bufptr; static int //compar(int &v1, int &v2) compar(const void *v1, const void *v2) { int result; _DtSvcProcessLock(); result = strcmp(&bufptr[*(int*)v1], &bufptr[*(int*)v2]); _DtSvcProcessUnlock(); return (result); } void _SHXbuf::filegen() { privbuf_charbuf path; _SHXcomponents stack; long vecstart = vec.size() - 1; if (vecstart < 0) return; long bufstart = long(vec[vecstart]); // Parse the file path, breaking it up into individual components. // Each component is marked as being either a wildcard component // or not. The wildcard components will have a '\' placed before // any quoted wildcard characters. The non-wildcard components // will be left unchanged. int bufpos = (int) bufstart; while (bufpos < buf.size()) { _SHXcomponent & comp = stack[stack.size()]; comp.is_pattern = FALSE; comp.offset = path.size(); comp.ptr = NULL; int startpos = bufpos; int ch; do { ch = buf[bufpos]; switch (ch) { case '/': ch = '\0'; break; case '*': case '?': case '[': if (flags[bufpos] == NOQUOTE) comp.is_pattern = TRUE; else path[path.size()] = '\\'; break; } path[path.size()] = ch; bufpos++; } while (ch != '\0'); // Add a '*' to the end of the last component if needed // for completion. if (bufpos >= buf.size()) // last component? if (bufpos > bufstart + 1) // non-null string? if (completion && !is_pattern) { path[path.size() - 1] = '*'; path[path.size()] = '\0'; comp.is_pattern = TRUE; break; } // If it wasn't a pattern, remove all of the '\' characters // that were added. if (!comp.is_pattern) { int len = bufpos - startpos - 1; strncpy(&path[comp.offset], &buf[startpos], len); path[comp.offset + len] = '\0'; } } // Fill in the character pointer values for all of the components. // We couldn't do this in the first pass because path is a // dynamic array. char *pathbuf = path.getarr(); for (int i = 0; i < stack.size(); i++) stack[i].ptr = &pathbuf[stack[i].offset]; // Remove the token that we just copied from the return vector // so that we can replace it with its expansion. vec.reset(vecstart); char filebuf[MAXPATHLEN]; expand(stack, filebuf, filebuf, 0); if (vec.size() == vecstart) // no matches? { vec[vecstart] = (char *)bufstart; // restore orig. token return; } // alphabetize the expansion to make it look pretty like ksh does. _DtSvcProcessLock(); bufptr = buf.getarr(); qsort(&vec[vecstart], (unsigned int)(vec.size() - vecstart), sizeof (char *), compar); // Find the longest match if we are doing completion: if (completion) { long i; // compare all entries to a copy of the first entry snprintf(filebuf, sizeof(filebuf), "%s", &bufptr[long(vec[0])]); for (i = 1; i < vec.size(); i++) { char *ref = filebuf; char *ptr = &bufptr[long(vec[i])]; while (*ref == *ptr && *ref != '\0' && *ptr != '\0') ref++, ptr++; *ref = '\0'; // shorten the reference copy } // Now store the best match as the first token. We will // have to shift the expansion vector down by one to // make room. for (i = vec.size(); i > 0; --i) { char *val = vec[i - 1]; vec[i] = val; } vec[0] = (char *)buf.size(); append(filebuf, EXPANDQUOTE); vec.reset(vec.size() - 1); // adjust for the append } _DtSvcProcessUnlock(); } implement_array(_SHXcomponents, _SHXcomponent, 4)