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