//config.c: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009-2013 * * This file is part of libroar a part of RoarAudio, * a cross-platform sound system for both, home and professional use. * See README for details. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * libroar is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * NOTE for everyone want's to change something and send patches: * read README and HACKING! There a addition information on * the license of this document you need to read before you send * any patches. * * NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc * or libpulse*: * The libs libroaresd, libroararts and libroarpulse link this lib * and are therefore GPL. Because of this it may be illigal to use * them with any software that uses libesd, libartsc or libpulse*. */ #include "libroar.h" #define LEN_AUTHFILE 1024 static struct roar_libroar_config_codec * roar_libroar_config_codec_get_conf(int32_t codec, int create, struct roar_libroar_config * config); struct roar_libroar_config * roar_libroar_get_config_ptr(void) { static struct roar_libroar_config config; static int inited = 0; static char authfile[LEN_AUTHFILE]; const char * home; if ( !inited ) { memset(&config, 0, sizeof(config)); #ifdef ROAR_SUPPORT_TRAP config.trap_policy = ROAR_TRAP_IGNORE; #endif config.opmode = ROAR_LIBROAR_CONFIG_OPMODE_NORMAL; config.server = NULL; config.authfile = NULL; config.forkapi = NULL; config.connect_internal = NULL; config.daemonimage = NULL; config.protocolversion = -1; // use default. home = roar_env_get_home(0); if ( home != NULL ) { snprintf(authfile, sizeof(authfile)-1, "%s/.roarauth", home); authfile[sizeof(authfile)-1] = 0; config.authfile = authfile; config.serversfile = NULL; } inited++; } return &config; } struct roar_libroar_config * roar_libroar_get_config(void) { struct roar_libroar_config * config = roar_libroar_get_config_ptr(); static int inited = 0; const char * next; char * buf; if ( !inited ) { inited++; // we do this early so we can use ROAR_{DBG,INFO,WARN,ERR}() in roar_libroar_config_parse(). next = roar_env_get("ROAR_OPTIONS"); if ( next != NULL ) { if ( (buf = roar_mm_strdup(next)) != NULL ) { roar_libroar_config_parse(buf, " "); roar_mm_free(buf); } } } return config; } int roar_libroar_reset_config(void) { struct roar_libroar_config * config = roar_libroar_get_config_ptr(); if ( config->codecs.codec != NULL ) { roar_mm_free(config->codecs.codec); config->codecs.num = 0; } if ( config->x11.display != NULL ) roar_mm_free(config->x11.display); config->x11.display = NULL; if ( config->daemonimage != NULL ) roar_mm_free(config->daemonimage); config->daemonimage = NULL; return 0; } #define _P_FP(v) ((int)(atof((v))*256.0)) #define _P_INT(v) (atoi((v))) #define _P_BOOL(v) (*(v) == 'y' || *(v) == 'j' || *(v) == 't' || *(v) == '1' ? 1 : 0) static int roar_libroar_config_parse_codec(struct roar_libroar_config * config, char * txt) { struct roar_libroar_config_codec * codec_cfg; int32_t codec; char * codec_str, * option_str, * value_str; char * toksave = NULL; ROAR_DBG("roar_libroar_config_parse_codec(config=%p, txt='%s') = ?", config, txt); if ( config == NULL || txt == NULL ) return -1; ROAR_DBG("roar_libroar_config_parse_codec(config=%p, txt='%s') = ?", config, txt); codec_str = roar_mm_strtok_r(txt, ":", &toksave); if ( codec_str == NULL ) return -1; option_str = roar_mm_strtok_r(NULL, ":", &toksave); if ( option_str == NULL ) return -1; value_str = roar_mm_strtok_r(NULL, ":", &toksave); if ( value_str == NULL ) return -1; ROAR_DBG("roar_libroar_config_parse_codec(config=%p, txt='%s') = ?", config, txt); if ( (codec = roar_str2codec(codec_str)) == -1 ) { ROAR_WARN("roar_libroar_config_parse_codec(*): Unknown codec: %s", codec_str); return -1; } ROAR_DBG("roar_libroar_config_parse_codec(config=%p, txt='%s'): codec=%i", config, txt, codec); if ( (codec_cfg = roar_libroar_config_codec_get_conf(codec, 1, config)) == NULL ) return -1; ROAR_DBG("roar_libroar_config_parse_codec(config=%p, txt='%s'): codec=%i, codec_cfg=%p", config, txt, codec, codec_cfg); if ( !strcmp(option_str, "q") || !strcmp(option_str, "quality") ) { codec_cfg->para_set |= ROAR_LIBROAR_CONFIG_PSET_Q; codec_cfg->q = _P_FP(value_str); } else if ( !strcmp(option_str, "complexity") ) { codec_cfg->para_set |= ROAR_LIBROAR_CONFIG_PSET_COMPLEXITY; codec_cfg->complexity = _P_FP(value_str); } else if ( !strcmp(option_str, "dtx") ) { codec_cfg->para_set |= ROAR_LIBROAR_CONFIG_PSET_DTX; codec_cfg->dtx = _P_BOOL(value_str); } else if ( !strcmp(option_str, "cc-max") ) { codec_cfg->para_set |= ROAR_LIBROAR_CONFIG_PSET_MAX_CC; codec_cfg->max_cc = _P_INT(value_str); } else if ( !strcmp(option_str, "vbr") ) { codec_cfg->para_set |= ROAR_LIBROAR_CONFIG_PSET_VBR; codec_cfg->vbr = _P_BOOL(value_str); } else if ( !strcmp(option_str, "mode") ) { if ( !strcmp(value_str, "nb") ) { codec_cfg->para_set |= ROAR_LIBROAR_CONFIG_PSET_MODE; codec_cfg->mode = ROAR_LIBROAR_CONFIG_MODE_NB; } else if ( !strcmp(value_str, "wb") ) { codec_cfg->para_set |= ROAR_LIBROAR_CONFIG_PSET_MODE; codec_cfg->mode = ROAR_LIBROAR_CONFIG_MODE_WB; } else if ( !strcmp(value_str, "uwb") ) { codec_cfg->para_set |= ROAR_LIBROAR_CONFIG_PSET_MODE; codec_cfg->mode = ROAR_LIBROAR_CONFIG_MODE_UWB; } else { ROAR_WARN("roar_libroar_config_parse_codec(*): Unknown codec mode: %s", value_str); return -1; } } else { ROAR_WARN("roar_libroar_config_parse_codec(*): Unknown codec option: %s", option_str); return -1; } return 0; } int roar_libroar_config_parse(char * txt, char * delm) { struct roar_libroar_config * config = roar_libroar_get_config_ptr(); ssize_t len; char * k, * v, * next = txt; while (next != NULL) { k = next; if ( delm == NULL ) { // no delm -> we have only one option next = NULL; } else { next = strstr(next, delm); } if ( next != NULL ) { *next = 0; next++; } ROAR_DBG("roar_libroar_config_parse(*): k='%s'", k); // strip leading spaces: while ( *k == ' ' ) k++; ROAR_DBG("roar_libroar_config_parse(*): k='%s'", k); // strip tailing new lions: len = roar_mm_strlen(k); if ( len != -1 ) for (len--; len && (k[len] == '\r' || k[len] == '\n'); len--) k[len] = 0; ROAR_DBG("roar_libroar_config_parse(*): k='%s'", k); // comments if ( *k == '#' ) continue; ROAR_DBG("roar_libroar_config_parse(*): k='%s'", k); // empty options: if ( *k == 0 ) continue; if ( (v = strstr(k, ":")) != NULL ) { *v = 0; v++; } ROAR_DBG("roar_libroar_config_parse(*): k='%s', v='%s'", k, v); if ( !strcmp(k, "workaround") ) { if ( !strcmp(v, "use-execed") ) { config->workaround.workarounds |= ROAR_LIBROAR_CONFIG_WAS_USE_EXECED; } else if ( !strcmp(v, "no-slp") ) { config->workaround.workarounds |= ROAR_LIBROAR_CONFIG_WAS_NO_SLP; } else { ROAR_WARN("roar_libroar_config_parse(*): Unknown workaround option: %s", v); } } else if ( !strcmp(k, "warning") || !strcmp(k, "warn") ) { if ( !strcmp(v, "sysio") ) { config->warnings.sysio = ROAR_WARNING_ALWAYS; } else if ( !strcmp(v, "obsolete") ) { config->warnings.obsolete = ROAR_WARNING_ALWAYS; } else if ( !strcmp(v, "all") ) { config->warnings.sysio = ROAR_WARNING_ALWAYS; config->warnings.obsolete = ROAR_WARNING_ALWAYS; } else { ROAR_WARN("roar_libroar_config_parse(*): Unknown warning option: %s", v); } } else if ( !strcmp(k, "opmode") ) { if ( !strcmp(v, "normal") ) { config->opmode = ROAR_LIBROAR_CONFIG_OPMODE_NORMAL; } else if ( !strcmp(v, "funny") ) { config->opmode = ROAR_LIBROAR_CONFIG_OPMODE_FUNNY; } else if ( !strcmp(v, "ms") ) { config->opmode = ROAR_LIBROAR_CONFIG_OPMODE_MS; } else { ROAR_WARN("roar_libroar_config_parse(*): Unknown opmode: %s", v); } #ifdef ROAR_SUPPORT_TRAP } else if ( !strcmp(k, "trap-policy") ) { if ( !strcmp(v, "ignore") ) { config->trap_policy = ROAR_TRAP_IGNORE; } else if ( !strcmp(v, "warn") ) { config->trap_policy = ROAR_TRAP_WARN; } else if ( !strcmp(v, "abort") ) { config->trap_policy = ROAR_TRAP_ABORT; #ifdef SIGKILL } else if ( !strcmp(v, "kill") ) { config->trap_policy = ROAR_TRAP_KILL; #endif #ifdef SIGSTOP } else if ( !strcmp(v, "stop") ) { config->trap_policy = ROAR_TRAP_STOP; #endif } else if ( !strcmp(v, "die") ) { config->trap_policy = ROAR_TRAP_DIE; } else { ROAR_WARN("roar_libroar_config_parse(*): Unknown trap policy: %s", v); } #endif } else if ( !strcmp(k, "force-rate") ) { config->info.rate = roar_str2rate(v); } else if ( !strcmp(k, "force-bits") ) { config->info.bits = roar_str2bits(v); } else if ( !strcmp(k, "force-channels") ) { config->info.channels = roar_str2channels(v); } else if ( !strcmp(k, "force-codec") ) { config->info.codec = roar_str2codec(v); } else if ( !strcmp(k, "codec") ) { if ( roar_libroar_config_parse_codec(config, v) == -1 ) { ROAR_WARN("roar_libroar_config_parse(*): Error parsing codec config option"); } } else if ( !strcmp(k, "set-server") ) { if ( roar_libroar_get_server() == NULL ) roar_libroar_set_server(v); } else if ( !strcmp(k, "set-authfile") ) { strncpy(config->authfile, v, LEN_AUTHFILE-1); config->authfile[LEN_AUTHFILE-1] = 0; } else if ( !strcmp(k, "x11-display") ) { if ( config->x11.display != NULL ) roar_mm_free(config->x11.display); config->x11.display = roar_mm_strdup(v); } else if ( !strcmp(k, "daemonimage") ) { if ( config->daemonimage != NULL ) roar_mm_free(config->daemonimage); config->daemonimage = roar_mm_strdup(v); } else if ( !strcmp(k, "serverflags") ) { if ( !strcmp(v, "nonblock") ) { config->serverflags |= ROAR_ENUM_FLAG_NONBLOCK; } else if ( !strcmp(v, "hardnonblock") ) { config->serverflags |= ROAR_ENUM_FLAG_HARDNONBLOCK; } else if ( !strcmp(v, "localonly") ) { config->serverflags |= ROAR_ENUM_FLAG_LOCALONLY; } else { ROAR_WARN("roar_libroar_config_parse(*): Unknown serverflag: %s", v); } } else if ( !strcmp(k, "protocolversion") ) { config->protocolversion = atoi(v); } else { ROAR_WARN("roar_libroar_config_parse(*): Unknown option: %s", k); } } return 0; } struct roar_libroar_config_codec * roar_libroar_config_codec_get(int32_t codec, int create) { struct roar_libroar_config * config = roar_libroar_get_config(); return roar_libroar_config_codec_get_conf(codec, create, config); } static struct roar_libroar_config_codec * roar_libroar_config_codec_get_conf(int32_t codec, int create, struct roar_libroar_config * config) { size_t i; int need_new = 1; ROAR_DBG("roar_libroar_config_codec_get_conf(codec=%i, create=%i, config=%p) = ?", codec, create, config); if ( codec < 0 || create < 0 ) return NULL; ROAR_DBG("roar_libroar_config_codec_get_conf(codec=%i, create=%i, config=%p) = ?", codec, create, config); if ( config->codecs.num == 0 ) { // no match case: if ( !create ) return NULL; } else { for (i = 0; i < config->codecs.num; i++) { if ( config->codecs.codec[i].codec == (uint32_t)codec ) return &(config->codecs.codec[i]); if ( config->codecs.codec[i].codec == (uint32_t)-1 ) need_new = 0; } } ROAR_DBG("roar_libroar_config_codec_get_conf(codec=%i, create=%i, config=%p) = ?", codec, create, config); if ( !create ) return NULL; if ( !need_new ) { for (i = 0; i < config->codecs.num; i++) { if ( config->codecs.codec[i].codec == (uint32_t)-1 ) { memset(&(config->codecs.codec[i]), 0, sizeof(struct roar_libroar_config_codec)); config->codecs.codec[i].codec = codec; return &(config->codecs.codec[i]); } } } if ( config->codecs.num == 0 ) { config->codecs.codec = roar_mm_malloc(16*sizeof(struct roar_libroar_config_codec)); } else { config->codecs.codec = roar_mm_realloc(config->codecs.codec, (config->codecs.num+16)*sizeof(struct roar_libroar_config_codec)); } if ( config->codecs.codec == NULL ) return NULL; memset(&(config->codecs.codec[config->codecs.num]), 0, 16); for (i = config->codecs.num; i < (config->codecs.num+16); i++) { config->codecs.codec[i].codec = (uint32_t)-1; } i = config->codecs.num; config->codecs.num += 16; memset(&(config->codecs.codec[i]), 0, sizeof(struct roar_libroar_config_codec)); config->codecs.codec[i].codec = codec; return &(config->codecs.codec[i]); } int roar_libroar_set_server(const char * server) { roar_libroar_get_config_ptr()->server = server; return 0; } const char * roar_libroar_get_server(void) { return roar_libroar_get_config_ptr()->server; } int roar_libroar_set_forkapi(const struct roar_libroar_forkapi * api) { roar_libroar_get_config_ptr()->forkapi = api; return 0; } int roar_libroar_set_connect_internal(struct roar_vio_calls * (*func)(struct roar_connection * con, const char * server, int type, int flags, uint_least32_t timeout)) { roar_libroar_get_config_ptr()->connect_internal = func; return 0; } void roar_libroar_nowarn(void) { roar_libroar_get_config_ptr()->nowarncounter++; } void roar_libroar_warn(void) { struct roar_libroar_config * cfg = roar_libroar_get_config_ptr(); if ( cfg->nowarncounter == 0 ) { ROAR_WARN("roar_libroar_warn(): Re-Enabling already enabled warnings! (Application error?)"); return; } cfg->nowarncounter--; } static const struct pathinfo { const char * name; const char * path; const int with_product; // 0 = no, 1 = yes, 2 = just product. const int with_provider; } __paths[] = { // prefixes: {"prefix", ROAR_PREFIX, 0, 0}, {"prefix-bin", ROAR_PREFIX_BIN, 0, 0}, {"prefix-sbin", ROAR_PREFIX_SBIN, 0, 0}, {"prefix-lib", ROAR_PREFIX_LIB, 0, 0}, {"prefix-inc", ROAR_PREFIX_INC, 0, 0}, {"prefix-man", ROAR_PREFIX_MAN, 0, 0}, {"prefix-man1", ROAR_PREFIX_MAN "/man1", 0, 0}, {"prefix-man2", ROAR_PREFIX_MAN "/man2", 0, 0}, {"prefix-man3", ROAR_PREFIX_MAN "/man3", 0, 0}, {"prefix-man4", ROAR_PREFIX_MAN "/man4", 0, 0}, {"prefix-man5", ROAR_PREFIX_MAN "/man5", 0, 0}, {"prefix-man6", ROAR_PREFIX_MAN "/man6", 0, 0}, {"prefix-man7", ROAR_PREFIX_MAN "/man7", 0, 0}, {"prefix-man8", ROAR_PREFIX_MAN "/man8", 0, 0}, {"prefix-man9", ROAR_PREFIX_MAN "/man9", 0, 0}, {"prefix-pc", ROAR_PREFIX_PC, 0, 0}, {"prefix-ckport", ROAR_PREFIX_CKPORT, 0, 0}, {"prefix-sysconf", ROAR_PREFIX_SYSCONF, 2, 0}, {"prefix-dev", ROAR_PREFIX_DEV, 0, 0}, {"prefix-doc", ROAR_PREFIX_DOC, 2, 0}, {"prefix-tmp", ROAR_PREFIX_TMP, 0, 0}, {"prefix-var", ROAR_PREFIX_VAR, 0, 0}, {"prefix-cache", ROAR_PREFIX_CACHE, 2, 0}, {"prefix-data", ROAR_PREFIX_DATA, 2, 0}, {"prefix-lock", ROAR_PREFIX_LOCK, 0, 0}, {"prefix-log", ROAR_PREFIX_LOG, 0, 0}, {"prefix-mail", ROAR_PREFIX_MAIL, 0, 0}, {"prefix-run", ROAR_PREFIX_RUN, 0, 0}, {"prefix-spool", ROAR_PREFIX_SPOOL, 2, 0}, {"prefix-comp-libs", ROAR_PREFIX_COMP_LIBS, 0, 0}, {"prefix-comp-bins", ROAR_PREFIX_COMP_BINS, 0, 0}, {"prefix-plugins", ROAR_PREFIX_PLUGINS, 1, 1}, {"prefix-buildsystem", ROAR_PREFIX_BUILDSYSTEM, 0, 0}, // bins: {"bin-default-daemonimage", "roard", 0, 0}, #ifdef ROAR_HAVE_BIN_SH {"bin-sh", ROAR_HAVE_BIN_SH, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_OGG123 {"bin-ogg123", ROAR_HAVE_BIN_OGG123, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_FLAC {"bin-flac", ROAR_HAVE_BIN_FLAC, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_TIMIDITY {"bin-timidity", ROAR_HAVE_BIN_TIMIDITY, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_CDPARANOIA {"bin-cdparanoia", ROAR_HAVE_BIN_CDPARANOIA, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_GNUPLOT {"bin-gnuplot", ROAR_HAVE_BIN_GNUPLOT, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_SSH {"bin-ssh", ROAR_HAVE_BIN_SSH, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_PINENTRY {"bin-pinentry", ROAR_HAVE_BIN_PINENTRY, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_SSH_ASKPASS {"bin-ssh-askpass", ROAR_HAVE_BIN_SSH_ASKPASS, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_GTK_LED_ASKPASS {"bin-gtk-led-askpass", ROAR_HAVE_BIN_GTK_LED_ASKPASS, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_X11_SSH_ASKPASS {"bin-x11-ssh-askpass", ROAR_HAVE_BIN_X11_SSH_ASKPASS, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_GNOME_SSH_ASKPASS {"bin-gnome-ssh-askpass", ROAR_HAVE_BIN_GNOME_SSH_ASKPASS, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_GPG {"bin-gpg", ROAR_HAVE_BIN_GPG, 0, 0}, #endif #ifdef ROAR_HAVE_BIN_EJECT {"bin-eject", ROAR_HAVE_BIN_EJECT, 0, 0}, #endif // devices: {"dev-stdin", ROAR_PREFIX_DEV "/stdin", 0, 0}, {"dev-default-pwmled", ROAR_PREFIX_DEV "/ttyS0", 0, 0}, {"dev-default-dmx4linux", ROAR_PREFIX_DEV "/dmx", 0, 0}, #ifdef ROAR_DEFAULT_CDROM {"dev-default-cdrom", ROAR_DEFAULT_CDROM, 0, 0}, #endif #ifdef ROAR_DEFAULT_TTY {"dev-default-tty", ROAR_DEFAULT_TTY, 0, 0}, #endif #ifdef ROAR_DEFAULT_OSS_DEV {"dev-default-oss-dev", ROAR_DEFAULT_OSS_DEV, 0, 0}, #endif #ifdef ROAR_DEFAULT_OSS_MIX_DEV {"dev-default-oss-mix-dev", ROAR_DEFAULT_OSS_MIX_DEV, 0, 0}, #endif // proc: #ifdef ROAR_PROC_NET_DECNET {"proc-net-decnet", ROAR_PROC_NET_DECNET, 0, 0}, #endif #ifdef ROAR_PROC_NET_DECNET_NEIGH {"proc-net-decnet-neigh", ROAR_PROC_NET_DECNET_NEIGH, 0, 0}, #endif #ifdef ROAR_PROC_NET_ARP {"proc-net-arp", ROAR_PROC_NET_ARP, 0, 0}, #endif // sysconf: {"sysconf-hosts", ROAR_PREFIX_SYSCONF "/hosts", 0, 0}, {"sysconf-roarserver", ROAR_PREFIX_SYSCONF "/roarserver", 0, 0}, // special dirs: {"dir-nx-home", "/NX-HOME-DIR", 0, 0} }; static int __product2path(char * path, size_t pathlen, int null_as_universal, const char * product, int type) { const char * c; const char * e; const char * s; const char * b; if ( product != NULL && !strcmp(product, "universal") ) { null_as_universal = 1; product = NULL; } if ( product == NULL ) { if ( null_as_universal ) { if ( type == 2 ) { snprintf(path, pathlen, "/universal"); } else { snprintf(path, pathlen, "/universal/universal"); } } else { path[0] = 0; } return 0; } b = strstr(product, " "); c = strstr(product, "<"); e = strstr(product, ">"); if ( b == NULL || c == NULL || e == NULL || c < b || e < c ) { roar_err_set(ROAR_ERROR_ILLSEQ); return -1; } c++; s = strstr(c, "/"); if ( type == 2 ) { snprintf(path, pathlen, "/%.*s", (int)(size_t)(b-product), product); } else if ( s == NULL ) { snprintf(path, pathlen, "/unreg-%.*s/%.*s", (int)(size_t)(e-c), c, (int)(size_t)(b-product), product); } else { snprintf(path, pathlen, "/%.*s-%.*s/%.*s", (int)(size_t)(s-c), c, (int)(size_t)(e-s-1), s+1, (int)(size_t)(b-product), product); } return 0; } static int __provider2path(char * path, size_t pathlen, const char * provider) { const char * c; const char * e; const char * s; if ( provider == NULL ) { path[0] = 0; return 0; } c = strstr(provider, "<"); e = strstr(provider, ">"); if ( c == NULL || e == NULL || e < c ) { roar_err_set(ROAR_ERROR_ILLSEQ); return -1; } c++; s = strstr(c, "/"); if ( s == NULL ) { snprintf(path, pathlen, "/unreg-%.*s", (int)(size_t)(e-c), c); } else { snprintf(path, pathlen, "/%.*s-%.*s", (int)(size_t)(s-c), c, (int)(size_t)(e-s-1), s+1); } return 0; roar_err_set(ROAR_ERROR_NOTSUP); return -1; } static const struct pathinfo * __lookup_path(const char * name) { size_t i; if ( name == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return NULL; } for (i = 0; i < (sizeof(__paths)/sizeof(*__paths)); i++) if ( !strcmp(__paths[i].name, name) ) return &(__paths[i]); roar_err_set(ROAR_ERROR_NOENT); return NULL; } void __strip_double_slashes(char * p) { const char * in = p; for (; *in; in++, p++) { *p = *in; if ( *in == '/' ) for (; in[1] == '/'; in++); } *p = 0; } char * roar_libroar_get_path(const char * name, int null_as_universal, const char * product, const char * provider) { const struct pathinfo * path; char buf_product[384]; char buf_provider[384]; ssize_t len_prefix, len_product, len_provider; char * ret, * p; ROAR_DBG("roar_libroar_get_path(name='%s', null_as_universal=%i, product='%s', provider='%s') = ?", name, null_as_universal, product, provider); path = __lookup_path(name); if ( path == NULL ) return NULL; if ( ((null_as_universal || product != NULL) && !path->with_product) || (provider != NULL && !path->with_provider) || (!null_as_universal && product == NULL && provider != NULL) ) { roar_err_set(ROAR_ERROR_INVAL); return NULL; } if ( __product2path(buf_product, sizeof(buf_product), null_as_universal, product, path->with_product) == -1 ) return NULL; if ( __provider2path(buf_provider, sizeof(buf_provider), provider) == -1 ) return NULL; len_prefix = roar_mm_strlen(path->path); len_product = roar_mm_strlen(buf_product); len_provider = roar_mm_strlen(buf_provider); p = ret = roar_mm_malloc(len_prefix+len_product+len_provider+1); if ( ret == NULL ) return NULL; memcpy(p, path->path, len_prefix); p += len_prefix; if ( p[-1] == '/' ) p--; memcpy(p, buf_product, len_product); p += len_product; memcpy(p, buf_provider, len_provider); p += len_provider; *p = 0; __strip_double_slashes(ret); return ret; } const char * roar_libroar_get_path_static(const char * name) { const struct pathinfo * path; path = __lookup_path(name); if ( path == NULL ) return NULL; return path->path; } ssize_t roar_libroar_list_path(const char ** list, size_t len, size_t offset) { size_t i; ssize_t idx = 0; ROAR_DBG("roar_libroar_list_path(list=%p, len=%lu, offset=%lu) = ?", list, (long unsigned int)len, (long unsigned int)offset); if ( list == NULL ) { roar_err_set(ROAR_ERROR_FAULT); return -1; } if ( len == 0 ) return 0; if ( offset >= (sizeof(__paths)/sizeof(*__paths)) ) return 0; for (i = offset; idx < len && i < (sizeof(__paths)/sizeof(*__paths)); i++) { list[idx++] = __paths[i].name; } return idx; } //ll