?? tclglob.c
字號:
#ifndef EXCLUDE_TCL/* * tclGlob.c -- * * This file provides procedures and commands for file name * manipulation, such as tilde expansion and globbing. * * Copyright 1990-1991 Regents of the University of California * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. The University of California * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. */#include "tclInt.h"#include "tclUnix.h"/* * The structure below is used to keep track of a globbing result * being built up (i.e. a partial list of file names). The list * grows dynamically to be as big as needed. */typedef struct { char *result; /* Pointer to result area. */ int totalSpace; /* Total number of characters allocated * for result. */ int spaceUsed; /* Number of characters currently in use * to hold the partial result (not including * the terminating NULL). */ int dynamic; /* 0 means result is static space, 1 means * it's dynamic. */} GlobResult;/* * Declarations for procedures local to this file: */static void AppendResult _ANSI_ARGS_((Tcl_Interp *interp, char *dir, char *separator, char *name, int nameLength));static int DoGlob _ANSI_ARGS_((Tcl_Interp *interp, char *dir, char *rem));/* *---------------------------------------------------------------------- * * AppendResult -- * * Given two parts of a file name (directory and element within * directory), concatenate the two together and append them to * the result building up in interp. * * Results: * There is no return value. * * Side effects: * Interp->result gets extended. * *---------------------------------------------------------------------- */static voidAppendResult(interp, dir, separator, name, nameLength) Tcl_Interp *interp; /* Interpreter whose result should be * appended to. */ char *dir; /* Name of directory, without trailing * slash except for root directory. */ char *separator; /* Separator string so use between dir and * name: either "/" or "" depending on dir. */ char *name; /* Name of file withing directory (NOT * necessarily null-terminated!). */ int nameLength; /* Number of characters in name. */{ int dirFlags, nameFlags; char *p, saved; /* * Next, see if we can put together a valid list element from dir * and name by calling Tcl_AppendResult. */ if (*dir == 0) { dirFlags = 0; } else { Tcl_ScanElement(dir, &dirFlags); } saved = name[nameLength]; name[nameLength] = 0; Tcl_ScanElement(name, &nameFlags); if ((dirFlags == 0) && (nameFlags == 0)) { if (*interp->result != 0) { Tcl_AppendResult(interp, " ", dir, separator, name, (char *) NULL); } else { Tcl_AppendResult(interp, dir, separator, name, (char *) NULL); } name[nameLength] = saved; return; } /* * This name has weird characters in it, so we have to convert it to * a list element. To do that, we have to merge the characters * into a single name. To do that, malloc a buffer to hold everything. */ p = (char *) ckalloc((unsigned) (strlen(dir) + strlen(separator) + nameLength + 1)); sprintf(p, "%s%s%s", dir, separator, name); name[nameLength] = saved; Tcl_AppendElement(interp, p, 0); ckfree(p);}/* *---------------------------------------------------------------------- * * DoGlob -- * * This recursive procedure forms the heart of the globbing * code. It performs a depth-first traversal of the tree * given by the path name to be globbed. * * Results: * The return value is a standard Tcl result indicating whether * an error occurred in globbing. After a normal return the * result in interp will be set to hold all of the file names * given by the dir and rem arguments. After an error the * result in interp will hold an error message. * * Side effects: * None. * *---------------------------------------------------------------------- */static intDoGlob(interp, dir, rem) Tcl_Interp *interp; /* Interpreter to use for error * reporting (e.g. unmatched brace). */ char *dir; /* Name of a directory at which to * start glob expansion. This name * is fixed: it doesn't contain any * globbing chars. */ char *rem; /* Path to glob-expand. */{ /* * When this procedure is entered, the name to be globbed may * already have been partly expanded by ancestor invocations of * DoGlob. The part that's already been expanded is in "dir" * (this may initially be empty), and the part still to expand * is in "rem". This procedure expands "rem" one level, making * recursive calls to itself if there's still more stuff left * in the remainder. */ register char *p; register char c; char *openBrace, *closeBrace; int gotSpecial, result; char *separator; /* * Figure out whether we'll need to add a slash between the directory * name and file names within the directory when concatenating them * together. */ if ((dir[0] == 0) || ((dir[0] == '/') && (dir[1] == 0))) { separator = ""; } else { separator = "/"; } /* * When generating information for the next lower call, * use static areas if the name is short, and malloc if the name * is longer. */#define STATIC_SIZE 200 /* * First, find the end of the next element in rem, checking * along the way for special globbing characters. */ gotSpecial = 0; openBrace = closeBrace = NULL; for (p = rem; ; p++) { c = *p; if ((c == '\0') || (c == '/')) { break; } if ((c == '{') && (openBrace == NULL)) { openBrace = p; } if ((c == '}') && (closeBrace == NULL)) { closeBrace = p; } if ((c == '*') || (c == '[') || (c == '\\') || (c == '?')) { gotSpecial = 1; } } /* * If there is an open brace in the argument, then make a recursive * call for each element between the braces. In this case, the * recursive call to DoGlob uses the same "dir" that we got. * If there are several brace-pairs in a single name, we just handle * one here, and the others will be handled in recursive calls. */ if (openBrace != NULL) { int remLength, l1, l2; char static1[STATIC_SIZE]; char *element, *newRem; if (closeBrace == NULL) { Tcl_ResetResult(interp); interp->result = "unmatched open-brace in file name"; return TCL_ERROR; } remLength = strlen(rem) + 1; if (remLength <= STATIC_SIZE) { newRem = static1; } else { newRem = (char *) ckalloc((unsigned) remLength); } l1 = openBrace-rem; strncpy(newRem, rem, l1); p = openBrace; for (p = openBrace; *p != '}'; ) { element = p+1; for (p = element; ((*p != '}') && (*p != ',')); p++) { /* Empty loop body: just find end of this element. */ } l2 = p - element; strncpy(newRem+l1, element, l2); strcpy(newRem+l1+l2, closeBrace+1); if (DoGlob(interp, dir, newRem) != TCL_OK) { return TCL_ERROR; } } if (remLength > STATIC_SIZE) { ckfree(newRem); } return TCL_OK; } /* * If there were any pattern-matching characters, then scan through * the directory to find all the matching names. */ if (gotSpecial) { yaffs_DIR *d; yaffs_dirent *entryPtr; int l1, l2; char *pattern, *newDir, *dirName, *path; char static1[STATIC_SIZE], static2[STATIC_SIZE]; struct yaffs_stat statBuf; /* * Be careful not to do any actual file system operations on a * directory named ""; instead, use ".". This is needed because * some versions of UNIX don't treat "" like "." automatically. */ if (*dir == '\0') { dirName = "."; } else { dirName = dir; } if (strcmp(".", dirName) == 0) { path = "./"; } else if (strcmp("..", dirName) == 0) { path = "../"; } else { path = dirName; } if ((yaffs_stat(path, &statBuf) != 0) || !S_ISDIR(statBuf.st_mode)) { return TCL_OK; } d = yaffs_opendir(path); if (d == NULL) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -