A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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. */
4
5/*
6 * This file implements the loader for linux, which includes
7 * a little bit of path handling.
8 *
9 * Generalized by MSP to provide an open_via_path function
10 * and lists of files for all purposes.
11 */
12
13/* #define PD_DEBUG(x) x */
14#define PD_DEBUG(x)
15void readsf_banana( void); /* debugging */
16
17#ifdef ROCKBOX
18
19#include "plugin.h"
20#include "../../pdbox.h"
21
22#include "m_pd.h"
23#include "m_imp.h"
24#include "s_stuff.h"
25
26#else /* ROCKBOX */
27#include <stdlib.h>
28#ifdef UNIX
29#include <unistd.h>
30#include <sys/stat.h>
31#endif
32#ifdef MSW
33#include <io.h>
34#endif
35
36#include <string.h>
37#include "m_pd.h"
38#include "m_imp.h"
39#include "s_stuff.h"
40#include <stdio.h>
41#include <fcntl.h>
42#endif /* ROCKBOX */
43
44static t_namelist *pd_path, *pd_helppath;
45
46/* Utility functions */
47
48/* copy until delimiter and return position after delimiter in string */
49/* if it was the last substring, return NULL */
50
51static const char* strtokcpy(char *to, const char *from, int delim)
52{
53 int size = 0;
54
55 while (from[size] != (char)delim && from[size] != '\0')
56 size++;
57
58 strncpy(to,from,size);
59 to[size] = '\0';
60 if (from[size] == '\0') return NULL;
61 if (size) return from+size+1;
62 else return NULL;
63}
64
65/* add a colon-separated list of names to a namelist */
66
67#ifdef MSW
68#define SEPARATOR ';'
69#else
70#define SEPARATOR ':'
71#endif
72
73static t_namelist *namelist_doappend(t_namelist *listwas, const char *s)
74{
75 t_namelist *nl = listwas, *rtn = listwas, *nl2;
76 nl2 = (t_namelist *)(getbytes(sizeof(*nl)));
77 nl2->nl_next = 0;
78 nl2->nl_string = (char *)getbytes(strlen(s) + 1);
79 strcpy(nl2->nl_string, s);
80 sys_unbashfilename(nl2->nl_string, nl2->nl_string);
81 if (!nl)
82 nl = rtn = nl2;
83 else
84 {
85 while (nl->nl_next)
86 nl = nl->nl_next;
87 nl->nl_next = nl2;
88 }
89 return (rtn);
90
91}
92
93t_namelist *namelist_append(t_namelist *listwas, const char *s)
94{
95 const char *npos;
96 char temp[MAXPDSTRING];
97 t_namelist *nl = listwas, *rtn = listwas;
98
99#ifdef ROCKBOX
100 (void) rtn;
101#endif
102
103 npos = s;
104 do
105 {
106 npos = strtokcpy(temp, npos, SEPARATOR);
107 if (! *temp) continue;
108 nl = namelist_doappend(nl, temp);
109 }
110 while (npos);
111 return (nl);
112}
113
114void namelist_free(t_namelist *listwas)
115{
116 t_namelist *nl, *nl2;
117 for (nl = listwas; nl; nl = nl2)
118 {
119 nl2 = nl->nl_next;
120 t_freebytes(nl->nl_string, strlen(nl->nl_string) + 1);
121 t_freebytes(nl, sizeof(*nl));
122 }
123}
124
125void sys_addpath(const char *p)
126{
127 pd_path = namelist_append(pd_path, p);
128}
129
130void sys_addhelppath(const char *p)
131{
132 pd_helppath = namelist_append(pd_helppath, p);
133}
134
135#ifdef MSW
136#define MSWOPENFLAG(bin) (bin ? _O_BINARY : _O_TEXT)
137#else
138#define MSWOPENFLAG(bin) 0
139#endif
140
141/* search for a file in a specified directory, then along the globally
142defined search path, using ext as filename extension. Exception:
143if the 'name' starts with a slash or a letter, colon, and slash in MSW,
144there is no search and instead we just try to open the file literally. The
145fd is returned, the directory ends up in the "dirresult" which must be at
146least "size" bytes. "nameresult" is set to point to the filename, which
147ends up in the same buffer as dirresult. */
148
149int open_via_path(const char *dir, const char *name, const char* ext,
150 char *dirresult, char **nameresult, unsigned int size, int bin)
151{
152 t_namelist *nl, thislist;
153 int fd = -1;
154 char listbuf[MAXPDSTRING];
155
156#ifdef ROCKBOX
157 (void) bin;
158#endif
159
160 if (name[0] == '/'
161#ifdef MSW
162 || (name[1] == ':' && name[2] == '/')
163#endif
164 )
165 {
166 thislist.nl_next = 0;
167 thislist.nl_string = listbuf;
168 listbuf[0] = 0;
169 }
170 else
171 {
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);
177 }
178
179 for (nl = &thislist; nl; nl = nl->nl_next)
180 {
181 if (strlen(nl->nl_string) + strlen(name) + strlen(ext) + 4 >
182 size)
183 continue;
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);
190
191 PD_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)
194 {
195 /* in UNIX, further check that it's not a directory */
196#ifdef UNIX
197 struct stat statbuf;
198 int ok = ((fstat(fd, &statbuf) >= 0) &&
199 !S_ISDIR(statbuf.st_mode));
200 if (!ok)
201 {
202 if (sys_verbose) post("tried %s; stat failed or directory",
203 dirresult);
204 close (fd);
205 fd = -1;
206 }
207 else
208#endif
209 {
210 char *slash;
211 if (sys_verbose) post("tried %s and succeeded", dirresult);
212 sys_unbashfilename(dirresult, dirresult);
213
214 slash = strrchr(dirresult, '/');
215 if (slash)
216 {
217 *slash = 0;
218 *nameresult = slash + 1;
219 }
220 else *nameresult = dirresult;
221
222 return (fd);
223 }
224 }
225 else
226 {
227 if (sys_verbose) post("tried %s and failed", dirresult);
228 }
229 }
230 *dirresult = 0;
231 *nameresult = dirresult;
232 return (-1);
233}
234
235static int do_open_via_helppath(const char *realname, t_namelist *listp)
236{
237 t_namelist *nl;
238 int fd = -1;
239 char dirresult[MAXPDSTRING], realdir[MAXPDSTRING];
240 for (nl = listp; nl; nl = nl->nl_next)
241 {
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);
248
249 PD_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)
252 {
253 /* in UNIX, further check that it's not a directory */
254#ifdef UNIX
255 struct stat statbuf;
256 int ok = ((fstat(fd, &statbuf) >= 0) &&
257 !S_ISDIR(statbuf.st_mode));
258 if (!ok)
259 {
260 if (sys_verbose) post("tried %s; stat failed or directory",
261 dirresult);
262 close (fd);
263 fd = -1;
264 }
265 else
266#endif
267 {
268#ifndef ROCKBOX
269 char *slash;
270#endif
271 if (sys_verbose) post("tried %s and succeeded", dirresult);
272 sys_unbashfilename(dirresult, dirresult);
273 close (fd);
274 glob_evalfile(0, gensym((char*)realname), gensym(realdir));
275 return (1);
276 }
277 }
278 else
279 {
280 if (sys_verbose) post("tried %s and failed", dirresult);
281 }
282 }
283 return (0);
284}
285
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
288 search attempts. */
289void open_via_helppath(const char *name, const char *dir)
290{
291#ifdef ROCKBOX
292 t_namelist thislist, *listp;
293#else /*ROCKBOX */
294 t_namelist *nl, thislist, *listp;
295 int fd = -1;
296#endif /* ROCKBOX */
297 char dirbuf2[MAXPDSTRING], realname[MAXPDSTRING];
298
299 /* if directory is supplied, put it at head of search list. */
300 if (*dir)
301 {
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);
307 listp = &thislist;
308 }
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))
317 return;
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))
323 return;
324 /* 3. "objectname.pd" */
325 if (do_open_via_helppath(name, listp))
326 return;
327 post("sorry, couldn't find help patch for \"%s\"", name);
328 return;
329}
330
331
332/* Startup file reading for linux and MACOSX. This should be replaced by
333a better mechanism. This should be integrated with the audio, MIDI, and
334path dialog system. */
335
336#ifdef UNIX
337
338#define STARTUPNAME ".pdrc"
339#define NUMARGS 1000
340
341int sys_argparse(int argc, char **argv);
342
343int sys_rcfile(void)
344{
345 FILE* file;
346 int i;
347 int k;
348 int rcargc;
349 char* rcargv[NUMARGS];
350 char* buffer;
351 char fname[MAXPDSTRING], buf[1000], *home = getenv("HOME");
352
353 /* parse a startup file */
354
355 *fname = '\0';
356
357 strncat(fname, home? home : ".", MAXPDSTRING-10);
358 strcat(fname, "/");
359
360 strcat(fname, STARTUPNAME);
361
362 if (!(file = fopen(fname, "r")))
363 return 1;
364
365 post("reading startup file: %s", fname);
366
367 rcargv[0] = "."; /* this no longer matters to sys_argparse() */
368
369 for (i = 1; i < NUMARGS-1; i++)
370 {
371 if (fscanf(file, "%999s", buf) < 0)
372 break;
373 buf[1000] = 0;
374 if (!(rcargv[i] = malloc(strlen(buf) + 1)))
375 return (1);
376 strcpy(rcargv[i], buf);
377 }
378 if (i >= NUMARGS-1)
379 fprintf(stderr, "startup file too long; extra args dropped\n");
380 rcargv[i] = 0;
381
382 rcargc = i;
383
384 /* parse the options */
385
386 fclose(file);
387 if (sys_verbose)
388 {
389 if (rcargv)
390 {
391 post("startup args from RC file:");
392 for (i = 1; i < rcargc; i++)
393 post("%s", rcargv[i]);
394 }
395 else post("no RC file arguments found");
396 }
397 if (sys_argparse(rcargc, rcargv))
398 {
399 post("error parsing RC arguments");
400 return (1);
401 }
402 return (0);
403}
404#endif /* UNIX */
405
406 /* start an audio settings dialog window */
407void glob_start_path_dialog(t_pd *dummy, t_floatarg flongform)
408{
409#ifdef ROCKBOX
410 (void) dummy;
411 (void) flongform;
412#else /* ROCKBOX */
413 char buf[MAXPDSTRING];
414 int i;
415 t_namelist *nl;
416
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);
419 for (; i < 10; i++)
420 sys_vgui("pd_set pd_path%d \"\"\n", i);
421
422 sprintf(buf, "pdtk_path_dialog %%s\n");
423 gfxstub_new(&glob_pdobject, glob_start_path_dialog, buf);
424#endif /* ROCKBOX */
425}
426
427 /* new values from dialog window */
428void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
429{
430 int i;
431
432#ifdef ROCKBOX
433 (void) dummy;
434 (void) s;
435#endif /* ROCKBOX */
436
437 namelist_free(pd_path);
438 pd_path = 0;
439 for (i = 0; i < argc; i++)
440 {
441 t_symbol *s = atom_getsymbolarg(i, argc, argv);
442 if (*s->s_name)
443 sys_addpath(s->s_name);
444 }
445}
446