Add FS #10214. Initial commit of the original PDa code for the GSoC Pure Data plugin...
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / s_path.c
blob26b8dfda9965ed4651ecf620d6868607505e05d6
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. */
5 /*
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.
11 */
13 /* #define DEBUG(x) x */
14 #define DEBUG(x)
15 void readsf_banana( void); /* debugging */
17 #include <stdlib.h>
18 #ifdef UNIX
19 #include <unistd.h>
20 #include <sys/stat.h>
21 #endif
22 #ifdef MSW
23 #include <io.h>
24 #endif
26 #include <string.h>
27 #include "m_pd.h"
28 #include "m_imp.h"
29 #include "s_stuff.h"
30 #include <stdio.h>
31 #include <fcntl.h>
33 static t_namelist *pd_path, *pd_helppath;
35 /* Utility functions */
37 /* copy until delimiter and return position after delimiter in string */
38 /* if it was the last substring, return NULL */
40 static const char* strtokcpy(char *to, const char *from, int delim)
42 int size = 0;
44 while (from[size] != (char)delim && from[size] != '\0')
45 size++;
47 strncpy(to,from,size);
48 to[size] = '\0';
49 if (from[size] == '\0') return NULL;
50 if (size) return from+size+1;
51 else return NULL;
54 /* add a colon-separated list of names to a namelist */
56 #ifdef MSW
57 #define SEPARATOR ';'
58 #else
59 #define SEPARATOR ':'
60 #endif
62 static t_namelist *namelist_doappend(t_namelist *listwas, const char *s)
64 t_namelist *nl = listwas, *rtn = listwas, *nl2;
65 nl2 = (t_namelist *)(getbytes(sizeof(*nl)));
66 nl2->nl_next = 0;
67 nl2->nl_string = (char *)getbytes(strlen(s) + 1);
68 strcpy(nl2->nl_string, s);
69 sys_unbashfilename(nl2->nl_string, nl2->nl_string);
70 if (!nl)
71 nl = rtn = nl2;
72 else
74 while (nl->nl_next)
75 nl = nl->nl_next;
76 nl->nl_next = nl2;
78 return (rtn);
82 t_namelist *namelist_append(t_namelist *listwas, const char *s)
84 const char *npos;
85 char temp[MAXPDSTRING];
86 t_namelist *nl = listwas, *rtn = listwas;
88 npos = s;
91 npos = strtokcpy(temp, npos, SEPARATOR);
92 if (! *temp) continue;
93 nl = namelist_doappend(nl, temp);
95 while (npos);
96 return (nl);
99 void namelist_free(t_namelist *listwas)
101 t_namelist *nl, *nl2;
102 for (nl = listwas; nl; nl = nl2)
104 nl2 = nl->nl_next;
105 t_freebytes(nl->nl_string, strlen(nl->nl_string) + 1);
106 t_freebytes(nl, sizeof(*nl));
110 void sys_addpath(const char *p)
112 pd_path = namelist_append(pd_path, p);
115 void sys_addhelppath(const char *p)
117 pd_helppath = namelist_append(pd_helppath, p);
120 #ifdef MSW
121 #define MSWOPENFLAG(bin) (bin ? _O_BINARY : _O_TEXT)
122 #else
123 #define MSWOPENFLAG(bin) 0
124 #endif
126 /* search for a file in a specified directory, then along the globally
127 defined search path, using ext as filename extension. Exception:
128 if the 'name' starts with a slash or a letter, colon, and slash in MSW,
129 there is no search and instead we just try to open the file literally. The
130 fd is returned, the directory ends up in the "dirresult" which must be at
131 least "size" bytes. "nameresult" is set to point to the filename, which
132 ends up in the same buffer as dirresult. */
134 int open_via_path(const char *dir, const char *name, const char* ext,
135 char *dirresult, char **nameresult, unsigned int size, int bin)
137 t_namelist *nl, thislist;
138 int fd = -1;
139 char listbuf[MAXPDSTRING];
141 if (name[0] == '/'
142 #ifdef MSW
143 || (name[1] == ':' && name[2] == '/')
144 #endif
147 thislist.nl_next = 0;
148 thislist.nl_string = listbuf;
149 listbuf[0] = 0;
151 else
153 thislist.nl_string = listbuf;
154 thislist.nl_next = pd_path;
155 strncpy(listbuf, dir, MAXPDSTRING);
156 listbuf[MAXPDSTRING-1] = 0;
157 sys_unbashfilename(listbuf, listbuf);
160 for (nl = &thislist; nl; nl = nl->nl_next)
162 if (strlen(nl->nl_string) + strlen(name) + strlen(ext) + 4 >
163 size)
164 continue;
165 strcpy(dirresult, nl->nl_string);
166 if (*dirresult && dirresult[strlen(dirresult)-1] != '/')
167 strcat(dirresult, "/");
168 strcat(dirresult, name);
169 strcat(dirresult, ext);
170 sys_bashfilename(dirresult, dirresult);
172 DEBUG(post("looking for %s",dirresult));
173 /* see if we can open the file for reading */
174 if ((fd=open(dirresult,O_RDONLY | MSWOPENFLAG(bin))) >= 0)
176 /* in UNIX, further check that it's not a directory */
177 #ifdef UNIX
178 struct stat statbuf;
179 int ok = ((fstat(fd, &statbuf) >= 0) &&
180 !S_ISDIR(statbuf.st_mode));
181 if (!ok)
183 if (sys_verbose) post("tried %s; stat failed or directory",
184 dirresult);
185 close (fd);
186 fd = -1;
188 else
189 #endif
191 char *slash;
192 if (sys_verbose) post("tried %s and succeeded", dirresult);
193 sys_unbashfilename(dirresult, dirresult);
194 slash = strrchr(dirresult, '/');
195 if (slash)
197 *slash = 0;
198 *nameresult = slash + 1;
200 else *nameresult = dirresult;
202 return (fd);
205 else
207 if (sys_verbose) post("tried %s and failed", dirresult);
210 *dirresult = 0;
211 *nameresult = dirresult;
212 return (-1);
215 static int do_open_via_helppath(const char *realname, t_namelist *listp)
217 t_namelist *nl;
218 int fd = -1;
219 char dirresult[MAXPDSTRING], realdir[MAXPDSTRING];
220 for (nl = listp; nl; nl = nl->nl_next)
222 strcpy(dirresult, nl->nl_string);
223 strcpy(realdir, dirresult);
224 if (*dirresult && dirresult[strlen(dirresult)-1] != '/')
225 strcat(dirresult, "/");
226 strcat(dirresult, realname);
227 sys_bashfilename(dirresult, dirresult);
229 DEBUG(post("looking for %s",dirresult));
230 /* see if we can open the file for reading */
231 if ((fd=open(dirresult,O_RDONLY | MSWOPENFLAG(0))) >= 0)
233 /* in UNIX, further check that it's not a directory */
234 #ifdef UNIX
235 struct stat statbuf;
236 int ok = ((fstat(fd, &statbuf) >= 0) &&
237 !S_ISDIR(statbuf.st_mode));
238 if (!ok)
240 if (sys_verbose) post("tried %s; stat failed or directory",
241 dirresult);
242 close (fd);
243 fd = -1;
245 else
246 #endif
248 char *slash;
249 if (sys_verbose) post("tried %s and succeeded", dirresult);
250 sys_unbashfilename(dirresult, dirresult);
251 close (fd);
252 glob_evalfile(0, gensym((char*)realname), gensym(realdir));
253 return (1);
256 else
258 if (sys_verbose) post("tried %s and failed", dirresult);
261 return (0);
264 /* LATER make this use open_via_path above. We expect the ".pd"
265 suffix here, even though we have to tear it back off for one of the
266 search attempts. */
267 void open_via_helppath(const char *name, const char *dir)
269 t_namelist *nl, thislist, *listp;
270 int fd = -1;
271 char dirbuf2[MAXPDSTRING], realname[MAXPDSTRING];
273 /* if directory is supplied, put it at head of search list. */
274 if (*dir)
276 thislist.nl_string = dirbuf2;
277 thislist.nl_next = pd_helppath;
278 strncpy(dirbuf2, dir, MAXPDSTRING);
279 dirbuf2[MAXPDSTRING-1] = 0;
280 sys_unbashfilename(dirbuf2, dirbuf2);
281 listp = &thislist;
283 else listp = pd_helppath;
284 /* 1. "objectname-help.pd" */
285 strncpy(realname, name, MAXPDSTRING-10);
286 realname[MAXPDSTRING-10] = 0;
287 if (strlen(realname) > 3 && !strcmp(realname+strlen(realname)-3, ".pd"))
288 realname[strlen(realname)-3] = 0;
289 strcat(realname, "-help.pd");
290 if (do_open_via_helppath(realname, listp))
291 return;
292 /* 2. "help-objectname.pd" */
293 strcpy(realname, "help-");
294 strncat(realname, name, MAXPDSTRING-10);
295 realname[MAXPDSTRING-1] = 0;
296 if (do_open_via_helppath(realname, listp))
297 return;
298 /* 3. "objectname.pd" */
299 if (do_open_via_helppath(name, listp))
300 return;
301 post("sorry, couldn't find help patch for \"%s\"", name);
302 return;
306 /* Startup file reading for linux and MACOSX. This should be replaced by
307 a better mechanism. This should be integrated with the audio, MIDI, and
308 path dialog system. */
310 #ifdef UNIX
312 #define STARTUPNAME ".pdrc"
313 #define NUMARGS 1000
315 int sys_argparse(int argc, char **argv);
317 int sys_rcfile(void)
319 FILE* file;
320 int i;
321 int k;
322 int rcargc;
323 char* rcargv[NUMARGS];
324 char* buffer;
325 char fname[MAXPDSTRING], buf[1000], *home = getenv("HOME");
327 /* parse a startup file */
329 *fname = '\0';
331 strncat(fname, home? home : ".", MAXPDSTRING-10);
332 strcat(fname, "/");
334 strcat(fname, STARTUPNAME);
336 if (!(file = fopen(fname, "r")))
337 return 1;
339 post("reading startup file: %s", fname);
341 rcargv[0] = "."; /* this no longer matters to sys_argparse() */
343 for (i = 1; i < NUMARGS-1; i++)
345 if (fscanf(file, "%999s", buf) < 0)
346 break;
347 buf[1000] = 0;
348 if (!(rcargv[i] = malloc(strlen(buf) + 1)))
349 return (1);
350 strcpy(rcargv[i], buf);
352 if (i >= NUMARGS-1)
353 fprintf(stderr, "startup file too long; extra args dropped\n");
354 rcargv[i] = 0;
356 rcargc = i;
358 /* parse the options */
360 fclose(file);
361 if (sys_verbose)
363 if (rcargv)
365 post("startup args from RC file:");
366 for (i = 1; i < rcargc; i++)
367 post("%s", rcargv[i]);
369 else post("no RC file arguments found");
371 if (sys_argparse(rcargc, rcargv))
373 post("error parsing RC arguments");
374 return (1);
376 return (0);
378 #endif /* UNIX */
380 /* start an audio settings dialog window */
381 void glob_start_path_dialog(t_pd *dummy, t_floatarg flongform)
383 char buf[MAXPDSTRING];
384 int i;
385 t_namelist *nl;
387 for (nl = pd_path, i = 0; nl && i < 10; nl = nl->nl_next, i++)
388 sys_vgui("pd_set pd_path%d \"%s\"\n", i, nl->nl_string);
389 for (; i < 10; i++)
390 sys_vgui("pd_set pd_path%d \"\"\n", i);
392 sprintf(buf, "pdtk_path_dialog %%s\n");
393 gfxstub_new(&glob_pdobject, glob_start_path_dialog, buf);
396 /* new values from dialog window */
397 void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
399 int i;
400 namelist_free(pd_path);
401 pd_path = 0;
402 for (i = 0; i < argc; i++)
404 t_symbol *s = atom_getsymbolarg(i, argc, argv);
405 if (*s->s_name)
406 sys_addpath(s->s_name);
411 /* Copyright (c) 1999 Guenter Geiger and others.
412 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
413 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
416 * This file implements the loader for linux, which includes
417 * a little bit of path handling.
419 * Generalized by MSP to provide an open_via_path function
420 * and lists of files for all purposes.
423 /* #define DEBUG(x) x */
424 #define DEBUG(x)
425 void readsf_banana( void); /* debugging */
427 #include <stdlib.h>
428 #ifdef UNIX
429 #include <unistd.h>
430 #include <sys/stat.h>
431 #endif
432 #ifdef MSW
433 #include <io.h>
434 #endif
436 #include <string.h>
437 #include "m_pd.h"
438 #include "m_imp.h"
439 #include "s_stuff.h"
440 #include <stdio.h>
441 #include <fcntl.h>
443 static t_namelist *pd_path, *pd_helppath;
445 /* Utility functions */
447 /* copy until delimiter and return position after delimiter in string */
448 /* if it was the last substring, return NULL */
450 static const char* strtokcpy(char *to, const char *from, int delim)
452 int size = 0;
454 while (from[size] != (char)delim && from[size] != '\0')
455 size++;
457 strncpy(to,from,size);
458 to[size] = '\0';
459 if (from[size] == '\0') return NULL;
460 if (size) return from+size+1;
461 else return NULL;
464 /* add a colon-separated list of names to a namelist */
466 #ifdef MSW
467 #define SEPARATOR ';'
468 #else
469 #define SEPARATOR ':'
470 #endif
472 static t_namelist *namelist_doappend(t_namelist *listwas, const char *s)
474 t_namelist *nl = listwas, *rtn = listwas, *nl2;
475 nl2 = (t_namelist *)(getbytes(sizeof(*nl)));
476 nl2->nl_next = 0;
477 nl2->nl_string = (char *)getbytes(strlen(s) + 1);
478 strcpy(nl2->nl_string, s);
479 sys_unbashfilename(nl2->nl_string, nl2->nl_string);
480 if (!nl)
481 nl = rtn = nl2;
482 else
484 while (nl->nl_next)
485 nl = nl->nl_next;
486 nl->nl_next = nl2;
488 return (rtn);
492 t_namelist *namelist_append(t_namelist *listwas, const char *s)
494 const char *npos;
495 char temp[MAXPDSTRING];
496 t_namelist *nl = listwas, *rtn = listwas;
498 npos = s;
501 npos = strtokcpy(temp, npos, SEPARATOR);
502 if (! *temp) continue;
503 nl = namelist_doappend(nl, temp);
505 while (npos);
506 return (nl);
509 void namelist_free(t_namelist *listwas)
511 t_namelist *nl, *nl2;
512 for (nl = listwas; nl; nl = nl2)
514 nl2 = nl->nl_next;
515 t_freebytes(nl->nl_string, strlen(nl->nl_string) + 1);
516 t_freebytes(nl, sizeof(*nl));
520 void sys_addpath(const char *p)
522 pd_path = namelist_append(pd_path, p);
525 void sys_addhelppath(const char *p)
527 pd_helppath = namelist_append(pd_helppath, p);
530 #ifdef MSW
531 #define MSWOPENFLAG(bin) (bin ? _O_BINARY : _O_TEXT)
532 #else
533 #define MSWOPENFLAG(bin) 0
534 #endif
536 /* search for a file in a specified directory, then along the globally
537 defined search path, using ext as filename extension. Exception:
538 if the 'name' starts with a slash or a letter, colon, and slash in MSW,
539 there is no search and instead we just try to open the file literally. The
540 fd is returned, the directory ends up in the "dirresult" which must be at
541 least "size" bytes. "nameresult" is set to point to the filename, which
542 ends up in the same buffer as dirresult. */
544 int open_via_path(const char *dir, const char *name, const char* ext,
545 char *dirresult, char **nameresult, unsigned int size, int bin)
547 t_namelist *nl, thislist;
548 int fd = -1;
549 char listbuf[MAXPDSTRING];
551 if (name[0] == '/'
552 #ifdef MSW
553 || (name[1] == ':' && name[2] == '/')
554 #endif
557 thislist.nl_next = 0;
558 thislist.nl_string = listbuf;
559 listbuf[0] = 0;
561 else
563 thislist.nl_string = listbuf;
564 thislist.nl_next = pd_path;
565 strncpy(listbuf, dir, MAXPDSTRING);
566 listbuf[MAXPDSTRING-1] = 0;
567 sys_unbashfilename(listbuf, listbuf);
570 for (nl = &thislist; nl; nl = nl->nl_next)
572 if (strlen(nl->nl_string) + strlen(name) + strlen(ext) + 4 >
573 size)
574 continue;
575 strcpy(dirresult, nl->nl_string);
576 if (*dirresult && dirresult[strlen(dirresult)-1] != '/')
577 strcat(dirresult, "/");
578 strcat(dirresult, name);
579 strcat(dirresult, ext);
580 sys_bashfilename(dirresult, dirresult);
582 DEBUG(post("looking for %s",dirresult));
583 /* see if we can open the file for reading */
584 if ((fd=open(dirresult,O_RDONLY | MSWOPENFLAG(bin))) >= 0)
586 /* in UNIX, further check that it's not a directory */
587 #ifdef UNIX
588 struct stat statbuf;
589 int ok = ((fstat(fd, &statbuf) >= 0) &&
590 !S_ISDIR(statbuf.st_mode));
591 if (!ok)
593 if (sys_verbose) post("tried %s; stat failed or directory",
594 dirresult);
595 close (fd);
596 fd = -1;
598 else
599 #endif
601 char *slash;
602 if (sys_verbose) post("tried %s and succeeded", dirresult);
603 sys_unbashfilename(dirresult, dirresult);
604 slash = strrchr(dirresult, '/');
605 if (slash)
607 *slash = 0;
608 *nameresult = slash + 1;
610 else *nameresult = dirresult;
612 return (fd);
615 else
617 if (sys_verbose) post("tried %s and failed", dirresult);
620 *dirresult = 0;
621 *nameresult = dirresult;
622 return (-1);
625 static int do_open_via_helppath(const char *realname, t_namelist *listp)
627 t_namelist *nl;
628 int fd = -1;
629 char dirresult[MAXPDSTRING], realdir[MAXPDSTRING];
630 for (nl = listp; nl; nl = nl->nl_next)
632 strcpy(dirresult, nl->nl_string);
633 strcpy(realdir, dirresult);
634 if (*dirresult && dirresult[strlen(dirresult)-1] != '/')
635 strcat(dirresult, "/");
636 strcat(dirresult, realname);
637 sys_bashfilename(dirresult, dirresult);
639 DEBUG(post("looking for %s",dirresult));
640 /* see if we can open the file for reading */
641 if ((fd=open(dirresult,O_RDONLY | MSWOPENFLAG(0))) >= 0)
643 /* in UNIX, further check that it's not a directory */
644 #ifdef UNIX
645 struct stat statbuf;
646 int ok = ((fstat(fd, &statbuf) >= 0) &&
647 !S_ISDIR(statbuf.st_mode));
648 if (!ok)
650 if (sys_verbose) post("tried %s; stat failed or directory",
651 dirresult);
652 close (fd);
653 fd = -1;
655 else
656 #endif
658 char *slash;
659 if (sys_verbose) post("tried %s and succeeded", dirresult);
660 sys_unbashfilename(dirresult, dirresult);
661 close (fd);
662 glob_evalfile(0, gensym((char*)realname), gensym(realdir));
663 return (1);
666 else
668 if (sys_verbose) post("tried %s and failed", dirresult);
671 return (0);
674 /* LATER make this use open_via_path above. We expect the ".pd"
675 suffix here, even though we have to tear it back off for one of the
676 search attempts. */
677 void open_via_helppath(const char *name, const char *dir)
679 t_namelist *nl, thislist, *listp;
680 int fd = -1;
681 char dirbuf2[MAXPDSTRING], realname[MAXPDSTRING];
683 /* if directory is supplied, put it at head of search list. */
684 if (*dir)
686 thislist.nl_string = dirbuf2;
687 thislist.nl_next = pd_helppath;
688 strncpy(dirbuf2, dir, MAXPDSTRING);
689 dirbuf2[MAXPDSTRING-1] = 0;
690 sys_unbashfilename(dirbuf2, dirbuf2);
691 listp = &thislist;
693 else listp = pd_helppath;
694 /* 1. "objectname-help.pd" */
695 strncpy(realname, name, MAXPDSTRING-10);
696 realname[MAXPDSTRING-10] = 0;
697 if (strlen(realname) > 3 && !strcmp(realname+strlen(realname)-3, ".pd"))
698 realname[strlen(realname)-3] = 0;
699 strcat(realname, "-help.pd");
700 if (do_open_via_helppath(realname, listp))
701 return;
702 /* 2. "help-objectname.pd" */
703 strcpy(realname, "help-");
704 strncat(realname, name, MAXPDSTRING-10);
705 realname[MAXPDSTRING-1] = 0;
706 if (do_open_via_helppath(realname, listp))
707 return;
708 /* 3. "objectname.pd" */
709 if (do_open_via_helppath(name, listp))
710 return;
711 post("sorry, couldn't find help patch for \"%s\"", name);
712 return;
716 /* Startup file reading for linux and MACOSX. This should be replaced by
717 a better mechanism. This should be integrated with the audio, MIDI, and
718 path dialog system. */
720 #ifdef UNIX
722 #define STARTUPNAME ".pdrc"
723 #define NUMARGS 1000
725 int sys_argparse(int argc, char **argv);
727 int sys_rcfile(void)
729 FILE* file;
730 int i;
731 int k;
732 int rcargc;
733 char* rcargv[NUMARGS];
734 char* buffer;
735 char fname[MAXPDSTRING], buf[1000], *home = getenv("HOME");
737 /* parse a startup file */
739 *fname = '\0';
741 strncat(fname, home? home : ".", MAXPDSTRING-10);
742 strcat(fname, "/");
744 strcat(fname, STARTUPNAME);
746 if (!(file = fopen(fname, "r")))
747 return 1;
749 post("reading startup file: %s", fname);
751 rcargv[0] = "."; /* this no longer matters to sys_argparse() */
753 for (i = 1; i < NUMARGS-1; i++)
755 if (fscanf(file, "%999s", buf) < 0)
756 break;
757 buf[1000] = 0;
758 if (!(rcargv[i] = malloc(strlen(buf) + 1)))
759 return (1);
760 strcpy(rcargv[i], buf);
762 if (i >= NUMARGS-1)
763 fprintf(stderr, "startup file too long; extra args dropped\n");
764 rcargv[i] = 0;
766 rcargc = i;
768 /* parse the options */
770 fclose(file);
771 if (sys_verbose)
773 if (rcargv)
775 post("startup args from RC file:");
776 for (i = 1; i < rcargc; i++)
777 post("%s", rcargv[i]);
779 else post("no RC file arguments found");
781 if (sys_argparse(rcargc, rcargv))
783 post("error parsing RC arguments");
784 return (1);
786 return (0);
788 #endif /* UNIX */
790 /* start an audio settings dialog window */
791 void glob_start_path_dialog(t_pd *dummy, t_floatarg flongform)
793 char buf[MAXPDSTRING];
794 int i;
795 t_namelist *nl;
797 for (nl = pd_path, i = 0; nl && i < 10; nl = nl->nl_next, i++)
798 sys_vgui("pd_set pd_path%d \"%s\"\n", i, nl->nl_string);
799 for (; i < 10; i++)
800 sys_vgui("pd_set pd_path%d \"\"\n", i);
802 sprintf(buf, "pdtk_path_dialog %%s\n");
803 gfxstub_new(&glob_pdobject, glob_start_path_dialog, buf);
806 /* new values from dialog window */
807 void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
809 int i;
810 namelist_free(pd_path);
811 pd_path = 0;
812 for (i = 0; i < argc; i++)
814 t_symbol *s = atom_getsymbolarg(i, argc, argv);
815 if (*s->s_name)
816 sys_addpath(s->s_name);