1 /* Copyright (c) 1999 Guenter Geiger and others.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
6 * This file implements the loader for linux, which includes
7 * a little bit of path handling.
9 * Generalized by MSP to provide an open_via_path function
10 * and lists of files for all purposes.
13 /* #define DEBUG(x) x */
15 void readsf_banana( void); /* debugging */
44 static t_namelist
*pd_path
, *pd_helppath
;
46 /* Utility functions */
48 /* copy until delimiter and return position after delimiter in string */
49 /* if it was the last substring, return NULL */
51 static const char* strtokcpy(char *to
, const char *from
, int delim
)
55 while (from
[size
] != (char)delim
&& from
[size
] != '\0')
58 strncpy(to
,from
,size
);
60 if (from
[size
] == '\0') return NULL
;
61 if (size
) return from
+size
+1;
65 /* add a colon-separated list of names to a namelist */
73 static t_namelist
*namelist_doappend(t_namelist
*listwas
, const char *s
)
75 t_namelist
*nl
= listwas
, *rtn
= listwas
, *nl2
;
76 nl2
= (t_namelist
*)(getbytes(sizeof(*nl
)));
78 nl2
->nl_string
= (char *)getbytes(strlen(s
) + 1);
79 strcpy(nl2
->nl_string
, s
);
80 sys_unbashfilename(nl2
->nl_string
, nl2
->nl_string
);
93 t_namelist
*namelist_append(t_namelist
*listwas
, const char *s
)
96 char temp
[MAXPDSTRING
];
97 t_namelist
*nl
= listwas
, *rtn
= listwas
;
106 npos
= strtokcpy(temp
, npos
, SEPARATOR
);
107 if (! *temp
) continue;
108 nl
= namelist_doappend(nl
, temp
);
114 void namelist_free(t_namelist
*listwas
)
116 t_namelist
*nl
, *nl2
;
117 for (nl
= listwas
; nl
; nl
= nl2
)
120 t_freebytes(nl
->nl_string
, strlen(nl
->nl_string
) + 1);
121 t_freebytes(nl
, sizeof(*nl
));
125 void sys_addpath(const char *p
)
127 pd_path
= namelist_append(pd_path
, p
);
130 void sys_addhelppath(const char *p
)
132 pd_helppath
= namelist_append(pd_helppath
, p
);
136 #define MSWOPENFLAG(bin) (bin ? _O_BINARY : _O_TEXT)
138 #define MSWOPENFLAG(bin) 0
141 /* search for a file in a specified directory, then along the globally
142 defined search path, using ext as filename extension. Exception:
143 if the 'name' starts with a slash or a letter, colon, and slash in MSW,
144 there is no search and instead we just try to open the file literally. The
145 fd is returned, the directory ends up in the "dirresult" which must be at
146 least "size" bytes. "nameresult" is set to point to the filename, which
147 ends up in the same buffer as dirresult. */
149 int open_via_path(const char *dir
, const char *name
, const char* ext
,
150 char *dirresult
, char **nameresult
, unsigned int size
, int bin
)
152 t_namelist
*nl
, thislist
;
154 char listbuf
[MAXPDSTRING
];
162 || (name
[1] == ':' && name
[2] == '/')
166 thislist
.nl_next
= 0;
167 thislist
.nl_string
= listbuf
;
172 thislist
.nl_string
= listbuf
;
173 thislist
.nl_next
= pd_path
;
174 strncpy(listbuf
, dir
, MAXPDSTRING
);
175 listbuf
[MAXPDSTRING
-1] = 0;
176 sys_unbashfilename(listbuf
, listbuf
);
179 for (nl
= &thislist
; nl
; nl
= nl
->nl_next
)
181 if (strlen(nl
->nl_string
) + strlen(name
) + strlen(ext
) + 4 >
184 strcpy(dirresult
, nl
->nl_string
);
185 if (*dirresult
&& dirresult
[strlen(dirresult
)-1] != '/')
186 strcat(dirresult
, "/");
187 strcat(dirresult
, name
);
188 strcat(dirresult
, ext
);
189 sys_bashfilename(dirresult
, dirresult
);
191 DEBUG(post("looking for %s",dirresult
));
192 /* see if we can open the file for reading */
193 if ((fd
=open(dirresult
,O_RDONLY
| MSWOPENFLAG(bin
))) >= 0)
195 /* in UNIX, further check that it's not a directory */
198 int ok
= ((fstat(fd
, &statbuf
) >= 0) &&
199 !S_ISDIR(statbuf
.st_mode
));
202 if (sys_verbose
) post("tried %s; stat failed or directory",
211 if (sys_verbose
) post("tried %s and succeeded", dirresult
);
212 sys_unbashfilename(dirresult
, dirresult
);
214 slash
= strrchr(dirresult
, '/');
218 *nameresult
= slash
+ 1;
220 else *nameresult
= dirresult
;
227 if (sys_verbose
) post("tried %s and failed", dirresult
);
231 *nameresult
= dirresult
;
235 static int do_open_via_helppath(const char *realname
, t_namelist
*listp
)
239 char dirresult
[MAXPDSTRING
], realdir
[MAXPDSTRING
];
240 for (nl
= listp
; nl
; nl
= nl
->nl_next
)
242 strcpy(dirresult
, nl
->nl_string
);
243 strcpy(realdir
, dirresult
);
244 if (*dirresult
&& dirresult
[strlen(dirresult
)-1] != '/')
245 strcat(dirresult
, "/");
246 strcat(dirresult
, realname
);
247 sys_bashfilename(dirresult
, dirresult
);
249 DEBUG(post("looking for %s",dirresult
));
250 /* see if we can open the file for reading */
251 if ((fd
=open(dirresult
,O_RDONLY
| MSWOPENFLAG(0))) >= 0)
253 /* in UNIX, further check that it's not a directory */
256 int ok
= ((fstat(fd
, &statbuf
) >= 0) &&
257 !S_ISDIR(statbuf
.st_mode
));
260 if (sys_verbose
) post("tried %s; stat failed or directory",
271 if (sys_verbose
) post("tried %s and succeeded", dirresult
);
272 sys_unbashfilename(dirresult
, dirresult
);
274 glob_evalfile(0, gensym((char*)realname
), gensym(realdir
));
280 if (sys_verbose
) post("tried %s and failed", dirresult
);
286 /* LATER make this use open_via_path above. We expect the ".pd"
287 suffix here, even though we have to tear it back off for one of the
289 void open_via_helppath(const char *name
, const char *dir
)
292 t_namelist thislist
, *listp
;
294 t_namelist
*nl
, thislist
, *listp
;
297 char dirbuf2
[MAXPDSTRING
], realname
[MAXPDSTRING
];
299 /* if directory is supplied, put it at head of search list. */
302 thislist
.nl_string
= dirbuf2
;
303 thislist
.nl_next
= pd_helppath
;
304 strncpy(dirbuf2
, dir
, MAXPDSTRING
);
305 dirbuf2
[MAXPDSTRING
-1] = 0;
306 sys_unbashfilename(dirbuf2
, dirbuf2
);
309 else listp
= pd_helppath
;
310 /* 1. "objectname-help.pd" */
311 strncpy(realname
, name
, MAXPDSTRING
-10);
312 realname
[MAXPDSTRING
-10] = 0;
313 if (strlen(realname
) > 3 && !strcmp(realname
+strlen(realname
)-3, ".pd"))
314 realname
[strlen(realname
)-3] = 0;
315 strcat(realname
, "-help.pd");
316 if (do_open_via_helppath(realname
, listp
))
318 /* 2. "help-objectname.pd" */
319 strcpy(realname
, "help-");
320 strncat(realname
, name
, MAXPDSTRING
-10);
321 realname
[MAXPDSTRING
-1] = 0;
322 if (do_open_via_helppath(realname
, listp
))
324 /* 3. "objectname.pd" */
325 if (do_open_via_helppath(name
, listp
))
327 post("sorry, couldn't find help patch for \"%s\"", name
);
332 /* Startup file reading for linux and MACOSX. This should be replaced by
333 a better mechanism. This should be integrated with the audio, MIDI, and
334 path dialog system. */
338 #define STARTUPNAME ".pdrc"
341 int sys_argparse(int argc
, char **argv
);
349 char* rcargv
[NUMARGS
];
351 char fname
[MAXPDSTRING
], buf
[1000], *home
= getenv("HOME");
353 /* parse a startup file */
357 strncat(fname
, home
? home
: ".", MAXPDSTRING
-10);
360 strcat(fname
, STARTUPNAME
);
362 if (!(file
= fopen(fname
, "r")))
365 post("reading startup file: %s", fname
);
367 rcargv
[0] = "."; /* this no longer matters to sys_argparse() */
369 for (i
= 1; i
< NUMARGS
-1; i
++)
371 if (fscanf(file
, "%999s", buf
) < 0)
374 if (!(rcargv
[i
] = malloc(strlen(buf
) + 1)))
376 strcpy(rcargv
[i
], buf
);
379 fprintf(stderr
, "startup file too long; extra args dropped\n");
384 /* parse the options */
391 post("startup args from RC file:");
392 for (i
= 1; i
< rcargc
; i
++)
393 post("%s", rcargv
[i
]);
395 else post("no RC file arguments found");
397 if (sys_argparse(rcargc
, rcargv
))
399 post("error parsing RC arguments");
406 /* start an audio settings dialog window */
407 void glob_start_path_dialog(t_pd
*dummy
, t_floatarg flongform
)
413 char buf
[MAXPDSTRING
];
417 for (nl
= pd_path
, i
= 0; nl
&& i
< 10; nl
= nl
->nl_next
, i
++)
418 sys_vgui("pd_set pd_path%d \"%s\"\n", i
, nl
->nl_string
);
420 sys_vgui("pd_set pd_path%d \"\"\n", i
);
422 sprintf(buf
, "pdtk_path_dialog %%s\n");
423 gfxstub_new(&glob_pdobject
, glob_start_path_dialog
, buf
);
427 /* new values from dialog window */
428 void glob_path_dialog(t_pd
*dummy
, t_symbol
*s
, int argc
, t_atom
*argv
)
437 namelist_free(pd_path
);
439 for (i
= 0; i
< argc
; i
++)
441 t_symbol
*s
= atom_getsymbolarg(i
, argc
, argv
);
443 sys_addpath(s
->s_name
);