string kpse_truncate_filename P1C(const_string, name) { unsigned c_len = 0; /* Length of current component. */ unsigned ret_len = 0; /* Length of constructed result. */ /* Allocate enough space. */ string ret = (string) xmalloc (strlen (name) + 1); for (; *name; name++) { if (IS_DIR_SEP (*name) || IS_DEVICE_SEP (*name)) { /* At a directory delimiter, reset component length. */ c_len = 0; } else if (c_len > NAME_MAX) { /* If past the max for a component, ignore this character. */ continue; } /* Copy this character. */ ret[ret_len++] = *name; c_len++; } ret[ret_len] = 0; return ret; }
static void dir_list_add (str_llist_type *l, string dir) { char last_char = dir[strlen (dir) - 1]; string saved_dir = IS_DIR_SEP_CH (last_char) || IS_DEVICE_SEP (last_char) ? xstrdup (dir) : concat (dir, DIR_SEP_STRING); str_llist_add (l, saved_dir); }
/* Return the current working directory. Returns NULL on errors. Any other returned value must be freed with free. This is used only when get_current_dir_name is not defined on the system. */ char* get_current_dir_name (void) { char *buf; const char *pwd; struct stat dotstat, pwdstat; /* If PWD is accurate, use it instead of calling getwd. PWD is sometimes a nicer name, and using it may avoid a fatal error if a parent directory is searchable but not readable. */ if ((pwd = egetenv ("PWD")) != 0 && (IS_DIRECTORY_SEP (*pwd) || (*pwd && IS_DEVICE_SEP (pwd[1]))) && stat (pwd, &pwdstat) == 0 && stat (".", &dotstat) == 0 && dotstat.st_ino == pwdstat.st_ino && dotstat.st_dev == pwdstat.st_dev #ifdef MAXPATHLEN && strlen (pwd) < MAXPATHLEN #endif ) { buf = (char *) xmalloc (strlen (pwd) + 1); strcpy (buf, pwd); } #ifdef HAVE_GETCWD else { size_t buf_size = 1024; for (;;) { int tmp_errno; buf = malloc (buf_size); if (! buf) break; if (getcwd (buf, buf_size) == buf) break; tmp_errno = errno; free (buf); if (tmp_errno != ERANGE) { errno = tmp_errno; return NULL; } buf_size *= 2; if (! buf_size) { errno = ENOMEM; return NULL; } } } #else else {
boolean kpathsea_absolute_p (kpathsea kpse, const_string filename, boolean relative_ok) { #ifndef VMS boolean absolute; boolean explicit_relative; #endif #ifdef VMS #include <string.h> (void)kpse; /* currenty not used */ return strcspn (filename, "]>:") != strlen (filename); #else /* not VMS */ absolute = IS_DIR_SEP (*filename) #ifdef DOSISH /* Novell allows non-alphanumeric drive letters. */ || (*filename && IS_DEVICE_SEP (filename[1])) #endif /* DOSISH */ #ifdef WIN32 /* UNC names */ || (*filename == '\\' && filename[1] == '\\') || (*filename == '/' && filename[1] == '/') #endif #ifdef AMIGA /* Colon anywhere means a device. */ || strchr (filename, ':') #endif /* AMIGA */ ; explicit_relative = relative_ok #ifdef AMIGA /* Leading / is like `../' on Unix and DOS. Allow Unix syntax, too, though, because of possible patch programs like `UnixDirsII' by Martin Scott. */ && IS_DIR_SEP (*filename) || 0 #endif /* AMIGA */ && (*filename == '.' && (IS_DIR_SEP (filename[1]) || (filename[1] == '.' && IS_DIR_SEP (filename[2])))); (void)kpse; /* currenty not used */ /* FIXME: On UNIX an IS_DIR_SEP of any but the last character in the name implies relative. */ return absolute || explicit_relative; #endif /* not VMS */ }
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 */ }