diff options
Diffstat (limited to 'src/libs/libgroff/searchpath.cpp')
-rw-r--r-- | src/libs/libgroff/searchpath.cpp | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/src/libs/libgroff/searchpath.cpp b/src/libs/libgroff/searchpath.cpp new file mode 100644 index 0000000..6062e8d --- /dev/null +++ b/src/libs/libgroff/searchpath.cpp @@ -0,0 +1,215 @@ +/* Copyright (C) 1989-2020 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "lib.h" + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> + +#include "searchpath.h" +#include "nonposix.h" + +#ifdef _WIN32 +# include "relocate.h" +#else +# define relocate(path) strsave(path) +#endif + +search_path::search_path(const char *envvar, const char *standard, + int add_home, int add_current) +{ + char *home = 0; + if (add_home) + home = getenv("HOME"); + char *e = 0; + if (envvar) + e = getenv(envvar); + dirs = new char[((e && *e) ? strlen(e) + 1 : 0) + + (add_current ? 1 + 1 : 0) + + ((home && *home) ? strlen(home) + 1 : 0) + + ((standard && *standard) ? strlen(standard) : 0) + + 1]; + *dirs = '\0'; + if (e && *e) { + strcat(dirs, e); + strcat(dirs, PATH_SEP); + } + if (add_current) { + strcat(dirs, "."); + strcat(dirs, PATH_SEP); + } + if (home && *home) { + strcat(dirs, home); + strcat(dirs, PATH_SEP); + } + if (standard && *standard) + strcat(dirs, standard); + init_len = strlen(dirs); +} + +search_path::~search_path() +{ + // dirs is always allocated + delete[] dirs; +} + +void search_path::command_line_dir(const char *s) +{ + char *old = dirs; + unsigned old_len = strlen(old); + unsigned slen = strlen(s); + dirs = new char[old_len + 1 + slen + 1]; + memcpy(dirs, old, old_len - init_len); + char *p = dirs; + p += old_len - init_len; + if (init_len == 0) + *p++ = PATH_SEP_CHAR; + memcpy(p, s, slen); + p += slen; + if (init_len > 0) { + *p++ = PATH_SEP_CHAR; + memcpy(p, old + old_len - init_len, init_len); + p += init_len; + } + *p++ = '\0'; + delete[] old; +} + +FILE *search_path::open_file(const char *name, char **pathp) +{ + assert(name != 0); + if (IS_ABSOLUTE(name) || *dirs == '\0') { + FILE *fp = fopen(name, "r"); + if (fp) { + if (pathp) + *pathp = strsave(name); + return fp; + } + else + return 0; + } + unsigned namelen = strlen(name); + char *p = dirs; + for (;;) { + char *end = strchr(p, PATH_SEP_CHAR); + if (!end) + end = strchr(p, '\0'); + int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; + char *origpath = new char[(end - p) + need_slash + namelen + 1]; + memcpy(origpath, p, end - p); + if (need_slash) + origpath[end - p] = '/'; + strcpy(origpath + (end - p) + need_slash, name); +#if 0 + fprintf(stderr, "origpath '%s'\n", origpath); +#endif + char *path = relocate(origpath); + delete[] origpath; +#if 0 + fprintf(stderr, "trying '%s'\n", path); +#endif + FILE *fp = fopen(path, "r"); + int err = errno; + if (fp) { + if (pathp) + *pathp = path; + else { + free(path); + errno = err; + } + return fp; + } + free(path); + errno = err; + if (*end == '\0') + break; + p = end + 1; + } + return 0; +} + +FILE *search_path::open_file_cautious(const char *name, char **pathp, + const char *mode) +{ + if (!mode) + mode = "r"; + bool reading = (strchr(mode, 'r') != 0); + if (name == 0 || strcmp(name, "-") == 0) { + if (pathp) + *pathp = strsave(reading ? "stdin" : "stdout"); + return (reading ? stdin : stdout); + } + if (!reading || IS_ABSOLUTE(name) || *dirs == '\0') { + FILE *fp = fopen(name, mode); + if (fp) { + if (pathp) + *pathp = strsave(name); + return fp; + } + else + return 0; + } + unsigned namelen = strlen(name); + char *p = dirs; + for (;;) { + char *end = strchr(p, PATH_SEP_CHAR); + if (!end) + end = strchr(p, '\0'); + int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; + char *origpath = new char[(end - p) + need_slash + namelen + 1]; + memcpy(origpath, p, end - p); + if (need_slash) + origpath[end - p] = '/'; + strcpy(origpath + (end - p) + need_slash, name); +#if 0 + fprintf(stderr, "origpath '%s'\n", origpath); +#endif + char *path = relocate(origpath); + delete[] origpath; +#if 0 + fprintf(stderr, "trying '%s'\n", path); +#endif + FILE *fp = fopen(path, mode); + int err = errno; + if (fp) { + if (pathp) + *pathp = path; + else { + free(path); + errno = err; + } + return fp; + } + free(path); + errno = err; + if (err != ENOENT) + return 0; + if (*end == '\0') + break; + p = end + 1; + } + errno = ENOENT; + return 0; +} + +// Local Variables: +// fill-column: 72 +// mode: C++ +// End: +// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: |