PostgreSQL Source Code  git master
spell.c File Reference
#include "postgres.h"
#include "catalog/pg_collation.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 125 of file spell.c.

Referenced by compact_palloc0().

◆ COMPACT_MAX_REQ

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

Definition at line 126 of file spell.c.

Referenced by compact_palloc0().

◆ cpalloc

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

Definition at line 157 of file spell.c.

Referenced by cpstrdup(), MergeAffix(), mkANode(), and mkVoidAffix().

◆ cpalloc0

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

Definition at line 158 of file spell.c.

Referenced by mkANode(), and mkSPNode().

◆ GETCHAR

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

Definition at line 191 of file spell.c.

Referenced by mkANode().

◆ GETWCHAR

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

Definition at line 190 of file spell.c.

Referenced by FindAffixes().

◆ MAX_NORM

#define MAX_NORM   1024

Definition at line 186 of file spell.c.

Referenced by addNorm(), addToResult(), NINormalizeWord(), and NormalizeSubWord().

◆ MAXNORMLEN

#define MAXNORMLEN   256

Definition at line 187 of file spell.c.

Referenced by NormalizeSubWord(), and SplitToVariants().

◆ PAE_INFIND

#define PAE_INFIND   3

Definition at line 793 of file spell.c.

Referenced by parse_affentry().

◆ PAE_INMASK

#define PAE_INMASK   1

Definition at line 791 of file spell.c.

Referenced by get_nextfield(), and parse_affentry().

◆ PAE_INREPL

#define PAE_INREPL   5

Definition at line 795 of file spell.c.

Referenced by parse_affentry().

◆ PAE_WAIT_FIND

#define PAE_WAIT_FIND   2

Definition at line 792 of file spell.c.

Referenced by parse_affentry(), and parse_ooaffentry().

◆ PAE_WAIT_FLAG

#define PAE_WAIT_FLAG   7

Definition at line 797 of file spell.c.

Referenced by parse_ooaffentry().

◆ PAE_WAIT_MASK

#define PAE_WAIT_MASK   0

Definition at line 790 of file spell.c.

Referenced by get_nextfield(), parse_affentry(), and parse_ooaffentry().

◆ PAE_WAIT_REPL

#define PAE_WAIT_REPL   4

Definition at line 794 of file spell.c.

Referenced by parse_affentry(), and parse_ooaffentry().

◆ PAE_WAIT_TYPE

#define PAE_WAIT_TYPE   6

Definition at line 796 of file spell.c.

Referenced by parse_ooaffentry().

◆ STRNCMP

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

Definition at line 189 of file spell.c.

Referenced by NIImportAffixes(), and NIImportOOAffixes().

◆ tmpalloc

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

Definition at line 78 of file spell.c.

Referenced by addCompoundAffixFlagValue(), mkANode(), NIAddAffix(), and NIAddSpell().

◆ tmpalloc0

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

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

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

Referenced by NIImportAffixes(), and NIImportOOAffixes().

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

◆ addNorm()

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

Definition at line 2535 of file spell.c.

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

Referenced by NINormalizeWord().

2536 {
2537  if (*lres == NULL)
2538  *lcur = *lres = (TSLexeme *) palloc(MAX_NORM * sizeof(TSLexeme));
2539 
2540  if (*lcur - *lres < MAX_NORM - 1)
2541  {
2542  (*lcur)->lexeme = word;
2543  (*lcur)->flags = flags;
2544  (*lcur)->nvariant = NVariant;
2545  (*lcur)++;
2546  (*lcur)->lexeme = NULL;
2547  }
2548 }
#define MAX_NORM
Definition: spell.c:186
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1393
void * palloc(Size size)
Definition: mcxt.c:1062

◆ AddStem()

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

Definition at line 2375 of file spell.c.

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

Referenced by SplitToVariants().

2376 {
2377  if (v->nstem >= v->lenstem)
2378  {
2379  v->lenstem *= 2;
2380  v->stem = (char **) repalloc(v->stem, sizeof(char *) * v->lenstem);
2381  }
2382 
2383  v->stem[v->nstem] = word;
2384  v->nstem++;
2385 }
int nstem
Definition: spell.c:2301
char ** stem
Definition: spell.c:2303
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1182
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1393
int lenstem
Definition: spell.c:2302

◆ addToResult()

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

Definition at line 2175 of file spell.c.

References MAX_NORM, and pstrdup().

Referenced by NormalizeSubWord().

2176 {
2177  if (cur - forms >= MAX_NORM - 1)
2178  return 0;
2179  if (forms == cur || strcmp(word, *(cur - 1)) != 0)
2180  {
2181  *cur = pstrdup(word);
2182  *(cur + 1) = NULL;
2183  return 1;
2184  }
2185 
2186  return 0;
2187 }
char * pstrdup(const char *in)
Definition: mcxt.c:1299
struct cursor * cur
Definition: ecpg.c:28
#define MAX_NORM
Definition: spell.c:186
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1393

◆ CheckAffix()

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

Definition at line 2085 of file spell.c.

References 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, 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(), and aff_struct::type.

Referenced by NormalizeSubWord().

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

◆ CheckCompoundAffixes()

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

Definition at line 2308 of file spell.c.

References word().

Referenced by SplitToVariants().

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

◆ cmpaffix()

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

Definition at line 310 of file spell.c.

References a1, a2, FF_PREFIX, aff_struct::repl, strbcmp(), and aff_struct::type.

Referenced by NISortAffixes().

311 {
312  const AFFIX *a1 = (const AFFIX *) s1;
313  const AFFIX *a2 = (const AFFIX *) s2;
314 
315  if (a1->type < a2->type)
316  return -1;
317  if (a1->type > a2->type)
318  return 1;
319  if (a1->type == FF_PREFIX)
320  return strcmp(a1->repl, a2->repl);
321  else
322  return strbcmp((const unsigned char *) a1->repl,
323  (const unsigned char *) a2->repl);
324 }
uint32 type
Definition: spell.h:102
static const FormData_pg_attribute a2
Definition: heap.c:166
char * s1
char * s2
#define FF_PREFIX
Definition: spell.h:128
char * repl
Definition: spell.h:108
static int strbcmp(const unsigned char *s1, const unsigned char *s2)
Definition: spell.c:256
static const FormData_pg_attribute a1
Definition: heap.c:152

◆ cmpcmdflag()

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

Definition at line 209 of file spell.c.

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

Referenced by getCompoundAffixFlagValue(), and NIImportOOAffixes().

210 {
212  *fv2 = (CompoundAffixFlag *) f2;
213 
214  Assert(fv1->flagMode == fv2->flagMode);
215 
216  if (fv1->flagMode == FM_NUM)
217  {
218  if (fv1->flag.i == fv2->flag.i)
219  return 0;
220 
221  return (fv1->flag.i > fv2->flag.i) ? 1 : -1;
222  }
223 
224  return strcmp(fv1->flag.s, fv2->flag.s);
225 }
int f1[ARRAY_SZIE]
Definition: sql-declare.c:113
union CompoundAffixFlag::@119 flag
Definition: spell.h:167
FlagMode flagMode
Definition: spell.h:184
#define Assert(condition)
Definition: c.h:804
int f2[ARRAY_SZIE]
Definition: sql-declare.c:116

◆ cmpspell()

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

Definition at line 196 of file spell.c.

References word().

Referenced by NISortDictionary().

197 {
198  return strcmp((*(SPELL *const *) s1)->word, (*(SPELL *const *) s2)->word);
199 }
char * s1
char * s2
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1393

◆ cmpspellaffix()

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

Definition at line 202 of file spell.c.

Referenced by NISortDictionary().

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

◆ compact_palloc0()

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

Definition at line 129 of file spell.c.

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

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

◆ CopyVar()

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

Definition at line 2350 of file spell.c.

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

Referenced by SplitToVariants().

2351 {
2352  SplitVar *v = (SplitVar *) palloc(sizeof(SplitVar));
2353 
2354  v->next = NULL;
2355  if (s)
2356  {
2357  int i;
2358 
2359  v->lenstem = s->lenstem;
2360  v->stem = (char **) palloc(sizeof(char *) * v->lenstem);
2361  v->nstem = s->nstem;
2362  for (i = 0; i < s->nstem; i++)
2363  v->stem[i] = (makedup) ? pstrdup(s->stem[i]) : s->stem[i];
2364  }
2365  else
2366  {
2367  v->lenstem = 16;
2368  v->stem = (char **) palloc(sizeof(char *) * v->lenstem);
2369  v->nstem = 0;
2370  }
2371  return v;
2372 }
char * pstrdup(const char *in)
Definition: mcxt.c:1299
int nstem
Definition: spell.c:2301
char ** stem
Definition: spell.c:2303
int lenstem
Definition: spell.c:2302
void * palloc(Size size)
Definition: mcxt.c:1062
int i
struct SplitVar * next
Definition: spell.c:2304

◆ cpstrdup()

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

Definition at line 161 of file spell.c.

References cpalloc.

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

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

◆ FindAffixes()

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

Definition at line 2042 of file spell.c.

References AffixNode::data, GETWCHAR, AffixNode::isvoid, AffixNode::length, AffixNodeData::naff, AffixNodeData::node, and AffixNodeData::val.

Referenced by NormalizeSubWord().

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

◆ findchar()

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

Definition at line 228 of file spell.c.

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

Referenced by NIImportDictionary().

229 {
230  while (*str)
231  {
232  if (t_iseq(str, c))
233  return str;
234  str += pg_mblen(str);
235  }
236 
237  return NULL;
238 }
char * c
#define t_iseq(x, c)
Definition: ts_locale.h:46
int pg_mblen(const char *mbstr)
Definition: mbutils.c:966

◆ findchar2()

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

Definition at line 241 of file spell.c.

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

Referenced by NIImportAffixes().

242 {
243  while (*str)
244  {
245  if (t_iseq(str, c1) || t_iseq(str, c2))
246  return str;
247  str += pg_mblen(str);
248  }
249 
250  return NULL;
251 }
#define t_iseq(x, c)
Definition: ts_locale.h:46
int pg_mblen(const char *mbstr)
Definition: mbutils.c:966

◆ FindWord()

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

Definition at line 601 of file spell.c.

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

Referenced by NormalizeSubWord().

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

◆ get_nextfield()

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

Definition at line 810 of file spell.c.

References COPYCHAR, PAE_INMASK, PAE_WAIT_MASK, pg_mblen(), t_iseq, and t_isspace().

Referenced by parse_ooaffentry().

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

◆ getAffixFlagSet()

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

Definition at line 1178 of file spell.c.

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

Referenced by NIImportOOAffixes().

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

◆ getCompoundAffixFlagValue()

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

Definition at line 1142 of file spell.c.

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

Referenced by makeCompoundFlags(), and NIImportOOAffixes().

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

◆ getNextFlagFromString()

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

Definition at line 348 of file spell.c.

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().

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

◆ IsAffixFlagInUse()

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

Definition at line 453 of file spell.c.

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

Referenced by FindWord(), and isAffixInUse().

454 {
455  char *flagcur;
456  char flag[BUFSIZ];
457 
458  if (*affixflag == 0)
459  return true;
460 
461  Assert(affix < Conf->nAffixData);
462 
463  flagcur = Conf->AffixData[affix];
464 
465  while (*flagcur)
466  {
467  getNextFlagFromString(Conf, &flagcur, flag);
468  /* Compare first affix flag in flagcur with affixflag */
469  if (strcmp(flag, affixflag) == 0)
470  return true;
471  }
472 
473  /* Could not find affixflag */
474  return false;
475 }
static void getNextFlagFromString(IspellDict *Conf, char **sflagset, char *sflag)
Definition: spell.c:348
char ** AffixData
Definition: spell.h:201
char * flag(int b)
Definition: test-ctype.c:33
#define Assert(condition)
Definition: c.h:804

◆ isAffixInUse()

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

Definition at line 1975 of file spell.c.

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

Referenced by NISortAffixes().

1976 {
1977  int i;
1978 
1979  for (i = 0; i < Conf->nAffixData; i++)
1980  if (IsAffixFlagInUse(Conf, i, affixflag))
1981  return true;
1982 
1983  return false;
1984 }
int nAffixData
Definition: spell.h:203
static bool IsAffixFlagInUse(IspellDict *Conf, int affix, const char *affixflag)
Definition: spell.c:453
int i

◆ lowerstr_ctx()

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

Definition at line 174 of file spell.c.

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

Referenced by NIImportDictionary(), and NIImportOOAffixes().

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

◆ makeCompoundFlags()

static uint32 makeCompoundFlags ( IspellDict Conf,
int  affix 
)
static

Definition at line 1637 of file spell.c.

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

Referenced by mkSPNode().

1638 {
1639  Assert(affix < Conf->nAffixData);
1640 
1641  return (getCompoundAffixFlagValue(Conf, Conf->AffixData[affix]) &
1643 }
static int getCompoundAffixFlagValue(IspellDict *Conf, char *s)
Definition: spell.c:1142
char ** AffixData
Definition: spell.h:201
#define FF_COMPOUNDFLAGMASK
Definition: spell.h:48
#define Assert(condition)
Definition: c.h:804

◆ MergeAffix()

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

Definition at line 1591 of file spell.c.

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

Referenced by mkSPNode().

1592 {
1593  char **ptr;
1594 
1595  Assert(a1 < Conf->nAffixData && a2 < Conf->nAffixData);
1596 
1597  /* Do not merge affix flags if one of affix flags is empty */
1598  if (*Conf->AffixData[a1] == '\0')
1599  return a2;
1600  else if (*Conf->AffixData[a2] == '\0')
1601  return a1;
1602 
1603  while (Conf->nAffixData + 1 >= Conf->lenAffixData)
1604  {
1605  Conf->lenAffixData *= 2;
1606  Conf->AffixData = (char **) repalloc(Conf->AffixData,
1607  sizeof(char *) * Conf->lenAffixData);
1608  }
1609 
1610  ptr = Conf->AffixData + Conf->nAffixData;
1611  if (Conf->flagMode == FM_NUM)
1612  {
1613  *ptr = cpalloc(strlen(Conf->AffixData[a1]) +
1614  strlen(Conf->AffixData[a2]) +
1615  1 /* comma */ + 1 /* \0 */ );
1616  sprintf(*ptr, "%s,%s", Conf->AffixData[a1], Conf->AffixData[a2]);
1617  }
1618  else
1619  {
1620  *ptr = cpalloc(strlen(Conf->AffixData[a1]) +
1621  strlen(Conf->AffixData[a2]) +
1622  1 /* \0 */ );
1623  sprintf(*ptr, "%s%s", Conf->AffixData[a1], Conf->AffixData[a2]);
1624  }
1625  ptr++;
1626  *ptr = NULL;
1627  Conf->nAffixData++;
1628 
1629  return Conf->nAffixData - 1;
1630 }
int nAffixData
Definition: spell.h:203
int lenAffixData
Definition: spell.h:202
#define sprintf
Definition: port.h:218
static const FormData_pg_attribute a2
Definition: heap.c:166
char ** AffixData
Definition: spell.h:201
Definition: spell.h:167
#define Assert(condition)
Definition: c.h:804
#define cpalloc(size)
Definition: spell.c:157
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1182
static const FormData_pg_attribute a1
Definition: heap.c:152
FlagMode flagMode
Definition: spell.h:209

◆ mkANode()

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

Definition at line 1844 of file spell.c.

References AffixNodeData::aff, IspellDict::Affix, ANHRDSZ, cpalloc, cpalloc0, AffixNode::data, GETCHAR, i, AffixNode::length, AffixNodeData::naff, AffixNodeData::node, pfree(), aff_struct::replen, tmpalloc, and AffixNodeData::val.

Referenced by NISortAffixes().

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

◆ mkSPNode()

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

Definition at line 1654 of file spell.c.

References SPNodeData::affix, SPNodeData::compoundflag, cpalloc0, spell_struct::d, SPNode::data, FF_COMPOUNDFLAG, FF_COMPOUNDONLY, i, SPNodeData::isword, SPNode::length, makeCompoundFlags(), MergeAffix(), SPNodeData::node, spell_struct::p, IspellDict::Spell, SPNHDRSZ, SPNodeData::val, and spell_struct::word.

Referenced by NISortDictionary().

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

◆ mkVoidAffix()

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

Definition at line 1921 of file spell.c.

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().

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

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

References IspellDict::Affix, MemoryContextCallback::arg, cpstrdup(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, FF_COMPOUNDFLAG, FF_COMPOUNDONLY, FF_COMPOUNDPERMITFLAG, FF_SUFFIX, aff_struct::find, find(), aff_struct::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, aff_struct::type, generate_unaccent_rules::type, and VoidString.

Referenced by NIImportAffixes(), and NIImportOOAffixes().

689 {
690  AFFIX *Affix;
691 
692  if (Conf->naffixes >= Conf->maffixes)
693  {
694  if (Conf->maffixes)
695  {
696  Conf->maffixes *= 2;
697  Conf->Affix = (AFFIX *) repalloc((void *) Conf->Affix, Conf->maffixes * sizeof(AFFIX));
698  }
699  else
700  {
701  Conf->maffixes = 16;
702  Conf->Affix = (AFFIX *) palloc(Conf->maffixes * sizeof(AFFIX));
703  }
704  }
705 
706  Affix = Conf->Affix + Conf->naffixes;
707 
708  /* This affix rule can be applied for words with any ending */
709  if (strcmp(mask, ".") == 0 || *mask == '\0')
710  {
711  Affix->issimple = 1;
712  Affix->isregis = 0;
713  }
714  /* This affix rule will use regis to search word ending */
715  else if (RS_isRegis(mask))
716  {
717  Affix->issimple = 0;
718  Affix->isregis = 1;
719  RS_compile(&(Affix->reg.regis), (type == FF_SUFFIX),
720  *mask ? mask : VoidString);
721  }
722  /* This affix rule will use regex_t to search word ending */
723  else
724  {
725  int masklen;
726  int wmasklen;
727  int err;
728  pg_wchar *wmask;
729  char *tmask;
730  aff_regex_struct *pregex;
731 
732  Affix->issimple = 0;
733  Affix->isregis = 0;
734  tmask = (char *) tmpalloc(strlen(mask) + 3);
735  if (type == FF_SUFFIX)
736  sprintf(tmask, "%s$", mask);
737  else
738  sprintf(tmask, "^%s", mask);
739 
740  masklen = strlen(tmask);
741  wmask = (pg_wchar *) tmpalloc((masklen + 1) * sizeof(pg_wchar));
742  wmasklen = pg_mb2wchar_with_len(tmask, wmask, masklen);
743 
744  /*
745  * The regex engine stores its stuff using malloc not palloc, so we
746  * must arrange to explicitly clean up the regex when the dictionary's
747  * context is cleared. That means the regex_t has to stay in a fixed
748  * location within the context; we can't keep it directly in the AFFIX
749  * struct, since we may sort and resize the array of AFFIXes.
750  */
751  Affix->reg.pregex = pregex = palloc(sizeof(aff_regex_struct));
752 
753  err = pg_regcomp(&(pregex->regex), wmask, wmasklen,
755  DEFAULT_COLLATION_OID);
756  if (err)
757  {
758  char errstr[100];
759 
760  pg_regerror(err, &(pregex->regex), errstr, sizeof(errstr));
761  ereport(ERROR,
762  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
763  errmsg("invalid regular expression: %s", errstr)));
764  }
765 
767  pregex->mcallback.arg = (void *) pregex;
769  &pregex->mcallback);
770  }
771 
772  Affix->flagflags = flagflags;
773  if ((Affix->flagflags & FF_COMPOUNDONLY) || (Affix->flagflags & FF_COMPOUNDPERMITFLAG))
774  {
775  if ((Affix->flagflags & FF_COMPOUNDFLAG) == 0)
776  Affix->flagflags |= FF_COMPOUNDFLAG;
777  }
778  Affix->flag = cpstrdup(Conf, flag);
779  Affix->type = type;
780 
781  Affix->find = (find && *find) ? cpstrdup(Conf, find) : VoidString;
782  if ((Affix->replen = strlen(repl)) > 0)
783  Affix->repl = cpstrdup(Conf, repl);
784  else
785  Affix->repl = VoidString;
786  Conf->naffixes++;
787 }
char * flag
Definition: spell.h:100
MemoryContextCallbackFunction func
Definition: palloc.h:49
int naffixes
Definition: spell.h:193
#define FF_COMPOUNDONLY
Definition: spell.h:42
static int find(struct vars *, struct cnfa *, struct colormap *)
Definition: regexec.c:393
uint32 flagflags
Definition: spell.h:102
uint32 type
Definition: spell.h:102
#define tmpalloc(sz)
Definition: spell.c:78
int errcode(int sqlerrcode)
Definition: elog.c:698
uint32 isregis
Definition: spell.h:102
int pg_regcomp(regex_t *re, const chr *string, size_t len, int flags, Oid collation)
Definition: regcomp.c:328
union aff_struct::@118 reg
MemoryContextCallback mcallback
Definition: spell.h:92
Regis regis
Definition: spell.h:112
#define sprintf
Definition: port.h:218
#define ERROR
Definition: elog.h:46
#define FF_SUFFIX
Definition: spell.h:127
char * flag(int b)
Definition: test-ctype.c:33
uint32 issimple
Definition: spell.h:102
AFFIX * Affix
Definition: spell.h:194
struct aff_struct AFFIX
size_t pg_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
Definition: regerror.c:60
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
#define REG_ADVANCED
Definition: regex.h:105
unsigned int pg_wchar
Definition: mbprint.c:31
char * find
Definition: spell.h:107
void RS_compile(Regis *r, bool issuffix, const char *str)
Definition: regis.c:85
int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
Definition: mbutils.c:929
#define ereport(elevel,...)
Definition: elog.h:157
static void regex_affix_deletion_callback(void *arg)
Definition: spell.c:661
#define REG_NOSUB
Definition: regex.h:109
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1182
aff_regex_struct * pregex
Definition: spell.h:111
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
bool RS_isRegis(const char *str)
Definition: regis.c:31
static char * VoidString
Definition: spell.c:193
static char * cpstrdup(IspellDict *Conf, const char *str)
Definition: spell.c:161
regex_t regex
Definition: spell.h:91
char * repl
Definition: spell.h:108
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
Definition: mcxt.c:292
#define FF_COMPOUNDFLAG
Definition: spell.h:46
int maffixes
Definition: spell.h:192
uint32 replen
Definition: spell.h:102
#define FF_COMPOUNDPERMITFLAG
Definition: spell.h:119

◆ NIAddSpell()

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

Definition at line 485 of file spell.c.

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

Referenced by NIImportDictionary().

486 {
487  if (Conf->nspell >= Conf->mspell)
488  {
489  if (Conf->mspell)
490  {
491  Conf->mspell *= 2;
492  Conf->Spell = (SPELL **) repalloc(Conf->Spell, Conf->mspell * sizeof(SPELL *));
493  }
494  else
495  {
496  Conf->mspell = 1024 * 20;
497  Conf->Spell = (SPELL **) tmpalloc(Conf->mspell * sizeof(SPELL *));
498  }
499  }
500  Conf->Spell[Conf->nspell] = (SPELL *) tmpalloc(SPELLHDRSZ + strlen(word) + 1);
501  strcpy(Conf->Spell[Conf->nspell]->word, word);
502  Conf->Spell[Conf->nspell]->p.flag = (*flag != '\0')
503  ? cpstrdup(Conf, flag) : VoidString;
504  Conf->nspell++;
505 }
int mspell
Definition: spell.h:231
#define tmpalloc(sz)
Definition: spell.c:78
int nspell
Definition: spell.h:230
char * flag(int b)
Definition: test-ctype.c:33
char word[FLEXIBLE_ARRAY_MEMBER]
Definition: spell.h:79
char * flag
Definition: spell.h:69
#define SPELLHDRSZ
Definition: spell.h:82
SPELL ** Spell
Definition: spell.h:229
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1182
union spell_struct::@116 p
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1393
static char * VoidString
Definition: spell.c:193
static char * cpstrdup(IspellDict *Conf, const char *str)
Definition: spell.c:161

◆ NIFinishBuild()

void NIFinishBuild ( IspellDict Conf)

Definition at line 102 of file spell.c.

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

Referenced by dispell_init().

103 {
104  /* Release no-longer-needed temp memory */
106  /* Just for cleanliness, zero the now-dangling pointers */
107  Conf->buildCxt = NULL;
108  Conf->Spell = NULL;
109  Conf->firstfree = NULL;
110  Conf->CompoundAffixFlags = NULL;
111 }
MemoryContext buildCxt
Definition: spell.h:226
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
CompoundAffixFlag * CompoundAffixFlags
Definition: spell.h:216
char * firstfree
Definition: spell.h:234
SPELL ** Spell
Definition: spell.h:229

◆ NIImportAffixes()

void NIImportAffixes ( IspellDict Conf,
const char *  filename 
)

Definition at line 1444 of file spell.c.

References addCompoundAffixFlagValue(), COPYCHAR, ereport, errcode(), errmsg(), ERROR, FF_COMPOUNDFLAG, FF_COMPOUNDONLY, FF_CROSSPRODUCT, FF_PREFIX, FF_SUFFIX, 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().

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

◆ NIImportDictionary()

void NIImportDictionary ( IspellDict Conf,
const char *  filename 
)

Definition at line 516 of file spell.c.

References ereport, errcode(), errmsg(), ERROR, 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().

517 {
519  char *line;
520 
521  if (!tsearch_readline_begin(&trst, filename))
522  ereport(ERROR,
523  (errcode(ERRCODE_CONFIG_FILE_ERROR),
524  errmsg("could not open dictionary file \"%s\": %m",
525  filename)));
526 
527  while ((line = tsearch_readline(&trst)) != NULL)
528  {
529  char *s,
530  *pstr;
531 
532  /* Set of affix flags */
533  const char *flag;
534 
535  /* Extract flag from the line */
536  flag = NULL;
537  if ((s = findchar(line, '/')))
538  {
539  *s++ = '\0';
540  flag = s;
541  while (*s)
542  {
543  /* we allow only single encoded flags for faster works */
544  if (pg_mblen(s) == 1 && t_isprint(s) && !t_isspace(s))
545  s++;
546  else
547  {
548  *s = '\0';
549  break;
550  }
551  }
552  }
553  else
554  flag = "";
555 
556  /* Remove trailing spaces */
557  s = line;
558  while (*s)
559  {
560  if (t_isspace(s))
561  {
562  *s = '\0';
563  break;
564  }
565  s += pg_mblen(s);
566  }
567  pstr = lowerstr_ctx(Conf, line);
568 
569  NIAddSpell(Conf, pstr, flag);
570  pfree(pstr);
571 
572  pfree(line);
573  }
574  tsearch_readline_end(&trst);
575 }
int t_isprint(const char *ptr)
Definition: ts_locale.c:85
static char * findchar(char *str, int c)
Definition: spell.c:228
int errcode(int sqlerrcode)
Definition: elog.c:698
static void NIAddSpell(IspellDict *Conf, const char *word, const char *flag)
Definition: spell.c:485
void pfree(void *pointer)
Definition: mcxt.c:1169
#define ERROR
Definition: elog.h:46
int t_isspace(const char *ptr)
Definition: ts_locale.c:53
char * flag(int b)
Definition: test-ctype.c:33
static char * lowerstr_ctx(IspellDict *Conf, const char *src)
Definition: spell.c:174
#define ereport(elevel,...)
Definition: elog.h:157
int pg_mblen(const char *mbstr)
Definition: mbutils.c:966
void tsearch_readline_end(tsearch_readline_state *stp)
Definition: ts_locale.c:193
char * tsearch_readline(tsearch_readline_state *stp)
Definition: ts_locale.c:148
bool tsearch_readline_begin(tsearch_readline_state *stp, const char *filename)
Definition: ts_locale.c:125
static char * filename
Definition: pg_dumpall.c:91
int errmsg(const char *fmt,...)
Definition: elog.c:909

◆ NIImportOOAffixes()

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

Definition at line 1215 of file spell.c.

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, 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().

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

◆ NINormalizeWord()

TSLexeme* NINormalizeWord ( IspellDict Conf,
char *  word 
)

Definition at line 2551 of file spell.c.

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

Referenced by dispell_lexize().

2552 {
2553  char **res;
2554  TSLexeme *lcur = NULL,
2555  *lres = NULL;
2556  uint16 NVariant = 1;
2557 
2558  res = NormalizeSubWord(Conf, word, 0);
2559 
2560  if (res)
2561  {
2562  char **ptr = res;
2563 
2564  while (*ptr && (lcur - lres) < MAX_NORM)
2565  {
2566  addNorm(&lres, &lcur, *ptr, 0, NVariant++);
2567  ptr++;
2568  }
2569  pfree(res);
2570  }
2571 
2572  if (Conf->usecompound)
2573  {
2574  int wordlen = strlen(word);
2575  SplitVar *ptr,
2576  *var = SplitToVariants(Conf, NULL, NULL, word, wordlen, 0, -1);
2577  int i;
2578 
2579  while (var)
2580  {
2581  if (var->nstem > 1)
2582  {
2583  char **subres = NormalizeSubWord(Conf, var->stem[var->nstem - 1], FF_COMPOUNDLAST);
2584 
2585  if (subres)
2586  {
2587  char **subptr = subres;
2588 
2589  while (*subptr)
2590  {
2591  for (i = 0; i < var->nstem - 1; i++)
2592  {
2593  addNorm(&lres, &lcur, (subptr == subres) ? var->stem[i] : pstrdup(var->stem[i]), 0, NVariant);
2594  }
2595 
2596  addNorm(&lres, &lcur, *subptr, 0, NVariant);
2597  subptr++;
2598  NVariant++;
2599  }
2600 
2601  pfree(subres);
2602  var->stem[0] = NULL;
2603  pfree(var->stem[var->nstem - 1]);
2604  }
2605  }
2606 
2607  for (i = 0; i < var->nstem && var->stem[i]; i++)
2608  pfree(var->stem[i]);
2609  ptr = var->next;
2610  pfree(var->stem);
2611  pfree(var);
2612  var = ptr;
2613  }
2614  }
2615 
2616  return lres;
2617 }
static char ** NormalizeSubWord(IspellDict *Conf, char *word, int flag)
Definition: spell.c:2190
bool usecompound
Definition: spell.h:208
char * pstrdup(const char *in)
Definition: mcxt.c:1299
#define FF_COMPOUNDLAST
Definition: spell.h:45
static void addNorm(TSLexeme **lres, TSLexeme **lcur, char *word, int flags, uint16 NVariant)
Definition: spell.c:2535
#define MAX_NORM
Definition: spell.c:186
unsigned short uint16
Definition: c.h:440
void pfree(void *pointer)
Definition: mcxt.c:1169
int nstem
Definition: spell.c:2301
static SplitVar * SplitToVariants(IspellDict *Conf, SPNode *snode, SplitVar *orig, char *word, int wordlen, int startpos, int minpos)
Definition: spell.c:2388
char ** stem
Definition: spell.c:2303
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1393
int i
struct SplitVar * next
Definition: spell.c:2304

◆ NISortAffixes()

void NISortAffixes ( IspellDict Conf)

Definition at line 1990 of file spell.c.

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().

1991 {
1992  AFFIX *Affix;
1993  size_t i;
1994  CMPDAffix *ptr;
1995  int firstsuffix = Conf->naffixes;
1996 
1997  if (Conf->naffixes == 0)
1998  return;
1999 
2000  /* Store compound affixes in the Conf->CompoundAffix array */
2001  if (Conf->naffixes > 1)
2002  qsort((void *) Conf->Affix, Conf->naffixes, sizeof(AFFIX), cmpaffix);
2003  Conf->CompoundAffix = ptr = (CMPDAffix *) palloc(sizeof(CMPDAffix) * Conf->naffixes);
2004  ptr->affix = NULL;
2005 
2006  for (i = 0; i < Conf->naffixes; i++)
2007  {
2008  Affix = &(((AFFIX *) Conf->Affix)[i]);
2009  if (Affix->type == FF_SUFFIX && i < firstsuffix)
2010  firstsuffix = i;
2011 
2012  if ((Affix->flagflags & FF_COMPOUNDFLAG) && Affix->replen > 0 &&
2013  isAffixInUse(Conf, Affix->flag))
2014  {
2015  bool issuffix = (Affix->type == FF_SUFFIX);
2016 
2017  if (ptr == Conf->CompoundAffix ||
2018  issuffix != (ptr - 1)->issuffix ||
2019  strbncmp((const unsigned char *) (ptr - 1)->affix,
2020  (const unsigned char *) Affix->repl,
2021  (ptr - 1)->len))
2022  {
2023  /* leave only unique and minimal suffixes */
2024  ptr->affix = Affix->repl;
2025  ptr->len = Affix->replen;
2026  ptr->issuffix = issuffix;
2027  ptr++;
2028  }
2029  }
2030  }
2031  ptr->affix = NULL;
2032  Conf->CompoundAffix = (CMPDAffix *) repalloc(Conf->CompoundAffix, sizeof(CMPDAffix) * (ptr - Conf->CompoundAffix + 1));
2033 
2034  /* Start build a prefix tree */
2035  Conf->Prefix = mkANode(Conf, 0, firstsuffix, 0, FF_PREFIX);
2036  Conf->Suffix = mkANode(Conf, firstsuffix, Conf->naffixes, 0, FF_SUFFIX);
2037  mkVoidAffix(Conf, true, firstsuffix);
2038  mkVoidAffix(Conf, false, firstsuffix);
2039 }
char * flag
Definition: spell.h:100
int naffixes
Definition: spell.h:193
uint32 flagflags
Definition: spell.h:102
AffixNode * Prefix
Definition: spell.h:197
AffixNode * Suffix
Definition: spell.h:196
uint32 type
Definition: spell.h:102
static int strbncmp(const unsigned char *s1, const unsigned char *s2, size_t count)
Definition: spell.c:279
static bool isAffixInUse(IspellDict *Conf, char *affixflag)
Definition: spell.c:1975
int len
Definition: spell.h:156
#define FF_SUFFIX
Definition: spell.h:127
static void mkVoidAffix(IspellDict *Conf, bool issuffix, int startsuffix)
Definition: spell.c:1921
AFFIX * Affix
Definition: spell.h:194
static AffixNode * mkANode(IspellDict *Conf, int low, int high, int level, int type)
Definition: spell.c:1844
char * affix
Definition: spell.h:155
bool issuffix
Definition: spell.h:157
#define FF_PREFIX
Definition: spell.h:128
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1182
CMPDAffix * CompoundAffix
Definition: spell.h:206
void * palloc(Size size)
Definition: mcxt.c:1062
int i
char * repl
Definition: spell.h:108
#define FF_COMPOUNDFLAG
Definition: spell.h:46
#define qsort(a, b, c, d)
Definition: port.h:504
uint32 replen
Definition: spell.h:102
static int cmpaffix(const void *s1, const void *s2)
Definition: spell.c:310

◆ NISortDictionary()

void NISortDictionary ( IspellDict Conf)

Definition at line 1736 of file spell.c.

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().

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

◆ NIStartBuild()

void NIStartBuild ( IspellDict Conf)

Definition at line 87 of file spell.c.

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

Referenced by dispell_init().

88 {
89  /*
90  * The temp context is a child of CurTransactionContext, so that it will
91  * go away automatically on error.
92  */
94  "Ispell dictionary init context",
96 }
MemoryContext buildCxt
Definition: spell.h:226
#define AllocSetContextCreate
Definition: memutils.h:173
MemoryContext CurTransactionContext
Definition: mcxt.c:54
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195

◆ NormalizeSubWord()

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

Definition at line 2190 of file spell.c.

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

Referenced by NINormalizeWord(), and SplitToVariants().

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

◆ parse_affentry()

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

Definition at line 932 of file spell.c.

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

Referenced by NIImportAffixes().

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

◆ parse_ooaffentry()

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

Definition at line 876 of file spell.c.

References elog, ERROR, get_nextfield(), PAE_WAIT_FIND, PAE_WAIT_FLAG, PAE_WAIT_MASK, PAE_WAIT_REPL, and PAE_WAIT_TYPE.

Referenced by NIImportOOAffixes().

878 {
879  int state = PAE_WAIT_TYPE;
880  int fields_read = 0;
881  bool valid = false;
882 
883  *type = *flag = *find = *repl = *mask = '\0';
884 
885  while (*str)
886  {
887  switch (state)
888  {
889  case PAE_WAIT_TYPE:
890  valid = get_nextfield(&str, type);
891  state = PAE_WAIT_FLAG;
892  break;
893  case PAE_WAIT_FLAG:
894  valid = get_nextfield(&str, flag);
895  state = PAE_WAIT_FIND;
896  break;
897  case PAE_WAIT_FIND:
898  valid = get_nextfield(&str, find);
899  state = PAE_WAIT_REPL;
900  break;
901  case PAE_WAIT_REPL:
902  valid = get_nextfield(&str, repl);
903  state = PAE_WAIT_MASK;
904  break;
905  case PAE_WAIT_MASK:
906  valid = get_nextfield(&str, mask);
907  state = -1; /* force loop exit */
908  break;
909  default:
910  elog(ERROR, "unrecognized state in parse_ooaffentry: %d",
911  state);
912  break;
913  }
914  if (valid)
915  fields_read++;
916  else
917  break; /* early EOL */
918  if (state < 0)
919  break; /* got all fields */
920  }
921 
922  return fields_read;
923 }
static int find(struct vars *, struct cnfa *, struct colormap *)
Definition: regexec.c:393
#define PAE_WAIT_TYPE
Definition: spell.c:796
#define PAE_WAIT_FLAG
Definition: spell.c:797
#define ERROR
Definition: elog.h:46
char * flag(int b)
Definition: test-ctype.c:33
static bool get_nextfield(char **str, char *next)
Definition: spell.c:810
Definition: regguts.h:317
#define PAE_WAIT_FIND
Definition: spell.c:792
#define elog(elevel,...)
Definition: elog.h:232
#define PAE_WAIT_MASK
Definition: spell.c:790
#define PAE_WAIT_REPL
Definition: spell.c:794

◆ regex_affix_deletion_callback()

static void regex_affix_deletion_callback ( void *  arg)
static

Definition at line 661 of file spell.c.

References pg_regfree(), and aff_regex_struct::regex.

Referenced by NIAddAffix().

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

◆ setCompoundAffixFlagValue()

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

Definition at line 1050 of file spell.c.

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().

1052 {
1053  if (Conf->flagMode == FM_NUM)
1054  {
1055  char *next;
1056  int i;
1057 
1058  i = strtol(s, &next, 10);
1059  if (s == next || errno == ERANGE)
1060  ereport(ERROR,
1061  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1062  errmsg("invalid affix flag \"%s\"", s)));
1063  if (i < 0 || i > FLAGNUM_MAXSIZE)
1064  ereport(ERROR,
1065  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1066  errmsg("affix flag \"%s\" is out of range", s)));
1067 
1068  entry->flag.i = i;
1069  }
1070  else
1071  entry->flag.s = cpstrdup(Conf, s);
1072 
1073  entry->flagMode = Conf->flagMode;
1074  entry->value = val;
1075 }
static int32 next
Definition: blutils.c:219
int errcode(int sqlerrcode)
Definition: elog.c:698
#define FLAGNUM_MAXSIZE
Definition: spell.h:188
union CompoundAffixFlag::@119 flag
uint32 value
Definition: spell.h:185
#define ERROR
Definition: elog.h:46
Definition: spell.h:167
FlagMode flagMode
Definition: spell.h:184
#define ereport(elevel,...)
Definition: elog.h:157
int errmsg(const char *fmt,...)
Definition: elog.c:909
static char * cpstrdup(IspellDict *Conf, const char *str)
Definition: spell.c:161
int i
long val
Definition: informix.c:664
FlagMode flagMode
Definition: spell.h:209

◆ SplitToVariants()

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

Definition at line 2388 of file spell.c.

References AddStem(), buf, 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, and SPNodeData::val.

Referenced by NINormalizeWord().

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

◆ strbcmp()

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

Definition at line 256 of file spell.c.

Referenced by cmpaffix().

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

◆ strbncmp()

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

Definition at line 279 of file spell.c.

Referenced by NISortAffixes().

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

Variable Documentation

◆ VoidString

char* VoidString = ""
static

Definition at line 193 of file spell.c.

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