*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
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;
uint16 posinsubst = 0;
uint16 nwrd = 0;
- lineno++;
-
ptr = line;
/* is it a comment? */
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))
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;
}
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 *
*
*
* 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"
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;
pfree(line);
}
- FreeFile(dict);
+ tsearch_readline_end(&trst);
}
#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,
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)
{
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)
{
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)
{
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);
}
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++;
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;
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;
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);
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");
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;
pfree(recoded);
}
+ tsearch_readline_end(&trst);
if (ptype)
pfree(ptype);
- FreeFile(affix);
}
/*
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",
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;
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 == '*')
{
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;
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);
pfree(recoded);
pfree(pstr);
}
- FreeFile(affix);
+ tsearch_readline_end(&trst);
}
static int
*
*
* 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
#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;