BRL-CAD
which.c
Go to the documentation of this file.
1 /* W H I C H . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2005-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 
21 #include "common.h"
22 
23 /* system headers */
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 
28 /* common headers */
29 #include "bu/debug.h"
30 #include "bu/file.h"
31 #include "bu/log.h"
32 #include "bu/str.h"
33 
34 
35 /* how big should PATH from getenv ever be */
36 #define MAXPATHENV 32767
37 
38 /* container for path match results */
39 static char bu_which_result[MAXPATHLEN] = {0};
40 
41 
42 const char *
43 bu_which(const char *cmd)
44 {
45  static const char *gotpath = NULL;
46 
47  char PATH[MAXPATHENV];
48 
49  char *directory = NULL;
50  char *position = NULL;
51  char curr_dir[] = ".";
52 
54  bu_log("bu_which: [%s]\n", cmd);
55  }
56 
57  if (UNLIKELY(!cmd || (strlen(cmd) == 0))) {
58  return NULL;
59  }
60 
61  /* start fresh */
62  memset(PATH, 0, MAXPATHENV);
63  memset(bu_which_result, 0, MAXPATHLEN);
64 
65  /* check for full/relative path match */
66  bu_strlcpy(bu_which_result, cmd, MAXPATHLEN);
67  if (!BU_STR_EQUAL(bu_which_result, cmd)) {
68  if (UNLIKELY(bu_debug & BU_DEBUG_PATHS)) {
69  bu_log("command [%s] is too long\n", cmd);
70  }
71  return NULL;
72  }
73 
74  if (bu_file_exists(bu_which_result, NULL) && strchr(bu_which_result, BU_DIR_SEPARATOR)) {
75  if (bu_which_result[0] == '\0')
76  return NULL; /* never return empty */
77  return bu_which_result;
78  }
79 
80  /* load up the PATH from the caller's user environment */
81  gotpath = getenv("PATH");
82  if (gotpath) {
83  bu_strlcpy(PATH, gotpath, MAXPATHENV);
84 
85  /* make sure it fit, we have a problem if it did not */
86  if (!BU_STR_EQUAL(PATH, gotpath)) {
87  position = strrchr(PATH, BU_PATH_SEPARATOR);
88  if (position) {
89  position = NULL;
90  } else {
91  /* too much and no separator? wtf. */
92  if (UNLIKELY(bu_debug & BU_DEBUG_PATHS)) {
93  bu_log("path contains invalid data?\n");
94  }
95  return NULL;
96  }
97  }
98 
99  if (UNLIKELY(bu_debug & BU_DEBUG_PATHS)) {
100  bu_log("PATH is %s\n", PATH);
101  }
102  } else {
103  if (UNLIKELY(bu_debug & BU_DEBUG_PATHS)) {
104  bu_log("PATH is NULL\n");
105  }
106  return NULL;
107  }
108 
109  /* search for the executable */
110  directory = PATH;
111  do {
112  position = strchr(directory, BU_PATH_SEPARATOR);
113  if (position) {
114  /* 'directory' can't be const because we have to change a character here: */
115  *position = '\0';
116  }
117 
118  /* empty means use current dir */
119  if (strlen(directory) == 0) {
120  directory = curr_dir; /* "."; */
121  }
122 
123  snprintf(bu_which_result, MAXPATHLEN, "%s/%s", directory, cmd);
124  if (bu_file_exists(bu_which_result, NULL)) {
125  if (bu_which_result[0] == '\0')
126  return NULL; /* never return empty */
127  return bu_which_result;
128  }
129 
130  if (position) {
131  directory = position + 1;
132  } else {
133  directory = NULL;
134  }
135  } while (directory); /* iterate over PATH directories */
136 
137  /* no path or no match */
138  if (UNLIKELY(bu_debug & BU_DEBUG_PATHS)) {
139  bu_log("no %s in %s\n", cmd, gotpath ? gotpath : "(no path)");
140  }
141 
142  return NULL;
143 }
144 
145 /*
146  * Local Variables:
147  * mode: C
148  * tab-width: 8
149  * indent-tabs-mode: t
150  * c-file-style: "stroustrup"
151  * End:
152  * ex: shiftwidth=4 tabstop=8
153  */
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
Header file for the BRL-CAD common definitions.
#define BU_DEBUG_PATHS
Definition: debug.h:68
char * strchr(const char *sp, int c)
#define MAXPATHENV
Definition: which.c:36
void * memset(void *s, int c, size_t n)
#define bu_strlcpy(dst, src, size)
Definition: str.h:60
const char * bu_which(const char *cmd)
Definition: which.c:43
#define BU_PATH_SEPARATOR
Definition: defines.h:127
#define BU_DIR_SEPARATOR
Definition: defines.h:97
int bu_debug
Definition: globals.c:87
int bu_file_exists(const char *path, int *fd)
Definition: file.c:57
#define UNLIKELY(expression)
Definition: common.h:282
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126
#define MAXPATHLEN
Definition: defines.h:113