X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=mysql_selector.c;h=f50ac410079615676268a0b0a5a2b7f546d744ce;hp=e2812fd7904df3d155d422569b74c86683bc4669;hb=7e15423daa82f48d09d946c052a01ab35b40fbee;hpb=10756ea9adc1b757ef1ccf2149bda9771923637c diff --git a/mysql_selector.c b/mysql_selector.c index e2812fd7..f50ac410 100644 --- a/mysql_selector.c +++ b/mysql_selector.c @@ -28,6 +28,7 @@ #include "db.h" #include #include +#include #include "error.h" #include "net.h" #include "string.h" @@ -39,6 +40,18 @@ extern struct misc_meta_data *mmd; static void *mysql_ptr = NULL; +/** + * contains name/replacement pairs used by s_a_r_list() + * + * \sa s_a_r() + */ +struct para_macro { + /** the name of the macro */ + const char *name; + /** the replacement text */ + const char *replacement; +}; + static struct para_macro macro_list[] = { { .name = "IS_N_SET", .replacement = "(data.%s != '1')" @@ -63,6 +76,93 @@ static struct para_macro macro_list[] = { } }; +/** + * simple search and replace routine + * + * \param src source string + * \param macro_name the name of the macro + * \param replacement the replacement format string + * + * In \p src, replace each occurence of \p macro_name(arg) by the string + * determined by the \p replacement format string. \p replacement may (but + * needs not) contain a single string conversion specifier (%s) which gets + * replaced by \p arg. + * + * \return A string in which all matches in \p src are replaced, or \p NULL if + * an syntax error was encountered. Caller must free the result. + * + * \sa regcomp(3) + */ +__must_check __malloc static char *s_a_r(const char *src, const char* macro_name, + const char *replacement) +{ + regex_t preg; + size_t nmatch = 1; + regmatch_t pmatch[1]; + int eflags = 0; + char *dest = NULL; + const char *bufptr = src; + + if (!macro_name || !replacement || !src) + return para_strdup(src); + regcomp(&preg, macro_name, 0); + while (regexec(&preg, bufptr, nmatch, pmatch, eflags) + != REG_NOMATCH) { + char *tmp, *arg, *o_bracket, *c_bracket; + + o_bracket = strchr(bufptr + pmatch[0].rm_so, '('); + c_bracket = o_bracket? strchr(o_bracket, ')') : NULL; + if (!c_bracket) + goto out; + tmp = para_strdup(bufptr); + tmp[pmatch[0].rm_so] = '\0'; + dest = para_strcat(dest, tmp); + free(tmp); + + arg = para_strdup(o_bracket + 1); + arg[c_bracket - o_bracket - 1] = '\0'; + tmp = make_message(replacement, arg); + free(arg); + dest = para_strcat(dest, tmp); + free(tmp); + bufptr = c_bracket; + bufptr++; + } + dest = para_strcat(dest, bufptr); +// PARA_DEBUG_LOG("%s: returning %s\n", __func__, dest); +out: + regfree(&preg); + return dest; +} + +/** + * replace a string according to a list of macros + * + * \param macro_list the array containing a macro/replacement pairs. + * \param src the source string + * + * This function just calls s_a_r() for each element of \p macro_list. + * + * \return \p NULL if one of the underlying calls to \p s_a_r returned \p NULL. + * Otherwise the completely expanded version of \p src is returned. + */ +__must_check __malloc static char *s_a_r_list(struct para_macro *macro_list, char *src) +{ + struct para_macro *mp = macro_list; + char *ret = NULL, *tmp = para_strdup(src); + + while (mp->name) { + ret = s_a_r(tmp, mp->name, mp->replacement); + free(tmp); + if (!ret) /* syntax error */ + return NULL; + tmp = ret; + mp++; + } + //PARA_DEBUG_LOG("%s: returning %s\n", __func__, dest); + return ret; +} + static int real_query(const char *query) { if (!mysql_ptr) @@ -359,7 +459,8 @@ int com_laa(int fd, int argc, __a_unused char *argv[]) /* * history */ -int com_hist(int fd, int argc, char *argv[]) { +int com_hist(int fd, int argc, char *argv[]) +{ int ret; void *result = NULL; char *q, *atts; @@ -437,7 +538,7 @@ int com_mbox(int fd, int argc, char *argv[]) if (!row[0]) goto out; - tmp = make_message("%s X-Attribute-%s: ', %s, '\n", query, + tmp = make_message("%sX-Attribute-%s: ', %s, '\n", query, row[0], row[0]); free(query); query = tmp; @@ -766,7 +867,7 @@ out: */ static char *get_selector_info(char *name) { - char *meta = NULL, *atts = NULL, *info, *dir = NULL, *query, *stream = NULL; + char *meta, *atts, *info, *dir, *query, *stream; void *result = NULL; MYSQL_ROW row = NULL; @@ -792,14 +893,10 @@ write: stream, meta, (result && row && row[0])? row[0] : "(no score)", atts); - if (dir) - free(dir); - if (meta) - free(meta); - if (atts) - free(atts); - if (stream) - free(stream); + free(dir); + free(meta); + free(atts); + free(stream); if (result) mysql_free_result(result); return info; @@ -2156,8 +2253,15 @@ static void shutdown_connection(void) /** * the init function of the mysql-based audio file selector * - * Check the command line options and initialize all function pointers of \a db. - * Connect to the mysql server and initialize the info string. + * \param db pointer to the struct to initialize + * + * Check the command line options and initialize all function pointers of \a + * db. Connect to the mysql server and initialize the info string. + * + * \return This function returns success even if it could not connect + * to the mysql server. This is because the connect is expected to fail + * if there the paraslash database is not yet created. This gives the + * user a chance to send the "cdb" to create the database. * * \sa struct audio_file_selector, misc_meta_data::selector_info, * random_selector.c