A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 446 lines 11 kB view raw
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