summaryrefslogtreecommitdiffstats
path: root/src/libs/libgroff/searchpath.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/libgroff/searchpath.cpp')
-rw-r--r--src/libs/libgroff/searchpath.cpp215
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: