geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

lregex.c
Go to the documentation of this file.
1/*
2* Copyright (c) 2000-2003, Darren Hiebert
3*
4* This source code is released for free distribution under the terms of the
5* GNU General Public License version 2 or (at your option) any later version.
6*
7* This module contains functions for applying regular expression matching.
8*
9* The code for utilizing the Gnu regex package with regards to processing the
10* regex option and checking for regex matches was adapted from routines in
11* Gnu etags.
12*/
13
14/*
15* INCLUDE FILES
16*/
17#include "general.h" /* must always come first */
18
19#include <string.h>
20
21#include <ctype.h>
22#include <stddef.h>
23#ifdef HAVE_SYS_TYPES_H
24# include <sys/types.h> /* declare off_t (not known to regex.h on FreeBSD) */
25#endif
26#include <regex.h>
27
28#include <inttypes.h>
29
30#include "debug.h"
31#include "colprint_p.h"
32#include "entry_p.h"
33#include "field_p.h"
34#include "flags_p.h"
35#include "htable.h"
36#include "kind.h"
37#include "options.h"
38#include "parse_p.h"
39#include "promise.h"
40#include "read.h"
41#include "read_p.h"
42#include "routines.h"
43#include "routines_p.h"
44#include "trashbox.h"
45#include "xtag_p.h"
46
47static bool regexAvailable = false;
48
49/*
50* MACROS
51*/
52
53/* Back-references \0 through \9 */
54#define BACK_REFERENCE_COUNT 10
55
56/* The max depth of taction=enter/leave stack */
57#define MTABLE_STACK_MAX_DEPTH 64
58
59/* How many times ctags allows a mtable parser
60 stays at the same input position across table switching.
61
62 The value is derived from MTABLE_STACK_MAX_DEPTH.
63 No deep meaning is in that. It just for simplifying
64 Tmain cases. */
65#define MTABLE_MOTIONLESS_MAX (MTABLE_STACK_MAX_DEPTH + 1)
66
67
68/*
69* DATA DECLARATIONS
70*/
71
73
75 SCOPE_REF = 1UL << 0,
76 SCOPE_POP = 1UL << 1,
77 SCOPE_PUSH = 1UL << 2,
78 SCOPE_CLEAR = 1UL << 3,
80};
81
84 TACTION_ENTER, /* {tenter=N} */
85 TACTION_LEAVE, /* {tleave} */
86 TACTION_JUMP, /* {tjump=N} */
87 TACTION_RESET, /* {treset=N} */
88 TACTION_QUIT, /* {tquit} */
89};
90
93 const char *template;
94};
95
100};
101
106 GUEST_LANG_STATIC_LANGNAME, /* C, Python,... */
109 } type;
110 union {
113 } spec;
114};
115
116struct guestSpec {
118#define BOUNDARY_START 0
119#define BOUNDARY_END 1
120 struct boundarySpec boundary[2];
121};
122
124#define NO_MULTILINE -1
127 /* true => start, false => end */
129};
130
134
135 /* used when action == TACTION_ENTER */
137};
138
139typedef struct {
144 union {
145 struct {
149 } tag;
150 struct {
152 void *userData;
153 } callback;
154 } u;
155 unsigned int scopeActions;
156 bool *disabled;
157
162
165
167
169
170 struct {
173 } message;
174
177
178
179typedef struct {
180 /* the pattern can be shared among entries using a refcount */
182
183 /* but the statistics are per-table-entry */
184 struct {
185 unsigned int match;
186 unsigned int unmatch;
187 } statistics;
189
190
191#define TABLE_INDEX_UNUSED -1
193 char *name;
195};
196
199 off_t offset;
200};
201
205
206 struct boundaryInRequest boundary[2];
207};
208
212
215
217
219};
220
221/*
222* DATA DEFINITIONS
223*/
224
225/*
226* FUNCTION DEFINITIONS
227*/
228static int getTableIndexForName (const struct lregexControlBlock *const lcb, const char *name);
229static void deletePattern (regexPattern *p);
230static int makePromiseForAreaSpecifiedWithOffsets (const char *parser,
231 off_t startOffset,
232 off_t endOffset);
233
234static struct guestRequest *guestRequestNew (void);
235static void guestRequestDelete (struct guestRequest *);
236static bool guestRequestIsFilled(struct guestRequest *);
237static void guestRequestClear (struct guestRequest *);
238static void guestRequestSubmit (struct guestRequest *);
239
240static void deleteTable (void *ptrn)
241{
242 struct regexTable *t = ptrn;
243
245 eFree (t->name);
246 eFree (t);
247}
248
249static void deleteTableEntry (void *ptrn)
250{
251 regexTableEntry *e = ptrn;
252 Assert (e && e->pattern);
254 eFree (e);
255}
256
258{
259 p->refcount--;
260
261 if (p->refcount > 0)
262 return;
263
264 regfree (p->pattern);
265 eFree (p->pattern);
266 p->pattern = NULL;
267
268 if (p->type == PTRN_TAG)
269 {
270 eFree (p->u.tag.name_pattern);
271 p->u.tag.name_pattern = NULL;
272 }
273
274 if (p->fieldPatterns)
275 {
277 p->fieldPatterns = NULL;
278 }
279
281
282 if (p->message.message_string)
284
287
288 eFree (p);
289}
290
291static void clearPatternSet (struct lregexControlBlock *lcb)
292{
295 ptrArrayClear (lcb->tables);
296}
297
299{
300 struct lregexControlBlock *lcb = xCalloc (1, struct lregexControlBlock);
301
305 lcb->tstack = ptrArrayNew(NULL);
306 lcb->guest_req = guestRequestNew ();
307 lcb->owner = parser->id;
308
309 return lcb;
310}
311
313{
314 clearPatternSet (lcb);
315
320
321 ptrArrayDelete (lcb->tables);
322 lcb->tables = NULL;
323
324 ptrArrayDelete (lcb->tstack);
325 lcb->tstack = NULL;
326
328 lcb->guest_req = NULL;
329
330 eFree (lcb);
331}
332
333/*
334* Regex pseudo-parser
335*/
336
338 const vString* const name, int kindIndex, int roleIndex, int scopeIndex, int placeholder,
339 unsigned long line, MIOPos *pos, int xtag_type)
340{
341 Assert (name != NULL && ((vStringLength (name) > 0) || placeholder));
342 initRefTagEntry (e, vStringValue (name), kindIndex, roleIndex);
343 e->extensionFields.scopeIndex = scopeIndex;
344 e->placeholder = !!placeholder;
345 if (line)
346 {
347 e->lineNumber = line;
348 e->filePosition = *pos;
349 }
350
351 if (xtag_type != XTAG_UNKNOWN)
352 markTagExtraBit (e, xtag_type);
353}
354
355/*
356* Regex pattern definition
357*/
358
359/* Take a string like "/blah/" and turn it into "blah", making sure
360 * that the first and last characters are the same, and handling
361 * quoted separator characters. Actually, stops on the occurrence of
362 * an unquoted separator. Also turns "\t" into a Tab character.
363 * Turns "\n" into a Newline character if MULTILINE is true.
364 * Returns pointer to terminating separator. Works in place. Null
365 * terminates name string.
366 */
367static char* scanSeparators (char* name, enum regexParserType regptype)
368{
369 char sep = name [0];
370 char *copyto = name;
371 bool quoted = false;
372
373 for (++name ; *name != '\0' ; ++name)
374 {
375 if (quoted)
376 {
377 if (*name == sep)
378 *copyto++ = sep;
379 else if (*name == 't')
380 *copyto++ = '\t';
381 else if ((regptype == REG_PARSER_MULTI_LINE
382 || (regptype == REG_PARSER_MULTI_TABLE))
383 && *name == 'n')
384 *copyto++ = '\n';
385 else
386 {
387 /* Something else is quoted, so preserve the quote. */
388 *copyto++ = '\\';
389 *copyto++ = *name;
390 }
391 quoted = false;
392 }
393 else if (*name == '\\')
394 quoted = true;
395 else if (*name == sep)
396 {
397 break;
398 }
399 else
400 *copyto++ = *name;
401 }
402 *copyto = '\0';
403 return name;
404}
405
406/* Parse `regexp', in form "/regex/name/[k,Kind/]flags" (where the separator
407 * character is whatever the first character of `regexp' is), by breaking it
408 * up into null terminated strings, removing the separators, and expanding
409 * '\t' into tabs. When complete, `regexp' points to the line matching
410 * pattern, a pointer to the name matching pattern is written to `name', a
411 * pointer to the kinds is written to `kinds' (possibly NULL), and a pointer
412 * to the trailing flags is written to `flags'. If the pattern is not in the
413 * correct format, a false value is returned.
414 */
415static bool parseTagRegex (
416 enum regexParserType regptype,
417 char* const regexp, char** const name,
418 char** const kinds, char** const flags)
419{
420 bool result = false;
421 const int separator = (unsigned char) regexp [0];
422
423 *name = scanSeparators (regexp, regptype);
424 if (*regexp == '\0')
425 error (WARNING, "empty regexp");
426 else if (**name != separator)
427 error (WARNING, "%s: incomplete regexp", regexp);
428 else
429 {
430 char* const third = scanSeparators (*name, false);
431 if (**name != '\0' && (*name) [strlen (*name) - 1] == '\\')
432 error (WARNING, "error in name pattern: \"%s\"", *name);
433 if (*third != separator)
434 error (WARNING, "%s: regexp missing final separator", regexp);
435 else
436 {
437 /*
438 * first----------V third------------V
439 * --regex-<LANG>=/regexp/replacement/[kind-spec/][flags]
440 * second----------------^ fourth---------------^
441 */
442
443 char* const fourth = scanSeparators (third, false);
444 if (*fourth == separator)
445 {
446 *kinds = third;
447 scanSeparators (fourth, false);
448 *flags = fourth;
449 }
450 else
451 {
452 *flags = third;
453 *kinds = NULL;
454 }
455 result = true;
456 }
457 }
458 return result;
459}
460
461
462static void pre_ptrn_flag_exclusive_short (char c CTAGS_ATTR_UNUSED, void* data)
463{
464 bool *exclusive = data;
465 *exclusive = true;
466}
467
468static void pre_ptrn_flag_exclusive_long (const char* const s CTAGS_ATTR_UNUSED, const char* const unused CTAGS_ATTR_UNUSED, void* data)
469{
471}
472
475 NULL, "skip testing the other patterns if a line is matched to this pattern"},
476};
477
478static void scope_ptrn_flag_eval (const char* const f CTAGS_ATTR_UNUSED,
479 const char* const v, void* data)
480{
481 unsigned int *bfields = data;
482
483 if (strcmp (v, "ref") == 0)
484 *bfields |= SCOPE_REF;
485 else if (strcmp (v, "push") == 0)
486 *bfields |= (SCOPE_PUSH | SCOPE_REF);
487 else if (strcmp (v, "pop") == 0)
488 *bfields |= SCOPE_POP;
489 else if (strcmp (v, "clear") == 0)
490 *bfields |= SCOPE_CLEAR;
491 else if (strcmp (v, "set") == 0)
492 *bfields |= (SCOPE_CLEAR | SCOPE_PUSH);
493 else
494 error (FATAL, "Unexpected value for scope flag in regex definition: scope=%s", v);
495}
496
497static void placeholder_ptrn_flag_eval (const char* const f CTAGS_ATTR_UNUSED,
498 const char* const v CTAGS_ATTR_UNUSED, void* data)
499{
500 unsigned int *bfields = data;
501 *bfields |= SCOPE_PLACEHOLDER;
502}
503
505 { '\0', "scope", NULL, scope_ptrn_flag_eval,
506 "ACTION", "use scope stack: ACTION = ref|push|pop|clear|set"},
507 { '\0', "placeholder", NULL, placeholder_ptrn_flag_eval,
508 NULL, "don't put this tag to tags file."},
509};
510
511static kindDefinition *kindNew (char letter, const char *name, const char *description)
512{
514 kdef->letter = letter;
515 kdef->name = eStrdup (name);
516 kdef->description = eStrdup(description? description: kdef->name);
517 kdef->enabled = true;
518 return kdef;
519}
520
521static void kindFree (kindDefinition *kind)
522{
523 kind->letter = '\0';
524 eFree ((void *)kind->name);
525 kind->name = NULL;
526 eFree ((void *)kind->description);
527 kind->description = NULL;
528 eFree (kind);
529}
530
531static void initMgroup(struct mGroupSpec *mgroup)
532{
535 mgroup->nextFromStart = false;
536}
537
538static void initGuestSpec (struct guestSpec *guest)
539{
540 guest->lang.type = GUEST_LANG_UNKNOWN;
541}
542
543static void initTaction(struct mTableActionSpec *taction)
544{
545 taction->action = TACTION_NOP;
546 taction->table = NULL;
547}
548
550{
551 ptrn->refcount++;
552 return ptrn;
553}
554
555static regexPattern * newPattern (regex_t* const pattern,
556 enum regexParserType regptype)
557{
559
560 ptrn->pattern = pattern;
561 ptrn->exclusive = false;
562 ptrn->accept_empty_name = false;
563 ptrn->regptype = regptype;
564 ptrn->xtagType = XTAG_UNKNOWN;
565
566 if (regptype == REG_PARSER_MULTI_LINE)
567 initMgroup(&ptrn->mgroup);
568 if (regptype == REG_PARSER_MULTI_TABLE)
569 initTaction(&ptrn->taction);
570 initGuestSpec (&ptrn->guest);
571
572 ptrn->u.tag.roleBits = 0;
573 ptrn->refcount = 1;
574 return ptrn;
575}
576
578{
580
581 Assert (other && other->pattern);
582
583 entry->pattern = refPattern(other->pattern);
584 return entry;
585}
586
587static regexTableEntry * newEntry (regex_t* const pattern,
588 enum regexParserType regptype)
589{
591 entry->pattern = newPattern (pattern, regptype);
592 return entry;
593}
594
596 int table_index,
597 regex_t* const pattern,
598 enum regexParserType regptype)
599{
600 regexTableEntry *entry = newEntry (pattern, regptype);
601
602 if (regptype == REG_PARSER_MULTI_TABLE)
603 {
604 struct regexTable *table = ptrArrayItem (lcb->tables, table_index);
605 Assert(table);
606
607 ptrArrayAdd (table->entries, entry);
608 }
609 else
610 ptrArrayAdd (lcb->entries[regptype], entry);
611
612 useRegexMethod(lcb->owner);
613
614 return entry->pattern;
615}
616
617static void pre_ptrn_flag_mgroup_long (const char* const s, const char* const v, void* data)
618{
619 struct mGroupSpec *mgroup = data;
620 if (!v)
621 {
622 error (WARNING, "no value is given for: %s", s);
623 return;
624 }
625 if (!strToInt (v, 10, &mgroup->forLineNumberDetermination))
626 {
627 error (WARNING, "wrong %s specification: %s", s, v);
629 }
630 else if (mgroup->forLineNumberDetermination < 0
632 {
633 error (WARNING, "out of range(0 ~ %d) %s specification: %s",
635 s, v);
637 }
638}
639
640static void pre_ptrn_flag_advanceTo_long (const char* const s, const char* const v, void* data)
641{
642 struct mGroupSpec *mgroup = data;
643 char *vdup;
644 char *tmp;
645
646
647 if (!v)
648 {
649 error (WARNING, "no value is given for: %s", s);
650 return;
651 }
652
653 vdup = eStrdup (v);
654
655 mgroup->nextFromStart = false;
656 if ((tmp = strstr(vdup, "start")))
657 {
658 mgroup->nextFromStart = true;
659 *tmp = '\0';
660 }
661 else if ((tmp = strstr(vdup, "end")))
662 *tmp = '\0';
663
664 if (!strToInt (vdup, 10, &(mgroup->forNextScanning)))
665 {
666 error (WARNING, "wrong %s specification: %s", s, vdup);
667 mgroup->nextFromStart = false;
668 }
669 else if (mgroup->forNextScanning < 0 || mgroup->forNextScanning >= BACK_REFERENCE_COUNT)
670 {
671 error (WARNING, "out of range(0 ~ %d) %s specification: %s",
672 (BACK_REFERENCE_COUNT - 1), s, vdup);
673 mgroup->nextFromStart = false;
674 }
675
676 eFree (vdup);
677}
678
682};
683
684static void pre_ptrn_flag_guest_long (const char* const s, const char* const v, void* data)
685{
686 struct guestPtrnFlagData *flagData = data;
687 enum regexParserType type = flagData->type;
688 struct guestSpec *guest = flagData->guest;
689 struct boundarySpec *current;
690
691 if (!v)
692 {
693 error (WARNING, "no value is given for: %s", s);
694 return;
695 }
696
697 char *tmp = strchr (v, ',');
698 if (tmp == NULL)
699 {
700 error (WARNING, "no terminator found for parser name: %s", s);
701 return;
702 }
703
704 if ((tmp - v) == 0)
705 {
706 if (type == REG_PARSER_MULTI_LINE)
707 {
708 error (WARNING,
709 "using placeholder for guest name field is not allowed in multiline regex spec: %s", v);
710 goto err;
711 }
712
713 guest->lang.type = GUEST_LANG_PLACEHOLDER;
714 }
715 else if (*v == '\\' || *v == '*')
716 {
717 const char *n_tmp = v + 1;
718 const char *n = n_tmp;
719 for (; isdigit (*n_tmp); n_tmp++);
720 char c = *n_tmp;
721 *(char *)n_tmp = '\0';
722 if (!strToInt (n, 10, &(guest->lang.spec.patternGroup)))
723 {
724 error (WARNING, "wrong guest name specification: %s", v);
725 goto err;
726 }
727 else if (guest->lang.spec.patternGroup >= BACK_REFERENCE_COUNT)
728 {
729 error (WARNING, "wrong guest name specification (back reference count is too large): %d",
730 guest->lang.spec.patternGroup);
731 goto err;
732 }
733
734 *(char *)n_tmp = c;
735 if (*n_tmp != ',')
736 {
737 error (WARNING, "wrong guest specification (garbage at the end of end guest spec): %s", v);
738 goto err;
739 }
740
741 guest->lang.type = (*v == '\\')
742 ? GUEST_LANG_PTN_GROUP_FOR_LANGNAME
743 : GUEST_LANG_PTN_GROUP_FOR_FILEMAP;
744 }
745 else
746 {
747 guest->lang.spec.lang = getNamedLanguage (v, (tmp - v));
748 if (guest->lang.spec.lang == LANG_IGNORE)
749 {
750 error (WARNING, "no parser found for the guest spec: %s", v);
751 goto err;
752 }
753 guest->lang.type = GUEST_LANG_STATIC_LANGNAME;
754 }
755
756 tmp++;
757 if (*tmp == '\0')
758 {
759 error (WARNING, "no area spec found in the guest spec: %s", v);
760 goto err;
761 }
762
763 for (int i = 0; i < 2; i++)
764 {
765 current = guest->boundary + i;
766 const char *current_field_str = (i == BOUNDARY_START? "start": "end");
767
768 if (tmp [0] == ((i == BOUNDARY_START)? ',': '\0'))
769 {
770 if (type == REG_PARSER_MULTI_LINE)
771 error (WARNING,
772 "using placeholder for %s field is not allowed in multiline regex spec: %s",
773 current_field_str, v);
774
775 current->placeholder = true;
776 }
777 else
778 {
779 char *n = tmp;
780
781 for (; isdigit (*tmp); tmp++);
782 char c = *tmp;
783 *tmp = '\0';
784 if (!strToInt (n, 10, &(current->patternGroup)))
785 {
786 error (WARNING, "wrong guest area specification (patternGroup of %s, number expected): %s:%s",
787 current_field_str, v, n);
788 goto err;
789 }
790 *tmp = c;
791 if (*tmp == '\0')
792 {
793 error (WARNING, "wrong guest area specification (patternGroup of %s, nether start nor end given): %s",
794 current_field_str, v);
795 goto err;
796 }
797 else if (strncmp (tmp, "start", 5) == 0)
798 {
799 current->fromStartOfGroup = true;
800 tmp += 5;
801 }
802 else if (strncmp (tmp, "end", 3) == 0)
803 {
804 current->fromStartOfGroup = false;
805 tmp += 3;
806 }
807 else
808 {
809 error (WARNING, "wrong guest area specification (%s): %s",
810 current_field_str, v);
811 goto err;
812 }
813 }
814
815 if (i == 0)
816 {
817 if (*tmp != ',')
818 {
819 error (WARNING,
820 "wrong guest area specification (separator between start and end boundaries): %s", v);
821 goto err;
822 }
823 tmp++;
824 }
825 else if (i == 1 && (*tmp != '\0'))
826 {
827 error (WARNING, "wrong guest area specification (garbage at the end of end boundary spec): %s", v);
828 goto err;
829 }
830 }
831 return;
832 err:
833 guest->lang.type = GUEST_LANG_UNKNOWN;
834}
835
837 { '\0', "mgroup", NULL, pre_ptrn_flag_mgroup_long,
838 "N", "a group in pattern determining the line number of tag"},
839 { '\0', "_advanceTo", NULL, pre_ptrn_flag_advanceTo_long,
840 "N[start|end]", "a group in pattern from where the next scan starts [0end]"},
841};
842
844#define EXPERIMENTAL "_"
846 "PARSERSPEC,N0[start|end],N1[start|end]", "run guest parser on the area"},
847};
848
849static bool hasMessage(const regexPattern *const ptrn)
850{
851 return (ptrn->message.selection > 0 && ptrn->message.message_string);
852}
853
856 const struct lregexControlBlock *const lcb;
858};
859
860static void common_flag_msg_long (const char* const s, const char* const v, void* data)
861{
862 struct commonFlagData *cdata = data;
863 regexPattern *ptrn = cdata->ptrn;
864
865 Assert (ptrn);
866
867 if (hasMessage(ptrn))
868 {
869 error (WARNING, "only one message flag may be given per regex (already set to '%s')",
870 ptrn->message.message_string);
871 return;
872 }
873
874 if (strcmp (s, "fatal") == 0)
875 {
876 ptrn->message.selection = FATAL;
877 }
878 else if (strcmp (s, "warning") == 0)
879 {
880 ptrn->message.selection = WARNING;
881 }
882
883 Assert (ptrn->message.selection != 0);
884
885 if (!v || !*v)
886 {
887 error (WARNING, "no message value is given for {%s}", s);
888 return;
889 }
890
891 const char* begin = v;
892 const char* end = v + strlen (v);
893 --end;
894
895 if (*begin != '"' || *end != '"' || begin == end)
896 {
897 error (WARNING, "argument for {%s} must be in double-quotes", s);
898 return;
899 }
900
901 ++begin;
902
903 if (begin < end)
904 ptrn->message.message_string = eStrndup (begin, end - begin);
905}
906
907static void common_flag_extra_long (const char* const s, const char* const v, void* data)
908{
909 struct commonFlagData * cdata = data;
910
911 Assert (cdata->ptrn);
912
913 if (!v)
914 {
915 error (WARNING, "no value is given for: %s", s);
916 return;
917 }
918
919 cdata->ptrn->xtagType = getXtagTypeForNameAndLanguage (v, cdata->owner);
920 if (cdata->ptrn->xtagType == XTAG_UNKNOWN)
921 error (WARNING, "no such extra \"%s\" in %s", v, getLanguageName(cdata->owner));
922}
923
924
925static struct fieldPattern * fieldPatternNew (fieldType ftype, const char *template)
926{
927 struct fieldPattern *fp;
928
929 fp = xMalloc(1, struct fieldPattern);
930 fp->ftype = ftype;
931 fp->template = eStrdup(template);
932
933 return fp;
934}
935
936static void fieldPatternDelete (struct fieldPattern *fp)
937{
938 eFree ((void *)fp->template);
939 eFree (fp);
940}
941
942static void common_flag_field_long (const char* const s, const char* const v, void* data)
943{
944 struct commonFlagData * cdata = data;
945 regexPattern *ptrn = cdata->ptrn;
946
947 Assert (ptrn);
948
949 struct fieldPattern *fp;
950 fieldType ftype;
951 char *fname;
952 const char* template;
953 char *tmp;
954
955 if (!v)
956 {
957 error (WARNING, "no value is given for: %s", s);
958 return;
959 }
960
961 tmp = strchr (v, ':');
962 if (tmp == NULL || tmp == v)
963 {
964 error (WARNING, "no field name is given for: %s", s);
965 return;
966 }
967
968 fname = eStrndup (v, tmp - v);
969 ftype = getFieldTypeForNameAndLanguage (fname, cdata->owner);
970 if (ftype == FIELD_UNKNOWN)
971 {
972 error (WARNING, "no such field \"%s\" in %s", fname, getLanguageName(cdata->owner));
973 eFree (fname);
974 return;
975 }
976
977 if (ptrn->fieldPatterns)
978 {
979 for (unsigned int i = 0; i < ptrArrayCount(ptrn->fieldPatterns); i++)
980 {
981 fp = ptrArrayItem(ptrn->fieldPatterns, i);
982 if (fp->ftype == ftype)
983 {
984 error (WARNING, "duplicated field specification \"%s\" in %s", fname, getLanguageName(cdata->owner));
985 eFree (fname);
986 return;
987 }
988 }
989 }
990 eFree (fname);
991
992 template = tmp + 1;
993 fp = fieldPatternNew (ftype, template);
994
995 if (ptrn->fieldPatterns == NULL)
997 ptrArrayAdd(ptrn->fieldPatterns, fp);
998}
999
1000static void common_flag_role_long (const char* const s, const char* const v, void* data)
1001{
1002 struct commonFlagData * cdata = data;
1003 regexPattern *ptrn = cdata->ptrn;
1004 roleDefinition * role;
1005
1006 Assert (ptrn);
1007
1008 if (!v)
1009 {
1010 error (WARNING, "no value is given for: %s", s);
1011 return;
1012 }
1013
1014 role = getLanguageRoleForName(cdata->owner,
1015 ptrn->u.tag.kindIndex, v);
1016 if (!role)
1017 {
1018 error (WARNING, "no such role: %s", v);
1019 return;
1020 }
1021
1022 ptrn->u.tag.roleBits |= makeRoleBit(role->id);
1023}
1024
1025static void common_flag_anonymous_long (const char* const s, const char* const v, void* data)
1026{
1027 struct commonFlagData * cdata = data;
1028 regexPattern *ptrn = cdata->ptrn;
1029
1030 Assert (ptrn);
1031
1032 if (ptrn->anonymous_tag_prefix)
1033 {
1034 error (WARNING, "an anonymous tag prefix for this pattern (%s) is already given: %s",
1035 ptrn->pattern_string? ptrn->pattern_string: "",
1036 ptrn->anonymous_tag_prefix);
1037 return;
1038 }
1039
1040 if (!v)
1041 {
1042 error (WARNING, "no PREFIX for anonymous regex flag is given (pattern == %s)",
1043 ptrn->pattern_string? ptrn->pattern_string: "");
1044 return;
1045 }
1046
1047 if (ptrn->u.tag.kindIndex == KIND_GHOST_INDEX)
1048 {
1049 error (WARNING, "use \"%s\" regex flag only with an explicitly defined kind", s);
1050 return;
1051 }
1052
1053 ptrn->anonymous_tag_prefix = eStrdup (v);
1054}
1055
1057 { '\0', "fatal", NULL, common_flag_msg_long ,
1058 "\"MESSAGE\"", "print the given MESSAGE and exit"},
1059 { '\0', "warning", NULL, common_flag_msg_long ,
1060 "\"MESSAGE\"", "print the given MESSAGE at WARNING level"},
1061#define EXPERIMENTAL "_"
1062 { '\0', EXPERIMENTAL "extra", NULL, common_flag_extra_long ,
1063 "EXTRA", "record the tag only when the extra is enabled"},
1064 { '\0', EXPERIMENTAL "field", NULL, common_flag_field_long ,
1065 "FIELD:VALUE", "record the matched string(VALUE) to parser own FIELD of the tag"},
1066 { '\0', EXPERIMENTAL "role", NULL, common_flag_role_long,
1067 "ROLE", "set the given ROLE to the roles field"},
1068 { '\0', EXPERIMENTAL "anonymous", NULL, common_flag_anonymous_long,
1069 "PREFIX", "make an anonymous tag with PREFIX"},
1070};
1071
1072
1073static void pre_ptrn_flag_mtable_long (const char* const s, const char* const v, void* data)
1074{
1075 struct commonFlagData * cdata = data;
1076 regexPattern *ptrn = cdata->ptrn;
1077 struct mTableActionSpec *taction;
1078 bool taking_table = true;
1079
1080 Assert (ptrn);
1081 Assert (cdata->lcb);
1082
1083 taction = &ptrn->taction;
1084
1085 if (strcmp (s, "tenter") == 0)
1086 taction->action = TACTION_ENTER;
1087 else if (strcmp (s, "tleave") == 0)
1088 {
1089 taction->action = TACTION_LEAVE;
1090 taking_table = false;
1091 }
1092 else if (strcmp (s, "tjump") == 0)
1093 taction->action = TACTION_JUMP;
1094 else if (strcmp (s, "treset") == 0)
1095 taction->action = TACTION_RESET;
1096 else if (strcmp (s, "tquit") == 0)
1097 {
1098 taction->action = TACTION_QUIT;
1099 taking_table = false;
1100 }
1101
1102 if (taking_table)
1103 {
1104 int t;
1105 char *continuation = NULL;
1106
1107
1108 if (!v || (!*v))
1109 error (FATAL, "no table is given for table action: %s", s);
1110
1111 if (taction->action == TACTION_ENTER
1112 && (continuation = strchr (v, ',')))
1113 {
1114 char *tableEnterTo;
1115
1116 tableEnterTo = eStrndup (v, continuation - v);
1117 t = getTableIndexForName (cdata->lcb, tableEnterTo);
1118 if (t < 0)
1119 error (FATAL, "table is not defined: %s", tableEnterTo);
1120 taction->table = ptrArrayItem (cdata->lcb->tables, t);
1121 eFree (tableEnterTo);
1122
1123 if (!*(continuation + 1))
1124 error (FATAL, "no continuation table is given for: %s", v);
1125
1126 int t_cont = getTableIndexForName (cdata->lcb, continuation + 1);
1127 if (t_cont < 0)
1128 error (FATAL, "table for continuation is not defined: %s", continuation + 1);
1129 taction->continuation_table = ptrArrayItem (cdata->lcb->tables, t_cont);
1130 }
1131 else
1132 {
1133 t = getTableIndexForName (cdata->lcb, v);
1134 if (t < 0)
1135 error (FATAL, "table is not defined: %s", v);
1136 taction->table = ptrArrayItem (cdata->lcb->tables, t);
1137 taction->continuation_table = NULL;
1138 }
1139 }
1140}
1141
1143 { '\0', "tenter", NULL, pre_ptrn_flag_mtable_long ,
1144 "TABLE[,CONT]", "enter to given regext table (with specifying continuation)"},
1145 { '\0', "tleave", NULL, pre_ptrn_flag_mtable_long ,
1146 NULL, "leave from the current regext table"},
1147 { '\0', "tjump", NULL, pre_ptrn_flag_mtable_long ,
1148 "TABLE", "jump to another regext table(don't push the current table to state stack)"},
1149 { '\0', "treset", NULL, pre_ptrn_flag_mtable_long ,
1150 "TABLE", "clear the state stack and jump to given regex table"},
1151 { '\0', "tquit", NULL, pre_ptrn_flag_mtable_long ,
1152 NULL, "stop the parsing with this parser"},
1153};
1154
1155
1156static void setKind(regexPattern * ptrn, const langType owner,
1157 const char kindLetter, const char* kindName,
1158 const char *const description,
1159 bool kind_explicitly_defined)
1160{
1161 Assert (ptrn);
1162 Assert (ptrn->u.tag.name_pattern);
1163 Assert (kindName);
1164 kindDefinition *kdef = getLanguageKindForLetter (owner, kindLetter);
1165
1166 if (kdef)
1167 {
1168 if (strcmp (kdef->name, kindName) && (strcmp(kindName, KIND_REGEX_DEFAULT_NAME)))
1169 /* When using a same kind letter for multiple regex patterns, the name of kind
1170 should be the same. */
1171 error (WARNING, "Don't reuse the kind letter `%c' in a language %s (old: \"%s\", new: \"%s\")",
1172 kdef->letter, getLanguageName (owner),
1173 kdef->name, kindName);
1174 ptrn->u.tag.kindIndex = kdef->id;
1175 }
1176 else if (*ptrn->u.tag.name_pattern == '\0' &&
1177 kindLetter == KIND_REGEX_DEFAULT_LETTER &&
1178 (strcmp(kindName, KIND_REGEX_DEFAULT_NAME) == 0) &&
1179 (!kind_explicitly_defined))
1181 else
1182 {
1183 kdef = kindNew (kindLetter, kindName, description);
1184 defineLanguageKind (owner, kdef, kindFree);
1185 ptrn->u.tag.kindIndex = kdef->id;
1186 }
1187}
1188
1189static void patternEvalFlags (struct lregexControlBlock *lcb,
1190 regexPattern * ptrn,
1191 enum regexParserType regptype,
1192 const char* flags)
1193{
1195 .owner = lcb->owner,
1196 .lcb = lcb,
1197 .ptrn = ptrn
1198 };
1199
1200 if (regptype == REG_PARSER_SINGLE_LINE)
1202
1204
1205 if (regptype == REG_PARSER_SINGLE_LINE || regptype == REG_PARSER_MULTI_TABLE)
1207
1208 if (regptype == REG_PARSER_MULTI_LINE || regptype == REG_PARSER_MULTI_TABLE)
1209 {
1210 ptrn->mgroup.forNextScanning = 0;
1211 /* ptrn->mgroup.nextFromStart is initialized in initMgroup() already. */
1213 }
1214
1216 .type = regptype,
1217 .guest = &ptrn->guest,
1218 };
1220
1221 if (regptype == REG_PARSER_MULTI_TABLE)
1223}
1224
1226 int table_index,
1227 enum regexParserType regptype, regex_t* const pattern,
1228 const char* const name, char kindLetter, const char* kindName,
1229 char *const description, const char* flags,
1230 bool kind_explicitly_defined,
1231 bool *disabled)
1232{
1233 regexPattern * ptrn = addCompiledTagCommon(lcb, table_index, pattern, regptype);
1234
1235 ptrn->type = PTRN_TAG;
1236 ptrn->u.tag.name_pattern = eStrdup (name);
1237 ptrn->disabled = disabled;
1238
1239 setKind(ptrn, lcb->owner, kindLetter, kindName, description, kind_explicitly_defined);
1240 patternEvalFlags (lcb, ptrn, regptype, flags);
1241
1242 return ptrn;
1243}
1244
1246 const regexCallback callback, const char* flags,
1247 bool *disabled,
1248 void *userData)
1249{
1250 regexPattern * ptrn;
1251 bool exclusive = false;
1252 flagsEval (flags, prePtrnFlagDef, ARRAY_SIZE(prePtrnFlagDef), &exclusive);
1254 ptrn->type = PTRN_CALLBACK;
1255 ptrn->u.callback.function = callback;
1256 ptrn->u.callback.userData = userData;
1257 ptrn->exclusive = exclusive;
1258 ptrn->disabled = disabled;
1259 return ptrn;
1260}
1261
1262
1263static void regex_flag_basic_short (char c CTAGS_ATTR_UNUSED, void* data)
1264{
1265 int* cflags = data;
1266 *cflags &= ~REG_EXTENDED;
1267}
1268
1269static void regex_flag_basic_long (const char* const s CTAGS_ATTR_UNUSED, const char* const unused CTAGS_ATTR_UNUSED, void* data)
1270{
1271 regex_flag_basic_short ('b', data);
1272}
1273
1274static void regex_flag_extend_short (char c CTAGS_ATTR_UNUSED, void* data)
1275{
1276 int* cflags = data;
1277 *cflags |= REG_EXTENDED;
1278}
1279
1280static void regex_flag_extend_long (const char* const c CTAGS_ATTR_UNUSED, const char* const unused CTAGS_ATTR_UNUSED, void* data)
1281{
1282 regex_flag_extend_short('e', data);
1283}
1284
1285static void regex_flag_icase_short (char c CTAGS_ATTR_UNUSED, void* data)
1286{
1287 int* cflags = data;
1288 *cflags |= REG_ICASE;
1289}
1290
1291static void regex_flag_icase_long (const char* s CTAGS_ATTR_UNUSED, const char* const unused CTAGS_ATTR_UNUSED, void* data)
1292{
1293 regex_flag_icase_short ('i', data);
1294}
1295
1296
1299 NULL, "interpreted as a Posix basic regular expression."},
1301 NULL, "interpreted as a Posix extended regular expression (default)"},
1303 NULL, "applied in a case-insensitive manner"},
1304};
1305
1306static regex_t* compileRegex (enum regexParserType regptype,
1307 const char* const regexp, const char* const flags)
1308{
1309 int cflags = REG_EXTENDED | REG_NEWLINE;
1310
1311 if (regptype == REG_PARSER_MULTI_TABLE)
1312 cflags &= ~REG_NEWLINE;
1313
1314 regex_t *result;
1315 int errcode;
1316
1317 flagsEval (flags,
1320 &cflags);
1321
1322 result = xMalloc (1, regex_t);
1323 errcode = regcomp (result, regexp, cflags);
1324 if (errcode != 0)
1325 {
1326 char errmsg[256];
1327 regerror (errcode, result, errmsg, 256);
1328 error (WARNING, "regcomp %s: %s", regexp, errmsg);
1329 regfree (result);
1330 eFree (result);
1331 result = NULL;
1332 }
1333 return result;
1334}
1335
1336
1337/* If a letter and/or a name are defined in kindSpec, return true. */
1338static bool parseKinds (
1339 const char* const kindSpec, char* const kindLetter, char** const kindName,
1340 char **description)
1341{
1342 *description = NULL;
1343
1344 if (kindSpec == NULL || kindSpec [0] == '\0')
1345 {
1346 *kindLetter = KIND_REGEX_DEFAULT_LETTER;
1347 *kindName = eStrdup (KIND_REGEX_DEFAULT_NAME);
1348 return false;
1349 }
1350 else
1351 {
1352 bool explicitly_defined = false;
1353 const char* k = kindSpec;
1354
1355 if (k [0] != ',' && (k [1] == ',' || k [1] == '\0'))
1356 {
1357 *kindLetter = *k++;
1358 explicitly_defined = true;
1359 }
1360 else
1361 *kindLetter = KIND_REGEX_DEFAULT_LETTER;
1362
1363 if (*k == ',')
1364 ++k;
1365
1366 if (k [0] == '\0')
1367 *kindName = eStrdup (KIND_REGEX_DEFAULT_NAME);
1368 else
1369 {
1370 const char *const comma = strchr (k, ',');
1371
1372 if (comma == NULL)
1373 {
1374 if (strlen (k) == 0)
1375 *kindName = eStrdup (KIND_REGEX_DEFAULT_NAME);
1376 else
1377 {
1378 *kindName = eStrdup (k);
1379 explicitly_defined = true;
1380 }
1381 }
1382 else
1383 {
1384 if (comma - k == 0)
1385 *kindName = eStrdup (KIND_REGEX_DEFAULT_NAME);
1386 else
1387 {
1388 *kindName = eStrndup (k, comma - k );
1389 explicitly_defined = true;
1390 }
1391 k = comma + 1;
1392 if (k [0] != '\0')
1393 *description = eStrdup (k);
1394 }
1395 }
1396 return explicitly_defined;
1397 }
1398}
1399
1400/*
1401* Regex pattern matching
1402*/
1403
1404
1406 const char* const in, const char* out,
1407 const int nmatch, const regmatch_t* const pmatch)
1408{
1409 vString* result = vStringNew ();
1410 const char* p;
1411 for (p = out ; *p != '\0' ; p++)
1412 {
1413 if (*p == '\\' && isdigit ((int) *++p))
1414 {
1415 const int dig = *p - '0';
1416 if (0 < dig && dig < nmatch && pmatch [dig].rm_so != -1)
1417 {
1418 const int diglen = pmatch [dig].rm_eo - pmatch [dig].rm_so;
1419 vStringNCatS (result, in + pmatch [dig].rm_so, diglen);
1420 }
1421 }
1422 else if (*p != '\n' && *p != '\r')
1423 vStringPut (result, *p);
1424 }
1425 return result;
1426}
1427
1428static unsigned long getInputLineNumberInRegPType (enum regexParserType regptype,
1429 off_t offset)
1430{
1431 return (regptype == REG_PARSER_MULTI_LINE || regptype == REG_PARSER_MULTI_TABLE)
1433 : getInputLineNumber ();
1434}
1435
1436static void fillEndLineFieldOfUpperScopes (struct lregexControlBlock *lcb, unsigned long endline)
1437{
1439 int n = lcb->currentScope;
1440
1441 while ((entry = getEntryInCorkQueue (n))
1442 && (entry->extensionFields.endLine == 0))
1443 {
1444 entry->extensionFields.endLine = endline;
1445 n = entry->extensionFields.scopeIndex;
1446 }
1447}
1448
1449static void matchTagPattern (struct lregexControlBlock *lcb,
1450 const char* line,
1451 const regexPattern* const patbuf,
1452 const regmatch_t* const pmatch,
1453 off_t offset)
1454{
1455 vString *const name =
1456 (patbuf->u.tag.name_pattern[0] != '\0') ? substitute (line,
1457 patbuf->u.tag.name_pattern,
1458 BACK_REFERENCE_COUNT, pmatch):
1460 patbuf->u.tag.kindIndex):
1461 vStringNewInit ("");
1462 bool placeholder = !!((patbuf->scopeActions & SCOPE_PLACEHOLDER) == SCOPE_PLACEHOLDER);
1463 int scope = CORK_NIL;
1464 int n;
1465
1468
1469 if (patbuf->scopeActions & SCOPE_REF)
1470 {
1472
1473 scope = lcb->currentScope;
1474 while ((entry = getEntryInCorkQueue (scope)) && entry->placeholder)
1475 /* Look at parent */
1476 scope = entry->extensionFields.scopeIndex;
1477 }
1478 if (patbuf->scopeActions & SCOPE_CLEAR)
1479 {
1480 unsigned long endline = getInputLineNumberInRegPType(patbuf->regptype, offset);
1481 fillEndLineFieldOfUpperScopes (lcb, endline);
1482 lcb->currentScope = CORK_NIL;
1483 }
1484 if (patbuf->scopeActions & SCOPE_POP)
1485 {
1487
1488 if (entry && (entry->extensionFields.endLine == 0))
1489 entry->extensionFields.endLine = getInputLineNumberInRegPType(patbuf->regptype, offset);
1490
1491 lcb->currentScope = entry? entry->extensionFields.scopeIndex: CORK_NIL;
1492 }
1493
1494 if (vStringLength (name) == 0 && (placeholder == false))
1495 {
1496 if (patbuf->accept_empty_name == false)
1497 error (WARNING, "%s:%lu: null expansion of name pattern \"%s\"",
1499 getInputLineNumberInRegPType(patbuf->regptype, offset),
1500 patbuf->u.tag.name_pattern);
1501 n = CORK_NIL;
1502 }
1503 else
1504 {
1505 static TrashBox* field_trashbox;
1506 unsigned long ln = 0;
1507 MIOPos pos;
1508 tagEntryInfo e;
1509 int kind;
1510 roleBitsType roleBits;
1511
1512 if ((patbuf->regptype == REG_PARSER_MULTI_LINE)
1513 || (patbuf->regptype == REG_PARSER_MULTI_TABLE))
1514 {
1515 ln = getInputLineNumberForFileOffset (offset);
1517 }
1518
1519 n = CORK_NIL;
1520 kind = patbuf->u.tag.kindIndex;
1521 roleBits = patbuf->u.tag.roleBits;
1522
1523 initRegexTag (&e, name, kind, ROLE_DEFINITION_INDEX, scope, placeholder,
1524 ln, ln == 0? NULL: &pos, patbuf->xtagType);
1525
1526 if (field_trashbox == NULL)
1527 {
1528 field_trashbox = trashBoxNew();
1529 DEFAULT_TRASH_BOX (field_trashbox, trashBoxDelete);
1530 }
1531
1532 if (patbuf->fieldPatterns)
1533 {
1534 for (unsigned int i = 0; i < ptrArrayCount(patbuf->fieldPatterns); i++)
1535 {
1536 struct fieldPattern *fp = ptrArrayItem(patbuf->fieldPatterns, i);
1537 if (isFieldEnabled (fp->ftype))
1538 {
1539 vString * const value = substitute (line, fp->template,
1540 BACK_REFERENCE_COUNT, pmatch);
1541 attachParserField (&e, false, fp->ftype, vStringValue (value));
1542 trashBoxPut (field_trashbox, value,
1544 }
1545 }
1546 }
1547
1548 if (roleBits)
1549 {
1550 unsigned int roleIndex;
1551
1552 for (roleIndex = 0;
1553 roleIndex < countLanguageRoles(e.langType, kind);
1554 roleIndex++)
1555 {
1556 if (roleBits & makeRoleBit(roleIndex))
1557 assignRole (&e, roleIndex);
1558 }
1559 }
1560
1561 if (patbuf->anonymous_tag_prefix)
1563
1564 n = makeTagEntry (&e);
1565
1566 trashBoxMakeEmpty(field_trashbox);
1567 }
1568
1569 if (patbuf->scopeActions & SCOPE_PUSH)
1570 lcb->currentScope = n;
1571
1573}
1574
1576 const vString* const line, const regexPattern* const patbuf,
1577 const regmatch_t* const pmatch)
1578{
1580 unsigned int count = 0;
1581 int i;
1582 for (i = 0 ; i < BACK_REFERENCE_COUNT ; ++i)
1583 {
1584 matches [i].start = pmatch [i].rm_so;
1585 matches [i].length = pmatch [i].rm_eo - pmatch [i].rm_so;
1586 /* a valid match may have both offsets == -1,
1587 * e.g. (foo)*(bar) matching "bar" - see CTags bug 271.
1588 * As POSIX regex doesn't seem to have a way to count matches,
1589 * we return the count up to the last non-empty match. */
1590 if (pmatch [i].rm_so != -1)
1591 count = i + 1;
1592 }
1593 return patbuf->u.callback.function (vStringValue (line), matches, count,
1594 patbuf->u.callback.userData);
1595}
1596
1597
1598static void printMessage(const langType language,
1599 const regexPattern *const ptrn,
1600 const off_t offset,
1601 const char *const line,
1602 const regmatch_t* const pmatch)
1603{
1604 vString *msg;
1605
1606 Assert (ptrn);
1607 Assert (ptrn->message.selection > 0);
1609
1611
1612 error (ptrn->message.selection, "%sMessage from regex<%s>: %s (%s:%lu)",
1613 (ptrn->message.selection == FATAL ? "Fatal: " : ""),
1614 getLanguageName (language),
1615 vStringValue (msg),
1617 getInputLineNumberInRegPType (ptrn->regptype, offset));
1618
1619 vStringDelete (msg);
1620}
1621
1622static bool isGuestRequestConsistent (struct guestRequest *guest_req)
1623{
1624 return (guest_req->lang != LANG_IGNORE)
1625 && (guest_req->boundary[BOUNDARY_START].offset < guest_req->boundary[BOUNDARY_END].offset);
1626}
1627
1628static bool fillGuestRequest (const char *start,
1629 const char *current,
1631 struct guestSpec *guest_spec,
1632 struct guestRequest *guest_req)
1633{
1634 if (guest_spec->lang.type == GUEST_LANG_UNKNOWN)
1635 return false;
1636 else if (guest_spec->lang.type == GUEST_LANG_PLACEHOLDER)
1637 ;
1638 else if (guest_spec->lang.type == GUEST_LANG_STATIC_LANGNAME)
1639 {
1640 guest_req->lang = guest_spec->lang.spec.lang;
1641 guest_req->lang_set = true;
1642 }
1643 else if (guest_spec->lang.type == GUEST_LANG_PTN_GROUP_FOR_LANGNAME)
1644 {
1645 const char * name = current + pmatch [guest_spec->lang.spec.patternGroup].rm_so;
1646 int size = pmatch [guest_spec->lang.spec.patternGroup].rm_eo
1647 - pmatch [guest_spec->lang.spec.patternGroup].rm_so;
1648 if (size > 0)
1649 {
1650 guest_req->lang = getNamedLanguage (name, size);
1651 guest_req->lang_set = true;
1652 }
1653 }
1654 else if (guest_spec->lang.type == GUEST_LANG_PTN_GROUP_FOR_FILEMAP)
1655 {
1656 const char * name = current + pmatch [guest_spec->lang.spec.patternGroup].rm_so;
1657 int size = pmatch [guest_spec->lang.spec.patternGroup].rm_eo
1658 - pmatch [guest_spec->lang.spec.patternGroup].rm_so;
1659 char *fname = (size > 0)? eStrndup (name, size): NULL;
1660
1661 if (fname)
1662 {
1663 guest_req->lang = getLanguageForFilename (fname, LANG_AUTO);
1664 guest_req->lang_set = true;
1665 eFree (fname);
1666 }
1667 }
1668
1669 for (int i = 0; i < 2; i++)
1670 {
1671 struct boundarySpec *boundary_spec = guest_spec->boundary + i;
1672 struct boundaryInRequest *boundary = guest_req->boundary + i;
1673 if (!boundary_spec->placeholder)
1674 {
1675 boundary->offset = current - start + (boundary_spec->fromStartOfGroup
1676 ? pmatch [boundary_spec->patternGroup].rm_so
1677 : pmatch [boundary_spec->patternGroup].rm_eo);
1678 boundary->offset_set = true;
1679 }
1680 }
1681 return guestRequestIsFilled (guest_req);
1682}
1683
1684static bool matchRegexPattern (struct lregexControlBlock *lcb,
1685 const vString* const line,
1687{
1688 bool result = false;
1690 int match;
1691 regexPattern* patbuf = entry->pattern;
1692 struct guestSpec *guest = &patbuf->guest;
1693
1694 if (patbuf->disabled && *(patbuf->disabled))
1695 return false;
1696
1697 match = regexec (patbuf->pattern, vStringValue (line),
1698 BACK_REFERENCE_COUNT, pmatch, 0);
1699 if (match == 0)
1700 {
1701 result = true;
1702 entry->statistics.match++;
1703
1704 if (hasMessage(patbuf))
1705 printMessage(lcb->owner, patbuf, 0, vStringValue (line), pmatch);
1706
1707 if (patbuf->type == PTRN_TAG)
1708 {
1709 matchTagPattern (lcb, vStringValue (line), patbuf, pmatch, 0);
1710
1711 if (guest->lang.type != GUEST_LANG_UNKNOWN)
1712 {
1713 unsigned long ln = getInputLineNumber ();
1714 long current = getInputFileOffsetForLine (ln);
1715 if (fillGuestRequest (vStringValue (line) - current,
1716 vStringValue (line), pmatch, guest, lcb->guest_req))
1717 {
1718 Assert (lcb->guest_req->lang != LANG_AUTO);
1722 }
1723 }
1724 }
1725 else if (patbuf->type == PTRN_CALLBACK)
1726 result = matchCallbackPattern (line, patbuf, pmatch);
1727 else
1728 {
1729 Assert ("invalid pattern type" == NULL);
1730 result = false;
1731 }
1732 }
1733 else
1734 entry->statistics.unmatch++;
1735 return result;
1736}
1737
1739 const vString* const allLines,
1741{
1742 const char *start;
1743 const char *current;
1744 off_t offset = 0;
1745 regexPattern* patbuf = entry->pattern;
1746 struct mGroupSpec *mgroup = &patbuf->mgroup;
1747 struct guestSpec *guest = &patbuf->guest;
1748
1749 bool result = false;
1751 int match = 0;
1752 unsigned int delta = 1;
1753
1754 Assert (patbuf);
1755
1756 if (patbuf->disabled && *(patbuf->disabled))
1757 return false;
1758
1759 current = start = vStringValue (allLines);
1760 do
1761 {
1762 match = regexec (patbuf->pattern, current,
1763 BACK_REFERENCE_COUNT, pmatch, 0);
1764 if (match != 0)
1765 {
1766 entry->statistics.unmatch++;
1767 break;
1768 }
1769
1770 if (hasMessage(patbuf))
1771 printMessage(lcb->owner, patbuf, (current + pmatch[0].rm_so) - start, current, pmatch);
1772
1773 offset = (current + pmatch [mgroup->forLineNumberDetermination].rm_so)
1774 - start;
1775
1776 entry->statistics.match++;
1777 if (patbuf->type == PTRN_TAG)
1778 {
1779 matchTagPattern (lcb, current, patbuf, pmatch, offset);
1780 result = true;
1781 }
1782 else if (patbuf->type == PTRN_CALLBACK)
1783 ; /* Not implemented yet */
1784 else
1785 {
1786 Assert ("invalid pattern type" == NULL);
1787 result = false;
1788 break;
1789 }
1790
1791 if (fillGuestRequest (start, current, pmatch, guest, lcb->guest_req))
1792 {
1793 Assert (lcb->guest_req->lang != LANG_AUTO);
1797 }
1798
1799 delta = (mgroup->nextFromStart
1800 ? pmatch [mgroup->forNextScanning].rm_so
1801 : pmatch [mgroup->forNextScanning].rm_eo);
1802 if (delta == 0)
1803 {
1804 unsigned int pos = current - start;
1805 error (WARNING,
1806 "a multi line regex pattern doesn't advance the input cursor: %s",
1807 patbuf->pattern_string);
1808 error (WARNING, "Language: %s, input file: %s, pos: %u",
1810 break;
1811 }
1812 current += delta;
1813
1814 } while (current < start + vStringLength (allLines));
1815
1816 return result;
1817}
1818
1819/* PUBLIC INTERFACE */
1820
1821/* Match against all patterns for specified language. Returns true if at least
1822 * on pattern matched.
1823 */
1824extern bool matchRegex (struct lregexControlBlock *lcb, const vString* const line)
1825{
1826 bool result = false;
1827 unsigned int i;
1828 for (i = 0 ; i < ptrArrayCount(lcb->entries[REG_PARSER_SINGLE_LINE]) ; ++i)
1829 {
1831 regexPattern *ptrn = entry->pattern;
1832
1833 Assert (ptrn);
1834
1835 if ((ptrn->xtagType != XTAG_UNKNOWN)
1836 && (!isXtagEnabled (ptrn->xtagType)))
1837 continue;
1838
1839 if (matchRegexPattern (lcb, line, entry))
1840 {
1841 result = true;
1842 if (ptrn->exclusive)
1843 break;
1844 }
1845 }
1846 return result;
1847}
1848
1850{
1851 lcb->currentScope = CORK_NIL;
1852
1853 ptrArrayClear (lcb->tstack);
1855}
1856
1858{
1859 unsigned long endline = getInputLineNumber ();
1860 fillEndLineFieldOfUpperScopes (lcb, endline);
1861}
1862
1863extern void findRegexTagsMainloop (int (* driver)(void))
1864{
1865 /* merely read all lines of the file */
1866 while (driver () != EOF)
1867 ;
1868}
1869
1870static int fileReadLineDriver(void)
1871{
1872 return (readLineFromInputFile () == NULL)? EOF: 1;
1873}
1874
1875extern void findRegexTags (void)
1876{
1878}
1879
1881{
1882 for (unsigned int i = 0; i < ptrArrayCount(entries); i++)
1883 {
1885 Assert (entry && entry->pattern);
1886 if (entry->pattern->scopeActions)
1887 return true;
1888 }
1889 return false;
1890}
1891
1893{
1895
1898 return true;
1899
1900 for (unsigned int i = 0; i < ptrArrayCount(lcb->tables); i++)
1901 {
1902 struct regexTable *table = ptrArrayItem(lcb->tables, i);
1903 if (hasScopeActionInRegex0 (table->entries))
1904 return true;
1905 }
1906
1907 return false;
1908}
1909
1910static char *escapeRegexPattern (const char* pattern)
1911{
1912 vString *p = vStringNew ();
1913
1914 while (*pattern != '\0')
1915 {
1916 char c = *pattern;
1917 if (c == '\n')
1918 vStringCatS(p, "\\n");
1919 else if (c == '\t')
1920 vStringCatS(p, "\\t");
1921 else if (c == '\\')
1922 vStringCatS(p, "\\\\");
1923 else
1924 vStringPut(p, c);
1925
1926 pattern++;
1927 }
1928
1929 return vStringDeleteUnwrap (p);
1930}
1931
1933 int table_index,
1934 enum regexParserType regptype,
1935 const char* const regex,
1936 const char* const name,
1937 const char* const kinds,
1938 const char* const flags,
1939 bool *disabled)
1940{
1941 Assert (regex != NULL);
1942 Assert (name != NULL);
1943
1944 if (!regexAvailable)
1945 return NULL;
1946
1947 regex_t* const cp = compileRegex (regptype, regex, flags);
1948 if (cp == NULL)
1949 return NULL;
1950
1951 char kindLetter;
1952 char* kindName;
1953 char* description;
1954 kindDefinition* fileKind;
1955
1956 bool explictly_defined = parseKinds (kinds, &kindLetter, &kindName, &description);
1957 fileKind = getLanguageKind (lcb->owner, KIND_FILE_INDEX);
1958 if (kindLetter == fileKind->letter)
1959 error (FATAL,
1960 "Kind letter \'%c\' used in regex definition \"%s\" of %s language is reserved in ctags main",
1961 kindLetter,
1962 regex,
1963 getLanguageName (lcb->owner));
1964 else if (!isalpha ((unsigned char)kindLetter))
1965 error (FATAL,
1966 "Kind letter must be an alphabetical character: \"%c\"",
1967 kindLetter);
1968
1969 if (strcmp (kindName, fileKind->name) == 0)
1970 error (FATAL,
1971 "Kind name \"%s\" used in regex definition \"%s\" of %s language is reserved in ctags main",
1972 kindName,
1973 regex,
1974 getLanguageName (lcb->owner));
1975
1976 const char *option_bsae = (regptype == REG_PARSER_SINGLE_LINE? "regex" :
1977 regptype == REG_PARSER_MULTI_LINE ? "mline-regex" :
1978 regptype == REG_PARSER_MULTI_TABLE? "_mtable-regex":
1979 NULL);
1980 Assert (option_bsae);
1981
1982 for (const char * p = kindName; *p; p++)
1983 {
1984 if (p == kindName)
1985 {
1986 if (!isalpha(*p))
1987 error (FATAL,
1988 "A kind name doesn't start with an alphabetical character: "
1989 "'%s' in \"--%s-%s\" option",
1990 kindName,
1991 option_bsae,
1992 getLanguageName (lcb->owner));
1993 }
1994 else
1995 {
1996 /*
1997 * People may object to this error.
1998 * Searching github repositories, I found not a few .ctags files
1999 * in which Exuberant-ctags users define kind names with whitespaces.
2000 * "FATAL" error breaks the compatibility.
2001 */
2002 if (!isalnum(*p))
2003 error (/* regptype == REG_PARSER_SINGLE_LINE? WARNING: */ FATAL,
2004 "Non-alphanumeric char is used in kind name: "
2005 "'%s' in \"--%s-%s\" option",
2006 kindName,
2007 option_bsae,
2008 getLanguageName (lcb->owner));
2009
2010 }
2011 }
2012
2013 regexPattern *rptr = addCompiledTagPattern (lcb, table_index,
2014 regptype, cp, name,
2015 kindLetter, kindName, description, flags,
2016 explictly_defined,
2017 disabled);
2018 rptr->pattern_string = escapeRegexPattern(regex);
2019
2020 eFree (kindName);
2021 if (description)
2022 eFree (description);
2023
2024 if (*name == '\0')
2025 {
2026 if (rptr->exclusive || rptr->scopeActions & SCOPE_PLACEHOLDER
2027 || rptr->anonymous_tag_prefix
2028 || regptype == REG_PARSER_MULTI_TABLE
2029 || rptr->guest.lang.type != GUEST_LANG_UNKNOWN
2030 )
2031 rptr->accept_empty_name = true;
2032 else
2033 error (WARNING, "%s: regexp missing name pattern", regex);
2034 }
2035
2036 return rptr;
2037}
2038
2039extern void addTagRegex (struct lregexControlBlock *lcb,
2040 const char* const regex,
2041 const char* const name,
2042 const char* const kinds,
2043 const char* const flags,
2044 bool *disabled)
2045{
2047 REG_PARSER_SINGLE_LINE, regex, name, kinds, flags, disabled);
2048}
2049
2050extern void addTagMultiLineRegex (struct lregexControlBlock *lcb, const char* const regex,
2051 const char* const name, const char* const kinds, const char* const flags,
2052 bool *disabled)
2053{
2055 REG_PARSER_MULTI_LINE, regex, name, kinds, flags, disabled);
2056}
2057
2059 const char* const table_name,
2060 const char* const regex,
2061 const char* const name, const char* const kinds, const char* const flags,
2062 bool *disabled)
2063{
2064 int table_index = getTableIndexForName (lcb, table_name);
2065
2066 if (table_index < 0)
2067 error (FATAL, "unknown table name: %s", table_name);
2068
2069 addTagRegexInternal (lcb, table_index, REG_PARSER_MULTI_TABLE, regex, name, kinds, flags,
2070 disabled);
2071}
2072
2073extern void addCallbackRegex (struct lregexControlBlock *lcb,
2074 const char* const regex,
2075 const char* const flags,
2076 const regexCallback callback,
2077 bool *disabled,
2078 void * userData)
2079{
2080 Assert (regex != NULL);
2081
2082 if (!regexAvailable)
2083 return;
2084
2085
2086 regex_t* const cp = compileRegex (REG_PARSER_SINGLE_LINE, regex, flags);
2087 if (cp != NULL)
2088 {
2089 regexPattern *rptr = addCompiledCallbackPattern (lcb, cp, callback, flags,
2090 disabled, userData);
2091 rptr->pattern_string = escapeRegexPattern(regex);
2092 }
2093}
2094
2095static void addTagRegexOption (struct lregexControlBlock *lcb,
2096 enum regexParserType regptype,
2097 const char* const pattern)
2098{
2099 if (!regexAvailable)
2100 return;
2101
2102 int table_index = TABLE_INDEX_UNUSED;
2103 char * regex_pat = NULL;
2104 char *name, *kinds, *flags;
2105
2106
2107 if (regptype == REG_PARSER_MULTI_TABLE)
2108 {
2109 const char *c;
2110 for (c = pattern; *c; c++)
2111 {
2112 if (! (isalnum(*c) || *c == '_'))
2113 {
2114 if (*c && (*(c + 1) != '^'))
2115 {
2116 vString *tmp = vStringNew ();
2117
2118 /* Put '^' as prefix for the pattern */
2119 vStringPut(tmp, *c);
2120 vStringPut(tmp, '^');
2121 vStringCatS(tmp, c + 1);
2122 regex_pat = vStringDeleteUnwrap(tmp);
2123 }
2124 else
2125 regex_pat = eStrdup (c);
2126 break;
2127 }
2128 }
2129
2130 if (regex_pat == NULL || *regex_pat == '\0')
2131 error (FATAL, "wrong mtable pattern specification: %s", pattern);
2132
2133 char *table_name = eStrndup(pattern, c - pattern);
2134 table_index = getTableIndexForName (lcb, table_name);
2135 if (table_index < 0)
2136 error (FATAL, "unknown table name: %s (in %s)", table_name, pattern);
2137 eFree(table_name);
2138 }
2139 else
2140 regex_pat = eStrdup (pattern);
2141
2142 if (parseTagRegex (regptype, regex_pat, &name, &kinds, &flags))
2143 addTagRegexInternal (lcb, table_index, regptype, regex_pat, name, kinds, flags,
2144 NULL);
2145
2146 eFree (regex_pat);
2147}
2148
2150 enum regexParserType regptype,
2151 const char* const parameter)
2152{
2153 if (parameter == NULL || parameter [0] == '\0')
2154 clearPatternSet (lcb);
2155 else if (parameter [0] != '@')
2156 addTagRegexOption (lcb, regptype, parameter);
2157 else if (! doesFileExist (parameter + 1))
2158 error (WARNING, "cannot open regex file");
2159 else
2160 {
2161 const char* regexfile = parameter + 1;
2162
2163 verbose ("open a regex file: %s\n", regexfile);
2164 MIO* const mio = mio_new_file (regexfile, "r");
2165 if (mio == NULL)
2166 error (WARNING | PERROR, "%s", regexfile);
2167 else
2168 {
2169 vString* const regex = vStringNew ();
2170 while (readLineRaw (regex, mio))
2171 {
2172 if (vStringLength (regex) > 1 && vStringValue (regex)[0] != '\n')
2173 addTagRegexOption (lcb, regptype, vStringValue (regex));
2174 }
2175 mio_unref (mio);
2176 vStringDelete (regex);
2177 }
2178 }
2179}
2180
2181/*
2182* Regex option parsing
2183*/
2184
2185extern void printRegexFlags (bool withListHeader, bool machinable, FILE *fp)
2186{
2187 struct colprintTable * table;
2188
2189 table = flagsColprintTableNew ();
2190
2196
2197 flagsColprintTablePrint (table, withListHeader, machinable, fp);
2198 colprintTableDelete(table);
2199}
2200
2201extern void printMultilineRegexFlags (bool withListHeader, bool machinable, FILE *fp)
2202{
2203 struct colprintTable * table;
2204
2205 table = flagsColprintTableNew ();
2206
2211
2212 flagsColprintTablePrint (table, withListHeader, machinable, fp);
2213 colprintTableDelete(table);
2214}
2215
2216extern void printMultitableRegexFlags (bool withListHeader, bool machinable, FILE *fp)
2217{
2218 struct colprintTable * table;
2219
2220 table = flagsColprintTableNew ();
2221
2228
2229 flagsColprintTablePrint (table, withListHeader, machinable, fp);
2230 colprintTableDelete(table);
2231}
2232
2233extern void freeRegexResources (void)
2234{
2235 /* TODO: SHOULD BE REMOVED */
2236}
2237
2239{
2241 return true;
2242 else if (ptrArrayCount(lcb->tables) > 0)
2243 return true;
2244 else
2245 return false;
2246}
2247
2248extern bool matchMultilineRegex (struct lregexControlBlock *lcb, const vString* const allLines)
2249{
2250 bool result = false;
2251
2252 unsigned int i;
2253
2254 for (i = 0; i < ptrArrayCount(lcb->entries [REG_PARSER_MULTI_LINE]); ++i)
2255 {
2257 Assert (entry && entry->pattern);
2258
2259 if ((entry->pattern->xtagType != XTAG_UNKNOWN)
2260 && (!isXtagEnabled (entry->pattern->xtagType)))
2261 continue;
2262
2263 result = matchMultilineRegexPattern (lcb, allLines, entry) || result;
2264 }
2265 return result;
2266}
2267
2268static int getTableIndexForName (const struct lregexControlBlock *const lcb, const char *name)
2269{
2270 unsigned int i;
2271
2272 for (i = 0; i < ptrArrayCount(lcb->tables); i++)
2273 {
2274 struct regexTable *table = ptrArrayItem(lcb->tables, i);
2275 if (strcmp (table->name, name) == 0)
2276 return (int)i;
2277 }
2278
2279 return TABLE_INDEX_UNUSED;
2280}
2281
2282extern void addRegexTable (struct lregexControlBlock *lcb, const char *name)
2283{
2284 const char *c;
2285 for (c = name; *c; c++)
2286 if (! (isalnum(*c) || *c == '_'))
2287 error (FATAL, "`%c' in \"%s\" is not acceptable as part of table name", *c, name);
2288
2289 if (getTableIndexForName(lcb, name) >= 0)
2290 {
2291 error (WARNING, "regex table \"%s\" is already defined", name);
2292 return;
2293 }
2294
2295 struct regexTable *table = xCalloc(1, struct regexTable);
2296 table->name = eStrdup (name);
2298
2299 ptrArrayAdd (lcb->tables, table);
2300}
2301
2302static void dumpSstack(FILE* fp, int scope)
2303{
2305 fprintf (fp, "scope : ");
2306 while ((entry = getEntryInCorkQueue (scope)))
2307 {
2308 fprintf(fp, "%s", entry->name);
2309
2310 scope = entry->extensionFields.scopeIndex;
2311 if (scope != CORK_NIL)
2312 fprintf(fp, "%c", '/');
2313 }
2314 fprintf (fp, "\n");
2315}
2316
2317static void dumpTstack(FILE* fp, ptrArray *tstack)
2318{
2319 for (unsigned int i = ptrArrayCount(tstack); i > 0; i--)
2320 {
2321 char tmp[2];
2322 struct regexTable *t = ptrArrayItem(tstack, i - 1);
2323 if (i == 1)
2324 tmp[0] = '\0';
2325 else
2326 {
2327 tmp[0] = '/';
2328 tmp[1] = '\0';
2329 }
2330 fprintf(fp, "%s%s", t->name, tmp);
2331 }
2332 fprintf(fp, "\n");
2333}
2334
2335static void printInputLine(FILE* vfp, const char *c, const off_t offset)
2336{
2337 vString *v = vStringNew ();
2338
2339 for (; *c && (*c != '\n'); c++)
2340 vStringPut(v, *c);
2341
2342 if (vStringLength (v) == 0 && *c == '\n')
2343 vStringCatS (v, "\\n");
2344
2345 fprintf (vfp, "\ninput : \"%s\" L%lu\n",
2346 vStringValue (v),
2348 vStringDelete(v);
2349}
2350
2351static void printMultitableMessage(const langType language,
2352 const char *const tableName,
2353 const unsigned int index,
2354 const regexPattern *const ptrn,
2355 const off_t offset,
2356 const char *const current,
2357 const regmatch_t* const pmatch)
2358{
2359 vString *msg;
2360
2361 Assert (ptrn);
2362 Assert (ptrn->message.selection > 0);
2364
2365 msg = substitute (current, ptrn->message.message_string, BACK_REFERENCE_COUNT, pmatch);
2366
2367 error (ptrn->message.selection, "%sMessage from mtable<%s/%s[%2u]>: %s (%s:%lu)",
2368 (ptrn->message.selection == FATAL ? "Fatal: " : ""),
2369 getLanguageName (language),
2370 tableName,
2371 index,
2372 vStringValue (msg),
2375
2376 vStringDelete (msg);
2377}
2378
2380 struct regexTable *table, const vString *const start, unsigned int *offset)
2381{
2382 struct regexTable *next = NULL;
2383 const char *current;
2385 const char *cstart = vStringValue(start);
2386 unsigned int delta;
2387
2388
2389 restart:
2390 current = cstart + *offset;
2391
2392 /* Accept the case *offset == vStringLength(start)
2393 because we want an empty regex // still matches empty input. */
2394 if (*offset > vStringLength(start))
2395 {
2396 *offset = vStringLength(start);
2397 goto out;
2398 }
2399
2400 BEGIN_VERBOSE(vfp);
2401 {
2402 printInputLine(vfp, current, *offset);
2403 }
2404 END_VERBOSE();
2405
2406 for (unsigned int i = 0; i < ptrArrayCount(table->entries); i++)
2407 {
2409 regexPattern *ptrn = entry->pattern;
2410 struct guestSpec *guest = &ptrn->guest;
2411
2412 Assert (ptrn);
2413
2414 BEGIN_VERBOSE(vfp);
2415 {
2416 char s[3];
2417 if (*current == '\n')
2418 {
2419 s [0] = '\\';
2420 s [1] = 'n';
2421 s [2] = '\0';
2422 }
2423 else if (*current == '\t')
2424 {
2425 s [0] = '\\';
2426 s [1] = 't';
2427 s [2] = '\0';
2428 }
2429 else if (*current == '\\')
2430 {
2431 s [0] = '\\';
2432 s [1] = '\\';
2433 s [2] = '\0';
2434 }
2435 else
2436 {
2437 s[0] = *current;
2438 s[1] = '\0';
2439 }
2440
2441 if (s[1] == '\0')
2442 fprintf (vfp, "match : '%s' %15s[%2u] /", s, table->name, i);
2443 else if (s[0] == '\0')
2444 fprintf (vfp, "match : '' %15s[%2u] /", table->name, i);
2445 else
2446 fprintf (vfp, "match :'%s' %15s[%2u] / ", s, table->name, i);
2447 fprintf (vfp, "%s/\n", ptrn->pattern_string);
2448 }
2449 END_VERBOSE();
2450
2451 int match = 0;
2452
2453 if (ptrn->disabled && *(ptrn->disabled))
2454 continue;
2455
2456 match = regexec (ptrn->pattern, current,
2457 BACK_REFERENCE_COUNT, pmatch, 0);
2458
2459 if (match == 0)
2460 {
2461 entry->statistics.match++;
2462
2463 if (ptrn->type == PTRN_TAG)
2464 {
2465 struct mTableActionSpec *taction = &(ptrn->taction);
2466
2467 matchTagPattern (lcb, current, ptrn, pmatch,
2468 (current
2469 + pmatch [ptrn->mgroup.forLineNumberDetermination].rm_so)
2470 - cstart);
2471 BEGIN_VERBOSE(vfp);
2472 {
2473 fprintf(vfp, "result: matched %d bytes\n", (int)(pmatch[0].rm_eo));
2474 dumpSstack (vfp, lcb->currentScope);
2475 }
2476 END_VERBOSE();
2477
2478 if (hasMessage(ptrn))
2479 printMultitableMessage (lcb->owner, table->name, i, ptrn,
2480 *offset, current, pmatch);
2481
2482 if (fillGuestRequest (cstart, current, pmatch, guest, lcb->guest_req))
2483 {
2484 Assert (lcb->guest_req->lang != LANG_AUTO);
2488 }
2489
2490 delta = (ptrn->mgroup.nextFromStart
2491 ? pmatch [ptrn->mgroup.forNextScanning].rm_so
2492 : pmatch [ptrn->mgroup.forNextScanning].rm_eo);
2493 *offset += delta;
2494
2495 switch (taction->action)
2496 {
2497 case TACTION_NOP:
2498 BEGIN_VERBOSE(vfp);
2499 {
2500 fprintf(vfp, "action: NOP in {%s}, stack: /", table->name);
2501 dumpTstack(vfp, lcb->tstack);
2502 }
2503 END_VERBOSE();
2504 break;
2505 case TACTION_ENTER:
2506 /* TODO: Limit the depth of tstack. */
2507 ptrArrayAdd (lcb->tstack,
2508 taction->continuation_table
2509 ? taction->continuation_table
2510 : table);
2511 next = taction->table;
2512 BEGIN_VERBOSE(vfp);
2513 {
2514 if (taction->continuation_table)
2515 fprintf(vfp, "action: [enter] to {%s}, cont: {%s}, stack: /",
2516 next->name,
2517 taction->continuation_table->name);
2518 else
2519 fprintf(vfp, "action: [enter] to {%s}, stack: /", next->name);
2520 dumpTstack(vfp, lcb->tstack);
2521 }
2522 END_VERBOSE();
2523 break;
2524 case TACTION_LEAVE:
2525 BEGIN_VERBOSE(vfp);
2526 {
2527 fprintf(vfp, "action: [leave] from {%s}, stack: /", table->name);
2528 dumpTstack(vfp, lcb->tstack);
2529 }
2530 END_VERBOSE();
2531 if (ptrArrayCount (lcb->tstack) == 0)
2532 {
2533 error (WARNING, "leave is specified as regex table action but the table stack is empty");
2534 return NULL;
2535 }
2536 next = ptrArrayLast(lcb->tstack);
2538 break;
2539 case TACTION_JUMP:
2540 next = taction->table;
2541 BEGIN_VERBOSE(vfp);
2542 {
2543 fprintf(vfp, "action: [jump] from {%s} to {%s}, stack: /", table->name, next->name);
2544 dumpTstack(vfp, lcb->tstack);
2545 }
2546 END_VERBOSE();
2547
2548 break;
2549 case TACTION_RESET:
2550 next = taction->table;
2551 BEGIN_VERBOSE(vfp);
2552 {
2553 fprintf(vfp, "action: [reset] to {%s}, stack: /", next->name);
2554 }
2555 END_VERBOSE();
2556
2557 ptrArrayClear (lcb->tstack);
2558 break;
2559 case TACTION_QUIT:
2560 BEGIN_VERBOSE(vfp);
2561 {
2562 fprintf(vfp, "action: [quit], stack: /");
2563 dumpTstack(vfp, lcb->tstack);
2564 }
2565 END_VERBOSE();
2566 return NULL;
2567 }
2568
2569 if (next)
2570 break;
2571
2572 if (delta == 0)
2573 {
2574 error (WARNING, "Forcefully advance the input pos because");
2575 error (WARNING, "following conditions for entering infinite loop are satisfied:");
2576 error (WARNING, "+ matching the pattern succeeds,");
2577 error (WARNING, "+ the next table is not given, and");
2578 error (WARNING, "+ the input file pos doesn't advance.");
2579 error (WARNING, "Language: %s, input file: %s, pos: %u",
2580 getLanguageName (lcb->owner), getInputFileName(), *offset);
2581 ++*offset;
2582 }
2583 }
2584 else if (ptrn->type == PTRN_CALLBACK)
2585 ; /* Not implemented yet */
2586 else
2587 {
2588 Assert ("invalid pattern type" == NULL);
2589 break;
2590 }
2591 goto restart;
2592 }
2593 else
2594 entry->statistics.unmatch++;
2595 }
2596 out:
2597 if (next == NULL && ptrArrayCount (lcb->tstack) > 0)
2598 {
2599 static int apop_count = 0;
2600 next = ptrArrayLast(lcb->tstack);
2601 verbose("result: no match - autopop<%d> from {%s} to {%s} @ %lu\n", apop_count++, table->name, next->name,
2604 }
2605 return next;
2606}
2607
2608extern void extendRegexTable (struct lregexControlBlock *lcb, const char *src, const char *dist)
2609{
2610
2611 int i;
2612 struct regexTable * src_table;
2613 struct regexTable * dist_table;
2614
2615 verbose ("extend regex table \"%s\" with \"%s\"\n", dist, src);
2616
2617 i = getTableIndexForName (lcb, src);
2618 if (i < 0)
2619 error (FATAL, "no such regex table in %s: %s", getLanguageName(lcb->owner), src);
2620 src_table = ptrArrayItem(lcb->tables, i);
2621
2622 i = getTableIndexForName (lcb, dist);
2623 if (i < 0)
2624 error (FATAL, "no such regex table in %s: %s", getLanguageName(lcb->owner), dist);
2625 dist_table = ptrArrayItem(lcb->tables, i);
2626
2627 for (i = 0; i < (int)ptrArrayCount(src_table->entries); i++)
2628 {
2629 regexTableEntry *entry = ptrArrayItem (src_table->entries, i);
2631 }
2632}
2633
2635{
2636 if (ptrArrayCount(lcb->tables) == 0)
2637 return;
2638
2639 fprintf(stderr, "\nMTABLE REGEX STATISTICS of %s\n", getLanguageName (lcb->owner));
2640 fputs("==============================================\n", stderr);
2641 for (unsigned int i = 0; i < ptrArrayCount(lcb->tables); i++)
2642 {
2643 struct regexTable *table = ptrArrayItem (lcb->tables, i);
2644 fprintf(stderr, "%s\n", table->name);
2645 fputs("-----------------------\n", stderr);
2646 for (unsigned int j = 0; j < ptrArrayCount(table->entries); j++)
2647 {
2649 Assert (entry && entry->pattern);
2650 fprintf(stderr, "%10u/%-10u%-40s ref: %d\n",
2651 entry->statistics.match,
2652 entry->statistics.unmatch + entry->statistics.match,
2653 entry->pattern->pattern_string,
2654 entry->pattern->refcount);
2655 }
2656 fputc('\n', stderr);
2657 }
2658}
2659
2660extern bool matchMultitableRegex (struct lregexControlBlock *lcb, const vString* const allLines)
2661{
2662 if (ptrArrayCount (lcb->tables) == 0)
2663 return false;
2664
2665 struct regexTable *table = ptrArrayItem (lcb->tables, 0);
2666 unsigned int offset = 0;
2667
2668 int motionless_counter = 0;
2669 unsigned int last_offset;
2670
2671
2672 while (table)
2673 {
2674 last_offset = offset;
2675 table = matchMultitableRegexTable(lcb, table, allLines, &offset);
2676
2677 if (last_offset == offset)
2678 motionless_counter++;
2679 else
2680 motionless_counter = 0;
2681
2682 if (motionless_counter > MTABLE_MOTIONLESS_MAX)
2683 {
2684 error (WARNING, "mtable<%s/%s>: the input cursor stays at %u in %s so long though the tables are switched",
2685 getLanguageName (lcb->owner),
2686 table->name, offset, getInputFileName ());
2687 break;
2688 }
2689
2690 if (table && (ptrArrayCount (lcb->tstack) > MTABLE_STACK_MAX_DEPTH))
2691 {
2692 unsigned int i;
2693 struct regexTable *t;
2694
2695 error (WARNING, "mtable<%s/%s>: the tenter/tleave stack overflows at %u in %s",
2696 getLanguageName (lcb->owner),
2697 table->name, offset, getInputFileName ());
2698 error (WARNING, "DUMP FROM THE TOP:");
2699 /* TODO: use dumpTstack */
2700 for (i = ptrArrayCount(lcb->tstack); 0 < i; --i)
2701 {
2702 t = ptrArrayItem (lcb->tstack, i - 1);
2703 error (WARNING, "%3u %s", i - 1, t->name);
2704 }
2705
2706 break;
2707 }
2708 }
2709
2710 return true;
2711}
2712
2713static int makePromiseForAreaSpecifiedWithOffsets (const char *parser,
2714 off_t startOffset,
2715 off_t endOffset)
2716{
2717 unsigned long startLine = getInputLineNumberForFileOffset(startOffset);
2718 unsigned long endLine = getInputLineNumberForFileOffset(endOffset);
2719 unsigned long startLineOffset = getInputFileOffsetForLine (startLine);
2720 unsigned long endLineOffset = getInputFileOffsetForLine (endLine);
2721
2722 return makePromise (parser,
2723 startLine, startOffset - startLineOffset,
2724 endLine, endOffset - endLineOffset,
2725 startOffset - startLineOffset);
2726}
2727
2728static struct guestRequest *guestRequestNew (void)
2729{
2730 struct guestRequest *r = xMalloc (1, struct guestRequest);
2731
2732
2734 return r;
2735}
2736
2737static void guestRequestDelete (struct guestRequest *r)
2738{
2739 eFree (r);
2740}
2741
2743{
2744 return (r->lang_set && (r->boundary + 0)->offset_set && (r->boundary + 1)->offset_set);
2745}
2746
2747static void guestRequestClear (struct guestRequest *r)
2748{
2749 r->lang_set = false;
2751 r->boundary[BOUNDARY_END].offset_set = false;
2752}
2753
2754static void guestRequestSubmit (struct guestRequest *r)
2755{
2756 const char *langName = getLanguageName (r->lang);
2757 verbose ("guestRequestSubmit: %s; "
2758 "range: %"PRId64" - %"PRId64"\n",
2759 langName,
2760 (int64_t)r->boundary[BOUNDARY_START].offset,
2761 (int64_t)r->boundary[BOUNDARY_END].offset);
2765}
2766
2767/* Return true if available. */
2768extern bool checkRegex (void)
2769{
2770#if defined (CHECK_REGCOMP)
2771 {
2772 /* Check for broken regcomp() on Cygwin */
2773 regex_t patbuf;
2774 int errcode;
2775 if (regcomp (&patbuf, "/hello/", 0) != 0)
2776 error (WARNING, "Disabling broken regex");
2777 else
2778 regexAvailable = true;
2779 }
2780#else
2781 /* We are using bundled regex engine. */
2782 regexAvailable = true;
2783#endif
2784 return regexAvailable;
2785}
gint index
Definition: build.c:2680
void colprintTableDelete(struct colprintTable *table)
Definition: colprint.c:109
#define Assert(c)
Definition: debug.h:47
const gchar * name
Definition: document.c:3219
gint pos
Definition: editor.c:87
int makeTagEntry(const tagEntryInfo *const tag)
Definition: entry.c:1675
void assignRole(tagEntryInfo *const e, int roleIndex)
Definition: entry.c:1964
void markTagExtraBit(tagEntryInfo *const tag, xtagType extra)
Definition: entry.c:1899
void initRefTagEntry(tagEntryInfo *const e, const char *const name, int kindIndex, int roleIndex)
Definition: entry.c:1838
tagEntryInfo * getEntryInCorkQueue(int n)
Definition: entry.c:1635
void attachParserField(tagEntryInfo *const tag, bool inCorkQueue, fieldType ftype, const char *value)
Definition: entry.c:969
uint64_t roleBitsType
Definition: entry.h:39
#define ROLE_DEFINITION_INDEX
Definition: entry.h:90
#define CORK_NIL
Definition: entry.h:145
static roleBitsType makeRoleBit(int roleIndex)
Definition: entry_p.h:69
void error(const errorSelection selection, const char *const format,...)
Definition: error.c:53
bool isFieldEnabled(fieldType type)
Definition: field.c:945
fieldType getFieldTypeForNameAndLanguage(const char *fieldName, langType language)
Definition: field.c:325
enum eFieldType fieldType
@ FIELD_UNKNOWN
Definition: field.h:29
void flagsColprintAddDefinitions(struct colprintTable *table, flagDefinition *def, unsigned int ndefs)
Definition: flags.c:84
struct colprintTable * flagsColprintTableNew(void)
Definition: flags.c:79
void flagsColprintTablePrint(struct colprintTable *table, bool withListHeader, bool machinable, FILE *fp)
Definition: flags.c:145
void flagsEval(const char *flags_original, flagDefinition *defs, unsigned int ndefs, void *data)
Definition: flags.c:24
#define CTAGS_ATTR_UNUSED
Definition: gcc-attr.h:22
vString * line
Definition: geany_cobol.c:133
unsigned int count
static vString * scope
Definition: geany_go.c:78
static bool match(const unsigned char *line, const char *word)
Definition: geany_tcl.c:55
#define KIND_GHOST_INDEX
Definition: kind.h:55
#define KIND_REGEX_DEFAULT_LETTER
Definition: kind.h:34
#define KIND_REGEX_DEFAULT_NAME
Definition: kind.h:35
#define KIND_FILE_INDEX
Definition: kind.h:59
static GOptionEntry entries[]
Definition: libmain.c:118
void notifyRegexInputEnd(struct lregexControlBlock *lcb)
Definition: lregex.c:1857
pType
Definition: lregex.c:72
@ PTRN_TAG
Definition: lregex.c:72
@ PTRN_CALLBACK
Definition: lregex.c:72
static int makePromiseForAreaSpecifiedWithOffsets(const char *parser, off_t startOffset, off_t endOffset)
Definition: lregex.c:2713
static void regex_flag_extend_long(const char *const c, const char *const unused, void *data)
Definition: lregex.c:1280
static bool parseKinds(const char *const kindSpec, char *const kindLetter, char **const kindName, char **description)
Definition: lregex.c:1338
static void addTagRegexOption(struct lregexControlBlock *lcb, enum regexParserType regptype, const char *const pattern)
Definition: lregex.c:2095
void printMultitableRegexFlags(bool withListHeader, bool machinable, FILE *fp)
Definition: lregex.c:2216
#define NO_MULTILINE
Definition: lregex.c:124
struct lregexControlBlock * allocLregexControlBlock(parserDefinition *parser)
Definition: lregex.c:298
static regexTableEntry * newEntry(regex_t *const pattern, enum regexParserType regptype)
Definition: lregex.c:587
static void regex_flag_icase_long(const char *s, const char *const unused, void *data)
Definition: lregex.c:1291
static void clearPatternSet(struct lregexControlBlock *lcb)
Definition: lregex.c:291
static flagDefinition prePtrnFlagDef[]
Definition: lregex.c:473
static regexPattern * addCompiledTagCommon(struct lregexControlBlock *lcb, int table_index, regex_t *const pattern, enum regexParserType regptype)
Definition: lregex.c:595
static flagDefinition guestPtrnFlagDef[]
Definition: lregex.c:843
void addTagMultiTableRegex(struct lregexControlBlock *lcb, const char *const table_name, const char *const regex, const char *const name, const char *const kinds, const char *const flags, bool *disabled)
Definition: lregex.c:2058
static bool hasScopeActionInRegex0(ptrArray *entries)
Definition: lregex.c:1880
static bool matchCallbackPattern(const vString *const line, const regexPattern *const patbuf, const regmatch_t *const pmatch)
Definition: lregex.c:1575
void addCallbackRegex(struct lregexControlBlock *lcb, const char *const regex, const char *const flags, const regexCallback callback, bool *disabled, void *userData)
Definition: lregex.c:2073
static void pre_ptrn_flag_guest_long(const char *const s, const char *const v, void *data)
Definition: lregex.c:684
static flagDefinition multilinePtrnFlagDef[]
Definition: lregex.c:836
static void guestRequestClear(struct guestRequest *)
Definition: lregex.c:2747
static void pre_ptrn_flag_exclusive_long(const char *const s, const char *const unused, void *data)
Definition: lregex.c:468
void freeRegexResources(void)
Definition: lregex.c:2233
static flagDefinition regexFlagDefs[]
Definition: lregex.c:1297
static void dumpSstack(FILE *fp, int scope)
Definition: lregex.c:2302
#define BACK_REFERENCE_COUNT
Definition: lregex.c:54
static bool isGuestRequestConsistent(struct guestRequest *guest_req)
Definition: lregex.c:1622
static void common_flag_msg_long(const char *const s, const char *const v, void *data)
Definition: lregex.c:860
void notifyRegexInputStart(struct lregexControlBlock *lcb)
Definition: lregex.c:1849
void extendRegexTable(struct lregexControlBlock *lcb, const char *src, const char *dist)
Definition: lregex.c:2608
static void regex_flag_basic_short(char c, void *data)
Definition: lregex.c:1263
static flagDefinition scopePtrnFlagDef[]
Definition: lregex.c:504
tableAction
Definition: lregex.c:82
@ TACTION_ENTER
Definition: lregex.c:84
@ TACTION_RESET
Definition: lregex.c:87
@ TACTION_JUMP
Definition: lregex.c:86
@ TACTION_LEAVE
Definition: lregex.c:85
@ TACTION_QUIT
Definition: lregex.c:88
@ TACTION_NOP
Definition: lregex.c:83
static char * escapeRegexPattern(const char *pattern)
Definition: lregex.c:1910
static unsigned long getInputLineNumberInRegPType(enum regexParserType regptype, off_t offset)
Definition: lregex.c:1428
static bool fillGuestRequest(const char *start, const char *current, regmatch_t pmatch[10], struct guestSpec *guest_spec, struct guestRequest *guest_req)
Definition: lregex.c:1628
static flagDefinition multitablePtrnFlagDef[]
Definition: lregex.c:1142
static void deletePattern(regexPattern *p)
Definition: lregex.c:257
static void patternEvalFlags(struct lregexControlBlock *lcb, regexPattern *ptrn, enum regexParserType regptype, const char *flags)
Definition: lregex.c:1189
static void initTaction(struct mTableActionSpec *taction)
Definition: lregex.c:543
static kindDefinition * kindNew(char letter, const char *name, const char *description)
Definition: lregex.c:511
#define MTABLE_STACK_MAX_DEPTH
Definition: lregex.c:57
static void printInputLine(FILE *vfp, const char *c, const off_t offset)
Definition: lregex.c:2335
#define MTABLE_MOTIONLESS_MAX
Definition: lregex.c:65
static int fileReadLineDriver(void)
Definition: lregex.c:1870
bool checkRegex(void)
Definition: lregex.c:2768
bool matchMultilineRegex(struct lregexControlBlock *lcb, const vString *const allLines)
Definition: lregex.c:2248
static bool parseTagRegex(enum regexParserType regptype, char *const regexp, char **const name, char **const kinds, char **const flags)
Definition: lregex.c:415
static bool matchMultilineRegexPattern(struct lregexControlBlock *lcb, const vString *const allLines, regexTableEntry *entry)
Definition: lregex.c:1738
void printRegexFlags(bool withListHeader, bool machinable, FILE *fp)
Definition: lregex.c:2185
void addTagMultiLineRegex(struct lregexControlBlock *lcb, const char *const regex, const char *const name, const char *const kinds, const char *const flags, bool *disabled)
Definition: lregex.c:2050
void freeLregexControlBlock(struct lregexControlBlock *lcb)
Definition: lregex.c:312
static char * scanSeparators(char *name, enum regexParserType regptype)
Definition: lregex.c:367
static void guestRequestDelete(struct guestRequest *)
Definition: lregex.c:2737
static void common_flag_extra_long(const char *const s, const char *const v, void *data)
Definition: lregex.c:907
static void regex_flag_basic_long(const char *const s, const char *const unused, void *data)
Definition: lregex.c:1269
static regexPattern * refPattern(regexPattern *ptrn)
Definition: lregex.c:549
bool hasScopeActionInRegex(struct lregexControlBlock *lcb)
Definition: lregex.c:1892
static void placeholder_ptrn_flag_eval(const char *const f, const char *const v, void *data)
Definition: lregex.c:497
static void common_flag_field_long(const char *const s, const char *const v, void *data)
Definition: lregex.c:942
void findRegexTags(void)
Definition: lregex.c:1875
static regexTableEntry * newRefPatternEntry(regexTableEntry *other)
Definition: lregex.c:577
static vString * substitute(const char *const in, const char *out, const int nmatch, const regmatch_t *const pmatch)
Definition: lregex.c:1405
void printMultitableStatistics(struct lregexControlBlock *lcb)
Definition: lregex.c:2634
static regexPattern * addTagRegexInternal(struct lregexControlBlock *lcb, int table_index, enum regexParserType regptype, const char *const regex, const char *const name, const char *const kinds, const char *const flags, bool *disabled)
Definition: lregex.c:1932
static bool regexAvailable
Definition: lregex.c:47
#define BOUNDARY_START
Definition: lregex.c:118
static regex_t * compileRegex(enum regexParserType regptype, const char *const regexp, const char *const flags)
Definition: lregex.c:1306
void findRegexTagsMainloop(int(*driver)(void))
Definition: lregex.c:1863
#define BOUNDARY_END
Definition: lregex.c:119
bool regexNeedsMultilineBuffer(struct lregexControlBlock *lcb)
Definition: lregex.c:2238
bool matchMultitableRegex(struct lregexControlBlock *lcb, const vString *const allLines)
Definition: lregex.c:2660
bool matchRegex(struct lregexControlBlock *lcb, const vString *const line)
Definition: lregex.c:1824
static void printMessage(const langType language, const regexPattern *const ptrn, const off_t offset, const char *const line, const regmatch_t *const pmatch)
Definition: lregex.c:1598
static void printMultitableMessage(const langType language, const char *const tableName, const unsigned int index, const regexPattern *const ptrn, const off_t offset, const char *const current, const regmatch_t *const pmatch)
Definition: lregex.c:2351
static bool guestRequestIsFilled(struct guestRequest *)
Definition: lregex.c:2742
static void common_flag_anonymous_long(const char *const s, const char *const v, void *data)
Definition: lregex.c:1025
static flagDefinition commonSpecFlagDef[]
Definition: lregex.c:1056
static void matchTagPattern(struct lregexControlBlock *lcb, const char *line, const regexPattern *const patbuf, const regmatch_t *const pmatch, off_t offset)
Definition: lregex.c:1449
void printMultilineRegexFlags(bool withListHeader, bool machinable, FILE *fp)
Definition: lregex.c:2201
void addTagRegex(struct lregexControlBlock *lcb, const char *const regex, const char *const name, const char *const kinds, const char *const flags, bool *disabled)
Definition: lregex.c:2039
static void pre_ptrn_flag_mgroup_long(const char *const s, const char *const v, void *data)
Definition: lregex.c:617
static void kindFree(kindDefinition *kind)
Definition: lregex.c:521
static struct regexTable * matchMultitableRegexTable(struct lregexControlBlock *lcb, struct regexTable *table, const vString *const start, unsigned int *offset)
Definition: lregex.c:2379
static void scope_ptrn_flag_eval(const char *const f, const char *const v, void *data)
Definition: lregex.c:478
static void setKind(regexPattern *ptrn, const langType owner, const char kindLetter, const char *kindName, const char *const description, bool kind_explicitly_defined)
Definition: lregex.c:1156
#define TABLE_INDEX_UNUSED
Definition: lregex.c:191
static void fieldPatternDelete(struct fieldPattern *fp)
Definition: lregex.c:936
static void initMgroup(struct mGroupSpec *mgroup)
Definition: lregex.c:531
static struct fieldPattern * fieldPatternNew(fieldType ftype, const char *template)
Definition: lregex.c:925
#define EXPERIMENTAL
static regexPattern * addCompiledCallbackPattern(struct lregexControlBlock *lcb, regex_t *const pattern, const regexCallback callback, const char *flags, bool *disabled, void *userData)
Definition: lregex.c:1245
static struct guestRequest * guestRequestNew(void)
Definition: lregex.c:2728
static void regex_flag_icase_short(char c, void *data)
Definition: lregex.c:1285
static void pre_ptrn_flag_mtable_long(const char *const s, const char *const v, void *data)
Definition: lregex.c:1073
static regexPattern * addCompiledTagPattern(struct lregexControlBlock *lcb, int table_index, enum regexParserType regptype, regex_t *const pattern, const char *const name, char kindLetter, const char *kindName, char *const description, const char *flags, bool kind_explicitly_defined, bool *disabled)
Definition: lregex.c:1225
static void guestRequestSubmit(struct guestRequest *)
Definition: lregex.c:2754
static int getTableIndexForName(const struct lregexControlBlock *const lcb, const char *name)
Definition: lregex.c:2268
static void regex_flag_extend_short(char c, void *data)
Definition: lregex.c:1274
scopeAction
Definition: lregex.c:74
@ SCOPE_PUSH
Definition: lregex.c:77
@ SCOPE_POP
Definition: lregex.c:76
@ SCOPE_PLACEHOLDER
Definition: lregex.c:79
@ SCOPE_CLEAR
Definition: lregex.c:78
@ SCOPE_REF
Definition: lregex.c:75
static void common_flag_role_long(const char *const s, const char *const v, void *data)
Definition: lregex.c:1000
static void pre_ptrn_flag_exclusive_short(char c, void *data)
Definition: lregex.c:462
void addRegexTable(struct lregexControlBlock *lcb, const char *name)
Definition: lregex.c:2282
static bool hasMessage(const regexPattern *const ptrn)
Definition: lregex.c:849
static void deleteTable(void *ptrn)
Definition: lregex.c:240
static bool matchRegexPattern(struct lregexControlBlock *lcb, const vString *const line, regexTableEntry *entry)
Definition: lregex.c:1684
static void pre_ptrn_flag_advanceTo_long(const char *const s, const char *const v, void *data)
Definition: lregex.c:640
static void deleteTableEntry(void *ptrn)
Definition: lregex.c:249
static regexPattern * newPattern(regex_t *const pattern, enum regexParserType regptype)
Definition: lregex.c:555
static void dumpTstack(FILE *fp, ptrArray *tstack)
Definition: lregex.c:2317
static void initGuestSpec(struct guestSpec *guest)
Definition: lregex.c:538
static void fillEndLineFieldOfUpperScopes(struct lregexControlBlock *lcb, unsigned long endline)
Definition: lregex.c:1436
static void initRegexTag(tagEntryInfo *e, const vString *const name, int kindIndex, int roleIndex, int scopeIndex, int placeholder, unsigned long line, MIOPos *pos, int xtag_type)
Definition: lregex.c:337
void processTagRegexOption(struct lregexControlBlock *lcb, enum regexParserType regptype, const char *const parameter)
Definition: lregex.c:2149
bool(* regexCallback)(const char *line, const regexMatch *matches, unsigned int count, void *userData)
Definition: lregex.h:44
regexParserType
Definition: lregex_p.h:28
@ REG_PARSER_SINGLE_LINE
Definition: lregex_p.h:29
@ REG_PARSER_MULTI_TABLE
Definition: lregex_p.h:31
@ REG_PARSER_MULTI_LINE
Definition: lregex_p.h:30
MIO * mio_new_file(const char *filename, const char *mode)
mio_new_file: @filename: Filename to open, same as the fopen()'s first argument @mode: Mode in which ...
Definition: mio.c:234
int mio_unref(MIO *mio)
mio_unref: @mio: A MIO object
Definition: mio.c:480
void verbose(const char *const format,...)
Definition: options.c:655
#define END_VERBOSE()
Definition: options.h:33
#define BEGIN_VERBOSE(VFP)
Definition: options.h:31
langType getNamedLanguage(const char *const name, size_t len)
Definition: parse.c:406
kindDefinition * getLanguageKind(const langType language, int kindIndex)
Definition: parse.c:317
langType getLanguageForFilename(const char *const filename, langType startFrom)
Definition: parse.c:520
vString * anonGenerateNew(const char *prefix, int kind)
Definition: parse.c:4720
const char * getLanguageName(const langType language)
Definition: parse.c:284
kindDefinition * getLanguageKindForLetter(const langType language, char kindLetter)
Definition: parse.c:338
void useRegexMethod(const langType language)
Definition: parse.c:4311
roleDefinition * getLanguageRoleForName(const langType language, int kindIndex, const char *roleName)
Definition: parse.c:367
unsigned int countLanguageRoles(const langType language, int kindIndex)
Definition: parse.c:312
int defineLanguageKind(const langType language, kindDefinition *def, freeKindDefFunc freeKindDef)
Definition: parse.c:301
#define LANG_IGNORE
Definition: parse.h:27
#define LANG_AUTO
Definition: parse.h:26
int makePromise(const char *parser, unsigned long startLine, long startCharOffset, unsigned long endLine, long endCharOffset, unsigned long sourceLineOffset)
Definition: promise.c:64
unsigned int ptrArrayCount(const ptrArray *const current)
Definition: ptrarray.c:80
void ptrArrayClear(ptrArray *const current)
Definition: ptrarray.c:99
void * ptrArrayItem(const ptrArray *const current, const unsigned int indx)
Definition: ptrarray.c:86
void * ptrArrayLast(const ptrArray *const current)
Definition: ptrarray.c:92
ptrArray * ptrArrayNew(ptrArrayDeleteFunc deleteFunc)
Definition: ptrarray.c:37
void ptrArrayDelete(ptrArray *const current)
Definition: ptrarray.c:111
void * ptrArrayRemoveLast(ptrArray *const current)
Definition: ptrarray.c:59
unsigned int ptrArrayAdd(ptrArray *const current, void *ptr)
Definition: ptrarray.c:47
void(* ptrArrayDeleteFunc)(void *data)
Definition: ptrarray.h:24
#define NULL
Definition: rbtree.h:150
MIOPos getInputFilePositionForLine(unsigned int line)
Definition: read.c:184
char * readLineRaw(vString *const vLine, MIO *const mio)
Definition: read.c:1016
const unsigned char * readLineFromInputFile(void)
Definition: read.c:1000
unsigned long getInputLineNumber(void)
Definition: read.c:142
long getInputFileOffsetForLine(unsigned int line)
Definition: read.c:190
const char * getInputFileName(void)
Definition: read.c:154
unsigned long getInputLineNumberForFileOffset(long offset)
Definition: read.c:360
size_t regerror(int errcode, const regex_t *__restrict preg, char *__restrict errbuf, size_t errbuf_size)
Definition: regcomp.c:530
int regcomp(regex_t *__restrict preg, const char *__restrict pattern, int cflags)
Definition: regcomp.c:468
void regfree(regex_t *preg)
Definition: regcomp.c:638
#define REG_ICASE
Definition: regex.h:276
#define REG_EXTENDED
Definition: regex.h:272
#define REG_NEWLINE
Definition: regex.h:281
int regexec(const regex_t *__preg, const char *__string, size_t __nmatch, regmatch_t __pmatch[], int __eflags)
char * eStrndup(const char *str, size_t len)
Definition: routines.c:334
bool doesFileExist(const char *const fileName)
Definition: routines.c:495
bool strToInt(const char *const str, int base, int *value)
Definition: routines.c:423
char * strstr(const char *str, const char *substr)
Definition: routines.c:304
char * eStrdup(const char *str)
Definition: routines.c:327
void eFree(void *const ptr)
Definition: routines.c:252
#define xMalloc(n, Type)
Definition: routines.h:23
@ PERROR
Definition: routines.h:37
@ FATAL
Definition: routines.h:37
@ WARNING
Definition: routines.h:37
#define ARRAY_SIZE(X)
Definition: routines.h:27
#define xCalloc(n, Type)
Definition: routines.h:24
int errorSelection
Definition: routines.h:36
GtkWidget * entry
Definition: search.c:118
MIOPos:
Definition: mio.h:101
MIO:
Definition: mio.c:136
bool fromStartOfGroup
Definition: lregex.c:98
bool placeholder
Definition: lregex.c:99
int patternGroup
Definition: lregex.c:97
regexPattern * ptrn
Definition: lregex.c:857
const struct lregexControlBlock *const lcb
Definition: lregex.c:856
const langType owner
Definition: lregex.c:855
fieldType ftype
Definition: lregex.c:92
const char * template
Definition: lregex.c:93
union guestLangSpec::@5 spec
enum guestLangSpec::guestLangSpecType type
int patternGroup
Definition: lregex.c:112
langType lang
Definition: lregex.c:111
@ GUEST_LANG_PTN_GROUP_FOR_LANGNAME
Definition: lregex.c:107
@ GUEST_LANG_PTN_GROUP_FOR_FILEMAP
Definition: lregex.c:108
@ GUEST_LANG_STATIC_LANGNAME
Definition: lregex.c:106
@ GUEST_LANG_PLACEHOLDER
Definition: lregex.c:105
@ GUEST_LANG_UNKNOWN
Definition: lregex.c:104
enum regexParserType type
Definition: lregex.c:680
struct guestSpec * guest
Definition: lregex.c:681
struct boundaryInRequest boundary[2]
Definition: lregex.c:206
langType lang
Definition: lregex.c:204
bool lang_set
Definition: lregex.c:203
struct guestLangSpec lang
Definition: lregex.c:117
struct boundarySpec boundary[2]
Definition: lregex.c:120
struct guestRequest * guest_req
Definition: lregex.c:216
ptrArray * tables
Definition: lregex.c:213
ptrArray * tstack
Definition: lregex.c:214
ptrArray * entries[2]
Definition: lregex.c:211
langType owner
Definition: lregex.c:218
int forLineNumberDetermination
Definition: lregex.c:125
int forNextScanning
Definition: lregex.c:126
bool nextFromStart
Definition: lregex.c:128
struct regexTable * table
Definition: lregex.c:133
struct regexTable * continuation_table
Definition: lregex.c:136
enum tableAction action
Definition: lregex.c:132
size_t start
Definition: lregex.h:37
size_t length
Definition: lregex.h:38
struct regexPattern::@6::@9 callback
roleBitsType roleBits
Definition: lregex.c:147
regexCallback function
Definition: lregex.c:151
bool * disabled
Definition: lregex.c:156
void * userData
Definition: lregex.c:152
enum pType type
Definition: lregex.c:141
bool accept_empty_name
Definition: lregex.c:143
unsigned int scopeActions
Definition: lregex.c:155
ptrArray * fieldPatterns
Definition: lregex.c:164
char * anonymous_tag_prefix
Definition: lregex.c:168
struct guestSpec guest
Definition: lregex.c:160
int xtagType
Definition: lregex.c:163
regex_t * pattern
Definition: lregex.c:140
char * pattern_string
Definition: lregex.c:166
enum regexParserType regptype
Definition: lregex.c:158
errorSelection selection
Definition: lregex.c:171
int kindIndex
Definition: lregex.c:146
struct mGroupSpec mgroup
Definition: lregex.c:159
char * message_string
Definition: lregex.c:172
char * name_pattern
Definition: lregex.c:148
struct mTableActionSpec taction
Definition: lregex.c:161
bool exclusive
Definition: lregex.c:142
int refcount
Definition: lregex.c:175
struct regexPattern::@7 message
union regexPattern::@6 u
struct regexPattern::@6::@8 tag
unsigned int unmatch
Definition: lregex.c:186
unsigned int match
Definition: lregex.c:185
regexPattern * pattern
Definition: lregex.c:181
char * name
Definition: lregex.c:193
ptrArray * entries
Definition: lregex.c:194
regoff_t rm_eo
Definition: regex.h:454
regoff_t rm_so
Definition: regex.h:453
char letter
Definition: kind.h:73
bool enabled
Definition: kind.h:72
char * name
Definition: kind.h:74
char * description
Definition: kind.h:75
langType id
Definition: parse.h:120
struct sTagEntryInfo::@3 extensionFields
MIOPos filePosition
Definition: entry.h:60
unsigned long lineNumber
Definition: entry.h:56
langType langType
Definition: entry.h:61
int scopeIndex
Definition: entry.h:80
unsigned int placeholder
Definition: entry.h:48
void trashBoxDelete(TrashBox *trash_box)
Definition: trashbox.c:55
TrashBox * trashBoxNew(void)
Definition: trashbox.c:36
void trashBoxMakeEmpty(TrashBox *trash_box)
Definition: trashbox.c:85
void * trashBoxPut(TrashBox *trash_box, void *item, TrashBoxDestroyItemProc destroy)
Definition: trashbox.c:65
#define DEFAULT_TRASH_BOX(PTR, PROC)
Definition: trashbox.h:34
void(* TrashBoxDestroyItemProc)(void *)
Definition: trashbox.h:27
int langType
Definition: types.h:13
void vStringNCatS(vString *const string, const char *const s, const size_t length)
Definition: vstring.c:124
void vStringStripTrailing(vString *const string)
Definition: vstring.c:186
vString * vStringNew(void)
Definition: vstring.c:70
void vStringDelete(vString *const string)
Definition: vstring.c:60
void vStringStripLeading(vString *const string)
Definition: vstring.c:171
void vStringCatS(vString *const string, const char *const s)
Definition: vstring.c:146
vString * vStringNewInit(const char *const s)
Definition: vstring.c:90
char * vStringDeleteUnwrap(vString *const string)
Definition: vstring.c:267
#define vStringLength(vs)
Definition: vstring.h:31
#define vStringValue(vs)
Definition: vstring.h:28
static void vStringPut(vString *const string, const int c)
Definition: vstring.h:101
bool isXtagEnabled(xtagType type)
Definition: xtag.c:235
xtagType getXtagTypeForNameAndLanguage(const char *name, langType language)
Definition: xtag.c:143
@ XTAG_UNKNOWN
Definition: xtag.h:26
@ XTAG_ANONYMOUS
Definition: xtag.h:36