static string kpse_expand_kpse_dot P1C(string, path) { string ret, elt; string kpse_dot = getenv("KPSE_DOT"); #ifdef MSDOS boolean malloced_kpse_dot = false; #endif if (kpse_dot == NULL) return path; ret = (string)xmalloc(1); *ret = 0; #ifdef MSDOS /* Some setups of ported Bash force $KPSE_DOT to have the //d/foo/bar form (when `pwd' is used), which is not understood by libc and the OS. Convert them back to the usual d:/foo/bar form. */ if (kpse_dot[0] == '/' && kpse_dot[1] == '/' && kpse_dot[2] >= 'A' && kpse_dot[2] <= 'z' && kpse_dot[3] == '/') { kpse_dot++; kpse_dot = xstrdup (kpse_dot); kpse_dot[0] = kpse_dot[1]; /* drive letter */ kpse_dot[1] = ':'; malloced_kpse_dot = true; } #endif for (elt = kpse_path_element (path); elt; elt = kpse_path_element (NULL)) { string save_ret = ret; boolean ret_copied = true; /* We assume that the !! magic is only used on absolute components. Single "." gets special treatment, as does "./" or its equivalent. */ if (kpse_absolute_p (elt, false) || (elt[0] == '!' && elt[1] == '!')) { ret = concat3(ret, elt, ENV_SEP_STRING); } else if (elt[0] == '.' && elt[1] == 0) { ret = concat3 (ret, kpse_dot, ENV_SEP_STRING); #ifndef VMS } else if (elt[0] == '.' && IS_DIR_SEP(elt[1])) { ret = concatn (ret, kpse_dot, elt + 1, ENV_SEP_STRING, NULL); } else if (*elt) { ret = concatn (ret, kpse_dot, DIR_SEP_STRING, elt, ENV_SEP_STRING, NULL); #endif } else { /* omit empty path elements from TEXMFCNF. See http://bugs.debian.org/358330. */ ret_copied = false; } if (ret_copied) free (save_ret); } #ifdef MSDOS if (malloced_kpse_dot) free (kpse_dot); #endif ret[strlen (ret) - 1] = 0; return ret; }
static str_list_type dir_list_search_list P3C(str_llist_type *, dirs, const_string*, names, boolean, search_all) { str_llist_elt_type *elt; str_list_type ret; unsigned allocated = INIT_ALLOC; string potential = XTALLOC(allocated, char); ret = str_list_init (); for (elt = *dirs; elt; elt = STR_LLIST_NEXT(*elt)) { const_string dir = STR_LLIST (*elt); unsigned dir_len = strlen (dir); int i; for (i = 0; names[i]; i++) { const_string name = names[i]; unsigned name_len; /* Don't bother with absolute & explicit relative. */ if (kpse_absolute_p(name, true)) continue; name_len = strlen(name); while (dir_len + name_len + 1 > allocated) { allocated += allocated; XRETALLOC (potential, allocated, char); } strcpy (potential, dir); strcat (potential+dir_len, name); if (kpse_readable_file (potential)) { str_list_add (&ret, potential); /* Move this element towards the top of the list. */ str_llist_float (dirs, elt); /* If caller only wanted one file returned, no need to terminate the list with NULL; the caller knows to only look at the first element. */ if (!search_all) return ret; /* Start new filename. */ allocated = INIT_ALLOC; potential = XTALLOC(allocated, char); } } } /* If we get here, either we didn't find any files, or we were finding all the files. But we're done with the last filename, anyway. */ free (potential); return ret; }
int main() { char **name; char *t[] = { "./foo", "\\\\server\\foo\\bar", "ftp://localhost/foo" }; for (name = t; name - t < sizeof(t)/sizeof(char*); name++) { printf ("Path `%s' %s absolute.\n", *name, kpse_absolute_p(*name, true) ? "is" : "is not"); } }
/* * Derived from BSD basename */ char *basename(char *str, const char *suffix){ char *p; int len = 0; const char *t; char *base; printf("basename of %s = ", str); #ifdef KPATHSEA for (p = base = (NAME_BEGINS_WITH_DEVICE(str) ? str+2 : str); *p; p++) { #else for (p = base = str; *p; p++) { #endif /* if (*p++ == DIRSEP) { base = p; len = 0; } */ if (IS_DIR_SEP(*p)) { base = p+1; len = 0; } else len++; } printf("%s\n", base); if (suffix != NULL) { for (t = suffix; *t; ++t); do { len--; t--; p--; if (*t != *p) break; if (t == suffix) { char *bn; if (len == 0) return NULL; bn = malloc(len+1); if (bn == NULL) fatal("Out of memory\n"); strncpy(bn, base, len); *(bn+len) = '\0'; /* RA */ return bn; } } while (p > base); } return base; } /* * Return true if name can be the name of a PostScript resource * (no extension and no absolute pathname). */ int ps_resource(const char *name) { if (strchr(name, '.')) return 0 ; #ifdef KPATHSEA if (kpse_absolute_p(name, true)) return 0; #else if (strchr(name, DIRSEP)) return 0 ; #endif return 1; }
search P3C(kpse_file_format_type, format, char *, file, char *, mode) { FILE *ret; string found_name; #ifdef SECURE /* This change suggested by [email protected] to disallow reading of arbitrary files. */ if (secure && kpse_absolute_p (file)) return NULL; #endif /* Most file looked for through here must exist -- the exception is VF's. Bitmap fonts go through pksearch. */ found_name = kpse_find_file (file, format, format != vfpath); if (found_name) { unsigned len = strlen (found_name); #ifndef AMIGA if ((format == figpath || format == headerpath) && ((len > 2 && FILESTRCASEEQ (found_name + len - 2, ".Z")) || (len > 3 && FILESTRCASEEQ (found_name + len - 3, ".gz")))) { /* FIXME : use zlib instead of gzip ! */ char *cmd = concat3 (GUNZIP, " -c ", found_name); ret = popen (cmd, "r"); to_close = USE_PCLOSE ; } else { #endif /* not AMIGA */ ret = fopen (found_name, mode); to_close = USE_FCLOSE ; #ifndef AMIGA } #endif /* not AMIGA */ if (!ret) FATAL_PERROR (found_name); /* Free result of previous search. */ if (realnameoffile) free (realnameoffile); /* Save in `name' and `realnameoffile' because other routines access those globals. Sigh. */ realnameoffile = found_name; strcpy(name, realnameoffile); } else ret = NULL; return ret; } /* end search */
boolean open_output (FILE **f_ptr, const_string fopen_mode) { string fname; boolean absolute = kpse_absolute_p(nameoffile+1, false); /* If we have an explicit output directory, use it. */ if (output_directory && !absolute) { fname = concat3(output_directory, DIR_SEP_STRING, nameoffile + 1); } else { fname = nameoffile + 1; } /* Is the filename openable as given? */ *f_ptr = fopen (fname, fopen_mode); if (!*f_ptr) { /* Can't open as given. Try the envvar. */ string texmfoutput = kpse_var_value("TEXMFOUTPUT"); if (texmfoutput && *texmfoutput && !absolute) { if (fname != nameoffile + 1) free(fname); fname = concat3(texmfoutput, DIR_SEP_STRING, nameoffile+1); *f_ptr = fopen(fname, fopen_mode); } } /* If this succeeded, change nameoffile accordingly. */ if (*f_ptr) { if (fname != nameoffile + 1) { free (nameoffile); namelength = strlen (fname); nameoffile = xmalloc (namelength + 2); strcpy (nameoffile + 1, fname); } recorder_record_output (fname); } if (fname != nameoffile +1) free(fname); return *f_ptr != NULL; }
static void log_search P1C(str_list_type, filenames) { static FILE *log_file = NULL; static boolean first_time = true; /* Need to open the log file? */ if (first_time) { /* Get name from either envvar or config file. */ string log_name = kpse_var_value ("TEXMFLOG"); first_time = false; if (log_name) { log_file = fopen (log_name, FOPEN_A_MODE); if (!log_file) perror (log_name); free (log_name); } } if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH) || log_file) { unsigned e; /* FILENAMES should never be null, but safety doesn't hurt. */ for (e = 0; e < STR_LIST_LENGTH (filenames) && STR_LIST_ELT (filenames, e); e++) { string filename = STR_LIST_ELT (filenames, e); /* Only record absolute filenames, for privacy. */ if (log_file && kpse_absolute_p (filename, false)) fprintf (log_file, "%lu %s\n", (long unsigned) time (NULL), filename); /* And show them online, if debugging. We've already started the debugging line in `search', where this is called, so just print the filename here, don't use DEBUGF. */ if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) { putc (' ', stderr); fputs (filename, stderr); } } } }
string kpse_find_glyph P4C(const_string, passed_fontname, unsigned, dpi, kpse_file_format_type, format, kpse_glyph_file_type *, glyph_file) { string ret; kpse_glyph_source_type source; string fontname = (string) passed_fontname; /* discard const */ /* Start the search: try the name we're given. */ source = kpse_glyph_source_normal; xputenv ("KPATHSEA_NAME", fontname); ret = try_resolution (fontname, dpi, format, glyph_file); /* Try all the various possibilities in order of preference. */ if (!ret) { /* Maybe FONTNAME was an alias. */ source = kpse_glyph_source_alias; ret = try_fontmap (&fontname, dpi, format, glyph_file); /* If not an alias, try creating it on the fly with mktexpk, unless FONTNAME is absolute or explicitly relative. */ if (!ret && !kpse_absolute_p (fontname, true)) { source = kpse_glyph_source_maketex; /* `try_resolution' leaves the envvar set randomly. */ xputenv_int ("KPATHSEA_DPI", dpi); ret = kpse_make_tex (format, fontname); } /* If mktex... succeeded, set return struct. Doesn't make sense for `kpse_make_tex' to set it, since it can only succeed or fail, unlike the other routines. */ if (ret) { KPSE_GLYPH_FILE_DPI (*glyph_file) = dpi; KPSE_GLYPH_FILE_NAME (*glyph_file) = fontname; } /* If mktex... failed, try any fallback resolutions. */ else { if (kpse_fallback_resolutions) ret = try_fallback_resolutions (fontname, dpi, format, glyph_file); /* We're down to the font of last resort. */ if (!ret && kpse_fallback_font) { const_string name = kpse_fallback_font; source = kpse_glyph_source_fallback; xputenv ("KPATHSEA_NAME", name); /* As before, first try it at the given size. */ ret = try_resolution (name, dpi, format, glyph_file); /* The fallback font at the fallback resolutions. */ if (!ret && kpse_fallback_resolutions) ret = try_fallback_resolutions (name, dpi, format, glyph_file); } } } /* If RET is null, then the caller is not supposed to look at GLYPH_FILE, so it doesn't matter if we assign something incorrect. */ KPSE_GLYPH_FILE_SOURCE (*glyph_file) = source; /* FIXME: fontname may have been allocated, but (worse) it may also have been assigned to struct that's passed out of this function. if (fontname != passed_fontname) free (fontname); */ return ret; }
boolean open_input (FILE **f_ptr, int filefmt, const_string fopen_mode) { string fname = NULL; #ifdef FUNNY_CORE_DUMP /* This only applies if a preloaded TeX/Metafont is being made; it allows automatic creation of the core dump (typing ^\ loses since that requires manual intervention). */ if ((filefmt == kpse_tex_format || filefmt == kpse_mf_format || filefmt == kpse_mp_format) && STREQ (nameoffile + 1, "HackyInputFileNameForCoreDump.tex")) funny_core_dump (); #endif /* We havent found anything yet. */ *f_ptr = NULL; if (fullnameoffile) free(fullnameoffile); fullnameoffile = NULL; /* Look in -output-directory first, if the filename is not absolute. This is because .aux and other such files will get written to the output directory, and we have to be able to read them from there. We only look for the name as-is. */ if (output_directory && !kpse_absolute_p (nameoffile+1, false)) { fname = concat3 (output_directory, DIR_SEP_STRING, nameoffile + 1); *f_ptr = fopen (fname, fopen_mode); if (*f_ptr) { free (nameoffile); namelength = strlen (fname); nameoffile = xmalloc (namelength + 2); strcpy (nameoffile + 1, fname); fullnameoffile = fname; } else { free (fname); } } /* No file means do the normal search. */ if (*f_ptr == NULL) { /* A negative FILEFMT means don't use a path. */ if (filefmt < 0) { /* no_file_path, for BibTeX .aux files and MetaPost things. */ *f_ptr = fopen(nameoffile + 1, fopen_mode); /* FIXME... fullnameoffile = xstrdup(nameoffile + 1); */ } else { /* The only exception to `must_exist' being true is \openin, for which we set `tex_input_type' to 0 in the change file. */ /* According to the pdfTeX people, pounding the disk for .vf files is overkill as well. A more general solution would be nice. */ boolean must_exist = (filefmt != kpse_tex_format || texinputtype) && (filefmt != kpse_vf_format); fname = kpse_find_file (nameoffile + 1, (kpse_file_format_type)filefmt, must_exist); if (fname) { fullnameoffile = xstrdup(fname); /* If we found the file in the current directory, don't leave the `./' at the beginning of `nameoffile', since it looks dumb when `tex foo' says `(./foo.tex ... )'. On the other hand, if the user said `tex ./foo', and that's what we opened, then keep it -- the user specified it, so we shouldn't remove it. */ if (fname[0] == '.' && IS_DIR_SEP (fname[1]) && (nameoffile[1] != '.' || !IS_DIR_SEP (nameoffile[2]))) { unsigned i = 0; while (fname[i + 2] != 0) { fname[i] = fname[i + 2]; i++; } fname[i] = 0; } /* kpse_find_file always returns a new string. */ free (nameoffile); namelength = strlen (fname); nameoffile = xmalloc (namelength + 2); strcpy (nameoffile + 1, fname); free (fname); /* This fopen is not allowed to fail. */ #if defined(PTEX) && !defined(WIN32) if (filefmt == kpse_tex_format || filefmt == kpse_bib_format) { *f_ptr = nkf_open (nameoffile + 1, fopen_mode); } else #endif *f_ptr = xfopen (nameoffile + 1, fopen_mode); } } } if (*f_ptr) { recorder_record_input (nameoffile + 1); /* If we just opened a TFM file, we have to read the first byte, to pretend we're Pascal. See tex.ch and mp.ch. Ditto for the ocp/ofm Omega file formats. */ if (filefmt == kpse_tfm_format) { tfmtemp = getc (*f_ptr); /* We intentionally do not check for EOF here, i.e., an empty TFM file. TeX will see the 255 byte and complain about a bad TFM file, which is what we want. */ } else if (filefmt == kpse_ocp_format) { ocptemp = getc (*f_ptr); } else if (filefmt == kpse_ofm_format) { tfmtemp = getc (*f_ptr); } } return *f_ptr != NULL; }
search_list P4C(const_string, path, const_string*, names, boolean, must_exist, boolean, all) { str_list_type ret_list; const_string* namep; string elt; boolean done = false; #ifdef __DJGPP__ /* We will use `stat' heavily, so let's request for the fastest possible version of `stat', by telling it what members of struct stat do we really need. We need to set this on each call because this is a library function; the caller might need other options from `stat'. Thus save the flags and restore them before exit. This call tells `stat' that we do NOT need to recognize executable files (neither by an extension nor by a magic signature); that we do NOT need time stamp of root directories; and that we do NOT need the write access bit in st_mode. Note that `kpse_set_progname' needs the EXEC bits, but it was already called by the time we get here. */ unsigned short save_djgpp_flags = _djstat_flags; _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT | _STAT_ROOT_TIME | _STAT_WRITEBIT; #endif ret_list = str_list_init(); if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) { DEBUGF1 ("start search(files=[%s", *names); for (namep = names+1; *namep != NULL; namep++) { fputc(' ', stderr); fputs(*namep, stderr); } fprintf (stderr, "], must_exist=%d, find_all=%d, path=%s).\n", must_exist, all, path); } /* No need to do any expansion on names. */ for (namep = names; *namep; namep++) { if (kpse_absolute_p(*namep, true) && kpse_readable_file(*namep)) { str_list_add(&ret_list, xstrdup(*namep)); /* I know, I know... */ goto out; } } /* Look at each path element in turn. */ for (elt = kpse_path_element (path); !done && elt; elt = kpse_path_element (NULL)) { str_list_type *found; boolean allow_disk_search = true; if (elt[0] == '!' && elt[1] == '!') { /* !! magic -> disallow disk searches. */ allow_disk_search = false; elt += 2; } /* See elt-dirs.c for side effects of this function. */ kpse_normalize_path(elt); /* Try ls-R, unless we're searching for texmf.cnf. */ found = first_search ? NULL : kpse_db_search_list(names, elt, all); /* Search the filesystem if (1) the path spec allows it, and either (2a) we are searching for texmf.cnf ; or (2b) no db exists; or (2c) no db's are relevant to this elt; or (3) MUST_EXIST && NAME was not in the db. In (2*), `found' will be NULL. In (3), `found' will be an empty list. */ if (allow_disk_search && (!found || (must_exist && !STR_LIST(*found)))) { str_llist_type *dirs = kpse_element_dirs (elt); if (dirs && *dirs) { if (!found) found = XTALLOC1 (str_list_type); *found = dir_list_search_list (dirs, names, all); } } /* Did we find anything? */ if (found && STR_LIST (*found)) { if (all) { str_list_concat (&ret_list, *found); } else { str_list_add (&ret_list, STR_LIST_ELT (*found, 0)); done = true; } } } out: if (STR_LIST_LENGTH (ret_list) == 0 || (all && STR_LIST_LAST_ELT (ret_list) != NULL)) str_list_add (&ret_list, NULL); if (first_search) { first_search = false; } else { /* Record the filenames we found, if desired. And wrap them in a debugging line if we're doing that. */ if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) { DEBUGF1 ("search([%s", *names); for (namep = names+1; *namep != NULL; namep++) { fputc(' ', stderr); fputs(*namep, stderr); } fputs ("]) =>", stderr); } log_search (ret_list); if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) putc ('\n', stderr); } #ifdef __DJGPP__ /* Undo any side effects. */ _djstat_flags = save_djgpp_flags; #endif return STR_LIST (ret_list); }
search P4C(const_string, path, const_string, original_name, boolean, must_exist, boolean, all) { str_list_type ret_list; string name; boolean absolute_p; #ifdef __DJGPP__ /* We will use `stat' heavily, so let's request for the fastest possible version of `stat', by telling it what members of struct stat do we really need. We need to set this on each call because this is a library function; the caller might need other options from `stat'. Thus save the flags and restore them before exit. This call tells `stat' that we do NOT need to recognize executable files (neither by an extension nor by a magic signature); that we do NOT need time stamp of root directories; and that we do NOT need the write access bit in st_mode. Note that `kpse_set_progname' needs the EXEC bits, but it was already called by the time we get here. */ unsigned short save_djgpp_flags = _djstat_flags; _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT | _STAT_ROOT_TIME | _STAT_WRITEBIT; #endif /* Make a leading ~ count as an absolute filename, and expand $FOO's. */ name = kpse_expand (original_name); /* If the first name is absolute or explicitly relative, no need to consider PATH at all. */ absolute_p = kpse_absolute_p (name, true); if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) DEBUGF4 ("start search(file=%s, must_exist=%d, find_all=%d, path=%s).\n", name, must_exist, all, path); /* Find the file(s). */ ret_list = absolute_p ? absolute_search (name) : path_search (path, name, must_exist, all); /* Append NULL terminator if we didn't find anything at all, or we're supposed to find ALL and the list doesn't end in NULL now. */ if (STR_LIST_LENGTH (ret_list) == 0 || (all && STR_LIST_LAST_ELT (ret_list) != NULL)) str_list_add (&ret_list, NULL); /* The very first search is for texmf.cnf. We can't log that, since we want to allow setting TEXMFLOG in texmf.cnf. */ if (first_search) { first_search = false; } else { /* Record the filenames we found, if desired. And wrap them in a debugging line if we're doing that. */ if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) DEBUGF1 ("search(%s) =>", original_name); log_search (ret_list); if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) putc ('\n', stderr); } #ifdef __DJGPP__ /* Undo any side effects. */ _djstat_flags = save_djgpp_flags; #endif return STR_LIST (ret_list); }
static string selfdir P1C(const_string, argv0) { string ret = NULL; string self = NULL; if (kpse_absolute_p (argv0, true)) { self = xstrdup (argv0); } else { #ifdef AMIGA #include <dos.h> #include <proto/dos.h> #include <proto/exec.h> BPTR lock; struct DosLibrary *DOSBase = (struct DosLibrary *) OpenLibrary ("dos.library", 0L); assert (DOSBase); self = xmalloc (BUFSIZ); lock = findpath (argv0); if (lock != ((BPTR) -1)) { if (getpath (lock, self) == -1) { *self = '\0'; } else { strcat (self,DIR_SEP_STRING); strcat (self,argv0); } UnLock (lock); } CloseLibrary((struct Library *) DOSBase); #else /* not AMIGA */ string elt; struct stat s; /* Have to check PATH. But don't call kpse_path_search since we don't want to search any ls-R's or do anything special with //'s. */ for (elt = kpse_path_element (getenv ("PATH")); !self && elt; elt = kpse_path_element (NULL)) { string name; /* UNIX tradition interprets the empty path element as "." */ if (*elt == 0) elt = "."; name = concat3 (elt, DIR_SEP_STRING, argv0); /* In order to do this perfectly, we'd have to check the owner bits only if we are the file owner, and the group bits only if we belong to the file group. That's a lot of work, though, and it's not likely that kpathsea will ever be used with a program that's only executable by some classes and not others. See the `file_status' function in execute_cmd.c in bash for what's necessary if we were to do it right. */ if (stat (name, &s) == 0 && s.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) { /* Do not stop at directories. */ if (!S_ISDIR(s.st_mode)) self = name; } } #endif /* not AMIGA */ } /* If argv0 is somehow dir/exename, `self' will still be NULL. */ if (!self) self = concat3 (".", DIR_SEP_STRING, argv0); ret = xdirname (remove_dots (expand_symlinks (self))); free (self); return ret; }