diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2008-06-18 20:55:42 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2008-06-18 20:55:42 +0000 |
commit | fbeb9da22be28c3252a1f704b028df0ecf1e3a0d (patch) | |
tree | d516dcc20cc60d5cc8482e0e8813ba9ce4869b2e /src/backend/tsearch | |
parent | 9de09c087d63b13b54a0db1073477d70188823c5 (diff) | |
download | postgresql-fbeb9da22be28c3252a1f704b028df0ecf1e3a0d.tar.gz |
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.
Diffstat (limited to 'src/backend/tsearch')
-rw-r--r-- | src/backend/tsearch/dict_synonym.c | 11 | ||||
-rw-r--r-- | src/backend/tsearch/dict_thesaurus.c | 33 | ||||
-rw-r--r-- | src/backend/tsearch/spell.c | 97 | ||||
-rw-r--r-- | src/backend/tsearch/ts_locale.c | 105 | ||||
-rw-r--r-- | src/backend/tsearch/ts_utils.c | 11 |
5 files changed, 161 insertions, 96 deletions
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 @@ -77,11 +81,110 @@ t_isprint(const char *ptr) /* + * 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 <ctype.h> #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); } |