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.
This commit is contained in:
Tom Lane 2008-06-18 20:55:42 +00:00
parent 9de09c087d
commit fbeb9da22b
7 changed files with 183 additions and 103 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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 *

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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 <wctype.h>
#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__ */