1 /* Copyright (c) 1992, 1999, 2001, 2002 John E. Davis
2 * This file is part of the S-Lang library.
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Perl Artistic License.
6 */
7 #include "slinclud.h"
8
9 #include "slang.h"
10 #include "_slang.h"
11 #if SLANG_HAS_KANJI_SUPPORT
12 #include "slkanji.h"
13 #endif
14
15 #ifdef upcase
16 # undef upcase
17 #endif
18
19 #define upcase(ch) (cs ? ch : UPPER_CASE(ch))
20
search_forward(register unsigned char * beg,unsigned char * end,unsigned char * key,register int key_len,int cs,int * ind)21 static unsigned char *search_forward (register unsigned char *beg,
22 unsigned char *end,
23 unsigned char *key,
24 register int key_len, int cs, int *ind)
25 {
26 register unsigned char char1;
27 unsigned char *pos, *top = beg;
28 int j, str_len;
29 register unsigned char ch;
30 register int db;
31 #if SLANG_HAS_KANJI_SUPPORT
32 int kflg = FALSE; /* is 2nd Kanji ? */
33 #endif
34
35 str_len = (int) (end - beg);
36 if (str_len < key_len) return (NULL);
37
38 if (key_len == 0)
39 return NULL;
40
41 char1 = key[key_len - 1];
42 beg += (key_len - 1);
43 #if SLANG_HAS_KANJI_SUPPORT
44 kflg = iskanji2nd(key, key_len-1);
45 #endif
46
47 while(1)
48 {
49 #if 1
50 while (beg < end)
51 {
52 ch = *beg;
53 db = ind[(unsigned char) ch];
54 #if SLANG_HAS_KANJI_SUPPORT
55 #if 0
56 /* if ((db < key_len) && */
57 /* (((cs || kflg) ? ch : UPPER_CASE(ch)) == char1)) break; */
58 #endif
59 #endif
60 if(!db) break; /* Why ??? */
61
62 beg += db; /* ind[(unsigned char) ch]; */
63 }
64 #else
65 if (cs) while (beg < end)
66 {
67 ch = *beg;
68 db = ind[(unsigned char) ch];
69 if ((db < key_len) && (ch == char1)) break;
70 beg += db; /* ind[(unsigned char) ch]; */
71 }
72 else while (beg < end)
73 {
74 ch = *beg;
75 db = ind[(unsigned char) ch];
76 if ((db < key_len) &&
77 (UPPER_CASE(ch) == char1)) break;
78 beg += db; /* ind[(unsigned char) ch]; */
79 }
80 #endif
81
82 if (beg >= end) return(NULL);
83
84 pos = beg - (key_len - 1);
85 for (j = 0; j < key_len; j++)
86 {
87 #if SLANG_HAS_KANJI_SUPPORT
88 if(iskanji(key[j])) {
89 if((pos[j] != key[j]) || (pos[j+1] != key[j+1])) break;
90 j++;
91 /* if((j+1) < key_len) j++; */
92 }
93 else {
94 ch = upcase(pos[j]);
95 if (ch != (unsigned char) key[j]) break;
96 if (!j && iskanji2nd(top, (int)(&pos[j] - top))) break;
97 }
98 #else
99 ch = upcase(pos[j]);
100 if (ch != (unsigned char) key[j]) break;
101 #endif
102 }
103
104 if (j == key_len) return(pos);
105 beg += 1;
106 }
107 }
108
search_backward(unsigned char * beg,unsigned char * end,unsigned char * key,int key_len,int cs,int * ind)109 static unsigned char *search_backward (unsigned char *beg,unsigned char *end,
110 unsigned char *key, int key_len,
111 int cs, int *ind)
112 {
113 unsigned char ch, char1;
114 int j, str_len, ofs;
115
116 str_len = (int) (end - beg);
117 if (str_len < key_len) return (NULL);
118
119 if (key_len == 0)
120 return NULL;
121
122 /* end -= (key_len - 1); */
123 end -= key_len;
124
125 char1 = key[0];
126
127 while(1)
128 {
129 while ((beg <= end) && (ch = *end, upcase(ch) != char1))
130 {
131 ofs = ind[(unsigned char) ch];
132 #ifdef __MSDOS__
133 /* This is needed for msdos segment wrapping problems */
134 if (beg + ofs > end) return(NULL);
135 #endif
136 end -= ofs;
137 }
138 if (beg > end) return(NULL);
139 for (j = 0; j < key_len; j++)
140 {
141 #if SLANG_HAS_KANJI_SUPPORT
142 if(iskanji(end[j])) {
143 if((end[j] != key[j]) || (end[j+1] != key[j+1])) break;
144 if((j+1) < key_len) j++;
145 }
146 else {
147 ch = upcase(end[j]);
148 if (ch != key[j]) break;
149 if (!j && iskanji2nd(beg, &end[j] - beg)) break;
150 }
151 #else
152 ch = upcase(end[j]);
153 if (ch != key[j]) break;
154 #endif
155 }
156 if (j == key_len) return(end);
157 end--;
158 }
159 }
160
SLsearch(unsigned char * pmin,unsigned char * pmax,SLsearch_Type * st)161 unsigned char *SLsearch (unsigned char *pmin, unsigned char *pmax,
162 SLsearch_Type *st)
163 {
164 if (st->dir > 0) return search_forward (pmin, pmax, st->key,
165 st->key_len, st->cs, st->ind);
166 else return search_backward (pmin, pmax, st->key,
167 st->key_len, st->cs, st->ind);
168 }
169
170 static int Case_Tables_Ok;
171
SLsearch_init(char * str,int dir,int cs,SLsearch_Type * st)172 int SLsearch_init (char *str, int dir, int cs, SLsearch_Type *st)
173 {
174 int i, maxi;
175 register int max = strlen(str);
176 unsigned char *w, *work = st->key;
177 register int *indp, *indpm;
178 int *ind = st->ind;
179 unsigned char *base = str;
180 #if SLANG_HAS_KANJI_SUPPORT
181 int kflg = FALSE;
182 #endif
183
184 if (max >= (int) sizeof (st->key))
185 {
186 SLang_doerror ("Search string too long.");
187 return -1;
188 }
189
190 st->dir = dir; st->cs = cs;
191
192 if (!Case_Tables_Ok) SLang_init_case_tables ();
193
194 if (dir > 0)
195 {
196 w = work;
197 }
198 else
199 {
200 maxi = max - 1;
201 str = str + maxi;
202 w = work + maxi;
203 }
204
205 /* for (i = 0; i < 256; i++) ind[i] = max; */
206 indp = ind; indpm = ind + 256;
207 while (indp < indpm)
208 {
209 *indp++ = max;
210 *indp++ = max;
211 *indp++ = max;
212 *indp++ = max;
213 }
214
215 i = 0;
216 while (i++ < max)
217 {
218 maxi = max - i;
219 #if SLANG_HAS_KANJI_SUPPORT
220 if(kflg == 1) kflg++;
221 else if(kflg) kflg = FALSE; /* kflag == 2 -> kflg = 0 */
222
223 if(!kflg)
224 if((0 < dir && iskanji(*str))
225 || (dir < 0 && iskanji2nd(base, (int)((unsigned char*)str - base))))
226 kflg = 1;
227
228 #endif
229 #if SLANG_HAS_KANJI_SUPPORT
230 if (cs || kflg)
231 #else
232 if (cs)
233 #endif
234 {
235 *w = *str;
236 ind[(unsigned char) *str] = maxi;
237 }
238 else
239 {
240 *w = UPPER_CASE(*str);
241 ind[(unsigned char) *w] = maxi;
242 ind[(unsigned char) LOWER_CASE(*str)] = maxi;
243 }
244 str += dir; w += dir;
245 }
246
247 work[max] = 0;
248 st->key_len = max;
249 return max;
250 }
251
252 /* 8bit clean upper and lowercase macros */
253 unsigned char _SLChg_LCase_Lut[256];
254 unsigned char _SLChg_UCase_Lut[256];
255
SLang_define_case(int * u,int * l)256 void SLang_define_case (int *u, int *l)
257 {
258 unsigned char up = (unsigned char) *u, dn = (unsigned char) *l;
259
260 _SLChg_LCase_Lut[up] = dn;
261 _SLChg_LCase_Lut[dn] = dn;
262 _SLChg_UCase_Lut[dn] = up;
263 _SLChg_UCase_Lut[up] = up;
264 }
265
SLang_init_case_tables(void)266 void SLang_init_case_tables (void)
267 {
268 int i, j;
269 if (Case_Tables_Ok) return;
270
271 for (i = 0; i < 256; i++)
272 {
273 _SLChg_UCase_Lut[i] = i;
274 _SLChg_LCase_Lut[i] = i;
275 }
276
277 for (i = 'A'; i <= 'Z'; i++)
278 {
279 j = i + 32;
280 _SLChg_UCase_Lut[j] = i;
281 _SLChg_LCase_Lut[i] = j;
282 }
283 #if !SLANG_HAS_KANJI_SUPPORT
284 # ifdef PC_SYSTEM
285 /* Initialize for DOS code page 437. */
286 _SLChg_UCase_Lut[135] = 128; _SLChg_LCase_Lut[128] = 135;
287 _SLChg_UCase_Lut[132] = 142; _SLChg_LCase_Lut[142] = 132;
288 _SLChg_UCase_Lut[134] = 143; _SLChg_LCase_Lut[143] = 134;
289 _SLChg_UCase_Lut[130] = 144; _SLChg_LCase_Lut[144] = 130;
290 _SLChg_UCase_Lut[145] = 146; _SLChg_LCase_Lut[146] = 145;
291 _SLChg_UCase_Lut[148] = 153; _SLChg_LCase_Lut[153] = 148;
292 _SLChg_UCase_Lut[129] = 154; _SLChg_LCase_Lut[154] = 129;
293 _SLChg_UCase_Lut[164] = 165; _SLChg_LCase_Lut[165] = 164;
294 # else
295 /* ISO Latin */
296 for (i = 192; i <= 221; i++)
297 {
298 j = i + 32;
299 _SLChg_UCase_Lut[j] = i;
300 _SLChg_LCase_Lut[i] = j;
301 }
302 _SLChg_UCase_Lut[215] = 215; _SLChg_LCase_Lut[215] = 215;
303 _SLChg_UCase_Lut[223] = 223; _SLChg_LCase_Lut[223] = 223;
304 _SLChg_UCase_Lut[247] = 247; _SLChg_LCase_Lut[247] = 247;
305 _SLChg_UCase_Lut[255] = 255; _SLChg_LCase_Lut[255] = 255;
306 # endif
307 #endif
308 Case_Tables_Ok = 1;
309 }
310