1114402Sru// -*- C++ -*- 2151497Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2003, 2005 3114402Sru Free Software Foundation, Inc. 4114402Sru Written by James Clark (jjc@jclark.com) 5114402Sru 6114402SruThis file is part of groff. 7114402Sru 8114402Srugroff is free software; you can redistribute it and/or modify it under 9114402Sruthe terms of the GNU General Public License as published by the Free 10114402SruSoftware Foundation; either version 2, or (at your option) any later 11114402Sruversion. 12114402Sru 13114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 14114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 15114402SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16114402Srufor more details. 17114402Sru 18114402SruYou should have received a copy of the GNU General Public License along 19114402Sruwith groff; see the file COPYING. If not, write to the Free Software 20151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 21114402Sru 22114402Sru#include "lib.h" 23114402Sru 24114402Sru#include <stdlib.h> 25114402Sru#include <assert.h> 26151497Sru#include <errno.h> 27114402Sru 28114402Sru#include "searchpath.h" 29114402Sru#include "nonposix.h" 30114402Sru 31151497Sru#ifdef _WIN32 32151497Sru# include "relocate.h" 33151497Sru#else 34151497Sru# define relocate(path) strsave(path) 35151497Sru#endif 36151497Sru 37114402Srusearch_path::search_path(const char *envvar, const char *standard, 38114402Sru int add_home, int add_current) 39114402Sru{ 40114402Sru char *home = 0; 41114402Sru if (add_home) 42114402Sru home = getenv("HOME"); 43114402Sru char *e = 0; 44114402Sru if (envvar) 45114402Sru e = getenv(envvar); 46114402Sru dirs = new char[((e && *e) ? strlen(e) + 1 : 0) 47114402Sru + (add_current ? 1 + 1 : 0) 48114402Sru + ((home && *home) ? strlen(home) + 1 : 0) 49114402Sru + ((standard && *standard) ? strlen(standard) : 0) 50114402Sru + 1]; 51114402Sru *dirs = '\0'; 52114402Sru if (e && *e) { 53114402Sru strcat(dirs, e); 54114402Sru strcat(dirs, PATH_SEP); 55114402Sru } 56114402Sru if (add_current) { 57114402Sru strcat(dirs, "."); 58114402Sru strcat(dirs, PATH_SEP); 59114402Sru } 60114402Sru if (home && *home) { 61114402Sru strcat(dirs, home); 62114402Sru strcat(dirs, PATH_SEP); 63114402Sru } 64114402Sru if (standard && *standard) 65114402Sru strcat(dirs, standard); 66114402Sru init_len = strlen(dirs); 67114402Sru} 68114402Sru 69114402Srusearch_path::~search_path() 70114402Sru{ 71114402Sru // dirs is always allocated 72114402Sru a_delete dirs; 73114402Sru} 74114402Sru 75114402Sruvoid search_path::command_line_dir(const char *s) 76114402Sru{ 77114402Sru char *old = dirs; 78114402Sru unsigned old_len = strlen(old); 79114402Sru unsigned slen = strlen(s); 80114402Sru dirs = new char[old_len + 1 + slen + 1]; 81114402Sru memcpy(dirs, old, old_len - init_len); 82114402Sru char *p = dirs; 83114402Sru p += old_len - init_len; 84114402Sru if (init_len == 0) 85151497Sru *p++ = PATH_SEP_CHAR; 86114402Sru memcpy(p, s, slen); 87114402Sru p += slen; 88114402Sru if (init_len > 0) { 89151497Sru *p++ = PATH_SEP_CHAR; 90114402Sru memcpy(p, old + old_len - init_len, init_len); 91114402Sru p += init_len; 92114402Sru } 93114402Sru *p++ = '\0'; 94114402Sru a_delete old; 95114402Sru} 96114402Sru 97114402SruFILE *search_path::open_file(const char *name, char **pathp) 98114402Sru{ 99114402Sru assert(name != 0); 100114402Sru if (IS_ABSOLUTE(name) || *dirs == '\0') { 101114402Sru FILE *fp = fopen(name, "r"); 102114402Sru if (fp) { 103114402Sru if (pathp) 104114402Sru *pathp = strsave(name); 105114402Sru return fp; 106114402Sru } 107114402Sru else 108114402Sru return 0; 109114402Sru } 110114402Sru unsigned namelen = strlen(name); 111114402Sru char *p = dirs; 112114402Sru for (;;) { 113151497Sru char *end = strchr(p, PATH_SEP_CHAR); 114114402Sru if (!end) 115114402Sru end = strchr(p, '\0'); 116114402Sru int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; 117151497Sru char *origpath = new char[(end - p) + need_slash + namelen + 1]; 118151497Sru memcpy(origpath, p, end - p); 119114402Sru if (need_slash) 120151497Sru origpath[end - p] = '/'; 121151497Sru strcpy(origpath + (end - p) + need_slash, name); 122114402Sru#if 0 123151497Sru fprintf(stderr, "origpath `%s'\n", origpath); 124151497Sru#endif 125151497Sru char *path = relocate(origpath); 126151497Sru a_delete origpath; 127151497Sru#if 0 128114402Sru fprintf(stderr, "trying `%s'\n", path); 129114402Sru#endif 130114402Sru FILE *fp = fopen(path, "r"); 131114402Sru if (fp) { 132114402Sru if (pathp) 133114402Sru *pathp = path; 134114402Sru else 135114402Sru a_delete path; 136114402Sru return fp; 137114402Sru } 138114402Sru a_delete path; 139114402Sru if (*end == '\0') 140114402Sru break; 141114402Sru p = end + 1; 142114402Sru } 143114402Sru return 0; 144114402Sru} 145151497Sru 146151497SruFILE *search_path::open_file_cautious(const char *name, char **pathp, 147151497Sru const char *mode) 148151497Sru{ 149151497Sru if (!mode) 150151497Sru mode = "r"; 151151497Sru bool reading = (strchr(mode, 'r') != 0); 152151497Sru if (name == 0 || strcmp(name, "-") == 0) { 153151497Sru if (pathp) 154151497Sru *pathp = strsave(reading ? "stdin" : "stdout"); 155151497Sru return (reading ? stdin : stdout); 156151497Sru } 157151497Sru if (!reading || IS_ABSOLUTE(name) || *dirs == '\0') { 158151497Sru FILE *fp = fopen(name, mode); 159151497Sru if (fp) { 160151497Sru if (pathp) 161151497Sru *pathp = strsave(name); 162151497Sru return fp; 163151497Sru } 164151497Sru else 165151497Sru return 0; 166151497Sru } 167151497Sru unsigned namelen = strlen(name); 168151497Sru char *p = dirs; 169151497Sru for (;;) { 170151497Sru char *end = strchr(p, PATH_SEP_CHAR); 171151497Sru if (!end) 172151497Sru end = strchr(p, '\0'); 173151497Sru int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; 174151497Sru char *origpath = new char[(end - p) + need_slash + namelen + 1]; 175151497Sru memcpy(origpath, p, end - p); 176151497Sru if (need_slash) 177151497Sru origpath[end - p] = '/'; 178151497Sru strcpy(origpath + (end - p) + need_slash, name); 179151497Sru#if 0 180151497Sru fprintf(stderr, "origpath `%s'\n", origpath); 181151497Sru#endif 182151497Sru char *path = relocate(origpath); 183151497Sru a_delete origpath; 184151497Sru#if 0 185151497Sru fprintf(stderr, "trying `%s'\n", path); 186151497Sru#endif 187151497Sru FILE *fp = fopen(path, mode); 188151497Sru if (fp) { 189151497Sru if (pathp) 190151497Sru *pathp = path; 191151497Sru else 192151497Sru a_delete path; 193151497Sru return fp; 194151497Sru } 195151497Sru int err = errno; 196151497Sru a_delete path; 197151497Sru if (err != ENOENT) 198151497Sru { 199151497Sru errno = err; 200151497Sru return 0; 201151497Sru } 202151497Sru if (*end == '\0') 203151497Sru break; 204151497Sru p = end + 1; 205151497Sru } 206151497Sru errno = ENOENT; 207151497Sru return 0; 208151497Sru} 209