1 /*
2 * New xlisp_path code by Dominic Mazzoni
3 *
4 * There is now a function provided to set the xlisp_path.
5 * This is particularly useful for external programs
6 * (e.g. Audacity, or a Nyquist GUI) that have their own
7 * mechanism of setting/finding the path. If xlisp_path
8 * is NULL, the old platform-specific methods are still
9 * used.
10 */
11 /* CHANGE LOG
12 *
13 * 24-dec-05 RBD
14 * Made ';' a valid path separator for every system (to work
15 * around a windows installer limitation)
16 *
17 * 22-jul-07 RBD
18 * Added get_user_id()
19 *
20 * 9-jan-08 RBD
21 * Added find-in-xlisp-path as XLISP primitive
22 *
23 * 22-jun-16 RBD & Paul Licameli
24 * Added cleanup code to free allocated memory
25 */
26
27 #include <string.h>
28
29 #include "switches.h"
30 #include "xlisp.h"
31
32 // boolean flag to support one-shot atexit() registration:
33 static unsigned char registered_path_cleanup = 0;
34
35 // save a copy of xlisp search path for return_xlisp_path():
36 static char *g_xlisp_path = NULL;
37
38 // return value for find_in_xlisp_path():
39 static char *g_xlptemp = NULL;
40
41
42 // clean up any allocated memory for this module (path.c)
path_cleanup(void)43 static void path_cleanup(void)
44 {
45 if (g_xlisp_path) {
46 free(g_xlisp_path);
47 g_xlisp_path = NULL;
48 }
49
50 if (g_xlptemp) {
51 free(g_xlptemp);
52 g_xlptemp = NULL;
53 }
54 }
55
56
57 // set_xlisp_path - set the search path
58 // the caller owns the parameter string, a copy is made
59 // and freed at program exit
set_xlisp_path(const char * p)60 void set_xlisp_path(const char *p)
61 {
62 // one-time register to free any allocated memory at cleanup
63 if (!registered_path_cleanup) {
64 atexit(path_cleanup);
65 registered_path_cleanup = 1;
66 }
67
68 if (g_xlisp_path) {
69 free(g_xlisp_path);
70 g_xlisp_path = NULL;
71 }
72
73 if (p) {
74 g_xlisp_path = malloc(strlen(p)+1);
75 // if malloc fails, program will crash here -- maybe that's better
76 // than setting g_xlisp_path to NULL, masking a critical problem
77 strcpy(g_xlisp_path, p);
78 }
79 }
80
81
82 #ifdef UNIX
unix_return_xlisp_path()83 const char *unix_return_xlisp_path()
84 {
85 char *paths = getenv("XLISPPATH");
86 if (!paths || !*paths) {
87 char msg[512];
88 sprintf(msg, "\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
89 "Warning: XLISP failed to find XLISPPATH in the environment.",
90 "If you are using Nyquist, probably you should cd to the",
91 "nyquist directory and type:",
92 " setenv XLISPPATH `pwd`/runtime:`pwd`/lib",
93 "or set XLISPPATH in your .login or .cshrc file.",
94 "If you use the bash shell, try:",
95 " XLISPPATH=`pwd`/runtime:`pwd`/lib; export XLISPPATH");
96 errputstr(msg);
97 }
98 return paths;
99 }
100 #endif
101
102 #ifdef WINDOWS
103 #include "winfun.h"
104
windows_return_xlisp_path()105 const char *windows_return_xlisp_path()
106 {
107 #define paths_max 1024
108 char paths[paths_max];
109 get_xlisp_path(paths, paths_max);
110 /* make sure we got paths, and the list is not empty */
111 if (!paths[0]) {
112 sprintf(paths, "\n%s\n%s\n%s\n",
113 "Warning: XLISP failed to find XLISPPATH in the Registry.",
114 "You should follow the installation instructions. Enter an",
115 "empty string if you really want no search path.");
116 errputstr(paths);
117 }
118 set_xlisp_path(paths);
119 /* for debugging:
120 errputstr("windows_return_xlisp_path() returns ");
121 errputstr(paths);
122 errputstr("\n"); */
123 return g_xlisp_path;
124 }
125
126 #endif
127
128 #ifdef MACINTOSH
mac_return_xlisp_path()129 const char *mac_return_xlisp_path()
130 {
131 #define paths_max 1024
132 char paths[paths_max];
133 int prefs_found = false;
134 get_xlisp_path(paths, paths_max, &prefs_found);
135 if (!paths[0]) {
136 if (prefs_found) {
137 sprintf(paths, "\n%s\n%s\n%s\n",
138 "Warning: XLISP failed to find XLISPPATH in XLisp Preferences.",
139 "You should probably delete XLisp Preferences and let XLisp",
140 "create a new one for you.");
141 }
142 else {
143 sprintf(paths, "\n%s\n%s\n%s\n%s\n%s\n",
144 "Warning: XLISP failed to find XLisp Preferences.",
145 "You should manually locate and load the file runtime:init.lsp",
146 "Nyquist will create an XLisp Preferences file to automatically",
147 "find the file next time. You may edit XLisp Preferences to add",
148 "additional search paths, using a comma as separator.");
149 }
150 errputstr(paths);
151 }
152 set_xlisp_path(paths);
153 return g_xlisp_path;
154 }
155
156
get_user_id()157 const char *get_user_id()
158 {
159 // not implemented for MACINTOSH (OS 9), just use "nyquist"
160 return "nyquist";
161 }
162 #endif
163
164
return_xlisp_path()165 const char *return_xlisp_path()
166 {
167 if (g_xlisp_path)
168 return g_xlisp_path;
169
170 // if g_xlisp_path has not been set, use one of the following
171 // to get the value, cache it in g_xlisp_path, and return it
172 #ifdef WINDOWS
173 return windows_return_xlisp_path();
174 #endif
175 #ifdef MACINTOSH
176 return mac_return_xlisp_path();
177 #endif
178 #ifdef UNIX
179 return unix_return_xlisp_path();
180 #endif
181 }
182
183
184 // find_in_xlisp_path -- find fname or fname.lsp by searching XLISP_PATH
185 //
186 // NOTE: this module owns the string. The string is valid
187 // until the next call to find_in_xlisp_path()
188 //
find_in_xlisp_path(const char * fname)189 const char *find_in_xlisp_path(const char *fname)
190 {
191 const char *paths = return_xlisp_path();
192 if (!paths)
193 return NULL;
194
195 // one-time register to free any allocated memory at cleanup
196 if (!registered_path_cleanup) {
197 atexit(path_cleanup);
198 registered_path_cleanup = 1;
199 }
200
201 while (paths && *paths) {
202 FILE *fp;
203 const char *start;
204 intptr_t len;
205
206 /* skip over separator */
207 while (*paths == os_sepchar || *paths == ';') paths++;
208
209 /* find next directory */
210 start = paths;
211 while (*paths && (*paths != os_sepchar && *paths != ';'))
212 paths++;
213
214 if (g_xlptemp) {
215 free(g_xlptemp);
216 g_xlptemp = NULL;
217 }
218
219 len = paths - start;
220 g_xlptemp = malloc(len + strlen(fname) + 10);
221 memcpy(g_xlptemp, start, len);
222
223 if (len == 0)
224 continue;
225
226 /* add "/" if needed */
227 if (g_xlptemp[len-1] != os_pathchar)
228 g_xlptemp[len++] = os_pathchar;
229
230 /* append the file name */
231 memcpy(&g_xlptemp[len], fname, strlen(fname));
232 len += strlen(fname);
233 g_xlptemp[len] = 0;
234
235
236 /* printf("Attempting to open %s, start is %s\n", g_xlptemp, start); */
237 fp = osaopen(g_xlptemp, "r");
238 if (!fp) {
239 /* try appending the .lsp extension */
240 if (needsextension(g_xlptemp)) {
241 strcat(g_xlptemp, ".lsp");
242 fp = osaopen(g_xlptemp, "r");
243 if (!fp) {
244 g_xlptemp[strlen(g_xlptemp) - 4] = 0; /* remove .lsp */
245 }
246 }
247 }
248 if (fp) {
249 fclose(fp);
250
251 #ifdef MACINTOSH
252 /* We found the file ok, call setup_preferences to create
253 * XLisp Preferences file (this only happens if previous
254 * attempt to find the file failed
255 */
256 setup_preferences(g_xlptemp);
257 #endif
258
259 return g_xlptemp;
260 }
261 }
262
263 /* It wasn't found */
264 return NULL;
265 }
266
267
268 /* xfind_in_xlisp_path -- search XLISPPATH for file, return full path */
xfind_in_xlisp_path()269 LVAL xfind_in_xlisp_path()
270 {
271 LVAL string = xlgastring();
272 const char *path = (const char *) getstring(string);
273 xllastarg();
274 path = find_in_xlisp_path(path);
275 return (path ? cvstring(path) : NULL);
276 }
277