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