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/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, 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 regex_affix_deletion_callback (void *arg)
 
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, char *s)
 
static 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, 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, char *word, int flag)
 
static int CheckCompoundAffixes (CMPDAffix **ptr, 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, char *word, int wordlen, int startpos, int minpos)
 
static void addNorm (TSLexeme **lres, TSLexeme **lcur, char *word, int flags, uint16 NVariant)
 
TSLexemeNINormalizeWord (IspellDict *Conf, char *word)
 

Variables

static char * VoidString = ""
 

Macro Definition Documentation

◆ COMPACT_ALLOC_CHUNK

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

Definition at line 126 of file spell.c.

◆ COMPACT_MAX_REQ

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

Definition at line 127 of file spell.c.

◆ cpalloc

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

Definition at line 158 of file spell.c.

◆ cpalloc0

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

Definition at line 159 of file spell.c.

◆ GETCHAR

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

Definition at line 192 of file spell.c.

◆ GETWCHAR

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

Definition at line 191 of file spell.c.

◆ MAX_NORM

#define MAX_NORM   1024

Definition at line 187 of file spell.c.

◆ MAXNORMLEN

#define MAXNORMLEN   256

Definition at line 188 of file spell.c.

◆ PAE_INFIND

#define PAE_INFIND   3

Definition at line 794 of file spell.c.

◆ PAE_INMASK

#define PAE_INMASK   1

Definition at line 792 of file spell.c.

◆ PAE_INREPL

#define PAE_INREPL   5

Definition at line 796 of file spell.c.

◆ PAE_WAIT_FIND

#define PAE_WAIT_FIND   2

Definition at line 793 of file spell.c.

◆ PAE_WAIT_FLAG

#define PAE_WAIT_FLAG   7

Definition at line 798 of file spell.c.

◆ PAE_WAIT_MASK

#define PAE_WAIT_MASK   0

Definition at line 791 of file spell.c.

◆ PAE_WAIT_REPL

#define PAE_WAIT_REPL   4

Definition at line 795 of file spell.c.

◆ PAE_WAIT_TYPE

#define PAE_WAIT_TYPE   6

Definition at line 797 of file spell.c.

◆ STRNCMP

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

Definition at line 190 of file spell.c.

◆ tmpalloc

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

Definition at line 79 of file spell.c.

◆ tmpalloc0

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

Definition at line 80 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 1086 of file spell.c.

1087 {
1088  CompoundAffixFlag *newValue;
1089  char sbuf[BUFSIZ];
1090  char *sflag;
1091  int clen;
1092 
1093  while (*s && t_isspace(s))
1094  s += pg_mblen(s);
1095 
1096  if (!*s)
1097  ereport(ERROR,
1098  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1099  errmsg("syntax error")));
1100 
1101  /* Get flag without \n */
1102  sflag = sbuf;
1103  while (*s && !t_isspace(s) && *s != '\n')
1104  {
1105  clen = pg_mblen(s);
1106  COPYCHAR(sflag, s);
1107  sflag += clen;
1108  s += clen;
1109  }
1110  *sflag = '\0';
1111 
1112  /* Resize array or allocate memory for array CompoundAffixFlag */
1113  if (Conf->nCompoundAffixFlag >= Conf->mCompoundAffixFlag)
1114  {
1115  if (Conf->mCompoundAffixFlag)
1116  {
1117  Conf->mCompoundAffixFlag *= 2;
1119  repalloc((void *) Conf->CompoundAffixFlags,
1120  Conf->mCompoundAffixFlag * sizeof(CompoundAffixFlag));
1121  }
1122  else
1123  {
1124  Conf->mCompoundAffixFlag = 10;
1127  }
1128  }
1129 
1130  newValue = Conf->CompoundAffixFlags + Conf->nCompoundAffixFlag;
1131 
1132  setCompoundAffixFlagValue(Conf, newValue, sbuf, val);
1133 
1134  Conf->usecompound = true;
1135  Conf->nCompoundAffixFlag++;
1136 }
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
long val
Definition: informix.c:664
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1024
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1456
static void setCompoundAffixFlagValue(IspellDict *Conf, CompoundAffixFlag *entry, char *s, uint32 val)
Definition: spell.c:1051
#define tmpalloc(sz)
Definition: spell.c:79
struct CompoundAffixFlag CompoundAffixFlag
bool usecompound
Definition: spell.h:208
CompoundAffixFlag * CompoundAffixFlags
Definition: spell.h:216
int nCompoundAffixFlag
Definition: spell.h:218
int mCompoundAffixFlag
Definition: spell.h:220
int t_isspace(const char *ptr)
Definition: ts_locale.c:53
#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(), t_isspace(), 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 2540 of file spell.c.

2541 {
2542  if (*lres == NULL)
2543  *lcur = *lres = (TSLexeme *) palloc(MAX_NORM * sizeof(TSLexeme));
2544 
2545  if (*lcur - *lres < MAX_NORM - 1)
2546  {
2547  (*lcur)->lexeme = word;
2548  (*lcur)->flags = flags;
2549  (*lcur)->nvariant = NVariant;
2550  (*lcur)++;
2551  (*lcur)->lexeme = NULL;
2552  }
2553 }
void * palloc(Size size)
Definition: mcxt.c:1210
static void word(struct vars *v, int dir, struct state *lp, struct state *rp)
Definition: regcomp.c:1476
#define MAX_NORM
Definition: spell.c:187

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

Referenced by NINormalizeWord().

◆ AddStem()

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

Definition at line 2377 of file spell.c.

2378 {
2379  if (v->nstem >= v->lenstem)
2380  {
2381  v->lenstem *= 2;
2382  v->stem = (char **) repalloc(v->stem, sizeof(char *) * v->lenstem);
2383  }
2384 
2385  v->stem[v->nstem] = word;
2386  v->nstem++;
2387 }
int nstem
Definition: spell.c:2303
int lenstem
Definition: spell.c:2304
char ** stem
Definition: spell.c:2305

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 2177 of file spell.c.

2178 {
2179  if (cur - forms >= MAX_NORM - 1)
2180  return 0;
2181  if (forms == cur || strcmp(word, *(cur - 1)) != 0)
2182  {
2183  *cur = pstrdup(word);
2184  *(cur + 1) = NULL;
2185  return 1;
2186  }
2187 
2188  return 0;
2189 }
struct cursor * cur
Definition: ecpg.c:28
char * pstrdup(const char *in)
Definition: mcxt.c:1624

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 2087 of file spell.c.

2088 {
2089  /*
2090  * Check compound allow flags
2091  */
2092 
2093  if (flagflags == 0)
2094  {
2095  if (Affix->flagflags & FF_COMPOUNDONLY)
2096  return NULL;
2097  }
2098  else if (flagflags & FF_COMPOUNDBEGIN)
2099  {
2100  if (Affix->flagflags & FF_COMPOUNDFORBIDFLAG)
2101  return NULL;
2102  if ((Affix->flagflags & FF_COMPOUNDBEGIN) == 0)
2103  if (Affix->type == FF_SUFFIX)
2104  return NULL;
2105  }
2106  else if (flagflags & FF_COMPOUNDMIDDLE)
2107  {
2108  if ((Affix->flagflags & FF_COMPOUNDMIDDLE) == 0 ||
2109  (Affix->flagflags & FF_COMPOUNDFORBIDFLAG))
2110  return NULL;
2111  }
2112  else if (flagflags & FF_COMPOUNDLAST)
2113  {
2114  if (Affix->flagflags & FF_COMPOUNDFORBIDFLAG)
2115  return NULL;
2116  if ((Affix->flagflags & FF_COMPOUNDLAST) == 0)
2117  if (Affix->type == FF_PREFIX)
2118  return NULL;
2119  }
2120 
2121  /*
2122  * make replace pattern of affix
2123  */
2124  if (Affix->type == FF_SUFFIX)
2125  {
2126  strcpy(newword, word);
2127  strcpy(newword + len - Affix->replen, Affix->find);
2128  if (baselen) /* store length of non-changed part of word */
2129  *baselen = len - Affix->replen;
2130  }
2131  else
2132  {
2133  /*
2134  * if prefix is an all non-changed part's length then all word
2135  * contains only prefix and suffix, so out
2136  */
2137  if (baselen && *baselen + strlen(Affix->find) <= Affix->replen)
2138  return NULL;
2139  strcpy(newword, Affix->find);
2140  strcat(newword, word + Affix->replen);
2141  }
2142 
2143  /*
2144  * check resulting word
2145  */
2146  if (Affix->issimple)
2147  return newword;
2148  else if (Affix->isregis)
2149  {
2150  if (RS_execute(&(Affix->reg.regis), newword))
2151  return newword;
2152  }
2153  else
2154  {
2155  pg_wchar *data;
2156  size_t data_len;
2157  int newword_len;
2158 
2159  /* Convert data string to wide characters */
2160  newword_len = strlen(newword);
2161  data = (pg_wchar *) palloc((newword_len + 1) * sizeof(pg_wchar));
2162  data_len = pg_mb2wchar_with_len(newword, data, newword_len);
2163 
2164  if (pg_regexec(&(Affix->reg.pregex->regex), data, data_len,
2165  0, NULL, 0, NULL, 0) == REG_OKAY)
2166  {
2167  pfree(data);
2168  return newword;
2169  }
2170  pfree(data);
2171  }
2172 
2173  return NULL;
2174 }
unsigned int pg_wchar
Definition: mbprint.c:31
int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
Definition: mbutils.c:987
void pfree(void *pointer)
Definition: mcxt.c:1436
const void size_t len
const void * data
#define REG_OKAY
Definition: regex.h:137
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:127
#define FF_PREFIX
Definition: spell.h:128
#define FF_COMPOUNDFORBIDFLAG
Definition: spell.h:120
#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
regex_t regex
Definition: spell.h:91
aff_regex_struct * pregex
Definition: spell.h:111
uint32 isregis
Definition: spell.h:105
uint32 type
Definition: spell.h:102
Regis regis
Definition: spell.h:112
uint32 replen
Definition: spell.h:106
union aff_struct::@117 reg
uint32 flagflags
Definition: spell.h:103
uint32 issimple
Definition: spell.h:104
char * find
Definition: spell.h:107

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_regex_struct::regex, aff_struct::regis, aff_struct::replen, RS_execute(), aff_struct::type, and word().

Referenced by NormalizeSubWord().

◆ CheckCompoundAffixes()

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

Definition at line 2310 of file spell.c.

2311 {
2312  bool issuffix;
2313 
2314  /* in case CompoundAffix is null: */
2315  if (*ptr == NULL)
2316  return -1;
2317 
2318  if (CheckInPlace)
2319  {
2320  while ((*ptr)->affix)
2321  {
2322  if (len > (*ptr)->len && strncmp((*ptr)->affix, word, (*ptr)->len) == 0)
2323  {
2324  len = (*ptr)->len;
2325  issuffix = (*ptr)->issuffix;
2326  (*ptr)++;
2327  return (issuffix) ? len : 0;
2328  }
2329  (*ptr)++;
2330  }
2331  }
2332  else
2333  {
2334  char *affbegin;
2335 
2336  while ((*ptr)->affix)
2337  {
2338  if (len > (*ptr)->len && (affbegin = strstr(word, (*ptr)->affix)) != NULL)
2339  {
2340  len = (*ptr)->len + (affbegin - word);
2341  issuffix = (*ptr)->issuffix;
2342  (*ptr)++;
2343  return (issuffix) ? len : 0;
2344  }
2345  (*ptr)++;
2346  }
2347  }
2348  return -1;
2349 }

References len, and word().

Referenced by SplitToVariants().

◆ cmpaffix()

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

Definition at line 311 of file spell.c.

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

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 210 of file spell.c.

211 {
213  *fv2 = (CompoundAffixFlag *) f2;
214 
215  Assert(fv1->flagMode == fv2->flagMode);
216 
217  if (fv1->flagMode == FM_NUM)
218  {
219  if (fv1->flag.i == fv2->flag.i)
220  return 0;
221 
222  return (fv1->flag.i > fv2->flag.i) ? 1 : -1;
223  }
224 
225  return strcmp(fv1->flag.s, fv2->flag.s);
226 }
Assert(fmt[strlen(fmt) - 1] !='\n')
@ FM_NUM
Definition: spell.h:167
int f1[ARRAY_SIZE]
Definition: sql-declare.c:113
int f2[ARRAY_SIZE]
Definition: sql-declare.c:116
union CompoundAffixFlag::@118 flag
FlagMode flagMode
Definition: spell.h:184

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 197 of file spell.c.

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

References s1, s2, and word().

Referenced by NISortDictionary().

◆ cmpspellaffix()

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

Definition at line 203 of file spell.c.

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

References s1, and s2.

Referenced by NISortDictionary().

◆ compact_palloc0()

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

Definition at line 130 of file spell.c.

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

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 2352 of file spell.c.

2353 {
2354  SplitVar *v = (SplitVar *) palloc(sizeof(SplitVar));
2355 
2356  v->next = NULL;
2357  if (s)
2358  {
2359  int i;
2360 
2361  v->lenstem = s->lenstem;
2362  v->stem = (char **) palloc(sizeof(char *) * v->lenstem);
2363  v->nstem = s->nstem;
2364  for (i = 0; i < s->nstem; i++)
2365  v->stem[i] = (makedup) ? pstrdup(s->stem[i]) : s->stem[i];
2366  }
2367  else
2368  {
2369  v->lenstem = 16;
2370  v->stem = (char **) palloc(sizeof(char *) * v->lenstem);
2371  v->nstem = 0;
2372  }
2373  return v;
2374 }
int i
Definition: isn.c:73
struct SplitVar * next
Definition: spell.c:2306

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 162 of file spell.c.

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

References cpalloc, res, and generate_unaccent_rules::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 2044 of file spell.c.

2045 {
2046  AffixNodeData *StopLow,
2047  *StopHigh,
2048  *StopMiddle;
2049  uint8 symbol;
2050 
2051  if (node->isvoid)
2052  { /* search void affixes */
2053  if (node->data->naff)
2054  return node->data;
2055  node = node->data->node;
2056  }
2057 
2058  while (node && *level < wrdlen)
2059  {
2060  StopLow = node->data;
2061  StopHigh = node->data + node->length;
2062  while (StopLow < StopHigh)
2063  {
2064  StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
2065  symbol = GETWCHAR(word, wrdlen, *level, type);
2066 
2067  if (StopMiddle->val == symbol)
2068  {
2069  (*level)++;
2070  if (StopMiddle->naff)
2071  return StopMiddle;
2072  node = StopMiddle->node;
2073  break;
2074  }
2075  else if (StopMiddle->val < symbol)
2076  StopLow = StopMiddle + 1;
2077  else
2078  StopHigh = StopMiddle;
2079  }
2080  if (StopLow >= StopHigh)
2081  break;
2082  }
2083  return NULL;
2084 }
unsigned char symbol
Definition: api.h:2
unsigned char uint8
Definition: c.h:488
#define GETWCHAR(W, L, N, T)
Definition: spell.c:191
uint32 naff
Definition: spell.h:139
uint32 val
Definition: spell.h:138
struct AffixNode * node
Definition: spell.h:141
uint32 isvoid
Definition: spell.h:146
AffixNodeData data[FLEXIBLE_ARRAY_MEMBER]
Definition: spell.h:148
uint32 length
Definition: spell.h:147

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

Referenced by NormalizeSubWord().

◆ findchar()

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

Definition at line 229 of file spell.c.

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

References pg_mblen(), generate_unaccent_rules::str, and t_iseq.

Referenced by NIImportDictionary().

◆ findchar2()

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

Definition at line 242 of file spell.c.

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

References pg_mblen(), generate_unaccent_rules::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 602 of file spell.c.

603 {
604  SPNode *node = Conf->Dictionary;
605  SPNodeData *StopLow,
606  *StopHigh,
607  *StopMiddle;
608  const uint8 *ptr = (const uint8 *) word;
609 
611 
612  while (node && *ptr)
613  {
614  StopLow = node->data;
615  StopHigh = node->data + node->length;
616  while (StopLow < StopHigh)
617  {
618  StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
619  if (StopMiddle->val == *ptr)
620  {
621  if (*(ptr + 1) == '\0' && StopMiddle->isword)
622  {
623  if (flag == 0)
624  {
625  /*
626  * The word can be formed only with another word. And
627  * in the flag parameter there is not a sign that we
628  * search compound words.
629  */
630  if (StopMiddle->compoundflag & FF_COMPOUNDONLY)
631  return 0;
632  }
633  else if ((flag & StopMiddle->compoundflag) == 0)
634  return 0;
635 
636  /*
637  * Check if this affix rule is presented in the affix set
638  * with index StopMiddle->affix.
639  */
640  if (IsAffixFlagInUse(Conf, StopMiddle->affix, affixflag))
641  return 1;
642  }
643  node = StopMiddle->node;
644  ptr++;
645  break;
646  }
647  else if (StopMiddle->val < *ptr)
648  StopLow = StopMiddle + 1;
649  else
650  StopHigh = StopMiddle;
651  }
652  if (StopLow >= StopHigh)
653  break;
654  }
655  return 0;
656 }
static bool IsAffixFlagInUse(IspellDict *Conf, int affix, const char *affixflag)
Definition: spell.c:454
#define FF_COMPOUNDFLAGMASK
Definition: spell.h:48
SPNode * Dictionary
Definition: spell.h:199
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 811 of file spell.c.

812 {
813  int state = PAE_WAIT_MASK;
814  int avail = BUFSIZ;
815 
816  while (**str)
817  {
818  if (state == PAE_WAIT_MASK)
819  {
820  if (t_iseq(*str, '#'))
821  return false;
822  else if (!t_isspace(*str))
823  {
824  int clen = pg_mblen(*str);
825 
826  if (clen < avail)
827  {
828  COPYCHAR(next, *str);
829  next += clen;
830  avail -= clen;
831  }
832  state = PAE_INMASK;
833  }
834  }
835  else /* state == PAE_INMASK */
836  {
837  if (t_isspace(*str))
838  {
839  *next = '\0';
840  return true;
841  }
842  else
843  {
844  int clen = pg_mblen(*str);
845 
846  if (clen < avail)
847  {
848  COPYCHAR(next, *str);
849  next += clen;
850  avail -= clen;
851  }
852  }
853  }
854  *str += pg_mblen(*str);
855  }
856 
857  *next = '\0';
858 
859  return (state == PAE_INMASK); /* OK if we got a nonempty field */
860 }
static int32 next
Definition: blutils.c:219
#define PAE_INMASK
Definition: spell.c:792
#define PAE_WAIT_MASK
Definition: spell.c:791
Definition: regguts.h:318

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

Referenced by parse_ooaffentry().

◆ getAffixFlagSet()

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

Definition at line 1179 of file spell.c.

1180 {
1181  if (Conf->useFlagAliases && *s != '\0')
1182  {
1183  int curaffix;
1184  char *end;
1185 
1186  curaffix = strtol(s, &end, 10);
1187  if (s == end || errno == ERANGE)
1188  ereport(ERROR,
1189  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1190  errmsg("invalid affix alias \"%s\"", s)));
1191 
1192  if (curaffix > 0 && curaffix < Conf->nAffixData)
1193 
1194  /*
1195  * Do not subtract 1 from curaffix because empty string was added
1196  * in NIImportOOAffixes
1197  */
1198  return Conf->AffixData[curaffix];
1199  else if (curaffix > Conf->nAffixData)
1200  ereport(ERROR,
1201  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1202  errmsg("invalid affix alias \"%s\"", s)));
1203  return VoidString;
1204  }
1205  else
1206  return s;
1207 }
static char * VoidString
Definition: spell.c:194
char ** AffixData
Definition: spell.h:201
int nAffixData
Definition: spell.h:203
bool useFlagAliases
Definition: spell.h:204

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

Referenced by NIImportOOAffixes().

◆ getCompoundAffixFlagValue()

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

Definition at line 1143 of file spell.c.

1144 {
1145  uint32 flag = 0;
1146  CompoundAffixFlag *found,
1147  key;
1148  char sflag[BUFSIZ];
1149  char *flagcur;
1150 
1151  if (Conf->nCompoundAffixFlag == 0)
1152  return 0;
1153 
1154  flagcur = s;
1155  while (*flagcur)
1156  {
1157  getNextFlagFromString(Conf, &flagcur, sflag);
1158  setCompoundAffixFlagValue(Conf, &key, sflag, 0);
1159 
1160  found = (CompoundAffixFlag *)
1161  bsearch(&key, (void *) Conf->CompoundAffixFlags,
1162  Conf->nCompoundAffixFlag, sizeof(CompoundAffixFlag),
1163  cmpcmdflag);
1164  if (found != NULL)
1165  flag |= found->value;
1166  }
1167 
1168  return flag;
1169 }
unsigned int uint32
Definition: c.h:490
static void getNextFlagFromString(IspellDict *Conf, char **sflagset, char *sflag)
Definition: spell.c:349
static int cmpcmdflag(const void *f1, const void *f2)
Definition: spell.c:210
uint32 value
Definition: spell.h:185

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,
char **  sflagset,
char *  sflag 
)
static

Definition at line 349 of file spell.c.

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

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

Referenced by getCompoundAffixFlagValue(), and IsAffixFlagInUse().

◆ IsAffixFlagInUse()

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

Definition at line 454 of file spell.c.

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

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

Referenced by FindWord(), and isAffixInUse().

◆ isAffixInUse()

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

Definition at line 1977 of file spell.c.

1978 {
1979  int i;
1980 
1981  for (i = 0; i < Conf->nAffixData; i++)
1982  if (IsAffixFlagInUse(Conf, i, affixflag))
1983  return true;
1984 
1985  return false;
1986 }

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

Referenced by NISortAffixes().

◆ lowerstr_ctx()

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

Definition at line 175 of file spell.c.

176 {
177  MemoryContext saveCtx;
178  char *dst;
179 
180  saveCtx = MemoryContextSwitchTo(Conf->buildCxt);
181  dst = lowerstr(src);
182  MemoryContextSwitchTo(saveCtx);
183 
184  return dst;
185 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
char * lowerstr(const char *str)
Definition: ts_locale.c:260

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

Referenced by NIImportDictionary(), and NIImportOOAffixes().

◆ makeCompoundFlags()

static uint32 makeCompoundFlags ( IspellDict Conf,
int  affix 
)
static

Definition at line 1639 of file spell.c.

1640 {
1641  Assert(affix < Conf->nAffixData);
1642 
1643  return (getCompoundAffixFlagValue(Conf, Conf->AffixData[affix]) &
1645 }
static int getCompoundAffixFlagValue(IspellDict *Conf, char *s)
Definition: spell.c:1143

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 1592 of file spell.c.

1593 {
1594  char **ptr;
1595 
1596  Assert(a1 < Conf->nAffixData && a2 < Conf->nAffixData);
1597 
1598  /* Do not merge affix flags if one of affix flags is empty */
1599  if (*Conf->AffixData[a1] == '\0')
1600  return a2;
1601  else if (*Conf->AffixData[a2] == '\0')
1602  return a1;
1603 
1604  /* Double the size of AffixData if there's not enough space */
1605  if (Conf->nAffixData + 1 >= Conf->lenAffixData)
1606  {
1607  Conf->lenAffixData *= 2;
1608  Conf->AffixData = (char **) repalloc(Conf->AffixData,
1609  sizeof(char *) * Conf->lenAffixData);
1610  }
1611 
1612  ptr = Conf->AffixData + Conf->nAffixData;
1613  if (Conf->flagMode == FM_NUM)
1614  {
1615  *ptr = cpalloc(strlen(Conf->AffixData[a1]) +
1616  strlen(Conf->AffixData[a2]) +
1617  1 /* comma */ + 1 /* \0 */ );
1618  sprintf(*ptr, "%s,%s", Conf->AffixData[a1], Conf->AffixData[a2]);
1619  }
1620  else
1621  {
1622  *ptr = cpalloc(strlen(Conf->AffixData[a1]) +
1623  strlen(Conf->AffixData[a2]) +
1624  1 /* \0 */ );
1625  sprintf(*ptr, "%s%s", Conf->AffixData[a1], Conf->AffixData[a2]);
1626  }
1627  ptr++;
1628  *ptr = NULL;
1629  Conf->nAffixData++;
1630 
1631  return Conf->nAffixData - 1;
1632 }
int lenAffixData
Definition: spell.h:202

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 1846 of file spell.c.

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

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

Referenced by NISortAffixes().

◆ mkSPNode()

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

Definition at line 1656 of file spell.c.

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

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

Referenced by NISortDictionary().

◆ mkVoidAffix()

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

Definition at line 1923 of file spell.c.

1924 {
1925  int i,
1926  cnt = 0;
1927  int start = (issuffix) ? startsuffix : 0;
1928  int end = (issuffix) ? Conf->naffixes : startsuffix;
1929  AffixNode *Affix = (AffixNode *) palloc0(ANHRDSZ + sizeof(AffixNodeData));
1930 
1931  Affix->length = 1;
1932  Affix->isvoid = 1;
1933 
1934  if (issuffix)
1935  {
1936  Affix->data->node = Conf->Suffix;
1937  Conf->Suffix = Affix;
1938  }
1939  else
1940  {
1941  Affix->data->node = Conf->Prefix;
1942  Conf->Prefix = Affix;
1943  }
1944 
1945  /* Count affixes with empty replace string */
1946  for (i = start; i < end; i++)
1947  if (Conf->Affix[i].replen == 0)
1948  cnt++;
1949 
1950  /* There is not affixes with empty replace string */
1951  if (cnt == 0)
1952  return;
1953 
1954  Affix->data->aff = (AFFIX **) cpalloc(sizeof(AFFIX *) * cnt);
1955  Affix->data->naff = (uint32) cnt;
1956 
1957  cnt = 0;
1958  for (i = start; i < end; i++)
1959  if (Conf->Affix[i].replen == 0)
1960  {
1961  Affix->data->aff[cnt] = Conf->Affix + i;
1962  cnt++;
1963  }
1964 }
AFFIX ** aff
Definition: spell.h:140
AffixNode * Suffix
Definition: spell.h:196
int naffixes
Definition: spell.h:193
AffixNode * Prefix
Definition: spell.h:197

References AffixNodeData::aff, IspellDict::Affix, ANHRDSZ, cpalloc, AffixNode::data, i, IspellDict::naffixes, AffixNodeData::node, palloc0(), IspellDict::Prefix, aff_struct::replen, 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 688 of file spell.c.

690 {
691  AFFIX *Affix;
692 
693  if (Conf->naffixes >= Conf->maffixes)
694  {
695  if (Conf->maffixes)
696  {
697  Conf->maffixes *= 2;
698  Conf->Affix = (AFFIX *) repalloc((void *) Conf->Affix, Conf->maffixes * sizeof(AFFIX));
699  }
700  else
701  {
702  Conf->maffixes = 16;
703  Conf->Affix = (AFFIX *) palloc(Conf->maffixes * sizeof(AFFIX));
704  }
705  }
706 
707  Affix = Conf->Affix + Conf->naffixes;
708 
709  /* This affix rule can be applied for words with any ending */
710  if (strcmp(mask, ".") == 0 || *mask == '\0')
711  {
712  Affix->issimple = 1;
713  Affix->isregis = 0;
714  }
715  /* This affix rule will use regis to search word ending */
716  else if (RS_isRegis(mask))
717  {
718  Affix->issimple = 0;
719  Affix->isregis = 1;
720  RS_compile(&(Affix->reg.regis), (type == FF_SUFFIX),
721  *mask ? mask : VoidString);
722  }
723  /* This affix rule will use regex_t to search word ending */
724  else
725  {
726  int masklen;
727  int wmasklen;
728  int err;
729  pg_wchar *wmask;
730  char *tmask;
731  aff_regex_struct *pregex;
732 
733  Affix->issimple = 0;
734  Affix->isregis = 0;
735  tmask = (char *) tmpalloc(strlen(mask) + 3);
736  if (type == FF_SUFFIX)
737  sprintf(tmask, "%s$", mask);
738  else
739  sprintf(tmask, "^%s", mask);
740 
741  masklen = strlen(tmask);
742  wmask = (pg_wchar *) tmpalloc((masklen + 1) * sizeof(pg_wchar));
743  wmasklen = pg_mb2wchar_with_len(tmask, wmask, masklen);
744 
745  /*
746  * The regex engine stores its stuff using malloc not palloc, so we
747  * must arrange to explicitly clean up the regex when the dictionary's
748  * context is cleared. That means the regex_t has to stay in a fixed
749  * location within the context; we can't keep it directly in the AFFIX
750  * struct, since we may sort and resize the array of AFFIXes.
751  */
752  Affix->reg.pregex = pregex = palloc(sizeof(aff_regex_struct));
753 
754  err = pg_regcomp(&(pregex->regex), wmask, wmasklen,
756  DEFAULT_COLLATION_OID);
757  if (err)
758  {
759  char errstr[100];
760 
761  pg_regerror(err, &(pregex->regex), errstr, sizeof(errstr));
762  ereport(ERROR,
763  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
764  errmsg("invalid regular expression: %s", errstr)));
765  }
766 
768  pregex->mcallback.arg = (void *) pregex;
770  &pregex->mcallback);
771  }
772 
773  Affix->flagflags = flagflags;
774  if ((Affix->flagflags & FF_COMPOUNDONLY) || (Affix->flagflags & FF_COMPOUNDPERMITFLAG))
775  {
776  if ((Affix->flagflags & FF_COMPOUNDFLAG) == 0)
777  Affix->flagflags |= FF_COMPOUNDFLAG;
778  }
779  Affix->flag = cpstrdup(Conf, flag);
780  Affix->type = type;
781 
782  Affix->find = (find && *find) ? cpstrdup(Conf, find) : VoidString;
783  if ((Affix->replen = strlen(repl)) > 0)
784  Affix->repl = cpstrdup(Conf, repl);
785  else
786  Affix->repl = VoidString;
787  Conf->naffixes++;
788 }
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
Definition: mcxt.c:461
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
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:103
#define REG_NOSUB
Definition: regex.h:107
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:162
static void regex_affix_deletion_callback(void *arg)
Definition: spell.c:662
#define FF_COMPOUNDPERMITFLAG
Definition: spell.h:119
struct aff_struct AFFIX
int maffixes
Definition: spell.h:192
MemoryContextCallbackFunction func
Definition: palloc.h:49
MemoryContextCallback mcallback
Definition: spell.h:92
char * flag
Definition: spell.h:100
char * repl
Definition: spell.h:108

References IspellDict::Affix, MemoryContextCallback::arg, cpstrdup(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, FF_COMPOUNDFLAG, FF_COMPOUNDONLY, FF_COMPOUNDPERMITFLAG, FF_SUFFIX, find(), aff_struct::find, aff_struct::flag, flag(), aff_struct::flagflags, MemoryContextCallback::func, aff_struct::isregis, aff_struct::issimple, IspellDict::maffixes, aff_regex_struct::mcallback, MemoryContextRegisterResetCallback(), IspellDict::naffixes, palloc(), pg_mb2wchar_with_len(), pg_regcomp(), pg_regerror(), aff_struct::pregex, aff_struct::reg, REG_ADVANCED, REG_NOSUB, aff_regex_struct::regex, regex_affix_deletion_callback(), aff_struct::regis, repalloc(), aff_struct::repl, aff_struct::replen, RS_compile(), RS_isRegis(), sprintf, tmpalloc, generate_unaccent_rules::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 486 of file spell.c.

487 {
488  if (Conf->nspell >= Conf->mspell)
489  {
490  if (Conf->mspell)
491  {
492  Conf->mspell *= 2;
493  Conf->Spell = (SPELL **) repalloc(Conf->Spell, Conf->mspell * sizeof(SPELL *));
494  }
495  else
496  {
497  Conf->mspell = 1024 * 20;
498  Conf->Spell = (SPELL **) tmpalloc(Conf->mspell * sizeof(SPELL *));
499  }
500  }
501  Conf->Spell[Conf->nspell] = (SPELL *) tmpalloc(SPELLHDRSZ + strlen(word) + 1);
502  strcpy(Conf->Spell[Conf->nspell]->word, word);
503  Conf->Spell[Conf->nspell]->p.flag = (*flag != '\0')
504  ? cpstrdup(Conf, flag) : VoidString;
505  Conf->nspell++;
506 }
#define SPELLHDRSZ
Definition: spell.h:82
int mspell
Definition: spell.h:231
int nspell
Definition: spell.h:230
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 103 of file spell.c.

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

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 1445 of file spell.c.

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

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, lowerstr(), NIAddAffix(), NIImportOOAffixes(), parse_affentry(), pfree(), pg_mblen(), prefixes(), STRNCMP, t_isspace(), 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 517 of file spell.c.

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

References ereport, errcode(), errmsg(), ERROR, filename, findchar(), flag(), lowerstr_ctx(), NIAddSpell(), pfree(), pg_mblen(), t_isprint(), t_isspace(), 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 1216 of file spell.c.

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

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, t_isspace(), tsearch_readline(), tsearch_readline_begin(), tsearch_readline_end(), generate_unaccent_rules::type, IspellDict::usecompound, IspellDict::useFlagAliases, and VoidString.

Referenced by NIImportAffixes().

◆ NINormalizeWord()

TSLexeme* NINormalizeWord ( IspellDict Conf,
char *  word 
)

Definition at line 2556 of file spell.c.

2557 {
2558  char **res;
2559  TSLexeme *lcur = NULL,
2560  *lres = NULL;
2561  uint16 NVariant = 1;
2562 
2563  res = NormalizeSubWord(Conf, word, 0);
2564 
2565  if (res)
2566  {
2567  char **ptr = res;
2568 
2569  while (*ptr && (lcur - lres) < MAX_NORM)
2570  {
2571  addNorm(&lres, &lcur, *ptr, 0, NVariant++);
2572  ptr++;
2573  }
2574  pfree(res);
2575  }
2576 
2577  if (Conf->usecompound)
2578  {
2579  int wordlen = strlen(word);
2580  SplitVar *ptr,
2581  *var = SplitToVariants(Conf, NULL, NULL, word, wordlen, 0, -1);
2582  int i;
2583 
2584  while (var)
2585  {
2586  if (var->nstem > 1)
2587  {
2588  char **subres = NormalizeSubWord(Conf, var->stem[var->nstem - 1], FF_COMPOUNDLAST);
2589 
2590  if (subres)
2591  {
2592  char **subptr = subres;
2593 
2594  while (*subptr)
2595  {
2596  for (i = 0; i < var->nstem - 1; i++)
2597  {
2598  addNorm(&lres, &lcur, (subptr == subres) ? var->stem[i] : pstrdup(var->stem[i]), 0, NVariant);
2599  }
2600 
2601  addNorm(&lres, &lcur, *subptr, 0, NVariant);
2602  subptr++;
2603  NVariant++;
2604  }
2605 
2606  pfree(subres);
2607  var->stem[0] = NULL;
2608  pfree(var->stem[var->nstem - 1]);
2609  }
2610  }
2611 
2612  for (i = 0; i < var->nstem && var->stem[i]; i++)
2613  pfree(var->stem[i]);
2614  ptr = var->next;
2615  pfree(var->stem);
2616  pfree(var);
2617  var = ptr;
2618  }
2619  }
2620 
2621  return lres;
2622 }
unsigned short uint16
Definition: c.h:489
static SplitVar * SplitToVariants(IspellDict *Conf, SPNode *snode, SplitVar *orig, char *word, int wordlen, int startpos, int minpos)
Definition: spell.c:2390
static void addNorm(TSLexeme **lres, TSLexeme **lcur, char *word, int flags, uint16 NVariant)
Definition: spell.c:2540
static char ** NormalizeSubWord(IspellDict *Conf, char *word, int flag)
Definition: spell.c:2192

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

Referenced by dispell_lexize().

◆ NISortAffixes()

void NISortAffixes ( IspellDict Conf)

Definition at line 1992 of file spell.c.

1993 {
1994  AFFIX *Affix;
1995  size_t i;
1996  CMPDAffix *ptr;
1997  int firstsuffix = Conf->naffixes;
1998 
1999  if (Conf->naffixes == 0)
2000  return;
2001 
2002  /* Store compound affixes in the Conf->CompoundAffix array */
2003  if (Conf->naffixes > 1)
2004  qsort((void *) Conf->Affix, Conf->naffixes, sizeof(AFFIX), cmpaffix);
2005  Conf->CompoundAffix = ptr = (CMPDAffix *) palloc(sizeof(CMPDAffix) * Conf->naffixes);
2006  ptr->affix = NULL;
2007 
2008  for (i = 0; i < Conf->naffixes; i++)
2009  {
2010  Affix = &(((AFFIX *) Conf->Affix)[i]);
2011  if (Affix->type == FF_SUFFIX && i < firstsuffix)
2012  firstsuffix = i;
2013 
2014  if ((Affix->flagflags & FF_COMPOUNDFLAG) && Affix->replen > 0 &&
2015  isAffixInUse(Conf, Affix->flag))
2016  {
2017  bool issuffix = (Affix->type == FF_SUFFIX);
2018 
2019  if (ptr == Conf->CompoundAffix ||
2020  issuffix != (ptr - 1)->issuffix ||
2021  strbncmp((const unsigned char *) (ptr - 1)->affix,
2022  (const unsigned char *) Affix->repl,
2023  (ptr - 1)->len))
2024  {
2025  /* leave only unique and minimal suffixes */
2026  ptr->affix = Affix->repl;
2027  ptr->len = Affix->replen;
2028  ptr->issuffix = issuffix;
2029  ptr++;
2030  }
2031  }
2032  }
2033  ptr->affix = NULL;
2034  Conf->CompoundAffix = (CMPDAffix *) repalloc(Conf->CompoundAffix, sizeof(CMPDAffix) * (ptr - Conf->CompoundAffix + 1));
2035 
2036  /* Start build a prefix tree */
2037  Conf->Prefix = mkANode(Conf, 0, firstsuffix, 0, FF_PREFIX);
2038  Conf->Suffix = mkANode(Conf, firstsuffix, Conf->naffixes, 0, FF_SUFFIX);
2039  mkVoidAffix(Conf, true, firstsuffix);
2040  mkVoidAffix(Conf, false, firstsuffix);
2041 }
static bool isAffixInUse(IspellDict *Conf, char *affixflag)
Definition: spell.c:1977
static int strbncmp(const unsigned char *s1, const unsigned char *s2, size_t count)
Definition: spell.c:280
static void mkVoidAffix(IspellDict *Conf, bool issuffix, int startsuffix)
Definition: spell.c:1923
static int cmpaffix(const void *s1, const void *s2)
Definition: spell.c:311
int len
Definition: spell.h:156
bool issuffix
Definition: spell.h:157
char * affix
Definition: spell.h:155
CMPDAffix * CompoundAffix
Definition: spell.h:206

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 1738 of file spell.c.

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

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

Referenced by dispell_init().

◆ NIStartBuild()

void NIStartBuild ( IspellDict Conf)

Definition at line 88 of file spell.c.

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

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

Referenced by dispell_init().

◆ NormalizeSubWord()

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

Definition at line 2192 of file spell.c.

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

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 933 of file spell.c.

934 {
935  int state = PAE_WAIT_MASK;
936  char *pmask = mask,
937  *pfind = find,
938  *prepl = repl;
939 
940  *mask = *find = *repl = '\0';
941 
942  while (*str)
943  {
944  if (state == PAE_WAIT_MASK)
945  {
946  if (t_iseq(str, '#'))
947  return false;
948  else if (!t_isspace(str))
949  {
950  COPYCHAR(pmask, str);
951  pmask += pg_mblen(str);
952  state = PAE_INMASK;
953  }
954  }
955  else if (state == PAE_INMASK)
956  {
957  if (t_iseq(str, '>'))
958  {
959  *pmask = '\0';
961  }
962  else if (!t_isspace(str))
963  {
964  COPYCHAR(pmask, str);
965  pmask += pg_mblen(str);
966  }
967  }
968  else if (state == PAE_WAIT_FIND)
969  {
970  if (t_iseq(str, '-'))
971  {
972  state = PAE_INFIND;
973  }
974  else if (t_isalpha(str) || t_iseq(str, '\'') /* english 's */ )
975  {
976  COPYCHAR(prepl, str);
977  prepl += pg_mblen(str);
978  state = PAE_INREPL;
979  }
980  else if (!t_isspace(str))
981  ereport(ERROR,
982  (errcode(ERRCODE_CONFIG_FILE_ERROR),
983  errmsg("syntax error")));
984  }
985  else if (state == PAE_INFIND)
986  {
987  if (t_iseq(str, ','))
988  {
989  *pfind = '\0';
991  }
992  else if (t_isalpha(str))
993  {
994  COPYCHAR(pfind, str);
995  pfind += pg_mblen(str);
996  }
997  else if (!t_isspace(str))
998  ereport(ERROR,
999  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1000  errmsg("syntax error")));
1001  }
1002  else if (state == PAE_WAIT_REPL)
1003  {
1004  if (t_iseq(str, '-'))
1005  {
1006  break; /* void repl */
1007  }
1008  else if (t_isalpha(str))
1009  {
1010  COPYCHAR(prepl, str);
1011  prepl += pg_mblen(str);
1012  state = PAE_INREPL;
1013  }
1014  else if (!t_isspace(str))
1015  ereport(ERROR,
1016  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1017  errmsg("syntax error")));
1018  }
1019  else if (state == PAE_INREPL)
1020  {
1021  if (t_iseq(str, '#'))
1022  {
1023  *prepl = '\0';
1024  break;
1025  }
1026  else if (t_isalpha(str))
1027  {
1028  COPYCHAR(prepl, str);
1029  prepl += pg_mblen(str);
1030  }
1031  else if (!t_isspace(str))
1032  ereport(ERROR,
1033  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1034  errmsg("syntax error")));
1035  }
1036  else
1037  elog(ERROR, "unrecognized state in parse_affentry: %d", state);
1038 
1039  str += pg_mblen(str);
1040  }
1041 
1042  *pmask = *pfind = *prepl = '\0';
1043 
1044  return (*mask && (*find || *repl));
1045 }
#define PAE_WAIT_REPL
Definition: spell.c:795
#define PAE_INREPL
Definition: spell.c:796
#define PAE_WAIT_FIND
Definition: spell.c:793
#define PAE_INFIND
Definition: spell.c:794
int t_isalpha(const char *ptr)
Definition: ts_locale.c:69

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(), generate_unaccent_rules::str, t_isalpha(), t_iseq, and t_isspace().

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 877 of file spell.c.

879 {
880  int state = PAE_WAIT_TYPE;
881  int fields_read = 0;
882  bool valid = false;
883 
884  *type = *flag = *find = *repl = *mask = '\0';
885 
886  while (*str)
887  {
888  switch (state)
889  {
890  case PAE_WAIT_TYPE:
891  valid = get_nextfield(&str, type);
893  break;
894  case PAE_WAIT_FLAG:
895  valid = get_nextfield(&str, flag);
897  break;
898  case PAE_WAIT_FIND:
899  valid = get_nextfield(&str, find);
901  break;
902  case PAE_WAIT_REPL:
903  valid = get_nextfield(&str, repl);
905  break;
906  case PAE_WAIT_MASK:
907  valid = get_nextfield(&str, mask);
908  state = -1; /* force loop exit */
909  break;
910  default:
911  elog(ERROR, "unrecognized state in parse_ooaffentry: %d",
912  state);
913  break;
914  }
915  if (valid)
916  fields_read++;
917  else
918  break; /* early EOL */
919  if (state < 0)
920  break; /* got all fields */
921  }
922 
923  return fields_read;
924 }
static bool get_nextfield(char **str, char *next)
Definition: spell.c:811
#define PAE_WAIT_FLAG
Definition: spell.c:798
#define PAE_WAIT_TYPE
Definition: spell.c:797

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

Referenced by NIImportOOAffixes().

◆ regex_affix_deletion_callback()

static void regex_affix_deletion_callback ( void *  arg)
static

Definition at line 662 of file spell.c.

663 {
664  aff_regex_struct *pregex = (aff_regex_struct *) arg;
665 
666  pg_regfree(&(pregex->regex));
667 }
void * arg
void pg_regfree(regex_t *re)
Definition: regfree.c:49

References arg, pg_regfree(), and aff_regex_struct::regex.

Referenced by NIAddAffix().

◆ setCompoundAffixFlagValue()

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

Definition at line 1051 of file spell.c.

1053 {
1054  if (Conf->flagMode == FM_NUM)
1055  {
1056  char *next;
1057  int i;
1058 
1059  i = strtol(s, &next, 10);
1060  if (s == next || errno == ERANGE)
1061  ereport(ERROR,
1062  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1063  errmsg("invalid affix flag \"%s\"", s)));
1064  if (i < 0 || i > FLAGNUM_MAXSIZE)
1065  ereport(ERROR,
1066  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1067  errmsg("affix flag \"%s\" is out of range", s)));
1068 
1069  entry->flag.i = i;
1070  }
1071  else
1072  entry->flag.s = cpstrdup(Conf, s);
1073 
1074  entry->flagMode = Conf->flagMode;
1075  entry->value = val;
1076 }

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,
char *  word,
int  wordlen,
int  startpos,
int  minpos 
)
static

Definition at line 2390 of file spell.c.

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

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(), startpos, SPNodeData::val, and word().

Referenced by NINormalizeWord().

◆ strbcmp()

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

Definition at line 257 of file spell.c.

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

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 280 of file spell.c.

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

References s1, and s2.

Referenced by NISortAffixes().

Variable Documentation

◆ VoidString

char* VoidString = ""
static

Definition at line 194 of file spell.c.

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