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

Referenced by parse_affentry().

◆ PAE_INMASK

#define PAE_INMASK   1

Definition at line 765 of file spell.c.

Referenced by get_nextfield(), and parse_affentry().

◆ PAE_INREPL

#define PAE_INREPL   5

Definition at line 769 of file spell.c.

Referenced by parse_affentry().

◆ PAE_WAIT_FIND

#define PAE_WAIT_FIND   2

Definition at line 766 of file spell.c.

Referenced by parse_affentry(), and parse_ooaffentry().

◆ PAE_WAIT_FLAG

#define PAE_WAIT_FLAG   7

Definition at line 771 of file spell.c.

Referenced by parse_ooaffentry().

◆ PAE_WAIT_MASK

#define PAE_WAIT_MASK   0

Definition at line 764 of file spell.c.

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

◆ PAE_WAIT_REPL

#define PAE_WAIT_REPL   4

Definition at line 768 of file spell.c.

Referenced by parse_affentry(), and parse_ooaffentry().

◆ PAE_WAIT_TYPE

#define PAE_WAIT_TYPE   6

Definition at line 770 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 1059 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().

1060 {
1061  CompoundAffixFlag *newValue;
1062  char sbuf[BUFSIZ];
1063  char *sflag;
1064  int clen;
1065 
1066  while (*s && t_isspace(s))
1067  s += pg_mblen(s);
1068 
1069  if (!*s)
1070  ereport(ERROR,
1071  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1072  errmsg("syntax error")));
1073 
1074  /* Get flag without \n */
1075  sflag = sbuf;
1076  while (*s && !t_isspace(s) && *s != '\n')
1077  {
1078  clen = pg_mblen(s);
1079  COPYCHAR(sflag, s);
1080  sflag += clen;
1081  s += clen;
1082  }
1083  *sflag = '\0';
1084 
1085  /* Resize array or allocate memory for array CompoundAffixFlag */
1086  if (Conf->nCompoundAffixFlag >= Conf->mCompoundAffixFlag)
1087  {
1088  if (Conf->mCompoundAffixFlag)
1089  {
1090  Conf->mCompoundAffixFlag *= 2;
1092  repalloc((void *) Conf->CompoundAffixFlags,
1093  Conf->mCompoundAffixFlag * sizeof(CompoundAffixFlag));
1094  }
1095  else
1096  {
1097  Conf->mCompoundAffixFlag = 10;
1100  }
1101  }
1102 
1103  newValue = Conf->CompoundAffixFlags + Conf->nCompoundAffixFlag;
1104 
1105  setCompoundAffixFlagValue(Conf, newValue, sbuf, val);
1106 
1107  Conf->usecompound = true;
1108  Conf->nCompoundAffixFlag++;
1109 }
#define COPYCHAR(d, s)
Definition: ts_locale.h:47
bool usecompound
Definition: spell.h:197
#define tmpalloc(sz)
Definition: spell.c:78
int errcode(int sqlerrcode)
Definition: elog.c:608
#define ERROR
Definition: elog.h:43
int t_isspace(const char *ptr)
Definition: ts_locale.c:52
#define ereport(elevel, rest)
Definition: elog.h:141
static void setCompoundAffixFlagValue(IspellDict *Conf, CompoundAffixFlag *entry, char *s, uint32 val)
Definition: spell.c:1024
struct CompoundAffixFlag CompoundAffixFlag
CompoundAffixFlag * CompoundAffixFlags
Definition: spell.h:205
int pg_mblen(const char *mbstr)
Definition: mbutils.c:802
int mCompoundAffixFlag
Definition: spell.h:209
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
int errmsg(const char *fmt,...)
Definition: elog.c:822
int nCompoundAffixFlag
Definition: spell.h:207
long val
Definition: informix.c:664

◆ addNorm()

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

Definition at line 2509 of file spell.c.

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

Referenced by NINormalizeWord().

2510 {
2511  if (*lres == NULL)
2512  *lcur = *lres = (TSLexeme *) palloc(MAX_NORM * sizeof(TSLexeme));
2513 
2514  if (*lcur - *lres < MAX_NORM - 1)
2515  {
2516  (*lcur)->lexeme = word;
2517  (*lcur)->flags = flags;
2518  (*lcur)->nvariant = NVariant;
2519  (*lcur)++;
2520  (*lcur)->lexeme = NULL;
2521  }
2522 }
#define MAX_NORM
Definition: spell.c:186
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1246
void * palloc(Size size)
Definition: mcxt.c:949

◆ AddStem()

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

Definition at line 2349 of file spell.c.

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

Referenced by SplitToVariants().

2350 {
2351  if (v->nstem >= v->lenstem)
2352  {
2353  v->lenstem *= 2;
2354  v->stem = (char **) repalloc(v->stem, sizeof(char *) * v->lenstem);
2355  }
2356 
2357  v->stem[v->nstem] = word;
2358  v->nstem++;
2359 }
int nstem
Definition: spell.c:2275
char ** stem
Definition: spell.c:2277
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1246
int lenstem
Definition: spell.c:2276

◆ addToResult()

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

Definition at line 2149 of file spell.c.

References MAX_NORM, and pstrdup().

Referenced by NormalizeSubWord().

2150 {
2151  if (cur - forms >= MAX_NORM - 1)
2152  return 0;
2153  if (forms == cur || strcmp(word, *(cur - 1)) != 0)
2154  {
2155  *cur = pstrdup(word);
2156  *(cur + 1) = NULL;
2157  return 1;
2158  }
2159 
2160  return 0;
2161 }
char * pstrdup(const char *in)
Definition: mcxt.c:1186
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:1246

◆ CheckAffix()

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

Definition at line 2059 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::reg, aff_struct::regex, aff_struct::regis, aff_struct::replen, RS_execute(), and aff_struct::type.

Referenced by NormalizeSubWord().

2060 {
2061  /*
2062  * Check compound allow flags
2063  */
2064 
2065  if (flagflags == 0)
2066  {
2067  if (Affix->flagflags & FF_COMPOUNDONLY)
2068  return NULL;
2069  }
2070  else if (flagflags & FF_COMPOUNDBEGIN)
2071  {
2072  if (Affix->flagflags & FF_COMPOUNDFORBIDFLAG)
2073  return NULL;
2074  if ((Affix->flagflags & FF_COMPOUNDBEGIN) == 0)
2075  if (Affix->type == FF_SUFFIX)
2076  return NULL;
2077  }
2078  else if (flagflags & FF_COMPOUNDMIDDLE)
2079  {
2080  if ((Affix->flagflags & FF_COMPOUNDMIDDLE) == 0 ||
2081  (Affix->flagflags & FF_COMPOUNDFORBIDFLAG))
2082  return NULL;
2083  }
2084  else if (flagflags & FF_COMPOUNDLAST)
2085  {
2086  if (Affix->flagflags & FF_COMPOUNDFORBIDFLAG)
2087  return NULL;
2088  if ((Affix->flagflags & FF_COMPOUNDLAST) == 0)
2089  if (Affix->type == FF_PREFIX)
2090  return NULL;
2091  }
2092 
2093  /*
2094  * make replace pattern of affix
2095  */
2096  if (Affix->type == FF_SUFFIX)
2097  {
2098  strcpy(newword, word);
2099  strcpy(newword + len - Affix->replen, Affix->find);
2100  if (baselen) /* store length of non-changed part of word */
2101  *baselen = len - Affix->replen;
2102  }
2103  else
2104  {
2105  /*
2106  * if prefix is an all non-changed part's length then all word
2107  * contains only prefix and suffix, so out
2108  */
2109  if (baselen && *baselen + strlen(Affix->find) <= Affix->replen)
2110  return NULL;
2111  strcpy(newword, Affix->find);
2112  strcat(newword, word + Affix->replen);
2113  }
2114 
2115  /*
2116  * check resulting word
2117  */
2118  if (Affix->issimple)
2119  return newword;
2120  else if (Affix->isregis)
2121  {
2122  if (RS_execute(&(Affix->reg.regis), newword))
2123  return newword;
2124  }
2125  else
2126  {
2127  int err;
2128  pg_wchar *data;
2129  size_t data_len;
2130  int newword_len;
2131 
2132  /* Convert data string to wide characters */
2133  newword_len = strlen(newword);
2134  data = (pg_wchar *) palloc((newword_len + 1) * sizeof(pg_wchar));
2135  data_len = pg_mb2wchar_with_len(newword, data, newword_len);
2136 
2137  if (!(err = pg_regexec(&(Affix->reg.regex), data, data_len, 0, NULL, 0, NULL, 0)))
2138  {
2139  pfree(data);
2140  return newword;
2141  }
2142  pfree(data);
2143  }
2144 
2145  return NULL;
2146 }
#define FF_COMPOUNDONLY
Definition: spell.h:42
uint32 flagflags
Definition: spell.h:91
uint32 type
Definition: spell.h:91
#define FF_COMPOUNDLAST
Definition: spell.h:45
#define FF_COMPOUNDMIDDLE
Definition: spell.h:44
uint32 isregis
Definition: spell.h:91
#define FF_COMPOUNDBEGIN
Definition: spell.h:43
Regis regis
Definition: spell.h:101
void pfree(void *pointer)
Definition: mcxt.c:1056
#define FF_SUFFIX
Definition: spell.h:116
bool RS_execute(Regis *r, char *str)
Definition: regis.c:213
uint32 issimple
Definition: spell.h:91
unsigned int pg_wchar
Definition: mbprint.c:31
char * find
Definition: spell.h:96
int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
Definition: mbutils.c:765
union aff_struct::@121 reg
regex_t regex
Definition: spell.h:100
#define FF_PREFIX
Definition: spell.h:117
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1246
#define FF_COMPOUNDFORBIDFLAG
Definition: spell.h:109
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:172
void * palloc(Size size)
Definition: mcxt.c:949
uint32 replen
Definition: spell.h:91

◆ CheckCompoundAffixes()

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

Definition at line 2282 of file spell.c.

References word().

Referenced by SplitToVariants().

2283 {
2284  bool issuffix;
2285 
2286  /* in case CompoundAffix is null: */
2287  if (*ptr == NULL)
2288  return -1;
2289 
2290  if (CheckInPlace)
2291  {
2292  while ((*ptr)->affix)
2293  {
2294  if (len > (*ptr)->len && strncmp((*ptr)->affix, word, (*ptr)->len) == 0)
2295  {
2296  len = (*ptr)->len;
2297  issuffix = (*ptr)->issuffix;
2298  (*ptr)++;
2299  return (issuffix) ? len : 0;
2300  }
2301  (*ptr)++;
2302  }
2303  }
2304  else
2305  {
2306  char *affbegin;
2307 
2308  while ((*ptr)->affix)
2309  {
2310  if (len > (*ptr)->len && (affbegin = strstr(word, (*ptr)->affix)) != NULL)
2311  {
2312  len = (*ptr)->len + (affbegin - word);
2313  issuffix = (*ptr)->issuffix;
2314  (*ptr)++;
2315  return (issuffix) ? len : 0;
2316  }
2317  (*ptr)++;
2318  }
2319  }
2320  return -1;
2321 }
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1246

◆ 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:91
static const FormData_pg_attribute a2
Definition: heap.c:166
char * s1
char * s2
#define FF_PREFIX
Definition: spell.h:117
char * repl
Definition: spell.h:97
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, CompoundAffixFlag::flag, CompoundAffixFlag::flagMode, FM_NUM, CompoundAffixFlag::i, and CompoundAffixFlag::s.

Referenced by getCompoundAffixFlagValue(), and NIImportOOAffixes().

210 {
211  CompoundAffixFlag *fv1 = (CompoundAffixFlag *) f1,
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 }
Definition: spell.h:156
union CompoundAffixFlag::@122 flag
FlagMode flagMode
Definition: spell.h:173
#define Assert(condition)
Definition: c.h:739

◆ 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:1246

◆ 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:215
size_t avail
Definition: spell.h:224
void * palloc0(Size size)
Definition: mcxt.c:980
#define COMPACT_ALLOC_CHUNK
Definition: spell.c:125
#define Assert(condition)
Definition: c.h:739
#define MAXALIGN(LEN)
Definition: c.h:692
char * firstfree
Definition: spell.h:223
#define COMPACT_MAX_REQ
Definition: spell.c:126

◆ CopyVar()

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

Definition at line 2324 of file spell.c.

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

Referenced by SplitToVariants().

2325 {
2326  SplitVar *v = (SplitVar *) palloc(sizeof(SplitVar));
2327 
2328  v->next = NULL;
2329  if (s)
2330  {
2331  int i;
2332 
2333  v->lenstem = s->lenstem;
2334  v->stem = (char **) palloc(sizeof(char *) * v->lenstem);
2335  v->nstem = s->nstem;
2336  for (i = 0; i < s->nstem; i++)
2337  v->stem[i] = (makedup) ? pstrdup(s->stem[i]) : s->stem[i];
2338  }
2339  else
2340  {
2341  v->lenstem = 16;
2342  v->stem = (char **) palloc(sizeof(char *) * v->lenstem);
2343  v->nstem = 0;
2344  }
2345  return v;
2346 }
char * pstrdup(const char *in)
Definition: mcxt.c:1186
int nstem
Definition: spell.c:2275
char ** stem
Definition: spell.c:2277
int lenstem
Definition: spell.c:2276
void * palloc(Size size)
Definition: mcxt.c:949
int i
struct SplitVar * next
Definition: spell.c:2278

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

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

Referenced by NormalizeSubWord().

2017 {
2018  AffixNodeData *StopLow,
2019  *StopHigh,
2020  *StopMiddle;
2021  uint8 symbol;
2022 
2023  if (node->isvoid)
2024  { /* search void affixes */
2025  if (node->data->naff)
2026  return node->data;
2027  node = node->data->node;
2028  }
2029 
2030  while (node && *level < wrdlen)
2031  {
2032  StopLow = node->data;
2033  StopHigh = node->data + node->length;
2034  while (StopLow < StopHigh)
2035  {
2036  StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
2037  symbol = GETWCHAR(word, wrdlen, *level, type);
2038 
2039  if (StopMiddle->val == symbol)
2040  {
2041  (*level)++;
2042  if (StopMiddle->naff)
2043  return StopMiddle;
2044  node = StopMiddle->node;
2045  break;
2046  }
2047  else if (StopMiddle->val < symbol)
2048  StopLow = StopMiddle + 1;
2049  else
2050  StopHigh = StopMiddle;
2051  }
2052  if (StopLow >= StopHigh)
2053  break;
2054  }
2055  return NULL;
2056 }
uint32 length
Definition: spell.h:135
struct AffixNode * node
Definition: spell.h:130
AffixNodeData data[FLEXIBLE_ARRAY_MEMBER]
Definition: spell.h:137
unsigned char uint8
Definition: c.h:357
#define GETWCHAR(W, L, N, T)
Definition: spell.c:190
uint32 val
Definition: spell.h:127
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1246
uint32 naff
Definition: spell.h:127
uint32 isvoid
Definition: spell.h:135
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:45
int pg_mblen(const char *mbstr)
Definition: mbutils.c:802

◆ 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:45
int pg_mblen(const char *mbstr)
Definition: mbutils.c:802

◆ 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:357
uint32 length
Definition: spell.h:52
uint32 isword
Definition: spell.h:29
struct SPNode * node
Definition: spell.h:35
SPNode * Dictionary
Definition: spell.h:188
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:1246
uint32 affix
Definition: spell.h:29

◆ get_nextfield()

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

Definition at line 784 of file spell.c.

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

Referenced by parse_ooaffentry().

785 {
786  int state = PAE_WAIT_MASK;
787  int avail = BUFSIZ;
788 
789  while (**str)
790  {
791  if (state == PAE_WAIT_MASK)
792  {
793  if (t_iseq(*str, '#'))
794  return false;
795  else if (!t_isspace(*str))
796  {
797  int clen = pg_mblen(*str);
798 
799  if (clen < avail)
800  {
801  COPYCHAR(next, *str);
802  next += clen;
803  avail -= clen;
804  }
805  state = PAE_INMASK;
806  }
807  }
808  else /* state == PAE_INMASK */
809  {
810  if (t_isspace(*str))
811  {
812  *next = '\0';
813  return true;
814  }
815  else
816  {
817  int clen = pg_mblen(*str);
818 
819  if (clen < avail)
820  {
821  COPYCHAR(next, *str);
822  next += clen;
823  avail -= clen;
824  }
825  }
826  }
827  *str += pg_mblen(*str);
828  }
829 
830  *next = '\0';
831 
832  return (state == PAE_INMASK); /* OK if we got a nonempty field */
833 }
#define COPYCHAR(d, s)
Definition: ts_locale.h:47
static int32 next
Definition: blutils.c:213
int t_isspace(const char *ptr)
Definition: ts_locale.c:52
#define t_iseq(x, c)
Definition: ts_locale.h:45
#define PAE_INMASK
Definition: spell.c:765
Definition: regguts.h:298
int pg_mblen(const char *mbstr)
Definition: mbutils.c:802
#define PAE_WAIT_MASK
Definition: spell.c:764

◆ getAffixFlagSet()

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

Definition at line 1152 of file spell.c.

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

Referenced by NIImportOOAffixes().

1153 {
1154  if (Conf->useFlagAliases && *s != '\0')
1155  {
1156  int curaffix;
1157  char *end;
1158 
1159  curaffix = strtol(s, &end, 10);
1160  if (s == end || errno == ERANGE)
1161  ereport(ERROR,
1162  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1163  errmsg("invalid affix alias \"%s\"", s)));
1164 
1165  if (curaffix > 0 && curaffix < Conf->nAffixData)
1166 
1167  /*
1168  * Do not subtract 1 from curaffix because empty string was added
1169  * in NIImportOOAffixes
1170  */
1171  return Conf->AffixData[curaffix];
1172  else if (curaffix > Conf->nAffixData)
1173  ereport(ERROR,
1174  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1175  errmsg("invalid affix alias \"%s\"", s)));
1176  return VoidString;
1177  }
1178  else
1179  return s;
1180 }
int nAffixData
Definition: spell.h:192
bool useFlagAliases
Definition: spell.h:193
int errcode(int sqlerrcode)
Definition: elog.c:608
#define ERROR
Definition: elog.h:43
char ** AffixData
Definition: spell.h:190
#define ereport(elevel, rest)
Definition: elog.h:141
int errmsg(const char *fmt,...)
Definition: elog.c:822
static char * VoidString
Definition: spell.c:193

◆ getCompoundAffixFlagValue()

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

Definition at line 1116 of file spell.c.

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

Referenced by makeCompoundFlags(), and NIImportOOAffixes().

1117 {
1118  uint32 flag = 0;
1119  CompoundAffixFlag *found,
1120  key;
1121  char sflag[BUFSIZ];
1122  char *flagcur;
1123 
1124  if (Conf->nCompoundAffixFlag == 0)
1125  return 0;
1126 
1127  flagcur = s;
1128  while (*flagcur)
1129  {
1130  getNextFlagFromString(Conf, &flagcur, sflag);
1131  setCompoundAffixFlagValue(Conf, &key, sflag, 0);
1132 
1133  found = (CompoundAffixFlag *)
1134  bsearch(&key, (void *) Conf->CompoundAffixFlags,
1135  Conf->nCompoundAffixFlag, sizeof(CompoundAffixFlag),
1136  cmpcmdflag);
1137  if (found != NULL)
1138  flag |= found->value;
1139  }
1140 
1141  return flag;
1142 }
static void getNextFlagFromString(IspellDict *Conf, char **sflagset, char *sflag)
Definition: spell.c:348
uint32 value
Definition: spell.h:174
char * flag(int b)
Definition: test-ctype.c:33
unsigned int uint32
Definition: c.h:359
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:1024
struct CompoundAffixFlag CompoundAffixFlag
CompoundAffixFlag * CompoundAffixFlags
Definition: spell.h:205
int nCompoundAffixFlag
Definition: spell.h:207

◆ 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:47
static int32 next
Definition: blutils.c:213
Definition: spell.h:154
int errcode(int sqlerrcode)
Definition: elog.c:608
#define FLAGNUM_MAXSIZE
Definition: spell.h:177
signed int int32
Definition: c.h:347
int t_isdigit(const char *ptr)
Definition: ts_locale.c:36
#define sprintf
Definition: port.h:194
#define ERROR
Definition: elog.h:43
int t_isspace(const char *ptr)
Definition: ts_locale.c:52
Definition: spell.h:156
#define t_iseq(x, c)
Definition: ts_locale.h:45
#define ereport(elevel, rest)
Definition: elog.h:141
int pg_mblen(const char *mbstr)
Definition: mbutils.c:802
Definition: spell.h:155
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
FlagMode flagMode
Definition: spell.h:198

◆ 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:190
char * flag(int b)
Definition: test-ctype.c:33
#define Assert(condition)
Definition: c.h:739

◆ isAffixInUse()

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

Definition at line 1949 of file spell.c.

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

Referenced by NISortAffixes().

1950 {
1951  int i;
1952 
1953  for (i = 0; i < Conf->nAffixData; i++)
1954  if (IsAffixFlagInUse(Conf, i, affixflag))
1955  return true;
1956 
1957  return false;
1958 }
int nAffixData
Definition: spell.h:192
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:215
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
char * lowerstr(const char *str)
Definition: ts_locale.c:239

◆ makeCompoundFlags()

static uint32 makeCompoundFlags ( IspellDict Conf,
int  affix 
)
static

Definition at line 1611 of file spell.c.

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

Referenced by mkSPNode().

1612 {
1613  Assert(affix < Conf->nAffixData);
1614 
1615  return (getCompoundAffixFlagValue(Conf, Conf->AffixData[affix]) &
1617 }
static int getCompoundAffixFlagValue(IspellDict *Conf, char *s)
Definition: spell.c:1116
char ** AffixData
Definition: spell.h:190
#define FF_COMPOUNDFLAGMASK
Definition: spell.h:48
#define Assert(condition)
Definition: c.h:739

◆ MergeAffix()

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

Definition at line 1565 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().

1566 {
1567  char **ptr;
1568 
1569  Assert(a1 < Conf->nAffixData && a2 < Conf->nAffixData);
1570 
1571  /* Do not merge affix flags if one of affix flags is empty */
1572  if (*Conf->AffixData[a1] == '\0')
1573  return a2;
1574  else if (*Conf->AffixData[a2] == '\0')
1575  return a1;
1576 
1577  while (Conf->nAffixData + 1 >= Conf->lenAffixData)
1578  {
1579  Conf->lenAffixData *= 2;
1580  Conf->AffixData = (char **) repalloc(Conf->AffixData,
1581  sizeof(char *) * Conf->lenAffixData);
1582  }
1583 
1584  ptr = Conf->AffixData + Conf->nAffixData;
1585  if (Conf->flagMode == FM_NUM)
1586  {
1587  *ptr = cpalloc(strlen(Conf->AffixData[a1]) +
1588  strlen(Conf->AffixData[a2]) +
1589  1 /* comma */ + 1 /* \0 */ );
1590  sprintf(*ptr, "%s,%s", Conf->AffixData[a1], Conf->AffixData[a2]);
1591  }
1592  else
1593  {
1594  *ptr = cpalloc(strlen(Conf->AffixData[a1]) +
1595  strlen(Conf->AffixData[a2]) +
1596  1 /* \0 */ );
1597  sprintf(*ptr, "%s%s", Conf->AffixData[a1], Conf->AffixData[a2]);
1598  }
1599  ptr++;
1600  *ptr = NULL;
1601  Conf->nAffixData++;
1602 
1603  return Conf->nAffixData - 1;
1604 }
int nAffixData
Definition: spell.h:192
int lenAffixData
Definition: spell.h:191
#define sprintf
Definition: port.h:194
static const FormData_pg_attribute a2
Definition: heap.c:166
char ** AffixData
Definition: spell.h:190
Definition: spell.h:156
#define Assert(condition)
Definition: c.h:739
#define cpalloc(size)
Definition: spell.c:157
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
static const FormData_pg_attribute a1
Definition: heap.c:152
FlagMode flagMode
Definition: spell.h:198

◆ mkANode()

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

Definition at line 1818 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().

1819 {
1820  int i;
1821  int nchar = 0;
1822  uint8 lastchar = '\0';
1823  AffixNode *rs;
1824  AffixNodeData *data;
1825  int lownew = low;
1826  int naff;
1827  AFFIX **aff;
1828 
1829  for (i = low; i < high; i++)
1830  if (Conf->Affix[i].replen > level && lastchar != GETCHAR(Conf->Affix + i, level, type))
1831  {
1832  nchar++;
1833  lastchar = GETCHAR(Conf->Affix + i, level, type);
1834  }
1835 
1836  if (!nchar)
1837  return NULL;
1838 
1839  aff = (AFFIX **) tmpalloc(sizeof(AFFIX *) * (high - low + 1));
1840  naff = 0;
1841 
1842  rs = (AffixNode *) cpalloc0(ANHRDSZ + nchar * sizeof(AffixNodeData));
1843  rs->length = nchar;
1844  data = rs->data;
1845 
1846  lastchar = '\0';
1847  for (i = low; i < high; i++)
1848  if (Conf->Affix[i].replen > level)
1849  {
1850  if (lastchar != GETCHAR(Conf->Affix + i, level, type))
1851  {
1852  if (lastchar)
1853  {
1854  /* Next level of the prefix tree */
1855  data->node = mkANode(Conf, lownew, i, level + 1, type);
1856  if (naff)
1857  {
1858  data->naff = naff;
1859  data->aff = (AFFIX **) cpalloc(sizeof(AFFIX *) * naff);
1860  memcpy(data->aff, aff, sizeof(AFFIX *) * naff);
1861  naff = 0;
1862  }
1863  data++;
1864  lownew = i;
1865  }
1866  lastchar = GETCHAR(Conf->Affix + i, level, type);
1867  }
1868  data->val = GETCHAR(Conf->Affix + i, level, type);
1869  if (Conf->Affix[i].replen == level + 1)
1870  { /* affix stopped */
1871  aff[naff++] = Conf->Affix + i;
1872  }
1873  }
1874 
1875  /* Next level of the prefix tree */
1876  data->node = mkANode(Conf, lownew, high, level + 1, type);
1877  if (naff)
1878  {
1879  data->naff = naff;
1880  data->aff = (AFFIX **) cpalloc(sizeof(AFFIX *) * naff);
1881  memcpy(data->aff, aff, sizeof(AFFIX *) * naff);
1882  naff = 0;
1883  }
1884 
1885  pfree(aff);
1886 
1887  return rs;
1888 }
uint32 length
Definition: spell.h:135
struct AffixNode * node
Definition: spell.h:130
AffixNodeData data[FLEXIBLE_ARRAY_MEMBER]
Definition: spell.h:137
AFFIX ** aff
Definition: spell.h:129
#define tmpalloc(sz)
Definition: spell.c:78
unsigned char uint8
Definition: c.h:357
#define ANHRDSZ
Definition: spell.h:140
void pfree(void *pointer)
Definition: mcxt.c:1056
#define GETCHAR(A, N, T)
Definition: spell.c:191
#define cpalloc0(size)
Definition: spell.c:158
uint32 val
Definition: spell.h:127
AFFIX * Affix
Definition: spell.h:183
static AffixNode * mkANode(IspellDict *Conf, int low, int high, int level, int type)
Definition: spell.c:1818
#define cpalloc(size)
Definition: spell.c:157
uint32 naff
Definition: spell.h:127
int i
uint32 replen
Definition: spell.h:91

◆ mkSPNode()

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

Definition at line 1628 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().

1629 {
1630  int i;
1631  int nchar = 0;
1632  char lastchar = '\0';
1633  SPNode *rs;
1634  SPNodeData *data;
1635  int lownew = low;
1636 
1637  for (i = low; i < high; i++)
1638  if (Conf->Spell[i]->p.d.len > level && lastchar != Conf->Spell[i]->word[level])
1639  {
1640  nchar++;
1641  lastchar = Conf->Spell[i]->word[level];
1642  }
1643 
1644  if (!nchar)
1645  return NULL;
1646 
1647  rs = (SPNode *) cpalloc0(SPNHDRSZ + nchar * sizeof(SPNodeData));
1648  rs->length = nchar;
1649  data = rs->data;
1650 
1651  lastchar = '\0';
1652  for (i = low; i < high; i++)
1653  if (Conf->Spell[i]->p.d.len > level)
1654  {
1655  if (lastchar != Conf->Spell[i]->word[level])
1656  {
1657  if (lastchar)
1658  {
1659  /* Next level of the prefix tree */
1660  data->node = mkSPNode(Conf, lownew, i, level + 1);
1661  lownew = i;
1662  data++;
1663  }
1664  lastchar = Conf->Spell[i]->word[level];
1665  }
1666  data->val = ((uint8 *) (Conf->Spell[i]->word))[level];
1667  if (Conf->Spell[i]->p.d.len == level + 1)
1668  {
1669  bool clearCompoundOnly = false;
1670 
1671  if (data->isword && data->affix != Conf->Spell[i]->p.d.affix)
1672  {
1673  /*
1674  * MergeAffix called a few times. If one of word is
1675  * allowed to be in compound word and another isn't, then
1676  * clear FF_COMPOUNDONLY flag.
1677  */
1678 
1679  clearCompoundOnly = (FF_COMPOUNDONLY & data->compoundflag
1680  & makeCompoundFlags(Conf, Conf->Spell[i]->p.d.affix))
1681  ? false : true;
1682  data->affix = MergeAffix(Conf, data->affix, Conf->Spell[i]->p.d.affix);
1683  }
1684  else
1685  data->affix = Conf->Spell[i]->p.d.affix;
1686  data->isword = 1;
1687 
1688  data->compoundflag = makeCompoundFlags(Conf, data->affix);
1689 
1690  if ((data->compoundflag & FF_COMPOUNDONLY) &&
1691  (data->compoundflag & FF_COMPOUNDFLAG) == 0)
1692  data->compoundflag |= FF_COMPOUNDFLAG;
1693 
1694  if (clearCompoundOnly)
1695  data->compoundflag &= ~FF_COMPOUNDONLY;
1696  }
1697  }
1698 
1699  /* Next level of the prefix tree */
1700  data->node = mkSPNode(Conf, lownew, high, level + 1);
1701 
1702  return rs;
1703 }
#define FF_COMPOUNDONLY
Definition: spell.h:42
struct spell_struct::@119::@120 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:1565
unsigned char uint8
Definition: c.h:357
static SPNode * mkSPNode(IspellDict *Conf, int low, int high, int level)
Definition: spell.c:1628
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:1611
char word[FLEXIBLE_ARRAY_MEMBER]
Definition: spell.h:79
SPELL ** Spell
Definition: spell.h:218
int i
union spell_struct::@119 p
#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 1895 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().

1896 {
1897  int i,
1898  cnt = 0;
1899  int start = (issuffix) ? startsuffix : 0;
1900  int end = (issuffix) ? Conf->naffixes : startsuffix;
1901  AffixNode *Affix = (AffixNode *) palloc0(ANHRDSZ + sizeof(AffixNodeData));
1902 
1903  Affix->length = 1;
1904  Affix->isvoid = 1;
1905 
1906  if (issuffix)
1907  {
1908  Affix->data->node = Conf->Suffix;
1909  Conf->Suffix = Affix;
1910  }
1911  else
1912  {
1913  Affix->data->node = Conf->Prefix;
1914  Conf->Prefix = Affix;
1915  }
1916 
1917  /* Count affixes with empty replace string */
1918  for (i = start; i < end; i++)
1919  if (Conf->Affix[i].replen == 0)
1920  cnt++;
1921 
1922  /* There is not affixes with empty replace string */
1923  if (cnt == 0)
1924  return;
1925 
1926  Affix->data->aff = (AFFIX **) cpalloc(sizeof(AFFIX *) * cnt);
1927  Affix->data->naff = (uint32) cnt;
1928 
1929  cnt = 0;
1930  for (i = start; i < end; i++)
1931  if (Conf->Affix[i].replen == 0)
1932  {
1933  Affix->data->aff[cnt] = Conf->Affix + i;
1934  cnt++;
1935  }
1936 }
int naffixes
Definition: spell.h:182
struct AffixNode * node
Definition: spell.h:130
AffixNodeData data[FLEXIBLE_ARRAY_MEMBER]
Definition: spell.h:137
AffixNode * Prefix
Definition: spell.h:186
AffixNode * Suffix
Definition: spell.h:185
AFFIX ** aff
Definition: spell.h:129
#define ANHRDSZ
Definition: spell.h:140
AFFIX * Affix
Definition: spell.h:183
unsigned int uint32
Definition: c.h:359
void * palloc0(Size size)
Definition: mcxt.c:980
#define cpalloc(size)
Definition: spell.c:157
int i
uint32 replen
Definition: spell.h:91

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

References IspellDict::Affix, cpstrdup(), ereport, errcode(), errmsg(), ERROR, FF_COMPOUNDFLAG, FF_COMPOUNDONLY, FF_COMPOUNDPERMITFLAG, FF_SUFFIX, aff_struct::find, find(), aff_struct::flag, aff_struct::flagflags, aff_struct::isregis, aff_struct::issimple, IspellDict::maffixes, IspellDict::naffixes, palloc(), pg_mb2wchar_with_len(), pg_regcomp(), pg_regerror(), aff_struct::reg, REG_ADVANCED, REG_NOSUB, aff_struct::regex, 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().

678 {
679  AFFIX *Affix;
680 
681  if (Conf->naffixes >= Conf->maffixes)
682  {
683  if (Conf->maffixes)
684  {
685  Conf->maffixes *= 2;
686  Conf->Affix = (AFFIX *) repalloc((void *) Conf->Affix, Conf->maffixes * sizeof(AFFIX));
687  }
688  else
689  {
690  Conf->maffixes = 16;
691  Conf->Affix = (AFFIX *) palloc(Conf->maffixes * sizeof(AFFIX));
692  }
693  }
694 
695  Affix = Conf->Affix + Conf->naffixes;
696 
697  /* This affix rule can be applied for words with any ending */
698  if (strcmp(mask, ".") == 0 || *mask == '\0')
699  {
700  Affix->issimple = 1;
701  Affix->isregis = 0;
702  }
703  /* This affix rule will use regis to search word ending */
704  else if (RS_isRegis(mask))
705  {
706  Affix->issimple = 0;
707  Affix->isregis = 1;
708  RS_compile(&(Affix->reg.regis), (type == FF_SUFFIX),
709  *mask ? mask : VoidString);
710  }
711  /* This affix rule will use regex_t to search word ending */
712  else
713  {
714  int masklen;
715  int wmasklen;
716  int err;
717  pg_wchar *wmask;
718  char *tmask;
719 
720  Affix->issimple = 0;
721  Affix->isregis = 0;
722  tmask = (char *) tmpalloc(strlen(mask) + 3);
723  if (type == FF_SUFFIX)
724  sprintf(tmask, "%s$", mask);
725  else
726  sprintf(tmask, "^%s", mask);
727 
728  masklen = strlen(tmask);
729  wmask = (pg_wchar *) tmpalloc((masklen + 1) * sizeof(pg_wchar));
730  wmasklen = pg_mb2wchar_with_len(tmask, wmask, masklen);
731 
732  err = pg_regcomp(&(Affix->reg.regex), wmask, wmasklen,
734  DEFAULT_COLLATION_OID);
735  if (err)
736  {
737  char errstr[100];
738 
739  pg_regerror(err, &(Affix->reg.regex), errstr, sizeof(errstr));
740  ereport(ERROR,
741  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
742  errmsg("invalid regular expression: %s", errstr)));
743  }
744  }
745 
746  Affix->flagflags = flagflags;
747  if ((Affix->flagflags & FF_COMPOUNDONLY) || (Affix->flagflags & FF_COMPOUNDPERMITFLAG))
748  {
749  if ((Affix->flagflags & FF_COMPOUNDFLAG) == 0)
750  Affix->flagflags |= FF_COMPOUNDFLAG;
751  }
752  Affix->flag = cpstrdup(Conf, flag);
753  Affix->type = type;
754 
755  Affix->find = (find && *find) ? cpstrdup(Conf, find) : VoidString;
756  if ((Affix->replen = strlen(repl)) > 0)
757  Affix->repl = cpstrdup(Conf, repl);
758  else
759  Affix->repl = VoidString;
760  Conf->naffixes++;
761 }
char * flag
Definition: spell.h:89
int naffixes
Definition: spell.h:182
#define FF_COMPOUNDONLY
Definition: spell.h:42
static int find(struct vars *, struct cnfa *, struct colormap *)
Definition: regexec.c:375
uint32 flagflags
Definition: spell.h:91
uint32 type
Definition: spell.h:91
#define tmpalloc(sz)
Definition: spell.c:78
int errcode(int sqlerrcode)
Definition: elog.c:608
uint32 isregis
Definition: spell.h:91
int pg_regcomp(regex_t *re, const chr *string, size_t len, int flags, Oid collation)
Definition: regcomp.c:313
Regis regis
Definition: spell.h:101
#define sprintf
Definition: port.h:194
#define ERROR
Definition: elog.h:43
#define FF_SUFFIX
Definition: spell.h:116
char * flag(int b)
Definition: test-ctype.c:33
uint32 issimple
Definition: spell.h:91
AFFIX * Affix
Definition: spell.h:183
struct aff_struct AFFIX
size_t pg_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
Definition: regerror.c:60
#define REG_ADVANCED
Definition: regex.h:103
#define ereport(elevel, rest)
Definition: elog.h:141
unsigned int pg_wchar
Definition: mbprint.c:31
char * find
Definition: spell.h:96
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:765
union aff_struct::@121 reg
regex_t regex
Definition: spell.h:100
#define REG_NOSUB
Definition: regex.h:107
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
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
char * repl
Definition: spell.h:97
#define FF_COMPOUNDFLAG
Definition: spell.h:46
int maffixes
Definition: spell.h:181
uint32 replen
Definition: spell.h:91
#define FF_COMPOUNDPERMITFLAG
Definition: spell.h:108

◆ 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:220
#define tmpalloc(sz)
Definition: spell.c:78
int nspell
Definition: spell.h:219
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:218
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1246
static char * VoidString
Definition: spell.c:193
static char * cpstrdup(IspellDict *Conf, const char *str)
Definition: spell.c:161
union spell_struct::@119 p

◆ 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:215
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
CompoundAffixFlag * CompoundAffixFlags
Definition: spell.h:205
char * firstfree
Definition: spell.h:223
SPELL ** Spell
Definition: spell.h:218

◆ NIImportAffixes()

void NIImportAffixes ( IspellDict Conf,
const char *  filename 
)

Definition at line 1418 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().

1419 {
1420  char *pstr = NULL;
1421  char flag[BUFSIZ];
1422  char mask[BUFSIZ];
1423  char find[BUFSIZ];
1424  char repl[BUFSIZ];
1425  char *s;
1426  bool suffixes = false;
1427  bool prefixes = false;
1428  char flagflags = 0;
1430  bool oldformat = false;
1431  char *recoded = NULL;
1432 
1433  if (!tsearch_readline_begin(&trst, filename))
1434  ereport(ERROR,
1435  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1436  errmsg("could not open affix file \"%s\": %m",
1437  filename)));
1438 
1439  Conf->usecompound = false;
1440  Conf->useFlagAliases = false;
1441  Conf->flagMode = FM_CHAR;
1442 
1443  while ((recoded = tsearch_readline(&trst)) != NULL)
1444  {
1445  pstr = lowerstr(recoded);
1446 
1447  /* Skip comments and empty lines */
1448  if (*pstr == '#' || *pstr == '\n')
1449  goto nextline;
1450 
1451  if (STRNCMP(pstr, "compoundwords") == 0)
1452  {
1453  /* Find case-insensitive L flag in non-lowercased string */
1454  s = findchar2(recoded, 'l', 'L');
1455  if (s)
1456  {
1457  while (*s && !t_isspace(s))
1458  s += pg_mblen(s);
1459  while (*s && t_isspace(s))
1460  s += pg_mblen(s);
1461 
1462  if (*s && pg_mblen(s) == 1)
1463  {
1465  Conf->usecompound = true;
1466  }
1467  oldformat = true;
1468  goto nextline;
1469  }
1470  }
1471  if (STRNCMP(pstr, "suffixes") == 0)
1472  {
1473  suffixes = true;
1474  prefixes = false;
1475  oldformat = true;
1476  goto nextline;
1477  }
1478  if (STRNCMP(pstr, "prefixes") == 0)
1479  {
1480  suffixes = false;
1481  prefixes = true;
1482  oldformat = true;
1483  goto nextline;
1484  }
1485  if (STRNCMP(pstr, "flag") == 0)
1486  {
1487  s = recoded + 4; /* we need non-lowercased string */
1488  flagflags = 0;
1489 
1490  while (*s && t_isspace(s))
1491  s += pg_mblen(s);
1492 
1493  if (*s == '*')
1494  {
1495  flagflags |= FF_CROSSPRODUCT;
1496  s++;
1497  }
1498  else if (*s == '~')
1499  {
1500  flagflags |= FF_COMPOUNDONLY;
1501  s++;
1502  }
1503 
1504  if (*s == '\\')
1505  s++;
1506 
1507  /*
1508  * An old-format flag is a single ASCII character; we expect it to
1509  * be followed by EOL, whitespace, or ':'. Otherwise this is a
1510  * new-format flag command.
1511  */
1512  if (*s && pg_mblen(s) == 1)
1513  {
1514  COPYCHAR(flag, s);
1515  flag[1] = '\0';
1516 
1517  s++;
1518  if (*s == '\0' || *s == '#' || *s == '\n' || *s == ':' ||
1519  t_isspace(s))
1520  {
1521  oldformat = true;
1522  goto nextline;
1523  }
1524  }
1525  goto isnewformat;
1526  }
1527  if (STRNCMP(recoded, "COMPOUNDFLAG") == 0 ||
1528  STRNCMP(recoded, "COMPOUNDMIN") == 0 ||
1529  STRNCMP(recoded, "PFX") == 0 ||
1530  STRNCMP(recoded, "SFX") == 0)
1531  goto isnewformat;
1532 
1533  if ((!suffixes) && (!prefixes))
1534  goto nextline;
1535 
1536  if (!parse_affentry(pstr, mask, find, repl))
1537  goto nextline;
1538 
1539  NIAddAffix(Conf, flag, flagflags, mask, find, repl, suffixes ? FF_SUFFIX : FF_PREFIX);
1540 
1541 nextline:
1542  pfree(recoded);
1543  pfree(pstr);
1544  }
1545  tsearch_readline_end(&trst);
1546  return;
1547 
1548 isnewformat:
1549  if (oldformat)
1550  ereport(ERROR,
1551  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1552  errmsg("affix file contains both old-style and new-style commands")));
1553  tsearch_readline_end(&trst);
1554 
1555  NIImportOOAffixes(Conf, filename);
1556 }
#define COPYCHAR(d, s)
Definition: ts_locale.h:47
#define FF_COMPOUNDONLY
Definition: spell.h:42
static int find(struct vars *, struct cnfa *, struct colormap *)
Definition: regexec.c:375
bool useFlagAliases
Definition: spell.h:193
bool usecompound
Definition: spell.h:197
Definition: spell.h:154
#define FF_CROSSPRODUCT
Definition: spell.h:110
int errcode(int sqlerrcode)
Definition: elog.c:608
static void NIImportOOAffixes(IspellDict *Conf, const char *filename)
Definition: spell.c:1189
char * lowerstr(const char *str)
Definition: ts_locale.c:239
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
static bool parse_affentry(char *str, char *mask, char *find, char *repl)
Definition: spell.c:906
#define FF_SUFFIX
Definition: spell.h:116
int t_isspace(const char *ptr)
Definition: ts_locale.c:52
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:676
char * flag(int b)
Definition: test-ctype.c:33
#define ereport(elevel, rest)
Definition: elog.h:141
#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:117
static void addCompoundAffixFlagValue(IspellDict *Conf, char *s, uint32 val)
Definition: spell.c:1059
int pg_mblen(const char *mbstr)
Definition: mbutils.c:802
void tsearch_readline_end(tsearch_readline_state *stp)
Definition: ts_locale.c:161
char * tsearch_readline(tsearch_readline_state *stp)
Definition: ts_locale.c:146
bool tsearch_readline_begin(tsearch_readline_state *stp, const char *filename)
Definition: ts_locale.c:124
static char * filename
Definition: pg_dumpall.c:90
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define FF_COMPOUNDFLAG
Definition: spell.h:46
FlagMode flagMode
Definition: spell.h:198

◆ 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:84
static char * findchar(char *str, int c)
Definition: spell.c:228
int errcode(int sqlerrcode)
Definition: elog.c:608
static void NIAddSpell(IspellDict *Conf, const char *word, const char *flag)
Definition: spell.c:485
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
int t_isspace(const char *ptr)
Definition: ts_locale.c:52
char * flag(int b)
Definition: test-ctype.c:33
#define ereport(elevel, rest)
Definition: elog.h:141
static char * lowerstr_ctx(IspellDict *Conf, const char *src)
Definition: spell.c:174
int pg_mblen(const char *mbstr)
Definition: mbutils.c:802
void tsearch_readline_end(tsearch_readline_state *stp)
Definition: ts_locale.c:161
char * tsearch_readline(tsearch_readline_state *stp)
Definition: ts_locale.c:146
bool tsearch_readline_begin(tsearch_readline_state *stp, const char *filename)
Definition: ts_locale.c:124
static char * filename
Definition: pg_dumpall.c:90
int errmsg(const char *fmt,...)
Definition: elog.c:822

◆ NIImportOOAffixes()

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

Definition at line 1189 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().

1190 {
1191  char type[BUFSIZ],
1192  *ptype = NULL;
1193  char sflag[BUFSIZ];
1194  char mask[BUFSIZ],
1195  *pmask;
1196  char find[BUFSIZ],
1197  *pfind;
1198  char repl[BUFSIZ],
1199  *prepl;
1200  bool isSuffix = false;
1201  int naffix = 0,
1202  curaffix = 0;
1203  int sflaglen = 0;
1204  char flagflags = 0;
1206  char *recoded;
1207 
1208  /* read file to find any flag */
1209  Conf->usecompound = false;
1210  Conf->useFlagAliases = false;
1211  Conf->flagMode = FM_CHAR;
1212 
1213  if (!tsearch_readline_begin(&trst, filename))
1214  ereport(ERROR,
1215  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1216  errmsg("could not open affix file \"%s\": %m",
1217  filename)));
1218 
1219  while ((recoded = tsearch_readline(&trst)) != NULL)
1220  {
1221  if (*recoded == '\0' || t_isspace(recoded) || t_iseq(recoded, '#'))
1222  {
1223  pfree(recoded);
1224  continue;
1225  }
1226 
1227  if (STRNCMP(recoded, "COMPOUNDFLAG") == 0)
1228  addCompoundAffixFlagValue(Conf, recoded + strlen("COMPOUNDFLAG"),
1229  FF_COMPOUNDFLAG);
1230  else if (STRNCMP(recoded, "COMPOUNDBEGIN") == 0)
1231  addCompoundAffixFlagValue(Conf, recoded + strlen("COMPOUNDBEGIN"),
1233  else if (STRNCMP(recoded, "COMPOUNDLAST") == 0)
1234  addCompoundAffixFlagValue(Conf, recoded + strlen("COMPOUNDLAST"),
1235  FF_COMPOUNDLAST);
1236  /* COMPOUNDLAST and COMPOUNDEND are synonyms */
1237  else if (STRNCMP(recoded, "COMPOUNDEND") == 0)
1238  addCompoundAffixFlagValue(Conf, recoded + strlen("COMPOUNDEND"),
1239  FF_COMPOUNDLAST);
1240  else if (STRNCMP(recoded, "COMPOUNDMIDDLE") == 0)
1241  addCompoundAffixFlagValue(Conf, recoded + strlen("COMPOUNDMIDDLE"),
1243  else if (STRNCMP(recoded, "ONLYINCOMPOUND") == 0)
1244  addCompoundAffixFlagValue(Conf, recoded + strlen("ONLYINCOMPOUND"),
1245  FF_COMPOUNDONLY);
1246  else if (STRNCMP(recoded, "COMPOUNDPERMITFLAG") == 0)
1248  recoded + strlen("COMPOUNDPERMITFLAG"),
1250  else if (STRNCMP(recoded, "COMPOUNDFORBIDFLAG") == 0)
1252  recoded + strlen("COMPOUNDFORBIDFLAG"),
1254  else if (STRNCMP(recoded, "FLAG") == 0)
1255  {
1256  char *s = recoded + strlen("FLAG");
1257 
1258  while (*s && t_isspace(s))
1259  s += pg_mblen(s);
1260 
1261  if (*s)
1262  {
1263  if (STRNCMP(s, "long") == 0)
1264  Conf->flagMode = FM_LONG;
1265  else if (STRNCMP(s, "num") == 0)
1266  Conf->flagMode = FM_NUM;
1267  else if (STRNCMP(s, "default") != 0)
1268  ereport(ERROR,
1269  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1270  errmsg("Ispell dictionary supports only "
1271  "\"default\", \"long\", "
1272  "and \"num\" flag values")));
1273  }
1274  }
1275 
1276  pfree(recoded);
1277  }
1278  tsearch_readline_end(&trst);
1279 
1280  if (Conf->nCompoundAffixFlag > 1)
1281  qsort((void *) Conf->CompoundAffixFlags, Conf->nCompoundAffixFlag,
1282  sizeof(CompoundAffixFlag), cmpcmdflag);
1283 
1284  if (!tsearch_readline_begin(&trst, filename))
1285  ereport(ERROR,
1286  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1287  errmsg("could not open affix file \"%s\": %m",
1288  filename)));
1289 
1290  while ((recoded = tsearch_readline(&trst)) != NULL)
1291  {
1292  int fields_read;
1293 
1294  if (*recoded == '\0' || t_isspace(recoded) || t_iseq(recoded, '#'))
1295  goto nextline;
1296 
1297  fields_read = parse_ooaffentry(recoded, type, sflag, find, repl, mask);
1298 
1299  if (ptype)
1300  pfree(ptype);
1301  ptype = lowerstr_ctx(Conf, type);
1302 
1303  /* First try to parse AF parameter (alias compression) */
1304  if (STRNCMP(ptype, "af") == 0)
1305  {
1306  /* First line is the number of aliases */
1307  if (!Conf->useFlagAliases)
1308  {
1309  Conf->useFlagAliases = true;
1310  naffix = atoi(sflag);
1311  if (naffix <= 0)
1312  ereport(ERROR,
1313  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1314  errmsg("invalid number of flag vector aliases")));
1315 
1316  /* Also reserve place for empty flag set */
1317  naffix++;
1318 
1319  Conf->AffixData = (char **) palloc0(naffix * sizeof(char *));
1320  Conf->lenAffixData = Conf->nAffixData = naffix;
1321 
1322  /* Add empty flag set into AffixData */
1323  Conf->AffixData[curaffix] = VoidString;
1324  curaffix++;
1325  }
1326  /* Other lines are aliases */
1327  else
1328  {
1329  if (curaffix < naffix)
1330  {
1331  Conf->AffixData[curaffix] = cpstrdup(Conf, sflag);
1332  curaffix++;
1333  }
1334  else
1335  ereport(ERROR,
1336  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1337  errmsg("number of aliases exceeds specified number %d",
1338  naffix - 1)));
1339  }
1340  goto nextline;
1341  }
1342  /* Else try to parse prefixes and suffixes */
1343  if (fields_read < 4 ||
1344  (STRNCMP(ptype, "sfx") != 0 && STRNCMP(ptype, "pfx") != 0))
1345  goto nextline;
1346 
1347  sflaglen = strlen(sflag);
1348  if (sflaglen == 0
1349  || (sflaglen > 1 && Conf->flagMode == FM_CHAR)
1350  || (sflaglen > 2 && Conf->flagMode == FM_LONG))
1351  goto nextline;
1352 
1353  /*--------
1354  * Affix header. For example:
1355  * SFX \ N 1
1356  *--------
1357  */
1358  if (fields_read == 4)
1359  {
1360  isSuffix = (STRNCMP(ptype, "sfx") == 0);
1361  if (t_iseq(find, 'y') || t_iseq(find, 'Y'))
1362  flagflags = FF_CROSSPRODUCT;
1363  else
1364  flagflags = 0;
1365  }
1366  /*--------
1367  * Affix fields. For example:
1368  * SFX \ 0 Y/L [^Y]
1369  *--------
1370  */
1371  else
1372  {
1373  char *ptr;
1374  int aflg = 0;
1375 
1376  /* Get flags after '/' (flags are case sensitive) */
1377  if ((ptr = strchr(repl, '/')) != NULL)
1378  aflg |= getCompoundAffixFlagValue(Conf,
1379  getAffixFlagSet(Conf,
1380  ptr + 1));
1381  /* Get lowercased version of string before '/' */
1382  prepl = lowerstr_ctx(Conf, repl);
1383  if ((ptr = strchr(prepl, '/')) != NULL)
1384  *ptr = '\0';
1385  pfind = lowerstr_ctx(Conf, find);
1386  pmask = lowerstr_ctx(Conf, mask);
1387  if (t_iseq(find, '0'))
1388  *pfind = '\0';
1389  if (t_iseq(repl, '0'))
1390  *prepl = '\0';
1391 
1392  NIAddAffix(Conf, sflag, flagflags | aflg, pmask, pfind, prepl,
1393  isSuffix ? FF_SUFFIX : FF_PREFIX);
1394  pfree(prepl);
1395  pfree(pfind);
1396  pfree(pmask);
1397  }
1398 
1399 nextline:
1400  pfree(recoded);
1401  }
1402 
1403  tsearch_readline_end(&trst);
1404  if (ptype)
1405  pfree(ptype);
1406 }
#define FF_COMPOUNDONLY
Definition: spell.h:42
int nAffixData
Definition: spell.h:192
int lenAffixData
Definition: spell.h:191
static int find(struct vars *, struct cnfa *, struct colormap *)
Definition: regexec.c:375
bool useFlagAliases
Definition: spell.h:193
bool usecompound
Definition: spell.h:197
static int getCompoundAffixFlagValue(IspellDict *Conf, char *s)
Definition: spell.c:1116
Definition: spell.h:154
#define FF_CROSSPRODUCT
Definition: spell.h:110
int errcode(int sqlerrcode)
Definition: elog.c:608
#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:1056
#define ERROR
Definition: elog.h:43
#define FF_SUFFIX
Definition: spell.h:116
char ** AffixData
Definition: spell.h:190
int t_isspace(const char *ptr)
Definition: ts_locale.c:52
Definition: spell.h:156
#define t_iseq(x, c)
Definition: ts_locale.h:45
static void NIAddAffix(IspellDict *Conf, const char *flag, char flagflags, const char *mask, const char *find, const char *repl, int type)
Definition: spell.c:676
#define ereport(elevel, rest)
Definition: elog.h:141
static int cmpcmdflag(const void *f1, const void *f2)
Definition: spell.c:209
void * palloc0(Size size)
Definition: mcxt.c:980
static char * lowerstr_ctx(IspellDict *Conf, const char *src)
Definition: spell.c:174
#define STRNCMP(s, p)
Definition: spell.c:189
CompoundAffixFlag * CompoundAffixFlags
Definition: spell.h:205
#define FF_PREFIX
Definition: spell.h:117
static void addCompoundAffixFlagValue(IspellDict *Conf, char *s, uint32 val)
Definition: spell.c:1059
int pg_mblen(const char *mbstr)
Definition: mbutils.c:802
void tsearch_readline_end(tsearch_readline_state *stp)
Definition: ts_locale.c:161
char * tsearch_readline(tsearch_readline_state *stp)
Definition: ts_locale.c:146
bool tsearch_readline_begin(tsearch_readline_state *stp, const char *filename)
Definition: ts_locale.c:124
Definition: spell.h:155
#define FF_COMPOUNDFORBIDFLAG
Definition: spell.h:109
static char * filename
Definition: pg_dumpall.c:90
int errmsg(const char *fmt,...)
Definition: elog.c:822
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:488
static int parse_ooaffentry(char *str, char *type, char *flag, char *find, char *repl, char *mask)
Definition: spell.c:850
static char * getAffixFlagSet(IspellDict *Conf, char *s)
Definition: spell.c:1152
int nCompoundAffixFlag
Definition: spell.h:207
#define FF_COMPOUNDPERMITFLAG
Definition: spell.h:108
FlagMode flagMode
Definition: spell.h:198

◆ NINormalizeWord()

TSLexeme* NINormalizeWord ( IspellDict Conf,
char *  word 
)

Definition at line 2525 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().

2526 {
2527  char **res;
2528  TSLexeme *lcur = NULL,
2529  *lres = NULL;
2530  uint16 NVariant = 1;
2531 
2532  res = NormalizeSubWord(Conf, word, 0);
2533 
2534  if (res)
2535  {
2536  char **ptr = res;
2537 
2538  while (*ptr && (lcur - lres) < MAX_NORM)
2539  {
2540  addNorm(&lres, &lcur, *ptr, 0, NVariant++);
2541  ptr++;
2542  }
2543  pfree(res);
2544  }
2545 
2546  if (Conf->usecompound)
2547  {
2548  int wordlen = strlen(word);
2549  SplitVar *ptr,
2550  *var = SplitToVariants(Conf, NULL, NULL, word, wordlen, 0, -1);
2551  int i;
2552 
2553  while (var)
2554  {
2555  if (var->nstem > 1)
2556  {
2557  char **subres = NormalizeSubWord(Conf, var->stem[var->nstem - 1], FF_COMPOUNDLAST);
2558 
2559  if (subres)
2560  {
2561  char **subptr = subres;
2562 
2563  while (*subptr)
2564  {
2565  for (i = 0; i < var->nstem - 1; i++)
2566  {
2567  addNorm(&lres, &lcur, (subptr == subres) ? var->stem[i] : pstrdup(var->stem[i]), 0, NVariant);
2568  }
2569 
2570  addNorm(&lres, &lcur, *subptr, 0, NVariant);
2571  subptr++;
2572  NVariant++;
2573  }
2574 
2575  pfree(subres);
2576  var->stem[0] = NULL;
2577  pfree(var->stem[var->nstem - 1]);
2578  }
2579  }
2580 
2581  for (i = 0; i < var->nstem && var->stem[i]; i++)
2582  pfree(var->stem[i]);
2583  ptr = var->next;
2584  pfree(var->stem);
2585  pfree(var);
2586  var = ptr;
2587  }
2588  }
2589 
2590  return lres;
2591 }
static char ** NormalizeSubWord(IspellDict *Conf, char *word, int flag)
Definition: spell.c:2164
bool usecompound
Definition: spell.h:197
char * pstrdup(const char *in)
Definition: mcxt.c:1186
#define FF_COMPOUNDLAST
Definition: spell.h:45
static void addNorm(TSLexeme **lres, TSLexeme **lcur, char *word, int flags, uint16 NVariant)
Definition: spell.c:2509
#define MAX_NORM
Definition: spell.c:186
unsigned short uint16
Definition: c.h:358
void pfree(void *pointer)
Definition: mcxt.c:1056
int nstem
Definition: spell.c:2275
static SplitVar * SplitToVariants(IspellDict *Conf, SPNode *snode, SplitVar *orig, char *word, int wordlen, int startpos, int minpos)
Definition: spell.c:2362
char ** stem
Definition: spell.c:2277
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1246
int i
struct SplitVar * next
Definition: spell.c:2278

◆ NISortAffixes()

void NISortAffixes ( IspellDict Conf)

Definition at line 1964 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().

1965 {
1966  AFFIX *Affix;
1967  size_t i;
1968  CMPDAffix *ptr;
1969  int firstsuffix = Conf->naffixes;
1970 
1971  if (Conf->naffixes == 0)
1972  return;
1973 
1974  /* Store compound affixes in the Conf->CompoundAffix array */
1975  if (Conf->naffixes > 1)
1976  qsort((void *) Conf->Affix, Conf->naffixes, sizeof(AFFIX), cmpaffix);
1977  Conf->CompoundAffix = ptr = (CMPDAffix *) palloc(sizeof(CMPDAffix) * Conf->naffixes);
1978  ptr->affix = NULL;
1979 
1980  for (i = 0; i < Conf->naffixes; i++)
1981  {
1982  Affix = &(((AFFIX *) Conf->Affix)[i]);
1983  if (Affix->type == FF_SUFFIX && i < firstsuffix)
1984  firstsuffix = i;
1985 
1986  if ((Affix->flagflags & FF_COMPOUNDFLAG) && Affix->replen > 0 &&
1987  isAffixInUse(Conf, Affix->flag))
1988  {
1989  bool issuffix = (Affix->type == FF_SUFFIX);
1990 
1991  if (ptr == Conf->CompoundAffix ||
1992  issuffix != (ptr - 1)->issuffix ||
1993  strbncmp((const unsigned char *) (ptr - 1)->affix,
1994  (const unsigned char *) Affix->repl,
1995  (ptr - 1)->len))
1996  {
1997  /* leave only unique and minimals suffixes */
1998  ptr->affix = Affix->repl;
1999  ptr->len = Affix->replen;
2000  ptr->issuffix = issuffix;
2001  ptr++;
2002  }
2003  }
2004  }
2005  ptr->affix = NULL;
2006  Conf->CompoundAffix = (CMPDAffix *) repalloc(Conf->CompoundAffix, sizeof(CMPDAffix) * (ptr - Conf->CompoundAffix + 1));
2007 
2008  /* Start build a prefix tree */
2009  Conf->Prefix = mkANode(Conf, 0, firstsuffix, 0, FF_PREFIX);
2010  Conf->Suffix = mkANode(Conf, firstsuffix, Conf->naffixes, 0, FF_SUFFIX);
2011  mkVoidAffix(Conf, true, firstsuffix);
2012  mkVoidAffix(Conf, false, firstsuffix);
2013 }
char * flag
Definition: spell.h:89
int naffixes
Definition: spell.h:182
uint32 flagflags
Definition: spell.h:91
AffixNode * Prefix
Definition: spell.h:186
AffixNode * Suffix
Definition: spell.h:185
uint32 type
Definition: spell.h:91
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:1949
int len
Definition: spell.h:145
#define FF_SUFFIX
Definition: spell.h:116
static void mkVoidAffix(IspellDict *Conf, bool issuffix, int startsuffix)
Definition: spell.c:1895
AFFIX * Affix
Definition: spell.h:183
static AffixNode * mkANode(IspellDict *Conf, int low, int high, int level, int type)
Definition: spell.c:1818
char * affix
Definition: spell.h:144
bool issuffix
Definition: spell.h:146
#define FF_PREFIX
Definition: spell.h:117
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069
CMPDAffix * CompoundAffix
Definition: spell.h:195
void * palloc(Size size)
Definition: mcxt.c:949
int i
char * repl
Definition: spell.h:97
#define FF_COMPOUNDFLAG
Definition: spell.h:46
#define qsort(a, b, c, d)
Definition: port.h:488
uint32 replen
Definition: spell.h:91
static int cmpaffix(const void *s1, const void *s2)
Definition: spell.c:310

◆ NISortDictionary()

void NISortDictionary ( IspellDict Conf)

Definition at line 1710 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().

1711 {
1712  int i;
1713  int naffix = 0;
1714  int curaffix;
1715 
1716  /* compress affixes */
1717 
1718  /*
1719  * If we use flag aliases then we need to use Conf->AffixData filled in
1720  * the NIImportOOAffixes().
1721  */
1722  if (Conf->useFlagAliases)
1723  {
1724  for (i = 0; i < Conf->nspell; i++)
1725  {
1726  char *end;
1727 
1728  if (*Conf->Spell[i]->p.flag != '\0')
1729  {
1730  curaffix = strtol(Conf->Spell[i]->p.flag, &end, 10);
1731  if (Conf->Spell[i]->p.flag == end || errno == ERANGE)
1732  ereport(ERROR,
1733  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1734  errmsg("invalid affix alias \"%s\"",
1735  Conf->Spell[i]->p.flag)));
1736  if (curaffix < 0 || curaffix >= Conf->nAffixData)
1737  ereport(ERROR,
1738  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1739  errmsg("invalid affix alias \"%s\"",
1740  Conf->Spell[i]->p.flag)));
1741  if (*end != '\0' && !t_isdigit(end) && !t_isspace(end))
1742  ereport(ERROR,
1743  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1744  errmsg("invalid affix alias \"%s\"",
1745  Conf->Spell[i]->p.flag)));
1746  }
1747  else
1748  {
1749  /*
1750  * If Conf->Spell[i]->p.flag is empty, then get empty value of
1751  * Conf->AffixData (0 index).
1752  */
1753  curaffix = 0;
1754  }
1755 
1756  Conf->Spell[i]->p.d.affix = curaffix;
1757  Conf->Spell[i]->p.d.len = strlen(Conf->Spell[i]->word);
1758  }
1759  }
1760  /* Otherwise fill Conf->AffixData here */
1761  else
1762  {
1763  /* Count the number of different flags used in the dictionary */
1764  qsort((void *) Conf->Spell, Conf->nspell, sizeof(SPELL *),
1765  cmpspellaffix);
1766 
1767  naffix = 0;
1768  for (i = 0; i < Conf->nspell; i++)
1769  {
1770  if (i == 0 ||
1771  strcmp(Conf->Spell[i]->p.flag, Conf->Spell[i - 1]->p.flag) != 0)
1772  naffix++;
1773  }
1774 
1775  /*
1776  * Fill in Conf->AffixData with the affixes that were used in the
1777  * dictionary. Replace textual flag-field of Conf->Spell entries with
1778  * indexes into Conf->AffixData array.
1779  */
1780  Conf->AffixData = (char **) palloc0(naffix * sizeof(char *));
1781 
1782  curaffix = -1;
1783  for (i = 0; i < Conf->nspell; i++)
1784  {
1785  if (i == 0 ||
1786  strcmp(Conf->Spell[i]->p.flag, Conf->AffixData[curaffix]) != 0)
1787  {
1788  curaffix++;
1789  Assert(curaffix < naffix);
1790  Conf->AffixData[curaffix] = cpstrdup(Conf,
1791  Conf->Spell[i]->p.flag);
1792  }
1793 
1794  Conf->Spell[i]->p.d.affix = curaffix;
1795  Conf->Spell[i]->p.d.len = strlen(Conf->Spell[i]->word);
1796  }
1797 
1798  Conf->lenAffixData = Conf->nAffixData = naffix;
1799  }
1800 
1801  /* Start build a prefix tree */
1802  qsort((void *) Conf->Spell, Conf->nspell, sizeof(SPELL *), cmpspell);
1803  Conf->Dictionary = mkSPNode(Conf, 0, Conf->nspell, 0);
1804 }
int nAffixData
Definition: spell.h:192
static int cmpspell(const void *s1, const void *s2)
Definition: spell.c:196
int lenAffixData
Definition: spell.h:191
bool useFlagAliases
Definition: spell.h:193
struct spell_struct::@119::@120 d
static SPNode * mkSPNode(IspellDict *Conf, int low, int high, int level)
Definition: spell.c:1628
int errcode(int sqlerrcode)
Definition: elog.c:608
SPNode * Dictionary
Definition: spell.h:188
int t_isdigit(const char *ptr)
Definition: ts_locale.c:36
int nspell
Definition: spell.h:219
#define ERROR
Definition: elog.h:43
char ** AffixData
Definition: spell.h:190
int t_isspace(const char *ptr)
Definition: ts_locale.c:52
#define ereport(elevel, rest)
Definition: elog.h:141
char word[FLEXIBLE_ARRAY_MEMBER]
Definition: spell.h:79
void * palloc0(Size size)
Definition: mcxt.c:980
char * flag
Definition: spell.h:69
#define Assert(condition)
Definition: c.h:739
SPELL ** Spell
Definition: spell.h:218
int errmsg(const char *fmt,...)
Definition: elog.c:822
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
union spell_struct::@119 p
#define qsort(a, b, c, d)
Definition: port.h:488

◆ 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:215
#define AllocSetContextCreate
Definition: memutils.h:170
MemoryContext CurTransactionContext
Definition: mcxt.c:50
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192

◆ NormalizeSubWord()

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

Definition at line 2164 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().

2165 {
2166  AffixNodeData *suffix = NULL,
2167  *prefix = NULL;
2168  int slevel = 0,
2169  plevel = 0;
2170  int wrdlen = strlen(word),
2171  swrdlen;
2172  char **forms;
2173  char **cur;
2174  char newword[2 * MAXNORMLEN] = "";
2175  char pnewword[2 * MAXNORMLEN] = "";
2176  AffixNode *snode = Conf->Suffix,
2177  *pnode;
2178  int i,
2179  j;
2180 
2181  if (wrdlen > MAXNORMLEN)
2182  return NULL;
2183  cur = forms = (char **) palloc(MAX_NORM * sizeof(char *));
2184  *cur = NULL;
2185 
2186 
2187  /* Check that the word itself is normal form */
2188  if (FindWord(Conf, word, VoidString, flag))
2189  {
2190  *cur = pstrdup(word);
2191  cur++;
2192  *cur = NULL;
2193  }
2194 
2195  /* Find all other NORMAL forms of the 'word' (check only prefix) */
2196  pnode = Conf->Prefix;
2197  plevel = 0;
2198  while (pnode)
2199  {
2200  prefix = FindAffixes(pnode, word, wrdlen, &plevel, FF_PREFIX);
2201  if (!prefix)
2202  break;
2203  for (j = 0; j < prefix->naff; j++)
2204  {
2205  if (CheckAffix(word, wrdlen, prefix->aff[j], flag, newword, NULL))
2206  {
2207  /* prefix success */
2208  if (FindWord(Conf, newword, prefix->aff[j]->flag, flag))
2209  cur += addToResult(forms, cur, newword);
2210  }
2211  }
2212  pnode = prefix->node;
2213  }
2214 
2215  /*
2216  * Find all other NORMAL forms of the 'word' (check suffix and then
2217  * prefix)
2218  */
2219  while (snode)
2220  {
2221  int baselen = 0;
2222 
2223  /* find possible suffix */
2224  suffix = FindAffixes(snode, word, wrdlen, &slevel, FF_SUFFIX);
2225  if (!suffix)
2226  break;
2227  /* foreach suffix check affix */
2228  for (i = 0; i < suffix->naff; i++)
2229  {
2230  if (CheckAffix(word, wrdlen, suffix->aff[i], flag, newword, &baselen))
2231  {
2232  /* suffix success */
2233  if (FindWord(Conf, newword, suffix->aff[i]->flag, flag))
2234  cur += addToResult(forms, cur, newword);
2235 
2236  /* now we will look changed word with prefixes */
2237  pnode = Conf->Prefix;
2238  plevel = 0;
2239  swrdlen = strlen(newword);
2240  while (pnode)
2241  {
2242  prefix = FindAffixes(pnode, newword, swrdlen, &plevel, FF_PREFIX);
2243  if (!prefix)
2244  break;
2245  for (j = 0; j < prefix->naff; j++)
2246  {
2247  if (CheckAffix(newword, swrdlen, prefix->aff[j], flag, pnewword, &baselen))
2248  {
2249  /* prefix success */
2250  char *ff = (prefix->aff[j]->flagflags & suffix->aff[i]->flagflags & FF_CROSSPRODUCT) ?
2251  VoidString : prefix->aff[j]->flag;
2252 
2253  if (FindWord(Conf, pnewword, ff, flag))
2254  cur += addToResult(forms, cur, pnewword);
2255  }
2256  }
2257  pnode = prefix->node;
2258  }
2259  }
2260  }
2261 
2262  snode = suffix->node;
2263  }
2264 
2265  if (cur == forms)
2266  {
2267  pfree(forms);
2268  return NULL;
2269  }
2270  return forms;
2271 }
char * flag
Definition: spell.h:89
uint32 flagflags
Definition: spell.h:91
struct AffixNode * node
Definition: spell.h:130
AffixNode * Prefix
Definition: spell.h:186
AffixNode * Suffix
Definition: spell.h:185
AFFIX ** aff
Definition: spell.h:129
char * pstrdup(const char *in)
Definition: mcxt.c:1186
struct cursor * cur
Definition: ecpg.c:28
#define FF_CROSSPRODUCT
Definition: spell.h:110
#define MAX_NORM
Definition: spell.c:186
#define MAXNORMLEN
Definition: spell.c:187
void pfree(void *pointer)
Definition: mcxt.c:1056
#define FF_SUFFIX
Definition: spell.h:116
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:2059
#define FF_PREFIX
Definition: spell.h:117
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1246
void * palloc(Size size)
Definition: mcxt.c:949
static int addToResult(char **forms, char **cur, char *word)
Definition: spell.c:2149
static char * VoidString
Definition: spell.c:193
uint32 naff
Definition: spell.h:127
int i
static AffixNodeData * FindAffixes(AffixNode *node, const char *word, int wrdlen, int *level, int type)
Definition: spell.c:2016

◆ parse_affentry()

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

Definition at line 906 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().

907 {
908  int state = PAE_WAIT_MASK;
909  char *pmask = mask,
910  *pfind = find,
911  *prepl = repl;
912 
913  *mask = *find = *repl = '\0';
914 
915  while (*str)
916  {
917  if (state == PAE_WAIT_MASK)
918  {
919  if (t_iseq(str, '#'))
920  return false;
921  else if (!t_isspace(str))
922  {
923  COPYCHAR(pmask, str);
924  pmask += pg_mblen(str);
925  state = PAE_INMASK;
926  }
927  }
928  else if (state == PAE_INMASK)
929  {
930  if (t_iseq(str, '>'))
931  {
932  *pmask = '\0';
933  state = PAE_WAIT_FIND;
934  }
935  else if (!t_isspace(str))
936  {
937  COPYCHAR(pmask, str);
938  pmask += pg_mblen(str);
939  }
940  }
941  else if (state == PAE_WAIT_FIND)
942  {
943  if (t_iseq(str, '-'))
944  {
945  state = PAE_INFIND;
946  }
947  else if (t_isalpha(str) || t_iseq(str, '\'') /* english 's */ )
948  {
949  COPYCHAR(prepl, str);
950  prepl += pg_mblen(str);
951  state = PAE_INREPL;
952  }
953  else if (!t_isspace(str))
954  ereport(ERROR,
955  (errcode(ERRCODE_CONFIG_FILE_ERROR),
956  errmsg("syntax error")));
957  }
958  else if (state == PAE_INFIND)
959  {
960  if (t_iseq(str, ','))
961  {
962  *pfind = '\0';
963  state = PAE_WAIT_REPL;
964  }
965  else if (t_isalpha(str))
966  {
967  COPYCHAR(pfind, str);
968  pfind += pg_mblen(str);
969  }
970  else if (!t_isspace(str))
971  ereport(ERROR,
972  (errcode(ERRCODE_CONFIG_FILE_ERROR),
973  errmsg("syntax error")));
974  }
975  else if (state == PAE_WAIT_REPL)
976  {
977  if (t_iseq(str, '-'))
978  {
979  break; /* void repl */
980  }
981  else if (t_isalpha(str))
982  {
983  COPYCHAR(prepl, str);
984  prepl += pg_mblen(str);
985  state = PAE_INREPL;
986  }
987  else if (!t_isspace(str))
988  ereport(ERROR,
989  (errcode(ERRCODE_CONFIG_FILE_ERROR),
990  errmsg("syntax error")));
991  }
992  else if (state == PAE_INREPL)
993  {
994  if (t_iseq(str, '#'))
995  {
996  *prepl = '\0';
997  break;
998  }
999  else if (t_isalpha(str))
1000  {
1001  COPYCHAR(prepl, str);
1002  prepl += pg_mblen(str);
1003  }
1004  else if (!t_isspace(str))
1005  ereport(ERROR,
1006  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1007  errmsg("syntax error")));
1008  }
1009  else
1010  elog(ERROR, "unrecognized state in parse_affentry: %d", state);
1011 
1012  str += pg_mblen(str);
1013  }
1014 
1015  *pmask = *pfind = *prepl = '\0';
1016 
1017  return (*mask && (*find || *repl));
1018 }
#define COPYCHAR(d, s)
Definition: ts_locale.h:47
#define PAE_INREPL
Definition: spell.c:769
static int find(struct vars *, struct cnfa *, struct colormap *)
Definition: regexec.c:375
#define PAE_INFIND
Definition: spell.c:767
int errcode(int sqlerrcode)
Definition: elog.c:608
#define ERROR
Definition: elog.h:43
int t_isspace(const char *ptr)
Definition: ts_locale.c:52
#define t_iseq(x, c)
Definition: ts_locale.h:45
#define ereport(elevel, rest)
Definition: elog.h:141
#define PAE_INMASK
Definition: spell.c:765
Definition: regguts.h:298
int pg_mblen(const char *mbstr)
Definition: mbutils.c:802
#define PAE_WAIT_FIND
Definition: spell.c:766
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
#define PAE_WAIT_MASK
Definition: spell.c:764
int t_isalpha(const char *ptr)
Definition: ts_locale.c:68
#define PAE_WAIT_REPL
Definition: spell.c:768

◆ parse_ooaffentry()

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

Definition at line 850 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().

852 {
853  int state = PAE_WAIT_TYPE;
854  int fields_read = 0;
855  bool valid = false;
856 
857  *type = *flag = *find = *repl = *mask = '\0';
858 
859  while (*str)
860  {
861  switch (state)
862  {
863  case PAE_WAIT_TYPE:
864  valid = get_nextfield(&str, type);
865  state = PAE_WAIT_FLAG;
866  break;
867  case PAE_WAIT_FLAG:
868  valid = get_nextfield(&str, flag);
869  state = PAE_WAIT_FIND;
870  break;
871  case PAE_WAIT_FIND:
872  valid = get_nextfield(&str, find);
873  state = PAE_WAIT_REPL;
874  break;
875  case PAE_WAIT_REPL:
876  valid = get_nextfield(&str, repl);
877  state = PAE_WAIT_MASK;
878  break;
879  case PAE_WAIT_MASK:
880  valid = get_nextfield(&str, mask);
881  state = -1; /* force loop exit */
882  break;
883  default:
884  elog(ERROR, "unrecognized state in parse_ooaffentry: %d",
885  state);
886  break;
887  }
888  if (valid)
889  fields_read++;
890  else
891  break; /* early EOL */
892  if (state < 0)
893  break; /* got all fields */
894  }
895 
896  return fields_read;
897 }
static int find(struct vars *, struct cnfa *, struct colormap *)
Definition: regexec.c:375
#define PAE_WAIT_TYPE
Definition: spell.c:770
#define PAE_WAIT_FLAG
Definition: spell.c:771
#define ERROR
Definition: elog.h:43
char * flag(int b)
Definition: test-ctype.c:33
static bool get_nextfield(char **str, char *next)
Definition: spell.c:784
Definition: regguts.h:298
#define PAE_WAIT_FIND
Definition: spell.c:766
#define elog(elevel,...)
Definition: elog.h:228
#define PAE_WAIT_MASK
Definition: spell.c:764
#define PAE_WAIT_REPL
Definition: spell.c:768

◆ setCompoundAffixFlagValue()

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

Definition at line 1024 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().

1026 {
1027  if (Conf->flagMode == FM_NUM)
1028  {
1029  char *next;
1030  int i;
1031 
1032  i = strtol(s, &next, 10);
1033  if (s == next || errno == ERANGE)
1034  ereport(ERROR,
1035  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1036  errmsg("invalid affix flag \"%s\"", s)));
1037  if (i < 0 || i > FLAGNUM_MAXSIZE)
1038  ereport(ERROR,
1039  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1040  errmsg("affix flag \"%s\" is out of range", s)));
1041 
1042  entry->flag.i = i;
1043  }
1044  else
1045  entry->flag.s = cpstrdup(Conf, s);
1046 
1047  entry->flagMode = Conf->flagMode;
1048  entry->value = val;
1049 }
static int32 next
Definition: blutils.c:213
int errcode(int sqlerrcode)
Definition: elog.c:608
#define FLAGNUM_MAXSIZE
Definition: spell.h:177
uint32 value
Definition: spell.h:174
#define ERROR
Definition: elog.h:43
Definition: spell.h:156
#define ereport(elevel, rest)
Definition: elog.h:141
union CompoundAffixFlag::@122 flag
FlagMode flagMode
Definition: spell.h:173
int errmsg(const char *fmt,...)
Definition: elog.c:822
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:198

◆ SplitToVariants()

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

Definition at line 2362 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().

2363 {
2364  SplitVar *var = NULL;
2365  SPNodeData *StopLow,
2366  *StopHigh,
2367  *StopMiddle = NULL;
2368  SPNode *node = (snode) ? snode : Conf->Dictionary;
2369  int level = (snode) ? minpos : startpos; /* recursive
2370  * minpos==level */
2371  int lenaff;
2372  CMPDAffix *caff;
2373  char *notprobed;
2374  int compoundflag = 0;
2375 
2376  notprobed = (char *) palloc(wordlen);
2377  memset(notprobed, 1, wordlen);
2378  var = CopyVar(orig, 1);
2379 
2380  while (level < wordlen)
2381  {
2382  /* find word with epenthetic or/and compound affix */
2383  caff = Conf->CompoundAffix;
2384  while (level > startpos && (lenaff = CheckCompoundAffixes(&caff, word + level, wordlen - level, (node) ? true : false)) >= 0)
2385  {
2386  /*
2387  * there is one of compound affixes, so check word for existings
2388  */
2389  char buf[MAXNORMLEN];
2390  char **subres;
2391 
2392  lenaff = level - startpos + lenaff;
2393 
2394  if (!notprobed[startpos + lenaff - 1])
2395  continue;
2396 
2397  if (level + lenaff - 1 <= minpos)
2398  continue;
2399 
2400  if (lenaff >= MAXNORMLEN)
2401  continue; /* skip too big value */
2402  if (lenaff > 0)
2403  memcpy(buf, word + startpos, lenaff);
2404  buf[lenaff] = '\0';
2405 
2406  if (level == 0)
2407  compoundflag = FF_COMPOUNDBEGIN;
2408  else if (level == wordlen - 1)
2409  compoundflag = FF_COMPOUNDLAST;
2410  else
2411  compoundflag = FF_COMPOUNDMIDDLE;
2412  subres = NormalizeSubWord(Conf, buf, compoundflag);
2413  if (subres)
2414  {
2415  /* Yes, it was a word from dictionary */
2416  SplitVar *new = CopyVar(var, 0);
2417  SplitVar *ptr = var;
2418  char **sptr = subres;
2419 
2420  notprobed[startpos + lenaff - 1] = 0;
2421 
2422  while (*sptr)
2423  {
2424  AddStem(new, *sptr);
2425  sptr++;
2426  }
2427  pfree(subres);
2428 
2429  while (ptr->next)
2430  ptr = ptr->next;
2431  ptr->next = SplitToVariants(Conf, NULL, new, word, wordlen, startpos + lenaff, startpos + lenaff);
2432 
2433  pfree(new->stem);
2434  pfree(new);
2435  }
2436  }
2437 
2438  if (!node)
2439  break;
2440 
2441  StopLow = node->data;
2442  StopHigh = node->data + node->length;
2443  while (StopLow < StopHigh)
2444  {
2445  StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
2446  if (StopMiddle->val == ((uint8 *) (word))[level])
2447  break;
2448  else if (StopMiddle->val < ((uint8 *) (word))[level])
2449  StopLow = StopMiddle + 1;
2450  else
2451  StopHigh = StopMiddle;
2452  }
2453 
2454  if (StopLow < StopHigh)
2455  {
2456  if (startpos == 0)
2457  compoundflag = FF_COMPOUNDBEGIN;
2458  else if (level == wordlen - 1)
2459  compoundflag = FF_COMPOUNDLAST;
2460  else
2461  compoundflag = FF_COMPOUNDMIDDLE;
2462 
2463  /* find infinitive */
2464  if (StopMiddle->isword &&
2465  (StopMiddle->compoundflag & compoundflag) &&
2466  notprobed[level])
2467  {
2468  /* ok, we found full compoundallowed word */
2469  if (level > minpos)
2470  {
2471  /* and its length more than minimal */
2472  if (wordlen == level + 1)
2473  {
2474  /* well, it was last word */
2475  AddStem(var, pnstrdup(word + startpos, wordlen - startpos));
2476  pfree(notprobed);
2477  return var;
2478  }
2479  else
2480  {
2481  /* then we will search more big word at the same point */
2482  SplitVar *ptr = var;
2483 
2484  while (ptr->next)
2485  ptr = ptr->next;
2486  ptr->next = SplitToVariants(Conf, node, var, word, wordlen, startpos, level);
2487  /* we can find next word */
2488  level++;
2489  AddStem(var, pnstrdup(word + startpos, level - startpos));
2490  node = Conf->Dictionary;
2491  startpos = level;
2492  continue;
2493  }
2494  }
2495  }
2496  node = StopMiddle->node;
2497  }
2498  else
2499  node = NULL;
2500  level++;
2501  }
2502 
2503  AddStem(var, pnstrdup(word + startpos, wordlen - startpos));
2504  pfree(notprobed);
2505  return var;
2506 }
static void AddStem(SplitVar *v, char *word)
Definition: spell.c:2349
static char ** NormalizeSubWord(IspellDict *Conf, char *word, int flag)
Definition: spell.c:2164
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1197
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:357
#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:188
#define MAXNORMLEN
Definition: spell.c:187
void pfree(void *pointer)
Definition: mcxt.c:1056
static int CheckCompoundAffixes(CMPDAffix **ptr, char *word, int len, bool CheckInPlace)
Definition: spell.c:2282
static char * buf
Definition: pg_test_fsync.c:67
static SplitVar * SplitToVariants(IspellDict *Conf, SPNode *snode, SplitVar *orig, char *word, int wordlen, int startpos, int minpos)
Definition: spell.c:2362
Definition: spell.h:50
static XLogRecPtr startpos
CMPDAffix * CompoundAffix
Definition: spell.h:195
static void word(struct vars *, int, struct state *, struct state *)
Definition: regcomp.c:1246
void * palloc(Size size)
Definition: mcxt.c:949
static SplitVar * CopyVar(SplitVar *s, int makedup)
Definition: spell.c:2324
struct SplitVar * next
Definition: spell.c:2278

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