Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * wparser_def.c
4 : : * Default text search parser
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : *
8 : : *
9 : : * IDENTIFICATION
10 : : * src/backend/tsearch/wparser_def.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : :
15 : : #include "postgres.h"
16 : :
17 : : #include <limits.h>
18 : : #include <wctype.h>
19 : :
20 : : #include "commands/defrem.h"
21 : : #include "mb/pg_wchar.h"
22 : : #include "miscadmin.h"
23 : : #include "tsearch/ts_public.h"
24 : : #include "tsearch/ts_type.h"
25 : : #include "tsearch/ts_utils.h"
26 : : #include "utils/builtins.h"
27 : : #include "utils/pg_locale.h"
28 : :
29 : :
30 : : /* Define me to enable tracing of parser behavior */
31 : : /* #define WPARSER_TRACE */
32 : :
33 : :
34 : : /* Output token categories */
35 : :
36 : : #define ASCIIWORD 1
37 : : #define WORD_T 2
38 : : #define NUMWORD 3
39 : : #define EMAIL 4
40 : : #define URL_T 5
41 : : #define HOST 6
42 : : #define SCIENTIFIC 7
43 : : #define VERSIONNUMBER 8
44 : : #define NUMPARTHWORD 9
45 : : #define PARTHWORD 10
46 : : #define ASCIIPARTHWORD 11
47 : : #define SPACE 12
48 : : #define TAG_T 13
49 : : #define PROTOCOL 14
50 : : #define NUMHWORD 15
51 : : #define ASCIIHWORD 16
52 : : #define HWORD 17
53 : : #define URLPATH 18
54 : : #define FILEPATH 19
55 : : #define DECIMAL_T 20
56 : : #define SIGNEDINT 21
57 : : #define UNSIGNEDINT 22
58 : : #define XMLENTITY 23
59 : :
60 : : #define LASTNUM 23
61 : :
62 : : static const char *const tok_alias[] = {
63 : : "",
64 : : "asciiword",
65 : : "word",
66 : : "numword",
67 : : "email",
68 : : "url",
69 : : "host",
70 : : "sfloat",
71 : : "version",
72 : : "hword_numpart",
73 : : "hword_part",
74 : : "hword_asciipart",
75 : : "blank",
76 : : "tag",
77 : : "protocol",
78 : : "numhword",
79 : : "asciihword",
80 : : "hword",
81 : : "url_path",
82 : : "file",
83 : : "float",
84 : : "int",
85 : : "uint",
86 : : "entity"
87 : : };
88 : :
89 : : static const char *const lex_descr[] = {
90 : : "",
91 : : "Word, all ASCII",
92 : : "Word, all letters",
93 : : "Word, letters and digits",
94 : : "Email address",
95 : : "URL",
96 : : "Host",
97 : : "Scientific notation",
98 : : "Version number",
99 : : "Hyphenated word part, letters and digits",
100 : : "Hyphenated word part, all letters",
101 : : "Hyphenated word part, all ASCII",
102 : : "Space symbols",
103 : : "XML tag",
104 : : "Protocol head",
105 : : "Hyphenated word, letters and digits",
106 : : "Hyphenated word, all ASCII",
107 : : "Hyphenated word, all letters",
108 : : "URL path",
109 : : "File or path name",
110 : : "Decimal notation",
111 : : "Signed integer",
112 : : "Unsigned integer",
113 : : "XML entity"
114 : : };
115 : :
116 : :
117 : : /* Parser states */
118 : :
119 : : typedef enum
120 : : {
121 : : TPS_Base = 0,
122 : : TPS_InNumWord,
123 : : TPS_InAsciiWord,
124 : : TPS_InWord,
125 : : TPS_InUnsignedInt,
126 : : TPS_InSignedIntFirst,
127 : : TPS_InSignedInt,
128 : : TPS_InSpace,
129 : : TPS_InUDecimalFirst,
130 : : TPS_InUDecimal,
131 : : TPS_InDecimalFirst,
132 : : TPS_InDecimal,
133 : : TPS_InVerVersion,
134 : : TPS_InSVerVersion,
135 : : TPS_InVersionFirst,
136 : : TPS_InVersion,
137 : : TPS_InMantissaFirst,
138 : : TPS_InMantissaSign,
139 : : TPS_InMantissa,
140 : : TPS_InXMLEntityFirst,
141 : : TPS_InXMLEntity,
142 : : TPS_InXMLEntityNumFirst,
143 : : TPS_InXMLEntityNum,
144 : : TPS_InXMLEntityHexNumFirst,
145 : : TPS_InXMLEntityHexNum,
146 : : TPS_InXMLEntityEnd,
147 : : TPS_InTagFirst,
148 : : TPS_InXMLBegin,
149 : : TPS_InTagCloseFirst,
150 : : TPS_InTagName,
151 : : TPS_InTagBeginEnd,
152 : : TPS_InTag,
153 : : TPS_InTagEscapeK,
154 : : TPS_InTagEscapeKK,
155 : : TPS_InTagBackSleshed,
156 : : TPS_InTagEnd,
157 : : TPS_InCommentFirst,
158 : : TPS_InCommentLast,
159 : : TPS_InComment,
160 : : TPS_InCloseCommentFirst,
161 : : TPS_InCloseCommentLast,
162 : : TPS_InCommentEnd,
163 : : TPS_InHostFirstDomain,
164 : : TPS_InHostDomainSecond,
165 : : TPS_InHostDomain,
166 : : TPS_InPortFirst,
167 : : TPS_InPort,
168 : : TPS_InHostFirstAN,
169 : : TPS_InHost,
170 : : TPS_InEmail,
171 : : TPS_InFileFirst,
172 : : TPS_InFileTwiddle,
173 : : TPS_InPathFirst,
174 : : TPS_InPathFirstFirst,
175 : : TPS_InPathSecond,
176 : : TPS_InFile,
177 : : TPS_InFileNext,
178 : : TPS_InURLPathFirst,
179 : : TPS_InURLPathStart,
180 : : TPS_InURLPath,
181 : : TPS_InFURL,
182 : : TPS_InProtocolFirst,
183 : : TPS_InProtocolSecond,
184 : : TPS_InProtocolEnd,
185 : : TPS_InHyphenAsciiWordFirst,
186 : : TPS_InHyphenAsciiWord,
187 : : TPS_InHyphenWordFirst,
188 : : TPS_InHyphenWord,
189 : : TPS_InHyphenNumWordFirst,
190 : : TPS_InHyphenNumWord,
191 : : TPS_InHyphenDigitLookahead,
192 : : TPS_InParseHyphen,
193 : : TPS_InParseHyphenHyphen,
194 : : TPS_InHyphenWordPart,
195 : : TPS_InHyphenAsciiWordPart,
196 : : TPS_InHyphenNumWordPart,
197 : : TPS_InHyphenUnsignedInt,
198 : : TPS_Null /* last state (fake value) */
199 : : } TParserState;
200 : :
201 : : /* forward declaration */
202 : : struct TParser;
203 : :
204 : : typedef int (*TParserCharTest) (struct TParser *); /* any p_is* functions
205 : : * except p_iseq */
206 : : typedef void (*TParserSpecial) (struct TParser *); /* special handler for
207 : : * special cases... */
208 : :
209 : : typedef struct
210 : : {
211 : : TParserCharTest isclass;
212 : : char c;
213 : : uint16 flags;
214 : : TParserState tostate;
215 : : int type;
216 : : TParserSpecial special;
217 : : } TParserStateActionItem;
218 : :
219 : : /* Flag bits in TParserStateActionItem.flags */
220 : : #define A_NEXT 0x0000
221 : : #define A_BINGO 0x0001
222 : : #define A_POP 0x0002
223 : : #define A_PUSH 0x0004
224 : : #define A_RERUN 0x0008
225 : : #define A_CLEAR 0x0010
226 : : #define A_MERGE 0x0020
227 : : #define A_CLRALL 0x0040
228 : :
229 : : typedef struct TParserPosition
230 : : {
231 : : int posbyte; /* position of parser in bytes */
232 : : int poschar; /* position of parser in characters */
233 : : int charlen; /* length of current char */
234 : : int lenbytetoken; /* length of token-so-far in bytes */
235 : : int lenchartoken; /* and in chars */
236 : : TParserState state;
237 : : struct TParserPosition *prev;
238 : : const TParserStateActionItem *pushedAtAction;
239 : : } TParserPosition;
240 : :
241 : : typedef struct TParser
242 : : {
243 : : /* string and position information */
244 : : char *str; /* multibyte string */
245 : : int lenstr; /* length of mbstring */
246 : : wchar_t *wstr; /* wide character string */
247 : : pg_wchar *pgwstr; /* wide character string for C-locale */
248 : : bool usewide;
249 : :
250 : : /* State of parse */
251 : : int charmaxlen;
252 : : TParserPosition *state;
253 : : bool ignore;
254 : : bool wanthost;
255 : :
256 : : /* silly char */
257 : : char c;
258 : :
259 : : /* out */
260 : : char *token;
261 : : int lenbytetoken;
262 : : int lenchartoken;
263 : : int type;
264 : : } TParser;
265 : :
266 : :
267 : : /* forward decls here */
268 : : static bool TParserGet(TParser *prs);
269 : :
270 : :
271 : : static TParserPosition *
5995 bruce@momjian.us 272 :CBC 5104 : newTParserPosition(TParserPosition *prev)
273 : : {
6081 tgl@sss.pgh.pa.us 274 : 5104 : TParserPosition *res = (TParserPosition *) palloc(sizeof(TParserPosition));
275 : :
276 [ + + ]: 5104 : if (prev)
277 : 2619 : memcpy(res, prev, sizeof(TParserPosition));
278 : : else
279 : 2485 : memset(res, 0, sizeof(TParserPosition));
280 : :
281 : 5104 : res->prev = prev;
282 : :
283 : 5104 : res->pushedAtAction = NULL;
284 : :
285 : 5104 : return res;
286 : : }
287 : :
288 : : static TParser *
289 : 2365 : TParserInit(char *str, int len)
290 : : {
291 : 2365 : TParser *prs = (TParser *) palloc0(sizeof(TParser));
292 : :
293 : 2365 : prs->charmaxlen = pg_database_encoding_max_length();
294 : 2365 : prs->str = str;
295 : 2365 : prs->lenstr = len;
296 : :
297 : : /*
298 : : * Use wide char code only when max encoding length > 1.
299 : : */
300 [ + - ]: 2365 : if (prs->charmaxlen > 1)
301 : : {
2489 302 : 2365 : pg_locale_t mylocale = 0; /* TODO */
303 : :
6081 304 : 2365 : prs->usewide = true;
394 jdavis@postgresql.or 305 [ + + ]: 2365 : if (database_ctype_is_c)
306 : : {
307 : : /*
308 : : * char2wchar doesn't work for C-locale and sizeof(pg_wchar) could
309 : : * be different from sizeof(wchar_t)
310 : : */
4753 bruce@momjian.us 311 : 787 : prs->pgwstr = (pg_wchar *) palloc(sizeof(pg_wchar) * (prs->lenstr + 1));
5522 teodor@sigaev.ru 312 : 787 : pg_mb2wchar_with_len(prs->str, prs->pgwstr, prs->lenstr);
313 : : }
314 : : else
315 : : {
316 : 1578 : prs->wstr = (wchar_t *) palloc(sizeof(wchar_t) * (prs->lenstr + 1));
4740 tgl@sss.pgh.pa.us 317 : 1578 : char2wchar(prs->wstr, prs->lenstr + 1, prs->str, prs->lenstr,
318 : : mylocale);
319 : : }
320 : : }
321 : : else
6081 tgl@sss.pgh.pa.us 322 :UBC 0 : prs->usewide = false;
323 : :
6081 tgl@sss.pgh.pa.us 324 :CBC 2365 : prs->state = newTParserPosition(NULL);
325 : 2365 : prs->state->state = TPS_Base;
326 : :
327 : : #ifdef WPARSER_TRACE
328 : : fprintf(stderr, "parsing \"%.*s\"\n", len, str);
329 : : #endif
330 : :
331 : 2365 : return prs;
332 : : }
333 : :
334 : : /*
335 : : * As an alternative to a full TParserInit one can create a
336 : : * TParserCopy which basically is a regular TParser without a private
337 : : * copy of the string - instead it uses the one from another TParser.
338 : : * This is useful because at some places TParsers are created
339 : : * recursively and the repeated copying around of the strings can
340 : : * cause major inefficiency if the source string is long.
341 : : * The new parser starts parsing at the original's current position.
342 : : *
343 : : * Obviously one must not close the original TParser before the copy.
344 : : */
345 : : static TParser *
5234 346 : 120 : TParserCopyInit(const TParser *orig)
347 : : {
348 : 120 : TParser *prs = (TParser *) palloc0(sizeof(TParser));
349 : :
350 : 120 : prs->charmaxlen = orig->charmaxlen;
351 : 120 : prs->str = orig->str + orig->state->posbyte;
352 : 120 : prs->lenstr = orig->lenstr - orig->state->posbyte;
353 : 120 : prs->usewide = orig->usewide;
354 : :
355 [ + + ]: 120 : if (orig->pgwstr)
356 : 40 : prs->pgwstr = orig->pgwstr + orig->state->poschar;
357 [ + + ]: 120 : if (orig->wstr)
358 : 80 : prs->wstr = orig->wstr + orig->state->poschar;
359 : :
360 : 120 : prs->state = newTParserPosition(NULL);
361 : 120 : prs->state->state = TPS_Base;
362 : :
363 : : #ifdef WPARSER_TRACE
364 : : fprintf(stderr, "parsing copy of \"%.*s\"\n", prs->lenstr, prs->str);
365 : : #endif
366 : :
367 : 120 : return prs;
368 : : }
369 : :
370 : :
371 : : static void
5995 bruce@momjian.us 372 : 2365 : TParserClose(TParser *prs)
373 : : {
6081 tgl@sss.pgh.pa.us 374 [ + + ]: 4730 : while (prs->state)
375 : : {
376 : 2365 : TParserPosition *ptr = prs->state->prev;
377 : :
378 : 2365 : pfree(prs->state);
379 : 2365 : prs->state = ptr;
380 : : }
381 : :
382 [ + + ]: 2365 : if (prs->wstr)
383 : 1578 : pfree(prs->wstr);
5522 teodor@sigaev.ru 384 [ + + ]: 2365 : if (prs->pgwstr)
385 : 787 : pfree(prs->pgwstr);
386 : :
387 : : #ifdef WPARSER_TRACE
388 : : fprintf(stderr, "closing parser\n");
389 : : #endif
6081 tgl@sss.pgh.pa.us 390 : 2365 : pfree(prs);
391 : 2365 : }
392 : :
393 : : /*
394 : : * Close a parser created with TParserCopyInit
395 : : */
396 : : static void
5234 397 : 120 : TParserCopyClose(TParser *prs)
398 : : {
399 [ + + ]: 306 : while (prs->state)
400 : : {
401 : 186 : TParserPosition *ptr = prs->state->prev;
402 : :
403 : 186 : pfree(prs->state);
404 : 186 : prs->state = ptr;
405 : : }
406 : :
407 : : #ifdef WPARSER_TRACE
408 : : fprintf(stderr, "closing parser copy\n");
409 : : #endif
410 : 120 : pfree(prs);
411 : 120 : }
412 : :
413 : :
414 : : /*
415 : : * Character-type support functions, equivalent to is* macros, but
416 : : * working with any possible encodings and locales. Notes:
417 : : * - with multibyte encoding and C-locale isw* function may fail
418 : : * or give wrong result.
419 : : * - multibyte encoding and C-locale often are used for
420 : : * Asian languages.
421 : : * - if locale is C then we use pgwstr instead of wstr.
422 : : */
423 : :
424 : : #define p_iswhat(type, nonascii) \
425 : : \
426 : : static int \
427 : : p_is##type(TParser *prs) \
428 : : { \
429 : : Assert(prs->state); \
430 : : if (prs->usewide) \
431 : : { \
432 : : if (prs->pgwstr) \
433 : : { \
434 : : unsigned int c = *(prs->pgwstr + prs->state->poschar); \
435 : : if (c > 0x7f) \
436 : : return nonascii; \
437 : : return is##type(c); \
438 : : } \
439 : : return isw##type(*(prs->wstr + prs->state->poschar)); \
440 : : } \
441 : : return is##type(*(unsigned char *) (prs->str + prs->state->posbyte)); \
442 : : } \
443 : : \
444 : : static int \
445 : : p_isnot##type(TParser *prs) \
446 : : { \
447 : : return !p_is##type(prs); \
448 : : }
449 : :
450 : : /*
451 : : * In C locale with a multibyte encoding, any non-ASCII symbol is considered
452 : : * an alpha character, but not a member of other char classes.
453 : : */
2396 454 [ - + + - : 12561 : p_iswhat(alnum, 1)
+ + - + ]
455 [ - + + - : 46886 : p_iswhat(alpha, 1)
+ + - + ]
456 [ - + + - : 18566 : p_iswhat(digit, 0)
+ + - + ]
2396 tgl@sss.pgh.pa.us 457 [ # # # # :UBC 0 : p_iswhat(lower, 0)
# # # # ]
458 [ # # # # : 0 : p_iswhat(print, 0)
# # # # ]
459 [ # # # # : 0 : p_iswhat(punct, 0)
# # # # ]
2396 tgl@sss.pgh.pa.us 460 [ - + + - :CBC 339 : p_iswhat(space, 0)
+ + - + ]
2396 tgl@sss.pgh.pa.us 461 [ # # # # :UBC 0 : p_iswhat(upper, 0)
# # # # ]
2396 tgl@sss.pgh.pa.us 462 [ - + + - :CBC 9 : p_iswhat(xdigit, 0)
+ + - + ]
463 : :
464 : : /* p_iseq should be used only for ascii symbols */
465 : :
466 : : static int
5995 bruce@momjian.us 467 : 115684 : p_iseq(TParser *prs, char c)
468 : : {
6081 tgl@sss.pgh.pa.us 469 [ - + ]: 115684 : Assert(prs->state);
470 [ + - + + ]: 115684 : return ((prs->state->charlen == 1 && *(prs->str + prs->state->posbyte) == c)) ? 1 : 0;
471 : : }
472 : :
473 : : static int
5995 bruce@momjian.us 474 : 50025 : p_isEOF(TParser *prs)
475 : : {
6081 tgl@sss.pgh.pa.us 476 [ - + ]: 50025 : Assert(prs->state);
477 [ + + - + ]: 50025 : return (prs->state->posbyte == prs->lenstr || prs->state->charlen == 0) ? 1 : 0;
478 : : }
479 : :
480 : : static int
5995 bruce@momjian.us 481 : 115684 : p_iseqC(TParser *prs)
482 : : {
6081 tgl@sss.pgh.pa.us 483 : 115684 : return p_iseq(prs, prs->c);
484 : : }
485 : :
486 : : static int
5995 bruce@momjian.us 487 :UBC 0 : p_isneC(TParser *prs)
488 : : {
6081 tgl@sss.pgh.pa.us 489 : 0 : return !p_iseq(prs, prs->c);
490 : : }
491 : :
492 : : static int
5995 bruce@momjian.us 493 :CBC 36730 : p_isascii(TParser *prs)
494 : : {
6081 tgl@sss.pgh.pa.us 495 [ + - + - ]: 36730 : return (prs->state->charlen == 1 && isascii((unsigned char) *(prs->str + prs->state->posbyte))) ? 1 : 0;
496 : : }
497 : :
498 : : static int
5995 bruce@momjian.us 499 : 36730 : p_isasclet(TParser *prs)
500 : : {
6018 tgl@sss.pgh.pa.us 501 [ + - + + ]: 36730 : return (p_isascii(prs) && p_isalpha(prs)) ? 1 : 0;
502 : : }
503 : :
504 : : static int
5100 505 : 1329 : p_isurlchar(TParser *prs)
506 : : {
507 : : char ch;
508 : :
509 : : /* no non-ASCII need apply */
510 [ - + ]: 1329 : if (prs->state->charlen != 1)
5100 tgl@sss.pgh.pa.us 511 :UBC 0 : return 0;
5100 tgl@sss.pgh.pa.us 512 :CBC 1329 : ch = *(prs->str + prs->state->posbyte);
513 : : /* no spaces or control characters */
514 [ + + - + ]: 1329 : if (ch <= 0x20 || ch >= 0x7F)
515 : 117 : return 0;
516 : : /* reject characters disallowed by RFC 3986 */
517 [ + + ]: 1212 : switch (ch)
518 : : {
519 : 12 : case '"':
520 : : case '<':
521 : : case '>':
522 : : case '\\':
523 : : case '^':
524 : : case '`':
525 : : case '{':
526 : : case '|':
527 : : case '}':
528 : 12 : return 0;
529 : : }
530 : 1200 : return 1;
531 : : }
532 : :
533 : :
534 : : /* deliberately suppress unused-function complaints for the above */
535 : : void _make_compiler_happy(void);
536 : : void
6081 tgl@sss.pgh.pa.us 537 :UBC 0 : _make_compiler_happy(void)
538 : : {
539 : 0 : p_isalnum(NULL);
540 : 0 : p_isnotalnum(NULL);
541 : 0 : p_isalpha(NULL);
542 : 0 : p_isnotalpha(NULL);
543 : 0 : p_isdigit(NULL);
544 : 0 : p_isnotdigit(NULL);
545 : 0 : p_islower(NULL);
546 : 0 : p_isnotlower(NULL);
547 : 0 : p_isprint(NULL);
548 : 0 : p_isnotprint(NULL);
549 : 0 : p_ispunct(NULL);
550 : 0 : p_isnotpunct(NULL);
551 : 0 : p_isspace(NULL);
552 : 0 : p_isnotspace(NULL);
553 : 0 : p_isupper(NULL);
554 : 0 : p_isnotupper(NULL);
555 : 0 : p_isxdigit(NULL);
556 : 0 : p_isnotxdigit(NULL);
557 : 0 : p_isEOF(NULL);
558 : 0 : p_iseqC(NULL);
559 : 0 : p_isneC(NULL);
560 : 0 : }
561 : :
562 : :
563 : : static void
5995 bruce@momjian.us 564 :CBC 126 : SpecialTags(TParser *prs)
565 : : {
6014 tgl@sss.pgh.pa.us 566 [ + + + + ]: 126 : switch (prs->state->lenchartoken)
567 : : {
2489 568 : 3 : case 8: /* </script */
6014 569 [ + - ]: 3 : if (pg_strncasecmp(prs->token, "</script", 8) == 0)
6081 570 : 3 : prs->ignore = false;
571 : 3 : break;
2489 572 : 12 : case 7: /* <script || </style */
6014 573 [ - + ]: 12 : if (pg_strncasecmp(prs->token, "</style", 7) == 0)
6081 tgl@sss.pgh.pa.us 574 :UBC 0 : prs->ignore = false;
6014 tgl@sss.pgh.pa.us 575 [ + + ]:CBC 12 : else if (pg_strncasecmp(prs->token, "<script", 7) == 0)
6081 576 : 3 : prs->ignore = true;
577 : 12 : break;
2489 578 : 9 : case 6: /* <style */
6014 579 [ - + ]: 9 : if (pg_strncasecmp(prs->token, "<style", 6) == 0)
6081 tgl@sss.pgh.pa.us 580 :UBC 0 : prs->ignore = true;
6081 tgl@sss.pgh.pa.us 581 :CBC 9 : break;
582 : 102 : default:
583 : 102 : break;
584 : : }
585 : 126 : }
586 : :
587 : : static void
5995 bruce@momjian.us 588 : 66 : SpecialFURL(TParser *prs)
589 : : {
6081 tgl@sss.pgh.pa.us 590 : 66 : prs->wanthost = true;
6014 591 : 66 : prs->state->posbyte -= prs->state->lenbytetoken;
592 : 66 : prs->state->poschar -= prs->state->lenchartoken;
6081 593 : 66 : }
594 : :
595 : : static void
5995 bruce@momjian.us 596 : 18 : SpecialHyphen(TParser *prs)
597 : : {
6014 tgl@sss.pgh.pa.us 598 : 18 : prs->state->posbyte -= prs->state->lenbytetoken;
599 : 18 : prs->state->poschar -= prs->state->lenchartoken;
6081 600 : 18 : }
601 : :
602 : : static void
5995 bruce@momjian.us 603 :UBC 0 : SpecialVerVersion(TParser *prs)
604 : : {
6014 tgl@sss.pgh.pa.us 605 : 0 : prs->state->posbyte -= prs->state->lenbytetoken;
606 : 0 : prs->state->poschar -= prs->state->lenchartoken;
607 : 0 : prs->state->lenbytetoken = 0;
608 : 0 : prs->state->lenchartoken = 0;
6081 609 : 0 : }
610 : :
611 : : static int
5995 bruce@momjian.us 612 :CBC 240 : p_isstophost(TParser *prs)
613 : : {
6081 tgl@sss.pgh.pa.us 614 [ + + ]: 240 : if (prs->wanthost)
615 : : {
616 : 102 : prs->wanthost = false;
617 : 102 : return 1;
618 : : }
619 : 138 : return 0;
620 : : }
621 : :
622 : : static int
5995 bruce@momjian.us 623 : 18031 : p_isignore(TParser *prs)
624 : : {
6081 tgl@sss.pgh.pa.us 625 : 18031 : return (prs->ignore) ? 1 : 0;
626 : : }
627 : :
628 : : static int
5995 bruce@momjian.us 629 : 45 : p_ishost(TParser *prs)
630 : : {
4753 631 : 45 : TParser *tmpprs = TParserCopyInit(prs);
6081 tgl@sss.pgh.pa.us 632 : 45 : int res = 0;
633 : :
5514 teodor@sigaev.ru 634 : 45 : tmpprs->wanthost = true;
635 : :
636 : : /*
637 : : * Check stack depth before recursing. (Since TParserGet() doesn't
638 : : * normally recurse, we put the cost of checking here not there.)
639 : : */
295 tgl@sss.pgh.pa.us 640 : 45 : check_stack_depth();
641 : :
6081 642 [ + - + + ]: 45 : if (TParserGet(tmpprs) && tmpprs->type == HOST)
643 : : {
6014 644 : 36 : prs->state->posbyte += tmpprs->lenbytetoken;
645 : 36 : prs->state->poschar += tmpprs->lenchartoken;
646 : 36 : prs->state->lenbytetoken += tmpprs->lenbytetoken;
647 : 36 : prs->state->lenchartoken += tmpprs->lenchartoken;
6081 648 : 36 : prs->state->charlen = tmpprs->state->charlen;
649 : 36 : res = 1;
650 : : }
5234 651 : 45 : TParserCopyClose(tmpprs);
652 : :
6081 653 : 45 : return res;
654 : : }
655 : :
656 : : static int
5995 bruce@momjian.us 657 : 75 : p_isURLPath(TParser *prs)
658 : : {
4753 659 : 75 : TParser *tmpprs = TParserCopyInit(prs);
6081 tgl@sss.pgh.pa.us 660 : 75 : int res = 0;
661 : :
662 : 75 : tmpprs->state = newTParserPosition(tmpprs->state);
5100 663 : 75 : tmpprs->state->state = TPS_InURLPathFirst;
664 : :
665 : : /*
666 : : * Check stack depth before recursing. (Since TParserGet() doesn't
667 : : * normally recurse, we put the cost of checking here not there.)
668 : : */
295 669 : 75 : check_stack_depth();
670 : :
5100 671 [ + - + + ]: 75 : if (TParserGet(tmpprs) && tmpprs->type == URLPATH)
672 : : {
6014 673 : 66 : prs->state->posbyte += tmpprs->lenbytetoken;
674 : 66 : prs->state->poschar += tmpprs->lenchartoken;
675 : 66 : prs->state->lenbytetoken += tmpprs->lenbytetoken;
676 : 66 : prs->state->lenchartoken += tmpprs->lenchartoken;
6081 677 : 66 : prs->state->charlen = tmpprs->state->charlen;
678 : 66 : res = 1;
679 : : }
5234 680 : 75 : TParserCopyClose(tmpprs);
681 : :
6081 682 : 75 : return res;
683 : : }
684 : :
685 : : /*
686 : : * returns true if current character has zero display length or
687 : : * it's a special sign in several languages. Such characters
688 : : * aren't a word-breaker although they aren't an isalpha.
689 : : * In beginning of word they aren't a part of it.
690 : : */
691 : : static int
5513 teodor@sigaev.ru 692 : 4362 : p_isspecial(TParser *prs)
693 : : {
694 : : /*
695 : : * pg_dsplen could return -1 which means error or control character
696 : : */
4753 bruce@momjian.us 697 [ - + ]: 4362 : if (pg_dsplen(prs->str + prs->state->posbyte) == 0)
5513 teodor@sigaev.ru 698 :UBC 0 : return 1;
699 : :
700 : : /*
701 : : * Unicode Characters in the 'Mark, Spacing Combining' Category That
702 : : * characters are not alpha although they are not breakers of word too.
703 : : * Check that only in utf encoding, because other encodings aren't
704 : : * supported by postgres or even exists.
705 : : */
4753 bruce@momjian.us 706 [ + - + - ]:CBC 4362 : if (GetDatabaseEncoding() == PG_UTF8 && prs->usewide)
707 : : {
708 : : static const pg_wchar strange_letter[] = {
709 : : /*
710 : : * use binary search, so elements should be ordered
711 : : */
712 : : 0x0903, /* DEVANAGARI SIGN VISARGA */
713 : : 0x093E, /* DEVANAGARI VOWEL SIGN AA */
714 : : 0x093F, /* DEVANAGARI VOWEL SIGN I */
715 : : 0x0940, /* DEVANAGARI VOWEL SIGN II */
716 : : 0x0949, /* DEVANAGARI VOWEL SIGN CANDRA O */
717 : : 0x094A, /* DEVANAGARI VOWEL SIGN SHORT O */
718 : : 0x094B, /* DEVANAGARI VOWEL SIGN O */
719 : : 0x094C, /* DEVANAGARI VOWEL SIGN AU */
720 : : 0x0982, /* BENGALI SIGN ANUSVARA */
721 : : 0x0983, /* BENGALI SIGN VISARGA */
722 : : 0x09BE, /* BENGALI VOWEL SIGN AA */
723 : : 0x09BF, /* BENGALI VOWEL SIGN I */
724 : : 0x09C0, /* BENGALI VOWEL SIGN II */
725 : : 0x09C7, /* BENGALI VOWEL SIGN E */
726 : : 0x09C8, /* BENGALI VOWEL SIGN AI */
727 : : 0x09CB, /* BENGALI VOWEL SIGN O */
728 : : 0x09CC, /* BENGALI VOWEL SIGN AU */
729 : : 0x09D7, /* BENGALI AU LENGTH MARK */
730 : : 0x0A03, /* GURMUKHI SIGN VISARGA */
731 : : 0x0A3E, /* GURMUKHI VOWEL SIGN AA */
732 : : 0x0A3F, /* GURMUKHI VOWEL SIGN I */
733 : : 0x0A40, /* GURMUKHI VOWEL SIGN II */
734 : : 0x0A83, /* GUJARATI SIGN VISARGA */
735 : : 0x0ABE, /* GUJARATI VOWEL SIGN AA */
736 : : 0x0ABF, /* GUJARATI VOWEL SIGN I */
737 : : 0x0AC0, /* GUJARATI VOWEL SIGN II */
738 : : 0x0AC9, /* GUJARATI VOWEL SIGN CANDRA O */
739 : : 0x0ACB, /* GUJARATI VOWEL SIGN O */
740 : : 0x0ACC, /* GUJARATI VOWEL SIGN AU */
741 : : 0x0B02, /* ORIYA SIGN ANUSVARA */
742 : : 0x0B03, /* ORIYA SIGN VISARGA */
743 : : 0x0B3E, /* ORIYA VOWEL SIGN AA */
744 : : 0x0B40, /* ORIYA VOWEL SIGN II */
745 : : 0x0B47, /* ORIYA VOWEL SIGN E */
746 : : 0x0B48, /* ORIYA VOWEL SIGN AI */
747 : : 0x0B4B, /* ORIYA VOWEL SIGN O */
748 : : 0x0B4C, /* ORIYA VOWEL SIGN AU */
749 : : 0x0B57, /* ORIYA AU LENGTH MARK */
750 : : 0x0BBE, /* TAMIL VOWEL SIGN AA */
751 : : 0x0BBF, /* TAMIL VOWEL SIGN I */
752 : : 0x0BC1, /* TAMIL VOWEL SIGN U */
753 : : 0x0BC2, /* TAMIL VOWEL SIGN UU */
754 : : 0x0BC6, /* TAMIL VOWEL SIGN E */
755 : : 0x0BC7, /* TAMIL VOWEL SIGN EE */
756 : : 0x0BC8, /* TAMIL VOWEL SIGN AI */
757 : : 0x0BCA, /* TAMIL VOWEL SIGN O */
758 : : 0x0BCB, /* TAMIL VOWEL SIGN OO */
759 : : 0x0BCC, /* TAMIL VOWEL SIGN AU */
760 : : 0x0BD7, /* TAMIL AU LENGTH MARK */
761 : : 0x0C01, /* TELUGU SIGN CANDRABINDU */
762 : : 0x0C02, /* TELUGU SIGN ANUSVARA */
763 : : 0x0C03, /* TELUGU SIGN VISARGA */
764 : : 0x0C41, /* TELUGU VOWEL SIGN U */
765 : : 0x0C42, /* TELUGU VOWEL SIGN UU */
766 : : 0x0C43, /* TELUGU VOWEL SIGN VOCALIC R */
767 : : 0x0C44, /* TELUGU VOWEL SIGN VOCALIC RR */
768 : : 0x0C82, /* KANNADA SIGN ANUSVARA */
769 : : 0x0C83, /* KANNADA SIGN VISARGA */
770 : : 0x0CBE, /* KANNADA VOWEL SIGN AA */
771 : : 0x0CC0, /* KANNADA VOWEL SIGN II */
772 : : 0x0CC1, /* KANNADA VOWEL SIGN U */
773 : : 0x0CC2, /* KANNADA VOWEL SIGN UU */
774 : : 0x0CC3, /* KANNADA VOWEL SIGN VOCALIC R */
775 : : 0x0CC4, /* KANNADA VOWEL SIGN VOCALIC RR */
776 : : 0x0CC7, /* KANNADA VOWEL SIGN EE */
777 : : 0x0CC8, /* KANNADA VOWEL SIGN AI */
778 : : 0x0CCA, /* KANNADA VOWEL SIGN O */
779 : : 0x0CCB, /* KANNADA VOWEL SIGN OO */
780 : : 0x0CD5, /* KANNADA LENGTH MARK */
781 : : 0x0CD6, /* KANNADA AI LENGTH MARK */
782 : : 0x0D02, /* MALAYALAM SIGN ANUSVARA */
783 : : 0x0D03, /* MALAYALAM SIGN VISARGA */
784 : : 0x0D3E, /* MALAYALAM VOWEL SIGN AA */
785 : : 0x0D3F, /* MALAYALAM VOWEL SIGN I */
786 : : 0x0D40, /* MALAYALAM VOWEL SIGN II */
787 : : 0x0D46, /* MALAYALAM VOWEL SIGN E */
788 : : 0x0D47, /* MALAYALAM VOWEL SIGN EE */
789 : : 0x0D48, /* MALAYALAM VOWEL SIGN AI */
790 : : 0x0D4A, /* MALAYALAM VOWEL SIGN O */
791 : : 0x0D4B, /* MALAYALAM VOWEL SIGN OO */
792 : : 0x0D4C, /* MALAYALAM VOWEL SIGN AU */
793 : : 0x0D57, /* MALAYALAM AU LENGTH MARK */
794 : : 0x0D82, /* SINHALA SIGN ANUSVARAYA */
795 : : 0x0D83, /* SINHALA SIGN VISARGAYA */
796 : : 0x0DCF, /* SINHALA VOWEL SIGN AELA-PILLA */
797 : : 0x0DD0, /* SINHALA VOWEL SIGN KETTI AEDA-PILLA */
798 : : 0x0DD1, /* SINHALA VOWEL SIGN DIGA AEDA-PILLA */
799 : : 0x0DD8, /* SINHALA VOWEL SIGN GAETTA-PILLA */
800 : : 0x0DD9, /* SINHALA VOWEL SIGN KOMBUVA */
801 : : 0x0DDA, /* SINHALA VOWEL SIGN DIGA KOMBUVA */
802 : : 0x0DDB, /* SINHALA VOWEL SIGN KOMBU DEKA */
803 : : 0x0DDC, /* SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA */
804 : : 0x0DDD, /* SINHALA VOWEL SIGN KOMBUVA HAA DIGA
805 : : * AELA-PILLA */
806 : : 0x0DDE, /* SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA */
807 : : 0x0DDF, /* SINHALA VOWEL SIGN GAYANUKITTA */
808 : : 0x0DF2, /* SINHALA VOWEL SIGN DIGA GAETTA-PILLA */
809 : : 0x0DF3, /* SINHALA VOWEL SIGN DIGA GAYANUKITTA */
810 : : 0x0F3E, /* TIBETAN SIGN YAR TSHES */
811 : : 0x0F3F, /* TIBETAN SIGN MAR TSHES */
812 : : 0x0F7F, /* TIBETAN SIGN RNAM BCAD */
813 : : 0x102B, /* MYANMAR VOWEL SIGN TALL AA */
814 : : 0x102C, /* MYANMAR VOWEL SIGN AA */
815 : : 0x1031, /* MYANMAR VOWEL SIGN E */
816 : : 0x1038, /* MYANMAR SIGN VISARGA */
817 : : 0x103B, /* MYANMAR CONSONANT SIGN MEDIAL YA */
818 : : 0x103C, /* MYANMAR CONSONANT SIGN MEDIAL RA */
819 : : 0x1056, /* MYANMAR VOWEL SIGN VOCALIC R */
820 : : 0x1057, /* MYANMAR VOWEL SIGN VOCALIC RR */
821 : : 0x1062, /* MYANMAR VOWEL SIGN SGAW KAREN EU */
822 : : 0x1063, /* MYANMAR TONE MARK SGAW KAREN HATHI */
823 : : 0x1064, /* MYANMAR TONE MARK SGAW KAREN KE PHO */
824 : : 0x1067, /* MYANMAR VOWEL SIGN WESTERN PWO KAREN EU */
825 : : 0x1068, /* MYANMAR VOWEL SIGN WESTERN PWO KAREN UE */
826 : : 0x1069, /* MYANMAR SIGN WESTERN PWO KAREN TONE-1 */
827 : : 0x106A, /* MYANMAR SIGN WESTERN PWO KAREN TONE-2 */
828 : : 0x106B, /* MYANMAR SIGN WESTERN PWO KAREN TONE-3 */
829 : : 0x106C, /* MYANMAR SIGN WESTERN PWO KAREN TONE-4 */
830 : : 0x106D, /* MYANMAR SIGN WESTERN PWO KAREN TONE-5 */
831 : : 0x1083, /* MYANMAR VOWEL SIGN SHAN AA */
832 : : 0x1084, /* MYANMAR VOWEL SIGN SHAN E */
833 : : 0x1087, /* MYANMAR SIGN SHAN TONE-2 */
834 : : 0x1088, /* MYANMAR SIGN SHAN TONE-3 */
835 : : 0x1089, /* MYANMAR SIGN SHAN TONE-5 */
836 : : 0x108A, /* MYANMAR SIGN SHAN TONE-6 */
837 : : 0x108B, /* MYANMAR SIGN SHAN COUNCIL TONE-2 */
838 : : 0x108C, /* MYANMAR SIGN SHAN COUNCIL TONE-3 */
839 : : 0x108F, /* MYANMAR SIGN RUMAI PALAUNG TONE-5 */
840 : : 0x17B6, /* KHMER VOWEL SIGN AA */
841 : : 0x17BE, /* KHMER VOWEL SIGN OE */
842 : : 0x17BF, /* KHMER VOWEL SIGN YA */
843 : : 0x17C0, /* KHMER VOWEL SIGN IE */
844 : : 0x17C1, /* KHMER VOWEL SIGN E */
845 : : 0x17C2, /* KHMER VOWEL SIGN AE */
846 : : 0x17C3, /* KHMER VOWEL SIGN AI */
847 : : 0x17C4, /* KHMER VOWEL SIGN OO */
848 : : 0x17C5, /* KHMER VOWEL SIGN AU */
849 : : 0x17C7, /* KHMER SIGN REAHMUK */
850 : : 0x17C8, /* KHMER SIGN YUUKALEAPINTU */
851 : : 0x1923, /* LIMBU VOWEL SIGN EE */
852 : : 0x1924, /* LIMBU VOWEL SIGN AI */
853 : : 0x1925, /* LIMBU VOWEL SIGN OO */
854 : : 0x1926, /* LIMBU VOWEL SIGN AU */
855 : : 0x1929, /* LIMBU SUBJOINED LETTER YA */
856 : : 0x192A, /* LIMBU SUBJOINED LETTER RA */
857 : : 0x192B, /* LIMBU SUBJOINED LETTER WA */
858 : : 0x1930, /* LIMBU SMALL LETTER KA */
859 : : 0x1931, /* LIMBU SMALL LETTER NGA */
860 : : 0x1933, /* LIMBU SMALL LETTER TA */
861 : : 0x1934, /* LIMBU SMALL LETTER NA */
862 : : 0x1935, /* LIMBU SMALL LETTER PA */
863 : : 0x1936, /* LIMBU SMALL LETTER MA */
864 : : 0x1937, /* LIMBU SMALL LETTER RA */
865 : : 0x1938, /* LIMBU SMALL LETTER LA */
866 : : 0x19B0, /* NEW TAI LUE VOWEL SIGN VOWEL SHORTENER */
867 : : 0x19B1, /* NEW TAI LUE VOWEL SIGN AA */
868 : : 0x19B2, /* NEW TAI LUE VOWEL SIGN II */
869 : : 0x19B3, /* NEW TAI LUE VOWEL SIGN U */
870 : : 0x19B4, /* NEW TAI LUE VOWEL SIGN UU */
871 : : 0x19B5, /* NEW TAI LUE VOWEL SIGN E */
872 : : 0x19B6, /* NEW TAI LUE VOWEL SIGN AE */
873 : : 0x19B7, /* NEW TAI LUE VOWEL SIGN O */
874 : : 0x19B8, /* NEW TAI LUE VOWEL SIGN OA */
875 : : 0x19B9, /* NEW TAI LUE VOWEL SIGN UE */
876 : : 0x19BA, /* NEW TAI LUE VOWEL SIGN AY */
877 : : 0x19BB, /* NEW TAI LUE VOWEL SIGN AAY */
878 : : 0x19BC, /* NEW TAI LUE VOWEL SIGN UY */
879 : : 0x19BD, /* NEW TAI LUE VOWEL SIGN OY */
880 : : 0x19BE, /* NEW TAI LUE VOWEL SIGN OAY */
881 : : 0x19BF, /* NEW TAI LUE VOWEL SIGN UEY */
882 : : 0x19C0, /* NEW TAI LUE VOWEL SIGN IY */
883 : : 0x19C8, /* NEW TAI LUE TONE MARK-1 */
884 : : 0x19C9, /* NEW TAI LUE TONE MARK-2 */
885 : : 0x1A19, /* BUGINESE VOWEL SIGN E */
886 : : 0x1A1A, /* BUGINESE VOWEL SIGN O */
887 : : 0x1A1B, /* BUGINESE VOWEL SIGN AE */
888 : : 0x1B04, /* BALINESE SIGN BISAH */
889 : : 0x1B35, /* BALINESE VOWEL SIGN TEDUNG */
890 : : 0x1B3B, /* BALINESE VOWEL SIGN RA REPA TEDUNG */
891 : : 0x1B3D, /* BALINESE VOWEL SIGN LA LENGA TEDUNG */
892 : : 0x1B3E, /* BALINESE VOWEL SIGN TALING */
893 : : 0x1B3F, /* BALINESE VOWEL SIGN TALING REPA */
894 : : 0x1B40, /* BALINESE VOWEL SIGN TALING TEDUNG */
895 : : 0x1B41, /* BALINESE VOWEL SIGN TALING REPA TEDUNG */
896 : : 0x1B43, /* BALINESE VOWEL SIGN PEPET TEDUNG */
897 : : 0x1B44, /* BALINESE ADEG ADEG */
898 : : 0x1B82, /* SUNDANESE SIGN PANGWISAD */
899 : : 0x1BA1, /* SUNDANESE CONSONANT SIGN PAMINGKAL */
900 : : 0x1BA6, /* SUNDANESE VOWEL SIGN PANAELAENG */
901 : : 0x1BA7, /* SUNDANESE VOWEL SIGN PANOLONG */
902 : : 0x1BAA, /* SUNDANESE SIGN PAMAAEH */
903 : : 0x1C24, /* LEPCHA SUBJOINED LETTER YA */
904 : : 0x1C25, /* LEPCHA SUBJOINED LETTER RA */
905 : : 0x1C26, /* LEPCHA VOWEL SIGN AA */
906 : : 0x1C27, /* LEPCHA VOWEL SIGN I */
907 : : 0x1C28, /* LEPCHA VOWEL SIGN O */
908 : : 0x1C29, /* LEPCHA VOWEL SIGN OO */
909 : : 0x1C2A, /* LEPCHA VOWEL SIGN U */
910 : : 0x1C2B, /* LEPCHA VOWEL SIGN UU */
911 : : 0x1C34, /* LEPCHA CONSONANT SIGN NYIN-DO */
912 : : 0x1C35, /* LEPCHA CONSONANT SIGN KANG */
913 : : 0xA823, /* SYLOTI NAGRI VOWEL SIGN A */
914 : : 0xA824, /* SYLOTI NAGRI VOWEL SIGN I */
915 : : 0xA827, /* SYLOTI NAGRI VOWEL SIGN OO */
916 : : 0xA880, /* SAURASHTRA SIGN ANUSVARA */
917 : : 0xA881, /* SAURASHTRA SIGN VISARGA */
918 : : 0xA8B4, /* SAURASHTRA CONSONANT SIGN HAARU */
919 : : 0xA8B5, /* SAURASHTRA VOWEL SIGN AA */
920 : : 0xA8B6, /* SAURASHTRA VOWEL SIGN I */
921 : : 0xA8B7, /* SAURASHTRA VOWEL SIGN II */
922 : : 0xA8B8, /* SAURASHTRA VOWEL SIGN U */
923 : : 0xA8B9, /* SAURASHTRA VOWEL SIGN UU */
924 : : 0xA8BA, /* SAURASHTRA VOWEL SIGN VOCALIC R */
925 : : 0xA8BB, /* SAURASHTRA VOWEL SIGN VOCALIC RR */
926 : : 0xA8BC, /* SAURASHTRA VOWEL SIGN VOCALIC L */
927 : : 0xA8BD, /* SAURASHTRA VOWEL SIGN VOCALIC LL */
928 : : 0xA8BE, /* SAURASHTRA VOWEL SIGN E */
929 : : 0xA8BF, /* SAURASHTRA VOWEL SIGN EE */
930 : : 0xA8C0, /* SAURASHTRA VOWEL SIGN AI */
931 : : 0xA8C1, /* SAURASHTRA VOWEL SIGN O */
932 : : 0xA8C2, /* SAURASHTRA VOWEL SIGN OO */
933 : : 0xA8C3, /* SAURASHTRA VOWEL SIGN AU */
934 : : 0xA952, /* REJANG CONSONANT SIGN H */
935 : : 0xA953, /* REJANG VIRAMA */
936 : : 0xAA2F, /* CHAM VOWEL SIGN O */
937 : : 0xAA30, /* CHAM VOWEL SIGN AI */
938 : : 0xAA33, /* CHAM CONSONANT SIGN YA */
939 : : 0xAA34, /* CHAM CONSONANT SIGN RA */
940 : : 0xAA4D /* CHAM CONSONANT SIGN FINAL H */
941 : : };
3739 tgl@sss.pgh.pa.us 942 : 4362 : const pg_wchar *StopLow = strange_letter,
4753 bruce@momjian.us 943 : 4362 : *StopHigh = strange_letter + lengthof(strange_letter),
944 : : *StopMiddle;
945 : : pg_wchar c;
946 : :
947 [ + + ]: 4362 : if (prs->pgwstr)
5513 teodor@sigaev.ru 948 : 1454 : c = *(prs->pgwstr + prs->state->poschar);
949 : : else
950 : 2908 : c = (pg_wchar) *(prs->wstr + prs->state->poschar);
951 : :
4753 bruce@momjian.us 952 [ + + ]: 39258 : while (StopLow < StopHigh)
953 : : {
5513 teodor@sigaev.ru 954 : 34896 : StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
4753 bruce@momjian.us 955 [ - + ]: 34896 : if (*StopMiddle == c)
5513 teodor@sigaev.ru 956 :UBC 0 : return 1;
4753 bruce@momjian.us 957 [ - + ]:CBC 34896 : else if (*StopMiddle < c)
5513 teodor@sigaev.ru 958 :UBC 0 : StopLow = StopMiddle + 1;
959 : : else
5513 teodor@sigaev.ru 960 :CBC 34896 : StopHigh = StopMiddle;
961 : : }
962 : : }
963 : :
964 : 4362 : return 0;
965 : : }
966 : :
967 : : /*
968 : : * Table of state/action of parser
969 : : */
970 : :
971 : : static const TParserStateActionItem actionTPS_Base[] = {
972 : : {p_isEOF, 0, A_NEXT, TPS_Null, 0, NULL},
973 : : {p_iseqC, '<', A_PUSH, TPS_InTagFirst, 0, NULL},
974 : : {p_isignore, 0, A_NEXT, TPS_InSpace, 0, NULL},
975 : : {p_isasclet, 0, A_NEXT, TPS_InAsciiWord, 0, NULL},
976 : : {p_isalpha, 0, A_NEXT, TPS_InWord, 0, NULL},
977 : : {p_isdigit, 0, A_NEXT, TPS_InUnsignedInt, 0, NULL},
978 : : {p_iseqC, '-', A_PUSH, TPS_InSignedIntFirst, 0, NULL},
979 : : {p_iseqC, '+', A_PUSH, TPS_InSignedIntFirst, 0, NULL},
980 : : {p_iseqC, '&', A_PUSH, TPS_InXMLEntityFirst, 0, NULL},
981 : : {p_iseqC, '~', A_PUSH, TPS_InFileTwiddle, 0, NULL},
982 : : {p_iseqC, '/', A_PUSH, TPS_InFileFirst, 0, NULL},
983 : : {p_iseqC, '.', A_PUSH, TPS_InPathFirstFirst, 0, NULL},
984 : : {NULL, 0, A_NEXT, TPS_InSpace, 0, NULL}
985 : : };
986 : :
987 : :
988 : : static const TParserStateActionItem actionTPS_InNumWord[] = {
989 : : {p_isEOF, 0, A_BINGO, TPS_Base, NUMWORD, NULL},
990 : : {p_isalnum, 0, A_NEXT, TPS_InNumWord, 0, NULL},
991 : : {p_isspecial, 0, A_NEXT, TPS_InNumWord, 0, NULL},
992 : : {p_iseqC, '@', A_PUSH, TPS_InEmail, 0, NULL},
993 : : {p_iseqC, '/', A_PUSH, TPS_InFileFirst, 0, NULL},
994 : : {p_iseqC, '.', A_PUSH, TPS_InFileNext, 0, NULL},
995 : : {p_iseqC, '-', A_PUSH, TPS_InHyphenNumWordFirst, 0, NULL},
996 : : {NULL, 0, A_BINGO, TPS_Base, NUMWORD, NULL}
997 : : };
998 : :
999 : : static const TParserStateActionItem actionTPS_InAsciiWord[] = {
1000 : : {p_isEOF, 0, A_BINGO, TPS_Base, ASCIIWORD, NULL},
1001 : : {p_isasclet, 0, A_NEXT, TPS_Null, 0, NULL},
1002 : : {p_iseqC, '.', A_PUSH, TPS_InHostFirstDomain, 0, NULL},
1003 : : {p_iseqC, '.', A_PUSH, TPS_InFileNext, 0, NULL},
1004 : : {p_iseqC, '-', A_PUSH, TPS_InHostFirstAN, 0, NULL},
1005 : : {p_iseqC, '-', A_PUSH, TPS_InHyphenAsciiWordFirst, 0, NULL},
1006 : : {p_iseqC, '_', A_PUSH, TPS_InHostFirstAN, 0, NULL},
1007 : : {p_iseqC, '@', A_PUSH, TPS_InEmail, 0, NULL},
1008 : : {p_iseqC, ':', A_PUSH, TPS_InProtocolFirst, 0, NULL},
1009 : : {p_iseqC, '/', A_PUSH, TPS_InFileFirst, 0, NULL},
1010 : : {p_isdigit, 0, A_PUSH, TPS_InHost, 0, NULL},
1011 : : {p_isdigit, 0, A_NEXT, TPS_InNumWord, 0, NULL},
1012 : : {p_isalpha, 0, A_NEXT, TPS_InWord, 0, NULL},
1013 : : {p_isspecial, 0, A_NEXT, TPS_InWord, 0, NULL},
1014 : : {NULL, 0, A_BINGO, TPS_Base, ASCIIWORD, NULL}
1015 : : };
1016 : :
1017 : : static const TParserStateActionItem actionTPS_InWord[] = {
1018 : : {p_isEOF, 0, A_BINGO, TPS_Base, WORD_T, NULL},
1019 : : {p_isalpha, 0, A_NEXT, TPS_Null, 0, NULL},
1020 : : {p_isspecial, 0, A_NEXT, TPS_Null, 0, NULL},
1021 : : {p_isdigit, 0, A_NEXT, TPS_InNumWord, 0, NULL},
1022 : : {p_iseqC, '-', A_PUSH, TPS_InHyphenWordFirst, 0, NULL},
1023 : : {NULL, 0, A_BINGO, TPS_Base, WORD_T, NULL}
1024 : : };
1025 : :
1026 : : static const TParserStateActionItem actionTPS_InUnsignedInt[] = {
1027 : : {p_isEOF, 0, A_BINGO, TPS_Base, UNSIGNEDINT, NULL},
1028 : : {p_isdigit, 0, A_NEXT, TPS_Null, 0, NULL},
1029 : : {p_iseqC, '.', A_PUSH, TPS_InHostFirstDomain, 0, NULL},
1030 : : {p_iseqC, '.', A_PUSH, TPS_InUDecimalFirst, 0, NULL},
1031 : : {p_iseqC, 'e', A_PUSH, TPS_InMantissaFirst, 0, NULL},
1032 : : {p_iseqC, 'E', A_PUSH, TPS_InMantissaFirst, 0, NULL},
1033 : : {p_iseqC, '-', A_PUSH, TPS_InHostFirstAN, 0, NULL},
1034 : : {p_iseqC, '_', A_PUSH, TPS_InHostFirstAN, 0, NULL},
1035 : : {p_iseqC, '@', A_PUSH, TPS_InEmail, 0, NULL},
1036 : : {p_isasclet, 0, A_PUSH, TPS_InHost, 0, NULL},
1037 : : {p_isalpha, 0, A_NEXT, TPS_InNumWord, 0, NULL},
1038 : : {p_isspecial, 0, A_NEXT, TPS_InNumWord, 0, NULL},
1039 : : {p_iseqC, '/', A_PUSH, TPS_InFileFirst, 0, NULL},
1040 : : {NULL, 0, A_BINGO, TPS_Base, UNSIGNEDINT, NULL}
1041 : : };
1042 : :
1043 : : static const TParserStateActionItem actionTPS_InSignedIntFirst[] = {
1044 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1045 : : {p_isdigit, 0, A_NEXT | A_CLEAR, TPS_InSignedInt, 0, NULL},
1046 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1047 : : };
1048 : :
1049 : : static const TParserStateActionItem actionTPS_InSignedInt[] = {
1050 : : {p_isEOF, 0, A_BINGO, TPS_Base, SIGNEDINT, NULL},
1051 : : {p_isdigit, 0, A_NEXT, TPS_Null, 0, NULL},
1052 : : {p_iseqC, '.', A_PUSH, TPS_InDecimalFirst, 0, NULL},
1053 : : {p_iseqC, 'e', A_PUSH, TPS_InMantissaFirst, 0, NULL},
1054 : : {p_iseqC, 'E', A_PUSH, TPS_InMantissaFirst, 0, NULL},
1055 : : {NULL, 0, A_BINGO, TPS_Base, SIGNEDINT, NULL}
1056 : : };
1057 : :
1058 : : static const TParserStateActionItem actionTPS_InSpace[] = {
1059 : : {p_isEOF, 0, A_BINGO, TPS_Base, SPACE, NULL},
1060 : : {p_iseqC, '<', A_BINGO, TPS_Base, SPACE, NULL},
1061 : : {p_isignore, 0, A_NEXT, TPS_Null, 0, NULL},
1062 : : {p_iseqC, '-', A_BINGO, TPS_Base, SPACE, NULL},
1063 : : {p_iseqC, '+', A_BINGO, TPS_Base, SPACE, NULL},
1064 : : {p_iseqC, '&', A_BINGO, TPS_Base, SPACE, NULL},
1065 : : {p_iseqC, '/', A_BINGO, TPS_Base, SPACE, NULL},
1066 : : {p_isnotalnum, 0, A_NEXT, TPS_InSpace, 0, NULL},
1067 : : {NULL, 0, A_BINGO, TPS_Base, SPACE, NULL}
1068 : : };
1069 : :
1070 : : static const TParserStateActionItem actionTPS_InUDecimalFirst[] = {
1071 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1072 : : {p_isdigit, 0, A_CLEAR, TPS_InUDecimal, 0, NULL},
1073 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1074 : : };
1075 : :
1076 : : static const TParserStateActionItem actionTPS_InUDecimal[] = {
1077 : : {p_isEOF, 0, A_BINGO, TPS_Base, DECIMAL_T, NULL},
1078 : : {p_isdigit, 0, A_NEXT, TPS_InUDecimal, 0, NULL},
1079 : : {p_iseqC, '.', A_PUSH, TPS_InVersionFirst, 0, NULL},
1080 : : {p_iseqC, 'e', A_PUSH, TPS_InMantissaFirst, 0, NULL},
1081 : : {p_iseqC, 'E', A_PUSH, TPS_InMantissaFirst, 0, NULL},
1082 : : {NULL, 0, A_BINGO, TPS_Base, DECIMAL_T, NULL}
1083 : : };
1084 : :
1085 : : static const TParserStateActionItem actionTPS_InDecimalFirst[] = {
1086 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1087 : : {p_isdigit, 0, A_CLEAR, TPS_InDecimal, 0, NULL},
1088 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1089 : : };
1090 : :
1091 : : static const TParserStateActionItem actionTPS_InDecimal[] = {
1092 : : {p_isEOF, 0, A_BINGO, TPS_Base, DECIMAL_T, NULL},
1093 : : {p_isdigit, 0, A_NEXT, TPS_InDecimal, 0, NULL},
1094 : : {p_iseqC, '.', A_PUSH, TPS_InVerVersion, 0, NULL},
1095 : : {p_iseqC, 'e', A_PUSH, TPS_InMantissaFirst, 0, NULL},
1096 : : {p_iseqC, 'E', A_PUSH, TPS_InMantissaFirst, 0, NULL},
1097 : : {NULL, 0, A_BINGO, TPS_Base, DECIMAL_T, NULL}
1098 : : };
1099 : :
1100 : : static const TParserStateActionItem actionTPS_InVerVersion[] = {
1101 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1102 : : {p_isdigit, 0, A_RERUN, TPS_InSVerVersion, 0, SpecialVerVersion},
1103 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1104 : : };
1105 : :
1106 : : static const TParserStateActionItem actionTPS_InSVerVersion[] = {
1107 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1108 : : {p_isdigit, 0, A_BINGO | A_CLRALL, TPS_InUnsignedInt, SPACE, NULL},
1109 : : {NULL, 0, A_NEXT, TPS_Null, 0, NULL}
1110 : : };
1111 : :
1112 : :
1113 : : static const TParserStateActionItem actionTPS_InVersionFirst[] = {
1114 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1115 : : {p_isdigit, 0, A_CLEAR, TPS_InVersion, 0, NULL},
1116 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1117 : : };
1118 : :
1119 : : static const TParserStateActionItem actionTPS_InVersion[] = {
1120 : : {p_isEOF, 0, A_BINGO, TPS_Base, VERSIONNUMBER, NULL},
1121 : : {p_isdigit, 0, A_NEXT, TPS_InVersion, 0, NULL},
1122 : : {p_iseqC, '.', A_PUSH, TPS_InVersionFirst, 0, NULL},
1123 : : {NULL, 0, A_BINGO, TPS_Base, VERSIONNUMBER, NULL}
1124 : : };
1125 : :
1126 : : static const TParserStateActionItem actionTPS_InMantissaFirst[] = {
1127 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1128 : : {p_isdigit, 0, A_CLEAR, TPS_InMantissa, 0, NULL},
1129 : : {p_iseqC, '+', A_NEXT, TPS_InMantissaSign, 0, NULL},
1130 : : {p_iseqC, '-', A_NEXT, TPS_InMantissaSign, 0, NULL},
1131 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1132 : : };
1133 : :
1134 : : static const TParserStateActionItem actionTPS_InMantissaSign[] = {
1135 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1136 : : {p_isdigit, 0, A_CLEAR, TPS_InMantissa, 0, NULL},
1137 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1138 : : };
1139 : :
1140 : : static const TParserStateActionItem actionTPS_InMantissa[] = {
1141 : : {p_isEOF, 0, A_BINGO, TPS_Base, SCIENTIFIC, NULL},
1142 : : {p_isdigit, 0, A_NEXT, TPS_InMantissa, 0, NULL},
1143 : : {NULL, 0, A_BINGO, TPS_Base, SCIENTIFIC, NULL}
1144 : : };
1145 : :
1146 : : static const TParserStateActionItem actionTPS_InXMLEntityFirst[] = {
1147 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1148 : : {p_iseqC, '#', A_NEXT, TPS_InXMLEntityNumFirst, 0, NULL},
1149 : : {p_isasclet, 0, A_NEXT, TPS_InXMLEntity, 0, NULL},
1150 : : {p_iseqC, ':', A_NEXT, TPS_InXMLEntity, 0, NULL},
1151 : : {p_iseqC, '_', A_NEXT, TPS_InXMLEntity, 0, NULL},
1152 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1153 : : };
1154 : :
1155 : : static const TParserStateActionItem actionTPS_InXMLEntity[] = {
1156 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1157 : : {p_isalnum, 0, A_NEXT, TPS_InXMLEntity, 0, NULL},
1158 : : {p_iseqC, ':', A_NEXT, TPS_InXMLEntity, 0, NULL},
1159 : : {p_iseqC, '_', A_NEXT, TPS_InXMLEntity, 0, NULL},
1160 : : {p_iseqC, '.', A_NEXT, TPS_InXMLEntity, 0, NULL},
1161 : : {p_iseqC, '-', A_NEXT, TPS_InXMLEntity, 0, NULL},
1162 : : {p_iseqC, ';', A_NEXT, TPS_InXMLEntityEnd, 0, NULL},
1163 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1164 : : };
1165 : :
1166 : : static const TParserStateActionItem actionTPS_InXMLEntityNumFirst[] = {
1167 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1168 : : {p_iseqC, 'x', A_NEXT, TPS_InXMLEntityHexNumFirst, 0, NULL},
1169 : : {p_iseqC, 'X', A_NEXT, TPS_InXMLEntityHexNumFirst, 0, NULL},
1170 : : {p_isdigit, 0, A_NEXT, TPS_InXMLEntityNum, 0, NULL},
1171 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1172 : : };
1173 : :
1174 : : static const TParserStateActionItem actionTPS_InXMLEntityHexNumFirst[] = {
1175 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1176 : : {p_isxdigit, 0, A_NEXT, TPS_InXMLEntityHexNum, 0, NULL},
1177 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1178 : : };
1179 : :
1180 : : static const TParserStateActionItem actionTPS_InXMLEntityNum[] = {
1181 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1182 : : {p_isdigit, 0, A_NEXT, TPS_InXMLEntityNum, 0, NULL},
1183 : : {p_iseqC, ';', A_NEXT, TPS_InXMLEntityEnd, 0, NULL},
1184 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1185 : : };
1186 : :
1187 : : static const TParserStateActionItem actionTPS_InXMLEntityHexNum[] = {
1188 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1189 : : {p_isxdigit, 0, A_NEXT, TPS_InXMLEntityHexNum, 0, NULL},
1190 : : {p_iseqC, ';', A_NEXT, TPS_InXMLEntityEnd, 0, NULL},
1191 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1192 : : };
1193 : :
1194 : : static const TParserStateActionItem actionTPS_InXMLEntityEnd[] = {
1195 : : {NULL, 0, A_BINGO | A_CLEAR, TPS_Base, XMLENTITY, NULL}
1196 : : };
1197 : :
1198 : : static const TParserStateActionItem actionTPS_InTagFirst[] = {
1199 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1200 : : {p_iseqC, '/', A_PUSH, TPS_InTagCloseFirst, 0, NULL},
1201 : : {p_iseqC, '!', A_PUSH, TPS_InCommentFirst, 0, NULL},
1202 : : {p_iseqC, '?', A_PUSH, TPS_InXMLBegin, 0, NULL},
1203 : : {p_isasclet, 0, A_PUSH, TPS_InTagName, 0, NULL},
1204 : : {p_iseqC, ':', A_PUSH, TPS_InTagName, 0, NULL},
1205 : : {p_iseqC, '_', A_PUSH, TPS_InTagName, 0, NULL},
1206 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1207 : : };
1208 : :
1209 : : static const TParserStateActionItem actionTPS_InXMLBegin[] = {
1210 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1211 : : /* <?xml ... */
1212 : : /* XXX do we wants states for the m and l ? Right now this accepts <?xZ */
1213 : : {p_iseqC, 'x', A_NEXT, TPS_InTag, 0, NULL},
1214 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1215 : : };
1216 : :
1217 : : static const TParserStateActionItem actionTPS_InTagCloseFirst[] = {
1218 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1219 : : {p_isasclet, 0, A_NEXT, TPS_InTagName, 0, NULL},
1220 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1221 : : };
1222 : :
1223 : : static const TParserStateActionItem actionTPS_InTagName[] = {
1224 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1225 : : /* <br/> case */
1226 : : {p_iseqC, '/', A_NEXT, TPS_InTagBeginEnd, 0, NULL},
1227 : : {p_iseqC, '>', A_NEXT, TPS_InTagEnd, 0, SpecialTags},
1228 : : {p_isspace, 0, A_NEXT, TPS_InTag, 0, SpecialTags},
1229 : : {p_isalnum, 0, A_NEXT, TPS_Null, 0, NULL},
1230 : : {p_iseqC, ':', A_NEXT, TPS_Null, 0, NULL},
1231 : : {p_iseqC, '_', A_NEXT, TPS_Null, 0, NULL},
1232 : : {p_iseqC, '.', A_NEXT, TPS_Null, 0, NULL},
1233 : : {p_iseqC, '-', A_NEXT, TPS_Null, 0, NULL},
1234 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1235 : : };
1236 : :
1237 : : static const TParserStateActionItem actionTPS_InTagBeginEnd[] = {
1238 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1239 : : {p_iseqC, '>', A_NEXT, TPS_InTagEnd, 0, NULL},
1240 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1241 : : };
1242 : :
1243 : : static const TParserStateActionItem actionTPS_InTag[] = {
1244 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1245 : : {p_iseqC, '>', A_NEXT, TPS_InTagEnd, 0, SpecialTags},
1246 : : {p_iseqC, '\'', A_NEXT, TPS_InTagEscapeK, 0, NULL},
1247 : : {p_iseqC, '"', A_NEXT, TPS_InTagEscapeKK, 0, NULL},
1248 : : {p_isasclet, 0, A_NEXT, TPS_Null, 0, NULL},
1249 : : {p_isdigit, 0, A_NEXT, TPS_Null, 0, NULL},
1250 : : {p_iseqC, '=', A_NEXT, TPS_Null, 0, NULL},
1251 : : {p_iseqC, '-', A_NEXT, TPS_Null, 0, NULL},
1252 : : {p_iseqC, '_', A_NEXT, TPS_Null, 0, NULL},
1253 : : {p_iseqC, '#', A_NEXT, TPS_Null, 0, NULL},
1254 : : {p_iseqC, '/', A_NEXT, TPS_Null, 0, NULL},
1255 : : {p_iseqC, ':', A_NEXT, TPS_Null, 0, NULL},
1256 : : {p_iseqC, '.', A_NEXT, TPS_Null, 0, NULL},
1257 : : {p_iseqC, '&', A_NEXT, TPS_Null, 0, NULL},
1258 : : {p_iseqC, '?', A_NEXT, TPS_Null, 0, NULL},
1259 : : {p_iseqC, '%', A_NEXT, TPS_Null, 0, NULL},
1260 : : {p_iseqC, '~', A_NEXT, TPS_Null, 0, NULL},
1261 : : {p_isspace, 0, A_NEXT, TPS_Null, 0, SpecialTags},
1262 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1263 : : };
1264 : :
1265 : : static const TParserStateActionItem actionTPS_InTagEscapeK[] = {
1266 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1267 : : {p_iseqC, '\\', A_PUSH, TPS_InTagBackSleshed, 0, NULL},
1268 : : {p_iseqC, '\'', A_NEXT, TPS_InTag, 0, NULL},
1269 : : {NULL, 0, A_NEXT, TPS_InTagEscapeK, 0, NULL}
1270 : : };
1271 : :
1272 : : static const TParserStateActionItem actionTPS_InTagEscapeKK[] = {
1273 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1274 : : {p_iseqC, '\\', A_PUSH, TPS_InTagBackSleshed, 0, NULL},
1275 : : {p_iseqC, '"', A_NEXT, TPS_InTag, 0, NULL},
1276 : : {NULL, 0, A_NEXT, TPS_InTagEscapeKK, 0, NULL}
1277 : : };
1278 : :
1279 : : static const TParserStateActionItem actionTPS_InTagBackSleshed[] = {
1280 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1281 : : {NULL, 0, A_MERGE, TPS_Null, 0, NULL}
1282 : : };
1283 : :
1284 : : static const TParserStateActionItem actionTPS_InTagEnd[] = {
1285 : : {NULL, 0, A_BINGO | A_CLRALL, TPS_Base, TAG_T, NULL}
1286 : : };
1287 : :
1288 : : static const TParserStateActionItem actionTPS_InCommentFirst[] = {
1289 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1290 : : {p_iseqC, '-', A_NEXT, TPS_InCommentLast, 0, NULL},
1291 : : /* <!DOCTYPE ...> */
1292 : : {p_iseqC, 'D', A_NEXT, TPS_InTag, 0, NULL},
1293 : : {p_iseqC, 'd', A_NEXT, TPS_InTag, 0, NULL},
1294 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1295 : : };
1296 : :
1297 : : static const TParserStateActionItem actionTPS_InCommentLast[] = {
1298 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1299 : : {p_iseqC, '-', A_NEXT, TPS_InComment, 0, NULL},
1300 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1301 : : };
1302 : :
1303 : : static const TParserStateActionItem actionTPS_InComment[] = {
1304 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1305 : : {p_iseqC, '-', A_NEXT, TPS_InCloseCommentFirst, 0, NULL},
1306 : : {NULL, 0, A_NEXT, TPS_Null, 0, NULL}
1307 : : };
1308 : :
1309 : : static const TParserStateActionItem actionTPS_InCloseCommentFirst[] = {
1310 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1311 : : {p_iseqC, '-', A_NEXT, TPS_InCloseCommentLast, 0, NULL},
1312 : : {NULL, 0, A_NEXT, TPS_InComment, 0, NULL}
1313 : : };
1314 : :
1315 : : static const TParserStateActionItem actionTPS_InCloseCommentLast[] = {
1316 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1317 : : {p_iseqC, '-', A_NEXT, TPS_Null, 0, NULL},
1318 : : {p_iseqC, '>', A_NEXT, TPS_InCommentEnd, 0, NULL},
1319 : : {NULL, 0, A_NEXT, TPS_InComment, 0, NULL}
1320 : : };
1321 : :
1322 : : static const TParserStateActionItem actionTPS_InCommentEnd[] = {
1323 : : {NULL, 0, A_BINGO | A_CLRALL, TPS_Base, TAG_T, NULL}
1324 : : };
1325 : :
1326 : : static const TParserStateActionItem actionTPS_InHostFirstDomain[] = {
1327 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1328 : : {p_isasclet, 0, A_NEXT, TPS_InHostDomainSecond, 0, NULL},
1329 : : {p_isdigit, 0, A_NEXT, TPS_InHost, 0, NULL},
1330 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1331 : : };
1332 : :
1333 : : static const TParserStateActionItem actionTPS_InHostDomainSecond[] = {
1334 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1335 : : {p_isasclet, 0, A_NEXT, TPS_InHostDomain, 0, NULL},
1336 : : {p_isdigit, 0, A_PUSH, TPS_InHost, 0, NULL},
1337 : : {p_iseqC, '-', A_PUSH, TPS_InHostFirstAN, 0, NULL},
1338 : : {p_iseqC, '_', A_PUSH, TPS_InHostFirstAN, 0, NULL},
1339 : : {p_iseqC, '.', A_PUSH, TPS_InHostFirstDomain, 0, NULL},
1340 : : {p_iseqC, '@', A_PUSH, TPS_InEmail, 0, NULL},
1341 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1342 : : };
1343 : :
1344 : : static const TParserStateActionItem actionTPS_InHostDomain[] = {
1345 : : {p_isEOF, 0, A_BINGO | A_CLRALL, TPS_Base, HOST, NULL},
1346 : : {p_isasclet, 0, A_NEXT, TPS_InHostDomain, 0, NULL},
1347 : : {p_isdigit, 0, A_PUSH, TPS_InHost, 0, NULL},
1348 : : {p_iseqC, ':', A_PUSH, TPS_InPortFirst, 0, NULL},
1349 : : {p_iseqC, '-', A_PUSH, TPS_InHostFirstAN, 0, NULL},
1350 : : {p_iseqC, '_', A_PUSH, TPS_InHostFirstAN, 0, NULL},
1351 : : {p_iseqC, '.', A_PUSH, TPS_InHostFirstDomain, 0, NULL},
1352 : : {p_iseqC, '@', A_PUSH, TPS_InEmail, 0, NULL},
1353 : : {p_isdigit, 0, A_POP, TPS_Null, 0, NULL},
1354 : : {p_isstophost, 0, A_BINGO | A_CLRALL, TPS_InURLPathStart, HOST, NULL},
1355 : : {p_iseqC, '/', A_PUSH, TPS_InFURL, 0, NULL},
1356 : : {NULL, 0, A_BINGO | A_CLRALL, TPS_Base, HOST, NULL}
1357 : : };
1358 : :
1359 : : static const TParserStateActionItem actionTPS_InPortFirst[] = {
1360 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1361 : : {p_isdigit, 0, A_NEXT, TPS_InPort, 0, NULL},
1362 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1363 : : };
1364 : :
1365 : : static const TParserStateActionItem actionTPS_InPort[] = {
1366 : : {p_isEOF, 0, A_BINGO | A_CLRALL, TPS_Base, HOST, NULL},
1367 : : {p_isdigit, 0, A_NEXT, TPS_InPort, 0, NULL},
1368 : : {p_isstophost, 0, A_BINGO | A_CLRALL, TPS_InURLPathStart, HOST, NULL},
1369 : : {p_iseqC, '/', A_PUSH, TPS_InFURL, 0, NULL},
1370 : : {NULL, 0, A_BINGO | A_CLRALL, TPS_Base, HOST, NULL}
1371 : : };
1372 : :
1373 : : static const TParserStateActionItem actionTPS_InHostFirstAN[] = {
1374 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1375 : : {p_isdigit, 0, A_NEXT, TPS_InHost, 0, NULL},
1376 : : {p_isasclet, 0, A_NEXT, TPS_InHost, 0, NULL},
1377 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1378 : : };
1379 : :
1380 : : static const TParserStateActionItem actionTPS_InHost[] = {
1381 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1382 : : {p_isdigit, 0, A_NEXT, TPS_InHost, 0, NULL},
1383 : : {p_isasclet, 0, A_NEXT, TPS_InHost, 0, NULL},
1384 : : {p_iseqC, '@', A_PUSH, TPS_InEmail, 0, NULL},
1385 : : {p_iseqC, '.', A_PUSH, TPS_InHostFirstDomain, 0, NULL},
1386 : : {p_iseqC, '-', A_PUSH, TPS_InHostFirstAN, 0, NULL},
1387 : : {p_iseqC, '_', A_PUSH, TPS_InHostFirstAN, 0, NULL},
1388 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1389 : : };
1390 : :
1391 : : static const TParserStateActionItem actionTPS_InEmail[] = {
1392 : : {p_isstophost, 0, A_POP, TPS_Null, 0, NULL},
1393 : : {p_ishost, 0, A_BINGO | A_CLRALL, TPS_Base, EMAIL, NULL},
1394 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1395 : : };
1396 : :
1397 : : static const TParserStateActionItem actionTPS_InFileFirst[] = {
1398 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1399 : : {p_isasclet, 0, A_NEXT, TPS_InFile, 0, NULL},
1400 : : {p_isdigit, 0, A_NEXT, TPS_InFile, 0, NULL},
1401 : : {p_iseqC, '.', A_NEXT, TPS_InPathFirst, 0, NULL},
1402 : : {p_iseqC, '_', A_NEXT, TPS_InFile, 0, NULL},
1403 : : {p_iseqC, '~', A_PUSH, TPS_InFileTwiddle, 0, NULL},
1404 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1405 : : };
1406 : :
1407 : : static const TParserStateActionItem actionTPS_InFileTwiddle[] = {
1408 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1409 : : {p_isasclet, 0, A_NEXT, TPS_InFile, 0, NULL},
1410 : : {p_isdigit, 0, A_NEXT, TPS_InFile, 0, NULL},
1411 : : {p_iseqC, '_', A_NEXT, TPS_InFile, 0, NULL},
1412 : : {p_iseqC, '/', A_NEXT, TPS_InFileFirst, 0, NULL},
1413 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1414 : : };
1415 : :
1416 : : static const TParserStateActionItem actionTPS_InPathFirst[] = {
1417 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1418 : : {p_isasclet, 0, A_NEXT, TPS_InFile, 0, NULL},
1419 : : {p_isdigit, 0, A_NEXT, TPS_InFile, 0, NULL},
1420 : : {p_iseqC, '_', A_NEXT, TPS_InFile, 0, NULL},
1421 : : {p_iseqC, '.', A_NEXT, TPS_InPathSecond, 0, NULL},
1422 : : {p_iseqC, '/', A_NEXT, TPS_InFileFirst, 0, NULL},
1423 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1424 : : };
1425 : :
1426 : : static const TParserStateActionItem actionTPS_InPathFirstFirst[] = {
1427 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1428 : : {p_iseqC, '.', A_NEXT, TPS_InPathSecond, 0, NULL},
1429 : : {p_iseqC, '/', A_NEXT, TPS_InFileFirst, 0, NULL},
1430 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1431 : : };
1432 : :
1433 : : static const TParserStateActionItem actionTPS_InPathSecond[] = {
1434 : : {p_isEOF, 0, A_BINGO | A_CLEAR, TPS_Base, FILEPATH, NULL},
1435 : : {p_iseqC, '/', A_NEXT | A_PUSH, TPS_InFileFirst, 0, NULL},
1436 : : {p_iseqC, '/', A_BINGO | A_CLEAR, TPS_Base, FILEPATH, NULL},
1437 : : {p_isspace, 0, A_BINGO | A_CLEAR, TPS_Base, FILEPATH, NULL},
1438 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1439 : : };
1440 : :
1441 : : static const TParserStateActionItem actionTPS_InFile[] = {
1442 : : {p_isEOF, 0, A_BINGO, TPS_Base, FILEPATH, NULL},
1443 : : {p_isasclet, 0, A_NEXT, TPS_InFile, 0, NULL},
1444 : : {p_isdigit, 0, A_NEXT, TPS_InFile, 0, NULL},
1445 : : {p_iseqC, '.', A_PUSH, TPS_InFileNext, 0, NULL},
1446 : : {p_iseqC, '_', A_NEXT, TPS_InFile, 0, NULL},
1447 : : {p_iseqC, '-', A_NEXT, TPS_InFile, 0, NULL},
1448 : : {p_iseqC, '/', A_PUSH, TPS_InFileFirst, 0, NULL},
1449 : : {NULL, 0, A_BINGO, TPS_Base, FILEPATH, NULL}
1450 : : };
1451 : :
1452 : : static const TParserStateActionItem actionTPS_InFileNext[] = {
1453 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1454 : : {p_isasclet, 0, A_CLEAR, TPS_InFile, 0, NULL},
1455 : : {p_isdigit, 0, A_CLEAR, TPS_InFile, 0, NULL},
1456 : : {p_iseqC, '_', A_CLEAR, TPS_InFile, 0, NULL},
1457 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1458 : : };
1459 : :
1460 : : static const TParserStateActionItem actionTPS_InURLPathFirst[] = {
1461 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1462 : : {p_isurlchar, 0, A_NEXT, TPS_InURLPath, 0, NULL},
1463 : : {NULL, 0, A_POP, TPS_Null, 0, NULL},
1464 : : };
1465 : :
1466 : : static const TParserStateActionItem actionTPS_InURLPathStart[] = {
1467 : : {NULL, 0, A_NEXT, TPS_InURLPath, 0, NULL}
1468 : : };
1469 : :
1470 : : static const TParserStateActionItem actionTPS_InURLPath[] = {
1471 : : {p_isEOF, 0, A_BINGO, TPS_Base, URLPATH, NULL},
1472 : : {p_isurlchar, 0, A_NEXT, TPS_InURLPath, 0, NULL},
1473 : : {NULL, 0, A_BINGO, TPS_Base, URLPATH, NULL}
1474 : : };
1475 : :
1476 : : static const TParserStateActionItem actionTPS_InFURL[] = {
1477 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1478 : : {p_isURLPath, 0, A_BINGO | A_CLRALL, TPS_Base, URL_T, SpecialFURL},
1479 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1480 : : };
1481 : :
1482 : : static const TParserStateActionItem actionTPS_InProtocolFirst[] = {
1483 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1484 : : {p_iseqC, '/', A_NEXT, TPS_InProtocolSecond, 0, NULL},
1485 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1486 : : };
1487 : :
1488 : : static const TParserStateActionItem actionTPS_InProtocolSecond[] = {
1489 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1490 : : {p_iseqC, '/', A_NEXT, TPS_InProtocolEnd, 0, NULL},
1491 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1492 : : };
1493 : :
1494 : : static const TParserStateActionItem actionTPS_InProtocolEnd[] = {
1495 : : {NULL, 0, A_BINGO | A_CLRALL, TPS_Base, PROTOCOL, NULL}
1496 : : };
1497 : :
1498 : : static const TParserStateActionItem actionTPS_InHyphenAsciiWordFirst[] = {
1499 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1500 : : {p_isasclet, 0, A_NEXT, TPS_InHyphenAsciiWord, 0, NULL},
1501 : : {p_isalpha, 0, A_NEXT, TPS_InHyphenWord, 0, NULL},
1502 : : {p_isdigit, 0, A_NEXT, TPS_InHyphenDigitLookahead, 0, NULL},
1503 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1504 : : };
1505 : :
1506 : : static const TParserStateActionItem actionTPS_InHyphenAsciiWord[] = {
1507 : : {p_isEOF, 0, A_BINGO | A_CLRALL, TPS_InParseHyphen, ASCIIHWORD, SpecialHyphen},
1508 : : {p_isasclet, 0, A_NEXT, TPS_InHyphenAsciiWord, 0, NULL},
1509 : : {p_isalpha, 0, A_NEXT, TPS_InHyphenWord, 0, NULL},
1510 : : {p_isspecial, 0, A_NEXT, TPS_InHyphenWord, 0, NULL},
1511 : : {p_isdigit, 0, A_NEXT, TPS_InHyphenNumWord, 0, NULL},
1512 : : {p_iseqC, '-', A_PUSH, TPS_InHyphenAsciiWordFirst, 0, NULL},
1513 : : {NULL, 0, A_BINGO | A_CLRALL, TPS_InParseHyphen, ASCIIHWORD, SpecialHyphen}
1514 : : };
1515 : :
1516 : : static const TParserStateActionItem actionTPS_InHyphenWordFirst[] = {
1517 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1518 : : {p_isalpha, 0, A_NEXT, TPS_InHyphenWord, 0, NULL},
1519 : : {p_isdigit, 0, A_NEXT, TPS_InHyphenDigitLookahead, 0, NULL},
1520 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1521 : : };
1522 : :
1523 : : static const TParserStateActionItem actionTPS_InHyphenWord[] = {
1524 : : {p_isEOF, 0, A_BINGO | A_CLRALL, TPS_InParseHyphen, HWORD, SpecialHyphen},
1525 : : {p_isalpha, 0, A_NEXT, TPS_InHyphenWord, 0, NULL},
1526 : : {p_isspecial, 0, A_NEXT, TPS_InHyphenWord, 0, NULL},
1527 : : {p_isdigit, 0, A_NEXT, TPS_InHyphenNumWord, 0, NULL},
1528 : : {p_iseqC, '-', A_PUSH, TPS_InHyphenWordFirst, 0, NULL},
1529 : : {NULL, 0, A_BINGO | A_CLRALL, TPS_InParseHyphen, HWORD, SpecialHyphen}
1530 : : };
1531 : :
1532 : : static const TParserStateActionItem actionTPS_InHyphenNumWordFirst[] = {
1533 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1534 : : {p_isalpha, 0, A_NEXT, TPS_InHyphenNumWord, 0, NULL},
1535 : : {p_isdigit, 0, A_NEXT, TPS_InHyphenDigitLookahead, 0, NULL},
1536 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1537 : : };
1538 : :
1539 : : static const TParserStateActionItem actionTPS_InHyphenNumWord[] = {
1540 : : {p_isEOF, 0, A_BINGO | A_CLRALL, TPS_InParseHyphen, NUMHWORD, SpecialHyphen},
1541 : : {p_isalnum, 0, A_NEXT, TPS_InHyphenNumWord, 0, NULL},
1542 : : {p_isspecial, 0, A_NEXT, TPS_InHyphenNumWord, 0, NULL},
1543 : : {p_iseqC, '-', A_PUSH, TPS_InHyphenNumWordFirst, 0, NULL},
1544 : : {NULL, 0, A_BINGO | A_CLRALL, TPS_InParseHyphen, NUMHWORD, SpecialHyphen}
1545 : : };
1546 : :
1547 : : static const TParserStateActionItem actionTPS_InHyphenDigitLookahead[] = {
1548 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1549 : : {p_isdigit, 0, A_NEXT, TPS_InHyphenDigitLookahead, 0, NULL},
1550 : : {p_isalpha, 0, A_NEXT, TPS_InHyphenNumWord, 0, NULL},
1551 : : {p_isspecial, 0, A_NEXT, TPS_InHyphenNumWord, 0, NULL},
1552 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1553 : : };
1554 : :
1555 : : static const TParserStateActionItem actionTPS_InParseHyphen[] = {
1556 : : {p_isEOF, 0, A_RERUN, TPS_Base, 0, NULL},
1557 : : {p_isasclet, 0, A_NEXT, TPS_InHyphenAsciiWordPart, 0, NULL},
1558 : : {p_isalpha, 0, A_NEXT, TPS_InHyphenWordPart, 0, NULL},
1559 : : {p_isdigit, 0, A_PUSH, TPS_InHyphenUnsignedInt, 0, NULL},
1560 : : {p_iseqC, '-', A_PUSH, TPS_InParseHyphenHyphen, 0, NULL},
1561 : : {NULL, 0, A_RERUN, TPS_Base, 0, NULL}
1562 : : };
1563 : :
1564 : : static const TParserStateActionItem actionTPS_InParseHyphenHyphen[] = {
1565 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1566 : : {p_isalnum, 0, A_BINGO | A_CLEAR, TPS_InParseHyphen, SPACE, NULL},
1567 : : {p_isspecial, 0, A_BINGO | A_CLEAR, TPS_InParseHyphen, SPACE, NULL},
1568 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1569 : : };
1570 : :
1571 : : static const TParserStateActionItem actionTPS_InHyphenWordPart[] = {
1572 : : {p_isEOF, 0, A_BINGO, TPS_Base, PARTHWORD, NULL},
1573 : : {p_isalpha, 0, A_NEXT, TPS_InHyphenWordPart, 0, NULL},
1574 : : {p_isspecial, 0, A_NEXT, TPS_InHyphenWordPart, 0, NULL},
1575 : : {p_isdigit, 0, A_NEXT, TPS_InHyphenNumWordPart, 0, NULL},
1576 : : {NULL, 0, A_BINGO, TPS_InParseHyphen, PARTHWORD, NULL}
1577 : : };
1578 : :
1579 : : static const TParserStateActionItem actionTPS_InHyphenAsciiWordPart[] = {
1580 : : {p_isEOF, 0, A_BINGO, TPS_Base, ASCIIPARTHWORD, NULL},
1581 : : {p_isasclet, 0, A_NEXT, TPS_InHyphenAsciiWordPart, 0, NULL},
1582 : : {p_isalpha, 0, A_NEXT, TPS_InHyphenWordPart, 0, NULL},
1583 : : {p_isspecial, 0, A_NEXT, TPS_InHyphenWordPart, 0, NULL},
1584 : : {p_isdigit, 0, A_NEXT, TPS_InHyphenNumWordPart, 0, NULL},
1585 : : {NULL, 0, A_BINGO, TPS_InParseHyphen, ASCIIPARTHWORD, NULL}
1586 : : };
1587 : :
1588 : : static const TParserStateActionItem actionTPS_InHyphenNumWordPart[] = {
1589 : : {p_isEOF, 0, A_BINGO, TPS_Base, NUMPARTHWORD, NULL},
1590 : : {p_isalnum, 0, A_NEXT, TPS_InHyphenNumWordPart, 0, NULL},
1591 : : {p_isspecial, 0, A_NEXT, TPS_InHyphenNumWordPart, 0, NULL},
1592 : : {NULL, 0, A_BINGO, TPS_InParseHyphen, NUMPARTHWORD, NULL}
1593 : : };
1594 : :
1595 : : static const TParserStateActionItem actionTPS_InHyphenUnsignedInt[] = {
1596 : : {p_isEOF, 0, A_POP, TPS_Null, 0, NULL},
1597 : : {p_isdigit, 0, A_NEXT, TPS_Null, 0, NULL},
1598 : : {p_isalpha, 0, A_CLEAR, TPS_InHyphenNumWordPart, 0, NULL},
1599 : : {p_isspecial, 0, A_CLEAR, TPS_InHyphenNumWordPart, 0, NULL},
1600 : : {NULL, 0, A_POP, TPS_Null, 0, NULL}
1601 : : };
1602 : :
1603 : :
1604 : : /*
1605 : : * main table of per-state parser actions
1606 : : */
1607 : : typedef struct
1608 : : {
1609 : : const TParserStateActionItem *action; /* the actual state info */
1610 : : TParserState state; /* only for Assert crosscheck */
1611 : : #ifdef WPARSER_TRACE
1612 : : const char *state_name; /* only for debug printout */
1613 : : #endif
1614 : : } TParserStateAction;
1615 : :
1616 : : #ifdef WPARSER_TRACE
1617 : : #define TPARSERSTATEACTION(state) \
1618 : : { CppConcat(action,state), state, CppAsString(state) }
1619 : : #else
1620 : : #define TPARSERSTATEACTION(state) \
1621 : : { CppConcat(action,state), state }
1622 : : #endif
1623 : :
1624 : : /*
1625 : : * order must be the same as in typedef enum {} TParserState!!
1626 : : */
1627 : :
1628 : : static const TParserStateAction Actions[] = {
1629 : : TPARSERSTATEACTION(TPS_Base),
1630 : : TPARSERSTATEACTION(TPS_InNumWord),
1631 : : TPARSERSTATEACTION(TPS_InAsciiWord),
1632 : : TPARSERSTATEACTION(TPS_InWord),
1633 : : TPARSERSTATEACTION(TPS_InUnsignedInt),
1634 : : TPARSERSTATEACTION(TPS_InSignedIntFirst),
1635 : : TPARSERSTATEACTION(TPS_InSignedInt),
1636 : : TPARSERSTATEACTION(TPS_InSpace),
1637 : : TPARSERSTATEACTION(TPS_InUDecimalFirst),
1638 : : TPARSERSTATEACTION(TPS_InUDecimal),
1639 : : TPARSERSTATEACTION(TPS_InDecimalFirst),
1640 : : TPARSERSTATEACTION(TPS_InDecimal),
1641 : : TPARSERSTATEACTION(TPS_InVerVersion),
1642 : : TPARSERSTATEACTION(TPS_InSVerVersion),
1643 : : TPARSERSTATEACTION(TPS_InVersionFirst),
1644 : : TPARSERSTATEACTION(TPS_InVersion),
1645 : : TPARSERSTATEACTION(TPS_InMantissaFirst),
1646 : : TPARSERSTATEACTION(TPS_InMantissaSign),
1647 : : TPARSERSTATEACTION(TPS_InMantissa),
1648 : : TPARSERSTATEACTION(TPS_InXMLEntityFirst),
1649 : : TPARSERSTATEACTION(TPS_InXMLEntity),
1650 : : TPARSERSTATEACTION(TPS_InXMLEntityNumFirst),
1651 : : TPARSERSTATEACTION(TPS_InXMLEntityNum),
1652 : : TPARSERSTATEACTION(TPS_InXMLEntityHexNumFirst),
1653 : : TPARSERSTATEACTION(TPS_InXMLEntityHexNum),
1654 : : TPARSERSTATEACTION(TPS_InXMLEntityEnd),
1655 : : TPARSERSTATEACTION(TPS_InTagFirst),
1656 : : TPARSERSTATEACTION(TPS_InXMLBegin),
1657 : : TPARSERSTATEACTION(TPS_InTagCloseFirst),
1658 : : TPARSERSTATEACTION(TPS_InTagName),
1659 : : TPARSERSTATEACTION(TPS_InTagBeginEnd),
1660 : : TPARSERSTATEACTION(TPS_InTag),
1661 : : TPARSERSTATEACTION(TPS_InTagEscapeK),
1662 : : TPARSERSTATEACTION(TPS_InTagEscapeKK),
1663 : : TPARSERSTATEACTION(TPS_InTagBackSleshed),
1664 : : TPARSERSTATEACTION(TPS_InTagEnd),
1665 : : TPARSERSTATEACTION(TPS_InCommentFirst),
1666 : : TPARSERSTATEACTION(TPS_InCommentLast),
1667 : : TPARSERSTATEACTION(TPS_InComment),
1668 : : TPARSERSTATEACTION(TPS_InCloseCommentFirst),
1669 : : TPARSERSTATEACTION(TPS_InCloseCommentLast),
1670 : : TPARSERSTATEACTION(TPS_InCommentEnd),
1671 : : TPARSERSTATEACTION(TPS_InHostFirstDomain),
1672 : : TPARSERSTATEACTION(TPS_InHostDomainSecond),
1673 : : TPARSERSTATEACTION(TPS_InHostDomain),
1674 : : TPARSERSTATEACTION(TPS_InPortFirst),
1675 : : TPARSERSTATEACTION(TPS_InPort),
1676 : : TPARSERSTATEACTION(TPS_InHostFirstAN),
1677 : : TPARSERSTATEACTION(TPS_InHost),
1678 : : TPARSERSTATEACTION(TPS_InEmail),
1679 : : TPARSERSTATEACTION(TPS_InFileFirst),
1680 : : TPARSERSTATEACTION(TPS_InFileTwiddle),
1681 : : TPARSERSTATEACTION(TPS_InPathFirst),
1682 : : TPARSERSTATEACTION(TPS_InPathFirstFirst),
1683 : : TPARSERSTATEACTION(TPS_InPathSecond),
1684 : : TPARSERSTATEACTION(TPS_InFile),
1685 : : TPARSERSTATEACTION(TPS_InFileNext),
1686 : : TPARSERSTATEACTION(TPS_InURLPathFirst),
1687 : : TPARSERSTATEACTION(TPS_InURLPathStart),
1688 : : TPARSERSTATEACTION(TPS_InURLPath),
1689 : : TPARSERSTATEACTION(TPS_InFURL),
1690 : : TPARSERSTATEACTION(TPS_InProtocolFirst),
1691 : : TPARSERSTATEACTION(TPS_InProtocolSecond),
1692 : : TPARSERSTATEACTION(TPS_InProtocolEnd),
1693 : : TPARSERSTATEACTION(TPS_InHyphenAsciiWordFirst),
1694 : : TPARSERSTATEACTION(TPS_InHyphenAsciiWord),
1695 : : TPARSERSTATEACTION(TPS_InHyphenWordFirst),
1696 : : TPARSERSTATEACTION(TPS_InHyphenWord),
1697 : : TPARSERSTATEACTION(TPS_InHyphenNumWordFirst),
1698 : : TPARSERSTATEACTION(TPS_InHyphenNumWord),
1699 : : TPARSERSTATEACTION(TPS_InHyphenDigitLookahead),
1700 : : TPARSERSTATEACTION(TPS_InParseHyphen),
1701 : : TPARSERSTATEACTION(TPS_InParseHyphenHyphen),
1702 : : TPARSERSTATEACTION(TPS_InHyphenWordPart),
1703 : : TPARSERSTATEACTION(TPS_InHyphenAsciiWordPart),
1704 : : TPARSERSTATEACTION(TPS_InHyphenNumWordPart),
1705 : : TPARSERSTATEACTION(TPS_InHyphenUnsignedInt)
1706 : : };
1707 : :
1708 : :
1709 : : static bool
5995 bruce@momjian.us 1710 : 14438 : TParserGet(TParser *prs)
1711 : : {
6014 tgl@sss.pgh.pa.us 1712 : 14438 : const TParserStateActionItem *item = NULL;
1713 : :
295 1714 [ - + ]: 14438 : CHECK_FOR_INTERRUPTS();
1715 : :
6018 1716 [ - + ]: 14438 : Assert(prs->state);
1717 : :
6081 1718 [ + + ]: 14438 : if (prs->state->posbyte >= prs->lenstr)
1719 : 2365 : return false;
1720 : :
6014 1721 : 12073 : prs->token = prs->str + prs->state->posbyte;
6081 1722 : 12073 : prs->state->pushedAtAction = NULL;
1723 : :
1724 : : /* look at string */
1725 [ + - ]: 51585 : while (prs->state->posbyte <= prs->lenstr)
1726 : : {
1727 [ + + ]: 51585 : if (prs->state->posbyte == prs->lenstr)
1728 : 2440 : prs->state->charlen = 0;
1729 : : else
1730 [ - + ]: 98290 : prs->state->charlen = (prs->charmaxlen == 1) ? prs->charmaxlen :
1731 : 49145 : pg_mblen(prs->str + prs->state->posbyte);
1732 : :
1733 [ - + ]: 51585 : Assert(prs->state->posbyte + prs->state->charlen <= prs->lenstr);
1734 [ - + ]: 51585 : Assert(prs->state->state >= TPS_Base && prs->state->state < TPS_Null);
1735 [ - + ]: 51585 : Assert(Actions[prs->state->state].state == prs->state->state);
1736 : :
6014 1737 [ + + ]: 51585 : if (prs->state->pushedAtAction)
1738 : : {
1739 : : /* After a POP, pick up at the next test */
1740 : 1296 : item = prs->state->pushedAtAction + 1;
1741 : 1296 : prs->state->pushedAtAction = NULL;
1742 : : }
1743 : : else
1744 : : {
1745 : 50289 : item = Actions[prs->state->state].action;
1746 [ - + ]: 50289 : Assert(item != NULL);
1747 : : }
1748 : :
1749 : : /* find action by character class */
6081 1750 [ + + ]: 277734 : while (item->isclass)
1751 : : {
1752 : 262062 : prs->c = item->c;
1753 [ + + ]: 262062 : if (item->isclass(prs) != 0)
6014 1754 : 35913 : break;
6081 1755 : 226149 : item++;
1756 : : }
1757 : :
1758 : : #ifdef WPARSER_TRACE
1759 : : {
1760 : : TParserPosition *ptr;
1761 : :
1762 : : fprintf(stderr, "state ");
1763 : : /* indent according to stack depth */
1764 : : for (ptr = prs->state->prev; ptr; ptr = ptr->prev)
1765 : : fprintf(stderr, " ");
1766 : : fprintf(stderr, "%s ", Actions[prs->state->state].state_name);
1767 : : if (prs->state->posbyte < prs->lenstr)
1768 : : fprintf(stderr, "at %c", *(prs->str + prs->state->posbyte));
1769 : : else
1770 : : fprintf(stderr, "at EOF");
1771 : : fprintf(stderr, " matched rule %d flags%s%s%s%s%s%s%s%s%s%s%s\n",
1772 : : (int) (item - Actions[prs->state->state].action),
1773 : : (item->flags & A_BINGO) ? " BINGO" : "",
1774 : : (item->flags & A_POP) ? " POP" : "",
1775 : : (item->flags & A_PUSH) ? " PUSH" : "",
1776 : : (item->flags & A_RERUN) ? " RERUN" : "",
1777 : : (item->flags & A_CLEAR) ? " CLEAR" : "",
1778 : : (item->flags & A_MERGE) ? " MERGE" : "",
1779 : : (item->flags & A_CLRALL) ? " CLRALL" : "",
1780 : : (item->tostate != TPS_Null) ? " tostate " : "",
1781 : : (item->tostate != TPS_Null) ? Actions[item->tostate].state_name : "",
1782 : : (item->type > 0) ? " type " : "",
1783 : : tok_alias[item->type]);
1784 : : }
1785 : : #endif
1786 : :
1787 : : /* call special handler if exists */
1788 [ + + ]: 51585 : if (item->special)
1789 : 210 : item->special(prs);
1790 : :
1791 : : /* BINGO, token is found */
1792 [ + + ]: 51585 : if (item->flags & A_BINGO)
1793 : : {
1794 [ - + ]: 12073 : Assert(item->type > 0);
6014 1795 : 12073 : prs->lenbytetoken = prs->state->lenbytetoken;
1796 : 12073 : prs->lenchartoken = prs->state->lenchartoken;
1797 : 12073 : prs->state->lenbytetoken = prs->state->lenchartoken = 0;
6081 1798 : 12073 : prs->type = item->type;
1799 : : }
1800 : :
1801 : : /* do various actions by flags */
1802 [ + + ]: 51585 : if (item->flags & A_POP)
1803 : : { /* pop stored state in stack */
1804 : 1305 : TParserPosition *ptr = prs->state->prev;
1805 : :
1806 : 1305 : pfree(prs->state);
1807 : 1305 : prs->state = ptr;
1808 [ - + ]: 1305 : Assert(prs->state);
1809 : : }
1810 [ + + ]: 50280 : else if (item->flags & A_PUSH)
1811 : : { /* push (store) state in stack */
1812 : 2544 : prs->state->pushedAtAction = item; /* remember where we push */
1813 : 2544 : prs->state = newTParserPosition(prs->state);
1814 : : }
1815 [ + + ]: 47736 : else if (item->flags & A_CLEAR)
1816 : : { /* clear previous pushed state */
1817 : : TParserPosition *ptr;
1818 : :
1819 [ - + ]: 249 : Assert(prs->state->prev);
1820 : 249 : ptr = prs->state->prev->prev;
1821 : 249 : pfree(prs->state->prev);
1822 : 249 : prs->state->prev = ptr;
1823 : : }
1824 [ + + ]: 47487 : else if (item->flags & A_CLRALL)
1825 : : { /* clear all previous pushed state */
1826 : : TParserPosition *ptr;
1827 : :
1828 [ + + ]: 1389 : while (prs->state->prev)
1829 : : {
1830 : 999 : ptr = prs->state->prev->prev;
1831 : 999 : pfree(prs->state->prev);
1832 : 999 : prs->state->prev = ptr;
1833 : : }
1834 : : }
1835 [ - + ]: 47097 : else if (item->flags & A_MERGE)
1836 : : { /* merge posinfo with current and pushed state */
6081 tgl@sss.pgh.pa.us 1837 :UBC 0 : TParserPosition *ptr = prs->state;
1838 : :
1839 [ # # ]: 0 : Assert(prs->state->prev);
1840 : 0 : prs->state = prs->state->prev;
1841 : :
1842 : 0 : prs->state->posbyte = ptr->posbyte;
1843 : 0 : prs->state->poschar = ptr->poschar;
1844 : 0 : prs->state->charlen = ptr->charlen;
6014 1845 : 0 : prs->state->lenbytetoken = ptr->lenbytetoken;
1846 : 0 : prs->state->lenchartoken = ptr->lenchartoken;
6081 1847 : 0 : pfree(ptr);
1848 : : }
1849 : :
1850 : : /* set new state if pointed */
6081 tgl@sss.pgh.pa.us 1851 [ + + ]:CBC 51585 : if (item->tostate != TPS_Null)
1852 : 33077 : prs->state->state = item->tostate;
1853 : :
1854 : : /* check for go away */
6018 1855 [ + + ]: 51585 : if ((item->flags & A_BINGO) ||
1856 [ - + ]: 39512 : (prs->state->posbyte >= prs->lenstr &&
6018 tgl@sss.pgh.pa.us 1857 [ # # ]:UBC 0 : (item->flags & A_RERUN) == 0))
1858 : : break;
1859 : :
1860 : : /* go to beginning of loop if we should rerun or we just restore state */
6081 tgl@sss.pgh.pa.us 1861 [ + + ]:CBC 39512 : if (item->flags & (A_RERUN | A_POP))
1862 : 1317 : continue;
1863 : :
1864 : : /* move forward */
1865 [ + - ]: 38195 : if (prs->state->charlen)
1866 : : {
1867 : 38195 : prs->state->posbyte += prs->state->charlen;
6014 1868 : 38195 : prs->state->lenbytetoken += prs->state->charlen;
6081 1869 : 38195 : prs->state->poschar++;
6014 1870 : 38195 : prs->state->lenchartoken++;
1871 : : }
1872 : : }
1873 : :
916 michael@paquier.xyz 1874 [ + - + - ]: 12073 : return (item && (item->flags & A_BINGO));
1875 : : }
1876 : :
1877 : : Datum
6081 tgl@sss.pgh.pa.us 1878 : 3411 : prsd_lextype(PG_FUNCTION_ARGS)
1879 : : {
1880 : 3411 : LexDescr *descr = (LexDescr *) palloc(sizeof(LexDescr) * (LASTNUM + 1));
1881 : : int i;
1882 : :
1883 [ + + ]: 81864 : for (i = 1; i <= LASTNUM; i++)
1884 : : {
1885 : 78453 : descr[i - 1].lexid = i;
1886 : 78453 : descr[i - 1].alias = pstrdup(tok_alias[i]);
1887 : 78453 : descr[i - 1].descr = pstrdup(lex_descr[i]);
1888 : : }
1889 : :
1890 : 3411 : descr[LASTNUM].lexid = 0;
1891 : :
1892 : 3411 : PG_RETURN_POINTER(descr);
1893 : : }
1894 : :
1895 : : Datum
1896 : 2365 : prsd_start(PG_FUNCTION_ARGS)
1897 : : {
1898 : 2365 : PG_RETURN_POINTER(TParserInit((char *) PG_GETARG_POINTER(0), PG_GETARG_INT32(1)));
1899 : : }
1900 : :
1901 : : Datum
1902 : 14318 : prsd_nexttoken(PG_FUNCTION_ARGS)
1903 : : {
1904 : 14318 : TParser *p = (TParser *) PG_GETARG_POINTER(0);
1905 : 14318 : char **t = (char **) PG_GETARG_POINTER(1);
1906 : 14318 : int *tlen = (int *) PG_GETARG_POINTER(2);
1907 : :
1908 [ + + ]: 14318 : if (!TParserGet(p))
1909 : 2365 : PG_RETURN_INT32(0);
1910 : :
6014 1911 : 11953 : *t = p->token;
1912 : 11953 : *tlen = p->lenbytetoken;
1913 : :
6081 1914 : 11953 : PG_RETURN_INT32(p->type);
1915 : : }
1916 : :
1917 : : Datum
1918 : 2365 : prsd_end(PG_FUNCTION_ARGS)
1919 : : {
1920 : 2365 : TParser *p = (TParser *) PG_GETARG_POINTER(0);
1921 : :
1922 : 2365 : TParserClose(p);
1923 : 2365 : PG_RETURN_VOID();
1924 : : }
1925 : :
1926 : :
1927 : : /*
1928 : : * ts_headline support begins here
1929 : : */
1930 : :
1931 : : /* token type classification macros */
1932 : : #define TS_IDIGNORE(x) ( (x)==TAG_T || (x)==PROTOCOL || (x)==SPACE || (x)==XMLENTITY )
1933 : : #define HLIDREPLACE(x) ( (x)==TAG_T )
1934 : : #define HLIDSKIP(x) ( (x)==URL_T || (x)==NUMHWORD || (x)==ASCIIHWORD || (x)==HWORD )
1935 : : #define XMLHLIDSKIP(x) ( (x)==URL_T || (x)==NUMHWORD || (x)==ASCIIHWORD || (x)==HWORD )
1936 : : #define NONWORDTOKEN(x) ( (x)==SPACE || HLIDREPLACE(x) || HLIDSKIP(x) )
1937 : : #define NOENDTOKEN(x) ( NONWORDTOKEN(x) || (x)==SCIENTIFIC || (x)==VERSIONNUMBER || (x)==DECIMAL_T || (x)==SIGNEDINT || (x)==UNSIGNEDINT || TS_IDIGNORE(x) )
1938 : :
1939 : : /*
1940 : : * Macros useful in headline selection. These rely on availability of
1941 : : * "HeadlineParsedText *prs" describing some text, and "int shortword"
1942 : : * describing the "short word" length parameter.
1943 : : */
1944 : :
1945 : : /* Interesting words are non-repeated search terms */
1946 : : #define INTERESTINGWORD(j) \
1947 : : (prs->words[j].item && !prs->words[j].repeated)
1948 : :
1949 : : /* Don't want to end at a non-word or a short word, unless interesting */
1950 : : #define BADENDPOINT(j) \
1951 : : ((NOENDTOKEN(prs->words[j].type) || prs->words[j].len <= shortword) && \
1952 : : !INTERESTINGWORD(j))
1953 : :
1954 : : typedef struct
1955 : : {
1956 : : /* one cover (well, really one fragment) for mark_hl_fragments */
1957 : : int32 startpos; /* fragment's starting word index */
1958 : : int32 endpos; /* ending word index (inclusive) */
1959 : : int32 poslen; /* number of interesting words */
1960 : : int32 curlen; /* total number of words */
1961 : : bool chosen; /* chosen? */
1962 : : bool excluded; /* excluded? */
1963 : : } CoverPos;
1964 : :
1965 : : typedef struct
1966 : : {
1967 : : /* callback data for checkcondition_HL */
1968 : : HeadlineWordEntry *words;
1969 : : int len;
1970 : : } hlCheck;
1971 : :
1972 : :
1973 : : /*
1974 : : * TS_execute callback for matching a tsquery operand to headline words
1975 : : *
1976 : : * Note: it's tempting to report words[] indexes as pos values to save
1977 : : * searching in hlCover; but that would screw up phrase matching, which
1978 : : * expects to measure distances in lexemes not tokens.
1979 : : */
1980 : : static TSTernaryValue
2929 teodor@sigaev.ru 1981 : 500 : checkcondition_HL(void *opaque, QueryOperand *val, ExecPhraseData *data)
1982 : : {
2866 rhaas@postgresql.org 1983 : 500 : hlCheck *checkval = (hlCheck *) opaque;
1984 : : int i;
1985 : :
1986 : : /* scan words array for matching items */
2929 teodor@sigaev.ru 1987 [ + + ]: 12725 : for (i = 0; i < checkval->len; i++)
1988 : : {
1989 [ + + ]: 12325 : if (checkval->words[i].item == val)
1990 : : {
1991 : : /* if data == NULL, don't need to report positions */
1992 [ + + ]: 437 : if (!data)
1360 tgl@sss.pgh.pa.us 1993 : 100 : return TS_YES;
1994 : :
2929 teodor@sigaev.ru 1995 [ + + ]: 337 : if (!data->pos)
1996 : : {
1997 : 238 : data->pos = palloc(sizeof(WordEntryPos) * checkval->len);
1998 : 238 : data->allocated = true;
1999 : 238 : data->npos = 1;
2000 : 238 : data->pos[0] = checkval->words[i].pos;
2001 : : }
2002 [ + - ]: 99 : else if (data->pos[data->npos - 1] < checkval->words[i].pos)
2003 : : {
2004 : 99 : data->pos[data->npos++] = checkval->words[i].pos;
2005 : : }
2006 : : }
2007 : : }
2008 : :
2009 [ + + + + ]: 400 : if (data && data->npos > 0)
1360 tgl@sss.pgh.pa.us 2010 : 238 : return TS_YES;
2011 : :
2012 : 162 : return TS_NO;
2013 : : }
2014 : :
2015 : : /*
2016 : : * hlCover: try to find a substring of prs' word list that satisfies query
2017 : : *
2018 : : * locations is the result of TS_execute_locations() for the query.
2019 : : * We use this to identify plausible subranges of the query.
2020 : : *
2021 : : * *nextpos is the lexeme position (NOT word index) to start the search
2022 : : * at. Caller should initialize this to zero. If successful, we'll
2023 : : * advance it to the next place to search at.
2024 : : *
2025 : : * On success, sets *p to first word index and *q to last word index of the
2026 : : * cover substring, and returns true.
2027 : : *
2028 : : * The result is a minimal cover, in the sense that both *p and *q will be
2029 : : * words used in the query.
2030 : : */
2031 : : static bool
451 2032 : 281 : hlCover(HeadlineParsedText *prs, TSQuery query, List *locations,
2033 : : int *nextpos, int *p, int *q)
2034 : : {
2035 : 281 : int pos = *nextpos;
2036 : :
2037 : : /* This loop repeats when our selected word-range fails the query */
2038 : : for (;;)
6081 2039 : 30 : {
2040 : : int posb,
2041 : : pose;
2042 : : ListCell *lc;
2043 : :
2044 : : /*
2045 : : * For each AND'ed query term or phrase, find its first occurrence at
2046 : : * or after pos; set pose to the maximum of those positions.
2047 : : *
2048 : : * We need not consider ORs or NOTs here; see the comments for
2049 : : * TS_execute_locations(). Rechecking the match with TS_execute(),
2050 : : * below, will deal with any ensuing imprecision.
2051 : : */
451 2052 : 311 : pose = -1;
2053 [ + + + + : 483 : foreach(lc, locations)
+ + ]
2054 : : {
2055 : 233 : ExecPhraseData *pdata = (ExecPhraseData *) lfirst(lc);
2056 : 233 : int first = -1;
2057 : :
2058 [ + + ]: 396 : for (int i = 0; i < pdata->npos; i++)
2059 : : {
2060 : : /* For phrase matches, use the ending lexeme */
2061 : 335 : int endp = pdata->pos[i];
2062 : :
2063 [ + + ]: 335 : if (endp >= pos)
2064 : : {
2065 : 172 : first = endp;
2066 : 172 : break;
2067 : : }
2068 : : }
2069 [ + + ]: 233 : if (first < 0)
2070 : 61 : return false; /* no more matches for this term */
2071 [ + + ]: 172 : if (first > pose)
2072 : 163 : pose = first;
2073 : : }
2074 : :
2075 [ + + ]: 250 : if (pose < 0)
2076 : 123 : return false; /* we only get here if empty list */
2077 : :
2078 : : /*
2079 : : * Now, for each AND'ed query term or phrase, find its last occurrence
2080 : : * at or before pose; set posb to the minimum of those positions.
2081 : : *
2082 : : * We start posb at INT_MAX - 1 to guarantee no overflow if we compute
2083 : : * posb + 1 below.
2084 : : */
2085 : 127 : posb = INT_MAX - 1;
2086 [ + - + + : 293 : foreach(lc, locations)
+ + ]
2087 : : {
2088 : 166 : ExecPhraseData *pdata = (ExecPhraseData *) lfirst(lc);
2089 : 166 : int last = -1;
2090 : :
2091 [ + - ]: 247 : for (int i = pdata->npos - 1; i >= 0; i--)
2092 : : {
2093 : : /* For phrase matches, use the starting lexeme */
2094 : 247 : int startp = pdata->pos[i] - pdata->width;
2095 : :
2096 [ + + ]: 247 : if (startp <= pose)
2097 : : {
2098 : 166 : last = startp;
2099 : 166 : break;
2100 : : }
2101 : : }
2102 [ + + ]: 166 : if (last < posb)
2103 : 136 : posb = last;
2104 : : }
2105 : :
2106 : : /*
2107 : : * We could end up with posb to the left of pos, in case some phrase
2108 : : * match crosses pos. Try the match starting at pos anyway, since the
2109 : : * result of TS_execute_locations is imprecise for phrase matches OR'd
2110 : : * with plain matches; that is, if the query is "(A <-> B) | C" then C
2111 : : * could match at pos even though the phrase match would have to
2112 : : * extend to the left of pos.
2113 : : */
2114 : 127 : posb = Max(posb, pos);
2115 : :
2116 : : /* This test probably always succeeds, but be paranoid */
2117 [ + - ]: 127 : if (posb <= pose)
2118 : : {
2119 : : /*
2120 : : * posb .. pose is now the shortest, earliest-after-pos range of
2121 : : * lexeme positions containing all the query terms. It will
2122 : : * contain all phrase matches, too, except in the corner case
2123 : : * described just above.
2124 : : *
2125 : : * Now convert these lexeme positions to indexes in prs->words[].
2126 : : */
2127 : 127 : int idxb = -1;
2128 : 127 : int idxe = -1;
2129 : :
2130 [ + + ]: 5812 : for (int i = 0; i < prs->curwords; i++)
2131 : : {
2132 [ + + ]: 5748 : if (prs->words[i].item == NULL)
2133 : 5306 : continue;
2134 [ + + + + ]: 442 : if (idxb < 0 && prs->words[i].pos >= posb)
2135 : 127 : idxb = i;
2136 [ + + ]: 442 : if (prs->words[i].pos <= pose)
2137 : 379 : idxe = i;
2138 : : else
2139 : 63 : break;
2140 : : }
2141 : :
2142 : : /* This test probably always succeeds, but be paranoid */
2143 [ + - + - ]: 127 : if (idxb >= 0 && idxe >= idxb)
2144 : : {
2145 : : /*
2146 : : * Finally, check that the selected range satisfies the query.
2147 : : * This should succeed in all simple cases; but odd cases
2148 : : * involving non-top-level NOT conditions or phrase matches
2149 : : * OR'd with other things could fail, since the result of
2150 : : * TS_execute_locations doesn't fully represent such things.
2151 : : */
2152 : : hlCheck ch;
2153 : :
2154 : 127 : ch.words = &(prs->words[idxb]);
2155 : 127 : ch.len = idxe - idxb + 1;
2156 [ + + ]: 127 : if (TS_execute(GETQUERY(query), &ch,
2157 : : TS_EXEC_EMPTY, checkcondition_HL))
2158 : : {
2159 : : /* Match! Advance *nextpos and return the word range. */
2160 : 97 : *nextpos = posb + 1;
2161 : 97 : *p = idxb;
2162 : 97 : *q = idxe;
2163 : 97 : return true;
2164 : : }
2165 : : }
2166 : : }
2167 : :
2168 : : /*
2169 : : * Advance pos and try again. Any later workable match must start
2170 : : * beyond posb.
2171 : : */
2172 : 30 : pos = posb + 1;
2173 : : }
2174 : : /* Can't get here, but stupider compilers complain if we leave it off */
2175 : : return false;
2176 : : }
2177 : :
2178 : : /*
2179 : : * Apply suitable highlight marking to words selected by headline selector
2180 : : *
2181 : : * The words from startpos to endpos inclusive are marked per highlightall
2182 : : */
2183 : : static void
1466 2184 : 193 : mark_fragment(HeadlineParsedText *prs, bool highlightall,
2185 : : int startpos, int endpos)
2186 : : {
2187 : : int i;
2188 : :
5658 teodor@sigaev.ru 2189 [ + + ]: 2827 : for (i = startpos; i <= endpos; i++)
2190 : : {
2191 [ + + ]: 2634 : if (prs->words[i].item)
2192 : 250 : prs->words[i].selected = 1;
1466 tgl@sss.pgh.pa.us 2193 [ + + ]: 2634 : if (!highlightall)
2194 : : {
5568 teodor@sigaev.ru 2195 [ - + ]: 2511 : if (HLIDREPLACE(prs->words[i].type))
5658 teodor@sigaev.ru 2196 :UBC 0 : prs->words[i].replace = 1;
4753 bruce@momjian.us 2197 [ + - + - :CBC 2511 : else if (HLIDSKIP(prs->words[i].type))
+ - - + ]
5568 teodor@sigaev.ru 2198 :UBC 0 : prs->words[i].skip = 1;
2199 : : }
2200 : : else
2201 : : {
5568 teodor@sigaev.ru 2202 [ + - + - :CBC 123 : if (XMLHLIDSKIP(prs->words[i].type))
+ + - + ]
2203 : 3 : prs->words[i].skip = 1;
2204 : : }
2205 : :
5658 2206 : 2634 : prs->words[i].in = (prs->words[i].repeated) ? 0 : 1;
2207 : : }
2208 : 193 : }
2209 : :
2210 : : /*
2211 : : * split a cover substring into fragments not longer than max_words
2212 : : *
2213 : : * At entry, *startpos and *endpos are the (remaining) bounds of the cover
2214 : : * substring. They are updated to hold the bounds of the next fragment.
2215 : : *
2216 : : * *curlen and *poslen are set to the fragment's length, in words and
2217 : : * interesting words respectively.
2218 : : */
2219 : : static void
2220 : 18 : get_next_fragment(HeadlineParsedText *prs, int *startpos, int *endpos,
2221 : : int *curlen, int *poslen, int max_words)
2222 : : {
2223 : : int i;
2224 : :
2225 : : /*
2226 : : * Objective: select a fragment of words between startpos and endpos such
2227 : : * that it has at most max_words and both ends have query words. If the
2228 : : * startpos and endpos are the endpoints of the cover and the cover has
2229 : : * fewer words than max_words, then this function should just return the
2230 : : * cover
2231 : : */
2232 : : /* first move startpos to an item */
4753 bruce@momjian.us 2233 [ + - ]: 444 : for (i = *startpos; i <= *endpos; i++)
2234 : : {
5658 teodor@sigaev.ru 2235 : 444 : *startpos = i;
1466 tgl@sss.pgh.pa.us 2236 [ + + + - ]: 444 : if (INTERESTINGWORD(i))
5658 teodor@sigaev.ru 2237 : 18 : break;
2238 : : }
2239 : : /* cut endpos to have only max_words */
2240 : 18 : *curlen = 0;
2241 : 18 : *poslen = 0;
4753 bruce@momjian.us 2242 [ + + + + ]: 480 : for (i = *startpos; i <= *endpos && *curlen < max_words; i++)
2243 : : {
5658 teodor@sigaev.ru 2244 [ + + + - : 462 : if (!NONWORDTOKEN(prs->words[i].type))
+ - + - +
- + - ]
2245 : 240 : *curlen += 1;
1466 tgl@sss.pgh.pa.us 2246 [ + + + - ]: 462 : if (INTERESTINGWORD(i))
5658 teodor@sigaev.ru 2247 : 27 : *poslen += 1;
2248 : : }
2249 : : /* if the cover was cut then move back endpos to a query item */
2250 [ + + ]: 18 : if (*endpos > i)
2251 : : {
2252 : 6 : *endpos = i;
4753 bruce@momjian.us 2253 [ + - ]: 420 : for (i = *endpos; i >= *startpos; i--)
2254 : : {
5658 teodor@sigaev.ru 2255 : 420 : *endpos = i;
1466 tgl@sss.pgh.pa.us 2256 [ + + + - ]: 420 : if (INTERESTINGWORD(i))
5658 teodor@sigaev.ru 2257 : 6 : break;
2258 [ + + + - : 414 : if (!NONWORDTOKEN(prs->words[i].type))
+ - + - +
- + - ]
2259 : 204 : *curlen -= 1;
2260 : : }
2261 : : }
2262 : 18 : }
2263 : :
2264 : : /*
2265 : : * Headline selector used when MaxFragments > 0
2266 : : *
2267 : : * Note: in this mode, highlightall is disregarded for phrase selection;
2268 : : * it only controls presentation details.
2269 : : */
2270 : : static void
451 tgl@sss.pgh.pa.us 2271 : 15 : mark_hl_fragments(HeadlineParsedText *prs, TSQuery query, List *locations,
2272 : : bool highlightall,
2273 : : int shortword, int min_words,
2274 : : int max_words, int max_fragments)
2275 : : {
2276 : : int32 poslen,
2277 : : curlen,
2278 : : i,
2279 : : f,
4753 bruce@momjian.us 2280 : 15 : num_f = 0;
2281 : : int32 stretch,
2282 : : maxstretch,
2283 : : posmarker;
2284 : :
4311 peter_e@gmx.net 2285 : 15 : int32 startpos = 0,
4753 bruce@momjian.us 2286 : 15 : endpos = 0,
451 tgl@sss.pgh.pa.us 2287 : 15 : nextpos = 0,
4753 bruce@momjian.us 2288 : 15 : p = 0,
2289 : 15 : q = 0;
2290 : :
4311 peter_e@gmx.net 2291 : 15 : int32 numcovers = 0,
4753 bruce@momjian.us 2292 : 15 : maxcovers = 32;
2293 : :
2294 : : int32 minI,
2295 : : minwords,
2296 : : maxitems;
2297 : : CoverPos *covers;
2298 : :
5658 teodor@sigaev.ru 2299 : 15 : covers = palloc(maxcovers * sizeof(CoverPos));
2300 : :
2301 : : /* get all covers */
451 tgl@sss.pgh.pa.us 2302 [ + + ]: 27 : while (hlCover(prs, query, locations, &nextpos, &p, &q))
2303 : : {
5658 teodor@sigaev.ru 2304 : 12 : startpos = p;
4753 bruce@momjian.us 2305 : 12 : endpos = q;
2306 : :
2307 : : /*
2308 : : * Break the cover into smaller fragments such that each fragment has
2309 : : * at most max_words. Also ensure that each end of each fragment is a
2310 : : * query word. This will allow us to stretch the fragment in either
2311 : : * direction
2312 : : */
2313 : :
5658 teodor@sigaev.ru 2314 [ + + ]: 30 : while (startpos <= endpos)
2315 : : {
2316 : 18 : get_next_fragment(prs, &startpos, &endpos, &curlen, &poslen, max_words);
2317 [ - + ]: 18 : if (numcovers >= maxcovers)
2318 : : {
5658 teodor@sigaev.ru 2319 :UBC 0 : maxcovers *= 2;
4753 bruce@momjian.us 2320 : 0 : covers = repalloc(covers, sizeof(CoverPos) * maxcovers);
2321 : : }
5658 teodor@sigaev.ru 2322 :CBC 18 : covers[numcovers].startpos = startpos;
4753 bruce@momjian.us 2323 : 18 : covers[numcovers].endpos = endpos;
2324 : 18 : covers[numcovers].curlen = curlen;
2325 : 18 : covers[numcovers].poslen = poslen;
1466 tgl@sss.pgh.pa.us 2326 : 18 : covers[numcovers].chosen = false;
2327 : 18 : covers[numcovers].excluded = false;
4753 bruce@momjian.us 2328 : 18 : numcovers++;
5658 teodor@sigaev.ru 2329 : 18 : startpos = endpos + 1;
4753 bruce@momjian.us 2330 : 18 : endpos = q;
2331 : : }
2332 : : }
2333 : :
2334 : : /* choose best covers */
5658 teodor@sigaev.ru 2335 [ + + ]: 33 : for (f = 0; f < max_fragments; f++)
2336 : : {
2337 : 24 : maxitems = 0;
3300 andres@anarazel.de 2338 : 24 : minwords = PG_INT32_MAX;
5658 teodor@sigaev.ru 2339 : 24 : minI = -1;
2340 : :
2341 : : /*
2342 : : * Choose the cover that contains max items. In case of tie choose the
2343 : : * one with smaller number of words.
2344 : : */
4753 bruce@momjian.us 2345 [ + + ]: 57 : for (i = 0; i < numcovers; i++)
2346 : : {
1466 tgl@sss.pgh.pa.us 2347 [ + + + - ]: 33 : if (!covers[i].chosen && !covers[i].excluded &&
2348 [ + + ]: 24 : (maxitems < covers[i].poslen ||
2349 [ + - ]: 6 : (maxitems == covers[i].poslen &&
2350 [ - + ]: 6 : minwords > covers[i].curlen)))
2351 : : {
5658 teodor@sigaev.ru 2352 : 18 : maxitems = covers[i].poslen;
2353 : 18 : minwords = covers[i].curlen;
4753 bruce@momjian.us 2354 : 18 : minI = i;
2355 : : }
2356 : : }
2357 : : /* if a cover was found mark it */
5658 teodor@sigaev.ru 2358 [ + + ]: 24 : if (minI >= 0)
2359 : : {
1466 tgl@sss.pgh.pa.us 2360 : 18 : covers[minI].chosen = true;
2361 : : /* adjust the size of cover */
5658 teodor@sigaev.ru 2362 : 18 : startpos = covers[minI].startpos;
4753 bruce@momjian.us 2363 : 18 : endpos = covers[minI].endpos;
2364 : 18 : curlen = covers[minI].curlen;
2365 : : /* stretch the cover if cover size is lower than max_words */
4891 peter_e@gmx.net 2366 [ + - ]: 18 : if (curlen < max_words)
2367 : : {
2368 : : /* divide the stretch on both sides of cover */
4753 bruce@momjian.us 2369 : 18 : maxstretch = (max_words - curlen) / 2;
2370 : :
2371 : : /*
2372 : : * first stretch the startpos stop stretching if 1. we hit the
2373 : : * beginning of document 2. exceed maxstretch 3. we hit an
2374 : : * already marked fragment
2375 : : */
2376 : 18 : stretch = 0;
5658 teodor@sigaev.ru 2377 : 18 : posmarker = startpos;
2378 [ + + + + : 300 : for (i = startpos - 1; i >= 0 && stretch < maxstretch && !prs->words[i].in; i--)
+ + ]
2379 : : {
2380 [ + + + - : 282 : if (!NONWORDTOKEN(prs->words[i].type))
+ - + - +
- + - ]
2381 : : {
4753 bruce@momjian.us 2382 : 135 : curlen++;
2383 : 135 : stretch++;
2384 : : }
5658 teodor@sigaev.ru 2385 : 282 : posmarker = i;
2386 : : }
2387 : : /* cut back startpos till we find a good endpoint */
1466 tgl@sss.pgh.pa.us 2388 [ + + + + : 66 : for (i = posmarker; i < startpos && BADENDPOINT(i); i++)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + +
+ - - - ]
2389 : : {
5658 teodor@sigaev.ru 2390 [ + + + - : 48 : if (!NONWORDTOKEN(prs->words[i].type))
+ - + - +
- + - ]
4753 bruce@momjian.us 2391 : 18 : curlen--;
2392 : : }
5658 teodor@sigaev.ru 2393 : 18 : startpos = i;
2394 : : /* now stretch the endpos as much as possible */
2395 : 18 : posmarker = endpos;
2396 [ + + + + : 483 : for (i = endpos + 1; i < prs->curwords && curlen < max_words && !prs->words[i].in; i++)
+ - ]
2397 : : {
2398 [ + + + - : 465 : if (!NONWORDTOKEN(prs->words[i].type))
+ - + - +
- + - ]
4753 bruce@momjian.us 2399 : 231 : curlen++;
4891 peter_e@gmx.net 2400 : 465 : posmarker = i;
2401 : : }
2402 : : /* cut back endpos till we find a good endpoint */
1466 tgl@sss.pgh.pa.us 2403 [ + + + + : 45 : for (i = posmarker; i > endpos && BADENDPOINT(i); i--)
+ - + - +
- + - + -
+ - + - +
- + + + +
+ - + - +
- + - - +
+ - - - ]
2404 : : {
5658 teodor@sigaev.ru 2405 [ + + + - : 27 : if (!NONWORDTOKEN(prs->words[i].type))
+ - + - +
- + - ]
4753 bruce@momjian.us 2406 : 12 : curlen--;
2407 : : }
5658 teodor@sigaev.ru 2408 : 18 : endpos = i;
2409 : : }
2410 : 18 : covers[minI].startpos = startpos;
4753 bruce@momjian.us 2411 : 18 : covers[minI].endpos = endpos;
2412 : 18 : covers[minI].curlen = curlen;
2413 : : /* Mark the chosen fragments (covers) */
1466 tgl@sss.pgh.pa.us 2414 : 18 : mark_fragment(prs, highlightall, startpos, endpos);
4753 bruce@momjian.us 2415 : 18 : num_f++;
2416 : : /* Exclude covers overlapping this one from future consideration */
2417 [ + + ]: 48 : for (i = 0; i < numcovers; i++)
2418 : : {
1466 tgl@sss.pgh.pa.us 2419 [ + + ]: 30 : if (i != minI &&
2420 [ + + ]: 12 : ((covers[i].startpos >= startpos &&
2421 [ + - ]: 6 : covers[i].startpos <= endpos) ||
2422 [ + + ]: 12 : (covers[i].endpos >= startpos &&
2423 [ + - ]: 6 : covers[i].endpos <= endpos) ||
2424 [ + + ]: 12 : (covers[i].startpos < startpos &&
2425 [ - + ]: 6 : covers[i].endpos > endpos)))
1466 tgl@sss.pgh.pa.us 2426 :UBC 0 : covers[i].excluded = true;
2427 : : }
2428 : : }
2429 : : else
1466 tgl@sss.pgh.pa.us 2430 :CBC 6 : break; /* no selectable covers remain */
2431 : : }
2432 : :
2433 : : /* show the first min_words words if we have not marked anything */
5658 teodor@sigaev.ru 2434 [ + + ]: 15 : if (num_f <= 0)
2435 : : {
374 tgl@sss.pgh.pa.us 2436 : 3 : startpos = curlen = 0;
2437 : 3 : endpos = -1;
5658 teodor@sigaev.ru 2438 [ + - + + ]: 93 : for (i = 0; i < prs->curwords && curlen < min_words; i++)
2439 : : {
2440 [ + + + - : 90 : if (!NONWORDTOKEN(prs->words[i].type))
+ - + - +
- + - ]
2441 : 45 : curlen++;
2442 : 90 : endpos = i;
2443 : : }
1466 tgl@sss.pgh.pa.us 2444 : 3 : mark_fragment(prs, highlightall, startpos, endpos);
2445 : : }
2446 : :
5658 teodor@sigaev.ru 2447 : 15 : pfree(covers);
2448 : 15 : }
2449 : :
2450 : : /*
2451 : : * Headline selector used when MaxFragments == 0
2452 : : */
2453 : : static void
451 tgl@sss.pgh.pa.us 2454 : 172 : mark_hl_words(HeadlineParsedText *prs, TSQuery query, List *locations,
2455 : : bool highlightall,
2456 : : int shortword, int min_words, int max_words)
2457 : : {
2458 : 172 : int nextpos = 0,
2459 : 172 : p = 0,
6081 2460 : 172 : q = 0;
2461 : 172 : int bestb = -1,
2462 : 172 : beste = -1;
2463 : 172 : int bestlen = -1;
1466 2464 : 172 : bool bestcover = false;
2465 : : int pose,
2466 : : posb,
2467 : : poslen,
2468 : : curlen;
2469 : : bool poscover;
2470 : : int i;
2471 : :
2472 [ + + ]: 172 : if (!highlightall)
2473 : : {
2474 : : /* examine all covers, select a headline using the best one */
451 2475 [ + + ]: 254 : while (hlCover(prs, query, locations, &nextpos, &p, &q))
2476 : : {
2477 : : /*
2478 : : * Count words (curlen) and interesting words (poslen) within
2479 : : * cover, but stop once we reach max_words. This step doesn't
2480 : : * consider whether that's a good stopping point. posb and pose
2481 : : * are set to the start and end indexes of the possible headline.
2482 : : */
6081 2483 : 85 : curlen = 0;
2484 : 85 : poslen = 0;
1466 2485 : 85 : posb = pose = p;
6081 2486 [ + + + + ]: 728 : for (i = p; i <= q && curlen < max_words; i++)
2487 : : {
2488 [ + + + - : 643 : if (!NONWORDTOKEN(prs->words[i].type))
+ - + - +
- + - ]
2489 : 364 : curlen++;
1466 2490 [ + + + - ]: 643 : if (INTERESTINGWORD(i))
6081 2491 : 145 : poslen++;
2492 : 643 : pose = i;
2493 : : }
2494 : :
2495 [ + + ]: 85 : if (curlen < max_words)
2496 : : {
2497 : : /*
2498 : : * We have room to lengthen the headline, so search forward
2499 : : * until it's full or we find a good stopping point. We'll
2500 : : * reconsider the word at "q", then move forward.
2501 : : */
2502 [ + + + - ]: 1469 : for (i = i - 1; i < prs->curwords && curlen < max_words; i++)
2503 : : {
1466 2504 [ + + ]: 1456 : if (i > q)
2505 : : {
6081 2506 [ + + + - : 1377 : if (!NONWORDTOKEN(prs->words[i].type))
+ - + - +
- + - ]
2507 : 687 : curlen++;
1466 2508 [ + + + - ]: 1377 : if (INTERESTINGWORD(i))
6081 2509 : 60 : poslen++;
2510 : : }
2511 : 1456 : pose = i;
1466 2512 [ + + + - : 1456 : if (BADENDPOINT(i))
+ - + - +
- + - + -
+ - + - +
+ + + + -
+ - + - +
- + + + +
- + ]
6081 2513 : 972 : continue;
2514 [ + + ]: 484 : if (curlen >= min_words)
2515 : 66 : break;
2516 : : }
1466 2517 [ + + ]: 79 : if (curlen < min_words)
2518 : : {
2519 : : /*
2520 : : * Reached end of text and our headline is still shorter
2521 : : * than min_words, so try to extend it to the left.
2522 : : */
5568 teodor@sigaev.ru 2523 [ + + ]: 183 : for (i = p - 1; i >= 0; i--)
2524 : : {
6081 tgl@sss.pgh.pa.us 2525 [ + + + - : 182 : if (!NONWORDTOKEN(prs->words[i].type))
+ - + - +
- + - ]
2526 : 91 : curlen++;
1466 2527 [ + + + - ]: 182 : if (INTERESTINGWORD(i))
6081 2528 : 3 : poslen++;
4753 bruce@momjian.us 2529 [ - + ]: 182 : if (curlen >= max_words)
5568 teodor@sigaev.ru 2530 :UBC 0 : break;
1466 tgl@sss.pgh.pa.us 2531 [ + + + - :CBC 182 : if (BADENDPOINT(i))
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + + - +
- - ]
6081 2532 : 118 : continue;
2533 [ + + ]: 64 : if (curlen >= min_words)
2534 : 12 : break;
2535 : : }
2536 : 13 : posb = (i >= 0) ? i : 0;
2537 : : }
2538 : : }
2539 : : else
2540 : : {
2541 : : /*
2542 : : * Can't make headline longer, so consider making it shorter
2543 : : * if needed to avoid a bad endpoint.
2544 : : */
2928 teodor@sigaev.ru 2545 [ + + ]: 6 : if (i > q)
2546 : 3 : i = q;
6081 tgl@sss.pgh.pa.us 2547 [ + - ]: 15 : for (; curlen > min_words; i--)
2548 : : {
1466 2549 [ + + + - : 15 : if (!BADENDPOINT(i))
+ - + - +
- + - + -
+ - + - +
- + + + -
+ - + - +
- + + + +
- + ]
2550 : : break;
6081 2551 [ + + + - : 9 : if (!NONWORDTOKEN(prs->words[i].type))
+ - + - +
- + - ]
2552 : 3 : curlen--;
1466 2553 [ - + - - ]: 9 : if (INTERESTINGWORD(i))
6081 tgl@sss.pgh.pa.us 2554 :UBC 0 : poslen--;
1466 tgl@sss.pgh.pa.us 2555 :CBC 9 : pose = i - 1;
2556 : : }
2557 : : }
2558 : :
2559 : : /*
2560 : : * Check whether the proposed headline includes the original
2561 : : * cover; it might not if we trimmed it due to max_words.
2562 : : */
2563 [ + - + + ]: 85 : poscover = (posb <= p && pose >= q);
2564 : :
2565 : : /*
2566 : : * Adopt this headline if it's better than the last one, giving
2567 : : * highest priority to headlines including the cover, then to
2568 : : * headlines with more interesting words, then to headlines with
2569 : : * good stopping points. (Since bestlen is initially -1, we will
2570 : : * certainly adopt the first headline.)
2571 : : */
2572 [ + + + - ]: 85 : if (poscover > bestcover ||
2573 [ + + + - ]: 39 : (poscover == bestcover && poslen > bestlen) ||
2574 [ + + ]: 36 : (poscover == bestcover && poslen == bestlen &&
2575 [ + - + - : 6 : !BADENDPOINT(pose) && BADENDPOINT(beste)))
+ - + - +
- + - + -
+ - + - +
- - + - -
- - - - -
- - - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - - + -
- - - - -
- - - - +
- - + ]
2576 : : {
6081 2577 : 49 : bestb = posb;
2578 : 49 : beste = pose;
2579 : 49 : bestlen = poslen;
1466 2580 : 49 : bestcover = poscover;
2581 : : }
2582 : : }
2583 : :
2584 : : /*
2585 : : * If we found nothing acceptable, select min_words words starting at
2586 : : * the beginning.
2587 : : */
6081 2588 [ + + ]: 169 : if (bestlen < 0)
2589 : : {
2590 : 120 : curlen = 0;
374 2591 : 120 : pose = -1;
6081 2592 [ + + + - ]: 519 : for (i = 0; i < prs->curwords && curlen < min_words; i++)
2593 : : {
2594 [ + + + - : 399 : if (!NONWORDTOKEN(prs->words[i].type))
+ - + - +
- + - ]
2595 : 258 : curlen++;
2596 : 399 : pose = i;
2597 : : }
2598 : 120 : bestb = 0;
2599 : 120 : beste = pose;
2600 : : }
2601 : : }
2602 : : else
2603 : : {
2604 : : /* highlightall mode: headline is whole document */
2605 : 3 : bestb = 0;
2606 : 3 : beste = prs->curwords - 1;
2607 : : }
2608 : :
1466 2609 : 172 : mark_fragment(prs, highlightall, bestb, beste);
5658 teodor@sigaev.ru 2610 : 172 : }
2611 : :
2612 : : /*
2613 : : * Default parser's prsheadline function
2614 : : */
2615 : : Datum
2616 : 187 : prsd_headline(PG_FUNCTION_ARGS)
2617 : : {
2618 : 187 : HeadlineParsedText *prs = (HeadlineParsedText *) PG_GETARG_POINTER(0);
2619 : 187 : List *prsoptions = (List *) PG_GETARG_POINTER(1);
2620 : 187 : TSQuery query = PG_GETARG_TSQUERY(2);
2621 : : List *locations;
2622 : :
2623 : : /* default option values: */
4753 bruce@momjian.us 2624 : 187 : int min_words = 15;
2625 : 187 : int max_words = 35;
2626 : 187 : int shortword = 3;
5658 teodor@sigaev.ru 2627 : 187 : int max_fragments = 0;
1466 tgl@sss.pgh.pa.us 2628 : 187 : bool highlightall = false;
2629 : : ListCell *l;
2630 : :
2631 : : /* Extract configuration option values */
5658 teodor@sigaev.ru 2632 : 187 : prs->startsel = NULL;
2633 : 187 : prs->stopsel = NULL;
1466 tgl@sss.pgh.pa.us 2634 : 187 : prs->fragdelim = NULL;
5658 teodor@sigaev.ru 2635 [ + + + + : 364 : foreach(l, prsoptions)
+ + ]
2636 : : {
2637 : 177 : DefElem *defel = (DefElem *) lfirst(l);
2638 : 177 : char *val = defGetString(defel);
2639 : :
2640 [ + + ]: 177 : if (pg_strcasecmp(defel->defname, "MaxWords") == 0)
2093 andres@anarazel.de 2641 : 18 : max_words = pg_strtoint32(val);
5658 teodor@sigaev.ru 2642 [ + + ]: 159 : else if (pg_strcasecmp(defel->defname, "MinWords") == 0)
2093 andres@anarazel.de 2643 : 18 : min_words = pg_strtoint32(val);
5658 teodor@sigaev.ru 2644 [ - + ]: 141 : else if (pg_strcasecmp(defel->defname, "ShortWord") == 0)
2093 andres@anarazel.de 2645 :UBC 0 : shortword = pg_strtoint32(val);
5658 teodor@sigaev.ru 2646 [ + + ]:CBC 141 : else if (pg_strcasecmp(defel->defname, "MaxFragments") == 0)
2093 andres@anarazel.de 2647 : 15 : max_fragments = pg_strtoint32(val);
5658 teodor@sigaev.ru 2648 [ + + ]: 126 : else if (pg_strcasecmp(defel->defname, "StartSel") == 0)
2649 : 60 : prs->startsel = pstrdup(val);
2650 [ + + ]: 66 : else if (pg_strcasecmp(defel->defname, "StopSel") == 0)
2651 : 60 : prs->stopsel = pstrdup(val);
2652 [ + + ]: 6 : else if (pg_strcasecmp(defel->defname, "FragmentDelimiter") == 0)
2653 : 3 : prs->fragdelim = pstrdup(val);
2654 [ + - ]: 3 : else if (pg_strcasecmp(defel->defname, "HighlightAll") == 0)
1466 tgl@sss.pgh.pa.us 2655 [ + - ]: 9 : highlightall = (pg_strcasecmp(val, "1") == 0 ||
2656 [ - + ]: 6 : pg_strcasecmp(val, "on") == 0 ||
2657 [ - - ]: 3 : pg_strcasecmp(val, "true") == 0 ||
1466 tgl@sss.pgh.pa.us 2658 [ # # ]:UBC 0 : pg_strcasecmp(val, "t") == 0 ||
1466 tgl@sss.pgh.pa.us 2659 [ + - - - ]:CBC 6 : pg_strcasecmp(val, "y") == 0 ||
1466 tgl@sss.pgh.pa.us 2660 :UBC 0 : pg_strcasecmp(val, "yes") == 0);
2661 : : else
5658 teodor@sigaev.ru 2662 [ # # ]: 0 : ereport(ERROR,
2663 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2664 : : errmsg("unrecognized headline parameter: \"%s\"",
2665 : : defel->defname)));
2666 : : }
2667 : :
2668 : : /* in HighlightAll mode these parameters are ignored */
1466 tgl@sss.pgh.pa.us 2669 [ + + ]:CBC 187 : if (!highlightall)
2670 : : {
5658 teodor@sigaev.ru 2671 [ - + ]: 184 : if (min_words >= max_words)
5658 teodor@sigaev.ru 2672 [ # # ]:UBC 0 : ereport(ERROR,
2673 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2674 : : errmsg("MinWords should be less than MaxWords")));
5658 teodor@sigaev.ru 2675 [ - + ]:CBC 184 : if (min_words <= 0)
5658 teodor@sigaev.ru 2676 [ # # ]:UBC 0 : ereport(ERROR,
2677 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2678 : : errmsg("MinWords should be positive")));
5658 teodor@sigaev.ru 2679 [ - + ]:CBC 184 : if (shortword < 0)
5658 teodor@sigaev.ru 2680 [ # # ]:UBC 0 : ereport(ERROR,
2681 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2682 : : errmsg("ShortWord should be >= 0")));
5658 teodor@sigaev.ru 2683 [ - + ]:CBC 184 : if (max_fragments < 0)
5658 teodor@sigaev.ru 2684 [ # # ]:UBC 0 : ereport(ERROR,
2685 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2686 : : errmsg("MaxFragments should be >= 0")));
2687 : : }
2688 : :
2689 : : /* Locate words and phrases matching the query */
374 tgl@sss.pgh.pa.us 2690 [ + + ]:CBC 187 : if (query->size > 0)
2691 : : {
2692 : : hlCheck ch;
2693 : :
2694 : 181 : ch.words = prs->words;
2695 : 181 : ch.len = prs->curwords;
2696 : 181 : locations = TS_execute_locations(GETQUERY(query), &ch, TS_EXEC_EMPTY,
2697 : : checkcondition_HL);
2698 : : }
2699 : : else
2700 : 6 : locations = NIL; /* empty query matches nothing */
2701 : :
2702 : : /* Apply appropriate headline selector */
5658 teodor@sigaev.ru 2703 [ + + ]: 187 : if (max_fragments == 0)
451 tgl@sss.pgh.pa.us 2704 : 172 : mark_hl_words(prs, query, locations, highlightall, shortword,
2705 : : min_words, max_words);
2706 : : else
2707 : 15 : mark_hl_fragments(prs, query, locations, highlightall, shortword,
2708 : : min_words, max_words, max_fragments);
2709 : :
2710 : : /* Fill in default values for string options */
6081 2711 [ + + ]: 187 : if (!prs->startsel)
2712 : 127 : prs->startsel = pstrdup("<b>");
2713 [ + + ]: 187 : if (!prs->stopsel)
2714 : 127 : prs->stopsel = pstrdup("</b>");
5658 teodor@sigaev.ru 2715 [ + + ]: 187 : if (!prs->fragdelim)
2716 : 184 : prs->fragdelim = pstrdup(" ... ");
2717 : :
2718 : : /* Caller will need these lengths, too */
6081 tgl@sss.pgh.pa.us 2719 : 187 : prs->startsellen = strlen(prs->startsel);
2720 : 187 : prs->stopsellen = strlen(prs->stopsel);
5658 teodor@sigaev.ru 2721 : 187 : prs->fragdelimlen = strlen(prs->fragdelim);
2722 : :
6081 tgl@sss.pgh.pa.us 2723 : 187 : PG_RETURN_POINTER(prs);
2724 : : }
|