From 17a7ad1c5be92be2eed52b21374b76b0ff3e84f9 Mon Sep 17 00:00:00 2001 From: Bert Frees Date: Mon, 9 Mar 2015 20:41:05 +0100 Subject: [PATCH] Better integration with table resolving functionality Instead of a comma separated list of directories, lou_indexTables now accepts an array of table names which are resolved to files. If lou_indexTables has not been called before lou_findTable, LOUIS_TABLEPATH will be indexed instead of simply failing. --- liblouis/compileTranslationTable.c | 47 +++++---- liblouis/findTable.c | 151 +++++++++++++++++++++-------- liblouis/liblouis.h.in | 9 +- liblouis/louis.h | 6 ++ tests/findTable.c | 3 +- 5 files changed, 153 insertions(+), 63 deletions(-) diff --git a/liblouis/compileTranslationTable.c b/liblouis/compileTranslationTable.c index cfede90024..f3b28291e5 100644 --- a/liblouis/compileTranslationTable.c +++ b/liblouis/compileTranslationTable.c @@ -4584,6 +4584,30 @@ resolveSubtable (const char *table, const char *base, const char *searchPath) return NULL; } +char * +getTablePath() +{ + char searchPath[MAXSTRING]; + char *path; + char *cp; + cp = searchPath; + path = getenv ("LOUIS_TABLEPATH"); + if (path != NULL && path[0] != '\0') + cp += sprintf (cp, ",%s", path); + path = lou_getDataPath (); + if (path != NULL && path[0] != '\0') + cp += sprintf (cp, ",%s%c%s%c%s", path, DIR_SEP, "liblouis", DIR_SEP, + "tables"); +#ifdef _WIN32 + path = lou_getProgramPath (); + if (path != NULL && path[0] != '\0') + cp += sprintf (cp, ",%s%s", path, "\\share\\liblouis\\tables"); +#else + cp += sprintf (cp, ",%s", TABLESDIR); +#endif + return strdup(searchPath); +} + /** * The default table resolver * @@ -4601,31 +4625,16 @@ resolveSubtable (const char *table, const char *base, const char *searchPath) static char ** defaultTableResolver (const char *tableList, const char *base) { - char searchPath[MAXSTRING]; + char * searchPath; char **tableFiles; char *subTable; char *tableList_copy; char *cp; - char *path; int last; int k; /* Set up search path */ - cp = searchPath; - path = getenv ("LOUIS_TABLEPATH"); - if (path != NULL && path[0] != '\0') - cp += sprintf (cp, ",%s", path); - path = lou_getDataPath (); - if (path != NULL && path[0] != '\0') - cp += sprintf (cp, ",%s%c%s%c%s", path, DIR_SEP, "liblouis", DIR_SEP, - "tables"); -#ifdef _WIN32 - path = lou_getProgramPath (); - if (path != NULL && path[0] != '\0') - cp += sprintf (cp, ",%s%s", path, "\\share\\liblouis\\tables"); -#else - cp += sprintf (cp, ",%s", TABLESDIR); -#endif + searchPath = getTablePath(); /* Count number of subtables in table list */ k = 0; @@ -4645,6 +4654,7 @@ defaultTableResolver (const char *tableList, const char *base) if (!(tableFiles[k++] = resolveSubtable (subTable, base, searchPath))) { logMessage (LOG_ERROR, "Cannot resolve table '%s'", subTable); + free(searchPath); free(tableList_copy); free (tableFiles); return NULL; @@ -4654,6 +4664,7 @@ defaultTableResolver (const char *tableList, const char *base) if (last) break; } + free(searchPath); free(tableList_copy); tableFiles[k] = NULL; return tableFiles; @@ -4681,7 +4692,7 @@ copyStringArray(const char ** array) return copy; } -static char ** +char ** resolveTable (const char *tableList, const char *base) { return copyStringArray((*tableResolver) (tableList, base)); diff --git a/liblouis/findTable.c b/liblouis/findTable.c index e57f10de1c..4990c85bf6 100644 --- a/liblouis/findTable.c +++ b/liblouis/findTable.c @@ -130,6 +130,36 @@ list_sort(List * list, int (* cmp)(void *, void *)) return newList; } +/* + * Get the size of a list. + */ +static int +list_size(List * list) +{ + int len = 0; + List * l; + for (l = list; l; l = l->tail) + len++; + return len; +} + +/* + * Convert a list into a NULL terminated array. + */ +static void ** +list_toArray(List * list, void * (* dup)(void *)) +{ + void ** array; + List * l; + int i; + array = malloc((1 + list_size(list)) * sizeof(void *)); + i = 0; + for (l = list; l; l = l->tail) + array[i++] = dup ? dup(l->head) : l->head; + array[i] = NULL; + return array; +} + /* ============================== FEATURE ================================= */ typedef struct @@ -378,18 +408,37 @@ widestrToStr(const widechar * str, size_t n) } /* - * Extract a list of features from a file. + * Extract a list of features from a table. */ static List * -analyzeTable(const char * fileName) +analyzeTable(const char * table) { + static char fileName[MAXSTRING]; + char ** resolved; List * features = NULL; FileInfo info; + int k; + resolved = resolveTable(table, NULL); + if (resolved == NULL) + { + logMessage(LOG_ERROR, "Cannot resolve table '%s'", table); + return NULL; + } + sprintf(fileName, "%s", *resolved); + k = 0; + for (k = 0; resolved[k]; k++) + free(resolved[k]); + free(resolved); + if (k > 1) + { + logMessage(LOG_ERROR, "Table '%s' resolves to more than one file", table); + return NULL; + } info.fileName = fileName; info.encoding = noEncoding; info.status = 0; info.lineNumber = 0; - if ((info.in = fopen(fileName, "rb"))) + if ((info.in = fopen(info.fileName, "rb"))) { while (getALine(&info)) { @@ -457,7 +506,7 @@ analyzeTable(const char * fileName) fclose(info.in); } else - logMessage (LOG_ERROR, "Cannot open table '%s'", fileName); + logMessage (LOG_ERROR, "Cannot open table '%s'", info.fileName); return list_sort(features, (int (*)(void *, void *))cmpKeys); compile_error: if (info.linepos < info.linelen) @@ -473,15 +522,40 @@ analyzeTable(const char * fileName) static List * tableIndex = NULL; +void EXPORT_CALL +lou_indexTables(const char ** tables) +{ + const char ** table; + list_free(tableIndex); + tableIndex = NULL; + for (table = tables; *table; table++) + { + logMessage(LOG_DEBUG, "Analyzing table %s", *table); + List * features = analyzeTable(*table); + if (features) + { + TableMeta m = { strdup(*table), features }; + tableIndex = list_conj(tableIndex, memcpy(malloc(sizeof(m)), &m, sizeof(m)), NULL, NULL, free); + } + } + if (!tableIndex) + logMessage(LOG_WARN, "No tables were indexed"); +} + #ifdef _WIN32 #define DIR_SEP '\\' #else #define DIR_SEP '/' #endif -void EXPORT_CALL -lou_indexTables(const char * searchPath) +/* + * Returns the list of files found on searchPath, where searchPath is a + * comma-separated list of directories. + */ +static List * +listFiles(char * searchPath) { + List * list; char * dirName; DIR * dir; struct dirent * file; @@ -489,8 +563,6 @@ lou_indexTables(const char * searchPath) struct stat info; int pos = 0; int n; - list_free(tableIndex); - tableIndex = NULL; while (1) { for (n = 0; searchPath[pos + n] != '\0' && searchPath[pos + n] != ','; n++); @@ -502,13 +574,7 @@ lou_indexTables(const char * searchPath) sprintf(fileName, "%s%c%s", dirName, DIR_SEP, file->d_name); if (stat(fileName, &info) == 0 && !(info.st_mode & S_IFDIR)) { - logMessage(LOG_DEBUG, "Analyzing table %s", fileName); - List * features = analyzeTable(fileName); - if (features) - { - TableMeta m = { strdup(fileName), features }; - tableIndex = list_conj(tableIndex, memcpy(malloc(sizeof(m)), &m, sizeof(m)), NULL, NULL, free); - } + list = list_conj(list, strdup(fileName), NULL, NULL, free); } } closedir(dir); @@ -524,41 +590,48 @@ lou_indexTables(const char * searchPath) else pos++; } - if (!tableIndex) - logMessage(LOG_WARN, "No tables were indexed"); + return list; } char * EXPORT_CALL lou_findTable(const char * query) { - if (tableIndex) + if (!tableIndex) { - List * queryFeatures = parseQuery(query); - int bestQuotient = 0; - char * bestMatch = NULL; - List * l; - for (l = tableIndex; l; l = l->tail) - { - TableMeta * table = l->head; - int q = matchFeatureLists(queryFeatures, table->features, 0); - if (q > bestQuotient) - { - bestQuotient = q; - bestMatch = strdup(table->name); - } - } - logMessage(LOG_INFO, "Best match: %s (%d)", bestMatch, bestQuotient); - if (bestMatch) - return bestMatch; - else + char * searchPath; + List * tables; + const char ** tablesArray; + logMessage(LOG_WARN, "Tables have not been indexed yet. Indexing LOUIS_TABLEPATH."); + searchPath = getTablePath(); + tables = listFiles(searchPath); + tablesArray = list_toArray(tables, NULL); + lou_indexTables(tablesArray); + free(searchPath); + list_free(tables); + free(tablesArray); + } + List * queryFeatures = parseQuery(query); + int bestQuotient = 0; + char * bestMatch = NULL; + List * l; + for (l = tableIndex; l; l = l->tail) + { + TableMeta * table = l->head; + int q = matchFeatureLists(queryFeatures, table->features, 0); + if (q > bestQuotient) { - logMessage(LOG_INFO, "No table could be found for query '%s'", query); - return NULL; + bestQuotient = q; + bestMatch = strdup(table->name); } } + if (bestMatch) + { + logMessage(LOG_INFO, "Best match: %s (%d)", bestMatch, bestQuotient); + return bestMatch; + } else { - logMessage(LOG_ERROR, "Tables have not been indexed yet. Call lou_indexTables first."); + logMessage(LOG_INFO, "No table could be found for query '%s'", query); return NULL; } } diff --git a/liblouis/liblouis.h.in b/liblouis/liblouis.h.in index 3f54b14f3d..235db470a9 100644 --- a/liblouis/liblouis.h.in +++ b/liblouis/liblouis.h.in @@ -173,11 +173,10 @@ typedef void (*logcallback)(int level, const char *message); void EXPORT_CALL lou_setLogLevel(logLevels level); /* Set the level for logging callback to be called at */ -void EXPORT_CALL lou_indexTables(const char * searchPath); -/* Parses, analyzes and indexes table on searchPath. searchPath is a - * colon-separated list of directories to search for tables. This function - * must be called prior to lou_findTable(). An error message is given when a - * table contains invalid or duplicate metadata fields. +void EXPORT_CALL lou_indexTables(const char ** tables); +/* Parses, analyzes and indexes tables. This function must be called prior to + * lou_findTable(). An error message is given when a table contains invalid or + * duplicate metadata fields. */ char * EXPORT_CALL lou_findTable(const char * query); /* Finds the best match for a query. Returns a string with the table diff --git a/liblouis/louis.h b/liblouis/louis.h index a670fb54c6..fde5463cc7 100644 --- a/liblouis/louis.h +++ b/liblouis/louis.h @@ -499,6 +499,12 @@ extern "C" int getALine (FileInfo * info); /* Read a line of widechar's from an input file */ + char * getTablePath(); +/* Comma separated list of directories to search for tables. */ + + char ** resolveTable(const char *tableList, const char *base); +/* Resolve tableList against base. */ + widechar getDotsForChar (widechar c); /* Returns the single-cell dot pattern corresponding to a character. */ diff --git a/tests/findTable.c b/tests/findTable.c index 5089aad55a..a7f7dd4e96 100644 --- a/tests/findTable.c +++ b/tests/findTable.c @@ -9,8 +9,9 @@ main(int argc, char **argv) { int success = 0; char * match; + const char * tables[] = {"tablesWithMetadata/foo","tablesWithMetadata/bar",NULL}; lou_setLogLevel(LOG_DEBUG); - lou_indexTables("tablesWithMetadata"); + lou_indexTables(tables); match = lou_findTable("id:foo"); success |= (!match || strcmp(match, "tablesWithMetadata/foo")); match = lou_findTable("language:en");