1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * dict_ispell.c |
4 | * Ispell dictionary interface |
5 | * |
6 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
7 | * |
8 | * |
9 | * IDENTIFICATION |
10 | * src/backend/tsearch/dict_ispell.c |
11 | * |
12 | *------------------------------------------------------------------------- |
13 | */ |
14 | #include "postgres.h" |
15 | |
16 | #include "commands/defrem.h" |
17 | #include "tsearch/dicts/spell.h" |
18 | #include "tsearch/ts_locale.h" |
19 | #include "tsearch/ts_utils.h" |
20 | #include "utils/builtins.h" |
21 | |
22 | |
23 | typedef struct |
24 | { |
25 | StopList stoplist; |
26 | IspellDict obj; |
27 | } DictISpell; |
28 | |
29 | Datum |
30 | dispell_init(PG_FUNCTION_ARGS) |
31 | { |
32 | List *dictoptions = (List *) PG_GETARG_POINTER(0); |
33 | DictISpell *d; |
34 | bool affloaded = false, |
35 | dictloaded = false, |
36 | stoploaded = false; |
37 | ListCell *l; |
38 | |
39 | d = (DictISpell *) palloc0(sizeof(DictISpell)); |
40 | |
41 | NIStartBuild(&(d->obj)); |
42 | |
43 | foreach(l, dictoptions) |
44 | { |
45 | DefElem *defel = (DefElem *) lfirst(l); |
46 | |
47 | if (strcmp(defel->defname, "dictfile" ) == 0) |
48 | { |
49 | if (dictloaded) |
50 | ereport(ERROR, |
51 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
52 | errmsg("multiple DictFile parameters" ))); |
53 | NIImportDictionary(&(d->obj), |
54 | get_tsearch_config_filename(defGetString(defel), |
55 | "dict" )); |
56 | dictloaded = true; |
57 | } |
58 | else if (strcmp(defel->defname, "afffile" ) == 0) |
59 | { |
60 | if (affloaded) |
61 | ereport(ERROR, |
62 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
63 | errmsg("multiple AffFile parameters" ))); |
64 | NIImportAffixes(&(d->obj), |
65 | get_tsearch_config_filename(defGetString(defel), |
66 | "affix" )); |
67 | affloaded = true; |
68 | } |
69 | else if (strcmp(defel->defname, "stopwords" ) == 0) |
70 | { |
71 | if (stoploaded) |
72 | ereport(ERROR, |
73 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
74 | errmsg("multiple StopWords parameters" ))); |
75 | readstoplist(defGetString(defel), &(d->stoplist), lowerstr); |
76 | stoploaded = true; |
77 | } |
78 | else |
79 | { |
80 | ereport(ERROR, |
81 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
82 | errmsg("unrecognized Ispell parameter: \"%s\"" , |
83 | defel->defname))); |
84 | } |
85 | } |
86 | |
87 | if (affloaded && dictloaded) |
88 | { |
89 | NISortDictionary(&(d->obj)); |
90 | NISortAffixes(&(d->obj)); |
91 | } |
92 | else if (!affloaded) |
93 | { |
94 | ereport(ERROR, |
95 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
96 | errmsg("missing AffFile parameter" ))); |
97 | } |
98 | else |
99 | { |
100 | ereport(ERROR, |
101 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
102 | errmsg("missing DictFile parameter" ))); |
103 | } |
104 | |
105 | NIFinishBuild(&(d->obj)); |
106 | |
107 | PG_RETURN_POINTER(d); |
108 | } |
109 | |
110 | Datum |
111 | dispell_lexize(PG_FUNCTION_ARGS) |
112 | { |
113 | DictISpell *d = (DictISpell *) PG_GETARG_POINTER(0); |
114 | char *in = (char *) PG_GETARG_POINTER(1); |
115 | int32 len = PG_GETARG_INT32(2); |
116 | char *txt; |
117 | TSLexeme *res; |
118 | TSLexeme *ptr, |
119 | *cptr; |
120 | |
121 | if (len <= 0) |
122 | PG_RETURN_POINTER(NULL); |
123 | |
124 | txt = lowerstr_with_len(in, len); |
125 | res = NINormalizeWord(&(d->obj), txt); |
126 | |
127 | if (res == NULL) |
128 | PG_RETURN_POINTER(NULL); |
129 | |
130 | cptr = res; |
131 | for (ptr = cptr; ptr->lexeme; ptr++) |
132 | { |
133 | if (searchstoplist(&(d->stoplist), ptr->lexeme)) |
134 | { |
135 | pfree(ptr->lexeme); |
136 | ptr->lexeme = NULL; |
137 | } |
138 | else |
139 | { |
140 | if (cptr != ptr) |
141 | memcpy(cptr, ptr, sizeof(TSLexeme)); |
142 | cptr++; |
143 | } |
144 | } |
145 | cptr->lexeme = NULL; |
146 | |
147 | PG_RETURN_POINTER(res); |
148 | } |
149 | |