PostgreSQL Source Code git master
spell.c File Reference
#include "postgres.h"
#include "catalog/pg_collation.h"
#include "miscadmin.h"
#include "tsearch/dicts/spell.h"
#include "tsearch/ts_locale.h"
#include "utils/formatting.h"
#include "utils/memutils.h"
Include dependency graph for spell.c:

Go to the source code of this file.

Data Structures

struct  SplitVar
 

Macros

#define tmpalloc(sz)   MemoryContextAlloc(Conf->buildCxt, (sz))
 
#define tmpalloc0(sz)   MemoryContextAllocZero(Conf->buildCxt, (sz))
 
#define COMPACT_ALLOC_CHUNK   8192 /* amount to get from palloc at once */
 
#define COMPACT_MAX_REQ   1024 /* must be < COMPACT_ALLOC_CHUNK */
 
#define cpalloc(size)   compact_palloc0(Conf, size)
 
#define cpalloc0(size)   compact_palloc0(Conf, size)
 
#define MAX_NORM   1024
 
#define MAXNORMLEN   256
 
#define STRNCMP(s, p)   strncmp( (s), (p), strlen(p) )
 
#define GETWCHAR(W, L, N, T)   ( ((const uint8*)(W))[ ((T)==FF_PREFIX) ? (N) : ( (L) - 1 - (N) ) ] )
 
#define GETCHAR(A, N, T)   GETWCHAR( (A)->repl, (A)->replen, N, T )
 
#define PAE_WAIT_MASK   0
 
#define PAE_INMASK   1
 
#define PAE_WAIT_FIND   2
 
#define PAE_INFIND   3
 
#define PAE_WAIT_REPL   4
 
#define PAE_INREPL   5
 
#define PAE_WAIT_TYPE   6
 
#define PAE_WAIT_FLAG   7
 

Typedefs

typedef struct SplitVar SplitVar
 

Functions

void NIStartBuild (IspellDict *Conf)
 
void NIFinishBuild (IspellDict *Conf)
 
static void * compact_palloc0 (IspellDict *Conf, size_t size)
 
static char * cpstrdup (IspellDict *Conf, const char *str)
 
static char * lowerstr_ctx (IspellDict *Conf, const char *src)
 
static int cmpspell (const void *s1, const void *s2)
 
static int cmpspellaffix (const void *s1, const void *s2)
 
static int cmpcmdflag (const void *f1, const void *f2)
 
static char * findchar (char *str, int c)
 
static char * findchar2 (char *str, int c1, int c2)
 
static int strbcmp (const unsigned char *s1, const unsigned char *s2)
 
static int strbncmp (const unsigned char *s1, const unsigned char *s2, size_t count)
 
static int cmpaffix (const void *s1, const void *s2)
 
static void getNextFlagFromString (IspellDict *Conf, const char **sflagset, char *sflag)
 
static bool IsAffixFlagInUse (IspellDict *Conf, int affix, const char *affixflag)
 
static void NIAddSpell (IspellDict *Conf, const char *word, const char *flag)
 
void NIImportDictionary (IspellDict *Conf, const char *filename)
 
static int FindWord (IspellDict *Conf, const char *word, const char *affixflag, int flag)
 
static void NIAddAffix (IspellDict *Conf, const char *flag, char flagflags, const char *mask, const char *find, const char *repl, int type)
 
static bool get_nextfield (char **str, char *next)
 
static int parse_ooaffentry (char *str, char *type, char *flag, char *find, char *repl, char *mask)
 
static bool parse_affentry (char *str, char *mask, char *find, char *repl)
 
static void setCompoundAffixFlagValue (IspellDict *Conf, CompoundAffixFlag *entry, char *s, uint32 val)
 
static void addCompoundAffixFlagValue (IspellDict *Conf, char *s, uint32 val)
 
static int getCompoundAffixFlagValue (IspellDict *Conf, const char *s)
 
static const char * getAffixFlagSet (IspellDict *Conf, char *s)
 
static void NIImportOOAffixes (IspellDict *Conf, const char *filename)
 
void NIImportAffixes (IspellDict *Conf, const char *filename)
 
static int MergeAffix (IspellDict *Conf, int a1, int a2)
 
static uint32 makeCompoundFlags (IspellDict *Conf, int affix)
 
static SPNodemkSPNode (IspellDict *Conf, int low, int high, int level)
 
void NISortDictionary (IspellDict *Conf)
 
static AffixNodemkANode (IspellDict *Conf, int low, int high, int level, int type)
 
static void mkVoidAffix (IspellDict *Conf, bool issuffix, int startsuffix)
 
static bool isAffixInUse (IspellDict *Conf, const char *affixflag)
 
void NISortAffixes (IspellDict *Conf)
 
static AffixNodeDataFindAffixes (AffixNode *node, const char *word, int wrdlen, int *level, int type)
 
static char * CheckAffix (const char *word, size_t len, AFFIX *Affix, int flagflags, char *newword, int *baselen)
 
static int addToResult (char **forms, char **cur, char *word)
 
static char ** NormalizeSubWord (IspellDict *Conf, const char *word, int flag)
 
static int CheckCompoundAffixes (CMPDAffix **ptr, const char *word, int len, bool CheckInPlace)
 
static SplitVarCopyVar (SplitVar *s, int makedup)
 
static void AddStem (SplitVar *v, char *word)
 
static SplitVarSplitToVariants (IspellDict *Conf, SPNode *snode, SplitVar *orig, const char *word, int wordlen, int startpos, int minpos)
 
static void addNorm (TSLexeme **lres, TSLexeme **lcur, char *word, int flags, uint16 NVariant)
 
TSLexemeNINormalizeWord (IspellDict *Conf, const char *word)
 

Variables

static const char * VoidString = ""
 

Macro Definition Documentation

◆ COMPACT_ALLOC_CHUNK

#define COMPACT_ALLOC_CHUNK   8192 /* amount to get from palloc at once */

Definition at line 127 of file spell.c.

◆ COMPACT_MAX_REQ

#define COMPACT_MAX_REQ   1024 /* must be < COMPACT_ALLOC_CHUNK */

Definition at line 128 of file spell.c.

◆ cpalloc

#define cpalloc (   size)    compact_palloc0(Conf, size)

Definition at line 159 of file spell.c.

◆ cpalloc0

#define cpalloc0 (   size)    compact_palloc0(Conf, size)

Definition at line 160 of file spell.c.

◆ GETCHAR

#define GETCHAR (   A,
  N,
  T 
)    GETWCHAR( (A)->repl, (A)->replen, N, T )

Definition at line 193 of file spell.c.

◆ GETWCHAR

#define GETWCHAR (   W,
  L,
  N,
  T 
)    ( ((const uint8*)(W))[ ((T)==FF_PREFIX) ? (N) : ( (L) - 1 - (N) ) ] )

Definition at line 192 of file spell.c.

◆ MAX_NORM

#define MAX_NORM   1024

Definition at line 188 of file spell.c.

◆ MAXNORMLEN

#define MAXNORMLEN   256

Definition at line 189 of file spell.c.

◆ PAE_INFIND

#define PAE_INFIND   3

Definition at line 776 of file spell.c.

◆ PAE_INMASK

#define PAE_INMASK   1

Definition at line 774 of file spell.c.

◆ PAE_INREPL

#define PAE_INREPL   5

Definition at line 778 of file spell.c.

◆ PAE_WAIT_FIND

#define PAE_WAIT_FIND   2

Definition at line 775 of file spell.c.

◆ PAE_WAIT_FLAG

#define PAE_WAIT_FLAG   7

Definition at line 780 of file spell.c.

◆ PAE_WAIT_MASK

#define PAE_WAIT_MASK   0

Definition at line 773 of file spell.c.

◆ PAE_WAIT_REPL

#define PAE_WAIT_REPL   4

Definition at line 777 of file spell.c.

◆ PAE_WAIT_TYPE

#define PAE_WAIT_TYPE   6

Definition at line 779 of file spell.c.

◆ STRNCMP

#define STRNCMP (   s,
 
)    strncmp( (s), (p), strlen(p) )

Definition at line 191 of file spell.c.

◆ tmpalloc

#define tmpalloc (   sz)    MemoryContextAlloc(Conf->buildCxt, (sz))

Definition at line 80 of file spell.c.

◆ tmpalloc0

#define tmpalloc0 (   sz)    MemoryContextAllocZero(Conf->buildCxt, (sz))

Definition at line 81 of file spell.c.

Typedef Documentation

◆ SplitVar

typedef struct SplitVar SplitVar

Function Documentation

◆ addCompoundAffixFlagValue()

static void addCompoundAffixFlagValue ( IspellDict Conf,
char *  s,
uint32  val 
)
static

Definition at line 1069 of file spell.c.

1070{
1071 CompoundAffixFlag *newValue;
1072 char sbuf[BUFSIZ];
1073 char *sflag;
1074 int clen;
1075
1076 while (*s && isspace((unsigned char) *s))
1077 s += pg_mblen(s);
1078
1079 if (!*s)
1080 ereport(ERROR,
1081 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1082 errmsg("syntax error")));
1083
1084 /* Get flag without \n */
1085 sflag = sbuf;
1086 while (*s && !isspace((unsigned char) *s) && *s != '\n')
1087 {
1088 clen = pg_mblen(s);
1089 COPYCHAR(sflag, s);
1090 sflag += clen;
1091 s += clen;
1092 }
1093 *sflag = '\0';
1094
1095 /* Resize array or allocate memory for array CompoundAffixFlag */
1096 if (Conf->nCompoundAffixFlag >= Conf->mCompoundAffixFlag)
1097 {
1098 if (Conf->mCompoundAffixFlag)
1099 {
1100 Conf->mCompoundAffixFlag *= 2;
1103 Conf->mCompoundAffixFlag * sizeof(CompoundAffixFlag));
1104 }
1105 else
1106 {
1107 Conf->mCompoundAffixFlag = 10;
1110 }
1111 }
1112
1113 newValue = Conf->CompoundAffixFlags + Conf->nCompoundAffixFlag;
1114
1115 setCompoundAffixFlagValue(Conf, newValue, sbuf, val);
1116
1117 Conf->usecompound = true;
1118 Conf->nCompoundAffixFlag++;
1119}
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
long val
Definition: informix.c:689
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1023
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1544
static void setCompoundAffixFlagValue(IspellDict *Conf, CompoundAffixFlag *entry, char *s, uint32 val)
Definition: spell.c:1033
#define tmpalloc(sz)
Definition: spell.c:80
bool usecompound
Definition: spell.h:202
CompoundAffixFlag * CompoundAffixFlags
Definition: spell.h:210
int nCompoundAffixFlag
Definition: spell.h:212
int mCompoundAffixFlag
Definition: spell.h:214
#define COPYCHAR(d, s)
Definition: ts_locale.h:40

References IspellDict::CompoundAffixFlags, COPYCHAR, ereport, errcode(), errmsg(), ERROR, IspellDict::mCompoundAffixFlag, IspellDict::nCompoundAffixFlag, pg_mblen(), repalloc(), setCompoundAffixFlagValue(), tmpalloc, IspellDict::usecompound, and val.

Referenced by NIImportAffixes(), and NIImportOOAffixes().

◆ addNorm()

static void addNorm ( TSLexeme **  lres,
TSLexeme **  lcur,
char *  word,
int  flags,
uint16  NVariant 
)
static

Definition at line 2529 of file spell.c.

2530{
2531 if (*lres == NULL)
2532 *lcur = *lres = (TSLexeme *) palloc(MAX_NORM * sizeof(TSLexeme));
2533
2534 if (*lcur - *lres < MAX_NORM - 1)
2535 {
2536 (*lcur)->lexeme = word;
2537 (*lcur)->flags = flags;
2538 (*lcur)->nvariant = NVariant;
2539 (*lcur)++;
2540 (*lcur)->lexeme = NULL;
2541 }
2542}
void * palloc(Size size)
Definition: mcxt.c:1317
static void word(struct vars *v, int dir, struct state *lp, struct state *rp)
Definition: regcomp.c:1476
#define MAX_NORM
Definition: spell.c:188

References MAX_NORM, palloc(), and word().

Referenced by NINormalizeWord().

◆ AddStem()

static void AddStem ( SplitVar v,
char *  word 
)
static

Definition at line 2366 of file spell.c.

2367{
2368 if (v->nstem >= v->lenstem)
2369 {
2370 v->lenstem *= 2;
2371 v->stem = (char **) repalloc(v->stem, sizeof(char *) * v->lenstem);
2372 }
2373
2374 v->stem[v->nstem] = word;
2375 v->nstem++;
2376}
int nstem
Definition: spell.c:2292
int lenstem
Definition: spell.c:2293
char ** stem
Definition: spell.c:2294

References SplitVar::lenstem, SplitVar::nstem, repalloc(), SplitVar::stem, and word().

Referenced by SplitToVariants().

◆ addToResult()

static int addToResult ( char **  forms,
char **  cur,
char *  word 
)
static

Definition at line 2166 of file spell.c.

2167{
2168 if (cur - forms >= MAX_NORM - 1)
2169 return 0;
2170 if (forms == cur || strcmp(word, *(cur - 1)) != 0)
2171 {
2172 *cur = pstrdup(word);
2173 *(cur + 1) = NULL;
2174 return 1;
2175 }
2176
2177 return 0;
2178}
struct cursor * cur
Definition: ecpg.c:29
char * pstrdup(const char *in)
Definition: mcxt.c:1699

References cur, MAX_NORM, pstrdup(), and word().

Referenced by NormalizeSubWord().

◆ CheckAffix()

static char * CheckAffix ( const char *  word,
size_t  len,
AFFIX Affix,
int  flagflags,
char *  newword,
int *  baselen 
)
static

Definition at line 2076 of file spell.c.

2077{
2078 /*
2079 * Check compound allow flags
2080 */
2081
2082 if (flagflags == 0)
2083 {
2084 if (Affix->flagflags & FF_COMPOUNDONLY)
2085 return NULL;
2086 }
2087 else if (flagflags & FF_COMPOUNDBEGIN)
2088 {
2089 if (Affix->flagflags & FF_COMPOUNDFORBIDFLAG)
2090 return NULL;
2091 if ((Affix->flagflags & FF_COMPOUNDBEGIN) == 0)
2092 if (Affix->type == FF_SUFFIX)
2093 return NULL;
2094 }
2095 else if (flagflags & FF_COMPOUNDMIDDLE)
2096 {
2097 if ((Affix->flagflags & FF_COMPOUNDMIDDLE) == 0 ||
2099 return NULL;
2100 }
2101 else if (flagflags & FF_COMPOUNDLAST)
2102 {
2103 if (Affix->flagflags & FF_COMPOUNDFORBIDFLAG)
2104 return NULL;
2105 if ((Affix->flagflags & FF_COMPOUNDLAST) == 0)
2106 if (Affix->type == FF_PREFIX)
2107 return NULL;
2108 }
2109
2110 /*
2111 * make replace pattern of affix
2112 */
2113 if (Affix->type == FF_SUFFIX)
2114 {
2115 strcpy(newword, word);
2116 strcpy(newword + len - Affix->replen, Affix->find);
2117 if (baselen) /* store length of non-changed part of word */
2118 *baselen = len - Affix->replen;
2119 }
2120 else
2121 {
2122 /*
2123 * if prefix is an all non-changed part's length then all word
2124 * contains only prefix and suffix, so out
2125 */
2126 if (baselen && *baselen + strlen(Affix->find) <= Affix->replen)
2127 return NULL;
2128 strcpy(newword, Affix->find);
2129 strcat(newword, word + Affix->replen);
2130 }
2131
2132 /*
2133 * check resulting word
2134 */
2135 if (Affix->issimple)
2136 return newword;
2137 else if (Affix->isregis)
2138 {
2139 if (RS_execute(&(Affix->reg.regis), newword))
2140 return newword;
2141 }
2142 else
2143 {
2144 pg_wchar *data;
2145 size_t data_len;
2146 int newword_len;
2147
2148 /* Convert data string to wide characters */
2149 newword_len = strlen(newword);
2150 data = (pg_wchar *) palloc((newword_len + 1) * sizeof(pg_wchar));
2151 data_len = pg_mb2wchar_with_len(newword, data, newword_len);
2152
2153 if (pg_regexec(Affix->reg.pregex, data, data_len,
2154 0, NULL, 0, NULL, 0) == REG_OKAY)
2155 {
2156 pfree(data);
2157 return newword;
2158 }
2159 pfree(data);
2160 }
2161
2162 return NULL;
2163}
unsigned int pg_wchar
Definition: mbprint.c:31
int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
Definition: mbutils.c:986
void pfree(void *pointer)
Definition: mcxt.c:1524
const void size_t len
const void * data
#define REG_OKAY
Definition: regex.h:215
int pg_regexec(regex_t *re, const chr *string, size_t len, size_t search_start, rm_detail_t *details, size_t nmatch, regmatch_t pmatch[], int flags)
Definition: regexec.c:185
bool RS_execute(Regis *r, char *str)
Definition: regis.c:213
#define FF_SUFFIX
Definition: spell.h:121
#define FF_PREFIX
Definition: spell.h:122
#define FF_COMPOUNDFORBIDFLAG
Definition: spell.h:114
#define FF_COMPOUNDBEGIN
Definition: spell.h:43
#define FF_COMPOUNDMIDDLE
Definition: spell.h:44
#define FF_COMPOUNDONLY
Definition: spell.h:42
#define FF_COMPOUNDLAST
Definition: spell.h:45
union aff_struct::@138 reg
const char * find
Definition: spell.h:96
uint32 isregis
Definition: spell.h:94
uint32 type
Definition: spell.h:91
Regis regis
Definition: spell.h:106
uint32 replen
Definition: spell.h:95
regex_t * pregex
Definition: spell.h:105
uint32 flagflags
Definition: spell.h:92
uint32 issimple
Definition: spell.h:93

References data, FF_COMPOUNDBEGIN, FF_COMPOUNDFORBIDFLAG, FF_COMPOUNDLAST, FF_COMPOUNDMIDDLE, FF_COMPOUNDONLY, FF_PREFIX, FF_SUFFIX, aff_struct::find, aff_struct::flagflags, aff_struct::isregis, aff_struct::issimple, len, palloc(), pfree(), pg_mb2wchar_with_len(), pg_regexec(), aff_struct::pregex, aff_struct::reg, REG_OKAY, aff_struct::regis, aff_struct::replen, RS_execute(), aff_struct::type, and word().

Referenced by NormalizeSubWord().

◆ CheckCompoundAffixes()

static int CheckCompoundAffixes ( CMPDAffix **  ptr,
const char *  word,
int  len,
bool  CheckInPlace 
)
static

Definition at line 2299 of file spell.c.

2300{
2301 bool issuffix;
2302
2303 /* in case CompoundAffix is null: */
2304 if (*ptr == NULL)
2305 return -1;
2306
2307 if (CheckInPlace)
2308 {
2309 while ((*ptr)->affix)
2310 {
2311 if (len > (*ptr)->len && strncmp((*ptr)->affix, word, (*ptr)->len) == 0)
2312 {
2313 len = (*ptr)->len;
2314 issuffix = (*ptr)->issuffix;
2315 (*ptr)++;
2316 return (issuffix) ? len : 0;
2317 }
2318 (*ptr)++;
2319 }
2320 }
2321 else
2322 {
2323 char *affbegin;
2324
2325 while ((*ptr)->affix)
2326 {
2327 if (len > (*ptr)->len && (affbegin = strstr(word, (*ptr)->affix)) != NULL)
2328 {
2329 len = (*ptr)->len + (affbegin - word);
2330 issuffix = (*ptr)->issuffix;
2331 (*ptr)++;
2332 return (issuffix) ? len : 0;
2333 }
2334 (*ptr)++;
2335 }
2336 }
2337 return -1;
2338}

References len, and word().

Referenced by SplitToVariants().

◆ cmpaffix()

static int cmpaffix ( const void *  s1,
const void *  s2 
)
static

Definition at line 312 of file spell.c.

313{
314 const AFFIX *a1 = (const AFFIX *) s1;
315 const AFFIX *a2 = (const AFFIX *) s2;
316
317 if (a1->type < a2->type)
318 return -1;
319 if (a1->type > a2->type)
320 return 1;
321 if (a1->type == FF_PREFIX)
322 return strcmp(a1->repl, a2->repl);
323 else
324 return strbcmp((const unsigned char *) a1->repl,
325 (const unsigned char *) a2->repl);
326}
static const FormData_pg_attribute a1
Definition: heap.c:144
static const FormData_pg_attribute a2
Definition: heap.c:157
char * s1
char * s2
static int strbcmp(const unsigned char *s1, const unsigned char *s2)
Definition: spell.c:258

References a1, a2, FF_PREFIX, s1, s2, and strbcmp().

Referenced by NISortAffixes().

◆ cmpcmdflag()

static int cmpcmdflag ( const void *  f1,
const void *  f2 
)
static

Definition at line 211 of file spell.c.

212{
214 *fv2 = (CompoundAffixFlag *) f2;
215
216 Assert(fv1->flagMode == fv2->flagMode);
217
218 if (fv1->flagMode == FM_NUM)
219 {
220 if (fv1->flag.i == fv2->flag.i)
221 return 0;
222
223 return (fv1->flag.i > fv2->flag.i) ? 1 : -1;
224 }
225
226 return strcmp(fv1->flag.s, fv2->flag.s);
227}
Assert(PointerIsAligned(start, uint64))
@ FM_NUM
Definition: spell.h:161
int f1[ARRAY_SIZE]
Definition: sql-declare.c:113
int f2[ARRAY_SIZE]
Definition: sql-declare.c:116
union CompoundAffixFlag::@139 flag
FlagMode flagMode
Definition: spell.h:178
const char * s
Definition: spell.h:173

References Assert(), f1, f2, CompoundAffixFlag::flag, CompoundAffixFlag::flagMode, FM_NUM, CompoundAffixFlag::i, and CompoundAffixFlag::s.

Referenced by getCompoundAffixFlagValue(), and NIImportOOAffixes().

◆ cmpspell()

static int cmpspell ( const void *  s1,
const void *  s2 
)
static

Definition at line 198 of file spell.c.

199{
200 return strcmp((*(SPELL *const *) s1)->word, (*(SPELL *const *) s2)->word);
201}

References s1, s2, and word().

Referenced by NISortDictionary().

◆ cmpspellaffix()

static int cmpspellaffix ( const void *  s1,
const void *  s2 
)
static

Definition at line 204 of file spell.c.

205{
206 return strcmp((*(SPELL *const *) s1)->p.flag,
207 (*(SPELL *const *) s2)->p.flag);
208}

References s1, and s2.

Referenced by NISortDictionary().

◆ compact_palloc0()

static void * compact_palloc0 ( IspellDict Conf,
size_t  size 
)
static

Definition at line 131 of file spell.c.

132{
133 void *result;
134
135 /* Should only be called during init */
136 Assert(Conf->buildCxt != NULL);
137
138 /* No point in this for large chunks */
139 if (size > COMPACT_MAX_REQ)
140 return palloc0(size);
141
142 /* Keep everything maxaligned */
143 size = MAXALIGN(size);
144
145 /* Need more space? */
146 if (size > Conf->avail)
147 {
150 }
151
152 result = Conf->firstfree;
153 Conf->firstfree += size;
154 Conf->avail -= size;
155
156 return result;
157}
#define MAXALIGN(LEN)
Definition: c.h:782
void * palloc0(Size size)
Definition: mcxt.c:1347
#define COMPACT_ALLOC_CHUNK
Definition: spell.c:127
#define COMPACT_MAX_REQ
Definition: spell.c:128
MemoryContext buildCxt
Definition: spell.h:220
char * firstfree
Definition: spell.h:228
size_t avail
Definition: spell.h:229

References Assert(), IspellDict::avail, IspellDict::buildCxt, COMPACT_ALLOC_CHUNK, COMPACT_MAX_REQ, IspellDict::firstfree, MAXALIGN, and palloc0().

◆ CopyVar()

static SplitVar * CopyVar ( SplitVar s,
int  makedup 
)
static

Definition at line 2341 of file spell.c.

2342{
2343 SplitVar *v = (SplitVar *) palloc(sizeof(SplitVar));
2344
2345 v->next = NULL;
2346 if (s)
2347 {
2348 int i;
2349
2350 v->lenstem = s->lenstem;
2351 v->stem = (char **) palloc(sizeof(char *) * v->lenstem);
2352 v->nstem = s->nstem;
2353 for (i = 0; i < s->nstem; i++)
2354 v->stem[i] = (makedup) ? pstrdup(s->stem[i]) : s->stem[i];
2355 }
2356 else
2357 {
2358 v->lenstem = 16;
2359 v->stem = (char **) palloc(sizeof(char *) * v->lenstem);
2360 v->nstem = 0;
2361 }
2362 return v;
2363}
int i
Definition: isn.c:74
struct SplitVar * next
Definition: spell.c:2295

References i, SplitVar::lenstem, SplitVar::next, SplitVar::nstem, palloc(), pstrdup(), and SplitVar::stem.

Referenced by SplitToVariants().

◆ cpstrdup()

static char * cpstrdup ( IspellDict Conf,
const char *  str 
)
static

Definition at line 163 of file spell.c.

164{
165 char *res = cpalloc(strlen(str) + 1);
166
167 strcpy(res, str);
168 return res;
169}
const char * str
#define cpalloc(size)
Definition: spell.c:159

References cpalloc, and str.

Referenced by NIAddAffix(), NIAddSpell(), NIImportOOAffixes(), NISortDictionary(), and setCompoundAffixFlagValue().

◆ FindAffixes()

static AffixNodeData * FindAffixes ( AffixNode node,
const char *  word,
int  wrdlen,
int *  level,
int  type 
)
static

Definition at line 2033 of file spell.c.

2034{
2035 AffixNodeData *StopLow,
2036 *StopHigh,
2037 *StopMiddle;
2038 uint8 symbol;
2039
2040 if (node->isvoid)
2041 { /* search void affixes */
2042 if (node->data->naff)
2043 return node->data;
2044 node = node->data->node;
2045 }
2046
2047 while (node && *level < wrdlen)
2048 {
2049 StopLow = node->data;
2050 StopHigh = node->data + node->length;
2051 while (StopLow < StopHigh)
2052 {
2053 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
2054 symbol = GETWCHAR(word, wrdlen, *level, type);
2055
2056 if (StopMiddle->val == symbol)
2057 {
2058 (*level)++;
2059 if (StopMiddle->naff)
2060 return StopMiddle;
2061 node = StopMiddle->node;
2062 break;
2063 }
2064 else if (StopMiddle->val < symbol)
2065 StopLow = StopMiddle + 1;
2066 else
2067 StopHigh = StopMiddle;
2068 }
2069 if (StopLow >= StopHigh)
2070 break;
2071 }
2072 return NULL;
2073}
unsigned char symbol
Definition: api.h:2
uint8_t uint8
Definition: c.h:500
#define GETWCHAR(W, L, N, T)
Definition: spell.c:192
uint32 naff
Definition: spell.h:133
uint32 val
Definition: spell.h:132
struct AffixNode * node
Definition: spell.h:135
uint32 isvoid
Definition: spell.h:140
AffixNodeData data[FLEXIBLE_ARRAY_MEMBER]
Definition: spell.h:142
uint32 length
Definition: spell.h:141
const char * type

References AffixNode::data, GETWCHAR, AffixNode::isvoid, AffixNode::length, AffixNodeData::naff, AffixNodeData::node, type, AffixNodeData::val, and word().

Referenced by NormalizeSubWord().

◆ findchar()

static char * findchar ( char *  str,
int  c 
)
static

Definition at line 230 of file spell.c.

231{
232 while (*str)
233 {
234 if (t_iseq(str, c))
235 return str;
236 str += pg_mblen(str);
237 }
238
239 return NULL;
240}
char * c
#define t_iseq(x, c)
Definition: ts_locale.h:38

References pg_mblen(), str, and t_iseq.

Referenced by NIImportDictionary().

◆ findchar2()

static char * findchar2 ( char *  str,
int  c1,
int  c2 
)
static

Definition at line 243 of file spell.c.

244{
245 while (*str)
246 {
247 if (t_iseq(str, c1) || t_iseq(str, c2))
248 return str;
249 str += pg_mblen(str);
250 }
251
252 return NULL;
253}

References pg_mblen(), str, and t_iseq.

Referenced by NIImportAffixes().

◆ FindWord()

static int FindWord ( IspellDict Conf,
const char *  word,
const char *  affixflag,
int  flag 
)
static

Definition at line 604 of file spell.c.

605{
606 SPNode *node = Conf->Dictionary;
607 SPNodeData *StopLow,
608 *StopHigh,
609 *StopMiddle;
610 const uint8 *ptr = (const uint8 *) word;
611
613
614 while (node && *ptr)
615 {
616 StopLow = node->data;
617 StopHigh = node->data + node->length;
618 while (StopLow < StopHigh)
619 {
620 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
621 if (StopMiddle->val == *ptr)
622 {
623 if (*(ptr + 1) == '\0' && StopMiddle->isword)
624 {
625 if (flag == 0)
626 {
627 /*
628 * The word can be formed only with another word. And
629 * in the flag parameter there is not a sign that we
630 * search compound words.
631 */
632 if (StopMiddle->compoundflag & FF_COMPOUNDONLY)
633 return 0;
634 }
635 else if ((flag & StopMiddle->compoundflag) == 0)
636 return 0;
637
638 /*
639 * Check if this affix rule is presented in the affix set
640 * with index StopMiddle->affix.
641 */
642 if (IsAffixFlagInUse(Conf, StopMiddle->affix, affixflag))
643 return 1;
644 }
645 node = StopMiddle->node;
646 ptr++;
647 break;
648 }
649 else if (StopMiddle->val < *ptr)
650 StopLow = StopMiddle + 1;
651 else
652 StopHigh = StopMiddle;
653 }
654 if (StopLow >= StopHigh)
655 break;
656 }
657 return 0;
658}
static bool IsAffixFlagInUse(IspellDict *Conf, int affix, const char *affixflag)
Definition: spell.c:456
#define FF_COMPOUNDFLAGMASK
Definition: spell.h:48
SPNode * Dictionary
Definition: spell.h:193
struct SPNode * node
Definition: spell.h:35
uint32 val
Definition: spell.h:29
uint32 compoundflag
Definition: spell.h:32
uint32 isword
Definition: spell.h:30
uint32 affix
Definition: spell.h:34
Definition: spell.h:51
SPNodeData data[FLEXIBLE_ARRAY_MEMBER]
Definition: spell.h:53
uint32 length
Definition: spell.h:52
char * flag(int b)
Definition: test-ctype.c:33

References SPNodeData::affix, SPNodeData::compoundflag, SPNode::data, IspellDict::Dictionary, FF_COMPOUNDFLAGMASK, FF_COMPOUNDONLY, flag(), IsAffixFlagInUse(), SPNodeData::isword, SPNode::length, SPNodeData::node, SPNodeData::val, and word().

Referenced by NormalizeSubWord().

◆ get_nextfield()

static bool get_nextfield ( char **  str,
char *  next 
)
static

Definition at line 793 of file spell.c.

794{
795 int state = PAE_WAIT_MASK;
796 int avail = BUFSIZ;
797
798 while (**str)
799 {
800 if (state == PAE_WAIT_MASK)
801 {
802 if (t_iseq(*str, '#'))
803 return false;
804 else if (!isspace((unsigned char) **str))
805 {
806 int clen = pg_mblen(*str);
807
808 if (clen < avail)
809 {
810 COPYCHAR(next, *str);
811 next += clen;
812 avail -= clen;
813 }
815 }
816 }
817 else /* state == PAE_INMASK */
818 {
819 if (isspace((unsigned char) **str))
820 {
821 *next = '\0';
822 return true;
823 }
824 else
825 {
826 int clen = pg_mblen(*str);
827
828 if (clen < avail)
829 {
830 COPYCHAR(next, *str);
831 next += clen;
832 avail -= clen;
833 }
834 }
835 }
836 *str += pg_mblen(*str);
837 }
838
839 *next = '\0';
840
841 return (state == PAE_INMASK); /* OK if we got a nonempty field */
842}
static int32 next
Definition: blutils.c:224
#define PAE_INMASK
Definition: spell.c:774
#define PAE_WAIT_MASK
Definition: spell.c:773
Definition: regguts.h:323

References COPYCHAR, next, PAE_INMASK, PAE_WAIT_MASK, pg_mblen(), str, and t_iseq.

Referenced by parse_ooaffentry().

◆ getAffixFlagSet()

static const char * getAffixFlagSet ( IspellDict Conf,
char *  s 
)
static

Definition at line 1162 of file spell.c.

1163{
1164 if (Conf->useFlagAliases && *s != '\0')
1165 {
1166 int curaffix;
1167 char *end;
1168
1169 errno = 0;
1170 curaffix = strtol(s, &end, 10);
1171 if (s == end || errno == ERANGE)
1172 ereport(ERROR,
1173 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1174 errmsg("invalid affix alias \"%s\"", s)));
1175
1176 if (curaffix > 0 && curaffix < Conf->nAffixData)
1177
1178 /*
1179 * Do not subtract 1 from curaffix because empty string was added
1180 * in NIImportOOAffixes
1181 */
1182 return Conf->AffixData[curaffix];
1183 else if (curaffix > Conf->nAffixData)
1184 ereport(ERROR,
1185 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1186 errmsg("invalid affix alias \"%s\"", s)));
1187 return VoidString;
1188 }
1189 else
1190 return s;
1191}
static const char * VoidString
Definition: spell.c:195
int nAffixData
Definition: spell.h:197
bool useFlagAliases
Definition: spell.h:198
const char ** AffixData
Definition: spell.h:195

References IspellDict::AffixData, ereport, errcode(), errmsg(), ERROR, IspellDict::nAffixData, IspellDict::useFlagAliases, and VoidString.

Referenced by NIImportOOAffixes().

◆ getCompoundAffixFlagValue()

static int getCompoundAffixFlagValue ( IspellDict Conf,
const char *  s 
)
static

Definition at line 1126 of file spell.c.

1127{
1128 uint32 flag = 0;
1129 CompoundAffixFlag *found,
1130 key;
1131 char sflag[BUFSIZ];
1132 const char *flagcur;
1133
1134 if (Conf->nCompoundAffixFlag == 0)
1135 return 0;
1136
1137 flagcur = s;
1138 while (*flagcur)
1139 {
1140 getNextFlagFromString(Conf, &flagcur, sflag);
1141 setCompoundAffixFlagValue(Conf, &key, sflag, 0);
1142
1143 found = (CompoundAffixFlag *)
1144 bsearch(&key, Conf->CompoundAffixFlags,
1146 cmpcmdflag);
1147 if (found != NULL)
1148 flag |= found->value;
1149 }
1150
1151 return flag;
1152}
uint32_t uint32
Definition: c.h:502
static void getNextFlagFromString(IspellDict *Conf, const char **sflagset, char *sflag)
Definition: spell.c:350
static int cmpcmdflag(const void *f1, const void *f2)
Definition: spell.c:211
uint32 value
Definition: spell.h:179

References cmpcmdflag(), IspellDict::CompoundAffixFlags, flag(), getNextFlagFromString(), sort-test::key, IspellDict::nCompoundAffixFlag, setCompoundAffixFlagValue(), and CompoundAffixFlag::value.

Referenced by makeCompoundFlags(), and NIImportOOAffixes().

◆ getNextFlagFromString()

static void getNextFlagFromString ( IspellDict Conf,
const char **  sflagset,
char *  sflag 
)
static

Definition at line 350 of file spell.c.

351{
352 int32 s;
353 char *next;
354 const char *sbuf = *sflagset;
355 int maxstep;
356 bool stop = false;
357 bool met_comma = false;
358
359 maxstep = (Conf->flagMode == FM_LONG) ? 2 : 1;
360
361 while (**sflagset)
362 {
363 switch (Conf->flagMode)
364 {
365 case FM_LONG:
366 case FM_CHAR:
367 COPYCHAR(sflag, *sflagset);
368 sflag += pg_mblen(*sflagset);
369
370 /* Go to start of the next flag */
371 *sflagset += pg_mblen(*sflagset);
372
373 /* Check if we get all characters of flag */
374 maxstep--;
375 stop = (maxstep == 0);
376 break;
377 case FM_NUM:
378 errno = 0;
379 s = strtol(*sflagset, &next, 10);
380 if (*sflagset == next || errno == ERANGE)
382 (errcode(ERRCODE_CONFIG_FILE_ERROR),
383 errmsg("invalid affix flag \"%s\"", *sflagset)));
384 if (s < 0 || s > FLAGNUM_MAXSIZE)
386 (errcode(ERRCODE_CONFIG_FILE_ERROR),
387 errmsg("affix flag \"%s\" is out of range",
388 *sflagset)));
389 sflag += sprintf(sflag, "%0d", s);
390
391 /* Go to start of the next flag */
392 *sflagset = next;
393 while (**sflagset)
394 {
395 if (isdigit((unsigned char) **sflagset))
396 {
397 if (!met_comma)
399 (errcode(ERRCODE_CONFIG_FILE_ERROR),
400 errmsg("invalid affix flag \"%s\"",
401 *sflagset)));
402 break;
403 }
404 else if (t_iseq(*sflagset, ','))
405 {
406 if (met_comma)
408 (errcode(ERRCODE_CONFIG_FILE_ERROR),
409 errmsg("invalid affix flag \"%s\"",
410 *sflagset)));
411 met_comma = true;
412 }
413 else if (!isspace((unsigned char) **sflagset))
414 {
416 (errcode(ERRCODE_CONFIG_FILE_ERROR),
417 errmsg("invalid character in affix flag \"%s\"",
418 *sflagset)));
419 }
420
421 *sflagset += pg_mblen(*sflagset);
422 }
423 stop = true;
424 break;
425 default:
426 elog(ERROR, "unrecognized type of Conf->flagMode: %d",
427 Conf->flagMode);
428 }
429
430 if (stop)
431 break;
432 }
433
434 if (Conf->flagMode == FM_LONG && maxstep > 0)
436 (errcode(ERRCODE_CONFIG_FILE_ERROR),
437 errmsg("invalid affix flag \"%s\" with \"long\" flag value",
438 sbuf)));
439
440 *sflag = '\0';
441}
int32_t int32
Definition: c.h:498
#define elog(elevel,...)
Definition: elog.h:225
#define sprintf
Definition: port.h:241
#define FLAGNUM_MAXSIZE
Definition: spell.h:182
@ FM_LONG
Definition: spell.h:160
@ FM_CHAR
Definition: spell.h:159
FlagMode flagMode
Definition: spell.h:203

References COPYCHAR, elog, ereport, errcode(), errmsg(), ERROR, IspellDict::flagMode, FLAGNUM_MAXSIZE, FM_CHAR, FM_LONG, FM_NUM, next, pg_mblen(), sprintf, and t_iseq.

Referenced by getCompoundAffixFlagValue(), and IsAffixFlagInUse().

◆ IsAffixFlagInUse()

static bool IsAffixFlagInUse ( IspellDict Conf,
int  affix,
const char *  affixflag 
)
static

Definition at line 456 of file spell.c.

457{
458 const char *flagcur;
459 char flag[BUFSIZ];
460
461 if (*affixflag == 0)
462 return true;
463
464 Assert(affix < Conf->nAffixData);
465
466 flagcur = Conf->AffixData[affix];
467
468 while (*flagcur)
469 {
470 getNextFlagFromString(Conf, &flagcur, flag);
471 /* Compare first affix flag in flagcur with affixflag */
472 if (strcmp(flag, affixflag) == 0)
473 return true;
474 }
475
476 /* Could not find affixflag */
477 return false;
478}

References IspellDict::AffixData, Assert(), flag(), and getNextFlagFromString().

Referenced by FindWord(), and isAffixInUse().

◆ isAffixInUse()

static bool isAffixInUse ( IspellDict Conf,
const char *  affixflag 
)
static

Definition at line 1966 of file spell.c.

1967{
1968 int i;
1969
1970 for (i = 0; i < Conf->nAffixData; i++)
1971 if (IsAffixFlagInUse(Conf, i, affixflag))
1972 return true;
1973
1974 return false;
1975}

References i, IsAffixFlagInUse(), and IspellDict::nAffixData.

Referenced by NISortAffixes().

◆ lowerstr_ctx()

static char * lowerstr_ctx ( IspellDict Conf,
const char *  src 
)
static

Definition at line 176 of file spell.c.

177{
178 MemoryContext saveCtx;
179 char *dst;
180
181 saveCtx = MemoryContextSwitchTo(Conf->buildCxt);
182 dst = str_tolower(src, strlen(src), DEFAULT_COLLATION_OID);
183 MemoryContextSwitchTo(saveCtx);
184
185 return dst;
186}
char * str_tolower(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1637
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124

References IspellDict::buildCxt, MemoryContextSwitchTo(), and str_tolower().

Referenced by NIImportDictionary(), and NIImportOOAffixes().

◆ makeCompoundFlags()

static uint32 makeCompoundFlags ( IspellDict Conf,
int  affix 
)
static

Definition at line 1627 of file spell.c.

1628{
1629 Assert(affix < Conf->nAffixData);
1630
1631 return (getCompoundAffixFlagValue(Conf, Conf->AffixData[affix]) &
1633}
static int getCompoundAffixFlagValue(IspellDict *Conf, const char *s)
Definition: spell.c:1126

References IspellDict::AffixData, Assert(), FF_COMPOUNDFLAGMASK, and getCompoundAffixFlagValue().

Referenced by mkSPNode().

◆ MergeAffix()

static int MergeAffix ( IspellDict Conf,
int  a1,
int  a2 
)
static

Definition at line 1576 of file spell.c.

1577{
1578 const char **ptr;
1579
1580 Assert(a1 < Conf->nAffixData && a2 < Conf->nAffixData);
1581
1582 /* Do not merge affix flags if one of affix flags is empty */
1583 if (*Conf->AffixData[a1] == '\0')
1584 return a2;
1585 else if (*Conf->AffixData[a2] == '\0')
1586 return a1;
1587
1588 /* Double the size of AffixData if there's not enough space */
1589 if (Conf->nAffixData + 1 >= Conf->lenAffixData)
1590 {
1591 Conf->lenAffixData *= 2;
1592 Conf->AffixData = (const char **) repalloc(Conf->AffixData,
1593 sizeof(char *) * Conf->lenAffixData);
1594 }
1595
1596 ptr = Conf->AffixData + Conf->nAffixData;
1597 if (Conf->flagMode == FM_NUM)
1598 {
1599 char *p = cpalloc(strlen(Conf->AffixData[a1]) +
1600 strlen(Conf->AffixData[a2]) +
1601 1 /* comma */ + 1 /* \0 */ );
1602
1603 sprintf(p, "%s,%s", Conf->AffixData[a1], Conf->AffixData[a2]);
1604 *ptr = p;
1605 }
1606 else
1607 {
1608 char *p = cpalloc(strlen(Conf->AffixData[a1]) +
1609 strlen(Conf->AffixData[a2]) +
1610 1 /* \0 */ );
1611
1612 sprintf(p, "%s%s", Conf->AffixData[a1], Conf->AffixData[a2]);
1613 *ptr = p;
1614 }
1615 ptr++;
1616 *ptr = NULL;
1617 Conf->nAffixData++;
1618
1619 return Conf->nAffixData - 1;
1620}
int lenAffixData
Definition: spell.h:196

References a1, a2, IspellDict::AffixData, Assert(), cpalloc, IspellDict::flagMode, FM_NUM, IspellDict::lenAffixData, IspellDict::nAffixData, repalloc(), and sprintf.

Referenced by mkSPNode().

◆ mkANode()

static AffixNode * mkANode ( IspellDict Conf,
int  low,
int  high,
int  level,
int  type 
)
static

Definition at line 1835 of file spell.c.

1836{
1837 int i;
1838 int nchar = 0;
1839 uint8 lastchar = '\0';
1840 AffixNode *rs;
1842 int lownew = low;
1843 int naff;
1844 AFFIX **aff;
1845
1846 for (i = low; i < high; i++)
1847 if (Conf->Affix[i].replen > level && lastchar != GETCHAR(Conf->Affix + i, level, type))
1848 {
1849 nchar++;
1850 lastchar = GETCHAR(Conf->Affix + i, level, type);
1851 }
1852
1853 if (!nchar)
1854 return NULL;
1855
1856 aff = (AFFIX **) tmpalloc(sizeof(AFFIX *) * (high - low + 1));
1857 naff = 0;
1858
1859 rs = (AffixNode *) cpalloc0(ANHRDSZ + nchar * sizeof(AffixNodeData));
1860 rs->length = nchar;
1861 data = rs->data;
1862
1863 lastchar = '\0';
1864 for (i = low; i < high; i++)
1865 if (Conf->Affix[i].replen > level)
1866 {
1867 if (lastchar != GETCHAR(Conf->Affix + i, level, type))
1868 {
1869 if (lastchar)
1870 {
1871 /* Next level of the prefix tree */
1872 data->node = mkANode(Conf, lownew, i, level + 1, type);
1873 if (naff)
1874 {
1875 data->naff = naff;
1876 data->aff = (AFFIX **) cpalloc(sizeof(AFFIX *) * naff);
1877 memcpy(data->aff, aff, sizeof(AFFIX *) * naff);
1878 naff = 0;
1879 }
1880 data++;
1881 lownew = i;
1882 }
1883 lastchar = GETCHAR(Conf->Affix + i, level, type);
1884 }
1885 data->val = GETCHAR(Conf->Affix + i, level, type);
1886 if (Conf->Affix[i].replen == level + 1)
1887 { /* affix stopped */
1888 aff[naff++] = Conf->Affix + i;
1889 }
1890 }
1891
1892 /* Next level of the prefix tree */
1893 data->node = mkANode(Conf, lownew, high, level + 1, type);
1894 if (naff)
1895 {
1896 data->naff = naff;
1897 data->aff = (AFFIX **) cpalloc(sizeof(AFFIX *) * naff);
1898 memcpy(data->aff, aff, sizeof(AFFIX *) * naff);
1899 naff = 0;
1900 }
1901
1902 pfree(aff);
1903
1904 return rs;
1905}
#define GETCHAR(A, N, T)
Definition: spell.c:193
static AffixNode * mkANode(IspellDict *Conf, int low, int high, int level, int type)
Definition: spell.c:1835
#define cpalloc0(size)
Definition: spell.c:160
#define ANHRDSZ
Definition: spell.h:145
AFFIX * Affix
Definition: spell.h:188

References IspellDict::Affix, ANHRDSZ, cpalloc, cpalloc0, AffixNode::data, data, GETCHAR, i, AffixNode::length, mkANode(), pfree(), aff_struct::replen, tmpalloc, and type.

Referenced by mkANode(), and NISortAffixes().

◆ mkSPNode()

static SPNode * mkSPNode ( IspellDict Conf,
int  low,
int  high,
int  level 
)
static

Definition at line 1644 of file spell.c.

1645{
1646 int i;
1647 int nchar = 0;
1648 char lastchar = '\0';
1649 SPNode *rs;
1651 int lownew = low;
1652
1653 for (i = low; i < high; i++)
1654 if (Conf->Spell[i]->p.d.len > level && lastchar != Conf->Spell[i]->word[level])
1655 {
1656 nchar++;
1657 lastchar = Conf->Spell[i]->word[level];
1658 }
1659
1660 if (!nchar)
1661 return NULL;
1662
1663 rs = (SPNode *) cpalloc0(SPNHDRSZ + nchar * sizeof(SPNodeData));
1664 rs->length = nchar;
1665 data = rs->data;
1666
1667 lastchar = '\0';
1668 for (i = low; i < high; i++)
1669 if (Conf->Spell[i]->p.d.len > level)
1670 {
1671 if (lastchar != Conf->Spell[i]->word[level])
1672 {
1673 if (lastchar)
1674 {
1675 /* Next level of the prefix tree */
1676 data->node = mkSPNode(Conf, lownew, i, level + 1);
1677 lownew = i;
1678 data++;
1679 }
1680 lastchar = Conf->Spell[i]->word[level];
1681 }
1682 data->val = ((uint8 *) (Conf->Spell[i]->word))[level];
1683 if (Conf->Spell[i]->p.d.len == level + 1)
1684 {
1685 bool clearCompoundOnly = false;
1686
1687 if (data->isword && data->affix != Conf->Spell[i]->p.d.affix)
1688 {
1689 /*
1690 * MergeAffix called a few times. If one of word is
1691 * allowed to be in compound word and another isn't, then
1692 * clear FF_COMPOUNDONLY flag.
1693 */
1694
1695 clearCompoundOnly = (FF_COMPOUNDONLY & data->compoundflag
1696 & makeCompoundFlags(Conf, Conf->Spell[i]->p.d.affix))
1697 ? false : true;
1698 data->affix = MergeAffix(Conf, data->affix, Conf->Spell[i]->p.d.affix);
1699 }
1700 else
1701 data->affix = Conf->Spell[i]->p.d.affix;
1702 data->isword = 1;
1703
1704 data->compoundflag = makeCompoundFlags(Conf, data->affix);
1705
1706 if ((data->compoundflag & FF_COMPOUNDONLY) &&
1707 (data->compoundflag & FF_COMPOUNDFLAG) == 0)
1708 data->compoundflag |= FF_COMPOUNDFLAG;
1709
1710 if (clearCompoundOnly)
1711 data->compoundflag &= ~FF_COMPOUNDONLY;
1712 }
1713 }
1714
1715 /* Next level of the prefix tree */
1716 data->node = mkSPNode(Conf, lownew, high, level + 1);
1717
1718 return rs;
1719}
static SPNode * mkSPNode(IspellDict *Conf, int low, int high, int level)
Definition: spell.c:1644
static uint32 makeCompoundFlags(IspellDict *Conf, int affix)
Definition: spell.c:1627
static int MergeAffix(IspellDict *Conf, int a1, int a2)
Definition: spell.c:1576
#define FF_COMPOUNDFLAG
Definition: spell.h:46
#define SPNHDRSZ
Definition: spell.h:56
SPELL ** Spell
Definition: spell.h:223
int len
Definition: spell.h:76
union spell_struct::@136 p
char word[FLEXIBLE_ARRAY_MEMBER]
Definition: spell.h:79
int affix
Definition: spell.h:74
struct spell_struct::@136::@137 d

References spell_struct::affix, cpalloc0, spell_struct::d, SPNode::data, data, FF_COMPOUNDFLAG, FF_COMPOUNDONLY, i, spell_struct::len, SPNode::length, makeCompoundFlags(), MergeAffix(), mkSPNode(), spell_struct::p, IspellDict::Spell, SPNHDRSZ, and spell_struct::word.

Referenced by mkSPNode(), and NISortDictionary().

◆ mkVoidAffix()

static void mkVoidAffix ( IspellDict Conf,
bool  issuffix,
int  startsuffix 
)
static

Definition at line 1912 of file spell.c.

1913{
1914 int i,
1915 cnt = 0;
1916 int start = (issuffix) ? startsuffix : 0;
1917 int end = (issuffix) ? Conf->naffixes : startsuffix;
1918 AffixNode *Affix = (AffixNode *) palloc0(ANHRDSZ + sizeof(AffixNodeData));
1919
1920 Affix->length = 1;
1921 Affix->isvoid = 1;
1922
1923 if (issuffix)
1924 {
1925 Affix->data->node = Conf->Suffix;
1926 Conf->Suffix = Affix;
1927 }
1928 else
1929 {
1930 Affix->data->node = Conf->Prefix;
1931 Conf->Prefix = Affix;
1932 }
1933
1934 /* Count affixes with empty replace string */
1935 for (i = start; i < end; i++)
1936 if (Conf->Affix[i].replen == 0)
1937 cnt++;
1938
1939 /* There is not affixes with empty replace string */
1940 if (cnt == 0)
1941 return;
1942
1943 Affix->data->aff = (AFFIX **) cpalloc(sizeof(AFFIX *) * cnt);
1944 Affix->data->naff = (uint32) cnt;
1945
1946 cnt = 0;
1947 for (i = start; i < end; i++)
1948 if (Conf->Affix[i].replen == 0)
1949 {
1950 Affix->data->aff[cnt] = Conf->Affix + i;
1951 cnt++;
1952 }
1953}
return str start
AFFIX ** aff
Definition: spell.h:134
AffixNode * Suffix
Definition: spell.h:190
int naffixes
Definition: spell.h:187
AffixNode * Prefix
Definition: spell.h:191

References AffixNodeData::aff, IspellDict::Affix, ANHRDSZ, cpalloc, AffixNode::data, i, IspellDict::naffixes, AffixNodeData::node, palloc0(), IspellDict::Prefix, aff_struct::replen, start, and IspellDict::Suffix.

Referenced by NISortAffixes().

◆ NIAddAffix()

static void NIAddAffix ( IspellDict Conf,
const char *  flag,
char  flagflags,
const char *  mask,
const char *  find,
const char *  repl,
int  type 
)
static

Definition at line 679 of file spell.c.

681{
682 AFFIX *Affix;
683
684 if (Conf->naffixes >= Conf->maffixes)
685 {
686 if (Conf->maffixes)
687 {
688 Conf->maffixes *= 2;
689 Conf->Affix = (AFFIX *) repalloc(Conf->Affix, Conf->maffixes * sizeof(AFFIX));
690 }
691 else
692 {
693 Conf->maffixes = 16;
694 Conf->Affix = (AFFIX *) palloc(Conf->maffixes * sizeof(AFFIX));
695 }
696 }
697
698 Affix = Conf->Affix + Conf->naffixes;
699
700 /* This affix rule can be applied for words with any ending */
701 if (strcmp(mask, ".") == 0 || *mask == '\0')
702 {
703 Affix->issimple = 1;
704 Affix->isregis = 0;
705 }
706 /* This affix rule will use regis to search word ending */
707 else if (RS_isRegis(mask))
708 {
709 Affix->issimple = 0;
710 Affix->isregis = 1;
711 RS_compile(&(Affix->reg.regis), (type == FF_SUFFIX),
712 *mask ? mask : VoidString);
713 }
714 /* This affix rule will use regex_t to search word ending */
715 else
716 {
717 int masklen;
718 int wmasklen;
719 int err;
720 pg_wchar *wmask;
721 char *tmask;
722
723 Affix->issimple = 0;
724 Affix->isregis = 0;
725 tmask = (char *) tmpalloc(strlen(mask) + 3);
726 if (type == FF_SUFFIX)
727 sprintf(tmask, "%s$", mask);
728 else
729 sprintf(tmask, "^%s", mask);
730
731 masklen = strlen(tmask);
732 wmask = (pg_wchar *) tmpalloc((masklen + 1) * sizeof(pg_wchar));
733 wmasklen = pg_mb2wchar_with_len(tmask, wmask, masklen);
734
735 /*
736 * The regex and all internal state created by pg_regcomp are
737 * allocated in the dictionary's memory context, and will be freed
738 * automatically when it is destroyed.
739 */
740 Affix->reg.pregex = palloc(sizeof(regex_t));
741 err = pg_regcomp(Affix->reg.pregex, wmask, wmasklen,
743 DEFAULT_COLLATION_OID);
744 if (err)
745 {
746 char errstr[100];
747
748 pg_regerror(err, Affix->reg.pregex, errstr, sizeof(errstr));
750 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
751 errmsg("invalid regular expression: %s", errstr)));
752 }
753 }
754
755 Affix->flagflags = flagflags;
756 if ((Affix->flagflags & FF_COMPOUNDONLY) || (Affix->flagflags & FF_COMPOUNDPERMITFLAG))
757 {
758 if ((Affix->flagflags & FF_COMPOUNDFLAG) == 0)
759 Affix->flagflags |= FF_COMPOUNDFLAG;
760 }
761 Affix->flag = cpstrdup(Conf, flag);
762 Affix->type = type;
763
764 Affix->find = (find && *find) ? cpstrdup(Conf, find) : VoidString;
765 if ((Affix->replen = strlen(repl)) > 0)
766 Affix->repl = cpstrdup(Conf, repl);
767 else
768 Affix->repl = VoidString;
769 Conf->naffixes++;
770}
void err(int eval, const char *fmt,...)
Definition: err.c:43
int pg_regcomp(regex_t *re, const chr *string, size_t len, int flags, Oid collation)
Definition: regcomp.c:372
size_t pg_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
Definition: regerror.c:60
#define REG_ADVANCED
Definition: regex.h:181
#define REG_NOSUB
Definition: regex.h:185
#define regex_t
Definition: regex.h:245
static int find(struct vars *v, struct cnfa *cnfa, struct colormap *cm)
Definition: regexec.c:419
void RS_compile(Regis *r, bool issuffix, const char *str)
Definition: regis.c:85
bool RS_isRegis(const char *str)
Definition: regis.c:31
static char * cpstrdup(IspellDict *Conf, const char *str)
Definition: spell.c:163
#define FF_COMPOUNDPERMITFLAG
Definition: spell.h:113
int maffixes
Definition: spell.h:186
const char * flag
Definition: spell.h:89
const char * repl
Definition: spell.h:97

References IspellDict::Affix, cpstrdup(), ereport, err(), errcode(), errmsg(), ERROR, FF_COMPOUNDFLAG, FF_COMPOUNDONLY, FF_COMPOUNDPERMITFLAG, FF_SUFFIX, find(), aff_struct::find, aff_struct::flag, flag(), aff_struct::flagflags, aff_struct::isregis, aff_struct::issimple, IspellDict::maffixes, IspellDict::naffixes, palloc(), pg_mb2wchar_with_len(), pg_regcomp(), pg_regerror(), aff_struct::pregex, aff_struct::reg, REG_ADVANCED, REG_NOSUB, regex_t, aff_struct::regis, repalloc(), aff_struct::repl, aff_struct::replen, RS_compile(), RS_isRegis(), sprintf, tmpalloc, type, aff_struct::type, and VoidString.

Referenced by NIImportAffixes(), and NIImportOOAffixes().

◆ NIAddSpell()

static void NIAddSpell ( IspellDict Conf,
const char *  word,
const char *  flag 
)
static

Definition at line 488 of file spell.c.

489{
490 if (Conf->nspell >= Conf->mspell)
491 {
492 if (Conf->mspell)
493 {
494 Conf->mspell *= 2;
495 Conf->Spell = (SPELL **) repalloc(Conf->Spell, Conf->mspell * sizeof(SPELL *));
496 }
497 else
498 {
499 Conf->mspell = 1024 * 20;
500 Conf->Spell = (SPELL **) tmpalloc(Conf->mspell * sizeof(SPELL *));
501 }
502 }
503 Conf->Spell[Conf->nspell] = (SPELL *) tmpalloc(SPELLHDRSZ + strlen(word) + 1);
504 strcpy(Conf->Spell[Conf->nspell]->word, word);
505 Conf->Spell[Conf->nspell]->p.flag = (*flag != '\0')
506 ? cpstrdup(Conf, flag) : VoidString;
507 Conf->nspell++;
508}
#define SPELLHDRSZ
Definition: spell.h:82
int mspell
Definition: spell.h:225
int nspell
Definition: spell.h:224
const char * flag
Definition: spell.h:69

References cpstrdup(), spell_struct::flag, flag(), IspellDict::mspell, IspellDict::nspell, spell_struct::p, repalloc(), IspellDict::Spell, SPELLHDRSZ, tmpalloc, VoidString, word(), and spell_struct::word.

Referenced by NIImportDictionary().

◆ NIFinishBuild()

void NIFinishBuild ( IspellDict Conf)

Definition at line 104 of file spell.c.

105{
106 /* Release no-longer-needed temp memory */
108 /* Just for cleanliness, zero the now-dangling pointers */
109 Conf->buildCxt = NULL;
110 Conf->Spell = NULL;
111 Conf->firstfree = NULL;
112 Conf->CompoundAffixFlags = NULL;
113}
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454

References IspellDict::buildCxt, IspellDict::CompoundAffixFlags, IspellDict::firstfree, MemoryContextDelete(), and IspellDict::Spell.

Referenced by dispell_init().

◆ NIImportAffixes()

void NIImportAffixes ( IspellDict Conf,
const char *  filename 
)

Definition at line 1429 of file spell.c.

1430{
1431 char *pstr = NULL;
1432 char flag[BUFSIZ];
1433 char mask[BUFSIZ];
1434 char find[BUFSIZ];
1435 char repl[BUFSIZ];
1436 char *s;
1437 bool suffixes = false;
1438 bool prefixes = false;
1439 char flagflags = 0;
1441 bool oldformat = false;
1442 char *recoded = NULL;
1443
1444 if (!tsearch_readline_begin(&trst, filename))
1445 ereport(ERROR,
1446 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1447 errmsg("could not open affix file \"%s\": %m",
1448 filename)));
1449
1450 Conf->usecompound = false;
1451 Conf->useFlagAliases = false;
1452 Conf->flagMode = FM_CHAR;
1453
1454 while ((recoded = tsearch_readline(&trst)) != NULL)
1455 {
1456 pstr = str_tolower(recoded, strlen(recoded), DEFAULT_COLLATION_OID);
1457
1458 /* Skip comments and empty lines */
1459 if (*pstr == '#' || *pstr == '\n')
1460 goto nextline;
1461
1462 if (STRNCMP(pstr, "compoundwords") == 0)
1463 {
1464 /* Find case-insensitive L flag in non-lowercased string */
1465 s = findchar2(recoded, 'l', 'L');
1466 if (s)
1467 {
1468 while (*s && !isspace((unsigned char) *s))
1469 s += pg_mblen(s);
1470 while (*s && isspace((unsigned char) *s))
1471 s += pg_mblen(s);
1472
1473 if (*s && pg_mblen(s) == 1)
1474 {
1476 Conf->usecompound = true;
1477 }
1478 oldformat = true;
1479 goto nextline;
1480 }
1481 }
1482 if (STRNCMP(pstr, "suffixes") == 0)
1483 {
1484 suffixes = true;
1485 prefixes = false;
1486 oldformat = true;
1487 goto nextline;
1488 }
1489 if (STRNCMP(pstr, "prefixes") == 0)
1490 {
1491 suffixes = false;
1492 prefixes = true;
1493 oldformat = true;
1494 goto nextline;
1495 }
1496 if (STRNCMP(pstr, "flag") == 0)
1497 {
1498 s = recoded + 4; /* we need non-lowercased string */
1499 flagflags = 0;
1500
1501 while (*s && isspace((unsigned char) *s))
1502 s += pg_mblen(s);
1503
1504 if (*s == '*')
1505 {
1506 flagflags |= FF_CROSSPRODUCT;
1507 s++;
1508 }
1509 else if (*s == '~')
1510 {
1511 flagflags |= FF_COMPOUNDONLY;
1512 s++;
1513 }
1514
1515 if (*s == '\\')
1516 s++;
1517
1518 /*
1519 * An old-format flag is a single ASCII character; we expect it to
1520 * be followed by EOL, whitespace, or ':'. Otherwise this is a
1521 * new-format flag command.
1522 */
1523 if (*s && pg_mblen(s) == 1)
1524 {
1525 COPYCHAR(flag, s);
1526 flag[1] = '\0';
1527
1528 s++;
1529 if (*s == '\0' || *s == '#' || *s == '\n' || *s == ':' ||
1530 isspace((unsigned char) *s))
1531 {
1532 oldformat = true;
1533 goto nextline;
1534 }
1535 }
1536 goto isnewformat;
1537 }
1538 if (STRNCMP(recoded, "COMPOUNDFLAG") == 0 ||
1539 STRNCMP(recoded, "COMPOUNDMIN") == 0 ||
1540 STRNCMP(recoded, "PFX") == 0 ||
1541 STRNCMP(recoded, "SFX") == 0)
1542 goto isnewformat;
1543
1544 if ((!suffixes) && (!prefixes))
1545 goto nextline;
1546
1547 if (!parse_affentry(pstr, mask, find, repl))
1548 goto nextline;
1549
1550 NIAddAffix(Conf, flag, flagflags, mask, find, repl, suffixes ? FF_SUFFIX : FF_PREFIX);
1551
1552nextline:
1553 pfree(recoded);
1554 pfree(pstr);
1555 }
1556 tsearch_readline_end(&trst);
1557 return;
1558
1559isnewformat:
1560 if (oldformat)
1561 ereport(ERROR,
1562 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1563 errmsg("affix file contains both old-style and new-style commands")));
1564 tsearch_readline_end(&trst);
1565
1567}
static char * filename
Definition: pg_dumpall.c:124
static void prefixes(struct vars *v)
Definition: regc_lex.c:99
static void NIImportOOAffixes(IspellDict *Conf, const char *filename)
Definition: spell.c:1200
static void NIAddAffix(IspellDict *Conf, const char *flag, char flagflags, const char *mask, const char *find, const char *repl, int type)
Definition: spell.c:679
#define STRNCMP(s, p)
Definition: spell.c:191
static char * findchar2(char *str, int c1, int c2)
Definition: spell.c:243
static bool parse_affentry(char *str, char *mask, char *find, char *repl)
Definition: spell.c:915
static void addCompoundAffixFlagValue(IspellDict *Conf, char *s, uint32 val)
Definition: spell.c:1069
#define FF_CROSSPRODUCT
Definition: spell.h:115
bool tsearch_readline_begin(tsearch_readline_state *stp, const char *filename)
Definition: ts_locale.c:89
char * tsearch_readline(tsearch_readline_state *stp)
Definition: ts_locale.c:112
void tsearch_readline_end(tsearch_readline_state *stp)
Definition: ts_locale.c:157

References addCompoundAffixFlagValue(), COPYCHAR, ereport, errcode(), errmsg(), ERROR, FF_COMPOUNDFLAG, FF_COMPOUNDONLY, FF_CROSSPRODUCT, FF_PREFIX, FF_SUFFIX, filename, find(), findchar2(), flag(), IspellDict::flagMode, FM_CHAR, NIAddAffix(), NIImportOOAffixes(), parse_affentry(), pfree(), pg_mblen(), prefixes(), str_tolower(), STRNCMP, tsearch_readline(), tsearch_readline_begin(), tsearch_readline_end(), IspellDict::usecompound, and IspellDict::useFlagAliases.

Referenced by dispell_init().

◆ NIImportDictionary()

void NIImportDictionary ( IspellDict Conf,
const char *  filename 
)

Definition at line 519 of file spell.c.

520{
522 char *line;
523
524 if (!tsearch_readline_begin(&trst, filename))
526 (errcode(ERRCODE_CONFIG_FILE_ERROR),
527 errmsg("could not open dictionary file \"%s\": %m",
528 filename)));
529
530 while ((line = tsearch_readline(&trst)) != NULL)
531 {
532 char *s,
533 *pstr;
534
535 /* Set of affix flags */
536 const char *flag;
537
538 /* Extract flag from the line */
539 flag = NULL;
540 if ((s = findchar(line, '/')))
541 {
542 *s++ = '\0';
543 flag = s;
544 while (*s)
545 {
546 /* we allow only single encoded flags for faster works */
547 if (pg_mblen(s) == 1 && isprint((unsigned char) *s) && !isspace((unsigned char) *s))
548 s++;
549 else
550 {
551 *s = '\0';
552 break;
553 }
554 }
555 }
556 else
557 flag = "";
558
559 /* Remove trailing spaces */
560 s = line;
561 while (*s)
562 {
563 if (isspace((unsigned char) *s))
564 {
565 *s = '\0';
566 break;
567 }
568 s += pg_mblen(s);
569 }
570 pstr = lowerstr_ctx(Conf, line);
571
572 NIAddSpell(Conf, pstr, flag);
573 pfree(pstr);
574
575 pfree(line);
576 }
578}
static void NIAddSpell(IspellDict *Conf, const char *word, const char *flag)
Definition: spell.c:488
static char * findchar(char *str, int c)
Definition: spell.c:230
static char * lowerstr_ctx(IspellDict *Conf, const char *src)
Definition: spell.c:176

References ereport, errcode(), errmsg(), ERROR, filename, findchar(), flag(), lowerstr_ctx(), NIAddSpell(), pfree(), pg_mblen(), tsearch_readline(), tsearch_readline_begin(), and tsearch_readline_end().

Referenced by dispell_init().

◆ NIImportOOAffixes()

static void NIImportOOAffixes ( IspellDict Conf,
const char *  filename 
)
static

Definition at line 1200 of file spell.c.

1201{
1202 char type[BUFSIZ],
1203 *ptype = NULL;
1204 char sflag[BUFSIZ];
1205 char mask[BUFSIZ],
1206 *pmask;
1207 char find[BUFSIZ],
1208 *pfind;
1209 char repl[BUFSIZ],
1210 *prepl;
1211 bool isSuffix = false;
1212 int naffix = 0,
1213 curaffix = 0;
1214 int sflaglen = 0;
1215 char flagflags = 0;
1217 char *recoded;
1218
1219 /* read file to find any flag */
1220 Conf->usecompound = false;
1221 Conf->useFlagAliases = false;
1222 Conf->flagMode = FM_CHAR;
1223
1224 if (!tsearch_readline_begin(&trst, filename))
1225 ereport(ERROR,
1226 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1227 errmsg("could not open affix file \"%s\": %m",
1228 filename)));
1229
1230 while ((recoded = tsearch_readline(&trst)) != NULL)
1231 {
1232 if (*recoded == '\0' || isspace((unsigned char) *recoded) || t_iseq(recoded, '#'))
1233 {
1234 pfree(recoded);
1235 continue;
1236 }
1237
1238 if (STRNCMP(recoded, "COMPOUNDFLAG") == 0)
1239 addCompoundAffixFlagValue(Conf, recoded + strlen("COMPOUNDFLAG"),
1241 else if (STRNCMP(recoded, "COMPOUNDBEGIN") == 0)
1242 addCompoundAffixFlagValue(Conf, recoded + strlen("COMPOUNDBEGIN"),
1244 else if (STRNCMP(recoded, "COMPOUNDLAST") == 0)
1245 addCompoundAffixFlagValue(Conf, recoded + strlen("COMPOUNDLAST"),
1247 /* COMPOUNDLAST and COMPOUNDEND are synonyms */
1248 else if (STRNCMP(recoded, "COMPOUNDEND") == 0)
1249 addCompoundAffixFlagValue(Conf, recoded + strlen("COMPOUNDEND"),
1251 else if (STRNCMP(recoded, "COMPOUNDMIDDLE") == 0)
1252 addCompoundAffixFlagValue(Conf, recoded + strlen("COMPOUNDMIDDLE"),
1254 else if (STRNCMP(recoded, "ONLYINCOMPOUND") == 0)
1255 addCompoundAffixFlagValue(Conf, recoded + strlen("ONLYINCOMPOUND"),
1257 else if (STRNCMP(recoded, "COMPOUNDPERMITFLAG") == 0)
1259 recoded + strlen("COMPOUNDPERMITFLAG"),
1261 else if (STRNCMP(recoded, "COMPOUNDFORBIDFLAG") == 0)
1263 recoded + strlen("COMPOUNDFORBIDFLAG"),
1265 else if (STRNCMP(recoded, "FLAG") == 0)
1266 {
1267 char *s = recoded + strlen("FLAG");
1268
1269 while (*s && isspace((unsigned char) *s))
1270 s += pg_mblen(s);
1271
1272 if (*s)
1273 {
1274 if (STRNCMP(s, "long") == 0)
1275 Conf->flagMode = FM_LONG;
1276 else if (STRNCMP(s, "num") == 0)
1277 Conf->flagMode = FM_NUM;
1278 else if (STRNCMP(s, "default") != 0)
1279 ereport(ERROR,
1280 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1281 errmsg("Ispell dictionary supports only "
1282 "\"default\", \"long\", "
1283 "and \"num\" flag values")));
1284 }
1285 }
1286
1287 pfree(recoded);
1288 }
1289 tsearch_readline_end(&trst);
1290
1291 if (Conf->nCompoundAffixFlag > 1)
1293 sizeof(CompoundAffixFlag), cmpcmdflag);
1294
1295 if (!tsearch_readline_begin(&trst, filename))
1296 ereport(ERROR,
1297 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1298 errmsg("could not open affix file \"%s\": %m",
1299 filename)));
1300
1301 while ((recoded = tsearch_readline(&trst)) != NULL)
1302 {
1303 int fields_read;
1304
1305 if (*recoded == '\0' || isspace((unsigned char) *recoded) || t_iseq(recoded, '#'))
1306 goto nextline;
1307
1308 fields_read = parse_ooaffentry(recoded, type, sflag, find, repl, mask);
1309
1310 if (ptype)
1311 pfree(ptype);
1312 ptype = lowerstr_ctx(Conf, type);
1313
1314 /* First try to parse AF parameter (alias compression) */
1315 if (STRNCMP(ptype, "af") == 0)
1316 {
1317 /* First line is the number of aliases */
1318 if (!Conf->useFlagAliases)
1319 {
1320 Conf->useFlagAliases = true;
1321 naffix = atoi(sflag);
1322 if (naffix <= 0)
1323 ereport(ERROR,
1324 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1325 errmsg("invalid number of flag vector aliases")));
1326
1327 /* Also reserve place for empty flag set */
1328 naffix++;
1329
1330 Conf->AffixData = (const char **) palloc0(naffix * sizeof(char *));
1331 Conf->lenAffixData = Conf->nAffixData = naffix;
1332
1333 /* Add empty flag set into AffixData */
1334 Conf->AffixData[curaffix] = VoidString;
1335 curaffix++;
1336 }
1337 /* Other lines are aliases */
1338 else
1339 {
1340 if (curaffix < naffix)
1341 {
1342 Conf->AffixData[curaffix] = cpstrdup(Conf, sflag);
1343 curaffix++;
1344 }
1345 else
1346 ereport(ERROR,
1347 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1348 errmsg("number of aliases exceeds specified number %d",
1349 naffix - 1)));
1350 }
1351 goto nextline;
1352 }
1353 /* Else try to parse prefixes and suffixes */
1354 if (fields_read < 4 ||
1355 (STRNCMP(ptype, "sfx") != 0 && STRNCMP(ptype, "pfx") != 0))
1356 goto nextline;
1357
1358 sflaglen = strlen(sflag);
1359 if (sflaglen == 0
1360 || (sflaglen > 1 && Conf->flagMode == FM_CHAR)
1361 || (sflaglen > 2 && Conf->flagMode == FM_LONG))
1362 goto nextline;
1363
1364 /*--------
1365 * Affix header. For example:
1366 * SFX \ N 1
1367 *--------
1368 */
1369 if (fields_read == 4)
1370 {
1371 isSuffix = (STRNCMP(ptype, "sfx") == 0);
1372 if (t_iseq(find, 'y') || t_iseq(find, 'Y'))
1373 flagflags = FF_CROSSPRODUCT;
1374 else
1375 flagflags = 0;
1376 }
1377 /*--------
1378 * Affix fields. For example:
1379 * SFX \ 0 Y/L [^Y]
1380 *--------
1381 */
1382 else
1383 {
1384 char *ptr;
1385 int aflg = 0;
1386
1387 /* Get flags after '/' (flags are case sensitive) */
1388 if ((ptr = strchr(repl, '/')) != NULL)
1389 aflg |= getCompoundAffixFlagValue(Conf,
1390 getAffixFlagSet(Conf,
1391 ptr + 1));
1392 /* Get lowercased version of string before '/' */
1393 prepl = lowerstr_ctx(Conf, repl);
1394 if ((ptr = strchr(prepl, '/')) != NULL)
1395 *ptr = '\0';
1396 pfind = lowerstr_ctx(Conf, find);
1397 pmask = lowerstr_ctx(Conf, mask);
1398 if (t_iseq(find, '0'))
1399 *pfind = '\0';
1400 if (t_iseq(repl, '0'))
1401 *prepl = '\0';
1402
1403 NIAddAffix(Conf, sflag, flagflags | aflg, pmask, pfind, prepl,
1404 isSuffix ? FF_SUFFIX : FF_PREFIX);
1405 pfree(prepl);
1406 pfree(pfind);
1407 pfree(pmask);
1408 }
1409
1410nextline:
1411 pfree(recoded);
1412 }
1413
1414 tsearch_readline_end(&trst);
1415 if (ptype)
1416 pfree(ptype);
1417}
#define qsort(a, b, c, d)
Definition: port.h:475
static int parse_ooaffentry(char *str, char *type, char *flag, char *find, char *repl, char *mask)
Definition: spell.c:859
static const char * getAffixFlagSet(IspellDict *Conf, char *s)
Definition: spell.c:1162

References addCompoundAffixFlagValue(), IspellDict::AffixData, cmpcmdflag(), IspellDict::CompoundAffixFlags, cpstrdup(), ereport, errcode(), errmsg(), ERROR, FF_COMPOUNDBEGIN, FF_COMPOUNDFLAG, FF_COMPOUNDFORBIDFLAG, FF_COMPOUNDLAST, FF_COMPOUNDMIDDLE, FF_COMPOUNDONLY, FF_COMPOUNDPERMITFLAG, FF_CROSSPRODUCT, FF_PREFIX, FF_SUFFIX, filename, find(), IspellDict::flagMode, FM_CHAR, FM_LONG, FM_NUM, getAffixFlagSet(), getCompoundAffixFlagValue(), IspellDict::lenAffixData, lowerstr_ctx(), IspellDict::nAffixData, IspellDict::nCompoundAffixFlag, NIAddAffix(), palloc0(), parse_ooaffentry(), pfree(), pg_mblen(), qsort, STRNCMP, t_iseq, tsearch_readline(), tsearch_readline_begin(), tsearch_readline_end(), type, IspellDict::usecompound, IspellDict::useFlagAliases, and VoidString.

Referenced by NIImportAffixes().

◆ NINormalizeWord()

TSLexeme * NINormalizeWord ( IspellDict Conf,
const char *  word 
)

Definition at line 2545 of file spell.c.

2546{
2547 char **res;
2548 TSLexeme *lcur = NULL,
2549 *lres = NULL;
2550 uint16 NVariant = 1;
2551
2552 res = NormalizeSubWord(Conf, word, 0);
2553
2554 if (res)
2555 {
2556 char **ptr = res;
2557
2558 while (*ptr && (lcur - lres) < MAX_NORM)
2559 {
2560 addNorm(&lres, &lcur, *ptr, 0, NVariant++);
2561 ptr++;
2562 }
2563 pfree(res);
2564 }
2565
2566 if (Conf->usecompound)
2567 {
2568 int wordlen = strlen(word);
2569 SplitVar *ptr,
2570 *var = SplitToVariants(Conf, NULL, NULL, word, wordlen, 0, -1);
2571 int i;
2572
2573 while (var)
2574 {
2575 if (var->nstem > 1)
2576 {
2577 char **subres = NormalizeSubWord(Conf, var->stem[var->nstem - 1], FF_COMPOUNDLAST);
2578
2579 if (subres)
2580 {
2581 char **subptr = subres;
2582
2583 while (*subptr)
2584 {
2585 for (i = 0; i < var->nstem - 1; i++)
2586 {
2587 addNorm(&lres, &lcur, (subptr == subres) ? var->stem[i] : pstrdup(var->stem[i]), 0, NVariant);
2588 }
2589
2590 addNorm(&lres, &lcur, *subptr, 0, NVariant);
2591 subptr++;
2592 NVariant++;
2593 }
2594
2595 pfree(subres);
2596 var->stem[0] = NULL;
2597 pfree(var->stem[var->nstem - 1]);
2598 }
2599 }
2600
2601 for (i = 0; i < var->nstem && var->stem[i]; i++)
2602 pfree(var->stem[i]);
2603 ptr = var->next;
2604 pfree(var->stem);
2605 pfree(var);
2606 var = ptr;
2607 }
2608 }
2609
2610 return lres;
2611}
uint16_t uint16
Definition: c.h:501
static void addNorm(TSLexeme **lres, TSLexeme **lcur, char *word, int flags, uint16 NVariant)
Definition: spell.c:2529
static char ** NormalizeSubWord(IspellDict *Conf, const char *word, int flag)
Definition: spell.c:2181
static SplitVar * SplitToVariants(IspellDict *Conf, SPNode *snode, SplitVar *orig, const char *word, int wordlen, int startpos, int minpos)
Definition: spell.c:2379

References addNorm(), FF_COMPOUNDLAST, i, MAX_NORM, SplitVar::next, NormalizeSubWord(), SplitVar::nstem, pfree(), pstrdup(), SplitToVariants(), SplitVar::stem, IspellDict::usecompound, and word().

Referenced by dispell_lexize().

◆ NISortAffixes()

void NISortAffixes ( IspellDict Conf)

Definition at line 1981 of file spell.c.

1982{
1983 AFFIX *Affix;
1984 size_t i;
1985 CMPDAffix *ptr;
1986 int firstsuffix = Conf->naffixes;
1987
1988 if (Conf->naffixes == 0)
1989 return;
1990
1991 /* Store compound affixes in the Conf->CompoundAffix array */
1992 if (Conf->naffixes > 1)
1993 qsort(Conf->Affix, Conf->naffixes, sizeof(AFFIX), cmpaffix);
1994 Conf->CompoundAffix = ptr = (CMPDAffix *) palloc(sizeof(CMPDAffix) * Conf->naffixes);
1995 ptr->affix = NULL;
1996
1997 for (i = 0; i < Conf->naffixes; i++)
1998 {
1999 Affix = &(((AFFIX *) Conf->Affix)[i]);
2000 if (Affix->type == FF_SUFFIX && i < firstsuffix)
2001 firstsuffix = i;
2002
2003 if ((Affix->flagflags & FF_COMPOUNDFLAG) && Affix->replen > 0 &&
2004 isAffixInUse(Conf, Affix->flag))
2005 {
2006 bool issuffix = (Affix->type == FF_SUFFIX);
2007
2008 if (ptr == Conf->CompoundAffix ||
2009 issuffix != (ptr - 1)->issuffix ||
2010 strbncmp((const unsigned char *) (ptr - 1)->affix,
2011 (const unsigned char *) Affix->repl,
2012 (ptr - 1)->len))
2013 {
2014 /* leave only unique and minimal suffixes */
2015 ptr->affix = Affix->repl;
2016 ptr->len = Affix->replen;
2017 ptr->issuffix = issuffix;
2018 ptr++;
2019 }
2020 }
2021 }
2022 ptr->affix = NULL;
2023 Conf->CompoundAffix = (CMPDAffix *) repalloc(Conf->CompoundAffix, sizeof(CMPDAffix) * (ptr - Conf->CompoundAffix + 1));
2024
2025 /* Start build a prefix tree */
2026 Conf->Prefix = mkANode(Conf, 0, firstsuffix, 0, FF_PREFIX);
2027 Conf->Suffix = mkANode(Conf, firstsuffix, Conf->naffixes, 0, FF_SUFFIX);
2028 mkVoidAffix(Conf, true, firstsuffix);
2029 mkVoidAffix(Conf, false, firstsuffix);
2030}
static int strbncmp(const unsigned char *s1, const unsigned char *s2, size_t count)
Definition: spell.c:281
static void mkVoidAffix(IspellDict *Conf, bool issuffix, int startsuffix)
Definition: spell.c:1912
static bool isAffixInUse(IspellDict *Conf, const char *affixflag)
Definition: spell.c:1966
static int cmpaffix(const void *s1, const void *s2)
Definition: spell.c:312
int len
Definition: spell.h:150
bool issuffix
Definition: spell.h:151
const char * affix
Definition: spell.h:149
CMPDAffix * CompoundAffix
Definition: spell.h:200

References CMPDAffix::affix, IspellDict::Affix, cmpaffix(), IspellDict::CompoundAffix, FF_COMPOUNDFLAG, FF_PREFIX, FF_SUFFIX, aff_struct::flag, aff_struct::flagflags, i, isAffixInUse(), CMPDAffix::issuffix, CMPDAffix::len, mkANode(), mkVoidAffix(), IspellDict::naffixes, palloc(), IspellDict::Prefix, qsort, repalloc(), aff_struct::repl, aff_struct::replen, strbncmp(), IspellDict::Suffix, and aff_struct::type.

Referenced by dispell_init().

◆ NISortDictionary()

void NISortDictionary ( IspellDict Conf)

Definition at line 1726 of file spell.c.

1727{
1728 int i;
1729 int naffix;
1730 int curaffix;
1731
1732 /* compress affixes */
1733
1734 /*
1735 * If we use flag aliases then we need to use Conf->AffixData filled in
1736 * the NIImportOOAffixes().
1737 */
1738 if (Conf->useFlagAliases)
1739 {
1740 for (i = 0; i < Conf->nspell; i++)
1741 {
1742 char *end;
1743
1744 if (*Conf->Spell[i]->p.flag != '\0')
1745 {
1746 errno = 0;
1747 curaffix = strtol(Conf->Spell[i]->p.flag, &end, 10);
1748 if (Conf->Spell[i]->p.flag == end || errno == ERANGE)
1749 ereport(ERROR,
1750 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1751 errmsg("invalid affix alias \"%s\"",
1752 Conf->Spell[i]->p.flag)));
1753 if (curaffix < 0 || curaffix >= Conf->nAffixData)
1754 ereport(ERROR,
1755 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1756 errmsg("invalid affix alias \"%s\"",
1757 Conf->Spell[i]->p.flag)));
1758 if (*end != '\0' && !isdigit((unsigned char) *end) && !isspace((unsigned char) *end))
1759 ereport(ERROR,
1760 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1761 errmsg("invalid affix alias \"%s\"",
1762 Conf->Spell[i]->p.flag)));
1763 }
1764 else
1765 {
1766 /*
1767 * If Conf->Spell[i]->p.flag is empty, then get empty value of
1768 * Conf->AffixData (0 index).
1769 */
1770 curaffix = 0;
1771 }
1772
1773 Conf->Spell[i]->p.d.affix = curaffix;
1774 Conf->Spell[i]->p.d.len = strlen(Conf->Spell[i]->word);
1775 }
1776 }
1777 /* Otherwise fill Conf->AffixData here */
1778 else
1779 {
1780 /* Count the number of different flags used in the dictionary */
1781 qsort(Conf->Spell, Conf->nspell, sizeof(SPELL *),
1783
1784 naffix = 0;
1785 for (i = 0; i < Conf->nspell; i++)
1786 {
1787 if (i == 0 ||
1788 strcmp(Conf->Spell[i]->p.flag, Conf->Spell[i - 1]->p.flag) != 0)
1789 naffix++;
1790 }
1791
1792 /*
1793 * Fill in Conf->AffixData with the affixes that were used in the
1794 * dictionary. Replace textual flag-field of Conf->Spell entries with
1795 * indexes into Conf->AffixData array.
1796 */
1797 Conf->AffixData = (const char **) palloc0(naffix * sizeof(const char *));
1798
1799 curaffix = -1;
1800 for (i = 0; i < Conf->nspell; i++)
1801 {
1802 if (i == 0 ||
1803 strcmp(Conf->Spell[i]->p.flag, Conf->AffixData[curaffix]) != 0)
1804 {
1805 curaffix++;
1806 Assert(curaffix < naffix);
1807 Conf->AffixData[curaffix] = cpstrdup(Conf,
1808 Conf->Spell[i]->p.flag);
1809 }
1810
1811 Conf->Spell[i]->p.d.affix = curaffix;
1812 Conf->Spell[i]->p.d.len = strlen(Conf->Spell[i]->word);
1813 }
1814
1815 Conf->lenAffixData = Conf->nAffixData = naffix;
1816 }
1817
1818 /* Start build a prefix tree */
1819 qsort(Conf->Spell, Conf->nspell, sizeof(SPELL *), cmpspell);
1820 Conf->Dictionary = mkSPNode(Conf, 0, Conf->nspell, 0);
1821}
static int cmpspell(const void *s1, const void *s2)
Definition: spell.c:198
static int cmpspellaffix(const void *s1, const void *s2)
Definition: spell.c:204

References spell_struct::affix, IspellDict::AffixData, Assert(), cmpspell(), cmpspellaffix(), cpstrdup(), spell_struct::d, IspellDict::Dictionary, ereport, errcode(), errmsg(), ERROR, spell_struct::flag, i, spell_struct::len, IspellDict::lenAffixData, mkSPNode(), IspellDict::nAffixData, IspellDict::nspell, spell_struct::p, palloc0(), qsort, IspellDict::Spell, IspellDict::useFlagAliases, and spell_struct::word.

Referenced by dispell_init().

◆ NIStartBuild()

void NIStartBuild ( IspellDict Conf)

Definition at line 89 of file spell.c.

90{
91 /*
92 * The temp context is a child of CurTransactionContext, so that it will
93 * go away automatically on error.
94 */
96 "Ispell dictionary init context",
98}
MemoryContext CurTransactionContext
Definition: mcxt.c:155
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, IspellDict::buildCxt, and CurTransactionContext.

Referenced by dispell_init().

◆ NormalizeSubWord()

static char ** NormalizeSubWord ( IspellDict Conf,
const char *  word,
int  flag 
)
static

Definition at line 2181 of file spell.c.

2182{
2183 AffixNodeData *suffix = NULL,
2184 *prefix = NULL;
2185 int slevel = 0,
2186 plevel = 0;
2187 int wrdlen = strlen(word),
2188 swrdlen;
2189 char **forms;
2190 char **cur;
2191 char newword[2 * MAXNORMLEN] = "";
2192 char pnewword[2 * MAXNORMLEN] = "";
2193 AffixNode *snode = Conf->Suffix,
2194 *pnode;
2195 int i,
2196 j;
2197
2198 if (wrdlen > MAXNORMLEN)
2199 return NULL;
2200 cur = forms = (char **) palloc(MAX_NORM * sizeof(char *));
2201 *cur = NULL;
2202
2203
2204 /* Check that the word itself is normal form */
2205 if (FindWord(Conf, word, VoidString, flag))
2206 {
2207 *cur = pstrdup(word);
2208 cur++;
2209 *cur = NULL;
2210 }
2211
2212 /* Find all other NORMAL forms of the 'word' (check only prefix) */
2213 pnode = Conf->Prefix;
2214 plevel = 0;
2215 while (pnode)
2216 {
2217 prefix = FindAffixes(pnode, word, wrdlen, &plevel, FF_PREFIX);
2218 if (!prefix)
2219 break;
2220 for (j = 0; j < prefix->naff; j++)
2221 {
2222 if (CheckAffix(word, wrdlen, prefix->aff[j], flag, newword, NULL))
2223 {
2224 /* prefix success */
2225 if (FindWord(Conf, newword, prefix->aff[j]->flag, flag))
2226 cur += addToResult(forms, cur, newword);
2227 }
2228 }
2229 pnode = prefix->node;
2230 }
2231
2232 /*
2233 * Find all other NORMAL forms of the 'word' (check suffix and then
2234 * prefix)
2235 */
2236 while (snode)
2237 {
2238 int baselen = 0;
2239
2240 /* find possible suffix */
2241 suffix = FindAffixes(snode, word, wrdlen, &slevel, FF_SUFFIX);
2242 if (!suffix)
2243 break;
2244 /* foreach suffix check affix */
2245 for (i = 0; i < suffix->naff; i++)
2246 {
2247 if (CheckAffix(word, wrdlen, suffix->aff[i], flag, newword, &baselen))
2248 {
2249 /* suffix success */
2250 if (FindWord(Conf, newword, suffix->aff[i]->flag, flag))
2251 cur += addToResult(forms, cur, newword);
2252
2253 /* now we will look changed word with prefixes */
2254 pnode = Conf->Prefix;
2255 plevel = 0;
2256 swrdlen = strlen(newword);
2257 while (pnode)
2258 {
2259 prefix = FindAffixes(pnode, newword, swrdlen, &plevel, FF_PREFIX);
2260 if (!prefix)
2261 break;
2262 for (j = 0; j < prefix->naff; j++)
2263 {
2264 if (CheckAffix(newword, swrdlen, prefix->aff[j], flag, pnewword, &baselen))
2265 {
2266 /* prefix success */
2267 const char *ff = (prefix->aff[j]->flagflags & suffix->aff[i]->flagflags & FF_CROSSPRODUCT) ?
2268 VoidString : prefix->aff[j]->flag;
2269
2270 if (FindWord(Conf, pnewword, ff, flag))
2271 cur += addToResult(forms, cur, pnewword);
2272 }
2273 }
2274 pnode = prefix->node;
2275 }
2276 }
2277 }
2278
2279 snode = suffix->node;
2280 }
2281
2282 if (cur == forms)
2283 {
2284 pfree(forms);
2285 return NULL;
2286 }
2287 return forms;
2288}
int j
Definition: isn.c:75
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:78
static int FindWord(IspellDict *Conf, const char *word, const char *affixflag, int flag)
Definition: spell.c:604
static AffixNodeData * FindAffixes(AffixNode *node, const char *word, int wrdlen, int *level, int type)
Definition: spell.c:2033
static char * CheckAffix(const char *word, size_t len, AFFIX *Affix, int flagflags, char *newword, int *baselen)
Definition: spell.c:2076
#define MAXNORMLEN
Definition: spell.c:189
static int addToResult(char **forms, char **cur, char *word)
Definition: spell.c:2166

References addToResult(), AffixNodeData::aff, CheckAffix(), cur, FF_CROSSPRODUCT, FF_PREFIX, FF_SUFFIX, FindAffixes(), FindWord(), aff_struct::flag, flag(), aff_struct::flagflags, i, if(), j, MAX_NORM, MAXNORMLEN, AffixNodeData::naff, AffixNodeData::node, palloc(), pfree(), IspellDict::Prefix, pstrdup(), IspellDict::Suffix, VoidString, and word().

Referenced by NINormalizeWord(), and SplitToVariants().

◆ parse_affentry()

static bool parse_affentry ( char *  str,
char *  mask,
char *  find,
char *  repl 
)
static

Definition at line 915 of file spell.c.

916{
917 int state = PAE_WAIT_MASK;
918 char *pmask = mask,
919 *pfind = find,
920 *prepl = repl;
921
922 *mask = *find = *repl = '\0';
923
924 while (*str)
925 {
926 if (state == PAE_WAIT_MASK)
927 {
928 if (t_iseq(str, '#'))
929 return false;
930 else if (!isspace((unsigned char) *str))
931 {
932 COPYCHAR(pmask, str);
933 pmask += pg_mblen(str);
935 }
936 }
937 else if (state == PAE_INMASK)
938 {
939 if (t_iseq(str, '>'))
940 {
941 *pmask = '\0';
943 }
944 else if (!isspace((unsigned char) *str))
945 {
946 COPYCHAR(pmask, str);
947 pmask += pg_mblen(str);
948 }
949 }
950 else if (state == PAE_WAIT_FIND)
951 {
952 if (t_iseq(str, '-'))
953 {
955 }
956 else if (t_isalpha(str) || t_iseq(str, '\'') /* english 's */ )
957 {
958 COPYCHAR(prepl, str);
959 prepl += pg_mblen(str);
961 }
962 else if (!isspace((unsigned char) *str))
964 (errcode(ERRCODE_CONFIG_FILE_ERROR),
965 errmsg("syntax error")));
966 }
967 else if (state == PAE_INFIND)
968 {
969 if (t_iseq(str, ','))
970 {
971 *pfind = '\0';
973 }
974 else if (t_isalpha(str))
975 {
976 COPYCHAR(pfind, str);
977 pfind += pg_mblen(str);
978 }
979 else if (!isspace((unsigned char) *str))
981 (errcode(ERRCODE_CONFIG_FILE_ERROR),
982 errmsg("syntax error")));
983 }
984 else if (state == PAE_WAIT_REPL)
985 {
986 if (t_iseq(str, '-'))
987 {
988 break; /* void repl */
989 }
990 else if (t_isalpha(str))
991 {
992 COPYCHAR(prepl, str);
993 prepl += pg_mblen(str);
995 }
996 else if (!isspace((unsigned char) *str))
998 (errcode(ERRCODE_CONFIG_FILE_ERROR),
999 errmsg("syntax error")));
1000 }
1001 else if (state == PAE_INREPL)
1002 {
1003 if (t_iseq(str, '#'))
1004 {
1005 *prepl = '\0';
1006 break;
1007 }
1008 else if (t_isalpha(str))
1009 {
1010 COPYCHAR(prepl, str);
1011 prepl += pg_mblen(str);
1012 }
1013 else if (!isspace((unsigned char) *str))
1014 ereport(ERROR,
1015 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1016 errmsg("syntax error")));
1017 }
1018 else
1019 elog(ERROR, "unrecognized state in parse_affentry: %d", state);
1020
1021 str += pg_mblen(str);
1022 }
1023
1024 *pmask = *pfind = *prepl = '\0';
1025
1026 return (*mask && (*find || *repl));
1027}
#define PAE_WAIT_REPL
Definition: spell.c:777
#define PAE_INREPL
Definition: spell.c:778
#define PAE_WAIT_FIND
Definition: spell.c:775
#define PAE_INFIND
Definition: spell.c:776
int t_isalpha(const char *ptr)
Definition: ts_locale.c:35

References COPYCHAR, elog, ereport, errcode(), errmsg(), ERROR, find(), PAE_INFIND, PAE_INMASK, PAE_INREPL, PAE_WAIT_FIND, PAE_WAIT_MASK, PAE_WAIT_REPL, pg_mblen(), str, t_isalpha(), and t_iseq.

Referenced by NIImportAffixes().

◆ parse_ooaffentry()

static int parse_ooaffentry ( char *  str,
char *  type,
char *  flag,
char *  find,
char *  repl,
char *  mask 
)
static

Definition at line 859 of file spell.c.

861{
862 int state = PAE_WAIT_TYPE;
863 int fields_read = 0;
864 bool valid = false;
865
866 *type = *flag = *find = *repl = *mask = '\0';
867
868 while (*str)
869 {
870 switch (state)
871 {
872 case PAE_WAIT_TYPE:
873 valid = get_nextfield(&str, type);
875 break;
876 case PAE_WAIT_FLAG:
877 valid = get_nextfield(&str, flag);
879 break;
880 case PAE_WAIT_FIND:
881 valid = get_nextfield(&str, find);
883 break;
884 case PAE_WAIT_REPL:
885 valid = get_nextfield(&str, repl);
887 break;
888 case PAE_WAIT_MASK:
889 valid = get_nextfield(&str, mask);
890 state = -1; /* force loop exit */
891 break;
892 default:
893 elog(ERROR, "unrecognized state in parse_ooaffentry: %d",
894 state);
895 break;
896 }
897 if (valid)
898 fields_read++;
899 else
900 break; /* early EOL */
901 if (state < 0)
902 break; /* got all fields */
903 }
904
905 return fields_read;
906}
static bool get_nextfield(char **str, char *next)
Definition: spell.c:793
#define PAE_WAIT_FLAG
Definition: spell.c:780
#define PAE_WAIT_TYPE
Definition: spell.c:779

References elog, ERROR, find(), flag(), get_nextfield(), PAE_WAIT_FIND, PAE_WAIT_FLAG, PAE_WAIT_MASK, PAE_WAIT_REPL, PAE_WAIT_TYPE, str, and type.

Referenced by NIImportOOAffixes().

◆ setCompoundAffixFlagValue()

static void setCompoundAffixFlagValue ( IspellDict Conf,
CompoundAffixFlag entry,
char *  s,
uint32  val 
)
static

Definition at line 1033 of file spell.c.

1035{
1036 if (Conf->flagMode == FM_NUM)
1037 {
1038 char *next;
1039 int i;
1040
1041 errno = 0;
1042 i = strtol(s, &next, 10);
1043 if (s == next || errno == ERANGE)
1044 ereport(ERROR,
1045 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1046 errmsg("invalid affix flag \"%s\"", s)));
1047 if (i < 0 || i > FLAGNUM_MAXSIZE)
1048 ereport(ERROR,
1049 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1050 errmsg("affix flag \"%s\" is out of range", s)));
1051
1052 entry->flag.i = i;
1053 }
1054 else
1055 entry->flag.s = cpstrdup(Conf, s);
1056
1057 entry->flagMode = Conf->flagMode;
1058 entry->value = val;
1059}

References cpstrdup(), ereport, errcode(), errmsg(), ERROR, CompoundAffixFlag::flag, CompoundAffixFlag::flagMode, IspellDict::flagMode, FLAGNUM_MAXSIZE, FM_NUM, i, CompoundAffixFlag::i, next, CompoundAffixFlag::s, val, and CompoundAffixFlag::value.

Referenced by addCompoundAffixFlagValue(), and getCompoundAffixFlagValue().

◆ SplitToVariants()

static SplitVar * SplitToVariants ( IspellDict Conf,
SPNode snode,
SplitVar orig,
const char *  word,
int  wordlen,
int  startpos,
int  minpos 
)
static

Definition at line 2379 of file spell.c.

2380{
2381 SplitVar *var = NULL;
2382 SPNodeData *StopLow,
2383 *StopHigh,
2384 *StopMiddle = NULL;
2385 SPNode *node = (snode) ? snode : Conf->Dictionary;
2386 int level = (snode) ? minpos : startpos; /* recursive
2387 * minpos==level */
2388 int lenaff;
2389 CMPDAffix *caff;
2390 char *notprobed;
2391 int compoundflag = 0;
2392
2393 /* since this function recurses, it could be driven to stack overflow */
2395
2396 notprobed = (char *) palloc(wordlen);
2397 memset(notprobed, 1, wordlen);
2398 var = CopyVar(orig, 1);
2399
2400 while (level < wordlen)
2401 {
2402 /* find word with epenthetic or/and compound affix */
2403 caff = Conf->CompoundAffix;
2404 while (level > startpos && (lenaff = CheckCompoundAffixes(&caff, word + level, wordlen - level, (node) ? true : false)) >= 0)
2405 {
2406 /*
2407 * there is one of compound affixes, so check word for existings
2408 */
2409 char buf[MAXNORMLEN];
2410 char **subres;
2411
2412 lenaff = level - startpos + lenaff;
2413
2414 if (!notprobed[startpos + lenaff - 1])
2415 continue;
2416
2417 if (level + lenaff - 1 <= minpos)
2418 continue;
2419
2420 if (lenaff >= MAXNORMLEN)
2421 continue; /* skip too big value */
2422 if (lenaff > 0)
2423 memcpy(buf, word + startpos, lenaff);
2424 buf[lenaff] = '\0';
2425
2426 if (level == 0)
2427 compoundflag = FF_COMPOUNDBEGIN;
2428 else if (level == wordlen - 1)
2429 compoundflag = FF_COMPOUNDLAST;
2430 else
2431 compoundflag = FF_COMPOUNDMIDDLE;
2432 subres = NormalizeSubWord(Conf, buf, compoundflag);
2433 if (subres)
2434 {
2435 /* Yes, it was a word from dictionary */
2436 SplitVar *new = CopyVar(var, 0);
2437 SplitVar *ptr = var;
2438 char **sptr = subres;
2439
2440 notprobed[startpos + lenaff - 1] = 0;
2441
2442 while (*sptr)
2443 {
2444 AddStem(new, *sptr);
2445 sptr++;
2446 }
2447 pfree(subres);
2448
2449 while (ptr->next)
2450 ptr = ptr->next;
2451 ptr->next = SplitToVariants(Conf, NULL, new, word, wordlen, startpos + lenaff, startpos + lenaff);
2452
2453 pfree(new->stem);
2454 pfree(new);
2455 }
2456 }
2457
2458 if (!node)
2459 break;
2460
2461 StopLow = node->data;
2462 StopHigh = node->data + node->length;
2463 while (StopLow < StopHigh)
2464 {
2465 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
2466 if (StopMiddle->val == ((uint8 *) (word))[level])
2467 break;
2468 else if (StopMiddle->val < ((uint8 *) (word))[level])
2469 StopLow = StopMiddle + 1;
2470 else
2471 StopHigh = StopMiddle;
2472 }
2473
2474 if (StopLow < StopHigh)
2475 {
2476 if (startpos == 0)
2477 compoundflag = FF_COMPOUNDBEGIN;
2478 else if (level == wordlen - 1)
2479 compoundflag = FF_COMPOUNDLAST;
2480 else
2481 compoundflag = FF_COMPOUNDMIDDLE;
2482
2483 /* find infinitive */
2484 if (StopMiddle->isword &&
2485 (StopMiddle->compoundflag & compoundflag) &&
2486 notprobed[level])
2487 {
2488 /* ok, we found full compoundallowed word */
2489 if (level > minpos)
2490 {
2491 /* and its length more than minimal */
2492 if (wordlen == level + 1)
2493 {
2494 /* well, it was last word */
2495 AddStem(var, pnstrdup(word + startpos, wordlen - startpos));
2496 pfree(notprobed);
2497 return var;
2498 }
2499 else
2500 {
2501 /* then we will search more big word at the same point */
2502 SplitVar *ptr = var;
2503
2504 while (ptr->next)
2505 ptr = ptr->next;
2506 ptr->next = SplitToVariants(Conf, node, var, word, wordlen, startpos, level);
2507 /* we can find next word */
2508 level++;
2509 AddStem(var, pnstrdup(word + startpos, level - startpos));
2510 node = Conf->Dictionary;
2511 startpos = level;
2512 continue;
2513 }
2514 }
2515 }
2516 node = StopMiddle->node;
2517 }
2518 else
2519 node = NULL;
2520 level++;
2521 }
2522
2523 AddStem(var, pnstrdup(word + startpos, wordlen - startpos));
2524 pfree(notprobed);
2525 return var;
2526}
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1710
static XLogRecPtr startpos
static char * buf
Definition: pg_test_fsync.c:72
static SplitVar * CopyVar(SplitVar *s, int makedup)
Definition: spell.c:2341
static int CheckCompoundAffixes(CMPDAffix **ptr, const char *word, int len, bool CheckInPlace)
Definition: spell.c:2299
static void AddStem(SplitVar *v, char *word)
Definition: spell.c:2366
void check_stack_depth(void)
Definition: stack_depth.c:95

References AddStem(), buf, check_stack_depth(), CheckCompoundAffixes(), IspellDict::CompoundAffix, SPNodeData::compoundflag, CopyVar(), SPNode::data, IspellDict::Dictionary, FF_COMPOUNDBEGIN, FF_COMPOUNDLAST, FF_COMPOUNDMIDDLE, SPNodeData::isword, SPNode::length, MAXNORMLEN, SplitVar::next, SPNodeData::node, NormalizeSubWord(), palloc(), pfree(), pnstrdup(), SplitToVariants(), startpos, SPNodeData::val, and word().

Referenced by NINormalizeWord(), and SplitToVariants().

◆ strbcmp()

static int strbcmp ( const unsigned char *  s1,
const unsigned char *  s2 
)
static

Definition at line 258 of file spell.c.

259{
260 int l1 = strlen((const char *) s1) - 1,
261 l2 = strlen((const char *) s2) - 1;
262
263 while (l1 >= 0 && l2 >= 0)
264 {
265 if (s1[l1] < s2[l2])
266 return -1;
267 if (s1[l1] > s2[l2])
268 return 1;
269 l1--;
270 l2--;
271 }
272 if (l1 < l2)
273 return -1;
274 if (l1 > l2)
275 return 1;
276
277 return 0;
278}

References s1, and s2.

Referenced by cmpaffix().

◆ strbncmp()

static int strbncmp ( const unsigned char *  s1,
const unsigned char *  s2,
size_t  count 
)
static

Definition at line 281 of file spell.c.

282{
283 int l1 = strlen((const char *) s1) - 1,
284 l2 = strlen((const char *) s2) - 1,
285 l = count;
286
287 while (l1 >= 0 && l2 >= 0 && l > 0)
288 {
289 if (s1[l1] < s2[l2])
290 return -1;
291 if (s1[l1] > s2[l2])
292 return 1;
293 l1--;
294 l2--;
295 l--;
296 }
297 if (l == 0)
298 return 0;
299 if (l1 < l2)
300 return -1;
301 if (l1 > l2)
302 return 1;
303 return 0;
304}

References s1, and s2.

Referenced by NISortAffixes().

Variable Documentation

◆ VoidString

const char* VoidString = ""
static

Definition at line 195 of file spell.c.

Referenced by getAffixFlagSet(), NIAddAffix(), NIAddSpell(), NIImportOOAffixes(), and NormalizeSubWord().