searchpath.cpp revision 114402
1// -*- C++ -*-
2/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
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, 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
27#include "searchpath.h"
28#include "nonposix.h"
29
30search_path::search_path(const char *envvar, const char *standard,
31			 int add_home, int add_current)
32{
33  char *home = 0;
34  if (add_home)
35    home = getenv("HOME");
36  char *e = 0;
37  if (envvar)
38    e = getenv(envvar);
39  dirs = new char[((e && *e) ? strlen(e) + 1 : 0)
40		  + (add_current ? 1 + 1 : 0)
41		  + ((home && *home) ? strlen(home) + 1 : 0)
42		  + ((standard && *standard) ? strlen(standard) : 0)
43		  + 1];
44  *dirs = '\0';
45  if (e && *e) {
46    strcat(dirs, e);
47    strcat(dirs, PATH_SEP);
48  }
49  if (add_current) {
50    strcat(dirs, ".");
51    strcat(dirs, PATH_SEP);
52  }
53  if (home && *home) {
54    strcat(dirs, home);
55    strcat(dirs, PATH_SEP);
56  }
57  if (standard && *standard)
58    strcat(dirs, standard);
59  init_len = strlen(dirs);
60}
61
62search_path::~search_path()
63{
64  // dirs is always allocated
65  a_delete dirs;
66}
67
68void search_path::command_line_dir(const char *s)
69{
70  char *old = dirs;
71  unsigned old_len = strlen(old);
72  unsigned slen = strlen(s);
73  dirs = new char[old_len + 1 + slen + 1];
74  memcpy(dirs, old, old_len - init_len);
75  char *p = dirs;
76  p += old_len - init_len;
77  if (init_len == 0)
78    *p++ = PATH_SEP[0];
79  memcpy(p, s, slen);
80  p += slen;
81  if (init_len > 0) {
82    *p++ = PATH_SEP[0];
83    memcpy(p, old + old_len - init_len, init_len);
84    p += init_len;
85  }
86  *p++ = '\0';
87  a_delete old;
88}
89
90FILE *search_path::open_file(const char *name, char **pathp)
91{
92  assert(name != 0);
93  if (IS_ABSOLUTE(name) || *dirs == '\0') {
94    FILE *fp = fopen(name, "r");
95    if (fp) {
96      if (pathp)
97	*pathp = strsave(name);
98      return fp;
99    }
100    else
101      return 0;
102  }
103  unsigned namelen = strlen(name);
104  char *p = dirs;
105  for (;;) {
106    char *end = strchr(p, PATH_SEP[0]);
107    if (!end)
108      end = strchr(p, '\0');
109    int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0;
110    char *path = new char[(end - p) + need_slash + namelen + 1];
111    memcpy(path, p, end - p);
112    if (need_slash)
113      path[end - p] = '/';
114    strcpy(path + (end - p) + need_slash, name);
115#if 0
116    fprintf(stderr, "trying `%s'\n", path);
117#endif
118    FILE *fp = fopen(path, "r");
119    if (fp) {
120      if (pathp)
121	*pathp = path;
122      else
123	a_delete path;
124      return fp;
125    }
126    a_delete path;
127    if (*end == '\0')
128      break;
129    p = end + 1;
130  }
131  return 0;
132}
133