📄 dir.c
字号:
/* * See if the result has any wildcards in it. If we find one, call * Dir_Expand right away, telling it to place the result on our list * of expansions. */ for (cp2 = file; *cp2 != '\0'; cp2++) { switch(*cp2) { case '*': case '?': case '{': case '[': Dir_Expand(file, path, expansions); goto next; } } if (*cp2 == '\0') { /* * Hit the end w/o finding any wildcards, so stick the expansion * on the end of the list. */ (void)Lst_AtEnd(expansions, file); } else { next: free(file); } start = cp+1; }}/*- *----------------------------------------------------------------------- * DirExpandInt -- * Internal expand routine. Passes through the directories in the * path one by one, calling DirMatchFiles for each. NOTE: This still * doesn't handle patterns in directories... * * Results: * None. * * Side Effects: * Things are added to the expansions list. * *----------------------------------------------------------------------- */static voidDirExpandInt(word, path, expansions) char *word; /* Word to expand */ Lst path; /* Path on which to look */ Lst expansions; /* Place to store the result */{ LstNode ln; /* Current node */ Path *p; /* Directory in the node */ if (Lst_Open(path) == SUCCESS) { while ((ln = Lst_Next(path)) != NILLNODE) { p = (Path *)Lst_Datum(ln); DirMatchFiles(word, p, expansions); } Lst_Close(path); }}/*- *----------------------------------------------------------------------- * DirPrintWord -- * Print a word in the list of expansions. Callback for Dir_Expand * when DEBUG(DIR), via Lst_ForEach. * * Results: * === 0 * * Side Effects: * The passed word is printed, followed by a space. * *----------------------------------------------------------------------- */static intDirPrintWord(word) char *word;{ printf("%s ", word); return(0);}/*- *----------------------------------------------------------------------- * Dir_Expand -- * Expand the given word into a list of words by globbing it looking * in the directories on the given search path. * * Results: * A list of words consisting of the files which exist along the search * path matching the given pattern. * * Side Effects: * Directories may be opened. Who knows? *----------------------------------------------------------------------- */voidDir_Expand (word, path, expansions) char *word; /* the word to expand */ Lst path; /* the list of directories in which to find * the resulting files */ Lst expansions; /* the list on which to place the results */{ char *cp; if (DEBUG(DIR)) { printf("expanding \"%s\"...", word); } cp = strchr(word, '{'); if (cp) { DirExpandCurly(word, cp, path, expansions); } else { cp = strchr(word, '/'); if (cp) { /* * The thing has a directory component -- find the first wildcard * in the string. */ for (cp = word; *cp; cp++) { if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') { break; } } if (*cp == '{') { /* * This one will be fun. */ DirExpandCurly(word, cp, path, expansions); return; } else if (*cp != '\0') { /* * Back up to the start of the component */ char *dirpath; while (cp > word && *cp != '/') { cp--; } if (cp != word) { char sc; /* * If the glob isn't in the first component, try and find * all the components up to the one with a wildcard. */ sc = cp[1]; cp[1] = '\0'; dirpath = Dir_FindFile(word, path); cp[1] = sc; /* * dirpath is null if can't find the leading component * XXX: Dir_FindFile won't find internal components. * i.e. if the path contains ../Etc/Object and we're * looking for Etc, it won't be found. Ah well. * Probably not important. */ if (dirpath != (char *)NULL) { char *dp = &dirpath[strlen(dirpath) - 1]; if (*dp == '/') *dp = '\0'; path = Lst_Init(FALSE); Dir_AddDir(path, dirpath); DirExpandInt(cp+1, path, expansions); Lst_Destroy(path, NOFREE); } } else { /* * Start the search from the local directory */ DirExpandInt(word, path, expansions); } } else { /* * Return the file -- this should never happen. */ DirExpandInt(word, path, expansions); } } else { /* * First the files in dot */ DirMatchFiles(word, dot, expansions); /* * Then the files in every other directory on the path. */ DirExpandInt(word, path, expansions); } } if (DEBUG(DIR)) { Lst_ForEach(expansions, DirPrintWord, NULL); fputc('\n', stdout); }}/*- *----------------------------------------------------------------------- * Dir_FindFile -- * Find the file with the given name along the given search path. * * Results: * The path to the file or NULL. This path is guaranteed to be in a * different part of memory than name and so may be safely free'd. * * Side Effects: * If the file is found in a directory which is not on the path * already (either 'name' is absolute or it is a relative path * [ dir1/.../dirn/file ] which exists below one of the directories * already on the search path), its directory is added to the end * of the path on the assumption that there will be more files in * that directory later on. Sometimes this is true. Sometimes not. *----------------------------------------------------------------------- */char *Dir_FindFile (name, path) char *name; /* the file to find */ Lst path; /* the Lst of directories to search */{ register char *p1; /* pointer into p->name */ register char *p2; /* pointer into name */ LstNode ln; /* a list element */ register char *file; /* the current filename to check */ register Path *p; /* current path member */ register char *cp; /* index of first slash, if any */ Boolean hasSlash; /* true if 'name' contains a / */ struct stat stb; /* Buffer for stat, if necessary */ Hash_Entry *entry; /* Entry for mtimes table */ /* * Find the final component of the name and note whether it has a * slash in it (the name, I mean) */ cp = strrchr (name, '/'); if (cp) { hasSlash = TRUE; cp += 1; } else { hasSlash = FALSE; cp = name; } if (DEBUG(DIR)) { printf("Searching for %s...", name); } /* * No matter what, we always look for the file in the current directory * before anywhere else and we *do not* add the ./ to it if it exists. * This is so there are no conflicts between what the user specifies * (fish.c) and what pmake finds (./fish.c). */ if ((!hasSlash || (cp - name == 2 && *name == '.')) && (Hash_FindEntry (&dot->files, cp) != (Hash_Entry *)NULL)) { if (DEBUG(DIR)) { printf("in '.'\n"); } hits += 1; dot->hits += 1; return (strdup (name)); } if (Lst_Open (path) == FAILURE) { if (DEBUG(DIR)) { printf("couldn't open path, file not found\n"); } misses += 1; return ((char *) NULL); } /* * We look through all the directories on the path seeking one which * contains the final component of the given name and whose final * component(s) match the name's initial component(s). If such a beast * is found, we concatenate the directory name and the final component * and return the resulting string. If we don't find any such thing, * we go on to phase two... */ while ((ln = Lst_Next (path)) != NILLNODE) { p = (Path *) Lst_Datum (ln); if (DEBUG(DIR)) { printf("%s...", p->name); } if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) { if (DEBUG(DIR)) { printf("here..."); } if (hasSlash) { /* * If the name had a slash, its initial components and p's * final components must match. This is false if a mismatch * is encountered before all of the initial components * have been checked (p2 > name at the end of the loop), or * we matched only part of one of the components of p * along with all the rest of them (*p1 != '/'). */ p1 = p->name + strlen (p->name) - 1; p2 = cp - 2; while (p2 >= name && *p1 == *p2) { p1 -= 1; p2 -= 1; } if (p2 >= name || (p1 >= p->name && *p1 != '/')) { if (DEBUG(DIR)) { printf("component mismatch -- continuing..."); } continue; } } file = str_concat (p->name, cp, STR_ADDSLASH); if (DEBUG(DIR)) { printf("returning %s\n", file); } Lst_Close (path); p->hits += 1; hits += 1; return (file); } else if (hasSlash) { /* * If the file has a leading path component and that component * exactly matches the entire name of the current search * directory, we assume the file doesn't exist and return NULL. */ for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) { continue; } if (*p1 == '\0' && p2 == cp - 1) { if (DEBUG(DIR)) { printf("must be here but isn't -- returing NULL\n"); } Lst_Close (path); return ((char *) NULL); } } } /* * We didn't find the file on any existing members of the directory. * If the name doesn't contain a slash, that means it doesn't exist. * If it *does* contain a slash, however, there is still hope: it * could be in a subdirectory of one of the members of the search * path. (eg. /usr/include and sys/types.h. The above search would * fail to turn up types.h in /usr/include, but it *is* in * /usr/include/sys/types.h) If we find such a beast, we assume there * will be more (what else can we assume?) and add all but the last * component of the resulting name onto the search path (at the * end). This phase is only performed if the file is *not* absolute. */ if (!hasSlash) { if (DEBUG(DIR)) { printf("failed.\n"); } misses += 1; return ((char *) NULL); } if (*name != '/') { Boolean checkedDot = FALSE; if (DEBUG(DIR)) { printf("failed. Trying subdirectories..."); } (void) Lst_Open (path); while ((ln = Lst_Next (path)) != NILLNODE) { p = (Path *) Lst_Datum (ln); if (p != dot) { file = str_concat (p->name, name, STR_ADDSLASH); } else { /* * Checking in dot -- DON'T put a leading ./ on the thing. */ file = strdup(name); checkedDot = TRUE; } if (DEBUG(DIR)) { printf("checking %s...", file); } if (stat (file, &stb) == 0) { if (DEBUG(DIR)) { printf("got it.\n"); } Lst_Close (path); /* * We've found another directory to search. We know there's * a slash in 'file' because we put one there. We nuke it after * finding it and call Dir_AddDir to add this new directory * onto the existing search path. Once that's done, we restore * the slash and triumphantly return the file name, knowing * that should a file in this directory every be referenced * again in such a manner, we will find it without having to do * numerous numbers of access calls. Hurrah! */ cp = strrchr (file, '/'); *cp = '\0'; Dir_AddDir (path, file); *cp = '/'; /* * Save the modification time so if it's needed, we don't have * to fetch it again. */ if (DEBUG(DIR)) { printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), file); } entry = Hash_CreateEntry(&mtimes, (char *) file, (Boolean *)NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -