From fbeb9da22be28c3252a1f704b028df0ecf1e3a0d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 18 Jun 2008 20:55:42 +0000 Subject: [PATCH] Improve error reporting for problems in text search configuration files by installing an error context subroutine that will provide the file name and line number for all errors detected while reading a config file. Some of the reader routines were already doing that in an ad-hoc way for errors detected directly in the reader, but it didn't help for problems detected in subroutines, such as encoding violations. Back-patch to 8.3 because 8.3 is where people will be trying to debug configuration files. --- contrib/dict_xsyn/dict_xsyn.c | 11 ++- src/backend/tsearch/dict_synonym.c | 11 ++- src/backend/tsearch/dict_thesaurus.c | 33 +++------ src/backend/tsearch/spell.c | 97 ++++++++++--------------- src/backend/tsearch/ts_locale.c | 105 ++++++++++++++++++++++++++- src/backend/tsearch/ts_utils.c | 11 ++- src/include/tsearch/ts_locale.h | 18 ++++- 7 files changed, 183 insertions(+), 103 deletions(-) diff --git a/contrib/dict_xsyn/dict_xsyn.c b/contrib/dict_xsyn/dict_xsyn.c index d98792aa01..f8430862be 100644 --- a/contrib/dict_xsyn/dict_xsyn.c +++ b/contrib/dict_xsyn/dict_xsyn.c @@ -6,7 +6,7 @@ * Copyright (c) 2007-2008, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/contrib/dict_xsyn/dict_xsyn.c,v 1.4 2008/01/01 20:31:21 tgl Exp $ + * $PostgreSQL: pgsql/contrib/dict_xsyn/dict_xsyn.c,v 1.5 2008/06/18 20:55:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,7 +16,6 @@ #include "commands/defrem.h" #include "fmgr.h" -#include "storage/fd.h" #include "tsearch/ts_locale.h" #include "tsearch/ts_utils.h" @@ -75,17 +74,17 @@ static void read_dictionary(DictSyn *d, char *filename) { char *real_filename = get_tsearch_config_filename(filename, "rules"); - FILE *fin; + tsearch_readline_state trst; char *line; int cur = 0; - if ((fin = AllocateFile(real_filename, "r")) == NULL) + if (!tsearch_readline_begin(&trst, real_filename)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not open synonym file \"%s\": %m", real_filename))); - while ((line = t_readline(fin)) != NULL) + while ((line = tsearch_readline(&trst)) != NULL) { char *value; char *key; @@ -119,7 +118,7 @@ read_dictionary(DictSyn *d, char *filename) cur++; } - FreeFile(fin); + tsearch_readline_end(&trst); d->len = cur; if (cur > 1) diff --git a/src/backend/tsearch/dict_synonym.c b/src/backend/tsearch/dict_synonym.c index 6f263603d7..8558602ace 100644 --- a/src/backend/tsearch/dict_synonym.c +++ b/src/backend/tsearch/dict_synonym.c @@ -7,14 +7,13 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tsearch/dict_synonym.c,v 1.8 2008/03/10 03:01:28 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tsearch/dict_synonym.c,v 1.9 2008/06/18 20:55:42 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "commands/defrem.h" -#include "storage/fd.h" #include "tsearch/ts_locale.h" #include "tsearch/ts_public.h" #include "tsearch/ts_utils.h" @@ -79,7 +78,7 @@ dsynonym_init(PG_FUNCTION_ARGS) ListCell *l; char *filename = NULL; bool case_sensitive = false; - FILE *fin; + tsearch_readline_state trst; char *starti, *starto, *end = NULL; @@ -108,7 +107,7 @@ dsynonym_init(PG_FUNCTION_ARGS) filename = get_tsearch_config_filename(filename, "syn"); - if ((fin = AllocateFile(filename, "r")) == NULL) + if (!tsearch_readline_begin(&trst, filename)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not open synonym file \"%s\": %m", @@ -116,7 +115,7 @@ dsynonym_init(PG_FUNCTION_ARGS) d = (DictSyn *) palloc0(sizeof(DictSyn)); - while ((line = t_readline(fin)) != NULL) + while ((line = tsearch_readline(&trst)) != NULL) { starti = findwrd(line, &end); if (!starti) @@ -175,7 +174,7 @@ skipline: pfree(line); } - FreeFile(fin); + tsearch_readline_end(&trst); d->len = cur; qsort(d->syn, d->len, sizeof(Syn), compareSyn); diff --git a/src/backend/tsearch/dict_thesaurus.c b/src/backend/tsearch/dict_thesaurus.c index 6fcffa7457..0f9c133f2e 100644 --- a/src/backend/tsearch/dict_thesaurus.c +++ b/src/backend/tsearch/dict_thesaurus.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tsearch/dict_thesaurus.c,v 1.11 2008/01/01 19:45:52 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/tsearch/dict_thesaurus.c,v 1.12 2008/06/18 20:55:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -15,7 +15,6 @@ #include "catalog/namespace.h" #include "commands/defrem.h" -#include "storage/fd.h" #include "tsearch/ts_cache.h" #include "tsearch/ts_locale.h" #include "tsearch/ts_public.h" @@ -169,21 +168,19 @@ addWrd(DictThesaurus *d, char *b, char *e, uint16 idsubst, uint16 nwrd, uint16 p static void thesaurusRead(char *filename, DictThesaurus *d) { - FILE *fh; - int lineno = 0; + tsearch_readline_state trst; uint16 idsubst = 0; bool useasis = false; char *line; filename = get_tsearch_config_filename(filename, "ths"); - fh = AllocateFile(filename, "r"); - if (!fh) + if (!tsearch_readline_begin(&trst, filename)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not open thesaurus file \"%s\": %m", filename))); - while ((line = t_readline(fh)) != NULL) + while ((line = tsearch_readline(&trst)) != NULL) { char *ptr; int state = TR_WAITLEX; @@ -191,8 +188,6 @@ thesaurusRead(char *filename, DictThesaurus *d) uint16 posinsubst = 0; uint16 nwrd = 0; - lineno++; - ptr = line; /* is it a comment? */ @@ -213,13 +208,9 @@ thesaurusRead(char *filename, DictThesaurus *d) if (t_iseq(ptr, ':')) { if (posinsubst == 0) - { - FreeFile(fh); ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("unexpected delimiter at line %d of thesaurus file \"%s\"", - lineno, filename))); - } + errmsg("unexpected delimiter"))); state = TR_WAITSUBS; } else if (!t_isspace(ptr)) @@ -269,8 +260,7 @@ thesaurusRead(char *filename, DictThesaurus *d) if (ptr == beginwrd) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("unexpected end of line or lexeme at line %d of thesaurus file \"%s\"", - lineno, filename))); + errmsg("unexpected end of line or lexeme"))); addWrd(d, beginwrd, ptr, idsubst, nwrd++, posinsubst, useasis); state = TR_WAITSUBS; } @@ -286,28 +276,23 @@ thesaurusRead(char *filename, DictThesaurus *d) if (ptr == beginwrd) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("unexpected end of line or lexeme at line %d of thesaurus file \"%s\"", - lineno, filename))); + errmsg("unexpected end of line or lexeme"))); addWrd(d, beginwrd, ptr, idsubst, nwrd++, posinsubst, useasis); } idsubst++; if (!(nwrd && posinsubst)) - { - FreeFile(fh); ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("unexpected end of line at line %d of thesaurus file \"%s\"", - lineno, filename))); - } + errmsg("unexpected end of line"))); pfree(line); } d->nsubst = idsubst; - FreeFile(fh); + tsearch_readline_end(&trst); } static TheLexeme * diff --git a/src/backend/tsearch/spell.c b/src/backend/tsearch/spell.c index a2837d1683..d6e3a081b8 100644 --- a/src/backend/tsearch/spell.c +++ b/src/backend/tsearch/spell.c @@ -7,14 +7,13 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tsearch/spell.c,v 1.11 2008/01/21 02:46:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tsearch/spell.c,v 1.12 2008/06/18 20:55:42 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include "storage/fd.h" #include "tsearch/dicts/spell.h" #include "tsearch/ts_locale.h" #include "utils/memutils.h" @@ -194,18 +193,18 @@ NIAddSpell(IspellDict *Conf, const char *word, const char *flag) void NIImportDictionary(IspellDict *Conf, const char *filename) { - FILE *dict; + tsearch_readline_state trst; char *line; checkTmpCtx(); - if (!(dict = AllocateFile(filename, "r"))) + if (!tsearch_readline_begin(&trst, filename)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not open dictionary file \"%s\": %m", filename))); - while ((line = t_readline(dict)) != NULL) + while ((line = tsearch_readline(&trst)) != NULL) { char *s, *pstr; @@ -250,7 +249,7 @@ NIImportDictionary(IspellDict *Conf, const char *filename) pfree(line); } - FreeFile(dict); + tsearch_readline_end(&trst); } @@ -392,8 +391,7 @@ NIAddAffix(IspellDict *Conf, int flag, char flagflags, const char *mask, const c #define PAE_INREPL 5 static bool -parse_affentry(char *str, char *mask, char *find, char *repl, - const char *filename, int lineno) +parse_affentry(char *str, char *mask, char *find, char *repl) { int state = PAE_WAIT_MASK; char *pmask = mask, @@ -443,8 +441,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl, else if (!t_isspace(str)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("syntax error at line %d of affix file \"%s\"", - lineno, filename))); + errmsg("syntax error"))); } else if (state == PAE_INFIND) { @@ -461,8 +458,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl, else if (!t_isspace(str)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("syntax error at line %d of affix file \"%s\"", - lineno, filename))); + errmsg("syntax error"))); } else if (state == PAE_WAIT_REPL) { @@ -479,8 +475,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl, else if (!t_isspace(str)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("syntax error at line %d of affix file \"%s\"", - lineno, filename))); + errmsg("syntax error"))); } else if (state == PAE_INREPL) { @@ -497,8 +492,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl, else if (!t_isspace(str)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("syntax error at line %d of affix file \"%s\"", - lineno, filename))); + errmsg("syntax error"))); } else elog(ERROR, "unrecognized state in parse_affentry: %d", state); @@ -512,8 +506,7 @@ parse_affentry(char *str, char *mask, char *find, char *repl, } static void -addFlagValue(IspellDict *Conf, char *s, uint32 val, - const char *filename, int lineno) +addFlagValue(IspellDict *Conf, char *s, uint32 val) { while (*s && t_isspace(s)) s++; @@ -521,14 +514,12 @@ addFlagValue(IspellDict *Conf, char *s, uint32 val, if (!*s) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("syntax error at line %d of affix file \"%s\"", - lineno, filename))); + errmsg("syntax error"))); if (pg_mblen(s) != 1) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("multibyte flag character is not allowed at line %d of affix file \"%s\"", - lineno, filename))); + errmsg("multibyte flag character is not allowed"))); Conf->flagval[(unsigned int) *s] = (unsigned char) val; Conf->usecompound = true; @@ -549,8 +540,7 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename) bool isSuffix = false; int flag = 0; char flagflags = 0; - FILE *affix; - int lineno = 0; + tsearch_readline_state trst; int scanread = 0; char scanbuf[BUFSIZ]; char *recoded; @@ -561,16 +551,14 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename) memset(Conf->flagval, 0, sizeof(Conf->flagval)); Conf->usecompound = false; - if (!(affix = AllocateFile(filename, "r"))) + if (!tsearch_readline_begin(&trst, filename)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not open affix file \"%s\": %m", filename))); - while ((recoded = t_readline(affix)) != NULL) + while ((recoded = tsearch_readline(&trst)) != NULL) { - lineno++; - if (*recoded == '\0' || t_isspace(recoded) || t_iseq(recoded, '#')) { pfree(recoded); @@ -579,29 +567,29 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename) if (STRNCMP(recoded, "COMPOUNDFLAG") == 0) addFlagValue(Conf, recoded + strlen("COMPOUNDFLAG"), - FF_COMPOUNDFLAG, filename, lineno); + FF_COMPOUNDFLAG); else if (STRNCMP(recoded, "COMPOUNDBEGIN") == 0) addFlagValue(Conf, recoded + strlen("COMPOUNDBEGIN"), - FF_COMPOUNDBEGIN, filename, lineno); + FF_COMPOUNDBEGIN); else if (STRNCMP(recoded, "COMPOUNDLAST") == 0) addFlagValue(Conf, recoded + strlen("COMPOUNDLAST"), - FF_COMPOUNDLAST, filename, lineno); + FF_COMPOUNDLAST); /* COMPOUNDLAST and COMPOUNDEND are synonyms */ else if (STRNCMP(recoded, "COMPOUNDEND") == 0) addFlagValue(Conf, recoded + strlen("COMPOUNDEND"), - FF_COMPOUNDLAST, filename, lineno); + FF_COMPOUNDLAST); else if (STRNCMP(recoded, "COMPOUNDMIDDLE") == 0) addFlagValue(Conf, recoded + strlen("COMPOUNDMIDDLE"), - FF_COMPOUNDMIDDLE, filename, lineno); + FF_COMPOUNDMIDDLE); else if (STRNCMP(recoded, "ONLYINCOMPOUND") == 0) addFlagValue(Conf, recoded + strlen("ONLYINCOMPOUND"), - FF_COMPOUNDONLY, filename, lineno); + FF_COMPOUNDONLY); else if (STRNCMP(recoded, "COMPOUNDPERMITFLAG") == 0) addFlagValue(Conf, recoded + strlen("COMPOUNDPERMITFLAG"), - FF_COMPOUNDPERMITFLAG, filename, lineno); + FF_COMPOUNDPERMITFLAG); else if (STRNCMP(recoded, "COMPOUNDFORBIDFLAG") == 0) addFlagValue(Conf, recoded + strlen("COMPOUNDFORBIDFLAG"), - FF_COMPOUNDFORBIDFLAG, filename, lineno); + FF_COMPOUNDFORBIDFLAG); else if (STRNCMP(recoded, "FLAG") == 0) { char *s = recoded + strlen("FLAG"); @@ -612,26 +600,23 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename) if (*s && STRNCMP(s, "default") != 0) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("Ispell dictionary supports only default flag value at line %d of affix file \"%s\"", - lineno, filename))); + errmsg("Ispell dictionary supports only default flag value"))); } pfree(recoded); } - FreeFile(affix); - lineno = 0; + tsearch_readline_end(&trst); sprintf(scanbuf, "%%6s %%%ds %%%ds %%%ds %%%ds", BUFSIZ / 5, BUFSIZ / 5, BUFSIZ / 5, BUFSIZ / 5); - if (!(affix = AllocateFile(filename, "r"))) + if (!tsearch_readline_begin(&trst, filename)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not open affix file \"%s\": %m", filename))); - while ((recoded = t_readline(affix)) != NULL) + while ((recoded = tsearch_readline(&trst)) != NULL) { - lineno++; if (*recoded == '\0' || t_isspace(recoded) || t_iseq(recoded, '#')) goto nextline; @@ -691,9 +676,9 @@ nextline: pfree(recoded); } + tsearch_readline_end(&trst); if (ptype) pfree(ptype); - FreeFile(affix); } /* @@ -713,14 +698,13 @@ NIImportAffixes(IspellDict *Conf, const char *filename) bool prefixes = false; int flag = 0; char flagflags = 0; - FILE *affix; - int lineno = 0; + tsearch_readline_state trst; bool oldformat = false; char *recoded = NULL; checkTmpCtx(); - if (!(affix = AllocateFile(filename, "r"))) + if (!tsearch_readline_begin(&trst, filename)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not open affix file \"%s\": %m", @@ -729,12 +713,10 @@ NIImportAffixes(IspellDict *Conf, const char *filename) memset(Conf->flagval, 0, sizeof(Conf->flagval)); Conf->usecompound = false; - while ((recoded = t_readline(affix)) != NULL) + while ((recoded = tsearch_readline(&trst)) != NULL) { pstr = lowerstr(recoded); - lineno++; - /* Skip comments and empty lines */ if (*pstr == '#' || *pstr == '\n') goto nextline; @@ -787,8 +769,7 @@ NIImportAffixes(IspellDict *Conf, const char *filename) if (pg_mblen(s) != 1) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("multibyte flag character is not allowed at line %d of affix file \"%s\"", - lineno, filename))); + errmsg("multibyte flag character is not allowed"))); if (*s == '*') { @@ -808,8 +789,7 @@ NIImportAffixes(IspellDict *Conf, const char *filename) if (pg_mblen(s) != 1) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("multibyte flag character is not allowed at line %d of affix file \"%s\"", - lineno, filename))); + errmsg("multibyte flag character is not allowed"))); flag = (unsigned char) *s; goto nextline; @@ -820,16 +800,15 @@ NIImportAffixes(IspellDict *Conf, const char *filename) if (oldformat) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("wrong affix file format for flag at line %d of affix file \"%s\"", - lineno, filename))); - FreeFile(affix); + errmsg("wrong affix file format for flag"))); + tsearch_readline_end(&trst); NIImportOOAffixes(Conf, filename); return; } if ((!suffixes) && (!prefixes)) goto nextline; - if (!parse_affentry(pstr, mask, find, repl, filename, lineno)) + if (!parse_affentry(pstr, mask, find, repl)) goto nextline; NIAddAffix(Conf, flag, flagflags, mask, find, repl, suffixes ? FF_SUFFIX : FF_PREFIX); @@ -838,7 +817,7 @@ nextline: pfree(recoded); pfree(pstr); } - FreeFile(affix); + tsearch_readline_end(&trst); } static int diff --git a/src/backend/tsearch/ts_locale.c b/src/backend/tsearch/ts_locale.c index 5ce367a497..53349d7fc0 100644 --- a/src/backend/tsearch/ts_locale.c +++ b/src/backend/tsearch/ts_locale.c @@ -7,15 +7,19 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tsearch/ts_locale.c,v 1.9 2008/06/18 18:42:54 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/tsearch/ts_locale.c,v 1.10 2008/06/18 20:55:42 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include "storage/fd.h" #include "tsearch/ts_locale.h" #include "tsearch/ts_public.h" +static void tsearch_readline_callback(void *arg); + + #ifdef USE_WIDE_UPPER_LOWER int @@ -76,12 +80,111 @@ t_isprint(const char *ptr) #endif /* USE_WIDE_UPPER_LOWER */ +/* + * Set up to read a file using tsearch_readline(). This facility is + * better than just reading the file directly because it provides error + * context pointing to the specific line where a problem is detected. + * + * Expected usage is: + * + * tsearch_readline_state trst; + * + * if (!tsearch_readline_begin(&trst, filename)) + * ereport(ERROR, + * (errcode(ERRCODE_CONFIG_FILE_ERROR), + * errmsg("could not open stop-word file \"%s\": %m", + * filename))); + * while ((line = tsearch_readline(&trst)) != NULL) + * process line; + * tsearch_readline_end(&trst); + * + * Note that the caller supplies the ereport() for file open failure; + * this is so that a custom message can be provided. The filename string + * passed to tsearch_readline_begin() must remain valid through + * tsearch_readline_end(). + */ +bool +tsearch_readline_begin(tsearch_readline_state *stp, + const char *filename) +{ + if ((stp->fp = AllocateFile(filename, "r")) == NULL) + return false; + stp->filename = filename; + stp->lineno = 0; + stp->curline = NULL; + /* Setup error traceback support for ereport() */ + stp->cb.callback = tsearch_readline_callback; + stp->cb.arg = (void *) stp; + stp->cb.previous = error_context_stack; + error_context_stack = &stp->cb; + return true; +} + /* * Read the next line from a tsearch data file (expected to be in UTF-8), and * convert it to database encoding if needed. The returned string is palloc'd. * NULL return means EOF. */ char * +tsearch_readline(tsearch_readline_state *stp) +{ + char *result; + + stp->lineno++; + stp->curline = NULL; + result = t_readline(stp->fp); + stp->curline = result; + return result; +} + +/* + * Close down after reading a file with tsearch_readline() + */ +void +tsearch_readline_end(tsearch_readline_state *stp) +{ + FreeFile(stp->fp); + /* Pop the error context stack */ + error_context_stack = stp->cb.previous; +} + +/* + * Error context callback for errors occurring while reading a tsearch + * configuration file. + */ +static void +tsearch_readline_callback(void *arg) +{ + tsearch_readline_state *stp = (tsearch_readline_state *) arg; + + /* + * We can't include the text of the config line for errors that occur + * during t_readline() itself. This is only partly a consequence of + * our arms-length use of that routine: the major cause of such + * errors is encoding violations, and we daren't try to print error + * messages containing badly-encoded data. + */ + if (stp->curline) + errcontext("line %d of configuration file \"%s\": \"%s\"", + stp->lineno, + stp->filename, + stp->curline); + else + errcontext("line %d of configuration file \"%s\"", + stp->lineno, + stp->filename); +} + + +/* + * Read the next line from a tsearch data file (expected to be in UTF-8), and + * convert it to database encoding if needed. The returned string is palloc'd. + * NULL return means EOF. + * + * Note: direct use of this function is now deprecated. Go through + * tsearch_readline() to provide better error reporting. + */ +char * t_readline(FILE *fp) { int len; diff --git a/src/backend/tsearch/ts_utils.c b/src/backend/tsearch/ts_utils.c index 3708d02689..0458664789 100644 --- a/src/backend/tsearch/ts_utils.c +++ b/src/backend/tsearch/ts_utils.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tsearch/ts_utils.c,v 1.10 2008/06/18 18:42:54 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/tsearch/ts_utils.c,v 1.11 2008/06/18 20:55:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,7 +17,6 @@ #include #include "miscadmin.h" -#include "storage/fd.h" #include "tsearch/ts_locale.h" #include "tsearch/ts_public.h" #include "tsearch/ts_utils.h" @@ -82,17 +81,17 @@ readstoplist(const char *fname, StopList *s, char *(*wordop) (const char *)) if (fname && *fname) { char *filename = get_tsearch_config_filename(fname, "stop"); - FILE *hin; + tsearch_readline_state trst; char *line; int reallen = 0; - if ((hin = AllocateFile(filename, "r")) == NULL) + if (!tsearch_readline_begin(&trst, filename)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not open stop-word file \"%s\": %m", filename))); - while ((line = t_readline(hin)) != NULL) + while ((line = tsearch_readline(&trst)) != NULL) { char *pbuf = line; @@ -135,7 +134,7 @@ readstoplist(const char *fname, StopList *s, char *(*wordop) (const char *)) (s->len)++; } - FreeFile(hin); + tsearch_readline_end(&trst); pfree(filename); } diff --git a/src/include/tsearch/ts_locale.h b/src/include/tsearch/ts_locale.h index 110efb191c..b05ab7f1b0 100644 --- a/src/include/tsearch/ts_locale.h +++ b/src/include/tsearch/ts_locale.h @@ -5,7 +5,7 @@ * * Copyright (c) 1998-2008, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/tsearch/ts_locale.h,v 1.7 2008/06/18 18:42:54 momjian Exp $ + * $PostgreSQL: pgsql/src/include/tsearch/ts_locale.h,v 1.8 2008/06/18 20:55:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -29,6 +29,16 @@ #include #endif +/* working state for tsearch_readline (should be a local var in caller) */ +typedef struct +{ + FILE *fp; + const char *filename; + int lineno; + char *curline; + ErrorContextCallback cb; +} tsearch_readline_state; + #define TOUCHAR(x) (*((const unsigned char *) (x))) #ifdef USE_WIDE_UPPER_LOWER @@ -55,6 +65,12 @@ extern int t_isprint(const char *ptr); extern char *lowerstr(const char *str); extern char *lowerstr_with_len(const char *str, int len); + +extern bool tsearch_readline_begin(tsearch_readline_state *stp, + const char *filename); +extern char *tsearch_readline(tsearch_readline_state *stp); +extern void tsearch_readline_end(tsearch_readline_state *stp); + extern char *t_readline(FILE *fp); #endif /* __TSLOCALE_H__ */