From 9a396eca29108af0ddcffdd007ed3c03639eddda Mon Sep 17 00:00:00 2001 From: Ron Pedde Date: Sun, 26 Mar 2006 22:07:33 +0000 Subject: [PATCH] Make compdirs work again, closing ticket #15 --- src/conf.c | 324 +++++++++++++++++++++++++++++++++++++--------- src/conf.h | 3 + src/mp3-scanner.c | 26 ++-- 3 files changed, 279 insertions(+), 74 deletions(-) diff --git a/src/conf.c b/src/conf.c index 2ab9eee9..18bb7399 100644 --- a/src/conf.c +++ b/src/conf.c @@ -74,14 +74,16 @@ typedef struct _CONF_ELEMENTS { /** Forwards */ static int _conf_verify(LL_HANDLE pll); -static LL_ITEM *_conf_fetch_item(LL_HANDLE pll, char *section, char *term); -static int _conf_exists(LL_HANDLE pll, char *section, char *term); +static LL_ITEM *_conf_fetch_item(LL_HANDLE pll, char *section, char *key); +static int _conf_exists(LL_HANDLE pll, char *section, char *key); static void _conf_lock(void); static void _conf_unlock(void); static int _conf_write(FILE *fp, LL *pll, int sublevel, char *parent); static CONF_ELEMENTS *_conf_get_keyinfo(char *section, char *key); static int _conf_makedir(char *path, char *user); static int _conf_existdir(char *path); +static int _conf_split(char *s, char *delimiters, char ***argvp); +static void _conf_dispose_split(char **argv); static CONF_ELEMENTS conf_elements[] = { { 1, 0, CONF_T_STRING,"general","runas" }, @@ -130,7 +132,7 @@ int _conf_makedir(char *path,char *user) { pathdup=strdup(path); if(!pathdup) { - DPRINTF(E_FATAL,L_CONF,"Malloc error\n"); + DPRINTF(E_FATAL,L_CONF,"Malloc error\n"); } next_token=pathdup+1; @@ -141,21 +143,21 @@ int _conf_makedir(char *path,char *user) { strcat(path_buffer,"/"); strcat(path_buffer,token); - if(!_conf_existdir(path_buffer)) { - /* FIXME: this is wrong -- it should really be 0700 owned by - * the runas user. That would require some os_ indirection - */ - DPRINTF(E_DBG,L_CONF,"Making %s\n",path_buffer); - if((mkdir(path_buffer,0700)) && (errno != EEXIST)) { - free(pathdup); - DPRINTF(E_LOG,L_CONF,"Could not make dirctory %s: %s\n", - path_buffer,strerror(errno)); - return FALSE; - } - os_chown(path_buffer,user); - } - retval = TRUE; - } + if(!_conf_existdir(path_buffer)) { + /* FIXME: this is wrong -- it should really be 0700 owned by + * the runas user. That would require some os_ indirection + */ + DPRINTF(E_DBG,L_CONF,"Making %s\n",path_buffer); + if((mkdir(path_buffer,0700)) && (errno != EEXIST)) { + free(pathdup); + DPRINTF(E_LOG,L_CONF,"Could not make dirctory %s: %s\n", + path_buffer,strerror(errno)); + return FALSE; + } + os_chown(path_buffer,user); + } + retval = TRUE; + } } free(pathdup); @@ -241,10 +243,10 @@ void _conf_unlock() { * * @param pll top level linked list to test (config tree) * @param section section to term (key) is in - * @param term term/key to look for + * @param key key to look for * @returns LL_ITEM of the key, or NULL */ -LL_ITEM *_conf_fetch_item(LL_HANDLE pll, char *section, char *term) { +LL_ITEM *_conf_fetch_item(LL_HANDLE pll, char *section, char *key) { LL_ITEM *psection; LL_ITEM *pitem; @@ -254,7 +256,7 @@ LL_ITEM *_conf_fetch_item(LL_HANDLE pll, char *section, char *term) { if(psection->type != LL_TYPE_LL) return NULL; - if(!(pitem = ll_fetch_item(psection->value.as_ll,term))) + if(!(pitem = ll_fetch_item(psection->value.as_ll,key))) return NULL; return pitem; @@ -265,11 +267,11 @@ LL_ITEM *_conf_fetch_item(LL_HANDLE pll, char *section, char *term) { * * @param pll config tree to test * @param section section to find the term under - * @param term key to search for under the specified section + * @param key key to search for under the specified section * @returns TRUE if key exists, FALSE otherwise */ -int _conf_exists(LL_HANDLE pll, char *section, char *term) { - if(!_conf_fetch_item(pll,section,term)) +int _conf_exists(LL_HANDLE pll, char *section, char *key) { + if(!_conf_fetch_item(pll,section,key)) return FALSE; return TRUE; @@ -312,37 +314,37 @@ int _conf_verify(LL_HANDLE pll) { } } if(pce->type == CONF_T_EXISTPATH) { - /* first, need to resolve */ + /* first, need to resolve */ pi = _conf_fetch_item(pll,pce->section, pce->term); if(pi) { memset(resolved_path,0,sizeof(resolved_path)); if(pi->value.as_string) { - DPRINTF(E_SPAM,L_CONF,"Found %s/%s as %s... checking\n", - pce->section, pce->term, pi->value.as_string); + DPRINTF(E_SPAM,L_CONF,"Found %s/%s as %s... checking\n", + pce->section, pce->term, pi->value.as_string); - /* verify it exists, creating it if necessary */ - if(!_conf_existdir(pi->value.as_string)) { - user = "nobody"; - ptemp = _conf_fetch_item(pll, "general", "runas"); - if(ptemp) { - user = ptemp->value.as_string; - } - - if(!_conf_makedir(pi->value.as_string,user)) { - is_valid=0; - DPRINTF(E_LOG,L_CONF,"Can't make path %s, invalid config.\n", - resolved_path); - } - } + /* verify it exists, creating it if necessary */ + if(!_conf_existdir(pi->value.as_string)) { + user = "nobody"; + ptemp = _conf_fetch_item(pll, "general", "runas"); + if(ptemp) { + user = ptemp->value.as_string; + } - if(_conf_existdir(pi->value.as_string)) { - realpath(pi->value.as_string,resolved_path); - free(pi->value.as_string); - pi->value.as_string = strdup(resolved_path); + if(!_conf_makedir(pi->value.as_string,user)) { + is_valid=0; + DPRINTF(E_LOG,L_CONF,"Can't make path %s, invalid config.\n", + resolved_path); + } + } - DPRINTF(E_SPAM,L_CONF,"Resolved to %s\n",resolved_path); - } - } + if(_conf_existdir(pi->value.as_string)) { + realpath(pi->value.as_string,resolved_path); + free(pi->value.as_string); + pi->value.as_string = strdup(resolved_path); + + DPRINTF(E_SPAM,L_CONF,"Resolved to %s\n",resolved_path); + } + } } } pce++; @@ -365,6 +367,7 @@ int conf_read(char *file) { FILE *fin; int err; LL_HANDLE pllnew, plltemp, pllcurrent, pllcomment; + LL_ITEM *pli; char linebuffer[CONF_LINEBUFFER+1]; char keybuffer[256]; char *comment, *term, *value, *delim; @@ -378,6 +381,8 @@ int conf_read(char *file) { int ws=0; CONF_ELEMENTS *pce; int key_type; + char **valuearray; + int index; if(conf_main_file) { conf_close(); @@ -523,6 +528,30 @@ int conf_read(char *file) { switch(key_type) { case CONF_T_MULTICOMMA: + /* first, see if we already have a tree... */ + pli = ll_fetch_item(pllcurrent,term); + if(!pli) { + if((ll_create(&plltemp) != LL_E_SUCCESS)) { + DPRINTF(E_FATAL,L_CONF,"Could not create " + "linked list.\n"); + } + ll_add_ll(pllcurrent,term,plltemp); + ll_set_flags(plltemp,0); /* allow dups */ + } else { + plltemp = pli->value.as_ll; + } + + /* got list, break comma sep and add */ + if(_conf_split(value,",",&valuearray) >= 0) { + index = 0; + while(valuearray[index]) { + ll_add_string(plltemp,term,valuearray[index]); + index++; + } + _conf_dispose_split(valuearray); + } else { + ll_add_string(plltemp,term,value); + } break; case CONF_T_INT: case CONF_T_STRING: @@ -730,18 +759,31 @@ int conf_get_string(char *section, char *key, char *dflt, char *out, int *size) * @returns a pointer to an allocated string containing the required * configuration key */ -char *conf_alloc_string (char *section, char *key, char *dflt) { - int size = -1; - char *out; +char *conf_alloc_string(char *section, char *key, char *dflt) { + LL_ITEM *pitem; + char *result; + char *retval; - /* FIXME: races */ - conf_get_string(section, key, dflt, NULL, &size); - out = (char *)malloc(size * sizeof(char)); + _conf_lock(); + pitem = _conf_fetch_item(conf_main,section,key); + if((!pitem) || (pitem->type != LL_TYPE_STRING)) { + result = dflt; + } else { + result = pitem->value.as_string; + } - if(conf_get_string (section, key, dflt, out, &size) != CONF_E_SUCCESS) - return NULL; + if(result == NULL) { + _conf_unlock(); + return NULL; + } - return out; + retval = strdup(result); + + if(!retval) { + DPRINTF(E_FATAL,L_CONF,"Malloc error in conf_alloc_string\n"); + } + _conf_unlock(); + return retval; } @@ -868,6 +910,8 @@ int conf_write(void) { int _conf_write(FILE *fp, LL *pll, int sublevel, char *parent) { LL_ITEM *pli; LL_ITEM *ppre, *pin; + LL_ITEM *plitemp; + char keybuffer[256]; if(!pll) @@ -896,8 +940,11 @@ int _conf_write(FILE *fp, LL *pll, int sublevel, char *parent) { switch(pli->type) { case LL_TYPE_LL: if(sublevel) { - /* something wrong! */ - DPRINTF(E_LOG,L_CONF,"LL in sublevel: %s\n",pli->key); + /* must be multivalued */ + plitemp = NULL; + while((plitemp = ll_get_next(pli->value.as_ll,plitemp))) { + fprintf(fp,"%s = %s\n",pli->key,plitemp->value.as_string); + } } else { fprintf(fp,"[%s]",pli->key); if(pin) { @@ -978,6 +1025,7 @@ int _conf_split(char *s, char *delimiters, char ***argvp) { const char *snew; char *t; char *tokptr; + char *tmp; if ((s == NULL) || (delimiters == NULL) || (argvp == NULL)) return -1; @@ -989,8 +1037,13 @@ int _conf_split(char *s, char *delimiters, char ***argvp) { strcpy(t, snew); numtokens = 0; tokptr = NULL; - while(strtok_r(t,delimiters,&tokptr) != NULL) + tmp = t; + while(strtok_r(tmp,delimiters,&tokptr) != NULL) { + tmp=NULL; numtokens++; + } + + DPRINTF(E_DBG,L_CONF,"Found %d tokens in %s\n",numtokens,s); if ((*argvp = malloc((numtokens + 1)*sizeof(char *))) == NULL) { free(t); @@ -1002,10 +1055,157 @@ int _conf_split(char *s, char *delimiters, char ***argvp) { else { strcpy(t, snew); tokptr = NULL; - for (i = 0; i < numtokens; i++) - *((*argvp) + i) = strtok_r(t, delimiters, &tokptr); + tmp = t; + for (i = 0; i < numtokens; i++) { + *((*argvp) + i) = strtok_r(tmp, delimiters, &tokptr); + tmp=NULL; + DPRINTF(E_DBG,L_CONF,"Token %d: %s\n",i+1,(*argvp)[i]); + } } *((*argvp) + numtokens) = NULL; return numtokens; } + +/** + * implode a multivalued term in a perl sense. + * + * @param section section of term to implode + * @param key key of term to implode + * @pararm delimiter what to "glue" them with + * @returns imploded string (preallocated), or NULL + */ +char *conf_implode(char *section, char *key, char *delimiter) { + LL_ITEM *pitem; + LL_ITEM *penum; + int count; + int len; + char *retval; + + _conf_lock(); + pitem = _conf_fetch_item(conf_main,section,key); + if((!pitem) || (pitem->type != LL_TYPE_LL)) { + _conf_unlock(); + return NULL; + } + + /* otherwise, alloc a string and go */ + count = len = 0; + penum = NULL; + while((penum = ll_get_next(pitem->value.as_ll,penum))) { + if(penum->type != LL_TYPE_STRING) { + DPRINTF(E_FATAL,L_CONF,"multivalued property not a string?\n"); + } + len += strlen(penum->value.as_string); + count++; + } + + if(!count) { + _conf_unlock(); + return NULL; + } + + len += (strlen(delimiter) * (count-1)); + retval = (char*)malloc(len + 1); + if(!retval) { + DPRINTF(E_FATAL,L_CONF,"conf_implode: malloc\n"); + } + + memset(retval,0,len+1); + penum = NULL; + while((penum = ll_get_next(pitem->value.as_ll,penum))) { + strcat(retval,penum->value.as_string); + if(--count) { + strcat(retval,delimiter); + } + } + + _conf_unlock(); + return retval; +} + +/** + * dispose of the argv set that was created in _conf_split + * + * @param argv string array to delete + */ +void _conf_dispose_split(char **argv) { + if(!argv) + return; + + if(argv[0]) + free(argv[0]); + + free(argv); +} + + +/** + * return a multi-valued item as an array (values) + * + * @param section section to fetch + * @param key multivalued key to get from array + * @returns TRUE on success, FALSE on failure + */ +int conf_get_array(char *section, char *key, char ***argvp) { + LL_ITEM *pitem, *penum; + int count; + int len; + + _conf_lock(); + pitem = _conf_fetch_item(conf_main,section,key); + if((!pitem) || (pitem->type != LL_TYPE_LL)) { + _conf_unlock(); + return FALSE; + } + + /* otherwise, alloc a string and go */ + count = 0; + penum = NULL; + while((penum = ll_get_next(pitem->value.as_ll,penum))) { + if(penum->type != LL_TYPE_STRING) { + DPRINTF(E_FATAL,L_CONF,"multivalued property not a string?\n"); + } + count++; + } + + /* now we have a count, alloc an argv */ + len = (count+1) * sizeof(char*); + *(argvp) = (char**)malloc(len); + if(!*(argvp)) { + DPRINTF(E_FATAL,L_CONF,"conf_get_array: malloc\n"); + } + + memset(*(argvp),0,len); + + count=0; + penum=NULL; + while((penum = ll_get_next(pitem->value.as_ll,penum))) { + (*argvp)[count] = strdup(penum->value.as_string); + if(!(*argvp)[count]) { + DPRINTF(E_FATAL,L_CONF,"conf_get_array: malloc\n"); + } + count++; + } + + _conf_unlock(); + return TRUE; +} + +/** + * dispose of the array created above + * + * @param argv argv pointer created + */ +void conf_dispose_array(char **argv) { + int index=0; + + if(!argv) + return; + + + while(argv[index]) { + free(argv[index]); + index++; + } +} diff --git a/src/conf.h b/src/conf.h index 5c08c9b8..5ab32321 100644 --- a/src/conf.h +++ b/src/conf.h @@ -45,4 +45,7 @@ extern int conf_isset(char *section, char *key); extern int conf_iswritable(void); extern int conf_write(void); +extern char *conf_implode(char *section, char *key, char *delimiter); +extern int conf_get_array(char *section, char *key, char ***argvp); +extern void conf_dispose_array(char **argv); #endif /* _CONFIG_H_ */ diff --git a/src/mp3-scanner.c b/src/mp3-scanner.c index 7b2957ab..9009bc23 100644 --- a/src/mp3-scanner.c +++ b/src/mp3-scanner.c @@ -261,22 +261,24 @@ int scan_init(char *path) { * check to see if a particular path is a complation path * * @param path path to check - * @returns 1 if it is a compilation path, 0 otherwise + * @returns TRUE if it is a compilation path, FALSE otherwise */ int scan_is_compdir(char *path) { -#if 0 int current=0; + char **compdirs; - if(!config.complist) - return 0; + if(!conf_get_array("general","compdirs",&compdirs)) + return FALSE; - while(config.complist[current]) { - if(strcasestr(path,config.complist[current])) - return 1; + while(compdirs[current]) { + if(strcasestr(path,compdirs[current])) { + conf_dispose_array(compdirs); + return TRUE; + } current++; } -#endif - return 0; + conf_dispose_array(compdirs); + return FALSE; } @@ -660,7 +662,7 @@ void make_composite_tags(MP3FILE *song) { if(!song->artist) { if (song->orchestra && song->conductor) { - len = (int)strlen(song->orchestra) + + len = (int)strlen(song->orchestra) + (int)strlen(sep) + (int)strlen(song->conductor); ptmp = (char*)malloc(len + 1); @@ -685,7 +687,7 @@ void make_composite_tags(MP3FILE *song) { sprintf(ptmp,"%s%s%s",song->artist, sep, song->title); free(song->title); song->title = ptmp; - + if(va_artist) { ptmp = strdup(va_artist); if(ptmp) { @@ -695,7 +697,7 @@ void make_composite_tags(MP3FILE *song) { } } } - + if(song->url) song->data_kind=1; else