1 /* $NetBSD: searchpath.cpp,v 1.1.1.1 2016/01/13 18:41:48 christos Exp $ */ 2 3 // -*- C++ -*- 4 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2003, 2005 5 Free Software Foundation, Inc. 6 Written by James Clark (jjc@jclark.com) 7 8 This file is part of groff. 9 10 groff is free software; you can redistribute it and/or modify it under 11 the terms of the GNU General Public License as published by the Free 12 Software Foundation; either version 2, or (at your option) any later 13 version. 14 15 groff is distributed in the hope that it will be useful, but WITHOUT ANY 16 WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 for more details. 19 20 You should have received a copy of the GNU General Public License along 21 with groff; see the file COPYING. If not, write to the Free Software 22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 23 24 #include "lib.h" 25 26 #include <stdlib.h> 27 #include <assert.h> 28 #include <errno.h> 29 30 #include "searchpath.h" 31 #include "nonposix.h" 32 33 #ifdef _WIN32 34 # include "relocate.h" 35 #else 36 # define relocate(path) strsave(path) 37 #endif 38 39 search_path::search_path(const char *envvar, const char *standard, 40 int add_home, int add_current) 41 { 42 char *home = 0; 43 if (add_home) 44 home = getenv("HOME"); 45 char *e = 0; 46 if (envvar) 47 e = getenv(envvar); 48 dirs = new char[((e && *e) ? strlen(e) + 1 : 0) 49 + (add_current ? 1 + 1 : 0) 50 + ((home && *home) ? strlen(home) + 1 : 0) 51 + ((standard && *standard) ? strlen(standard) : 0) 52 + 1]; 53 *dirs = '\0'; 54 if (e && *e) { 55 strcat(dirs, e); 56 strcat(dirs, PATH_SEP); 57 } 58 if (add_current) { 59 strcat(dirs, "."); 60 strcat(dirs, PATH_SEP); 61 } 62 if (home && *home) { 63 strcat(dirs, home); 64 strcat(dirs, PATH_SEP); 65 } 66 if (standard && *standard) 67 strcat(dirs, standard); 68 init_len = strlen(dirs); 69 } 70 71 search_path::~search_path() 72 { 73 // dirs is always allocated 74 a_delete dirs; 75 } 76 77 void search_path::command_line_dir(const char *s) 78 { 79 char *old = dirs; 80 unsigned old_len = strlen(old); 81 unsigned slen = strlen(s); 82 dirs = new char[old_len + 1 + slen + 1]; 83 memcpy(dirs, old, old_len - init_len); 84 char *p = dirs; 85 p += old_len - init_len; 86 if (init_len == 0) 87 *p++ = PATH_SEP_CHAR; 88 memcpy(p, s, slen); 89 p += slen; 90 if (init_len > 0) { 91 *p++ = PATH_SEP_CHAR; 92 memcpy(p, old + old_len - init_len, init_len); 93 p += init_len; 94 } 95 *p++ = '\0'; 96 a_delete old; 97 } 98 99 FILE *search_path::open_file(const char *name, char **pathp) 100 { 101 assert(name != 0); 102 if (IS_ABSOLUTE(name) || *dirs == '\0') { 103 FILE *fp = fopen(name, "r"); 104 if (fp) { 105 if (pathp) 106 *pathp = strsave(name); 107 return fp; 108 } 109 else 110 return 0; 111 } 112 unsigned namelen = strlen(name); 113 char *p = dirs; 114 for (;;) { 115 char *end = strchr(p, PATH_SEP_CHAR); 116 if (!end) 117 end = strchr(p, '\0'); 118 int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; 119 char *origpath = new char[(end - p) + need_slash + namelen + 1]; 120 memcpy(origpath, p, end - p); 121 if (need_slash) 122 origpath[end - p] = '/'; 123 strcpy(origpath + (end - p) + need_slash, name); 124 #if 0 125 fprintf(stderr, "origpath `%s'\n", origpath); 126 #endif 127 char *path = relocate(origpath); 128 a_delete origpath; 129 #if 0 130 fprintf(stderr, "trying `%s'\n", path); 131 #endif 132 FILE *fp = fopen(path, "r"); 133 if (fp) { 134 if (pathp) 135 *pathp = path; 136 else 137 a_delete path; 138 return fp; 139 } 140 a_delete path; 141 if (*end == '\0') 142 break; 143 p = end + 1; 144 } 145 return 0; 146 } 147 148 FILE *search_path::open_file_cautious(const char *name, char **pathp, 149 const char *mode) 150 { 151 if (!mode) 152 mode = "r"; 153 bool reading = (strchr(mode, 'r') != 0); 154 if (name == 0 || strcmp(name, "-") == 0) { 155 if (pathp) 156 *pathp = strsave(reading ? "stdin" : "stdout"); 157 return (reading ? stdin : stdout); 158 } 159 if (!reading || IS_ABSOLUTE(name) || *dirs == '\0') { 160 FILE *fp = fopen(name, mode); 161 if (fp) { 162 if (pathp) 163 *pathp = strsave(name); 164 return fp; 165 } 166 else 167 return 0; 168 } 169 unsigned namelen = strlen(name); 170 char *p = dirs; 171 for (;;) { 172 char *end = strchr(p, PATH_SEP_CHAR); 173 if (!end) 174 end = strchr(p, '\0'); 175 int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; 176 char *origpath = new char[(end - p) + need_slash + namelen + 1]; 177 memcpy(origpath, p, end - p); 178 if (need_slash) 179 origpath[end - p] = '/'; 180 strcpy(origpath + (end - p) + need_slash, name); 181 #if 0 182 fprintf(stderr, "origpath `%s'\n", origpath); 183 #endif 184 char *path = relocate(origpath); 185 a_delete origpath; 186 #if 0 187 fprintf(stderr, "trying `%s'\n", path); 188 #endif 189 FILE *fp = fopen(path, mode); 190 if (fp) { 191 if (pathp) 192 *pathp = path; 193 else 194 a_delete path; 195 return fp; 196 } 197 int err = errno; 198 a_delete path; 199 if (err != ENOENT) 200 { 201 errno = err; 202 return 0; 203 } 204 if (*end == '\0') 205 break; 206 p = end + 1; 207 } 208 errno = ENOENT; 209 return 0; 210 } 211