Merge branch 'cde-fixups-1' of ssh://git.code.sf.net/p/cdesktopenv/code into cde...
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / UAS / DtSR / TextParser.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 // $XConsortium: TextParser.cc /main/4 1996/06/11 17:41:43 cde-hal $
24 /*      Copyright (c) 1995,1996 FUJITSU LIMITED         */
25 /*      All Rights Reserved                             */
26
27 #include <assert.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <sstream>
33 using namespace std;
34
35 #include "TextParser.hh"
36
37 #ifndef False
38 #define False   0
39 #endif
40 #ifndef True
41 #define True    1
42 #endif
43
44 const char *
45 StringParser::brute_force(const char* text_in, int n_of_pats,
46                                 const char* patterns, int sensitive)
47 {
48     if (text_in == NULL || *text_in == '\0')
49         return NULL;
50     else if (patterns == NULL || *patterns == '\0')
51         return NULL;
52
53     if (! (n_of_pats > 0))
54         return NULL;
55
56     char** pat_tbl = new char*[n_of_pats + 1];
57     char** pat_tbl_end = pat_tbl + n_of_pats;
58
59     int npat, len;
60     for (npat = 0; *patterns && n_of_pats > 0; npat++, n_of_pats--) {
61         char* del = (char *)strchr(patterns, '\n');
62         if (del != NULL) { // more pattern specified
63             len = del - patterns;
64             pat_tbl[npat] = new char[len + 1];
65             *((char *) memcpy(pat_tbl[npat], patterns, len) + len) = '\0';
66             patterns = del + 1;
67         }
68         else {
69             int len = strlen(patterns);
70             pat_tbl[npat] = new char[len + 1];
71             *((char *) memcpy(pat_tbl[npat], patterns, len) + len) = '\0';
72             patterns += strlen(patterns);
73             assert( *patterns == '\0' );
74         }
75     }
76     pat_tbl[npat] = NULL; // pointer table terminated
77
78     assert( npat > 0 ); // at least one pattern available here
79
80 #ifdef DEBUG
81     if (*patterns)
82         fprintf(stderr, "(WARNING) more patterns available than specified\n");
83     if (n_of_pats > 0)
84         fprintf(stderr, "(WARNING) less patterns available than specified\n");
85 #endif
86
87     int text_len = strlen(text_in);
88
89     // remove null and too long patterns
90     int i;
91     for (i = 0 ; pat_tbl[i]; i++) {
92         if (*(pat_tbl[i]) == '\0' || text_len < (int) strlen(pat_tbl[i])) {
93             delete[] pat_tbl[i];
94             pat_tbl[i] = NULL;
95             npat--;
96         }
97     }
98
99     // remove redundance
100     char** cursor;
101     for (cursor = pat_tbl; cursor < pat_tbl_end; cursor++) {
102         if (*cursor == NULL)
103             continue;
104         char** p = cursor + 1;
105         for (; p < pat_tbl_end; p++) {
106             if (*p == NULL)
107                 continue;
108             if (strcmp(*cursor, *p) == 0)
109                 break;
110         }
111         if (p < pat_tbl_end) { // same pattern found
112             delete[] *cursor;
113             *cursor = NULL;
114             npat--;
115         }
116     }
117
118     // compact pat_tbl
119     char** free_slot;
120     for (free_slot = pat_tbl; *free_slot; free_slot++);
121     if (free_slot < pat_tbl_end) { // there is a free slot
122         cursor = pat_tbl;
123         for (i = 0; i < npat; i++, cursor++) {
124             // find next pattern
125             for (; *cursor == NULL && cursor < pat_tbl_end; cursor++);
126             assert( cursor < pat_tbl_end );
127             if (free_slot && free_slot < cursor) {
128                 *free_slot = *cursor;
129                 *cursor = NULL;
130                 // find next available free slot
131                 free_slot++;
132                 for (; *free_slot; free_slot++);
133                 if (free_slot == pat_tbl_end)
134                     free_slot = NULL;
135             }
136         }
137     }
138     else {
139         free_slot = NULL;
140     }
141
142     if (npat == 0) { // there is no effective patterns after all
143         delete[] pat_tbl;
144         return NULL;
145     }
146
147 #ifdef DEBUG
148     fprintf(stderr, "(DEBUG) %d effective patterns=", npat);
149     for (int k = 0; pat_tbl[k]; k++) {
150         fprintf(stderr, "\"%s\" ", pat_tbl[k]);
151     }
152     fprintf(stderr, "\n");
153 #endif
154
155     char* caped_text = NULL;
156     string capstr;
157
158     if (sensitive == False) { // case-insensitive search
159         unsigned char *p;
160         for (int i = 0; i < npat; i++) {
161             for (p = (unsigned char*)pat_tbl[i]; *p; p++) {
162                 if (*p < 0x7B && *p > 0x60) // a ... z
163                     *p = *p - 0x20;
164             }
165         }
166         ostringstream capitalized;
167         for (p = (unsigned char*)text_in; *p; p++) {
168             if (*p < 0x7B && *p > 0x60) // a ... z
169                 capitalized << (char)(*p - 0x20); // capitalize
170             else
171                 capitalized << *p;
172         }
173         capstr = capitalized.str();
174         text_in = caped_text = (char *)capstr.c_str();
175     }
176
177     ostringstream text_run;
178
179     for (int index = 0; index < text_len;) {
180         unsigned int candidate = (1 << npat) - 1;
181         unsigned int success = 0;
182         int i, j;
183         for (i = index, j = 0 ; i < text_len + 1 && candidate; i++, j++) {
184             for (int n = 0; n < npat; n++) {
185                 unsigned int mask = 1;
186                 mask = mask << (npat - 1 - n);
187                 if (candidate & mask) { // still candidate
188                     if (pat_tbl[n][j] == '\0') {
189                         success |= mask;
190                         candidate &= ~mask;
191                         continue;
192                     }
193                     else if (pat_tbl[n][j] != text_in[i]) {
194                         candidate &= ~mask;
195                         continue;
196                     }
197                 }
198                 else {
199                     continue;
200                 }
201             }
202         }
203
204         if (success) { // matched
205             // select the longest one
206 #ifdef SETECT_LONGEST
207             int nth = npat;
208 #endif
209             for (int n = 0; success > 0; success /= 0x02, n++) {
210                 if (success & 0x01) {
211 #ifdef SETECT_LONGEST
212                     if (nth == npat)
213                         nth = npat - 1 - n;
214                     else {
215                         if (strlen(pat_tbl[nth])
216                                         < strlen(pat_tbl[npat - 1 - n])) {
217                             nth = npat - 1 - n;
218                         }
219                     }
220 #else
221                     text_run << index << '\t' <<
222                                 strlen(pat_tbl[npat - 1 - n]) << '\n';
223 #endif
224                 }
225             }
226 #ifdef SETECT_LONGEST
227             text_run << index << '\t' << strlen(pat_tbl[nth]) << '\n';
228 #endif
229         }
230
231         index += mblen(text_in + index, MB_CUR_MAX);
232     }
233
234     for (i = 0; i < npat; i++)
235         free (pat_tbl[i]);
236     delete[] pat_tbl;
237
238     if (caped_text)
239         delete[] caped_text;
240
241     static string trunstr = text_run.str();
242
243     if (!trunstr.size())
244         return NULL;
245
246     return trunstr.c_str();
247 }
248
249 const char *
250 StringParser::project_textrun(const char* org_textrun)
251 {
252     if (org_textrun == NULL || *org_textrun == '\0')
253         return NULL;
254
255     istringstream textrun(org_textrun);
256
257     char line[128];
258     textrun.get(line, 128, '\n');
259     if (textrun.get() != '\n')
260         return NULL;
261
262     char *offstr, *lenstr;
263
264     offstr = line;
265     if ((lenstr = strchr(line, '\t')) == NULL)
266         return NULL;
267     *lenstr++ = '\0';
268
269     int off, len;
270     off = atoi(offstr);
271     len = atoi(lenstr);
272     if (off < 0 || len <= 0) {
273 #ifdef DEBUG
274         fprintf(stderr, "(ERROR) either off=%d or len=%d is invalid\n",
275                                                                 off, len);
276 #endif
277         return NULL;
278     }
279
280     ostringstream ret_text;
281
282     while (textrun.get(line, 128, '\n')) {
283         if (textrun.get() != '\n') {
284 #ifdef DEBUG
285             fprintf(stderr, "(ERROR) line is not followed by newline\n");
286 #endif
287             break;
288         }
289
290         int next_off, next_len;
291         offstr = line;
292         if ((lenstr = strchr(line, '\t')) == NULL) {
293 #ifdef DEBUG
294             fprintf(stderr, "(ERROR) tab chatacter not found in \"%s\"\n", line);
295 #endif
296             break;
297         }
298         *lenstr++ = '\0';
299         next_off = atoi(offstr);
300         next_len = atoi(lenstr);
301         if (next_off < off || next_len <= 0) {
302 #ifdef DEBUG
303             fprintf(stderr, "(ERROR) either off=%d or length=%d is invalid\n",
304                                                         next_off, next_len);
305 #endif
306             break;
307         }
308
309         if (next_off <= off + len) { // overlap detected
310             if (off + len < next_off + next_len)
311                 len = next_off + next_len - off; // merge
312         }
313         else {
314             ret_text << off << '\t' << len << '\n';
315             off = next_off;
316             len = next_len;
317         }
318     }
319
320     ret_text << off << '\t' << len << '\n' << '\0';
321
322     static string rettstr = ret_text.str();
323     return rettstr.c_str();
324 }
325
326 const char *
327 StringParser::hilite(const char* text, int n, const char* pats)
328 {
329     const char* textrun = brute_force(text, n, pats);
330
331     if (textrun == NULL)
332         return NULL;
333
334     return project_textrun(textrun);
335 }
336
337
338