dtinfo subtree dtinfo
[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 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;
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             pat_tbl[npat] = new char[del - patterns + 1];
64             strncpy(pat_tbl[npat], patterns, del - patterns);
65             pat_tbl[npat][del - patterns] = '\0';
66             patterns = del + 1;
67         }
68         else {
69             pat_tbl[npat] = new char[strlen(patterns) + 1];
70             strcpy(pat_tbl[npat], patterns);
71             patterns += strlen(patterns);
72             assert( *patterns == '\0' );
73         }
74     }
75     pat_tbl[npat] = NULL; // pointer table terminated
76
77     assert( npat > 0 ); // at least one pattern available here
78
79 #ifdef DEBUG
80     if (*patterns)
81         fprintf(stderr, "(WARNING) more patterns available than specified\n");
82     if (n_of_pats > 0)
83         fprintf(stderr, "(WARNING) less patterns available than specified\n");
84 #endif
85
86     int text_len = strlen(text_in);
87
88     // remove null and too long patterns
89     int i;
90     for (i = 0 ; pat_tbl[i]; i++) {
91         if (*(pat_tbl[i]) == '\0' || text_len < strlen(pat_tbl[i])) {
92             delete[] pat_tbl[i];
93             pat_tbl[i] = NULL;
94             npat--;
95         }
96     }
97
98     // remove redundance
99     char** cursor;
100     for (cursor = pat_tbl; cursor < pat_tbl_end; cursor++) {
101         if (*cursor == NULL)
102             continue;
103         char** p = cursor + 1;
104         for (; p < pat_tbl_end; p++) {
105             if (*p == NULL)
106                 continue;
107             if (strcmp(*cursor, *p) == 0)
108                 break;
109         }
110         if (p < pat_tbl_end) { // same pattern found
111             delete[] *cursor;
112             *cursor = NULL;
113             npat--;
114         }
115     }
116
117     // compact pat_tbl
118     char** free_slot;
119     for (free_slot = pat_tbl; *free_slot; free_slot++);
120     if (free_slot < pat_tbl_end) { // there is a free slot
121         cursor = pat_tbl;
122         for (i = 0; i < npat; i++, cursor++) {
123             // find next pattern
124             for (; *cursor == NULL && cursor < pat_tbl_end; cursor++);
125             assert( cursor < pat_tbl_end );
126             if (free_slot && free_slot < cursor) {
127                 *free_slot = *cursor;
128                 *cursor = NULL;
129                 // find next available free slot
130                 free_slot++;
131                 for (; *free_slot; free_slot++);
132                 if (free_slot == pat_tbl_end)
133                     free_slot = NULL;
134             }
135         }
136     }
137     else {
138         free_slot = NULL;
139     }
140
141     if (npat == 0) { // there is no effective patterns after all
142         delete[] pat_tbl;
143         return NULL;
144     }
145
146 #ifdef DEBUG
147     fprintf(stderr, "(DEBUG) %d effective patterns=", npat);
148     for (int k = 0; pat_tbl[k]; k++) {
149         fprintf(stderr, "\"%s\" ", pat_tbl[k]);
150     }
151     fprintf(stderr, "\n");
152 #endif
153
154     char* caped_text = NULL;
155
156     if (sensitive == False) { // case-insensitive search
157         unsigned char *p;
158         for (int i = 0; i < npat; i++) {
159             for (p = (unsigned char*)pat_tbl[i]; *p; p++) {
160                 if (*p < 0x7B && *p > 0x60) // a ... z
161                     *p = *p - 0x20;
162             }
163         }
164         ostringstream capitalized;
165         for (p = (unsigned char*)text_in; *p; p++) {
166             if (*p < 0x7B && *p > 0x60) // a ... z
167                 capitalized << (char)(*p - 0x20); // capitalize
168             else
169                 capitalized << *p;
170         }
171         text_in = caped_text = (char *)capitalized.str().c_str();
172         *(char*)(text_in + capitalized.str().size()) = '\0';
173     }
174
175     ostringstream text_run;
176
177     for (int index = 0; index < text_len;) {
178         unsigned int candidate = (1 << npat) - 1;
179         unsigned int success = 0;
180         int i, j;
181         for (i = index, j = 0 ; i < text_len + 1 && candidate; i++, j++) {
182             for (int n = 0; n < npat; n++) {
183                 unsigned int mask = 1;
184                 mask = mask << (npat - 1 - n);
185                 if (candidate & mask) { // still candidate
186                     if (pat_tbl[n][j] == '\0') {
187                         success |= mask;
188                         candidate &= ~mask;
189                         continue;
190                     }
191                     else if (pat_tbl[n][j] != text_in[i]) {
192                         candidate &= ~mask;
193                         continue;
194                     }
195                 }
196                 else {
197                     continue;
198                 }
199             }
200         }
201
202         if (success) { // matched
203             // select the longest one
204 #ifdef SETECT_LONGEST
205             int nth = npat;
206 #endif
207             for (int n = 0; success > 0; success /= 0x02, n++) {
208                 if (success & 0x01) {
209 #ifdef SETECT_LONGEST
210                     if (nth == npat)
211                         nth = npat - 1 - n;
212                     else {
213                         if (strlen(pat_tbl[nth])
214                                         < strlen(pat_tbl[npat - 1 - n])) {
215                             nth = npat - 1 - n;
216                         }
217                     }
218 #else
219                     text_run << index << '\t' <<
220                                 strlen(pat_tbl[npat - 1 - n]) << '\n';
221 #endif
222                 }
223             }
224 #ifdef SETECT_LONGEST
225             text_run << index << '\t' << strlen(pat_tbl[nth]) << '\n';
226 #endif
227         }
228
229         index += mblen(text_in + index, MB_CUR_MAX);
230     }
231
232     for (i = 0; i < npat; i++)
233         free (pat_tbl[i]);
234     free (pat_tbl);
235
236     if (caped_text)
237         delete[] caped_text;
238
239     char* ret_text = (char *)text_run.str().c_str();
240
241     if (ret_text == NULL)
242         return NULL;
243     else if (*ret_text == '\0') {
244         delete[] ret_text;
245         return NULL;
246     }
247     else
248         return ret_text;
249
250 }
251
252 char *
253 StringParser::project_textrun(const char* org_textrun)
254 {
255     if (org_textrun == NULL || *org_textrun == '\0')
256         return NULL;
257
258     istringstream textrun(org_textrun);
259
260     char line[128];
261     textrun.get(line, 128, '\n');
262     if (textrun.get() != '\n')
263         return NULL;
264
265     char *offstr, *lenstr;
266
267     offstr = line;
268     if ((lenstr = strchr(line, '\t')) == NULL)
269         return NULL;
270     *lenstr++ = '\0';
271
272     int off, len;
273     off = atoi(offstr);
274     len = atoi(lenstr);
275     if (off < 0 || len <= 0) {
276 #ifdef DEBUG
277         fprintf(stderr, "(ERROR) either off=%d or len=%d is invalid\n",
278                                                                 off, len);
279 #endif
280         return NULL;
281     }
282
283     ostringstream ret_text;
284
285     while (textrun.get(line, 128, '\n')) {
286         if (textrun.get() != '\n') {
287 #ifdef DEBUG
288             fprintf(stderr, "(ERROR) line is not followed by newline\n");
289 #endif
290             break;
291         }
292
293         int next_off, next_len;
294         offstr = line;
295         if ((lenstr = strchr(line, '\t')) == NULL) {
296 #ifdef DEBUG
297             fprintf(stderr, "(ERROR) tab chatacter not found in \"%s\"\n", line);
298 #endif
299             break;
300         }
301         *lenstr++ = '\0';
302         next_off = atoi(offstr);
303         next_len = atoi(lenstr);
304         if (next_off < off || next_len <= 0) {
305 #ifdef DEBUG
306             fprintf(stderr, "(ERROR) either off=%d or length=%d is invalid\n",
307                                                         next_off, next_len);
308 #endif
309             break;
310         }
311
312         if (next_off <= off + len) { // overlap detected
313             if (off + len < next_off + next_len)
314                 len = next_off + next_len - off; // merge
315         }
316         else {
317             ret_text << off << '\t' << len << '\n';
318             off = next_off;
319             len = next_len;
320         }
321     }
322
323     ret_text << off << '\t' << len << '\n' << '\0';
324
325     return (char *)ret_text.str().c_str();
326 }
327
328 char *
329 StringParser::hilite(const char* text, int n, const char* pats)
330 {
331     char* textrun = brute_force(text, n, pats);
332
333     if (textrun == NULL)
334         return NULL;
335
336     char* prjed_textrun = project_textrun(textrun);
337     delete[] textrun;
338
339     return prjed_textrun;
340 }
341
342
343