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