void opendir_cleanup(void *xdir) { DIR *dir; dir = xdir; xclosedir(dir); }
static void do_subdir (kpathsea kpse, str_llist_type *str_list_ptr, string elt, unsigned elt_length, string post) { #ifdef WIN32 WIN32_FIND_DATAW find_file_data; HANDLE hnd; int proceed; int nlinks = 2; #else DIR *dir; struct dirent *e; #endif /* not WIN32 */ fn_type name; /* Some old compilers don't allow aggregate initialization. */ name = fn_copy0 (elt, elt_length); assert (IS_DIR_SEP_CH (elt[elt_length - 1]) || IS_DEVICE_SEP (elt[elt_length - 1])); #if defined (WIN32) strcpy(dirname, FN_STRING(name)); strcat(dirname, "/*.*"); /* "*.*" or "*" -- seems equivalent. */ get_wstring_from_fsyscp(dirname, dirnamew); hnd = FindFirstFileW(dirnamew, &find_file_data); if (hnd == INVALID_HANDLE_VALUE) { fn_free(&name); return; } /* Include top level before subdirectories, if nothing to match. */ if (*post == 0) dir_list_add (str_list_ptr, FN_STRING (name)); else { /* If we do have something to match, see if it exists. For example, POST might be `pk/ljfour', and they might have a directory `$TEXMF/fonts/pk/ljfour' that we should find. */ fn_str_grow (&name, post); expand_elt (kpse, str_list_ptr, FN_STRING (name), elt_length); fn_shrink_to (&name, elt_length); } proceed = 1; while (proceed) { if (find_file_data.cFileName[0] != L'.') { int links; /* Construct the potential subdirectory name. */ potname = get_fsyscp_from_wstring(find_file_data.cFileName, potname=NULL); fn_str_grow (&name, potname); free(potname); /* Maybe we have cached the leafness of this directory. The function will return 0 if unknown, else the actual (Unix-like) value. */ links = kpathsea_dir_links (kpse, FN_STRING (name), 0); if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { unsigned potential_len = FN_LENGTH (name); /* in any case, compute the leafness */ nlinks++; /* It's a directory, so append the separator. */ fn_str_grow (&name, DIR_SEP_STRING); if (*post != 0) { fn_str_grow (&name, post); /* Unfortunately we can't check if the new element is a leaf directory, because we don't have a directory name here, we just have a path spec. This means we may descend into a leaf directory cm/pk, if the spec is ...fonts//pk//. */ expand_elt (kpse, str_list_ptr, FN_STRING (name), potential_len); fn_shrink_to (&name, potential_len); } /* Should we recurse? To see if the subdirectory is a leaf, check if it has two links (one for . and one for ..). This means that symbolic links to directories do not affect the leaf-ness. This is arguably wrong, but the only alternative I know of is to stat every entry in the directory, and that is unacceptably slow. */ if (links == 0 || links > 2) /* All criteria are met; find subdirectories. */ do_subdir (kpse, str_list_ptr, FN_STRING (name), potential_len, post); else if (*post == 0) /* Nothing to match, no recursive subdirectories to look for: we're done with this branch. Add it. */ dir_list_add (str_list_ptr, FN_STRING (name)); } fn_shrink_to (&name, elt_length); } proceed = FindNextFileW (hnd, &find_file_data); } /* Update the leafness of name. */ kpathsea_dir_links(kpse, FN_STRING(name), nlinks); fn_free (&name); FindClose(hnd); #else /* not WIN32 */ /* If we can't open it, quit. */ dir = opendir (FN_STRING (name)); if (dir == NULL) { fn_free (&name); return; } /* Include top level before subdirectories, if nothing to match. */ if (*post == 0) dir_list_add (str_list_ptr, FN_STRING (name)); else { /* If we do have something to match, see if it exists. For example, POST might be `pk/ljfour', and they might have a directory `$TEXMF/fonts/pk/ljfour' that we should find. */ fn_str_grow (&name, post); expand_elt (kpse, str_list_ptr, FN_STRING (name), elt_length); fn_shrink_to (&name, elt_length); } while ((e = readdir (dir)) != NULL) { /* If it begins with a `.', never mind. (This allows ``hidden'' directories that the algorithm won't find.) */ if (e->d_name[0] != '.') { int links; /* Construct the potential subdirectory name. */ fn_str_grow (&name, e->d_name); /* If we can't stat it, or if it isn't a directory, continue. */ links = kpathsea_dir_links (kpse, FN_STRING (name), 0); if (links >= 0) { unsigned potential_len = FN_LENGTH (name); /* It's a directory, so append the separator. */ fn_str_grow (&name, DIR_SEP_STRING); if (*post != 0) { fn_str_grow (&name, post); /* Unfortunately we can't check if the new element is a leaf directory, because we don't have a directory name here, we just have a path spec. This means we may descend into a leaf directory cm/pk, if the spec is ...fonts//pk//. */ expand_elt (kpse, str_list_ptr, FN_STRING (name), potential_len); fn_shrink_to (&name, potential_len); } /* Should we recurse? To see if the subdirectory is a leaf, check if it has two links (one for . and one for ..). This means that symbolic links to directories do not affect the leaf-ness. This is arguably wrong, but the only alternative I know of is to stat every entry in the directory, and that is unacceptably slow. The #ifdef here makes all this configurable at compile-time, so that if we're using VMS directories or some such, we can still find subdirectories, even if it is much slower. */ #ifdef ST_NLINK_TRICK /* With SAS/C++ 6.55 on the Amiga, stat sets the st_nlink field to -1 for a file, or to 1 for a directory. Cygwin 1.7 also leaves st_nlink as 1: http://cygwin.com/ml/cygwin-developers/2008-04/msg00110.html */ if (links != 2) #endif /* ST_NLINK_TRICK */ /* All criteria are met; find subdirectories. */ do_subdir (kpse, str_list_ptr, FN_STRING (name), potential_len, post); #ifdef ST_NLINK_TRICK else if (*post == 0) /* Nothing to match, no recursive subdirectories to look for: we're done with this branch. Add it. */ dir_list_add (str_list_ptr, FN_STRING (name)); #endif } /* Remove the directory entry we just checked from `name'. */ fn_shrink_to (&name, elt_length); } } fn_free (&name); xclosedir (dir); #endif /* not WIN32 */ }
static void do_subdir P4C(str_llist_type *, str_list_ptr, const_string, elt, unsigned, elt_length, const_string, post) { #ifdef WIN32 WIN32_FIND_DATA find_file_data; HANDLE hnd; int proceed; #else DIR *dir; struct dirent *e; #endif /* not WIN32 */ fn_type name; /* Some old compilers don't allow aggregate initialization. */ name = fn_copy0 (elt, elt_length); assert (IS_DIR_SEP (elt[elt_length - 1]) || IS_DEVICE_SEP (elt[elt_length - 1])); #if defined (WIN32) strcpy(dirname, FN_STRING(name)); strcat(dirname, "/*.*"); /* "*.*" or "*" -- seems equivalent. */ hnd = FindFirstFile(dirname, &find_file_data); if (hnd == INVALID_HANDLE_VALUE) { fn_free(&name); return; } /* Include top level before subdirectories, if nothing to match. */ if (*post == 0) dir_list_add (str_list_ptr, FN_STRING (name)); else { /* If we do have something to match, see if it exists. For example, POST might be `pk/ljfour', and they might have a directory `$TEXMF/fonts/pk/ljfour' that we should find. */ fn_str_grow (&name, post); expand_elt (str_list_ptr, FN_STRING (name), elt_length); fn_shrink_to (&name, elt_length); } proceed = 1; while (proceed) { if (find_file_data.cFileName[0] != '.') { /* Construct the potential subdirectory name. */ fn_str_grow (&name, find_file_data.cFileName); if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { unsigned potential_len = FN_LENGTH (name); /* It's a directory, so append the separator. */ fn_str_grow (&name, DIR_SEP_STRING); do_subdir (str_list_ptr, FN_STRING (name), potential_len, post); } fn_shrink_to (&name, elt_length); } proceed = FindNextFile (hnd, &find_file_data); } fn_free (&name); FindClose(hnd); #else /* not WIN32 */ /* If we can't open it, quit. */ dir = opendir (FN_STRING (name)); if (dir == NULL) { fn_free (&name); return; } /* Include top level before subdirectories, if nothing to match. */ if (*post == 0) dir_list_add (str_list_ptr, FN_STRING (name)); else { /* If we do have something to match, see if it exists. For example, POST might be `pk/ljfour', and they might have a directory `$TEXMF/fonts/pk/ljfour' that we should find. */ fn_str_grow (&name, post); expand_elt (str_list_ptr, FN_STRING (name), elt_length); fn_shrink_to (&name, elt_length); } while ((e = readdir (dir)) != NULL) { /* If it begins with a `.', never mind. (This allows ``hidden'' directories that the algorithm won't find.) */ if (e->d_name[0] != '.') { int links; /* Construct the potential subdirectory name. */ fn_str_grow (&name, e->d_name); /* If we can't stat it, or if it isn't a directory, continue. */ links = dir_links (FN_STRING (name)); if (links >= 0) { unsigned potential_len = FN_LENGTH (name); /* It's a directory, so append the separator. */ fn_str_grow (&name, DIR_SEP_STRING); /* Should we recurse? To see if the subdirectory is a leaf, check if it has two links (one for . and one for ..). This means that symbolic links to directories do not affect the leaf-ness. This is arguably wrong, but the only alternative I know of is to stat every entry in the directory, and that is unacceptably slow. The #ifdef here makes all this configurable at compile-time, so that if we're using VMS directories or some such, we can still find subdirectories, even if it is much slower. */ #ifdef ST_NLINK_TRICK #ifdef AMIGA /* With SAS/C++ 6.55 on the Amiga, `stat' sets the `st_nlink' field to -1 for a file, or to 1 for a directory. */ if (links == 1) #else if (links > 2) #endif /* not AMIGA */ #endif /* not ST_NLINK_TRICK */ /* All criteria are met; find subdirectories. */ do_subdir (str_list_ptr, FN_STRING (name), potential_len, post); #ifdef ST_NLINK_TRICK else if (*post == 0) /* Nothing to match, no recursive subdirectories to look for: we're done with this branch. Add it. */ dir_list_add (str_list_ptr, FN_STRING (name)); #endif } /* Remove the directory entry we just checked from `name'. */ fn_shrink_to (&name, elt_length); } } fn_free (&name); xclosedir (dir); #endif /* not WIN32 */ }
string xgetcwd (void) { /* If the system provides getcwd, use it. If not, use getwd if available. But provide a way not to use getcwd: on some systems getcwd forks, which is expensive and may in fact be impossible for large programs like tex. If your system needs this define and it is not detected by configure, let me know. -- Olaf Weber <[email protected] */ #if defined (HAVE_GETCWD) && !defined (GETCWD_FORKS) char path[PATH_MAX + 1]; #if defined(WIN32) string pp; #endif if (getcwd (path, PATH_MAX + 1) == NULL) { FATAL_PERROR ("getcwd"); } #if defined(WIN32) for (pp = path; *pp; pp++) { if (*pp == '\\') *pp = '/'; #if defined (KPSE_COMPAT_API) else if (IS_KANJI(pp)) pp++; #endif } #endif return xstrdup (path); #elif defined (HAVE_GETWD) char path[PATH_MAX + 1]; if (getwd (path) == NULL) { FATAL_PERROR ("getwd"); } return xstrdup (path); #else /* (not HAVE_GETCWD || GETCWD_FORKS) && not HAVE_GETWD */ struct stat root_stat, cwd_stat; string cwd_path = (string)xmalloc(2); /* In case we assign "/" below. */ *cwd_path = 0; /* Find the inodes of the root and current directories. */ root_stat = xstat("/"); cwd_stat = xstat("."); /* Go up the directory hierarchy until we get to root, prepending each directory we pass through to `cwd_path'. */ while (!SAME_FILE_P(root_stat, cwd_stat)) { struct dirent *e; DIR *parent_dir; boolean found = false; xchdir(".."); parent_dir = xopendir("."); /* Look through the parent directory for the entry with the same inode, so we can get its name. */ while ((e = readdir (parent_dir)) != NULL && !found) { struct stat test_stat; test_stat = xlstat(e->d_name); if (SAME_FILE_P(test_stat, cwd_stat)) { /* We've found it. Prepend the pathname. */ string temp = cwd_path; cwd_path = concat3("/", e->d_name, cwd_path); free(temp); /* Set up to test the next parent. */ cwd_stat = xstat("."); /* Stop reading this directory. */ found = true; } } if (!found) LIB_FATAL2("No inode %d/device %d in parent directory", cwd_stat.st_ino, cwd_stat.st_dev); xclosedir(parent_dir); } /* If the current directory is the root, cwd_path will be the empty string, and we will have not gone through the loop. */ if (*cwd_path == 0) strcpy(cwd_path, "/"); else /* Go back to where we were. */ xchdir(cwd_path); #ifdef DOSISH /* Prepend the drive letter to CWD_PATH, since this technique never tells us what the drive is. Note that on MS-DOS/MS-Windows, the branch that works around missing `getwd' will probably only work for DJGPP (which does have `getwd'), because only DJGPP reports meaningful st_ino numbers. But someday, somebody might need this... */ { char drive[3]; string temp = cwd_path; /* Make the drive letter lower-case, unless it is beyond Z: (yes, there ARE such drives, in case of Novell Netware on MS-DOS). */ drive[0] = root_stat.st_dev + (root_stat.st_dev < 26 ? 'a' : 'A'); drive[1] = ':'; drive[2] = '\0'; cwd_path = concat(drive, cwd_path); free(temp); } #endif return cwd_path; #endif /* (not HAVE_GETCWD || GETCWD_FORKS) && not HAVE_GETWD */ }