filename = get_tsearch_config_filename(filename, "rules"); if (!tsearch_readline_begin(&trst, filename))
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not open unaccent file \"%s\": %m",
filename)));
do
{ /* *pg_do_encoding_conversion()(calledbytsearch_readline())will *emitexceptionifitfindsuntranslatablecharactersincurrent *locale.Wejustskipsuchlines,continuingwiththenext.
*/
skip = true;
PG_TRY();
{ char *line;
while ((line = tsearch_readline(&trst)) != NULL)
{ /*---------- *Theformatofeachlinemustbe"src"or"srctrg",where *srcandtrgaresequencesofoneormorenon-whitespace *characters,separatedbywhitespace.Whitespaceatstart *orendoflineisignored.Iftrgisomitted,anempty *stringisusedasthereplacement.trgcanbeoptionally *quoted,inwhichcasewhitespacesareincludedinit. * *Weuseasimplestatemachine,withstates *0initial(beforesrc) *1insrc *2inwhitespaceaftersrc *3intrg(non-quoted) *4intrg(quoted) *5inwhitespaceaftertrg *-1syntaxerrordetected(twostrings) *-2syntaxerrordetected(unfinishedquotedstring) *----------
*/ int state; char *ptr; char *src = NULL; char *trg = NULL; char *trgstore = NULL; int ptrlen; int srclen = 0; int trglen = 0; int trgstorelen = 0; bool trgquoted = false;
state = 0; for (ptr = line; *ptr; ptr += ptrlen)
{
ptrlen = pg_mblen_cstr(ptr); /* ignore whitespace, but end src or trg */ if (isspace((unsignedchar) *ptr))
{ if (state == 1)
state = 2; elseif (state == 3)
state = 5; /* whitespaces are OK in quoted area */ if (state != 4) continue;
} switch (state)
{ case0: /* start of src */
src = ptr;
srclen = ptrlen;
state = 1; break; case1: /* continue src */
srclen += ptrlen; break; case2: /* start of trg */ if (*ptr == '"')
{
trgquoted = true;
state = 4;
} else
state = 3;
trg = ptr;
trglen = ptrlen; break; case3: /* continue non-quoted trg */
trglen += ptrlen; break; case4: /* continue quoted trg */
trglen += ptrlen;
/* *Ifthisisaquote,consideritastheendof *trgexceptifthefollow-upcharacterisitself *aquote.
*/ if (*ptr == '"')
{ if (*(ptr + 1) == '"')
{
ptr++;
trglen += 1;
} else
state = 5;
} break; default: /* bogus line format */
state = -1; break;
}
}
if (state == 1 || state == 2)
{ /* trg was omitted, so use "" */
trg = "";
trglen = 0;
}
/* If still in a quoted area, fallback to an error */ if (state == 4)
state = -2;
/* If trg was quoted, remove its quotes and unescape it */ if (trgquoted && state > 0)
{ /* Ignore first and end quotes */
trgstore = (char *) palloc(sizeof(char) * (trglen - 2));
trgstorelen = 0; for (int i = 1; i < trglen - 1; i++)
{
trgstore[trgstorelen] = trg[i];
trgstorelen++; /* skip second double quotes */ if (trg[i] == '"' && trg[i + 1] == '"')
i++;
}
} else
{
trgstore = (char *) palloc(sizeof(char) * trglen);
trgstorelen = trglen;
memcpy(trgstore, trg, trgstorelen);
}
if (state > 0)
rootTrie = placeChar(rootTrie,
(unsignedchar *) src, srclen,
trgstore, trgstorelen); elseif (state == -1)
ereport(WARNING,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid syntax: more than two strings in unaccent rule"))); elseif (state == -2)
ereport(WARNING,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid syntax: unfinished quoted string in unaccent rule")));
/* we allocate storage for the buffer only if needed */
buf.data = NULL;
while (len > 0)
{
TrieChar *node; int matchlen;
node = findReplaceTo(rootTrie, (unsignedchar *) srcchar, len,
&matchlen); if (node && node->replaceTo)
{ if (buf.data == NULL)
{ /* initialize buffer */
initStringInfo(&buf); /* insert any data we already skipped over */ if (srcchar != srcstart)
appendBinaryStringInfo(&buf, srcstart, srcchar - srcstart);
}
appendBinaryStringInfo(&buf, node->replaceTo, node->replacelen);
} else
{
matchlen = pg_mblen_range(srcchar, srcend); if (buf.data != NULL)
appendBinaryStringInfo(&buf, srcchar, matchlen);
}
srcchar += matchlen;
len -= matchlen;
}
/* return a result only if we made at least one substitution */ if (buf.data != NULL)
{
res = (TSLexeme *) palloc0(sizeof(TSLexeme) * 2);
res->lexeme = buf.data;
res->flags = TSL_FILTER;
} else
res = NULL;
PG_RETURN_POINTER(res);
}
/* *Function-likewrapperfordictionary
*/
PG_FUNCTION_INFO_V1(unaccent_dict);
Datum
unaccent_dict(PG_FUNCTION_ARGS)
{
text *str; int strArg;
Oid dictOid;
TSDictionaryCacheEntry *dict;
TSLexeme *res;
if (PG_NARGS() == 1)
{ /* *Usethe"unaccent"dictionarythatisinthesameschemathatthis *functionisin.
*/
Oid procnspid = get_func_namespace(fcinfo->flinfo->fn_oid); constchar *dictname = "unaccent";