xref: /Universal-ctags/main/lregex.c (revision 6024deefc593abced0b42582f4cf1a8658aac96f)
1d4c6f1e6SMasatake YAMATO /*
2d4c6f1e6SMasatake YAMATO *   Copyright (c) 2000-2003, Darren Hiebert
3d4c6f1e6SMasatake YAMATO *
4d4c6f1e6SMasatake YAMATO *   This source code is released for free distribution under the terms of the
50ce38835Sviccuad *   GNU General Public License version 2 or (at your option) any later version.
6d4c6f1e6SMasatake YAMATO *
7d4c6f1e6SMasatake YAMATO *   This module contains functions for applying regular expression matching.
8d4c6f1e6SMasatake YAMATO *
95dbd2e67SK.Takata *   The code for utilizing the Gnu regex package with regards to processing the
10d4c6f1e6SMasatake YAMATO *   regex option and checking for regex matches was adapted from routines in
11d4c6f1e6SMasatake YAMATO *   Gnu etags.
12d4c6f1e6SMasatake YAMATO */
13d4c6f1e6SMasatake YAMATO 
14d4c6f1e6SMasatake YAMATO /*
15d4c6f1e6SMasatake YAMATO *   INCLUDE FILES
16d4c6f1e6SMasatake YAMATO */
17d4c6f1e6SMasatake YAMATO #include "general.h"  /* must always come first */
18d4c6f1e6SMasatake YAMATO 
19d4c6f1e6SMasatake YAMATO #include <string.h>
20d4c6f1e6SMasatake YAMATO 
21d4c6f1e6SMasatake YAMATO #include <ctype.h>
22d4c6f1e6SMasatake YAMATO #include <stddef.h>
23d4c6f1e6SMasatake YAMATO #ifdef HAVE_SYS_TYPES_H
24d4c6f1e6SMasatake YAMATO # include <sys/types.h>  /* declare off_t (not known to regex.h on FreeBSD) */
25d4c6f1e6SMasatake YAMATO #endif
26d4c6f1e6SMasatake YAMATO 
27540cbe83SK.Takata #include <inttypes.h>
28540cbe83SK.Takata 
29d4c6f1e6SMasatake YAMATO #include "debug.h"
30c2a93c9fSMasatake YAMATO #include "colprint_p.h"
31a57cbfc9SMasatake YAMATO #include "entry_p.h"
32c08c70d0SMasatake YAMATO #include "field_p.h"
33bf281e9cSMasatake YAMATO #include "flags_p.h"
34a4e7ab31SMasatake YAMATO #include "htable.h"
353525c8f1SMasatake YAMATO #include "kind.h"
36a7c0db8cSMasatake YAMATO #include "options.h"
37e8386a4eSMasatake YAMATO #include "optscript.h"
380d502ef0SMasatake YAMATO #include "parse_p.h"
39b19716b4SMasatake YAMATO #include "promise.h"
40d4c6f1e6SMasatake YAMATO #include "read.h"
41b5df137eSMasatake YAMATO #include "read_p.h"
42d4c6f1e6SMasatake YAMATO #include "routines.h"
4329e40fb6SMasatake YAMATO #include "routines_p.h"
44668e3666SMasatake YAMATO #include "script_p.h"
4585021c5bSMasatake YAMATO #include "trace.h"
46f53f3c39SMasatake YAMATO #include "trashbox.h"
47e2a3289bSMasatake YAMATO #include "xtag_p.h"
48d4c6f1e6SMasatake YAMATO 
49ce990805SThomas Braun static bool regexAvailable = false;
50d4c6f1e6SMasatake YAMATO 
51d4c6f1e6SMasatake YAMATO /*
52d4c6f1e6SMasatake YAMATO *   MACROS
53d4c6f1e6SMasatake YAMATO */
54d4c6f1e6SMasatake YAMATO 
55042e4190SMasatake YAMATO /* The max depth of taction=enter/leave stack */
56042e4190SMasatake YAMATO #define MTABLE_STACK_MAX_DEPTH 64
57042e4190SMasatake YAMATO 
58afcf38b2SMasatake YAMATO /* How many times ctags allows a mtable parser
59afcf38b2SMasatake YAMATO    stays at the same input position across table switching.
60afcf38b2SMasatake YAMATO 
61afcf38b2SMasatake YAMATO    The value is derived from MTABLE_STACK_MAX_DEPTH.
62afcf38b2SMasatake YAMATO    No deep meaning is in that. It just for simplifying
63afcf38b2SMasatake YAMATO    Tmain cases. */
64afcf38b2SMasatake YAMATO #define MTABLE_MOTIONLESS_MAX (MTABLE_STACK_MAX_DEPTH + 1)
65afcf38b2SMasatake YAMATO 
66c30b89acSMasatake YAMATO #define DEFAULT_REGEX_BACKEND "e"
67042e4190SMasatake YAMATO 
68d4c6f1e6SMasatake YAMATO /*
69d4c6f1e6SMasatake YAMATO *   DATA DECLARATIONS
70d4c6f1e6SMasatake YAMATO */
71d4c6f1e6SMasatake YAMATO 
72d4c6f1e6SMasatake YAMATO enum pType { PTRN_TAG, PTRN_CALLBACK };
73d4c6f1e6SMasatake YAMATO 
742fa3c9e1SMasatake YAMATO enum scopeAction {
752fa3c9e1SMasatake YAMATO 	SCOPE_REF     = 1UL << 0,
762fa3c9e1SMasatake YAMATO 	SCOPE_POP     = 1UL << 1,
772fa3c9e1SMasatake YAMATO 	SCOPE_PUSH    = 1UL << 2,
782fa3c9e1SMasatake YAMATO 	SCOPE_CLEAR   = 1UL << 3,
79f998e51dSMasatake YAMATO 	SCOPE_REF_AFTER_POP = 1UL << 4,
80f998e51dSMasatake YAMATO 	SCOPE_PLACEHOLDER = 1UL << 5,
812fa3c9e1SMasatake YAMATO };
822fa3c9e1SMasatake YAMATO 
830cbf3f0dSMasatake YAMATO enum tableAction {
840cbf3f0dSMasatake YAMATO 	TACTION_NOP,
850cbf3f0dSMasatake YAMATO 	TACTION_ENTER,				/* {tenter=N} */
860cbf3f0dSMasatake YAMATO 	TACTION_LEAVE,				/* {tleave} */
870cbf3f0dSMasatake YAMATO 	TACTION_JUMP,					/* {tjump=N} */
880cbf3f0dSMasatake YAMATO 	TACTION_RESET,				/* {treset=N} */
890cbf3f0dSMasatake YAMATO 	TACTION_QUIT,					/* {tquit} */
900cbf3f0dSMasatake YAMATO };
910cbf3f0dSMasatake YAMATO 
92f53f3c39SMasatake YAMATO struct fieldPattern {
93f53f3c39SMasatake YAMATO 	fieldType ftype;
94f53f3c39SMasatake YAMATO 	const char *template;
95f53f3c39SMasatake YAMATO };
96f53f3c39SMasatake YAMATO 
976cdf5716SMasatake YAMATO struct boundarySpec {
986cdf5716SMasatake YAMATO 	int patternGroup;
996cdf5716SMasatake YAMATO 	bool fromStartOfGroup;
1006cdf5716SMasatake YAMATO 	bool placeholder;
1016cdf5716SMasatake YAMATO };
1026cdf5716SMasatake YAMATO 
1036cdf5716SMasatake YAMATO struct guestLangSpec {
1046cdf5716SMasatake YAMATO 	enum guestLangSpecType {
1056cdf5716SMasatake YAMATO 		GUEST_LANG_UNKNOWN,
1066cdf5716SMasatake YAMATO 		GUEST_LANG_PLACEHOLDER,			   /* _ */
1076cdf5716SMasatake YAMATO 		GUEST_LANG_STATIC_LANGNAME,		   /* C, Python,... */
1086cdf5716SMasatake YAMATO 		GUEST_LANG_PTN_GROUP_FOR_LANGNAME, /* \1, \2, ..., \9 */
1096cdf5716SMasatake YAMATO 		GUEST_LANG_PTN_GROUP_FOR_FILEMAP, /* *1, *2, ... *9 */
1106cdf5716SMasatake YAMATO 	} type;
1116cdf5716SMasatake YAMATO 	union {
1126cdf5716SMasatake YAMATO 		langType lang;
1136cdf5716SMasatake YAMATO 		int patternGroup;
1146cdf5716SMasatake YAMATO 	} spec;
1156cdf5716SMasatake YAMATO };
1166cdf5716SMasatake YAMATO 
1176cdf5716SMasatake YAMATO struct guestSpec {
1186cdf5716SMasatake YAMATO 	struct guestLangSpec lang;
1196cdf5716SMasatake YAMATO #define BOUNDARY_START 0
1206cdf5716SMasatake YAMATO #define BOUNDARY_END  1
1216cdf5716SMasatake YAMATO 	struct boundarySpec boundary[2];
1226cdf5716SMasatake YAMATO };
1236cdf5716SMasatake YAMATO 
124c9bfc26fSMasatake YAMATO struct mGroupSpec {
125b2c16b34SMasatake YAMATO #define NO_MULTILINE -1
126c9bfc26fSMasatake YAMATO 	int forLineNumberDetermination;
127c9bfc26fSMasatake YAMATO 	int forNextScanning;
128c9bfc26fSMasatake YAMATO 	/* true => start, false => end */
129c9bfc26fSMasatake YAMATO 	bool nextFromStart;
130c9bfc26fSMasatake YAMATO };
131c9bfc26fSMasatake YAMATO 
1320cbf3f0dSMasatake YAMATO struct mTableActionSpec {
1330cbf3f0dSMasatake YAMATO 	enum tableAction action;
1340cbf3f0dSMasatake YAMATO 	struct regexTable *table;
13540177cd9SMasatake YAMATO 
13640177cd9SMasatake YAMATO 	/* used when action == TACTION_ENTER */
13740177cd9SMasatake YAMATO 	struct regexTable *continuation_table;
1380cbf3f0dSMasatake YAMATO };
1390cbf3f0dSMasatake YAMATO 
140d4c6f1e6SMasatake YAMATO typedef struct {
141c30b89acSMasatake YAMATO 	regexCompiledCode pattern;
142d4c6f1e6SMasatake YAMATO 	enum pType type;
143ce990805SThomas Braun 	bool exclusive;
144ce990805SThomas Braun 	bool accept_empty_name;
145d4c6f1e6SMasatake YAMATO 	union {
146d4c6f1e6SMasatake YAMATO 		struct {
147fbcb3274SMasatake YAMATO 			int kindIndex;
14884f3a057SMasatake YAMATO 			roleBitsType roleBits;
149d4c6f1e6SMasatake YAMATO 			char *name_pattern;
150d4c6f1e6SMasatake YAMATO 		} tag;
151d4c6f1e6SMasatake YAMATO 		struct {
152d4c6f1e6SMasatake YAMATO 			regexCallback function;
1536ff4dab6SMasatake YAMATO 			void *userData;
154d4c6f1e6SMasatake YAMATO 		} callback;
155d4c6f1e6SMasatake YAMATO 	} u;
1562fa3c9e1SMasatake YAMATO 	unsigned int scopeActions;
157ce990805SThomas Braun 	bool *disabled;
1581b9c3aecSMasatake YAMATO 
1591b9c3aecSMasatake YAMATO 	enum regexParserType regptype;
160c9bfc26fSMasatake YAMATO 	struct mGroupSpec mgroup;
1616cdf5716SMasatake YAMATO 	struct guestSpec guest;
1620cbf3f0dSMasatake YAMATO 	struct mTableActionSpec taction;
1630cbf3f0dSMasatake YAMATO 
16410db13faSMasatake YAMATO 	int   xtagType;
165f53f3c39SMasatake YAMATO 	ptrArray *fieldPatterns;
1669ec7efeaSMasatake YAMATO 
1675372d785SMasatake YAMATO 	char *pattern_string;
1681e923193SMasatake YAMATO 
1690d56cc8eSMasatake YAMATO 	char *anonymous_tag_prefix;
1700d56cc8eSMasatake YAMATO 
1719a1e266aSHadriel Kaplan 	struct {
1729a1e266aSHadriel Kaplan 		errorSelection selection;
1739a1e266aSHadriel Kaplan 		char *message_string;
1749a1e266aSHadriel Kaplan 	} message;
1759a1e266aSHadriel Kaplan 
176e8386a4eSMasatake YAMATO 	char *optscript_src;
177e8386a4eSMasatake YAMATO 	EsObject *optscript;
178e8386a4eSMasatake YAMATO 
1799ec7efeaSMasatake YAMATO 	int refcount;
180d4c6f1e6SMasatake YAMATO } regexPattern;
181d4c6f1e6SMasatake YAMATO 
182d4c6f1e6SMasatake YAMATO 
183134629a0SHadriel Kaplan typedef struct {
184134629a0SHadriel Kaplan 	/* the pattern can be shared among entries using a refcount */
185134629a0SHadriel Kaplan 	regexPattern *pattern;
186134629a0SHadriel Kaplan 
187134629a0SHadriel Kaplan 	/* but the statistics are per-table-entry */
188134629a0SHadriel Kaplan 	struct {
189134629a0SHadriel Kaplan 		unsigned int match;
190134629a0SHadriel Kaplan 		unsigned int unmatch;
191134629a0SHadriel Kaplan 	} statistics;
192134629a0SHadriel Kaplan } regexTableEntry;
193134629a0SHadriel Kaplan 
194134629a0SHadriel Kaplan 
1950cbf3f0dSMasatake YAMATO #define TABLE_INDEX_UNUSED -1
196e0e33135SMasatake YAMATO struct regexTable {
197e0e33135SMasatake YAMATO 	char *name;
198134629a0SHadriel Kaplan 	ptrArray *entries;
199e0e33135SMasatake YAMATO };
200e0e33135SMasatake YAMATO 
2016cdf5716SMasatake YAMATO struct boundaryInRequest {
2026cdf5716SMasatake YAMATO 	bool offset_set;
2036cdf5716SMasatake YAMATO 	off_t offset;
2046cdf5716SMasatake YAMATO };
2056cdf5716SMasatake YAMATO 
2066cdf5716SMasatake YAMATO struct guestRequest {
2076cdf5716SMasatake YAMATO 	bool lang_set;
2086cdf5716SMasatake YAMATO 	langType lang;
2096cdf5716SMasatake YAMATO 
2106cdf5716SMasatake YAMATO 	struct boundaryInRequest boundary[2];
2116cdf5716SMasatake YAMATO };
2126cdf5716SMasatake YAMATO 
2132bbd136eSMasatake YAMATO typedef struct {
2142bbd136eSMasatake YAMATO 	const char *line;
215ed3202bdSMasatake YAMATO 	const char *start;
2162bbd136eSMasatake YAMATO 	const regexPattern* const patbuf;
2172bbd136eSMasatake YAMATO 	const regmatch_t* const pmatch;
2182bbd136eSMasatake YAMATO 	int nmatch;
2192b8d4c66SMasatake YAMATO 	struct mTableActionSpec taction;
220653692b7SMasatake YAMATO 	bool advanceto;
221653692b7SMasatake YAMATO 	unsigned int advanceto_delta;
2222bbd136eSMasatake YAMATO } scriptWindow;
2232bbd136eSMasatake YAMATO 
22453dda59eSMasatake YAMATO struct lregexControlBlock {
2253afb5475SMasatake YAMATO 	int currentScope;
226134629a0SHadriel Kaplan 	ptrArray *entries [2];
227e0e33135SMasatake YAMATO 
228e0e33135SMasatake YAMATO 	ptrArray *tables;
22941e0b4f8SMasatake YAMATO 	ptrArray *tstack;
230e0e33135SMasatake YAMATO 
2316cdf5716SMasatake YAMATO 	struct guestRequest *guest_req;
2326cdf5716SMasatake YAMATO 
233e8386a4eSMasatake YAMATO 	EsObject *local_dict;
234e8386a4eSMasatake YAMATO 
235b6124a60SMasatake YAMATO 	ptrArray *hook[SCRIPT_HOOK_MAX];
236b6124a60SMasatake YAMATO 	ptrArray *hook_code[SCRIPT_HOOK_MAX];
2375c872341SMasatake YAMATO 
238bce55cc7SMasatake YAMATO 	langType owner;
2392bbd136eSMasatake YAMATO 
2402bbd136eSMasatake YAMATO 	scriptWindow *window;
241bce55cc7SMasatake YAMATO };
242bce55cc7SMasatake YAMATO 
243d4c6f1e6SMasatake YAMATO /*
244d4c6f1e6SMasatake YAMATO *   DATA DEFINITIONS
245d4c6f1e6SMasatake YAMATO */
246e8386a4eSMasatake YAMATO static OptVM *optvm;
247e8386a4eSMasatake YAMATO static EsObject *lregex_dict = es_nil;
248d4c6f1e6SMasatake YAMATO 
249d4c6f1e6SMasatake YAMATO /*
250d4c6f1e6SMasatake YAMATO *   FUNCTION DEFINITIONS
251d4c6f1e6SMasatake YAMATO */
25246837a67SHadriel Kaplan static int getTableIndexForName (const struct lregexControlBlock *const lcb, const char *name);
253134629a0SHadriel Kaplan static void deletePattern (regexPattern *p);
254b19716b4SMasatake YAMATO static int  makePromiseForAreaSpecifiedWithOffsets (const char *parser,
255b19716b4SMasatake YAMATO 													off_t startOffset,
256b19716b4SMasatake YAMATO 													off_t endOffset);
257b19716b4SMasatake YAMATO 
2586cdf5716SMasatake YAMATO static struct guestRequest *guestRequestNew (void);
2596cdf5716SMasatake YAMATO static void   guestRequestDelete (struct guestRequest *);
2606cdf5716SMasatake YAMATO static bool   guestRequestIsFilled(struct guestRequest *);
2616cdf5716SMasatake YAMATO static void   guestRequestClear (struct guestRequest *);
2626cdf5716SMasatake YAMATO static void   guestRequestSubmit (struct guestRequest *);
263d4c6f1e6SMasatake YAMATO 
264668e3666SMasatake YAMATO static EsObject *scriptRead (OptVM *vm, const char *src);
2652bbd136eSMasatake YAMATO static void scriptSetup (OptVM *vm, struct lregexControlBlock *lcb, int corkIndex, scriptWindow *window);
266668e3666SMasatake YAMATO static EsObject* scriptEval (OptVM *vm, EsObject *optscript);
267b6124a60SMasatake YAMATO static void scriptEvalHook (OptVM *vm, struct lregexControlBlock *lcb, enum scriptHook hook);
268668e3666SMasatake YAMATO static void scriptTeardown (OptVM *vm, struct lregexControlBlock *lcb);
269fba3677cSMasatake YAMATO 
27077bd99b5SMasatake YAMATO static char* make_match_string (scriptWindow *window, int group);
271cf6b3bb9SMasatake YAMATO static matchLoc *make_mloc (scriptWindow *window, int group, bool start);
27277bd99b5SMasatake YAMATO 
deleteTable(void * ptrn)273e0e33135SMasatake YAMATO static void deleteTable (void *ptrn)
274e0e33135SMasatake YAMATO {
275e0e33135SMasatake YAMATO 	struct regexTable *t = ptrn;
276e0e33135SMasatake YAMATO 
277134629a0SHadriel Kaplan 	ptrArrayDelete (t->entries);
27806a48990SMasatake YAMATO 	eFree (t->name);
279e0e33135SMasatake YAMATO 	eFree (t);
280e0e33135SMasatake YAMATO }
281e0e33135SMasatake YAMATO 
deleteTableEntry(void * ptrn)282134629a0SHadriel Kaplan static void deleteTableEntry (void *ptrn)
283c9bfc26fSMasatake YAMATO {
284134629a0SHadriel Kaplan 	regexTableEntry *e = ptrn;
285134629a0SHadriel Kaplan 	Assert (e && e->pattern);
286134629a0SHadriel Kaplan 	deletePattern (e->pattern);
287134629a0SHadriel Kaplan 	eFree (e);
288134629a0SHadriel Kaplan }
289c9bfc26fSMasatake YAMATO 
deletePattern(regexPattern * p)290134629a0SHadriel Kaplan static void deletePattern (regexPattern *p)
291134629a0SHadriel Kaplan {
2929ec7efeaSMasatake YAMATO 	p->refcount--;
2939ec7efeaSMasatake YAMATO 
2949ec7efeaSMasatake YAMATO 	if (p->refcount > 0)
2959ec7efeaSMasatake YAMATO 		return;
2969ec7efeaSMasatake YAMATO 
297c30b89acSMasatake YAMATO 	p->pattern.backend->delete_code (p->pattern.code);
298d4c6f1e6SMasatake YAMATO 
299d4c6f1e6SMasatake YAMATO 	if (p->type == PTRN_TAG)
300d4c6f1e6SMasatake YAMATO 	{
301d4c6f1e6SMasatake YAMATO 		eFree (p->u.tag.name_pattern);
302d4c6f1e6SMasatake YAMATO 		p->u.tag.name_pattern = NULL;
303d4c6f1e6SMasatake YAMATO 	}
304f53f3c39SMasatake YAMATO 
305f53f3c39SMasatake YAMATO 	if (p->fieldPatterns)
306f53f3c39SMasatake YAMATO 	{
307f53f3c39SMasatake YAMATO 		ptrArrayDelete (p->fieldPatterns);
308f53f3c39SMasatake YAMATO 		p->fieldPatterns = NULL;
309f53f3c39SMasatake YAMATO 	}
310b2c16b34SMasatake YAMATO 
3115372d785SMasatake YAMATO 	eFree (p->pattern_string);
3129a1e266aSHadriel Kaplan 
3139a1e266aSHadriel Kaplan 	if (p->message.message_string)
3149a1e266aSHadriel Kaplan 		eFree (p->message.message_string);
3159a1e266aSHadriel Kaplan 
3160d56cc8eSMasatake YAMATO 	if (p->anonymous_tag_prefix)
3170d56cc8eSMasatake YAMATO 		eFree (p->anonymous_tag_prefix);
3180d56cc8eSMasatake YAMATO 
319e8386a4eSMasatake YAMATO 	if (p->optscript)
320e8386a4eSMasatake YAMATO 		es_object_unref (p->optscript);
321e8386a4eSMasatake YAMATO 	if (p->optscript_src)
322e8386a4eSMasatake YAMATO 		eFree (p->optscript_src);
323e8386a4eSMasatake YAMATO 
324134629a0SHadriel Kaplan 	eFree (p);
325d4c6f1e6SMasatake YAMATO }
326b2c16b34SMasatake YAMATO 
clearPatternSet(struct lregexControlBlock * lcb)327b2c16b34SMasatake YAMATO static void clearPatternSet (struct lregexControlBlock *lcb)
328b2c16b34SMasatake YAMATO {
329134629a0SHadriel Kaplan 	ptrArrayClear (lcb->entries [REG_PARSER_SINGLE_LINE]);
330134629a0SHadriel Kaplan 	ptrArrayClear (lcb->entries [REG_PARSER_MULTI_LINE]);
331e0e33135SMasatake YAMATO 	ptrArrayClear (lcb->tables);
332d4c6f1e6SMasatake YAMATO }
333d4c6f1e6SMasatake YAMATO 
allocLregexControlBlock(parserDefinition * parser)334bce55cc7SMasatake YAMATO extern struct lregexControlBlock* allocLregexControlBlock (parserDefinition *parser)
335bce55cc7SMasatake YAMATO {
336bce55cc7SMasatake YAMATO 	struct lregexControlBlock *lcb = xCalloc (1, struct lregexControlBlock);
337b2c16b34SMasatake YAMATO 
338134629a0SHadriel Kaplan 	lcb->entries[REG_PARSER_SINGLE_LINE] = ptrArrayNew(deleteTableEntry);
339134629a0SHadriel Kaplan 	lcb->entries[REG_PARSER_MULTI_LINE] = ptrArrayNew(deleteTableEntry);
340e0e33135SMasatake YAMATO 	lcb->tables = ptrArrayNew(deleteTable);
34141e0b4f8SMasatake YAMATO 	lcb->tstack = ptrArrayNew(NULL);
3426cdf5716SMasatake YAMATO 	lcb->guest_req = guestRequestNew ();
343e8386a4eSMasatake YAMATO 	lcb->local_dict = es_nil;
3441409a195SMasatake YAMATO 
345b6124a60SMasatake YAMATO 	for (int i = 0; i< SCRIPT_HOOK_MAX; i++)
3461409a195SMasatake YAMATO 	{
3471409a195SMasatake YAMATO 		lcb->hook[i] = ptrArrayNew (eFree);
3481409a195SMasatake YAMATO 		lcb->hook_code[i] = ptrArrayNew ((ptrArrayDeleteFunc)es_object_unref);
3491409a195SMasatake YAMATO 	}
350bce55cc7SMasatake YAMATO 	lcb->owner = parser->id;
351b2c16b34SMasatake YAMATO 
352bce55cc7SMasatake YAMATO 	return lcb;
353bce55cc7SMasatake YAMATO }
354bce55cc7SMasatake YAMATO 
freeLregexControlBlock(struct lregexControlBlock * lcb)355bce55cc7SMasatake YAMATO extern void freeLregexControlBlock (struct lregexControlBlock* lcb)
356bce55cc7SMasatake YAMATO {
357056b32e1SMasatake YAMATO 	clearPatternSet (lcb);
358b2c16b34SMasatake YAMATO 
359134629a0SHadriel Kaplan 	ptrArrayDelete (lcb->entries [REG_PARSER_SINGLE_LINE]);
360134629a0SHadriel Kaplan 	lcb->entries [REG_PARSER_SINGLE_LINE] = NULL;
361134629a0SHadriel Kaplan 	ptrArrayDelete (lcb->entries [REG_PARSER_MULTI_LINE]);
362134629a0SHadriel Kaplan 	lcb->entries [REG_PARSER_MULTI_LINE] = NULL;
363b2c16b34SMasatake YAMATO 
364e0e33135SMasatake YAMATO 	ptrArrayDelete (lcb->tables);
365e0e33135SMasatake YAMATO 	lcb->tables = NULL;
366e0e33135SMasatake YAMATO 
36741e0b4f8SMasatake YAMATO 	ptrArrayDelete (lcb->tstack);
36841e0b4f8SMasatake YAMATO 	lcb->tstack = NULL;
36941e0b4f8SMasatake YAMATO 
3706cdf5716SMasatake YAMATO 	guestRequestDelete (lcb->guest_req);
3716cdf5716SMasatake YAMATO 	lcb->guest_req = NULL;
3726cdf5716SMasatake YAMATO 
373e8386a4eSMasatake YAMATO 	es_object_unref (lcb->local_dict);
374e8386a4eSMasatake YAMATO 	lcb->local_dict = es_nil;
375e8386a4eSMasatake YAMATO 
376b6124a60SMasatake YAMATO 	for (int i = 0; i < SCRIPT_HOOK_MAX; i++)
3771409a195SMasatake YAMATO 	{
3781409a195SMasatake YAMATO 		ptrArrayDelete (lcb->hook[i]);
3791409a195SMasatake YAMATO 		lcb->hook[i] = NULL;
3805c872341SMasatake YAMATO 
3811409a195SMasatake YAMATO 		ptrArrayDelete (lcb->hook_code[i]);
3821409a195SMasatake YAMATO 		lcb->hook_code[i] = NULL;
3831409a195SMasatake YAMATO 	}
384cda2e6c3SMasatake YAMATO 
385bce55cc7SMasatake YAMATO 	eFree (lcb);
386bce55cc7SMasatake YAMATO }
387bce55cc7SMasatake YAMATO 
388d4c6f1e6SMasatake YAMATO /*
3895dbd2e67SK.Takata *   Regex pseudo-parser
390d4c6f1e6SMasatake YAMATO */
391d4c6f1e6SMasatake YAMATO 
initRegexTag(tagEntryInfo * e,const char * name,int kindIndex,int roleIndex,int scopeIndex,int placeholder,unsigned long line,MIOPos * pos,int xtag_type)392e024ff82SHadriel Kaplan static void initRegexTag (tagEntryInfo *e,
393a114f06bSMasatake YAMATO 		const char * name, int kindIndex, int roleIndex, int scopeIndex, int placeholder,
39410db13faSMasatake YAMATO 		unsigned long line, MIOPos *pos, int xtag_type)
395d4c6f1e6SMasatake YAMATO {
396a114f06bSMasatake YAMATO 	Assert (name != NULL  &&  ((name[0] != '\0') || placeholder));
397a114f06bSMasatake YAMATO 	initRefTagEntry (e, name, kindIndex, roleIndex);
398f53f3c39SMasatake YAMATO 	e->extensionFields.scopeIndex = scopeIndex;
399f53f3c39SMasatake YAMATO 	e->placeholder = !!placeholder;
40013939209SMasatake YAMATO 	if (line)
40113939209SMasatake YAMATO 	{
402f53f3c39SMasatake YAMATO 		e->lineNumber = line;
403f53f3c39SMasatake YAMATO 		e->filePosition = *pos;
40413939209SMasatake YAMATO 	}
40513939209SMasatake YAMATO 
40610db13faSMasatake YAMATO 	if (xtag_type != XTAG_UNKNOWN)
407f53f3c39SMasatake YAMATO 		markTagExtraBit (e, xtag_type);
408d4c6f1e6SMasatake YAMATO }
409d4c6f1e6SMasatake YAMATO 
410d4c6f1e6SMasatake YAMATO /*
411d4c6f1e6SMasatake YAMATO *   Regex pattern definition
412d4c6f1e6SMasatake YAMATO */
413d4c6f1e6SMasatake YAMATO 
414d4c6f1e6SMasatake YAMATO /* Take a string like "/blah/" and turn it into "blah", making sure
415d4c6f1e6SMasatake YAMATO  * that the first and last characters are the same, and handling
416d4c6f1e6SMasatake YAMATO  * quoted separator characters.  Actually, stops on the occurrence of
417d4c6f1e6SMasatake YAMATO  * an unquoted separator.  Also turns "\t" into a Tab character.
418641e337aSMasatake YAMATO  * Turns "\n" into a Newline character if MULTILINE is true.
419d4c6f1e6SMasatake YAMATO  * Returns pointer to terminating separator.  Works in place.  Null
420d4c6f1e6SMasatake YAMATO  * terminates name string.
421d4c6f1e6SMasatake YAMATO  */
scanSeparators(char * name,bool multiline)42263611edeSMasatake YAMATO static char* scanSeparators (char* name, bool multiline)
423d4c6f1e6SMasatake YAMATO {
424d4c6f1e6SMasatake YAMATO 	char sep = name [0];
425d4c6f1e6SMasatake YAMATO 	char *copyto = name;
426ce990805SThomas Braun 	bool quoted = false;
427d4c6f1e6SMasatake YAMATO 
428d4c6f1e6SMasatake YAMATO 	for (++name ; *name != '\0' ; ++name)
429d4c6f1e6SMasatake YAMATO 	{
430d4c6f1e6SMasatake YAMATO 		if (quoted)
431d4c6f1e6SMasatake YAMATO 		{
432d4c6f1e6SMasatake YAMATO 			if (*name == sep)
433d4c6f1e6SMasatake YAMATO 				*copyto++ = sep;
434d4c6f1e6SMasatake YAMATO 			else if (*name == 't')
435d4c6f1e6SMasatake YAMATO 				*copyto++ = '\t';
43663611edeSMasatake YAMATO 			else if (multiline && *name == 'n')
437641e337aSMasatake YAMATO 				*copyto++ = '\n';
438d4c6f1e6SMasatake YAMATO 			else
439d4c6f1e6SMasatake YAMATO 			{
440d4c6f1e6SMasatake YAMATO 				/* Something else is quoted, so preserve the quote. */
441d4c6f1e6SMasatake YAMATO 				*copyto++ = '\\';
442d4c6f1e6SMasatake YAMATO 				*copyto++ = *name;
443d4c6f1e6SMasatake YAMATO 			}
444ce990805SThomas Braun 			quoted = false;
445d4c6f1e6SMasatake YAMATO 		}
446d4c6f1e6SMasatake YAMATO 		else if (*name == '\\')
447ce990805SThomas Braun 			quoted = true;
448d4c6f1e6SMasatake YAMATO 		else if (*name == sep)
449d4c6f1e6SMasatake YAMATO 		{
450d4c6f1e6SMasatake YAMATO 			break;
451d4c6f1e6SMasatake YAMATO 		}
452d4c6f1e6SMasatake YAMATO 		else
453d4c6f1e6SMasatake YAMATO 			*copyto++ = *name;
454d4c6f1e6SMasatake YAMATO 	}
455d4c6f1e6SMasatake YAMATO 	*copyto = '\0';
456d4c6f1e6SMasatake YAMATO 	return name;
457d4c6f1e6SMasatake YAMATO }
458d4c6f1e6SMasatake YAMATO 
459d4c6f1e6SMasatake YAMATO /* Parse `regexp', in form "/regex/name/[k,Kind/]flags" (where the separator
460d4c6f1e6SMasatake YAMATO  * character is whatever the first character of `regexp' is), by breaking it
461d4c6f1e6SMasatake YAMATO  * up into null terminated strings, removing the separators, and expanding
462d4c6f1e6SMasatake YAMATO  * '\t' into tabs. When complete, `regexp' points to the line matching
463d4c6f1e6SMasatake YAMATO  * pattern, a pointer to the name matching pattern is written to `name', a
464d4c6f1e6SMasatake YAMATO  * pointer to the kinds is written to `kinds' (possibly NULL), and a pointer
465d4c6f1e6SMasatake YAMATO  * to the trailing flags is written to `flags'. If the pattern is not in the
466d4c6f1e6SMasatake YAMATO  * correct format, a false value is returned.
467d4c6f1e6SMasatake YAMATO  */
parseTagRegex(enum regexParserType regptype,char * const regexp,char ** const name,char ** const kinds,char ** const flags)468ce990805SThomas Braun static bool parseTagRegex (
4691b9c3aecSMasatake YAMATO 		enum regexParserType regptype,
470d4c6f1e6SMasatake YAMATO 		char* const regexp, char** const name,
471d4c6f1e6SMasatake YAMATO 		char** const kinds, char** const flags)
472d4c6f1e6SMasatake YAMATO {
473ce990805SThomas Braun 	bool result = false;
474d4c6f1e6SMasatake YAMATO 	const int separator = (unsigned char) regexp [0];
475d4c6f1e6SMasatake YAMATO 
47663611edeSMasatake YAMATO 	*name = scanSeparators (regexp, (regptype == REG_PARSER_MULTI_LINE
47763611edeSMasatake YAMATO 									 || regptype == REG_PARSER_MULTI_TABLE));
478d4c6f1e6SMasatake YAMATO 	if (*regexp == '\0')
479d4c6f1e6SMasatake YAMATO 		error (WARNING, "empty regexp");
480d4c6f1e6SMasatake YAMATO 	else if (**name != separator)
481d4c6f1e6SMasatake YAMATO 		error (WARNING, "%s: incomplete regexp", regexp);
482d4c6f1e6SMasatake YAMATO 	else
483d4c6f1e6SMasatake YAMATO 	{
484641e337aSMasatake YAMATO 		char* const third = scanSeparators (*name, false);
48512ddaaa3SMasatake YAMATO 		if (**name != '\0' && (*name) [strlen (*name) - 1] == '\\')
486d4c6f1e6SMasatake YAMATO 			error (WARNING, "error in name pattern: \"%s\"", *name);
487d4c6f1e6SMasatake YAMATO 		if (*third != separator)
488d4c6f1e6SMasatake YAMATO 			error (WARNING, "%s: regexp missing final separator", regexp);
489d4c6f1e6SMasatake YAMATO 		else
490d4c6f1e6SMasatake YAMATO 		{
491b8e4238dSMasatake YAMATO 			/*
492b8e4238dSMasatake YAMATO 			 * first----------V third------------V
493162e9f15SMasatake YAMATO 			 * --regex-<LANG>=/regexp/replacement/[kind-spec/][flags][{{\n...\n}}]
494b8e4238dSMasatake YAMATO 			 * second----------------^ fourth---------------^
495b8e4238dSMasatake YAMATO 			 */
496b8e4238dSMasatake YAMATO 
497162e9f15SMasatake YAMATO 			/*
498162e9f15SMasatake YAMATO 			 * The following code assumes "{{\n" is never used in flags.
499162e9f15SMasatake YAMATO 			 * If the input comes from the command line or an optlib file,
500162e9f15SMasatake YAMATO 			 * this assumption is always correct; a new line character is never
501162e9f15SMasatake YAMATO 			 * put at the middle (or end) of the input.
502162e9f15SMasatake YAMATO 			 *
503162e9f15SMasatake YAMATO 			 * TODO: How about the input comes from the source code translated
504162e9f15SMasatake YAMATO 			 * by optlib2c?
505162e9f15SMasatake YAMATO 			 */
506162e9f15SMasatake YAMATO 			char *script = strstr (third, "{{\n");
507162e9f15SMasatake YAMATO 			if (script)
508162e9f15SMasatake YAMATO 			{
509162e9f15SMasatake YAMATO 				/* The script part should not be unescaed by scanSeparators().
510162e9f15SMasatake YAMATO 				 * By spitting the string, we can hide the script part from
511162e9f15SMasatake YAMATO 				 * scanSeparators(). */
512162e9f15SMasatake YAMATO 				script [0] = '\0';
513162e9f15SMasatake YAMATO 			}
514162e9f15SMasatake YAMATO 
515641e337aSMasatake YAMATO 			char* const fourth = scanSeparators (third, false);
516d4c6f1e6SMasatake YAMATO 			if (*fourth == separator)
517d4c6f1e6SMasatake YAMATO 			{
518d4c6f1e6SMasatake YAMATO 				*kinds = third;
519641e337aSMasatake YAMATO 				scanSeparators (fourth, false);
520d4c6f1e6SMasatake YAMATO 				*flags = fourth;
521d4c6f1e6SMasatake YAMATO 			}
522d4c6f1e6SMasatake YAMATO 			else
523d4c6f1e6SMasatake YAMATO 			{
524d4c6f1e6SMasatake YAMATO 				*flags = third;
525d4c6f1e6SMasatake YAMATO 				*kinds = NULL;
526d4c6f1e6SMasatake YAMATO 			}
527162e9f15SMasatake YAMATO 
528162e9f15SMasatake YAMATO 			if (script)
529162e9f15SMasatake YAMATO 			{
530162e9f15SMasatake YAMATO 				Assert (*flags);
531162e9f15SMasatake YAMATO 
532162e9f15SMasatake YAMATO 				char *end = *flags + strlen (*flags);
533162e9f15SMasatake YAMATO 				script [0] = '{';
534162e9f15SMasatake YAMATO 				if (end != script)
535162e9f15SMasatake YAMATO 				{
536162e9f15SMasatake YAMATO 					size_t len = strlen (script);
537162e9f15SMasatake YAMATO 					memmove (end, script, len);
538162e9f15SMasatake YAMATO 					end [len] = '\0';
539162e9f15SMasatake YAMATO 				}
540162e9f15SMasatake YAMATO 			}
541162e9f15SMasatake YAMATO 
542ce990805SThomas Braun 			result = true;
543d4c6f1e6SMasatake YAMATO 		}
544d4c6f1e6SMasatake YAMATO 	}
545d4c6f1e6SMasatake YAMATO 	return result;
546d4c6f1e6SMasatake YAMATO }
547d4c6f1e6SMasatake YAMATO 
548d4c6f1e6SMasatake YAMATO 
pre_ptrn_flag_exclusive_short(char c CTAGS_ATTR_UNUSED,void * data)5498ccb7ee9SJiří Techet static void pre_ptrn_flag_exclusive_short (char c CTAGS_ATTR_UNUSED, void* data)
550d4c6f1e6SMasatake YAMATO {
551ce990805SThomas Braun 	bool *exclusive = data;
552ce990805SThomas Braun 	*exclusive = true;
553d4c6f1e6SMasatake YAMATO }
554d4c6f1e6SMasatake YAMATO 
pre_ptrn_flag_exclusive_long(const char * const s CTAGS_ATTR_UNUSED,const char * const unused CTAGS_ATTR_UNUSED,void * data)5558ccb7ee9SJiří Techet static void pre_ptrn_flag_exclusive_long (const char* const s CTAGS_ATTR_UNUSED, const char* const unused CTAGS_ATTR_UNUSED, void* data)
556d4c6f1e6SMasatake YAMATO {
5575fdabf71SMasatake YAMATO 	pre_ptrn_flag_exclusive_short ('x', data);
558d4c6f1e6SMasatake YAMATO }
559d4c6f1e6SMasatake YAMATO 
5605fdabf71SMasatake YAMATO static flagDefinition prePtrnFlagDef[] = {
5613fac0fc6SMasatake YAMATO 	{ 'x',  "exclusive", pre_ptrn_flag_exclusive_short, pre_ptrn_flag_exclusive_long ,
5623fac0fc6SMasatake YAMATO 	  NULL, "skip testing the other patterns if a line is matched to this pattern"},
5635fdabf71SMasatake YAMATO };
5645fdabf71SMasatake YAMATO 
scope_ptrn_flag_eval(const char * const f CTAGS_ATTR_UNUSED,const char * const v,void * data)5658ccb7ee9SJiří Techet static void scope_ptrn_flag_eval (const char* const f  CTAGS_ATTR_UNUSED,
5662fa3c9e1SMasatake YAMATO 				  const char* const v, void* data)
5672fa3c9e1SMasatake YAMATO {
568c2bd0a7eSMasatake YAMATO 	unsigned int *bfields = data;
5692fa3c9e1SMasatake YAMATO 
5702fa3c9e1SMasatake YAMATO 	if (strcmp (v, "ref") == 0)
5712fa3c9e1SMasatake YAMATO 		*bfields |= SCOPE_REF;
5722fa3c9e1SMasatake YAMATO 	else if (strcmp (v, "push") == 0)
5732fa3c9e1SMasatake YAMATO 		*bfields |= (SCOPE_PUSH | SCOPE_REF);
5742fa3c9e1SMasatake YAMATO 	else if (strcmp (v, "pop") == 0)
5752fa3c9e1SMasatake YAMATO 		*bfields |= SCOPE_POP;
5762fa3c9e1SMasatake YAMATO 	else if (strcmp (v, "clear") == 0)
5772fa3c9e1SMasatake YAMATO 		*bfields |= SCOPE_CLEAR;
5782fa3c9e1SMasatake YAMATO 	else if (strcmp (v, "set") == 0)
5792fa3c9e1SMasatake YAMATO 		*bfields |= (SCOPE_CLEAR | SCOPE_PUSH);
580f998e51dSMasatake YAMATO 	else if (strcmp (v, "replace") == 0)
581f998e51dSMasatake YAMATO 		*bfields |= (SCOPE_POP|SCOPE_REF_AFTER_POP|SCOPE_PUSH);
5822fa3c9e1SMasatake YAMATO 	else
5832fa3c9e1SMasatake YAMATO 		error (FATAL, "Unexpected value for scope flag in regex definition: scope=%s", v);
5842fa3c9e1SMasatake YAMATO }
5852fa3c9e1SMasatake YAMATO 
placeholder_ptrn_flag_eval(const char * const f CTAGS_ATTR_UNUSED,const char * const v CTAGS_ATTR_UNUSED,void * data)5868ccb7ee9SJiří Techet static void placeholder_ptrn_flag_eval (const char* const f  CTAGS_ATTR_UNUSED,
5878ccb7ee9SJiří Techet 				     const char* const v  CTAGS_ATTR_UNUSED, void* data)
588b593f516SMasatake YAMATO {
589c2bd0a7eSMasatake YAMATO 	unsigned int *bfields = data;
590b593f516SMasatake YAMATO 	*bfields |= SCOPE_PLACEHOLDER;
591b593f516SMasatake YAMATO }
592b593f516SMasatake YAMATO 
5932fa3c9e1SMasatake YAMATO static flagDefinition scopePtrnFlagDef[] = {
5942fa3c9e1SMasatake YAMATO 	{ '\0', "scope",     NULL, scope_ptrn_flag_eval,
595f998e51dSMasatake YAMATO 	  "ACTION", "use scope stack: ACTION = ref|push|pop|clear|set|replace"},
596b593f516SMasatake YAMATO 	{ '\0', "placeholder",  NULL, placeholder_ptrn_flag_eval,
597b593f516SMasatake YAMATO 	  NULL, "don't put this tag to tags file."},
5982fa3c9e1SMasatake YAMATO };
5992fa3c9e1SMasatake YAMATO 
kindNew(char letter,const char * name,const char * description)600fbcb3274SMasatake YAMATO static kindDefinition *kindNew (char letter, const char *name, const char *description)
601a4e7ab31SMasatake YAMATO {
602fbcb3274SMasatake YAMATO 	kindDefinition *kdef = xCalloc (1, kindDefinition);
603fbcb3274SMasatake YAMATO 	kdef->letter        = letter;
604691d5f94SMasatake YAMATO 	kdef->name = eStrdup (name);
605fbcb3274SMasatake YAMATO 	kdef->description = eStrdup(description? description: kdef->name);
606fbcb3274SMasatake YAMATO 	kdef->enabled = true;
607fbcb3274SMasatake YAMATO 	return kdef;
608a4e7ab31SMasatake YAMATO }
609a4e7ab31SMasatake YAMATO 
kindFree(kindDefinition * kind)610fbcb3274SMasatake YAMATO static void kindFree (kindDefinition *kind)
611a4e7ab31SMasatake YAMATO {
612a4e7ab31SMasatake YAMATO 	kind->letter = '\0';
6135705d883SMasatake YAMATO 	eFree ((void *)kind->name);
614a4e7ab31SMasatake YAMATO 	kind->name = NULL;
6155705d883SMasatake YAMATO 	eFree ((void *)kind->description);
616a4e7ab31SMasatake YAMATO 	kind->description = NULL;
617a4e7ab31SMasatake YAMATO 	eFree (kind);
618a4e7ab31SMasatake YAMATO }
619a4e7ab31SMasatake YAMATO 
initMgroup(struct mGroupSpec * mgroup)620b2c16b34SMasatake YAMATO static void initMgroup(struct mGroupSpec *mgroup)
621b2c16b34SMasatake YAMATO {
622b2c16b34SMasatake YAMATO 	mgroup->forLineNumberDetermination = NO_MULTILINE;
623b2c16b34SMasatake YAMATO 	mgroup->forNextScanning = NO_MULTILINE;
624b2c16b34SMasatake YAMATO 	mgroup->nextFromStart = false;
625b2c16b34SMasatake YAMATO }
626b2c16b34SMasatake YAMATO 
initGuestSpec(struct guestSpec * guest)6276cdf5716SMasatake YAMATO static void initGuestSpec (struct guestSpec *guest)
6286cdf5716SMasatake YAMATO {
6296cdf5716SMasatake YAMATO 	guest->lang.type = GUEST_LANG_UNKNOWN;
6306cdf5716SMasatake YAMATO }
6316cdf5716SMasatake YAMATO 
initTaction(struct mTableActionSpec * taction)6320cbf3f0dSMasatake YAMATO static void initTaction(struct mTableActionSpec *taction)
6330cbf3f0dSMasatake YAMATO {
6340cbf3f0dSMasatake YAMATO 	taction->action = TACTION_NOP;
6350cbf3f0dSMasatake YAMATO 	taction->table = NULL;
6360cbf3f0dSMasatake YAMATO }
6370cbf3f0dSMasatake YAMATO 
refPattern(regexPattern * ptrn)638bf809d1aSMasatake YAMATO static regexPattern * refPattern (regexPattern * ptrn)
639bf809d1aSMasatake YAMATO {
640bf809d1aSMasatake YAMATO 	ptrn->refcount++;
641bf809d1aSMasatake YAMATO 	return ptrn;
642bf809d1aSMasatake YAMATO }
643bf809d1aSMasatake YAMATO 
newPattern(regexCompiledCode * const pattern,enum regexParserType regptype)644c30b89acSMasatake YAMATO static regexPattern * newPattern (regexCompiledCode* const pattern,
645b2c16b34SMasatake YAMATO 								  enum regexParserType regptype)
646b2c16b34SMasatake YAMATO {
647b2c16b34SMasatake YAMATO 	regexPattern *ptrn = xCalloc(1, regexPattern);
648b2c16b34SMasatake YAMATO 
649c30b89acSMasatake YAMATO 	ptrn->pattern.backend = pattern->backend;
650c30b89acSMasatake YAMATO 	ptrn->pattern.code = pattern->code;
651c30b89acSMasatake YAMATO 
652b2c16b34SMasatake YAMATO 	ptrn->exclusive = false;
653b2c16b34SMasatake YAMATO 	ptrn->accept_empty_name = false;
654b2c16b34SMasatake YAMATO 	ptrn->regptype = regptype;
655f74a98d6SHadriel Kaplan 	ptrn->xtagType = XTAG_UNKNOWN;
656b2c16b34SMasatake YAMATO 
657b2c16b34SMasatake YAMATO 	if (regptype == REG_PARSER_MULTI_LINE)
658b2c16b34SMasatake YAMATO 		initMgroup(&ptrn->mgroup);
6590cbf3f0dSMasatake YAMATO 	if (regptype == REG_PARSER_MULTI_TABLE)
6600cbf3f0dSMasatake YAMATO 		initTaction(&ptrn->taction);
6616cdf5716SMasatake YAMATO 	initGuestSpec (&ptrn->guest);
662b2c16b34SMasatake YAMATO 
66384f3a057SMasatake YAMATO 	ptrn->u.tag.roleBits = 0;
6649ec7efeaSMasatake YAMATO 	ptrn->refcount = 1;
665e8386a4eSMasatake YAMATO 
666e8386a4eSMasatake YAMATO 	ptrn->optscript = NULL;
667e8386a4eSMasatake YAMATO 	ptrn->optscript_src = NULL;
668e8386a4eSMasatake YAMATO 
669b2c16b34SMasatake YAMATO 	return ptrn;
670b2c16b34SMasatake YAMATO }
671b2c16b34SMasatake YAMATO 
newRefPatternEntry(regexTableEntry * other)672134629a0SHadriel Kaplan static regexTableEntry * newRefPatternEntry (regexTableEntry * other)
673134629a0SHadriel Kaplan {
674134629a0SHadriel Kaplan 	regexTableEntry *entry = xCalloc (1, regexTableEntry);
675134629a0SHadriel Kaplan 
676134629a0SHadriel Kaplan 	Assert (other && other->pattern);
677134629a0SHadriel Kaplan 
678134629a0SHadriel Kaplan 	entry->pattern = refPattern(other->pattern);
679134629a0SHadriel Kaplan 	return entry;
680134629a0SHadriel Kaplan }
681134629a0SHadriel Kaplan 
newEntry(regexCompiledCode * const pattern,enum regexParserType regptype)682c30b89acSMasatake YAMATO static regexTableEntry * newEntry (regexCompiledCode* const pattern,
683134629a0SHadriel Kaplan 								   enum regexParserType regptype)
684134629a0SHadriel Kaplan {
685134629a0SHadriel Kaplan 	regexTableEntry *entry = xCalloc (1, regexTableEntry);
686134629a0SHadriel Kaplan 	entry->pattern = newPattern (pattern, regptype);
687134629a0SHadriel Kaplan 	return entry;
688134629a0SHadriel Kaplan }
689134629a0SHadriel Kaplan 
addCompiledTagCommon(struct lregexControlBlock * lcb,int table_index,regexCompiledCode * const pattern,enum regexParserType regptype)69053dda59eSMasatake YAMATO static regexPattern* addCompiledTagCommon (struct lregexControlBlock *lcb,
6910cbf3f0dSMasatake YAMATO 										   int table_index,
692c30b89acSMasatake YAMATO 										   regexCompiledCode* const pattern,
6931b9c3aecSMasatake YAMATO 										   enum regexParserType regptype)
694d4c6f1e6SMasatake YAMATO {
695134629a0SHadriel Kaplan 	regexTableEntry *entry = newEntry (pattern, regptype);
696a4e7ab31SMasatake YAMATO 
6970cbf3f0dSMasatake YAMATO 	if (regptype == REG_PARSER_MULTI_TABLE)
6980cbf3f0dSMasatake YAMATO 	{
6990cbf3f0dSMasatake YAMATO 		struct regexTable *table = ptrArrayItem (lcb->tables, table_index);
7000cbf3f0dSMasatake YAMATO 		Assert(table);
7010cbf3f0dSMasatake YAMATO 
702134629a0SHadriel Kaplan 		ptrArrayAdd (table->entries, entry);
7030cbf3f0dSMasatake YAMATO 	}
7040cbf3f0dSMasatake YAMATO 	else
705134629a0SHadriel Kaplan 		ptrArrayAdd (lcb->entries[regptype], entry);
706d4c6f1e6SMasatake YAMATO 
70753dda59eSMasatake YAMATO 	useRegexMethod(lcb->owner);
708c9bfc26fSMasatake YAMATO 
709134629a0SHadriel Kaplan 	return entry->pattern;
710d4c6f1e6SMasatake YAMATO }
711d4c6f1e6SMasatake YAMATO 
pre_ptrn_flag_mgroup_long(const char * const s,const char * const v,void * data)712e77d0926SMasatake YAMATO static void pre_ptrn_flag_mgroup_long (const char* const s, const char* const v, void* data)
71313939209SMasatake YAMATO {
714c9bfc26fSMasatake YAMATO 	struct mGroupSpec *mgroup = data;
715ed569600SMasatake YAMATO 	if (!v)
716ed569600SMasatake YAMATO 	{
717ed569600SMasatake YAMATO 		error (WARNING, "no value is given for: %s", s);
718ed569600SMasatake YAMATO 		return;
719ed569600SMasatake YAMATO 	}
720c9bfc26fSMasatake YAMATO 	if (!strToInt (v, 10, &mgroup->forLineNumberDetermination))
72113939209SMasatake YAMATO 	{
722c9bfc26fSMasatake YAMATO 		error (WARNING, "wrong %s specification: %s", s, v);
723c9bfc26fSMasatake YAMATO 		mgroup->forLineNumberDetermination = NO_MULTILINE;
72413939209SMasatake YAMATO 	}
725c9bfc26fSMasatake YAMATO 	else if (mgroup->forLineNumberDetermination < 0
726c9bfc26fSMasatake YAMATO 			 || mgroup->forLineNumberDetermination >= BACK_REFERENCE_COUNT)
72713939209SMasatake YAMATO 	{
728c9bfc26fSMasatake YAMATO 		error (WARNING, "out of range(0 ~ %d) %s specification: %s",
729c9bfc26fSMasatake YAMATO 			   (BACK_REFERENCE_COUNT - 1),
730c9bfc26fSMasatake YAMATO 			   s, v);
731c9bfc26fSMasatake YAMATO 		mgroup->forLineNumberDetermination = NO_MULTILINE;
73213939209SMasatake YAMATO 	}
733c9bfc26fSMasatake YAMATO }
734c9bfc26fSMasatake YAMATO 
pre_ptrn_flag_advanceTo_long(const char * const s,const char * const v,void * data)735c9bfc26fSMasatake YAMATO static void pre_ptrn_flag_advanceTo_long (const char* const s, const char* const v, void* data)
736c9bfc26fSMasatake YAMATO {
737c9bfc26fSMasatake YAMATO 	struct mGroupSpec *mgroup = data;
738c9bfc26fSMasatake YAMATO 	char *vdup;
739c9bfc26fSMasatake YAMATO 	char *tmp;
740c9bfc26fSMasatake YAMATO 
741c9bfc26fSMasatake YAMATO 
742c9bfc26fSMasatake YAMATO 	if (!v)
743c9bfc26fSMasatake YAMATO 	{
744c9bfc26fSMasatake YAMATO 		error (WARNING, "no value is given for: %s", s);
745c9bfc26fSMasatake YAMATO 		return;
746c9bfc26fSMasatake YAMATO 	}
747c9bfc26fSMasatake YAMATO 
748c9bfc26fSMasatake YAMATO 	vdup = eStrdup (v);
749c9bfc26fSMasatake YAMATO 
750c9bfc26fSMasatake YAMATO 	mgroup->nextFromStart = false;
751c9bfc26fSMasatake YAMATO 	if ((tmp = strstr(vdup, "start")))
752c9bfc26fSMasatake YAMATO 	{
753c9bfc26fSMasatake YAMATO 		mgroup->nextFromStart = true;
754c9bfc26fSMasatake YAMATO 		*tmp = '\0';
755c9bfc26fSMasatake YAMATO 	}
756c9bfc26fSMasatake YAMATO 	else if ((tmp = strstr(vdup, "end")))
757c9bfc26fSMasatake YAMATO 		*tmp = '\0';
758c9bfc26fSMasatake YAMATO 
759c9bfc26fSMasatake YAMATO 	if (!strToInt (vdup, 10, &(mgroup->forNextScanning)))
760c9bfc26fSMasatake YAMATO 	{
761c9bfc26fSMasatake YAMATO 		error (WARNING, "wrong %s specification: %s", s, vdup);
762c9bfc26fSMasatake YAMATO 		mgroup->nextFromStart = false;
763c9bfc26fSMasatake YAMATO 	}
764c9bfc26fSMasatake YAMATO 	else if (mgroup->forNextScanning < 0 || mgroup->forNextScanning >= BACK_REFERENCE_COUNT)
765c9bfc26fSMasatake YAMATO 	{
766c9bfc26fSMasatake YAMATO 		error (WARNING, "out of range(0 ~ %d) %s specification: %s",
767c9bfc26fSMasatake YAMATO 			   (BACK_REFERENCE_COUNT - 1), s, vdup);
768c9bfc26fSMasatake YAMATO 		mgroup->nextFromStart = false;
769c9bfc26fSMasatake YAMATO 	}
770c9bfc26fSMasatake YAMATO 
771c9bfc26fSMasatake YAMATO 	eFree (vdup);
77213939209SMasatake YAMATO }
77313939209SMasatake YAMATO 
7746cdf5716SMasatake YAMATO struct guestPtrnFlagData {
7756cdf5716SMasatake YAMATO 	enum regexParserType type;
7766cdf5716SMasatake YAMATO 	struct guestSpec *guest;
7776cdf5716SMasatake YAMATO };
7786cdf5716SMasatake YAMATO 
pre_ptrn_flag_guest_long(const char * const s,const char * const v,void * data)7796cdf5716SMasatake YAMATO static void pre_ptrn_flag_guest_long (const char* const s, const char* const v, void* data)
7806cdf5716SMasatake YAMATO {
7816cdf5716SMasatake YAMATO 	struct guestPtrnFlagData *flagData = data;
7826cdf5716SMasatake YAMATO 	enum regexParserType type = flagData->type;
7836cdf5716SMasatake YAMATO 	struct guestSpec *guest = flagData->guest;
7846cdf5716SMasatake YAMATO 	struct boundarySpec *current;
7856cdf5716SMasatake YAMATO 
7866cdf5716SMasatake YAMATO 	if (!v)
7876cdf5716SMasatake YAMATO 	{
7886cdf5716SMasatake YAMATO 		error (WARNING, "no value is given for: %s", s);
7896cdf5716SMasatake YAMATO 		return;
7906cdf5716SMasatake YAMATO 	}
7916cdf5716SMasatake YAMATO 
7926cdf5716SMasatake YAMATO 	char *tmp = strchr (v, ',');
7936cdf5716SMasatake YAMATO 	if (tmp == NULL)
7946cdf5716SMasatake YAMATO 	{
7956cdf5716SMasatake YAMATO 		error (WARNING, "no terminator found for parser name: %s", s);
7966cdf5716SMasatake YAMATO 		return;
7976cdf5716SMasatake YAMATO 	}
7986cdf5716SMasatake YAMATO 
7996cdf5716SMasatake YAMATO 	if ((tmp - v) == 0)
8006cdf5716SMasatake YAMATO 	{
8016cdf5716SMasatake YAMATO 		if (type == REG_PARSER_MULTI_LINE)
8026cdf5716SMasatake YAMATO 		{
8036cdf5716SMasatake YAMATO 			error (WARNING,
8046cdf5716SMasatake YAMATO 				   "using placeholder for guest name field is not allowed in multiline regex spec: %s", v);
8056cdf5716SMasatake YAMATO 			goto err;
8066cdf5716SMasatake YAMATO 		}
8076cdf5716SMasatake YAMATO 
8086cdf5716SMasatake YAMATO 		guest->lang.type = GUEST_LANG_PLACEHOLDER;
8096cdf5716SMasatake YAMATO 	}
8106cdf5716SMasatake YAMATO 	else if (*v == '\\' || *v == '*')
8116cdf5716SMasatake YAMATO 	{
8126cdf5716SMasatake YAMATO 		const char *n_tmp = v + 1;
8136cdf5716SMasatake YAMATO 		const char *n = n_tmp;
8146cdf5716SMasatake YAMATO 		for (; isdigit (*n_tmp); n_tmp++);
8156cdf5716SMasatake YAMATO 		char c = *n_tmp;
8166cdf5716SMasatake YAMATO 		*(char *)n_tmp = '\0';
8176cdf5716SMasatake YAMATO 		if (!strToInt (n, 10, &(guest->lang.spec.patternGroup)))
8186cdf5716SMasatake YAMATO 		{
8196cdf5716SMasatake YAMATO 			error (WARNING, "wrong guest name specification: %s", v);
8206cdf5716SMasatake YAMATO 			goto err;
8216cdf5716SMasatake YAMATO 		}
8226cdf5716SMasatake YAMATO 		else if (guest->lang.spec.patternGroup >= BACK_REFERENCE_COUNT)
8236cdf5716SMasatake YAMATO 		{
8246cdf5716SMasatake YAMATO 			error (WARNING, "wrong guest name specification (back reference count is too large): %d",
8256cdf5716SMasatake YAMATO 				   guest->lang.spec.patternGroup);
8266cdf5716SMasatake YAMATO 			goto err;
8276cdf5716SMasatake YAMATO 		}
8286cdf5716SMasatake YAMATO 
8296cdf5716SMasatake YAMATO 		*(char *)n_tmp = c;
8306cdf5716SMasatake YAMATO 		if (*n_tmp != ',')
8316cdf5716SMasatake YAMATO 		{
8326cdf5716SMasatake YAMATO 			error (WARNING, "wrong guest specification (garbage at the end of end guest spec): %s", v);
8336cdf5716SMasatake YAMATO 			goto err;
8346cdf5716SMasatake YAMATO 		}
8356cdf5716SMasatake YAMATO 
8366cdf5716SMasatake YAMATO 		guest->lang.type = (*v == '\\')
8376cdf5716SMasatake YAMATO 			? GUEST_LANG_PTN_GROUP_FOR_LANGNAME
8386cdf5716SMasatake YAMATO 			: GUEST_LANG_PTN_GROUP_FOR_FILEMAP;
8396cdf5716SMasatake YAMATO 	}
8406cdf5716SMasatake YAMATO 	else
8416cdf5716SMasatake YAMATO 	{
842*6024deefSMasatake YAMATO 		guest->lang.spec.lang = getNamedLanguageOrAlias (v, (tmp - v));
8436cdf5716SMasatake YAMATO 		if (guest->lang.spec.lang == LANG_IGNORE)
8446cdf5716SMasatake YAMATO 		{
8456cdf5716SMasatake YAMATO 			error (WARNING, "no parser found for the guest spec: %s", v);
8466cdf5716SMasatake YAMATO 			goto err;
8476cdf5716SMasatake YAMATO 		}
8486cdf5716SMasatake YAMATO 		guest->lang.type = GUEST_LANG_STATIC_LANGNAME;
8496cdf5716SMasatake YAMATO 	}
8506cdf5716SMasatake YAMATO 
8516cdf5716SMasatake YAMATO 	tmp++;
8526cdf5716SMasatake YAMATO 	if (*tmp == '\0')
8536cdf5716SMasatake YAMATO 	{
8546cdf5716SMasatake YAMATO 		error (WARNING, "no area spec found in the guest spec: %s", v);
8556cdf5716SMasatake YAMATO 		goto err;
8566cdf5716SMasatake YAMATO 	}
8576cdf5716SMasatake YAMATO 
8586cdf5716SMasatake YAMATO 	for (int i = 0; i < 2; i++)
8596cdf5716SMasatake YAMATO 	{
8606cdf5716SMasatake YAMATO 		current = guest->boundary + i;
8616cdf5716SMasatake YAMATO 		const char *current_field_str = (i == BOUNDARY_START? "start": "end");
8626cdf5716SMasatake YAMATO 
8636cdf5716SMasatake YAMATO 		if (tmp [0] == ((i == BOUNDARY_START)? ',': '\0'))
8646cdf5716SMasatake YAMATO 		{
8656cdf5716SMasatake YAMATO 			if (type == REG_PARSER_MULTI_LINE)
8666cdf5716SMasatake YAMATO 				error (WARNING,
8676cdf5716SMasatake YAMATO 					   "using placeholder for %s field is not allowed in multiline regex spec: %s",
8686cdf5716SMasatake YAMATO 					   current_field_str, v);
8696cdf5716SMasatake YAMATO 
8706cdf5716SMasatake YAMATO 			current->placeholder = true;
8716cdf5716SMasatake YAMATO 		}
8726cdf5716SMasatake YAMATO 		else
8736cdf5716SMasatake YAMATO 		{
8746cdf5716SMasatake YAMATO 			char *n = tmp;
8756cdf5716SMasatake YAMATO 
8766cdf5716SMasatake YAMATO 			for (; isdigit (*tmp); tmp++);
8776cdf5716SMasatake YAMATO 			char c = *tmp;
8786cdf5716SMasatake YAMATO 			*tmp = '\0';
8796cdf5716SMasatake YAMATO 			if (!strToInt (n, 10, &(current->patternGroup)))
8806cdf5716SMasatake YAMATO 			{
8816cdf5716SMasatake YAMATO 				error (WARNING, "wrong guest area specification (patternGroup of %s, number expected): %s:%s",
8826cdf5716SMasatake YAMATO 					   current_field_str, v, n);
8836cdf5716SMasatake YAMATO 				goto err;
8846cdf5716SMasatake YAMATO 			}
8856cdf5716SMasatake YAMATO 			*tmp = c;
8866cdf5716SMasatake YAMATO 			if (*tmp == '\0')
8876cdf5716SMasatake YAMATO 			{
8886cdf5716SMasatake YAMATO 				error (WARNING, "wrong guest area specification (patternGroup of %s, nether start nor end given): %s",
8896cdf5716SMasatake YAMATO 					   current_field_str, v);
8906cdf5716SMasatake YAMATO 				goto err;
8916cdf5716SMasatake YAMATO 			}
8926cdf5716SMasatake YAMATO 			else if (strncmp (tmp, "start", 5) == 0)
8936cdf5716SMasatake YAMATO 			{
8946cdf5716SMasatake YAMATO 				current->fromStartOfGroup = true;
8956cdf5716SMasatake YAMATO 				tmp += 5;
8966cdf5716SMasatake YAMATO 			}
8976cdf5716SMasatake YAMATO 			else if (strncmp (tmp, "end", 3) == 0)
8986cdf5716SMasatake YAMATO 			{
8996cdf5716SMasatake YAMATO 				current->fromStartOfGroup = false;
9006cdf5716SMasatake YAMATO 				tmp += 3;
9016cdf5716SMasatake YAMATO 			}
9026cdf5716SMasatake YAMATO 			else
9036cdf5716SMasatake YAMATO 			{
9046cdf5716SMasatake YAMATO 				error (WARNING, "wrong guest area specification (%s): %s",
9056cdf5716SMasatake YAMATO 					   current_field_str, v);
9066cdf5716SMasatake YAMATO 				goto err;
9076cdf5716SMasatake YAMATO 			}
9086cdf5716SMasatake YAMATO 		}
9096cdf5716SMasatake YAMATO 
9106cdf5716SMasatake YAMATO 		if (i == 0)
9116cdf5716SMasatake YAMATO 		{
9126cdf5716SMasatake YAMATO 			if (*tmp != ',')
9136cdf5716SMasatake YAMATO 			{
9146cdf5716SMasatake YAMATO 				error (WARNING,
9156cdf5716SMasatake YAMATO 					   "wrong guest area specification (separator between start and end boundaries): %s", v);
9166cdf5716SMasatake YAMATO 				goto err;
9176cdf5716SMasatake YAMATO 			}
9186cdf5716SMasatake YAMATO 			tmp++;
9196cdf5716SMasatake YAMATO 		}
9206cdf5716SMasatake YAMATO 		else if (i == 1 && (*tmp != '\0'))
9216cdf5716SMasatake YAMATO 		{
9226cdf5716SMasatake YAMATO 			error (WARNING, "wrong guest area specification (garbage at the end of end boundary spec): %s", v);
9236cdf5716SMasatake YAMATO 			goto err;
9246cdf5716SMasatake YAMATO 		}
9256cdf5716SMasatake YAMATO 	}
9266cdf5716SMasatake YAMATO 	return;
9276cdf5716SMasatake YAMATO  err:
9286cdf5716SMasatake YAMATO 	guest->lang.type = GUEST_LANG_UNKNOWN;
9296cdf5716SMasatake YAMATO }
9306cdf5716SMasatake YAMATO 
93113939209SMasatake YAMATO static flagDefinition multilinePtrnFlagDef[] = {
932e77d0926SMasatake YAMATO 	{ '\0',  "mgroup", NULL, pre_ptrn_flag_mgroup_long,
933641e337aSMasatake YAMATO 	  "N", "a group in pattern determining the line number of tag"},
934c9bfc26fSMasatake YAMATO 	{ '\0',  "_advanceTo", NULL, pre_ptrn_flag_advanceTo_long,
935c9bfc26fSMasatake YAMATO 	  "N[start|end]", "a group in pattern from where the next scan starts [0end]"},
93613939209SMasatake YAMATO };
93713939209SMasatake YAMATO 
9386cdf5716SMasatake YAMATO static flagDefinition guestPtrnFlagDef[] = {
9396cdf5716SMasatake YAMATO #define EXPERIMENTAL "_"
9406cdf5716SMasatake YAMATO 	{ '\0',  EXPERIMENTAL "guest", NULL, pre_ptrn_flag_guest_long,
9416cdf5716SMasatake YAMATO 	  "PARSERSPEC,N0[start|end],N1[start|end]", "run guest parser on the area"},
9426cdf5716SMasatake YAMATO };
9436cdf5716SMasatake YAMATO 
hasMessage(const regexPattern * const ptrn)9449a1e266aSHadriel Kaplan static bool hasMessage(const regexPattern *const ptrn)
9459a1e266aSHadriel Kaplan {
9469a1e266aSHadriel Kaplan 	return (ptrn->message.selection > 0 && ptrn->message.message_string);
9479a1e266aSHadriel Kaplan }
9489a1e266aSHadriel Kaplan 
949f74a98d6SHadriel Kaplan struct commonFlagData {
95046837a67SHadriel Kaplan 	const langType owner;
95146837a67SHadriel Kaplan 	const struct lregexControlBlock *const lcb;
952f74a98d6SHadriel Kaplan 	regexPattern *ptrn;
95310db13faSMasatake YAMATO };
95410db13faSMasatake YAMATO 
common_flag_msg_long(const char * const s,const char * const v,void * data)9559a1e266aSHadriel Kaplan static void common_flag_msg_long (const char* const s, const char* const v, void* data)
9569a1e266aSHadriel Kaplan {
9579a1e266aSHadriel Kaplan 	struct commonFlagData *cdata = data;
9589a1e266aSHadriel Kaplan 	regexPattern *ptrn = cdata->ptrn;
9599a1e266aSHadriel Kaplan 
9609a1e266aSHadriel Kaplan 	Assert (ptrn);
9619a1e266aSHadriel Kaplan 
9629a1e266aSHadriel Kaplan 	if (hasMessage(ptrn))
9639a1e266aSHadriel Kaplan 	{
9649a1e266aSHadriel Kaplan 		error (WARNING, "only one message flag may be given per regex (already set to '%s')",
9659a1e266aSHadriel Kaplan 			   ptrn->message.message_string);
9669a1e266aSHadriel Kaplan 		return;
9679a1e266aSHadriel Kaplan 	}
9689a1e266aSHadriel Kaplan 
9699a1e266aSHadriel Kaplan 	if (strcmp (s, "fatal") == 0)
9709a1e266aSHadriel Kaplan 	{
9719a1e266aSHadriel Kaplan 		ptrn->message.selection = FATAL;
9729a1e266aSHadriel Kaplan 	}
9739a1e266aSHadriel Kaplan 	else if (strcmp (s, "warning") == 0)
9749a1e266aSHadriel Kaplan 	{
9759a1e266aSHadriel Kaplan 		ptrn->message.selection = WARNING;
9769a1e266aSHadriel Kaplan 	}
9779a1e266aSHadriel Kaplan 
9789a1e266aSHadriel Kaplan 	Assert (ptrn->message.selection != 0);
9799a1e266aSHadriel Kaplan 
9809a1e266aSHadriel Kaplan 	if (!v || !*v)
9819a1e266aSHadriel Kaplan 	{
9829a1e266aSHadriel Kaplan 		error (WARNING, "no message value is given for {%s}", s);
9839a1e266aSHadriel Kaplan 		return;
9849a1e266aSHadriel Kaplan 	}
9859a1e266aSHadriel Kaplan 
9869a1e266aSHadriel Kaplan 	const char* begin = v;
9879a1e266aSHadriel Kaplan 	const char* end = v + strlen (v);
9889a1e266aSHadriel Kaplan 	--end;
9899a1e266aSHadriel Kaplan 
9909a1e266aSHadriel Kaplan 	if (*begin != '"' || *end != '"' || begin == end)
9919a1e266aSHadriel Kaplan 	{
9929a1e266aSHadriel Kaplan 		error (WARNING, "argument for {%s} must be in double-quotes", s);
9939a1e266aSHadriel Kaplan 		return;
9949a1e266aSHadriel Kaplan 	}
9959a1e266aSHadriel Kaplan 
9969a1e266aSHadriel Kaplan 	++begin;
9979a1e266aSHadriel Kaplan 
9989a1e266aSHadriel Kaplan 	if (begin < end)
9999a1e266aSHadriel Kaplan 		ptrn->message.message_string = eStrndup (begin, end - begin);
10009a1e266aSHadriel Kaplan }
10019a1e266aSHadriel Kaplan 
common_flag_extra_long(const char * const s,const char * const v,void * data)100217d77272SHadriel Kaplan static void common_flag_extra_long (const char* const s, const char* const v, void* data)
100310db13faSMasatake YAMATO {
1004f74a98d6SHadriel Kaplan 	struct commonFlagData * cdata = data;
1005f74a98d6SHadriel Kaplan 
1006f74a98d6SHadriel Kaplan 	Assert (cdata->ptrn);
100710db13faSMasatake YAMATO 
100810db13faSMasatake YAMATO 	if (!v)
100910db13faSMasatake YAMATO 	{
101010db13faSMasatake YAMATO 		error (WARNING, "no value is given for: %s", s);
101110db13faSMasatake YAMATO 		return;
101210db13faSMasatake YAMATO 	}
101310db13faSMasatake YAMATO 
1014f74a98d6SHadriel Kaplan 	cdata->ptrn->xtagType = getXtagTypeForNameAndLanguage (v, cdata->owner);
1015f74a98d6SHadriel Kaplan 	if (cdata->ptrn->xtagType == XTAG_UNKNOWN)
1016f74a98d6SHadriel Kaplan 		error (WARNING, "no such extra \"%s\" in %s", v, getLanguageName(cdata->owner));
101710db13faSMasatake YAMATO }
101810db13faSMasatake YAMATO 
1019f53f3c39SMasatake YAMATO 
fieldPatternNew(fieldType ftype,const char * template)1020f53f3c39SMasatake YAMATO static struct fieldPattern * fieldPatternNew (fieldType ftype, const char *template)
1021f53f3c39SMasatake YAMATO {
1022f53f3c39SMasatake YAMATO 	struct fieldPattern *fp;
1023f53f3c39SMasatake YAMATO 
1024f53f3c39SMasatake YAMATO 	fp = xMalloc(1, struct fieldPattern);
1025f53f3c39SMasatake YAMATO 	fp->ftype = ftype;
1026f53f3c39SMasatake YAMATO 	fp->template = eStrdup(template);
1027f53f3c39SMasatake YAMATO 
1028f53f3c39SMasatake YAMATO 	return fp;
1029f53f3c39SMasatake YAMATO }
1030f53f3c39SMasatake YAMATO 
fieldPatternDelete(struct fieldPattern * fp)1031f53f3c39SMasatake YAMATO static void fieldPatternDelete (struct fieldPattern *fp)
1032f53f3c39SMasatake YAMATO {
1033f53f3c39SMasatake YAMATO 	eFree ((void *)fp->template);
1034f53f3c39SMasatake YAMATO 	eFree (fp);
1035f53f3c39SMasatake YAMATO }
1036f53f3c39SMasatake YAMATO 
common_flag_field_long(const char * const s,const char * const v,void * data)103717d77272SHadriel Kaplan static void common_flag_field_long (const char* const s, const char* const v, void* data)
1038f53f3c39SMasatake YAMATO {
10399c2744edSHadriel Kaplan 	struct commonFlagData * cdata = data;
10409c2744edSHadriel Kaplan 	regexPattern *ptrn = cdata->ptrn;
10419c2744edSHadriel Kaplan 
10429c2744edSHadriel Kaplan 	Assert (ptrn);
1043f53f3c39SMasatake YAMATO 
1044f53f3c39SMasatake YAMATO 	struct fieldPattern *fp;
1045f53f3c39SMasatake YAMATO 	fieldType ftype;
1046f53f3c39SMasatake YAMATO 	char *fname;
1047f53f3c39SMasatake YAMATO 	const char* template;
1048f53f3c39SMasatake YAMATO 	char *tmp;
1049f53f3c39SMasatake YAMATO 
1050f53f3c39SMasatake YAMATO 	if (!v)
1051f53f3c39SMasatake YAMATO 	{
1052f53f3c39SMasatake YAMATO 		error (WARNING, "no value is given for: %s", s);
1053f53f3c39SMasatake YAMATO 		return;
1054f53f3c39SMasatake YAMATO 	}
1055f53f3c39SMasatake YAMATO 
1056f53f3c39SMasatake YAMATO 	tmp = strchr (v, ':');
1057f53f3c39SMasatake YAMATO 	if (tmp == NULL || tmp == v)
1058f53f3c39SMasatake YAMATO 	{
1059f53f3c39SMasatake YAMATO 		error (WARNING, "no field name is given for: %s", s);
1060f53f3c39SMasatake YAMATO 		return;
1061f53f3c39SMasatake YAMATO 	}
1062f53f3c39SMasatake YAMATO 
1063f53f3c39SMasatake YAMATO 	fname = eStrndup (v, tmp - v);
10649c2744edSHadriel Kaplan 	ftype = getFieldTypeForNameAndLanguage (fname, cdata->owner);
1065f53f3c39SMasatake YAMATO 	if (ftype == FIELD_UNKNOWN)
1066f53f3c39SMasatake YAMATO 	{
10679c2744edSHadriel Kaplan 		error (WARNING, "no such field \"%s\" in %s", fname, getLanguageName(cdata->owner));
1068f53f3c39SMasatake YAMATO 		eFree (fname);
1069f53f3c39SMasatake YAMATO 		return;
1070f53f3c39SMasatake YAMATO 	}
1071f53f3c39SMasatake YAMATO 
10729c2744edSHadriel Kaplan 	if (ptrn->fieldPatterns)
1073f53f3c39SMasatake YAMATO 	{
10749c2744edSHadriel Kaplan 		for (unsigned int i = 0; i < ptrArrayCount(ptrn->fieldPatterns); i++)
1075f53f3c39SMasatake YAMATO 		{
10769c2744edSHadriel Kaplan 			fp = ptrArrayItem(ptrn->fieldPatterns, i);
1077f53f3c39SMasatake YAMATO 			if (fp->ftype == ftype)
1078f53f3c39SMasatake YAMATO 			{
10799c2744edSHadriel Kaplan 				error (WARNING, "duplicated field specification \"%s\" in %s", fname, getLanguageName(cdata->owner));
1080f53f3c39SMasatake YAMATO 				eFree (fname);
1081f53f3c39SMasatake YAMATO 				return;
1082f53f3c39SMasatake YAMATO 			}
1083f53f3c39SMasatake YAMATO 		}
1084f53f3c39SMasatake YAMATO 	}
1085f53f3c39SMasatake YAMATO 	eFree (fname);
1086f53f3c39SMasatake YAMATO 
1087f53f3c39SMasatake YAMATO 	template = tmp + 1;
1088f53f3c39SMasatake YAMATO 	fp = fieldPatternNew (ftype, template);
1089f53f3c39SMasatake YAMATO 
10909c2744edSHadriel Kaplan 	if (ptrn->fieldPatterns == NULL)
10919c2744edSHadriel Kaplan 		ptrn->fieldPatterns = ptrArrayNew((ptrArrayDeleteFunc)fieldPatternDelete);
10929c2744edSHadriel Kaplan 	ptrArrayAdd(ptrn->fieldPatterns, fp);
1093f53f3c39SMasatake YAMATO }
1094f53f3c39SMasatake YAMATO 
common_flag_role_long(const char * const s,const char * const v,void * data)109517d77272SHadriel Kaplan static void common_flag_role_long (const char* const s, const char* const v, void* data)
109617d77272SHadriel Kaplan {
109717d77272SHadriel Kaplan 	struct commonFlagData * cdata = data;
109817d77272SHadriel Kaplan 	regexPattern *ptrn = cdata->ptrn;
109917d77272SHadriel Kaplan 	roleDefinition * role;
110017d77272SHadriel Kaplan 
110117d77272SHadriel Kaplan 	Assert (ptrn);
110217d77272SHadriel Kaplan 
110317d77272SHadriel Kaplan 	if (!v)
110417d77272SHadriel Kaplan 	{
110517d77272SHadriel Kaplan 		error (WARNING, "no value is given for: %s", s);
110617d77272SHadriel Kaplan 		return;
110717d77272SHadriel Kaplan 	}
110817d77272SHadriel Kaplan 
110917d77272SHadriel Kaplan 	role = getLanguageRoleForName(cdata->owner,
111017d77272SHadriel Kaplan 								  ptrn->u.tag.kindIndex, v);
111117d77272SHadriel Kaplan 	if (!role)
111217d77272SHadriel Kaplan 	{
111317d77272SHadriel Kaplan 		error (WARNING, "no such role: %s", v);
111417d77272SHadriel Kaplan 		return;
111517d77272SHadriel Kaplan 	}
111617d77272SHadriel Kaplan 
111717d77272SHadriel Kaplan 	ptrn->u.tag.roleBits |= makeRoleBit(role->id);
111817d77272SHadriel Kaplan }
11199c2744edSHadriel Kaplan 
common_flag_anonymous_long(const char * const s,const char * const v,void * data)1120c2c0d2b7SMasatake YAMATO static void common_flag_anonymous_long (const char* const s, const char* const v, void* data)
11210d56cc8eSMasatake YAMATO {
11220d56cc8eSMasatake YAMATO 	struct commonFlagData * cdata = data;
11230d56cc8eSMasatake YAMATO 	regexPattern *ptrn = cdata->ptrn;
11240d56cc8eSMasatake YAMATO 
11250d56cc8eSMasatake YAMATO 	Assert (ptrn);
11260d56cc8eSMasatake YAMATO 
11270d56cc8eSMasatake YAMATO 	if (ptrn->anonymous_tag_prefix)
11280d56cc8eSMasatake YAMATO 	{
11290d56cc8eSMasatake YAMATO 		error (WARNING, "an anonymous tag prefix for this pattern (%s) is already given: %s",
11300d56cc8eSMasatake YAMATO 			   ptrn->pattern_string? ptrn->pattern_string: "",
11310d56cc8eSMasatake YAMATO 			   ptrn->anonymous_tag_prefix);
11320d56cc8eSMasatake YAMATO 		return;
11330d56cc8eSMasatake YAMATO 	}
11340d56cc8eSMasatake YAMATO 
11350d56cc8eSMasatake YAMATO 	if (!v)
11360d56cc8eSMasatake YAMATO 	{
11370d56cc8eSMasatake YAMATO 		error (WARNING, "no PREFIX for anonymous regex flag is given (pattern == %s)",
11380d56cc8eSMasatake YAMATO 			   ptrn->pattern_string? ptrn->pattern_string: "");
11390d56cc8eSMasatake YAMATO 		return;
11400d56cc8eSMasatake YAMATO 	}
11410d56cc8eSMasatake YAMATO 
1142c2c0d2b7SMasatake YAMATO 	if (ptrn->u.tag.kindIndex == KIND_GHOST_INDEX)
1143c2c0d2b7SMasatake YAMATO 	{
1144c2c0d2b7SMasatake YAMATO 		error (WARNING, "use \"%s\" regex flag only with an explicitly defined kind", s);
1145c2c0d2b7SMasatake YAMATO 		return;
1146c2c0d2b7SMasatake YAMATO 	}
1147c2c0d2b7SMasatake YAMATO 
11480d56cc8eSMasatake YAMATO 	ptrn->anonymous_tag_prefix = eStrdup (v);
11490d56cc8eSMasatake YAMATO }
11500d56cc8eSMasatake YAMATO 
11519c2744edSHadriel Kaplan static flagDefinition commonSpecFlagDef[] = {
11529c2744edSHadriel Kaplan 	{ '\0',  "fatal", NULL, common_flag_msg_long ,
11539c2744edSHadriel Kaplan 	  "\"MESSAGE\"", "print the given MESSAGE and exit"},
11549c2744edSHadriel Kaplan 	{ '\0',  "warning", NULL, common_flag_msg_long ,
11559c2744edSHadriel Kaplan 	  "\"MESSAGE\"", "print the given MESSAGE at WARNING level"},
1156f53f3c39SMasatake YAMATO #define EXPERIMENTAL "_"
11579c2744edSHadriel Kaplan 	{ '\0',  EXPERIMENTAL "extra", NULL, common_flag_extra_long ,
11589c2744edSHadriel Kaplan 	  "EXTRA", "record the tag only when the extra is enabled"},
11599c2744edSHadriel Kaplan 	{ '\0',  EXPERIMENTAL "field", NULL, common_flag_field_long ,
116084f3a057SMasatake YAMATO 	  "FIELD:VALUE", "record the matched string(VALUE) to parser own FIELD of the tag"},
116117d77272SHadriel Kaplan 	{ '\0',  EXPERIMENTAL "role", NULL, common_flag_role_long,
116217d77272SHadriel Kaplan 	  "ROLE", "set the given ROLE to the roles field"},
11630d56cc8eSMasatake YAMATO 	{ '\0',  EXPERIMENTAL "anonymous", NULL, common_flag_anonymous_long,
11640d56cc8eSMasatake YAMATO 	  "PREFIX", "make an anonymous tag with PREFIX"},
1165f53f3c39SMasatake YAMATO };
1166f53f3c39SMasatake YAMATO 
116713939209SMasatake YAMATO 
pre_ptrn_flag_mtable_long(const char * const s,const char * const v,void * data)11680cbf3f0dSMasatake YAMATO static void pre_ptrn_flag_mtable_long (const char* const s, const char* const v, void* data)
11690cbf3f0dSMasatake YAMATO {
117046837a67SHadriel Kaplan 	struct commonFlagData * cdata = data;
117146837a67SHadriel Kaplan 	regexPattern *ptrn = cdata->ptrn;
117246837a67SHadriel Kaplan 	struct mTableActionSpec *taction;
11730cbf3f0dSMasatake YAMATO 	bool taking_table = true;
11740cbf3f0dSMasatake YAMATO 
117546837a67SHadriel Kaplan 	Assert (ptrn);
117646837a67SHadriel Kaplan 	Assert (cdata->lcb);
117746837a67SHadriel Kaplan 
117846837a67SHadriel Kaplan 	taction = &ptrn->taction;
117946837a67SHadriel Kaplan 
11800cbf3f0dSMasatake YAMATO 	if (strcmp (s, "tenter") == 0)
11810cbf3f0dSMasatake YAMATO 		taction->action = TACTION_ENTER;
11820cbf3f0dSMasatake YAMATO 	else if (strcmp (s, "tleave") == 0)
11830cbf3f0dSMasatake YAMATO 	{
11840cbf3f0dSMasatake YAMATO 		taction->action = TACTION_LEAVE;
11850cbf3f0dSMasatake YAMATO 		taking_table = false;
11860cbf3f0dSMasatake YAMATO 	}
11870cbf3f0dSMasatake YAMATO 	else if (strcmp (s, "tjump") == 0)
11880cbf3f0dSMasatake YAMATO 		taction->action = TACTION_JUMP;
11890cbf3f0dSMasatake YAMATO 	else if (strcmp (s, "treset") == 0)
11900cbf3f0dSMasatake YAMATO 		taction->action = TACTION_RESET;
11910cbf3f0dSMasatake YAMATO 	else if (strcmp (s, "tquit") == 0)
11920cbf3f0dSMasatake YAMATO 	{
11930cbf3f0dSMasatake YAMATO 		taction->action = TACTION_QUIT;
11940cbf3f0dSMasatake YAMATO 		taking_table = false;
11950cbf3f0dSMasatake YAMATO 	}
11960cbf3f0dSMasatake YAMATO 
11970cbf3f0dSMasatake YAMATO 	if (taking_table)
11980cbf3f0dSMasatake YAMATO 	{
119940177cd9SMasatake YAMATO 		int t;
120040177cd9SMasatake YAMATO 		char *continuation = NULL;
120140177cd9SMasatake YAMATO 
120240177cd9SMasatake YAMATO 
12030cbf3f0dSMasatake YAMATO 		if (!v || (!*v))
12040cbf3f0dSMasatake YAMATO 			error (FATAL, "no table is given for table action: %s", s);
12050cbf3f0dSMasatake YAMATO 
120640177cd9SMasatake YAMATO 		if (taction->action == TACTION_ENTER
120740177cd9SMasatake YAMATO 			&& (continuation = strchr (v, ',')))
120840177cd9SMasatake YAMATO 		{
120940177cd9SMasatake YAMATO 			char *tableEnterTo;
121040177cd9SMasatake YAMATO 
121140177cd9SMasatake YAMATO 			tableEnterTo = eStrndup (v, continuation - v);
121246837a67SHadriel Kaplan 			t = getTableIndexForName (cdata->lcb, tableEnterTo);
121340177cd9SMasatake YAMATO 			if (t < 0)
121440177cd9SMasatake YAMATO 				error (FATAL, "table is not defined: %s", tableEnterTo);
121546837a67SHadriel Kaplan 			taction->table = ptrArrayItem (cdata->lcb->tables, t);
121640177cd9SMasatake YAMATO 			eFree (tableEnterTo);
121740177cd9SMasatake YAMATO 
121840177cd9SMasatake YAMATO 			if (!*(continuation + 1))
121940177cd9SMasatake YAMATO 				error (FATAL, "no continuation table is given for: %s", v);
122040177cd9SMasatake YAMATO 
122146837a67SHadriel Kaplan 			int t_cont = getTableIndexForName (cdata->lcb, continuation + 1);
122240177cd9SMasatake YAMATO 			if (t_cont < 0)
122340177cd9SMasatake YAMATO 				error (FATAL, "table for continuation is not defined: %s", continuation + 1);
122446837a67SHadriel Kaplan 			taction->continuation_table = ptrArrayItem (cdata->lcb->tables, t_cont);
122540177cd9SMasatake YAMATO 		}
122640177cd9SMasatake YAMATO 		else
122740177cd9SMasatake YAMATO 		{
122846837a67SHadriel Kaplan 			t = getTableIndexForName (cdata->lcb, v);
12290cbf3f0dSMasatake YAMATO 			if (t < 0)
12300cbf3f0dSMasatake YAMATO 				error (FATAL, "table is not defined: %s", v);
123146837a67SHadriel Kaplan 			taction->table = ptrArrayItem (cdata->lcb->tables, t);
123240177cd9SMasatake YAMATO 			taction->continuation_table = NULL;
123340177cd9SMasatake YAMATO 		}
12340cbf3f0dSMasatake YAMATO 	}
12350cbf3f0dSMasatake YAMATO }
12360cbf3f0dSMasatake YAMATO 
12370cbf3f0dSMasatake YAMATO static flagDefinition multitablePtrnFlagDef[] = {
12380cbf3f0dSMasatake YAMATO 	{ '\0',  "tenter", NULL, pre_ptrn_flag_mtable_long ,
123940177cd9SMasatake YAMATO 	  "TABLE[,CONT]", "enter to given regext table (with specifying continuation)"},
12400cbf3f0dSMasatake YAMATO 	{ '\0',  "tleave", NULL, pre_ptrn_flag_mtable_long ,
12410cbf3f0dSMasatake YAMATO 	  NULL, "leave from the current regext table"},
12420cbf3f0dSMasatake YAMATO 	{ '\0',  "tjump", NULL, pre_ptrn_flag_mtable_long ,
12430cbf3f0dSMasatake YAMATO 	  "TABLE", "jump to another regext table(don't push the current table to state stack)"},
12440cbf3f0dSMasatake YAMATO 	{ '\0',  "treset", NULL, pre_ptrn_flag_mtable_long ,
12450cbf3f0dSMasatake YAMATO 	  "TABLE", "clear the state stack and jump to given regex table"},
12460cbf3f0dSMasatake YAMATO 	{ '\0',  "tquit", NULL, pre_ptrn_flag_mtable_long ,
12470cbf3f0dSMasatake YAMATO 	  NULL, "stop the parsing with this parser"},
12480cbf3f0dSMasatake YAMATO };
12490cbf3f0dSMasatake YAMATO 
12500cbf3f0dSMasatake YAMATO 
setKind(regexPattern * ptrn,const langType owner,const char kindLetter,const char * kindName,const char * const description,bool kind_explicitly_defined)12517dda83ebSHadriel Kaplan static void setKind(regexPattern * ptrn, const langType owner,
12527dda83ebSHadriel Kaplan 					const char kindLetter, const char* kindName,
12533950d588SMasatake YAMATO 					const char *const description,
12543950d588SMasatake YAMATO 					bool kind_explicitly_defined)
12557dda83ebSHadriel Kaplan {
12567dda83ebSHadriel Kaplan 	Assert (ptrn);
12577dda83ebSHadriel Kaplan 	Assert (ptrn->u.tag.name_pattern);
1258691d5f94SMasatake YAMATO 	Assert (kindName);
12593950d588SMasatake YAMATO 	kindDefinition *kdef = getLanguageKindForLetter (owner, kindLetter);
12607dda83ebSHadriel Kaplan 
12617dda83ebSHadriel Kaplan 	if (kdef)
12627dda83ebSHadriel Kaplan 	{
1263691d5f94SMasatake YAMATO 		if (strcmp (kdef->name, kindName) && (strcmp(kindName, KIND_REGEX_DEFAULT_NAME)))
12647dda83ebSHadriel Kaplan 			/* When using a same kind letter for multiple regex patterns, the name of kind
12657dda83ebSHadriel Kaplan 			   should be the same. */
12667dda83ebSHadriel Kaplan 			error  (WARNING, "Don't reuse the kind letter `%c' in a language %s (old: \"%s\", new: \"%s\")",
12677dda83ebSHadriel Kaplan 					kdef->letter, getLanguageName (owner),
12687dda83ebSHadriel Kaplan 					kdef->name, kindName);
12693950d588SMasatake YAMATO 		ptrn->u.tag.kindIndex = kdef->id;
12707dda83ebSHadriel Kaplan 	}
12713950d588SMasatake YAMATO 	else if (*ptrn->u.tag.name_pattern == '\0' &&
12723950d588SMasatake YAMATO 			 kindLetter == KIND_REGEX_DEFAULT_LETTER &&
12733950d588SMasatake YAMATO 			 (strcmp(kindName, KIND_REGEX_DEFAULT_NAME) == 0) &&
12743950d588SMasatake YAMATO 			 (!kind_explicitly_defined))
12753950d588SMasatake YAMATO 		ptrn->u.tag.kindIndex = KIND_GHOST_INDEX;
12767dda83ebSHadriel Kaplan 	else
12777dda83ebSHadriel Kaplan 	{
12787dda83ebSHadriel Kaplan 		kdef = kindNew (kindLetter, kindName, description);
12797dda83ebSHadriel Kaplan 		defineLanguageKind (owner, kdef, kindFree);
12807dda83ebSHadriel Kaplan 		ptrn->u.tag.kindIndex = kdef->id;
12817dda83ebSHadriel Kaplan 	}
12827dda83ebSHadriel Kaplan }
12837dda83ebSHadriel Kaplan 
patternEvalFlags(struct lregexControlBlock * lcb,regexPattern * ptrn,enum regexParserType regptype,const char * flags)1284afe7a692SMasatake YAMATO static void patternEvalFlags (struct lregexControlBlock *lcb,
1285afe7a692SMasatake YAMATO 							  regexPattern * ptrn,
1286afe7a692SMasatake YAMATO 							  enum regexParserType regptype,
1287afe7a692SMasatake YAMATO 							  const char* flags)
1288d4c6f1e6SMasatake YAMATO {
1289f74a98d6SHadriel Kaplan 	struct commonFlagData commonFlagData = {
129010db13faSMasatake YAMATO 		.owner = lcb->owner,
12910cbf3f0dSMasatake YAMATO 		.lcb = lcb,
129246837a67SHadriel Kaplan 		.ptrn = ptrn
12930cbf3f0dSMasatake YAMATO 	};
12940cbf3f0dSMasatake YAMATO 
129546837a67SHadriel Kaplan 	if (regptype == REG_PARSER_SINGLE_LINE)
129646837a67SHadriel Kaplan 		flagsEval (flags, prePtrnFlagDef, ARRAY_SIZE(prePtrnFlagDef), &ptrn->exclusive);
129746837a67SHadriel Kaplan 
1298e8386a4eSMasatake YAMATO 	const char * optscript = flagsEval (flags, commonSpecFlagDef, ARRAY_SIZE(commonSpecFlagDef), &commonFlagData);
1299e8386a4eSMasatake YAMATO 	if (optscript)
1300e8386a4eSMasatake YAMATO 	{
1301668e3666SMasatake YAMATO 		ptrn->optscript = scriptRead (optvm, optscript);
1302e8386a4eSMasatake YAMATO 		ptrn->optscript_src = eStrdup (optscript);
1303e8386a4eSMasatake YAMATO 	}
1304f74a98d6SHadriel Kaplan 
130546837a67SHadriel Kaplan 	if (regptype == REG_PARSER_SINGLE_LINE || regptype == REG_PARSER_MULTI_TABLE)
1306f998e51dSMasatake YAMATO 	{
130746837a67SHadriel Kaplan 		flagsEval (flags, scopePtrnFlagDef, ARRAY_SIZE(scopePtrnFlagDef), &ptrn->scopeActions);
1308f998e51dSMasatake YAMATO 		if ((ptrn->scopeActions & (SCOPE_REF|SCOPE_REF_AFTER_POP)) == (SCOPE_REF|SCOPE_REF_AFTER_POP))
1309f998e51dSMasatake YAMATO 			error (WARNING, "%s: don't combine \"replace\" with the other scope action.",
1310f998e51dSMasatake YAMATO 				   getLanguageName (lcb->owner));
1311f998e51dSMasatake YAMATO 	}
131246837a67SHadriel Kaplan 
13130cbf3f0dSMasatake YAMATO 	if (regptype == REG_PARSER_MULTI_LINE || regptype == REG_PARSER_MULTI_TABLE)
1314f5ccb78dSMasatake YAMATO 	{
1315f5ccb78dSMasatake YAMATO 		ptrn->mgroup.forNextScanning = 0;
1316f5ccb78dSMasatake YAMATO 		/* ptrn->mgroup.nextFromStart is initialized in initMgroup() already. */
1317c9bfc26fSMasatake YAMATO 		flagsEval (flags, multilinePtrnFlagDef, ARRAY_SIZE(multilinePtrnFlagDef), &ptrn->mgroup);
1318f5ccb78dSMasatake YAMATO 	}
1319c9bfc26fSMasatake YAMATO 
13206cdf5716SMasatake YAMATO 	struct guestPtrnFlagData guestPtrnFlagData = {
13216cdf5716SMasatake YAMATO 		.type = regptype,
13226cdf5716SMasatake YAMATO 		.guest = &ptrn->guest,
13236cdf5716SMasatake YAMATO 	};
13246cdf5716SMasatake YAMATO 	flagsEval (flags, guestPtrnFlagDef, ARRAY_SIZE(guestPtrnFlagDef), &guestPtrnFlagData);
13256cdf5716SMasatake YAMATO 
13260cbf3f0dSMasatake YAMATO 	if (regptype == REG_PARSER_MULTI_TABLE)
132746837a67SHadriel Kaplan 		flagsEval (flags, multitablePtrnFlagDef, ARRAY_SIZE(multitablePtrnFlagDef), &commonFlagData);
1328afe7a692SMasatake YAMATO }
1329afe7a692SMasatake YAMATO 
addCompiledTagPattern(struct lregexControlBlock * lcb,int table_index,enum regexParserType regptype,regexCompiledCode * const pattern,const char * const name,char kindLetter,const char * kindName,char * const description,const char * flags,bool kind_explicitly_defined,bool * disabled)1330afe7a692SMasatake YAMATO static regexPattern *addCompiledTagPattern (struct lregexControlBlock *lcb,
1331afe7a692SMasatake YAMATO 											int table_index,
1332c30b89acSMasatake YAMATO 											enum regexParserType regptype, regexCompiledCode* const pattern,
1333afe7a692SMasatake YAMATO 					    const char* const name, char kindLetter, const char* kindName,
1334afe7a692SMasatake YAMATO 					    char *const description, const char* flags,
13353950d588SMasatake YAMATO 					    bool kind_explicitly_defined,
1336afe7a692SMasatake YAMATO 					    bool *disabled)
1337afe7a692SMasatake YAMATO {
1338afe7a692SMasatake YAMATO 	regexPattern * ptrn = addCompiledTagCommon(lcb, table_index, pattern, regptype);
1339afe7a692SMasatake YAMATO 
1340afe7a692SMasatake YAMATO 	ptrn->type = PTRN_TAG;
1341afe7a692SMasatake YAMATO 	ptrn->u.tag.name_pattern = eStrdup (name);
1342afe7a692SMasatake YAMATO 	ptrn->disabled = disabled;
1343afe7a692SMasatake YAMATO 
13443950d588SMasatake YAMATO 	setKind(ptrn, lcb->owner, kindLetter, kindName, description, kind_explicitly_defined);
1345afe7a692SMasatake YAMATO 	patternEvalFlags (lcb, ptrn, regptype, flags);
13460cbf3f0dSMasatake YAMATO 
134712ddaaa3SMasatake YAMATO 	return ptrn;
1348d4c6f1e6SMasatake YAMATO }
1349d4c6f1e6SMasatake YAMATO 
addCompiledCallbackPattern(struct lregexControlBlock * lcb,regexCompiledCode * const pattern,const regexCallback callback,const char * flags,bool * disabled,void * userData)1350c30b89acSMasatake YAMATO static regexPattern *addCompiledCallbackPattern (struct lregexControlBlock *lcb, regexCompiledCode* const pattern,
13516ff4dab6SMasatake YAMATO 					const regexCallback callback, const char* flags,
1352ce990805SThomas Braun 					bool *disabled,
13536ff4dab6SMasatake YAMATO 					void *userData)
1354d4c6f1e6SMasatake YAMATO {
1355d4c6f1e6SMasatake YAMATO 	regexPattern * ptrn;
1356ce990805SThomas Braun 	bool exclusive = false;
13573db72c21SMasatake YAMATO 	flagsEval (flags, prePtrnFlagDef, ARRAY_SIZE(prePtrnFlagDef), &exclusive);
13580cbf3f0dSMasatake YAMATO 	ptrn = addCompiledTagCommon(lcb, TABLE_INDEX_UNUSED, pattern, REG_PARSER_SINGLE_LINE);
1359d4c6f1e6SMasatake YAMATO 	ptrn->type    = PTRN_CALLBACK;
1360d4c6f1e6SMasatake YAMATO 	ptrn->u.callback.function = callback;
13616ff4dab6SMasatake YAMATO 	ptrn->u.callback.userData = userData;
13625fdabf71SMasatake YAMATO 	ptrn->exclusive = exclusive;
13632a738f47SMasatake YAMATO 	ptrn->disabled = disabled;
13645372d785SMasatake YAMATO 	return ptrn;
1365d4c6f1e6SMasatake YAMATO }
1366d4c6f1e6SMasatake YAMATO 
136765426ae0SMasatake YAMATO #ifndef HAVE_PCRE2
no_pcre2_regex_flag_short(char c,void * data)136865426ae0SMasatake YAMATO static void no_pcre2_regex_flag_short (char c, void* data)
136965426ae0SMasatake YAMATO {
137065426ae0SMasatake YAMATO 	error (WARNING, "'p' flag is specied but pcre2 regex engine is not linked.");
137165426ae0SMasatake YAMATO }
no_pcre2_regex_flag_long(const char * const s,const char * const unused CTAGS_ATTR_UNUSED,void * data)137265426ae0SMasatake YAMATO static void no_pcre2_regex_flag_long (const char* const s, const char* const unused CTAGS_ATTR_UNUSED, void* data)
137365426ae0SMasatake YAMATO {
137465426ae0SMasatake YAMATO 	error (WARNING, "{pcre2} flag is specied but pcre2 regex engine is not linked.");
137565426ae0SMasatake YAMATO }
137665426ae0SMasatake YAMATO #endif
137765426ae0SMasatake YAMATO 
1378c30b89acSMasatake YAMATO static flagDefinition backendFlagDefs[] = {
1379c30b89acSMasatake YAMATO 	{ 'b', "basic",  basic_regex_flag_short,  basic_regex_flag_long,
1380c30b89acSMasatake YAMATO 	  NULL, "interpreted as a Posix basic regular expression."},
1381c30b89acSMasatake YAMATO 	{ 'e', "extend", extend_regex_flag_short, extend_regex_flag_long,
1382c30b89acSMasatake YAMATO 	  NULL, "interpreted as a Posix extended regular expression (default)"},
13836a8d5b70SMasatake YAMATO #ifdef HAVE_PCRE2
13846a8d5b70SMasatake YAMATO 	{ 'p', "pcre2",  pcre2_regex_flag_short, pcre2_regex_flag_long,
13856a8d5b70SMasatake YAMATO 	  NULL, "use pcre2 regex engine"},
138665426ae0SMasatake YAMATO #else
138765426ae0SMasatake YAMATO 	{ 'p', "pcre2",  no_pcre2_regex_flag_short, no_pcre2_regex_flag_long,
138865426ae0SMasatake YAMATO 	  NULL, "pcre2 is NOT linked!"},
13896a8d5b70SMasatake YAMATO #endif
1390c30b89acSMasatake YAMATO };
1391d4c6f1e6SMasatake YAMATO 
regex_flag_icase_short(char c CTAGS_ATTR_UNUSED,void * data)13928ccb7ee9SJiří Techet static void regex_flag_icase_short (char c CTAGS_ATTR_UNUSED, void* data)
1393d4c6f1e6SMasatake YAMATO {
1394c30b89acSMasatake YAMATO 	struct flagDefsDescriptor *desc = data;
1395c30b89acSMasatake YAMATO 	desc->backend->set_icase_flag (&desc->flags);
1396d4c6f1e6SMasatake YAMATO }
1397d4c6f1e6SMasatake YAMATO 
regex_flag_icase_long(const char * s CTAGS_ATTR_UNUSED,const char * const unused CTAGS_ATTR_UNUSED,void * data)13988ccb7ee9SJiří Techet static void regex_flag_icase_long (const char* s CTAGS_ATTR_UNUSED, const char* const unused CTAGS_ATTR_UNUSED, void* data)
1399d4c6f1e6SMasatake YAMATO {
1400d4c6f1e6SMasatake YAMATO 	regex_flag_icase_short ('i', data);
1401d4c6f1e6SMasatake YAMATO }
1402d4c6f1e6SMasatake YAMATO 
1403c30b89acSMasatake YAMATO static flagDefinition backendCommonRegexFlagDefs[] = {
14043fac0fc6SMasatake YAMATO 	{ 'i', "icase",  regex_flag_icase_short,  regex_flag_icase_long,
14053fac0fc6SMasatake YAMATO 	  NULL, "applied in a case-insensitive manner"},
14063fac0fc6SMasatake YAMATO };
14073fac0fc6SMasatake YAMATO 
1408c30b89acSMasatake YAMATO 
choose_backend(const char * flags,enum regexParserType regptype,bool error_if_no_backend)14096a8d5b70SMasatake YAMATO static struct flagDefsDescriptor choose_backend (const char *flags, enum regexParserType regptype, bool error_if_no_backend)
1410c30b89acSMasatake YAMATO {
1411c30b89acSMasatake YAMATO 	struct flagDefsDescriptor desc = {
1412c30b89acSMasatake YAMATO 		.backend  = NULL,
1413c30b89acSMasatake YAMATO 		.flags = 0,
1414c30b89acSMasatake YAMATO 		.regptype = regptype,
1415c30b89acSMasatake YAMATO 	};
1416c30b89acSMasatake YAMATO 
1417c30b89acSMasatake YAMATO 	if (flags)
1418c30b89acSMasatake YAMATO 		flagsEval (flags,
1419c30b89acSMasatake YAMATO 				   backendFlagDefs,
1420c30b89acSMasatake YAMATO 				   ARRAY_SIZE(backendFlagDefs),
1421c30b89acSMasatake YAMATO 				   &desc);
1422c30b89acSMasatake YAMATO 
1423c30b89acSMasatake YAMATO 	/* Choose the default backend. */
1424c30b89acSMasatake YAMATO 	if (desc.backend == NULL)
14256a8d5b70SMasatake YAMATO 	{
14266a8d5b70SMasatake YAMATO 		if (flags && error_if_no_backend)
14276a8d5b70SMasatake YAMATO 			error (FATAL, "No sunch backend for the name: \"%s\"", flags);
14286a8d5b70SMasatake YAMATO 
1429c30b89acSMasatake YAMATO 		flagsEval (DEFAULT_REGEX_BACKEND,
1430c30b89acSMasatake YAMATO 				   backendFlagDefs,
1431c30b89acSMasatake YAMATO 				   ARRAY_SIZE(backendFlagDefs),
1432c30b89acSMasatake YAMATO 				   &desc);
14336a8d5b70SMasatake YAMATO 	}
1434c30b89acSMasatake YAMATO 	return desc;
1435c30b89acSMasatake YAMATO }
1436c30b89acSMasatake YAMATO 
compileRegex(enum regexParserType regptype,const char * const regexp,const char * const flags)1437c30b89acSMasatake YAMATO static regexCompiledCode compileRegex (enum regexParserType regptype,
143841e0b4f8SMasatake YAMATO 									   const char* const regexp, const char* const flags)
1439d4c6f1e6SMasatake YAMATO {
14406a8d5b70SMasatake YAMATO 	struct flagDefsDescriptor desc = choose_backend (flags, regptype, false);
144141e0b4f8SMasatake YAMATO 
1442c30b89acSMasatake YAMATO 	/* Evaluate backend specific flags */
1443c30b89acSMasatake YAMATO 	flagsEval (flags,
1444c30b89acSMasatake YAMATO 			   desc.backend->fdefs,
1445c30b89acSMasatake YAMATO 			   desc.backend->fdef_count,
1446c30b89acSMasatake YAMATO 			   &desc.flags);
1447d4c6f1e6SMasatake YAMATO 
1448d4c6f1e6SMasatake YAMATO 	flagsEval (flags,
1449c30b89acSMasatake YAMATO 			   backendCommonRegexFlagDefs,
1450c30b89acSMasatake YAMATO 			   ARRAY_SIZE (backendCommonRegexFlagDefs),
1451c30b89acSMasatake YAMATO 			   &desc);
1452d4c6f1e6SMasatake YAMATO 
1453c30b89acSMasatake YAMATO 	return desc.backend->compile (desc.backend, regexp, desc.flags);
1454d4c6f1e6SMasatake YAMATO }
1455d4c6f1e6SMasatake YAMATO 
1456d4c6f1e6SMasatake YAMATO 
14577882f6d8SMasatake YAMATO /* If a letter and/or a name are defined in kindSpec, return true. */
parseKinds(const char * const kindSpec,char * const kindLetter,char ** const kindName,char ** description)14587882f6d8SMasatake YAMATO static bool parseKinds (
14594b447dd0SMasatake YAMATO 		const char* const kindSpec, char* const kindLetter, char** const kindName,
1460d4c6f1e6SMasatake YAMATO 		char **description)
1461d4c6f1e6SMasatake YAMATO {
1462d4c6f1e6SMasatake YAMATO 	*description = NULL;
1463b948e230SMasatake YAMATO 
14644b447dd0SMasatake YAMATO 	if (kindSpec == NULL  ||  kindSpec [0] == '\0')
1465d4c6f1e6SMasatake YAMATO 	{
146649a1e332SMasatake YAMATO 		*kindLetter = KIND_REGEX_DEFAULT_LETTER;
14677e1bd430SMasatake YAMATO 		*kindName = eStrdup (KIND_REGEX_DEFAULT_NAME);
14687882f6d8SMasatake YAMATO 		return false;
1469d4c6f1e6SMasatake YAMATO 	}
1470087b3e2bSMasatake YAMATO 	else
1471d4c6f1e6SMasatake YAMATO 	{
14727882f6d8SMasatake YAMATO 		bool explicitly_defined = false;
14734b447dd0SMasatake YAMATO 		const char* k = kindSpec;
1474b948e230SMasatake YAMATO 
1475d4c6f1e6SMasatake YAMATO 		if (k [0] != ','  &&  (k [1] == ','  ||  k [1] == '\0'))
14767882f6d8SMasatake YAMATO 		{
147749a1e332SMasatake YAMATO 			*kindLetter = *k++;
14787882f6d8SMasatake YAMATO 			explicitly_defined = true;
14797882f6d8SMasatake YAMATO 		}
1480d4c6f1e6SMasatake YAMATO 		else
148149a1e332SMasatake YAMATO 			*kindLetter = KIND_REGEX_DEFAULT_LETTER;
1482b948e230SMasatake YAMATO 
1483d4c6f1e6SMasatake YAMATO 		if (*k == ',')
1484d4c6f1e6SMasatake YAMATO 			++k;
1485b948e230SMasatake YAMATO 
1486d4c6f1e6SMasatake YAMATO 		if (k [0] == '\0')
14877e1bd430SMasatake YAMATO 			*kindName = eStrdup (KIND_REGEX_DEFAULT_NAME);
1488d4c6f1e6SMasatake YAMATO 		else
1489d4c6f1e6SMasatake YAMATO 		{
1490d4c6f1e6SMasatake YAMATO 			const char *const comma = strchr (k, ',');
1491b948e230SMasatake YAMATO 
1492d4c6f1e6SMasatake YAMATO 			if (comma == NULL)
14937882f6d8SMasatake YAMATO 			{
14947882f6d8SMasatake YAMATO 				if (strlen (k) == 0)
14957882f6d8SMasatake YAMATO 					*kindName = eStrdup (KIND_REGEX_DEFAULT_NAME);
14967882f6d8SMasatake YAMATO 				else
14977882f6d8SMasatake YAMATO 				{
1498d4c6f1e6SMasatake YAMATO 					*kindName = eStrdup (k);
14997882f6d8SMasatake YAMATO 					explicitly_defined = true;
15007882f6d8SMasatake YAMATO 				}
15017882f6d8SMasatake YAMATO 			}
15027882f6d8SMasatake YAMATO 			else
15037882f6d8SMasatake YAMATO 			{
15047882f6d8SMasatake YAMATO 				if (comma - k == 0)
15057882f6d8SMasatake YAMATO 					*kindName = eStrdup (KIND_REGEX_DEFAULT_NAME);
1506d4c6f1e6SMasatake YAMATO 				else
1507d4c6f1e6SMasatake YAMATO 				{
1508153ec6e9SMasatake YAMATO 					*kindName = eStrndup (k, comma - k );
15097882f6d8SMasatake YAMATO 					explicitly_defined = true;
15107882f6d8SMasatake YAMATO 				}
1511d4c6f1e6SMasatake YAMATO 				k = comma + 1;
1512d4c6f1e6SMasatake YAMATO 				if (k [0] != '\0')
1513d4c6f1e6SMasatake YAMATO 					*description = eStrdup (k);
1514d4c6f1e6SMasatake YAMATO 			}
1515d4c6f1e6SMasatake YAMATO 		}
15167882f6d8SMasatake YAMATO 		return explicitly_defined;
1517d4c6f1e6SMasatake YAMATO 	}
1518d4c6f1e6SMasatake YAMATO }
1519d4c6f1e6SMasatake YAMATO 
1520d4c6f1e6SMasatake YAMATO /*
1521d4c6f1e6SMasatake YAMATO *   Regex pattern matching
1522d4c6f1e6SMasatake YAMATO */
1523d4c6f1e6SMasatake YAMATO 
1524d4c6f1e6SMasatake YAMATO 
substitute(const char * const in,const char * out,const int nmatch,const regmatch_t * const pmatch)1525d4c6f1e6SMasatake YAMATO static vString* substitute (
1526d4c6f1e6SMasatake YAMATO 		const char* const in, const char* out,
15270248c4bfSMasatake YAMATO 		const int nmatch, const regmatch_t* const pmatch)
1528d4c6f1e6SMasatake YAMATO {
1529d4c6f1e6SMasatake YAMATO 	vString* result = vStringNew ();
1530d4c6f1e6SMasatake YAMATO 	const char* p;
1531d4c6f1e6SMasatake YAMATO 	for (p = out  ;  *p != '\0'  ;  p++)
1532d4c6f1e6SMasatake YAMATO 	{
1533d4c6f1e6SMasatake YAMATO 		if (*p == '\\'  &&  isdigit ((int) *++p))
1534d4c6f1e6SMasatake YAMATO 		{
1535d4c6f1e6SMasatake YAMATO 			const int dig = *p - '0';
1536d4c6f1e6SMasatake YAMATO 			if (0 < dig  &&  dig < nmatch  &&  pmatch [dig].rm_so != -1)
1537d4c6f1e6SMasatake YAMATO 			{
1538d4c6f1e6SMasatake YAMATO 				const int diglen = pmatch [dig].rm_eo - pmatch [dig].rm_so;
1539d4c6f1e6SMasatake YAMATO 				vStringNCatS (result, in + pmatch [dig].rm_so, diglen);
1540d4c6f1e6SMasatake YAMATO 			}
1541d4c6f1e6SMasatake YAMATO 		}
15420248c4bfSMasatake YAMATO 		else if (*p != '\n'  &&  *p != '\r')
1543d4c6f1e6SMasatake YAMATO 			vStringPut (result, *p);
1544d4c6f1e6SMasatake YAMATO 	}
1545d4c6f1e6SMasatake YAMATO 	return result;
1546d4c6f1e6SMasatake YAMATO }
1547d4c6f1e6SMasatake YAMATO 
getInputLineNumberInRegPType(enum regexParserType regptype,off_t offset)15480abfb303SMasatake YAMATO static unsigned long getInputLineNumberInRegPType (enum regexParserType regptype,
15490abfb303SMasatake YAMATO 												   off_t offset)
15500abfb303SMasatake YAMATO {
155141e0b4f8SMasatake YAMATO 	return (regptype == REG_PARSER_MULTI_LINE || regptype == REG_PARSER_MULTI_TABLE)
15520abfb303SMasatake YAMATO 		? getInputLineNumberForFileOffset (offset)
15530abfb303SMasatake YAMATO 		: getInputLineNumber ();
15540abfb303SMasatake YAMATO }
15550abfb303SMasatake YAMATO 
fillEndLineFieldOfUpperScopes(struct lregexControlBlock * lcb,unsigned long endline)1556ec25b18fSMasatake YAMATO static void fillEndLineFieldOfUpperScopes (struct lregexControlBlock *lcb, unsigned long endline)
1557ec25b18fSMasatake YAMATO {
1558ec25b18fSMasatake YAMATO 	tagEntryInfo *entry;
15593afb5475SMasatake YAMATO 	int n = lcb->currentScope;
1560ec25b18fSMasatake YAMATO 
1561ec25b18fSMasatake YAMATO 	while ((entry = getEntryInCorkQueue (n))
1562ec25b18fSMasatake YAMATO 		   && (entry->extensionFields.endLine == 0))
1563ec25b18fSMasatake YAMATO 	{
1564ec25b18fSMasatake YAMATO 		entry->extensionFields.endLine = endline;
1565ec25b18fSMasatake YAMATO 		n = entry->extensionFields.scopeIndex;
1566ec25b18fSMasatake YAMATO 	}
1567ec25b18fSMasatake YAMATO }
1568ec25b18fSMasatake YAMATO 
hasNameSlot(const regexPattern * const patbuf)1569e8386a4eSMasatake YAMATO static bool hasNameSlot (const regexPattern* const patbuf)
1570e8386a4eSMasatake YAMATO {
1571e8386a4eSMasatake YAMATO 	return (patbuf->u.tag.name_pattern[0] != '\0'
1572e8386a4eSMasatake YAMATO 			|| patbuf->anonymous_tag_prefix);
1573e8386a4eSMasatake YAMATO }
1574e8386a4eSMasatake YAMATO 
scopeActionRef(int currentScope)1575f998e51dSMasatake YAMATO static int scopeActionRef (int currentScope)
1576f998e51dSMasatake YAMATO {
1577f998e51dSMasatake YAMATO 	int scope = currentScope;
1578f998e51dSMasatake YAMATO 	tagEntryInfo *entry;
1579f998e51dSMasatake YAMATO 	while ((entry = getEntryInCorkQueue (scope)) && entry->placeholder)
1580f998e51dSMasatake YAMATO 		/* Look at parent */
1581f998e51dSMasatake YAMATO 		scope = entry->extensionFields.scopeIndex;
1582f998e51dSMasatake YAMATO 	return scope;
1583f998e51dSMasatake YAMATO }
1584f998e51dSMasatake YAMATO 
matchTagPattern(struct lregexControlBlock * lcb,const char * line,const regexPattern * const patbuf,const regmatch_t * const pmatch,off_t offset,scriptWindow * window)1585fbcb3274SMasatake YAMATO static void matchTagPattern (struct lregexControlBlock *lcb,
1586fbcb3274SMasatake YAMATO 		const char* line,
1587d4c6f1e6SMasatake YAMATO 		const regexPattern* const patbuf,
158813939209SMasatake YAMATO 		const regmatch_t* const pmatch,
15892bbd136eSMasatake YAMATO 			     off_t offset, scriptWindow *window)
1590d4c6f1e6SMasatake YAMATO {
15910d56cc8eSMasatake YAMATO 	vString *const name =
15920d56cc8eSMasatake YAMATO 		(patbuf->u.tag.name_pattern[0] != '\0') ? substitute (line,
15930d56cc8eSMasatake YAMATO 															  patbuf->u.tag.name_pattern,
15940d56cc8eSMasatake YAMATO 															  BACK_REFERENCE_COUNT, pmatch):
15950d56cc8eSMasatake YAMATO 		(patbuf->anonymous_tag_prefix) ? anonGenerateNew (patbuf->anonymous_tag_prefix,
15960d56cc8eSMasatake YAMATO 														  patbuf->u.tag.kindIndex):
15970d56cc8eSMasatake YAMATO 		vStringNewInit ("");
1598ce990805SThomas Braun 	bool placeholder = !!((patbuf->scopeActions & SCOPE_PLACEHOLDER) == SCOPE_PLACEHOLDER);
15993afb5475SMasatake YAMATO 	int scope = CORK_NIL;
16002fa3c9e1SMasatake YAMATO 	int n;
16012fa3c9e1SMasatake YAMATO 
1602b593f516SMasatake YAMATO 	vStringStripLeading (name);
1603b593f516SMasatake YAMATO 	vStringStripTrailing (name);
1604b593f516SMasatake YAMATO 
16052fa3c9e1SMasatake YAMATO 	if (patbuf->scopeActions & SCOPE_REF)
1606f998e51dSMasatake YAMATO 		scope = scopeActionRef (lcb->currentScope);
16072fa3c9e1SMasatake YAMATO 	if (patbuf->scopeActions & SCOPE_CLEAR)
16082db4cedcSMasatake YAMATO 	{
16091e91f04aSMasatake YAMATO 		unsigned long endline = getInputLineNumberInRegPType(patbuf->regptype, offset);
1610dcac9704SMasatake YAMATO 
1611dcac9704SMasatake YAMATO 		/*
1612dcac9704SMasatake YAMATO 		 * SCOPE_CLEAR|SCOPE_PUSH implies that "set" was specified as the scope action.
1613dcac9704SMasatake YAMATO 		 * If the specified action is "set", getInputLineNumberInRegPType()
1614dcac9704SMasatake YAMATO 		 * returns the start line of the NEW scope. The cleared scopes are ended BEFORE
1615dcac9704SMasatake YAMATO 		 * the new scope. There is a gap. We must adjust the "end:" field here.
1616dcac9704SMasatake YAMATO 		 */
1617dcac9704SMasatake YAMATO 		if (patbuf->scopeActions & SCOPE_PUSH && endline > 0)
1618dcac9704SMasatake YAMATO 			endline--;
1619dcac9704SMasatake YAMATO 
1620ec25b18fSMasatake YAMATO 		fillEndLineFieldOfUpperScopes (lcb, endline);
16212db4cedcSMasatake YAMATO 		lcb->currentScope = CORK_NIL;
16222db4cedcSMasatake YAMATO 	}
16232fa3c9e1SMasatake YAMATO 	if (patbuf->scopeActions & SCOPE_POP)
16242fa3c9e1SMasatake YAMATO 	{
16252db4cedcSMasatake YAMATO 		tagEntryInfo *entry = getEntryInCorkQueue (lcb->currentScope);
16261e91f04aSMasatake YAMATO 
16271e91f04aSMasatake YAMATO 		if (entry && (entry->extensionFields.endLine == 0))
1628f998e51dSMasatake YAMATO 		{
16291e91f04aSMasatake YAMATO 			entry->extensionFields.endLine = getInputLineNumberInRegPType(patbuf->regptype, offset);
16301e91f04aSMasatake YAMATO 
1631f998e51dSMasatake YAMATO 			/*
1632f998e51dSMasatake YAMATO 			 * SCOPE_POP|SCOPE_REF_AFTER_POP implies that "replace" was specified as the
1633f998e51dSMasatake YAMATO 			 * scope action. If the specified action is "replace", getInputLineNumberInRegPType()
1634f998e51dSMasatake YAMATO 			 * returns the start line of the NEW scope. The popped scope is ended BEFORE
1635f998e51dSMasatake YAMATO 			 * the new scope. There is a gap. We must adjust the "end:" field here.
1636f998e51dSMasatake YAMATO 			 */
1637f998e51dSMasatake YAMATO 			if ((patbuf->scopeActions & SCOPE_REF_AFTER_POP) &&
1638f998e51dSMasatake YAMATO 				entry->extensionFields.endLine > 1)
1639f998e51dSMasatake YAMATO 				entry->extensionFields.endLine--;
1640f998e51dSMasatake YAMATO 		}
1641f998e51dSMasatake YAMATO 
16422db4cedcSMasatake YAMATO 		lcb->currentScope = entry? entry->extensionFields.scopeIndex: CORK_NIL;
16432fa3c9e1SMasatake YAMATO 	}
1644f998e51dSMasatake YAMATO 	if (patbuf->scopeActions & SCOPE_REF_AFTER_POP)
1645f998e51dSMasatake YAMATO 		scope = scopeActionRef (lcb->currentScope);
1646b593f516SMasatake YAMATO 
1647ce990805SThomas Braun 	if (vStringLength (name) == 0 && (placeholder == false))
1648b593f516SMasatake YAMATO 	{
1649ce990805SThomas Braun 		if (patbuf->accept_empty_name == false)
165013939209SMasatake YAMATO 			error (WARNING, "%s:%lu: null expansion of name pattern \"%s\"",
165113939209SMasatake YAMATO 			       getInputFileName (),
16520abfb303SMasatake YAMATO 				   getInputLineNumberInRegPType(patbuf->regptype, offset),
1653d4c6f1e6SMasatake YAMATO 			       patbuf->u.tag.name_pattern);
1654f6027918SMasatake YAMATO 		n = CORK_NIL;
16552fa3c9e1SMasatake YAMATO 	}
1656b593f516SMasatake YAMATO 	else
165713939209SMasatake YAMATO 	{
1658e024ff82SHadriel Kaplan 		static TrashBox* field_trashbox;
165913939209SMasatake YAMATO 		unsigned long ln = 0;
166013939209SMasatake YAMATO 		MIOPos pos;
1661f53f3c39SMasatake YAMATO 		tagEntryInfo e;
166216a2541cSMasatake YAMATO 		int kind;
166384f3a057SMasatake YAMATO 		roleBitsType roleBits;
166413939209SMasatake YAMATO 
166541e0b4f8SMasatake YAMATO 		if ((patbuf->regptype == REG_PARSER_MULTI_LINE)
166641e0b4f8SMasatake YAMATO 			|| (patbuf->regptype == REG_PARSER_MULTI_TABLE))
166713939209SMasatake YAMATO 		{
166813939209SMasatake YAMATO 			ln = getInputLineNumberForFileOffset (offset);
166913939209SMasatake YAMATO 			pos = getInputFilePositionForLine (ln);
167013939209SMasatake YAMATO 		}
167113939209SMasatake YAMATO 
1672f53f3c39SMasatake YAMATO 		n = CORK_NIL;
167316a2541cSMasatake YAMATO 		kind = patbuf->u.tag.kindIndex;
167484f3a057SMasatake YAMATO 		roleBits = patbuf->u.tag.roleBits;
1675f53f3c39SMasatake YAMATO 
1676a114f06bSMasatake YAMATO 		initRegexTag (&e, vStringValue (name), kind, ROLE_DEFINITION_INDEX, scope, placeholder,
1677e024ff82SHadriel Kaplan 					  ln, ln == 0? NULL: &pos, patbuf->xtagType);
1678e024ff82SHadriel Kaplan 
1679f53f3c39SMasatake YAMATO 		if (field_trashbox == NULL)
1680f53f3c39SMasatake YAMATO 		{
1681f53f3c39SMasatake YAMATO 			field_trashbox = trashBoxNew();
1682f53f3c39SMasatake YAMATO 			DEFAULT_TRASH_BOX (field_trashbox, trashBoxDelete);
1683f53f3c39SMasatake YAMATO 		}
1684f53f3c39SMasatake YAMATO 
1685f53f3c39SMasatake YAMATO 		if (patbuf->fieldPatterns)
1686f53f3c39SMasatake YAMATO 		{
168746ab94ccSMasatake YAMATO 			for (unsigned int i = 0; i < ptrArrayCount(patbuf->fieldPatterns); i++)
1688f53f3c39SMasatake YAMATO 			{
1689f53f3c39SMasatake YAMATO 				struct fieldPattern *fp = ptrArrayItem(patbuf->fieldPatterns, i);
1690f53f3c39SMasatake YAMATO 				if (isFieldEnabled (fp->ftype))
1691f53f3c39SMasatake YAMATO 				{
1692f53f3c39SMasatake YAMATO 					vString * const value = substitute (line, fp->template,
16930248c4bfSMasatake YAMATO 														BACK_REFERENCE_COUNT, pmatch);
1694aa4def17SMasatake YAMATO 					attachParserField (&e, false, fp->ftype, vStringValue (value));
1695f53f3c39SMasatake YAMATO 					trashBoxPut (field_trashbox, value,
1696f53f3c39SMasatake YAMATO 								 (TrashBoxDestroyItemProc)vStringDelete);
1697f53f3c39SMasatake YAMATO 				}
1698f53f3c39SMasatake YAMATO 			}
1699f53f3c39SMasatake YAMATO 		}
170084f3a057SMasatake YAMATO 
170184f3a057SMasatake YAMATO 		if (roleBits)
170284f3a057SMasatake YAMATO 		{
17034c64e833SMasatake YAMATO 			unsigned int roleIndex;
170484f3a057SMasatake YAMATO 
170584f3a057SMasatake YAMATO 			for (roleIndex = 0;
170684f3a057SMasatake YAMATO 				 roleIndex < countLanguageRoles(e.langType, kind);
170784f3a057SMasatake YAMATO 				 roleIndex++)
170884f3a057SMasatake YAMATO 			{
170984f3a057SMasatake YAMATO 				if (roleBits & makeRoleBit(roleIndex))
171084f3a057SMasatake YAMATO 					assignRole (&e, roleIndex);
171184f3a057SMasatake YAMATO 			}
171284f3a057SMasatake YAMATO 		}
17130d56cc8eSMasatake YAMATO 
17140d56cc8eSMasatake YAMATO 		if (patbuf->anonymous_tag_prefix)
17150d56cc8eSMasatake YAMATO 			markTagExtraBit (&e, XTAG_ANONYMOUS);
17160d56cc8eSMasatake YAMATO 
1717f53f3c39SMasatake YAMATO 		n = makeTagEntry (&e);
1718f53f3c39SMasatake YAMATO 
1719f53f3c39SMasatake YAMATO 		trashBoxMakeEmpty(field_trashbox);
1720f53f3c39SMasatake YAMATO 	}
1721b593f516SMasatake YAMATO 
1722b593f516SMasatake YAMATO 	if (patbuf->scopeActions & SCOPE_PUSH)
17232db4cedcSMasatake YAMATO 		lcb->currentScope = n;
17242fa3c9e1SMasatake YAMATO 
17252bbd136eSMasatake YAMATO 	if (n != CORK_NIL && window)
1726e8386a4eSMasatake YAMATO 	{
17272bbd136eSMasatake YAMATO 		scriptSetup (optvm, lcb, n, window);
1728668e3666SMasatake YAMATO 		EsObject *e = scriptEval (optvm, patbuf->optscript);
1729e8386a4eSMasatake YAMATO 		if (es_error_p (e))
1730e8386a4eSMasatake YAMATO 			error (WARNING, "error when evaluating: %s", patbuf->optscript_src);
1731e8386a4eSMasatake YAMATO 		es_object_unref (e);
1732668e3666SMasatake YAMATO 		scriptTeardown (optvm, lcb);
1733e8386a4eSMasatake YAMATO 	}
1734e8386a4eSMasatake YAMATO 
1735d4c6f1e6SMasatake YAMATO 	vStringDelete (name);
1736d4c6f1e6SMasatake YAMATO }
1737d4c6f1e6SMasatake YAMATO 
matchCallbackPattern(const vString * const line,const regexPattern * const patbuf,const regmatch_t * const pmatch)173818480890SMasatake YAMATO static bool matchCallbackPattern (
1739d4c6f1e6SMasatake YAMATO 		const vString* const line, const regexPattern* const patbuf,
1740d4c6f1e6SMasatake YAMATO 		const regmatch_t* const pmatch)
1741d4c6f1e6SMasatake YAMATO {
1742d4c6f1e6SMasatake YAMATO 	regexMatch matches [BACK_REFERENCE_COUNT];
1743d4c6f1e6SMasatake YAMATO 	unsigned int count = 0;
1744d4c6f1e6SMasatake YAMATO 	int i;
1745d4c6f1e6SMasatake YAMATO 	for (i = 0  ;  i < BACK_REFERENCE_COUNT  ;  ++i)
1746d4c6f1e6SMasatake YAMATO 	{
1747d4c6f1e6SMasatake YAMATO 		matches [i].start  = pmatch [i].rm_so;
1748d4c6f1e6SMasatake YAMATO 		matches [i].length = pmatch [i].rm_eo - pmatch [i].rm_so;
1749d4c6f1e6SMasatake YAMATO 		/* a valid match may have both offsets == -1,
1750d4c6f1e6SMasatake YAMATO 		 * e.g. (foo)*(bar) matching "bar" - see CTags bug 271.
1751d4c6f1e6SMasatake YAMATO 		 * As POSIX regex doesn't seem to have a way to count matches,
1752d4c6f1e6SMasatake YAMATO 		 * we return the count up to the last non-empty match. */
1753d4c6f1e6SMasatake YAMATO 		if (pmatch [i].rm_so != -1)
1754d4c6f1e6SMasatake YAMATO 			count = i + 1;
1755d4c6f1e6SMasatake YAMATO 	}
175618480890SMasatake YAMATO 	return patbuf->u.callback.function (vStringValue (line), matches, count,
17576ff4dab6SMasatake YAMATO 				     patbuf->u.callback.userData);
1758d4c6f1e6SMasatake YAMATO }
1759d4c6f1e6SMasatake YAMATO 
17609a1e266aSHadriel Kaplan 
printMessage(const langType language,const regexPattern * const ptrn,const off_t offset,const char * const line,const regmatch_t * const pmatch)17619a1e266aSHadriel Kaplan static void printMessage(const langType language,
17629a1e266aSHadriel Kaplan 						 const regexPattern *const ptrn,
17639a1e266aSHadriel Kaplan 						 const off_t offset,
17649a1e266aSHadriel Kaplan 						 const char *const line,
17659a1e266aSHadriel Kaplan 						 const regmatch_t* const pmatch)
17669a1e266aSHadriel Kaplan {
17679a1e266aSHadriel Kaplan 	vString *msg;
17689a1e266aSHadriel Kaplan 
17699a1e266aSHadriel Kaplan 	Assert (ptrn);
17709a1e266aSHadriel Kaplan 	Assert (ptrn->message.selection > 0);
17719a1e266aSHadriel Kaplan 	Assert (ptrn->message.message_string);
17729a1e266aSHadriel Kaplan 
17739a1e266aSHadriel Kaplan 	msg = substitute (line, ptrn->message.message_string, BACK_REFERENCE_COUNT, pmatch);
17749a1e266aSHadriel Kaplan 
17759a1e266aSHadriel Kaplan 	error (ptrn->message.selection, "%sMessage from regex<%s>: %s (%s:%lu)",
17769a1e266aSHadriel Kaplan 		   (ptrn->message.selection == FATAL ? "Fatal: " : ""),
17779a1e266aSHadriel Kaplan 		   getLanguageName (language),
17789a1e266aSHadriel Kaplan 		   vStringValue (msg),
17799a1e266aSHadriel Kaplan 		   getInputFileName (),
17809a1e266aSHadriel Kaplan 		   getInputLineNumberInRegPType (ptrn->regptype, offset));
17819a1e266aSHadriel Kaplan 
17829a1e266aSHadriel Kaplan 	vStringDelete (msg);
17839a1e266aSHadriel Kaplan }
17849a1e266aSHadriel Kaplan 
isGuestRequestConsistent(struct guestRequest * guest_req)17856cdf5716SMasatake YAMATO static bool isGuestRequestConsistent (struct guestRequest *guest_req)
17866cdf5716SMasatake YAMATO {
17876cdf5716SMasatake YAMATO 	return (guest_req->lang != LANG_IGNORE)
17886cdf5716SMasatake YAMATO 		&& (guest_req->boundary[BOUNDARY_START].offset < guest_req->boundary[BOUNDARY_END].offset);
17896cdf5716SMasatake YAMATO }
17906cdf5716SMasatake YAMATO 
fillGuestRequest(const char * start,const char * current,regmatch_t pmatch[BACK_REFERENCE_COUNT],struct guestSpec * guest_spec,struct guestRequest * guest_req)17916cdf5716SMasatake YAMATO static bool fillGuestRequest (const char *start,
17926cdf5716SMasatake YAMATO 							  const char *current,
17936cdf5716SMasatake YAMATO 							  regmatch_t pmatch [BACK_REFERENCE_COUNT],
17946cdf5716SMasatake YAMATO 							  struct guestSpec *guest_spec,
17956cdf5716SMasatake YAMATO 							  struct guestRequest *guest_req)
17966cdf5716SMasatake YAMATO {
17976cdf5716SMasatake YAMATO 	if (guest_spec->lang.type == GUEST_LANG_UNKNOWN)
17986cdf5716SMasatake YAMATO 		return false;
17996cdf5716SMasatake YAMATO 	else if (guest_spec->lang.type == GUEST_LANG_PLACEHOLDER)
18006cdf5716SMasatake YAMATO 		;
18016cdf5716SMasatake YAMATO 	else if (guest_spec->lang.type == GUEST_LANG_STATIC_LANGNAME)
18026cdf5716SMasatake YAMATO 	{
18036cdf5716SMasatake YAMATO 		guest_req->lang = guest_spec->lang.spec.lang;
18046cdf5716SMasatake YAMATO 		guest_req->lang_set = true;
18056cdf5716SMasatake YAMATO 	}
18066cdf5716SMasatake YAMATO 	else if (guest_spec->lang.type == GUEST_LANG_PTN_GROUP_FOR_LANGNAME)
18076cdf5716SMasatake YAMATO 	{
18086cdf5716SMasatake YAMATO 		const char * name = current + pmatch [guest_spec->lang.spec.patternGroup].rm_so;
18096cdf5716SMasatake YAMATO 		int size = pmatch [guest_spec->lang.spec.patternGroup].rm_eo
18106cdf5716SMasatake YAMATO 			- pmatch [guest_spec->lang.spec.patternGroup].rm_so;
18116cdf5716SMasatake YAMATO 		if (size > 0)
181202108d6fScyy 		{
1813*6024deefSMasatake YAMATO 			guest_req->lang = getNamedLanguageOrAlias (name, size);
18146cdf5716SMasatake YAMATO 			guest_req->lang_set = true;
18156cdf5716SMasatake YAMATO 		}
181602108d6fScyy 	}
18176cdf5716SMasatake YAMATO 	else if (guest_spec->lang.type == GUEST_LANG_PTN_GROUP_FOR_FILEMAP)
18186cdf5716SMasatake YAMATO 	{
18196cdf5716SMasatake YAMATO 		const char * name = current + pmatch [guest_spec->lang.spec.patternGroup].rm_so;
18206cdf5716SMasatake YAMATO 		int size = pmatch [guest_spec->lang.spec.patternGroup].rm_eo
18216cdf5716SMasatake YAMATO 			- pmatch [guest_spec->lang.spec.patternGroup].rm_so;
18226cdf5716SMasatake YAMATO 		char *fname = (size > 0)? eStrndup (name, size): NULL;
18236cdf5716SMasatake YAMATO 
18246cdf5716SMasatake YAMATO 		if (fname)
18256cdf5716SMasatake YAMATO 		{
18266cdf5716SMasatake YAMATO 			guest_req->lang = getLanguageForFilename (fname, LANG_AUTO);
182702108d6fScyy 			guest_req->lang_set = true;
18286cdf5716SMasatake YAMATO 			eFree (fname);
18296cdf5716SMasatake YAMATO 		}
18306cdf5716SMasatake YAMATO 	}
18316cdf5716SMasatake YAMATO 
18326cdf5716SMasatake YAMATO 	for (int i = 0; i < 2; i++)
18336cdf5716SMasatake YAMATO 	{
18346cdf5716SMasatake YAMATO 		struct boundarySpec *boundary_spec = guest_spec->boundary + i;
18356cdf5716SMasatake YAMATO 		struct boundaryInRequest *boundary = guest_req->boundary + i;
18366cdf5716SMasatake YAMATO 		if (!boundary_spec->placeholder)
18376cdf5716SMasatake YAMATO 		{
18386cdf5716SMasatake YAMATO 			boundary->offset =  current - start + (boundary_spec->fromStartOfGroup
18396cdf5716SMasatake YAMATO 												   ? pmatch [boundary_spec->patternGroup].rm_so
18406cdf5716SMasatake YAMATO 												   : pmatch [boundary_spec->patternGroup].rm_eo);
18416cdf5716SMasatake YAMATO 			boundary->offset_set = true;
18426cdf5716SMasatake YAMATO 		}
18436cdf5716SMasatake YAMATO 	}
18446cdf5716SMasatake YAMATO 	return guestRequestIsFilled (guest_req);
18456cdf5716SMasatake YAMATO }
18469a1e266aSHadriel Kaplan 
matchRegexPattern(struct lregexControlBlock * lcb,const vString * const line,regexTableEntry * entry)1847fbcb3274SMasatake YAMATO static bool matchRegexPattern (struct lregexControlBlock *lcb,
1848fbcb3274SMasatake YAMATO 							   const vString* const line,
1849134629a0SHadriel Kaplan 							   regexTableEntry *entry)
1850d4c6f1e6SMasatake YAMATO {
1851ce990805SThomas Braun 	bool result = false;
1852d4c6f1e6SMasatake YAMATO 	regmatch_t pmatch [BACK_REFERENCE_COUNT];
18532a738f47SMasatake YAMATO 	int match;
1854134629a0SHadriel Kaplan 	regexPattern* patbuf = entry->pattern;
18556cdf5716SMasatake YAMATO 	struct guestSpec  *guest = &patbuf->guest;
18562a738f47SMasatake YAMATO 
18572a738f47SMasatake YAMATO 	if (patbuf->disabled && *(patbuf->disabled))
1858ce990805SThomas Braun 		return false;
18592a738f47SMasatake YAMATO 
1860c30b89acSMasatake YAMATO 	match = patbuf->pattern.backend->match (patbuf->pattern.backend,
1861c30b89acSMasatake YAMATO 											patbuf->pattern.code, vStringValue (line),
1862c30b89acSMasatake YAMATO 											vStringLength (line),
1863c30b89acSMasatake YAMATO 											pmatch);
1864c30b89acSMasatake YAMATO 
1865d4c6f1e6SMasatake YAMATO 	if (match == 0)
1866d4c6f1e6SMasatake YAMATO 	{
1867ce990805SThomas Braun 		result = true;
1868134629a0SHadriel Kaplan 		entry->statistics.match++;
18692bbd136eSMasatake YAMATO 		scriptWindow window = {
18702bbd136eSMasatake YAMATO 			.line = vStringValue (line),
1871ed3202bdSMasatake YAMATO 			.start = 0,
18722bbd136eSMasatake YAMATO 			.patbuf = patbuf,
18732bbd136eSMasatake YAMATO 			.pmatch = pmatch,
18742bbd136eSMasatake YAMATO 			.nmatch = BACK_REFERENCE_COUNT,
1875653692b7SMasatake YAMATO 			.advanceto = false,
18762bbd136eSMasatake YAMATO 		};
18772bbd136eSMasatake YAMATO 
1878e8386a4eSMasatake YAMATO 		if (patbuf->optscript && (! hasNameSlot (patbuf)))
1879e8386a4eSMasatake YAMATO 		{
18802bbd136eSMasatake YAMATO 			scriptSetup (optvm, lcb, CORK_NIL, &window);
1881668e3666SMasatake YAMATO 			EsObject *e = scriptEval (optvm, patbuf->optscript);
1882e8386a4eSMasatake YAMATO 			if (es_error_p (e))
1883e8386a4eSMasatake YAMATO 				error (WARNING, "error when evaluating: %s", patbuf->optscript_src);
1884e8386a4eSMasatake YAMATO 			es_object_unref (e);
1885668e3666SMasatake YAMATO 			scriptTeardown (optvm, lcb);
1886e8386a4eSMasatake YAMATO 		}
18871e923193SMasatake YAMATO 
18889a1e266aSHadriel Kaplan 		if (hasMessage(patbuf))
18899a1e266aSHadriel Kaplan 			printMessage(lcb->owner, patbuf, 0, vStringValue (line), pmatch);
18909a1e266aSHadriel Kaplan 
1891d4c6f1e6SMasatake YAMATO 		if (patbuf->type == PTRN_TAG)
18926cdf5716SMasatake YAMATO 		{
18932bbd136eSMasatake YAMATO 			matchTagPattern (lcb, vStringValue (line), patbuf, pmatch, 0,
18942bbd136eSMasatake YAMATO 							 (patbuf->optscript && hasNameSlot (patbuf))? &window: NULL);
18956cdf5716SMasatake YAMATO 
18966cdf5716SMasatake YAMATO 			if (guest->lang.type != GUEST_LANG_UNKNOWN)
18976cdf5716SMasatake YAMATO 			{
18986cdf5716SMasatake YAMATO 				unsigned long ln = getInputLineNumber ();
18996cdf5716SMasatake YAMATO 				long current = getInputFileOffsetForLine (ln);
19006cdf5716SMasatake YAMATO 				if (fillGuestRequest (vStringValue (line) - current,
19016cdf5716SMasatake YAMATO 									  vStringValue (line), pmatch, guest, lcb->guest_req))
19026cdf5716SMasatake YAMATO 				{
19036cdf5716SMasatake YAMATO 					Assert (lcb->guest_req->lang != LANG_AUTO);
19046cdf5716SMasatake YAMATO 					if (isGuestRequestConsistent(lcb->guest_req))
19056cdf5716SMasatake YAMATO 						guestRequestSubmit (lcb->guest_req);
19066cdf5716SMasatake YAMATO 					guestRequestClear (lcb->guest_req);
19076cdf5716SMasatake YAMATO 				}
19086cdf5716SMasatake YAMATO 			}
19096cdf5716SMasatake YAMATO 		}
1910d4c6f1e6SMasatake YAMATO 		else if (patbuf->type == PTRN_CALLBACK)
191118480890SMasatake YAMATO 			result = matchCallbackPattern (line, patbuf, pmatch);
1912d4c6f1e6SMasatake YAMATO 		else
1913d4c6f1e6SMasatake YAMATO 		{
1914d4c6f1e6SMasatake YAMATO 			Assert ("invalid pattern type" == NULL);
1915ce990805SThomas Braun 			result = false;
1916d4c6f1e6SMasatake YAMATO 		}
1917d4c6f1e6SMasatake YAMATO 	}
19181e923193SMasatake YAMATO 	else
1919134629a0SHadriel Kaplan 		entry->statistics.unmatch++;
1920d4c6f1e6SMasatake YAMATO 	return result;
1921d4c6f1e6SMasatake YAMATO }
1922d4c6f1e6SMasatake YAMATO 
matchMultilineRegexPattern(struct lregexControlBlock * lcb,const vString * const allLines,regexTableEntry * entry)1923fbcb3274SMasatake YAMATO static bool matchMultilineRegexPattern (struct lregexControlBlock *lcb,
1924fbcb3274SMasatake YAMATO 										const vString* const allLines,
1925134629a0SHadriel Kaplan 										regexTableEntry *entry)
192613939209SMasatake YAMATO {
192713939209SMasatake YAMATO 	const char *start;
192813939209SMasatake YAMATO 	const char *current;
19299a1e266aSHadriel Kaplan 	off_t offset = 0;
1930134629a0SHadriel Kaplan 	regexPattern* patbuf = entry->pattern;
19316cdf5716SMasatake YAMATO 	struct mGroupSpec *mgroup = &patbuf->mgroup;
19326cdf5716SMasatake YAMATO 	struct guestSpec  *guest = &patbuf->guest;
193313939209SMasatake YAMATO 
193413939209SMasatake YAMATO 	bool result = false;
193513939209SMasatake YAMATO 	regmatch_t pmatch [BACK_REFERENCE_COUNT];
193613939209SMasatake YAMATO 	int match = 0;
1937a33dec34SMasatake YAMATO 	unsigned int delta = 1;
193813939209SMasatake YAMATO 
1939134629a0SHadriel Kaplan 	Assert (patbuf);
1940134629a0SHadriel Kaplan 
194113939209SMasatake YAMATO 	if (patbuf->disabled && *(patbuf->disabled))
194213939209SMasatake YAMATO 		return false;
194313939209SMasatake YAMATO 
1944a33dec34SMasatake YAMATO 	current = start = vStringValue (allLines);
1945a33dec34SMasatake YAMATO 	do
194613939209SMasatake YAMATO 	{
1947c30b89acSMasatake YAMATO 		match = patbuf->pattern.backend->match (patbuf->pattern.backend,
1948c30b89acSMasatake YAMATO 												patbuf->pattern.code, current,
1949c30b89acSMasatake YAMATO 												vStringLength (allLines) - (current - start),
1950c30b89acSMasatake YAMATO 												pmatch);
1951c30b89acSMasatake YAMATO 
1952a33dec34SMasatake YAMATO 		if (match != 0)
195313939209SMasatake YAMATO 		{
1954134629a0SHadriel Kaplan 			entry->statistics.unmatch++;
1955a33dec34SMasatake YAMATO 			break;
1956a33dec34SMasatake YAMATO 		}
1957a33dec34SMasatake YAMATO 
19589a1e266aSHadriel Kaplan 		if (hasMessage(patbuf))
19599a1e266aSHadriel Kaplan 			printMessage(lcb->owner, patbuf, (current + pmatch[0].rm_so) - start, current, pmatch);
19609a1e266aSHadriel Kaplan 
19616cdf5716SMasatake YAMATO 		offset = (current + pmatch [mgroup->forLineNumberDetermination].rm_so)
19629a1e266aSHadriel Kaplan 				 - start;
19639a1e266aSHadriel Kaplan 
1964134629a0SHadriel Kaplan 		entry->statistics.match++;
19652bbd136eSMasatake YAMATO 		scriptWindow window = {
19662bbd136eSMasatake YAMATO 			.line = current,
1967ed3202bdSMasatake YAMATO 			.start = start,
19682bbd136eSMasatake YAMATO 			.patbuf = patbuf,
19692bbd136eSMasatake YAMATO 			.pmatch = pmatch,
19702bbd136eSMasatake YAMATO 			.nmatch = BACK_REFERENCE_COUNT,
1971653692b7SMasatake YAMATO 			.advanceto = false,
19722bbd136eSMasatake YAMATO 		};
19732bbd136eSMasatake YAMATO 
1974e8386a4eSMasatake YAMATO 		if (patbuf->optscript && (! hasNameSlot (patbuf)))
1975e8386a4eSMasatake YAMATO 		{
19762bbd136eSMasatake YAMATO 			scriptSetup (optvm, lcb, CORK_NIL, &window);
1977668e3666SMasatake YAMATO 			EsObject *e = scriptEval (optvm, patbuf->optscript);
1978e8386a4eSMasatake YAMATO 			if (es_error_p (e))
1979e8386a4eSMasatake YAMATO 				error (WARNING, "error when evaluating: %s", patbuf->optscript_src);
1980e8386a4eSMasatake YAMATO 			es_object_unref (e);
1981668e3666SMasatake YAMATO 			scriptTeardown (optvm, lcb);
1982e8386a4eSMasatake YAMATO 		}
1983e8386a4eSMasatake YAMATO 
198413939209SMasatake YAMATO 		if (patbuf->type == PTRN_TAG)
198513939209SMasatake YAMATO 		{
19862bbd136eSMasatake YAMATO 			matchTagPattern (lcb, current, patbuf, pmatch, offset,
19872bbd136eSMasatake YAMATO 							 (patbuf->optscript && hasNameSlot (patbuf))? &window: NULL);
198813939209SMasatake YAMATO 			result = true;
198913939209SMasatake YAMATO 		}
199013939209SMasatake YAMATO 		else if (patbuf->type == PTRN_CALLBACK)
199113939209SMasatake YAMATO 			;	/* Not implemented yet */
199213939209SMasatake YAMATO 		else
199313939209SMasatake YAMATO 		{
199413939209SMasatake YAMATO 			Assert ("invalid pattern type" == NULL);
199513939209SMasatake YAMATO 			result = false;
199613939209SMasatake YAMATO 			break;
199713939209SMasatake YAMATO 		}
1998a33dec34SMasatake YAMATO 
19996cdf5716SMasatake YAMATO 		if (fillGuestRequest (start, current, pmatch, guest, lcb->guest_req))
20006cdf5716SMasatake YAMATO 		{
20016cdf5716SMasatake YAMATO 			Assert (lcb->guest_req->lang != LANG_AUTO);
20026cdf5716SMasatake YAMATO 			if (isGuestRequestConsistent(lcb->guest_req))
20036cdf5716SMasatake YAMATO 				guestRequestSubmit (lcb->guest_req);
20046cdf5716SMasatake YAMATO 			guestRequestClear (lcb->guest_req);
20056cdf5716SMasatake YAMATO 		}
20066cdf5716SMasatake YAMATO 
20076cdf5716SMasatake YAMATO 		delta = (mgroup->nextFromStart
20086cdf5716SMasatake YAMATO 				 ? pmatch [mgroup->forNextScanning].rm_so
20096cdf5716SMasatake YAMATO 				 : pmatch [mgroup->forNextScanning].rm_eo);
2010a33dec34SMasatake YAMATO 		if (delta == 0)
2011a33dec34SMasatake YAMATO 		{
2012746bdfabSColomban Wendling 			unsigned int pos = current - start;
2013a33dec34SMasatake YAMATO 			error (WARNING,
2014a33dec34SMasatake YAMATO 				   "a multi line regex pattern doesn't advance the input cursor: %s",
2015a33dec34SMasatake YAMATO 				   patbuf->pattern_string);
2016a33dec34SMasatake YAMATO 			error (WARNING, "Language: %s, input file: %s, pos: %u",
2017746bdfabSColomban Wendling 				   getLanguageName (lcb->owner), getInputFileName(), pos);
2018a33dec34SMasatake YAMATO 			break;
201913939209SMasatake YAMATO 		}
2020a33dec34SMasatake YAMATO 		current += delta;
2021a33dec34SMasatake YAMATO 
2022a33dec34SMasatake YAMATO 	} while (current < start + vStringLength (allLines));
2023a33dec34SMasatake YAMATO 
202413939209SMasatake YAMATO 	return result;
202513939209SMasatake YAMATO }
2026d4c6f1e6SMasatake YAMATO 
2027d4c6f1e6SMasatake YAMATO /* PUBLIC INTERFACE */
2028d4c6f1e6SMasatake YAMATO 
2029d4c6f1e6SMasatake YAMATO /* Match against all patterns for specified language. Returns true if at least
2030d4c6f1e6SMasatake YAMATO  * on pattern matched.
2031d4c6f1e6SMasatake YAMATO  */
matchRegex(struct lregexControlBlock * lcb,const vString * const line)203253dda59eSMasatake YAMATO extern bool matchRegex (struct lregexControlBlock *lcb, const vString* const line)
2033d4c6f1e6SMasatake YAMATO {
2034ce990805SThomas Braun 	bool result = false;
2035d4c6f1e6SMasatake YAMATO 	unsigned int i;
2036134629a0SHadriel Kaplan 	for (i = 0  ;  i < ptrArrayCount(lcb->entries[REG_PARSER_SINGLE_LINE])  ;  ++i)
2037d4c6f1e6SMasatake YAMATO 	{
2038134629a0SHadriel Kaplan 		regexTableEntry *entry = ptrArrayItem(lcb->entries[REG_PARSER_SINGLE_LINE], i);
2039134629a0SHadriel Kaplan 		regexPattern *ptrn = entry->pattern;
2040134629a0SHadriel Kaplan 
2041134629a0SHadriel Kaplan 		Assert (ptrn);
204210db13faSMasatake YAMATO 
204310db13faSMasatake YAMATO 		if ((ptrn->xtagType != XTAG_UNKNOWN)
204410db13faSMasatake YAMATO 			&& (!isXtagEnabled (ptrn->xtagType)))
204510db13faSMasatake YAMATO 				continue;
204610db13faSMasatake YAMATO 
2047134629a0SHadriel Kaplan 		if (matchRegexPattern (lcb, line, entry))
2048d4c6f1e6SMasatake YAMATO 		{
2049ce990805SThomas Braun 			result = true;
2050d4c6f1e6SMasatake YAMATO 			if (ptrn->exclusive)
2051d4c6f1e6SMasatake YAMATO 				break;
2052d4c6f1e6SMasatake YAMATO 		}
2053d4c6f1e6SMasatake YAMATO 	}
2054d4c6f1e6SMasatake YAMATO 	return result;
2055d4c6f1e6SMasatake YAMATO }
2056d4c6f1e6SMasatake YAMATO 
notifyRegexInputStart(struct lregexControlBlock * lcb)20572db4cedcSMasatake YAMATO extern void notifyRegexInputStart (struct lregexControlBlock *lcb)
20582db4cedcSMasatake YAMATO {
20592db4cedcSMasatake YAMATO 	lcb->currentScope = CORK_NIL;
206041e0b4f8SMasatake YAMATO 
206141e0b4f8SMasatake YAMATO 	ptrArrayClear (lcb->tstack);
20626cdf5716SMasatake YAMATO 	guestRequestClear (lcb->guest_req);
2063e8386a4eSMasatake YAMATO 
2064e8386a4eSMasatake YAMATO 	opt_vm_dstack_push (optvm, lregex_dict);
2065e8386a4eSMasatake YAMATO 
2066e8386a4eSMasatake YAMATO 	if (es_null (lcb->local_dict))
2067e8386a4eSMasatake YAMATO 		lcb->local_dict = opt_dict_new (23);
2068e8386a4eSMasatake YAMATO 	opt_vm_dstack_push (optvm, lcb->local_dict);
20692bbd136eSMasatake YAMATO 	opt_vm_set_app_data (optvm, lcb);
2070b6124a60SMasatake YAMATO 	scriptEvalHook (optvm, lcb, SCRIPT_HOOK_PRELUDE);
20712db4cedcSMasatake YAMATO }
20722db4cedcSMasatake YAMATO 
notifyRegexInputEnd(struct lregexControlBlock * lcb)20732db4cedcSMasatake YAMATO extern void notifyRegexInputEnd (struct lregexControlBlock *lcb)
20742db4cedcSMasatake YAMATO {
2075b6124a60SMasatake YAMATO 	scriptEvalHook (optvm, lcb, SCRIPT_HOOK_SEQUEL);
20762bbd136eSMasatake YAMATO 	opt_vm_set_app_data (optvm, NULL);
2077e8386a4eSMasatake YAMATO 	opt_vm_clear (optvm);
2078e8386a4eSMasatake YAMATO 	opt_dict_clear (lcb->local_dict);
2079ec25b18fSMasatake YAMATO 	unsigned long endline = getInputLineNumber ();
2080ec25b18fSMasatake YAMATO 	fillEndLineFieldOfUpperScopes (lcb, endline);
20812db4cedcSMasatake YAMATO }
20822db4cedcSMasatake YAMATO 
findRegexTagsMainloop(int (* driver)(void))20832d7d0792SMasatake YAMATO extern void findRegexTagsMainloop (int (* driver)(void))
2084d4c6f1e6SMasatake YAMATO {
2085d4c6f1e6SMasatake YAMATO 	/* merely read all lines of the file */
20862d7d0792SMasatake YAMATO 	while (driver () != EOF)
2087d4c6f1e6SMasatake YAMATO 		;
2088d4c6f1e6SMasatake YAMATO }
2089d4c6f1e6SMasatake YAMATO 
fileReadLineDriver(void)20902d7d0792SMasatake YAMATO static int fileReadLineDriver(void)
20912d7d0792SMasatake YAMATO {
20921b312fe7SMasatake YAMATO 	return (readLineFromInputFile () == NULL)? EOF: 1;
20932d7d0792SMasatake YAMATO }
20942d7d0792SMasatake YAMATO 
findRegexTags(void)20952d7d0792SMasatake YAMATO extern void findRegexTags (void)
20962d7d0792SMasatake YAMATO {
20972d7d0792SMasatake YAMATO 	findRegexTagsMainloop (fileReadLineDriver);
20982d7d0792SMasatake YAMATO }
20992d7d0792SMasatake YAMATO 
doesExpectCorkInRegex0(ptrArray * entries)2100c25346c2SMasatake YAMATO static bool doesExpectCorkInRegex0(ptrArray *entries)
21012fa3c9e1SMasatake YAMATO {
2102134629a0SHadriel Kaplan 	for (unsigned int i = 0; i < ptrArrayCount(entries); i++)
2103b2c16b34SMasatake YAMATO 	{
2104134629a0SHadriel Kaplan 		regexTableEntry *entry = ptrArrayItem(entries, i);
2105134629a0SHadriel Kaplan 		Assert (entry && entry->pattern);
2106e8386a4eSMasatake YAMATO 		if (entry->pattern->scopeActions
2107e8386a4eSMasatake YAMATO 			|| entry->pattern->optscript
2108e8386a4eSMasatake YAMATO 			)
210941e0b4f8SMasatake YAMATO 			return true;
211041e0b4f8SMasatake YAMATO 	}
211141e0b4f8SMasatake YAMATO 	return false;
2112b2c16b34SMasatake YAMATO }
2113a656c9bfSMasatake YAMATO 
doesExpectCorkInRegex(struct lregexControlBlock * lcb)2114c25346c2SMasatake YAMATO extern bool doesExpectCorkInRegex (struct lregexControlBlock *lcb)
211541e0b4f8SMasatake YAMATO {
2116134629a0SHadriel Kaplan 	ptrArray *entries;
211741e0b4f8SMasatake YAMATO 
2118134629a0SHadriel Kaplan 	entries = lcb->entries[REG_PARSER_SINGLE_LINE];
2119c25346c2SMasatake YAMATO 	if (doesExpectCorkInRegex0 (entries))
212041e0b4f8SMasatake YAMATO 		return true;
212141e0b4f8SMasatake YAMATO 
2122235d5682SMasatake YAMATO 	entries = lcb->entries[REG_PARSER_MULTI_LINE];
2123235d5682SMasatake YAMATO 	if (doesExpectCorkInRegex0 (entries))
2124235d5682SMasatake YAMATO 		return true;
2125235d5682SMasatake YAMATO 
212641e0b4f8SMasatake YAMATO 	for (unsigned int i = 0; i < ptrArrayCount(lcb->tables); i++)
212741e0b4f8SMasatake YAMATO 	{
212841e0b4f8SMasatake YAMATO 		struct regexTable *table = ptrArrayItem(lcb->tables, i);
2129c25346c2SMasatake YAMATO 		if (doesExpectCorkInRegex0 (table->entries))
213041e0b4f8SMasatake YAMATO 			return true;
213141e0b4f8SMasatake YAMATO 	}
213241e0b4f8SMasatake YAMATO 
213341e0b4f8SMasatake YAMATO 	return false;
21342fa3c9e1SMasatake YAMATO }
21352fa3c9e1SMasatake YAMATO 
escapeRegexPattern(const char * pattern)21365372d785SMasatake YAMATO static char *escapeRegexPattern (const char* pattern)
21375372d785SMasatake YAMATO {
21385372d785SMasatake YAMATO 	vString *p = vStringNew ();
21395372d785SMasatake YAMATO 
21405372d785SMasatake YAMATO 	while (*pattern != '\0')
21415372d785SMasatake YAMATO 	{
21425372d785SMasatake YAMATO 		char c = *pattern;
21435372d785SMasatake YAMATO 		if (c == '\n')
21445372d785SMasatake YAMATO 			vStringCatS(p, "\\n");
21455372d785SMasatake YAMATO 		else if (c == '\t')
21465372d785SMasatake YAMATO 			vStringCatS(p, "\\t");
21475372d785SMasatake YAMATO 		else if (c == '\\')
21485372d785SMasatake YAMATO 			vStringCatS(p, "\\\\");
21495372d785SMasatake YAMATO 		else
21505372d785SMasatake YAMATO 			vStringPut(p, c);
21515372d785SMasatake YAMATO 
21525372d785SMasatake YAMATO 		pattern++;
21535372d785SMasatake YAMATO 	}
21545372d785SMasatake YAMATO 
21555372d785SMasatake YAMATO 	return vStringDeleteUnwrap (p);
21565372d785SMasatake YAMATO }
21575372d785SMasatake YAMATO 
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)2158056b32e1SMasatake YAMATO static regexPattern *addTagRegexInternal (struct lregexControlBlock *lcb,
21590cbf3f0dSMasatake YAMATO 										  int table_index,
21601b9c3aecSMasatake YAMATO 					  enum regexParserType regptype,
2161ed0c063bSMasatake YAMATO 					  const char* const regex,
2162ed0c063bSMasatake YAMATO 					  const char* const name,
2163ed0c063bSMasatake YAMATO 					  const char* const kinds,
21642a738f47SMasatake YAMATO 					  const char* const flags,
2165ce990805SThomas Braun 					  bool *disabled)
2166d4c6f1e6SMasatake YAMATO {
2167d4c6f1e6SMasatake YAMATO 	Assert (regex != NULL);
2168d4c6f1e6SMasatake YAMATO 	Assert (name != NULL);
2169d00f728aSMasatake YAMATO 
2170d00f728aSMasatake YAMATO 	if (!regexAvailable)
2171d00f728aSMasatake YAMATO 		return NULL;
2172d00f728aSMasatake YAMATO 
2173c30b89acSMasatake YAMATO 	regexCompiledCode cp = compileRegex (regptype, regex, flags);
2174c30b89acSMasatake YAMATO 	if (cp.code == NULL)
2175c30b89acSMasatake YAMATO 	{
2176c30b89acSMasatake YAMATO 		error (WARNING, "pattern: %s", regex);
2177c30b89acSMasatake YAMATO 		if (table_index != TABLE_INDEX_UNUSED)
2178c30b89acSMasatake YAMATO 		{
2179c30b89acSMasatake YAMATO 			struct regexTable *table = ptrArrayItem (lcb->tables, table_index);
2180c30b89acSMasatake YAMATO 			error (WARNING, "table: %s[%u]", table->name, ptrArrayCount (table->entries));
2181c30b89acSMasatake YAMATO 			error (WARNING, "language: %s", getLanguageName (lcb->owner));
2182c30b89acSMasatake YAMATO 		}
2183c30b89acSMasatake YAMATO 		else
2184c30b89acSMasatake YAMATO 			error (WARNING, "language: %s[%u]", getLanguageName (lcb->owner),
2185c30b89acSMasatake YAMATO 				   ptrArrayCount (lcb->entries[regptype]));
2186f4e9820bSMasatake YAMATO 		return NULL;
2187c30b89acSMasatake YAMATO 	}
218841e0b4f8SMasatake YAMATO 
21890f8ba855SMasatake YAMATO 	char kindLetter;
2190d4c6f1e6SMasatake YAMATO 	char* kindName;
2191d4c6f1e6SMasatake YAMATO 	char* description;
21920f8ba855SMasatake YAMATO 	kindDefinition* fileKind;
21931fc8725aSMasatake YAMATO 
21943950d588SMasatake YAMATO 	bool explictly_defined =  parseKinds (kinds, &kindLetter, &kindName, &description);
21950f8ba855SMasatake YAMATO 	fileKind = getLanguageKind (lcb->owner, KIND_FILE_INDEX);
21960f8ba855SMasatake YAMATO 	if (kindLetter == fileKind->letter)
21971fc8725aSMasatake YAMATO 		error (FATAL,
21981fc8725aSMasatake YAMATO 			   "Kind letter \'%c\' used in regex definition \"%s\" of %s language is reserved in ctags main",
21990f8ba855SMasatake YAMATO 			   kindLetter,
22000f8ba855SMasatake YAMATO 			   regex,
22010f8ba855SMasatake YAMATO 			   getLanguageName (lcb->owner));
2202b0747823SMasatake YAMATO 	else if (!isalpha ((unsigned char)kindLetter))
2203b0747823SMasatake YAMATO 		error (FATAL,
2204b0747823SMasatake YAMATO 			   "Kind letter must be an alphabetical character: \"%c\"",
2205b0747823SMasatake YAMATO 			   kindLetter);
2206b0747823SMasatake YAMATO 
2207b0747823SMasatake YAMATO 	if (strcmp (kindName, fileKind->name) == 0)
22080f8ba855SMasatake YAMATO 		error (FATAL,
22090f8ba855SMasatake YAMATO 			   "Kind name \"%s\" used in regex definition \"%s\" of %s language is reserved in ctags main",
22100f8ba855SMasatake YAMATO 			   kindName,
22111fc8725aSMasatake YAMATO 			   regex,
2212056b32e1SMasatake YAMATO 			   getLanguageName (lcb->owner));
2213b0747823SMasatake YAMATO 
2214b0747823SMasatake YAMATO 	const char *option_bsae = (regptype == REG_PARSER_SINGLE_LINE? "regex"        :
2215b0747823SMasatake YAMATO 							   regptype == REG_PARSER_MULTI_LINE ? "mline-regex"  :
2216b0747823SMasatake YAMATO 							   regptype == REG_PARSER_MULTI_TABLE? "_mtable-regex":
2217b0747823SMasatake YAMATO 							   NULL);
2218b0747823SMasatake YAMATO 	Assert (option_bsae);
2219b0747823SMasatake YAMATO 
2220b0747823SMasatake YAMATO 	for (const char * p = kindName; *p; p++)
2221b0747823SMasatake YAMATO 	{
2222b0747823SMasatake YAMATO 		if (p == kindName)
2223b0747823SMasatake YAMATO 		{
2224b0747823SMasatake YAMATO 			if (!isalpha(*p))
2225e0b5213bSMasatake YAMATO 				error (FATAL,
2226b0747823SMasatake YAMATO 					   "A kind name doesn't start with an alphabetical character: "
2227b0747823SMasatake YAMATO 					   "'%s' in \"--%s-%s\" option",
2228b0747823SMasatake YAMATO 					   kindName,
2229b0747823SMasatake YAMATO 					   option_bsae,
2230b0747823SMasatake YAMATO 					   getLanguageName (lcb->owner));
2231b0747823SMasatake YAMATO 		}
2232b0747823SMasatake YAMATO 		else
2233b0747823SMasatake YAMATO 		{
2234b0747823SMasatake YAMATO 			/*
2235b0747823SMasatake YAMATO 			 * People may object to this error.
2236b0747823SMasatake YAMATO 			 * Searching github repositories, I found not a few .ctags files
2237b0747823SMasatake YAMATO 			 * in which Exuberant-ctags users define kind names with whitespaces.
2238b0747823SMasatake YAMATO 			 * "FATAL" error breaks the compatibility.
2239b0747823SMasatake YAMATO 			 */
2240b0747823SMasatake YAMATO 			if (!isalnum(*p))
2241b0747823SMasatake YAMATO 				error (/* regptype == REG_PARSER_SINGLE_LINE? WARNING: */ FATAL,
2242b0747823SMasatake YAMATO 					   "Non-alphanumeric char is used in kind name: "
2243b0747823SMasatake YAMATO 					   "'%s' in \"--%s-%s\" option",
2244b0747823SMasatake YAMATO 					   kindName,
2245b0747823SMasatake YAMATO 					   option_bsae,
2246b0747823SMasatake YAMATO 					   getLanguageName (lcb->owner));
2247b0747823SMasatake YAMATO 
2248b0747823SMasatake YAMATO 		}
2249b0747823SMasatake YAMATO 	}
22501fc8725aSMasatake YAMATO 
2251f4e9820bSMasatake YAMATO 	regexPattern *rptr = addCompiledTagPattern (lcb, table_index,
2252c30b89acSMasatake YAMATO 												regptype, &cp, name,
22530f8ba855SMasatake YAMATO 												kindLetter, kindName, description, flags,
22543950d588SMasatake YAMATO 												explictly_defined,
22552a738f47SMasatake YAMATO 												disabled);
22565372d785SMasatake YAMATO 	rptr->pattern_string = escapeRegexPattern(regex);
2257691d5f94SMasatake YAMATO 
2258a4e7ab31SMasatake YAMATO 	eFree (kindName);
2259a4e7ab31SMasatake YAMATO 	if (description)
2260a4e7ab31SMasatake YAMATO 		eFree (description);
2261a87d30edSMasatake YAMATO 
2262a87d30edSMasatake YAMATO 	if (*name == '\0')
2263a87d30edSMasatake YAMATO 	{
22640cbf3f0dSMasatake YAMATO 		if (rptr->exclusive || rptr->scopeActions & SCOPE_PLACEHOLDER
22650d56cc8eSMasatake YAMATO 			|| rptr->anonymous_tag_prefix
22666cdf5716SMasatake YAMATO 			|| regptype == REG_PARSER_MULTI_TABLE
22676cdf5716SMasatake YAMATO 			|| rptr->guest.lang.type != GUEST_LANG_UNKNOWN
2268e8386a4eSMasatake YAMATO 			|| rptr->optscript
22696cdf5716SMasatake YAMATO 			)
2270ce990805SThomas Braun 			rptr->accept_empty_name = true;
2271a87d30edSMasatake YAMATO 		else
2272a87d30edSMasatake YAMATO 			error (WARNING, "%s: regexp missing name pattern", regex);
2273a87d30edSMasatake YAMATO 	}
2274a87d30edSMasatake YAMATO 
227512ddaaa3SMasatake YAMATO 	return rptr;
227612ddaaa3SMasatake YAMATO }
227712ddaaa3SMasatake YAMATO 
addTagRegex(struct lregexControlBlock * lcb,const char * const regex,const char * const name,const char * const kinds,const char * const flags,bool * disabled)2278056b32e1SMasatake YAMATO extern void addTagRegex (struct lregexControlBlock *lcb,
227911af5b2cSMasatake YAMATO 			 const char* const regex,
228011af5b2cSMasatake YAMATO 			 const char* const name,
228111af5b2cSMasatake YAMATO 			 const char* const kinds,
228211af5b2cSMasatake YAMATO 			 const char* const flags,
2283ce990805SThomas Braun 			 bool *disabled)
228412ddaaa3SMasatake YAMATO {
22850cbf3f0dSMasatake YAMATO 	addTagRegexInternal (lcb, TABLE_INDEX_UNUSED,
22860cbf3f0dSMasatake YAMATO 						 REG_PARSER_SINGLE_LINE, regex, name, kinds, flags, disabled);
2287641e337aSMasatake YAMATO }
2288641e337aSMasatake YAMATO 
addTagMultiLineRegex(struct lregexControlBlock * lcb,const char * const regex,const char * const name,const char * const kinds,const char * const flags,bool * disabled)2289641e337aSMasatake YAMATO extern void addTagMultiLineRegex (struct lregexControlBlock *lcb, const char* const regex,
2290641e337aSMasatake YAMATO 								  const char* const name, const char* const kinds, const char* const flags,
2291641e337aSMasatake YAMATO 								  bool *disabled)
2292641e337aSMasatake YAMATO {
22930cbf3f0dSMasatake YAMATO 	addTagRegexInternal (lcb, TABLE_INDEX_UNUSED,
22940cbf3f0dSMasatake YAMATO 						 REG_PARSER_MULTI_LINE, regex, name, kinds, flags, disabled);
2295d4c6f1e6SMasatake YAMATO }
2296d4c6f1e6SMasatake YAMATO 
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)229789c588f7SMasatake YAMATO extern void addTagMultiTableRegex(struct lregexControlBlock *lcb,
229889c588f7SMasatake YAMATO 								  const char* const table_name,
229989c588f7SMasatake YAMATO 								  const char* const regex,
230089c588f7SMasatake YAMATO 								  const char* const name, const char* const kinds, const char* const flags,
230189c588f7SMasatake YAMATO 								  bool *disabled)
230289c588f7SMasatake YAMATO {
230389c588f7SMasatake YAMATO 	int table_index = getTableIndexForName (lcb, table_name);
230489c588f7SMasatake YAMATO 
230589c588f7SMasatake YAMATO 	if (table_index < 0)
230689c588f7SMasatake YAMATO 		error (FATAL, "unknown table name: %s", table_name);
230789c588f7SMasatake YAMATO 
230889c588f7SMasatake YAMATO 	addTagRegexInternal (lcb, table_index, REG_PARSER_MULTI_TABLE, regex, name, kinds, flags,
230989c588f7SMasatake YAMATO 						 disabled);
231089c588f7SMasatake YAMATO }
231189c588f7SMasatake YAMATO 
addCallbackRegex(struct lregexControlBlock * lcb,const char * const regex,const char * const flags,const regexCallback callback,bool * disabled,void * userData)231253dda59eSMasatake YAMATO extern void addCallbackRegex (struct lregexControlBlock *lcb,
231353dda59eSMasatake YAMATO 			      const char* const regex,
231453dda59eSMasatake YAMATO 			      const char* const flags,
231553dda59eSMasatake YAMATO 			      const regexCallback callback,
2316ce990805SThomas Braun 			      bool *disabled,
23176ff4dab6SMasatake YAMATO 			      void * userData)
2318d4c6f1e6SMasatake YAMATO {
2319d4c6f1e6SMasatake YAMATO 	Assert (regex != NULL);
2320d00f728aSMasatake YAMATO 
2321d00f728aSMasatake YAMATO 	if (!regexAvailable)
2322d00f728aSMasatake YAMATO 		return;
2323d00f728aSMasatake YAMATO 
2324d00f728aSMasatake YAMATO 
2325c30b89acSMasatake YAMATO 	regexCompiledCode cp = compileRegex (REG_PARSER_SINGLE_LINE, regex, flags);
2326c30b89acSMasatake YAMATO 	if (cp.code == NULL)
23275372d785SMasatake YAMATO 	{
2328c30b89acSMasatake YAMATO 		error (WARNING, "pattern: %s", regex);
2329c30b89acSMasatake YAMATO 		error (WARNING, "language: %s", getLanguageName (lcb->owner));
2330c30b89acSMasatake YAMATO 		return;
2331c30b89acSMasatake YAMATO 	}
2332c30b89acSMasatake YAMATO 
2333c30b89acSMasatake YAMATO 	regexPattern *rptr = addCompiledCallbackPattern (lcb, &cp, callback, flags,
23342a738f47SMasatake YAMATO 													 disabled, userData);
23355372d785SMasatake YAMATO 	rptr->pattern_string = escapeRegexPattern(regex);
23365372d785SMasatake YAMATO }
2337d4c6f1e6SMasatake YAMATO 
addTagRegexOption(struct lregexControlBlock * lcb,enum regexParserType regptype,const char * const pattern)2338056b32e1SMasatake YAMATO static void addTagRegexOption (struct lregexControlBlock *lcb,
23391b9c3aecSMasatake YAMATO 							   enum regexParserType regptype,
2340056b32e1SMasatake YAMATO 							   const char* const pattern)
2341d4c6f1e6SMasatake YAMATO {
2342d00f728aSMasatake YAMATO 	if (!regexAvailable)
2343d00f728aSMasatake YAMATO 		return;
2344d00f728aSMasatake YAMATO 
23450cbf3f0dSMasatake YAMATO 	int table_index = TABLE_INDEX_UNUSED;
23460cbf3f0dSMasatake YAMATO 	char * regex_pat = NULL;
2347d4c6f1e6SMasatake YAMATO 	char *name, *kinds, *flags;
23480cbf3f0dSMasatake YAMATO 
23490cbf3f0dSMasatake YAMATO 
23500cbf3f0dSMasatake YAMATO 	if (regptype == REG_PARSER_MULTI_TABLE)
23510cbf3f0dSMasatake YAMATO 	{
23520cbf3f0dSMasatake YAMATO 		const char *c;
23530cbf3f0dSMasatake YAMATO 		for (c = pattern; *c; c++)
23540cbf3f0dSMasatake YAMATO 		{
23550cbf3f0dSMasatake YAMATO 			if (! (isalnum(*c) || *c == '_'))
23560cbf3f0dSMasatake YAMATO 			{
235741e0b4f8SMasatake YAMATO 				if (*c &&  (*(c + 1) != '^'))
235841e0b4f8SMasatake YAMATO 				{
235941e0b4f8SMasatake YAMATO 					vString *tmp = vStringNew ();
236041e0b4f8SMasatake YAMATO 
236141e0b4f8SMasatake YAMATO 					/* Put '^' as prefix for the pattern */
236241e0b4f8SMasatake YAMATO 					vStringPut(tmp, *c);
236341e0b4f8SMasatake YAMATO 					vStringPut(tmp, '^');
236441e0b4f8SMasatake YAMATO 					vStringCatS(tmp, c + 1);
236541e0b4f8SMasatake YAMATO 					regex_pat = vStringDeleteUnwrap(tmp);
236641e0b4f8SMasatake YAMATO 				}
236741e0b4f8SMasatake YAMATO 				else
23680cbf3f0dSMasatake YAMATO 					regex_pat = eStrdup (c);
23690cbf3f0dSMasatake YAMATO 				break;
23700cbf3f0dSMasatake YAMATO 			}
23710cbf3f0dSMasatake YAMATO 		}
237241e0b4f8SMasatake YAMATO 
23730cbf3f0dSMasatake YAMATO 		if (regex_pat == NULL || *regex_pat == '\0')
23740cbf3f0dSMasatake YAMATO 			error (FATAL, "wrong mtable pattern specification: %s", pattern);
23750cbf3f0dSMasatake YAMATO 
23760cbf3f0dSMasatake YAMATO 		char *table_name = eStrndup(pattern, c - pattern);
23770cbf3f0dSMasatake YAMATO 		table_index = getTableIndexForName (lcb, table_name);
23780cbf3f0dSMasatake YAMATO 		if (table_index < 0)
23790cbf3f0dSMasatake YAMATO 			error (FATAL, "unknown table name: %s (in %s)", table_name, pattern);
23800cbf3f0dSMasatake YAMATO 		eFree(table_name);
23810cbf3f0dSMasatake YAMATO 	}
23820cbf3f0dSMasatake YAMATO 	else
23830cbf3f0dSMasatake YAMATO 		regex_pat = eStrdup (pattern);
23840cbf3f0dSMasatake YAMATO 
23851b9c3aecSMasatake YAMATO 	if (parseTagRegex (regptype, regex_pat, &name, &kinds, &flags))
23860cbf3f0dSMasatake YAMATO 		addTagRegexInternal (lcb, table_index, regptype, regex_pat, name, kinds, flags,
23872a738f47SMasatake YAMATO 							 NULL);
23880cbf3f0dSMasatake YAMATO 
2389d4c6f1e6SMasatake YAMATO 	eFree (regex_pat);
2390d4c6f1e6SMasatake YAMATO }
2391d4c6f1e6SMasatake YAMATO 
processTagRegexOption(struct lregexControlBlock * lcb,enum regexParserType regptype,const char * const parameter)2392056b32e1SMasatake YAMATO extern void processTagRegexOption (struct lregexControlBlock *lcb,
23931b9c3aecSMasatake YAMATO 								   enum regexParserType regptype,
2394056b32e1SMasatake YAMATO 								   const char* const parameter)
2395056b32e1SMasatake YAMATO {
2396056b32e1SMasatake YAMATO 	if (parameter == NULL  ||  parameter [0] == '\0')
2397056b32e1SMasatake YAMATO 		clearPatternSet (lcb);
2398056b32e1SMasatake YAMATO 	else if (parameter [0] != '@')
23991b9c3aecSMasatake YAMATO 		addTagRegexOption (lcb, regptype, parameter);
2400056b32e1SMasatake YAMATO 	else if (! doesFileExist (parameter + 1))
2401056b32e1SMasatake YAMATO 		error (WARNING, "cannot open regex file");
2402056b32e1SMasatake YAMATO 	else
2403056b32e1SMasatake YAMATO 	{
2404056b32e1SMasatake YAMATO 		const char* regexfile = parameter + 1;
24052b808106SMasatake YAMATO 
24062b808106SMasatake YAMATO 		verbose ("open a regex file: %s\n", regexfile);
2407056b32e1SMasatake YAMATO 		MIO* const mio = mio_new_file (regexfile, "r");
2408056b32e1SMasatake YAMATO 		if (mio == NULL)
2409056b32e1SMasatake YAMATO 			error (WARNING | PERROR, "%s", regexfile);
2410056b32e1SMasatake YAMATO 		else
2411056b32e1SMasatake YAMATO 		{
2412056b32e1SMasatake YAMATO 			vString* const regex = vStringNew ();
2413056b32e1SMasatake YAMATO 			while (readLineRaw (regex, mio))
24146b2b1915SMasatake YAMATO 			{
24156b2b1915SMasatake YAMATO 				if (vStringLength (regex) > 1 && vStringValue (regex)[0] != '\n')
24161b9c3aecSMasatake YAMATO 					addTagRegexOption (lcb, regptype, vStringValue (regex));
24176b2b1915SMasatake YAMATO 			}
2418b978efd6SMasatake YAMATO 			mio_unref (mio);
2419056b32e1SMasatake YAMATO 			vStringDelete (regex);
2420056b32e1SMasatake YAMATO 		}
2421056b32e1SMasatake YAMATO 	}
2422056b32e1SMasatake YAMATO }
2423056b32e1SMasatake YAMATO 
2424d4c6f1e6SMasatake YAMATO /*
2425d4c6f1e6SMasatake YAMATO *   Regex option parsing
2426d4c6f1e6SMasatake YAMATO */
2427d4c6f1e6SMasatake YAMATO 
printRegexFlags(bool withListHeader,bool machinable,const char * flags,FILE * fp)2428c30b89acSMasatake YAMATO extern void printRegexFlags (bool withListHeader, bool machinable, const char *flags, FILE *fp)
24293fac0fc6SMasatake YAMATO {
2430c30b89acSMasatake YAMATO 	struct colprintTable * table = flagsColprintTableNew ();
2431d4a3a6e8SMasatake YAMATO 
2432c30b89acSMasatake YAMATO 	if (flags && *flags != '\0')
2433c30b89acSMasatake YAMATO 	{
24346a8d5b70SMasatake YAMATO 		/* Print backend specific flags.
24356a8d5b70SMasatake YAMATO 		 * This code is just stub because there is no backend having a specific flag.
24366a8d5b70SMasatake YAMATO 		 * The help message for this option is not updated. */
24376a8d5b70SMasatake YAMATO 		struct flagDefsDescriptor desc = choose_backend (flags, REG_PARSER_SINGLE_LINE, true);
2438c30b89acSMasatake YAMATO 		flagsColprintAddDefinitions (table, desc.backend->fdefs, desc.backend->fdef_count);
2439c30b89acSMasatake YAMATO 	}
2440c30b89acSMasatake YAMATO 	else
2441c30b89acSMasatake YAMATO 	{
2442c30b89acSMasatake YAMATO 		flagsColprintAddDefinitions (table, backendFlagDefs, ARRAY_SIZE(backendFlagDefs));
2443c30b89acSMasatake YAMATO 		flagsColprintAddDefinitions (table, backendCommonRegexFlagDefs, ARRAY_SIZE(backendCommonRegexFlagDefs));
2444d4a3a6e8SMasatake YAMATO 		flagsColprintAddDefinitions (table, prePtrnFlagDef, ARRAY_SIZE (prePtrnFlagDef));
24456cdf5716SMasatake YAMATO 		flagsColprintAddDefinitions (table, guestPtrnFlagDef, ARRAY_SIZE (guestPtrnFlagDef));
2446d4a3a6e8SMasatake YAMATO 		flagsColprintAddDefinitions (table, scopePtrnFlagDef, ARRAY_SIZE (scopePtrnFlagDef));
2447f74a98d6SHadriel Kaplan 		flagsColprintAddDefinitions (table, commonSpecFlagDef, ARRAY_SIZE (commonSpecFlagDef));
2448c30b89acSMasatake YAMATO 	}
24499653ebd3SMasatake YAMATO 
24509653ebd3SMasatake YAMATO 	flagsColprintTablePrint (table, withListHeader, machinable, fp);
24519653ebd3SMasatake YAMATO 	colprintTableDelete(table);
24529653ebd3SMasatake YAMATO }
24539653ebd3SMasatake YAMATO 
printMultilineRegexFlags(bool withListHeader,bool machinable,const char * flags,FILE * fp)2454c30b89acSMasatake YAMATO extern void printMultilineRegexFlags (bool withListHeader, bool machinable, const char *flags, FILE *fp)
24559653ebd3SMasatake YAMATO {
2456c30b89acSMasatake YAMATO 	struct colprintTable * table = flagsColprintTableNew ();
24579653ebd3SMasatake YAMATO 
2458c30b89acSMasatake YAMATO 	if (flags && *flags != '\0')
2459c30b89acSMasatake YAMATO 	{
24606a8d5b70SMasatake YAMATO 		/* Print backend specific flags.
24616a8d5b70SMasatake YAMATO 		 * This code is just stub because there is no backend having a specific flag.
24626a8d5b70SMasatake YAMATO 		 * The help message for this option is not updated. */
24636a8d5b70SMasatake YAMATO 		struct flagDefsDescriptor desc = choose_backend (flags, REG_PARSER_MULTI_LINE, true);
2464c30b89acSMasatake YAMATO 		flagsColprintAddDefinitions (table, desc.backend->fdefs, desc.backend->fdef_count);
2465c30b89acSMasatake YAMATO 	}
2466c30b89acSMasatake YAMATO 	else
2467c30b89acSMasatake YAMATO 	{
2468c30b89acSMasatake YAMATO 		flagsColprintAddDefinitions (table, backendFlagDefs, ARRAY_SIZE(backendFlagDefs));
2469c30b89acSMasatake YAMATO 		flagsColprintAddDefinitions (table, backendCommonRegexFlagDefs, ARRAY_SIZE(backendCommonRegexFlagDefs));
2470d4a3a6e8SMasatake YAMATO 		flagsColprintAddDefinitions (table, multilinePtrnFlagDef, ARRAY_SIZE (multilinePtrnFlagDef));
24716cdf5716SMasatake YAMATO 		flagsColprintAddDefinitions (table, guestPtrnFlagDef, ARRAY_SIZE (guestPtrnFlagDef));
2472f74a98d6SHadriel Kaplan 		flagsColprintAddDefinitions (table, commonSpecFlagDef, ARRAY_SIZE (commonSpecFlagDef));
2473c30b89acSMasatake YAMATO 	}
2474d4a3a6e8SMasatake YAMATO 
2475d4a3a6e8SMasatake YAMATO 	flagsColprintTablePrint (table, withListHeader, machinable, fp);
2476d4a3a6e8SMasatake YAMATO 	colprintTableDelete(table);
24773fac0fc6SMasatake YAMATO }
24783fac0fc6SMasatake YAMATO 
printMultitableRegexFlags(bool withListHeader,bool machinable,const char * flags,FILE * fp)2479c30b89acSMasatake YAMATO extern void printMultitableRegexFlags (bool withListHeader, bool machinable, const char *flags, FILE *fp)
2480e5f37e21SMasatake YAMATO {
2481c30b89acSMasatake YAMATO 	struct colprintTable * table = flagsColprintTableNew ();
2482e5f37e21SMasatake YAMATO 
2483c30b89acSMasatake YAMATO 	if (flags && *flags != '\0')
2484c30b89acSMasatake YAMATO 	{
24856a8d5b70SMasatake YAMATO 		/* Print backend specific flags.
24866a8d5b70SMasatake YAMATO 		 * This code is just stub because there is no backend having a specific flag.
24876a8d5b70SMasatake YAMATO 		 * The help message for this option is not updated. */
24886a8d5b70SMasatake YAMATO 		struct flagDefsDescriptor desc = choose_backend (flags, REG_PARSER_MULTI_TABLE, true);
2489c30b89acSMasatake YAMATO 		flagsColprintAddDefinitions (table, desc.backend->fdefs, desc.backend->fdef_count);
2490c30b89acSMasatake YAMATO 	}
2491c30b89acSMasatake YAMATO 	else
2492c30b89acSMasatake YAMATO 	{
2493c30b89acSMasatake YAMATO 		flagsColprintAddDefinitions (table, backendFlagDefs, ARRAY_SIZE(backendFlagDefs));
2494c30b89acSMasatake YAMATO 		flagsColprintAddDefinitions (table, backendCommonRegexFlagDefs, ARRAY_SIZE(backendCommonRegexFlagDefs));
2495e5f37e21SMasatake YAMATO 		flagsColprintAddDefinitions (table, multilinePtrnFlagDef, ARRAY_SIZE (multilinePtrnFlagDef));
2496e5f37e21SMasatake YAMATO 		flagsColprintAddDefinitions (table, multitablePtrnFlagDef, ARRAY_SIZE (multitablePtrnFlagDef));
24976cdf5716SMasatake YAMATO 		flagsColprintAddDefinitions (table, guestPtrnFlagDef, ARRAY_SIZE (guestPtrnFlagDef));
2498e5f37e21SMasatake YAMATO 		flagsColprintAddDefinitions (table, scopePtrnFlagDef, ARRAY_SIZE (scopePtrnFlagDef));
2499f74a98d6SHadriel Kaplan 		flagsColprintAddDefinitions (table, commonSpecFlagDef, ARRAY_SIZE (commonSpecFlagDef));
2500c30b89acSMasatake YAMATO 	}
2501e5f37e21SMasatake YAMATO 
2502e5f37e21SMasatake YAMATO 	flagsColprintTablePrint (table, withListHeader, machinable, fp);
2503e5f37e21SMasatake YAMATO 	colprintTableDelete(table);
2504e5f37e21SMasatake YAMATO }
2505e5f37e21SMasatake YAMATO 
freeRegexResources(void)2506d4c6f1e6SMasatake YAMATO extern void freeRegexResources (void)
2507d4c6f1e6SMasatake YAMATO {
2508e8386a4eSMasatake YAMATO 	es_object_unref (lregex_dict);
2509e8386a4eSMasatake YAMATO 	opt_vm_delete (optvm);
2510d4c6f1e6SMasatake YAMATO }
2511d4c6f1e6SMasatake YAMATO 
regexNeedsMultilineBuffer(struct lregexControlBlock * lcb)251216a203f6SMasatake YAMATO extern bool regexNeedsMultilineBuffer (struct lregexControlBlock *lcb)
251313939209SMasatake YAMATO {
2514134629a0SHadriel Kaplan 	if  (ptrArrayCount(lcb->entries [REG_PARSER_MULTI_LINE]) > 0)
251541e0b4f8SMasatake YAMATO 		return true;
251641e0b4f8SMasatake YAMATO 	else if (ptrArrayCount(lcb->tables) > 0)
251741e0b4f8SMasatake YAMATO 		return true;
251841e0b4f8SMasatake YAMATO 	else
251941e0b4f8SMasatake YAMATO 		return false;
252013939209SMasatake YAMATO }
252113939209SMasatake YAMATO 
matchMultilineRegex(struct lregexControlBlock * lcb,const vString * const allLines)252253dda59eSMasatake YAMATO extern bool matchMultilineRegex (struct lregexControlBlock *lcb, const vString* const allLines)
252313939209SMasatake YAMATO {
252413939209SMasatake YAMATO 	bool result = false;
252513939209SMasatake YAMATO 
252653dda59eSMasatake YAMATO 	unsigned int i;
252753dda59eSMasatake YAMATO 
2528134629a0SHadriel Kaplan 	for (i = 0; i < ptrArrayCount(lcb->entries [REG_PARSER_MULTI_LINE]); ++i)
252953dda59eSMasatake YAMATO 	{
2530134629a0SHadriel Kaplan 		regexTableEntry *entry = ptrArrayItem(lcb->entries [REG_PARSER_MULTI_LINE], i);
2531134629a0SHadriel Kaplan 		Assert (entry && entry->pattern);
253210db13faSMasatake YAMATO 
2533134629a0SHadriel Kaplan 		if ((entry->pattern->xtagType != XTAG_UNKNOWN)
2534134629a0SHadriel Kaplan 			&& (!isXtagEnabled (entry->pattern->xtagType)))
253510db13faSMasatake YAMATO 			continue;
253610db13faSMasatake YAMATO 
2537134629a0SHadriel Kaplan 		result = matchMultilineRegexPattern (lcb, allLines, entry) || result;
253813939209SMasatake YAMATO 	}
2539ce71b90aSMasatake YAMATO 	return result;
254013939209SMasatake YAMATO }
254113939209SMasatake YAMATO 
getTableIndexForName(const struct lregexControlBlock * const lcb,const char * name)254246837a67SHadriel Kaplan static int getTableIndexForName (const struct lregexControlBlock *const lcb, const char *name)
2543e0e33135SMasatake YAMATO {
2544e0e33135SMasatake YAMATO 	unsigned int i;
2545e0e33135SMasatake YAMATO 
2546e0e33135SMasatake YAMATO 	for (i = 0; i < ptrArrayCount(lcb->tables); i++)
2547e0e33135SMasatake YAMATO 	{
2548e0e33135SMasatake YAMATO 		struct regexTable *table = ptrArrayItem(lcb->tables, i);
2549e0e33135SMasatake YAMATO 		if (strcmp (table->name, name) == 0)
2550e0e33135SMasatake YAMATO 			return (int)i;
2551e0e33135SMasatake YAMATO 	}
2552e0e33135SMasatake YAMATO 
25530cbf3f0dSMasatake YAMATO 	return TABLE_INDEX_UNUSED;
2554e0e33135SMasatake YAMATO }
2555e0e33135SMasatake YAMATO 
addRegexTable(struct lregexControlBlock * lcb,const char * name)2556e0e33135SMasatake YAMATO extern void addRegexTable (struct lregexControlBlock *lcb, const char *name)
2557e0e33135SMasatake YAMATO {
2558e0e33135SMasatake YAMATO 	const char *c;
2559e0e33135SMasatake YAMATO 	for (c = name; *c; c++)
2560e0e33135SMasatake YAMATO 		if (! (isalnum(*c) || *c == '_'))
2561e0e33135SMasatake YAMATO 			error (FATAL, "`%c' in \"%s\" is not acceptable as part of table name", *c, name);
2562e0e33135SMasatake YAMATO 
2563e0e33135SMasatake YAMATO 	if (getTableIndexForName(lcb, name) >= 0)
2564e0e33135SMasatake YAMATO 	{
2565e0e33135SMasatake YAMATO 		error (WARNING, "regex table \"%s\" is already defined", name);
2566e0e33135SMasatake YAMATO 		return;
2567e0e33135SMasatake YAMATO 	}
2568e0e33135SMasatake YAMATO 
2569e0e33135SMasatake YAMATO 	struct regexTable *table = xCalloc(1, struct regexTable);
2570e0e33135SMasatake YAMATO 	table->name = eStrdup (name);
2571134629a0SHadriel Kaplan 	table->entries = ptrArrayNew(deleteTableEntry);
2572e0e33135SMasatake YAMATO 
2573e0e33135SMasatake YAMATO 	ptrArrayAdd (lcb->tables, table);
2574e0e33135SMasatake YAMATO }
257513939209SMasatake YAMATO 
dumpSstack(FILE * fp,int scope)25763afb5475SMasatake YAMATO static void dumpSstack(FILE* fp, int scope)
2577adafc5f9SMasatake YAMATO {
25783671ad72SMasatake YAMATO 	tagEntryInfo *entry;
2579adafc5f9SMasatake YAMATO 	fprintf (fp, "scope : ");
25803671ad72SMasatake YAMATO 	while ((entry = getEntryInCorkQueue (scope)))
2581adafc5f9SMasatake YAMATO 	{
2582adafc5f9SMasatake YAMATO 		fprintf(fp, "%s", entry->name);
2583adafc5f9SMasatake YAMATO 
2584adafc5f9SMasatake YAMATO 		scope = entry->extensionFields.scopeIndex;
2585adafc5f9SMasatake YAMATO 		if (scope != CORK_NIL)
2586adafc5f9SMasatake YAMATO 			fprintf(fp, "%c", '/');
2587adafc5f9SMasatake YAMATO 	}
2588adafc5f9SMasatake YAMATO 	fprintf (fp, "\n");
2589adafc5f9SMasatake YAMATO }
2590adafc5f9SMasatake YAMATO 
dumpTstack(FILE * fp,ptrArray * tstack)2591adafc5f9SMasatake YAMATO static void dumpTstack(FILE* fp, ptrArray *tstack)
2592adafc5f9SMasatake YAMATO {
2593adafc5f9SMasatake YAMATO 	for (unsigned int i = ptrArrayCount(tstack); i > 0; i--)
2594adafc5f9SMasatake YAMATO 	{
2595adafc5f9SMasatake YAMATO 		char tmp[2];
2596adafc5f9SMasatake YAMATO 		struct regexTable *t = ptrArrayItem(tstack, i - 1);
2597adafc5f9SMasatake YAMATO 		if (i == 1)
2598adafc5f9SMasatake YAMATO 			tmp[0] = '\0';
2599adafc5f9SMasatake YAMATO 		else
2600adafc5f9SMasatake YAMATO 		{
2601adafc5f9SMasatake YAMATO 			tmp[0] = '/';
2602adafc5f9SMasatake YAMATO 			tmp[1] = '\0';
2603adafc5f9SMasatake YAMATO 		}
2604adafc5f9SMasatake YAMATO 		fprintf(fp, "%s%s", t->name, tmp);
2605adafc5f9SMasatake YAMATO 	}
2606adafc5f9SMasatake YAMATO 	fprintf(fp, "\n");
2607adafc5f9SMasatake YAMATO }
2608adafc5f9SMasatake YAMATO 
printInputLine(FILE * vfp,const char * c,const off_t offset)2609e8dbee90SHadriel Kaplan static void printInputLine(FILE* vfp, const char *c, const off_t offset)
2610e8dbee90SHadriel Kaplan {
2611e8dbee90SHadriel Kaplan 	vString *v = vStringNew ();
2612e8dbee90SHadriel Kaplan 
2613e8dbee90SHadriel Kaplan 	for (; *c && (*c != '\n'); c++)
2614e8dbee90SHadriel Kaplan 		vStringPut(v, *c);
2615e8dbee90SHadriel Kaplan 
2616e8dbee90SHadriel Kaplan 	if (vStringLength (v) == 0 && *c == '\n')
2617e8dbee90SHadriel Kaplan 		vStringCatS (v, "\\n");
2618e8dbee90SHadriel Kaplan 
2619e8dbee90SHadriel Kaplan 	fprintf (vfp, "\ninput : \"%s\" L%lu\n",
2620e8dbee90SHadriel Kaplan 			 vStringValue (v),
2621e8dbee90SHadriel Kaplan 			 getInputLineNumberForFileOffset(offset));
2622e8dbee90SHadriel Kaplan 	vStringDelete(v);
2623e8dbee90SHadriel Kaplan }
2624e8dbee90SHadriel Kaplan 
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)26259a1e266aSHadriel Kaplan static void printMultitableMessage(const langType language,
26269a1e266aSHadriel Kaplan 								   const char *const tableName,
26279a1e266aSHadriel Kaplan 								   const unsigned int index,
26289a1e266aSHadriel Kaplan 								   const regexPattern *const ptrn,
26299a1e266aSHadriel Kaplan 								   const off_t offset,
26309a1e266aSHadriel Kaplan 								   const char *const current,
26319a1e266aSHadriel Kaplan 								   const regmatch_t* const pmatch)
26329a1e266aSHadriel Kaplan {
26339a1e266aSHadriel Kaplan 	vString *msg;
26349a1e266aSHadriel Kaplan 
26359a1e266aSHadriel Kaplan 	Assert (ptrn);
26369a1e266aSHadriel Kaplan 	Assert (ptrn->message.selection > 0);
26379a1e266aSHadriel Kaplan 	Assert (ptrn->message.message_string);
26389a1e266aSHadriel Kaplan 
26399a1e266aSHadriel Kaplan 	msg = substitute (current, ptrn->message.message_string, BACK_REFERENCE_COUNT, pmatch);
26409a1e266aSHadriel Kaplan 
26419a1e266aSHadriel Kaplan 	error (ptrn->message.selection, "%sMessage from mtable<%s/%s[%2u]>: %s (%s:%lu)",
26429a1e266aSHadriel Kaplan 		   (ptrn->message.selection == FATAL ? "Fatal: " : ""),
26439a1e266aSHadriel Kaplan 		   getLanguageName (language),
26449a1e266aSHadriel Kaplan 		   tableName,
26459a1e266aSHadriel Kaplan 		   index,
26469a1e266aSHadriel Kaplan 		   vStringValue (msg),
26479a1e266aSHadriel Kaplan 		   getInputFileName (),
26489a1e266aSHadriel Kaplan 		   getInputLineNumberForFileOffset (offset));
26499a1e266aSHadriel Kaplan 
26509a1e266aSHadriel Kaplan 	vStringDelete (msg);
26519a1e266aSHadriel Kaplan }
26529a1e266aSHadriel Kaplan 
matchMultitableRegexTable(struct lregexControlBlock * lcb,struct regexTable * table,const vString * const start,unsigned int * offset)265341e0b4f8SMasatake YAMATO static struct regexTable * matchMultitableRegexTable (struct lregexControlBlock *lcb,
265441e0b4f8SMasatake YAMATO 													  struct regexTable *table, const vString *const start, unsigned int *offset)
265541e0b4f8SMasatake YAMATO {
265641e0b4f8SMasatake YAMATO 	struct regexTable *next = NULL;
265741e0b4f8SMasatake YAMATO 	const char *current;
265841e0b4f8SMasatake YAMATO 	regmatch_t pmatch [BACK_REFERENCE_COUNT];
265941e0b4f8SMasatake YAMATO 	const char *cstart = vStringValue(start);
26601f3437b7SMasatake YAMATO 	unsigned int delta;
266141e0b4f8SMasatake YAMATO 
266241e0b4f8SMasatake YAMATO 
266341e0b4f8SMasatake YAMATO  restart:
266441e0b4f8SMasatake YAMATO 	current = cstart + *offset;
266541e0b4f8SMasatake YAMATO 
26661f3437b7SMasatake YAMATO 	/* Accept the case *offset == vStringLength(start)
26671f3437b7SMasatake YAMATO 	   because we want an empty regex // still matches empty input. */
26681f3437b7SMasatake YAMATO 	if (*offset > vStringLength(start))
26691f3437b7SMasatake YAMATO 	{
26701f3437b7SMasatake YAMATO 		*offset = vStringLength(start);
267141e0b4f8SMasatake YAMATO 		goto out;
26721f3437b7SMasatake YAMATO 	}
267341e0b4f8SMasatake YAMATO 
2674e8dbee90SHadriel Kaplan 	BEGIN_VERBOSE(vfp);
2675e8dbee90SHadriel Kaplan 	{
2676e8dbee90SHadriel Kaplan 		printInputLine(vfp, current, *offset);
2677e8dbee90SHadriel Kaplan 	}
2678e8dbee90SHadriel Kaplan 	END_VERBOSE();
2679e8dbee90SHadriel Kaplan 
2680134629a0SHadriel Kaplan 	for (unsigned int i = 0; i < ptrArrayCount(table->entries); i++)
268141e0b4f8SMasatake YAMATO 	{
2682134629a0SHadriel Kaplan 		regexTableEntry *entry = ptrArrayItem(table->entries, i);
26836fa01766SBernd 		if ((entry->pattern->xtagType != XTAG_UNKNOWN)
26846fa01766SBernd 			&& (!isXtagEnabled (entry->pattern->xtagType)))
26856fa01766SBernd 			continue;
26866fa01766SBernd 
2687134629a0SHadriel Kaplan 		regexPattern *ptrn = entry->pattern;
26886cdf5716SMasatake YAMATO 		struct guestSpec  *guest = &ptrn->guest;
2689134629a0SHadriel Kaplan 
2690134629a0SHadriel Kaplan 		Assert (ptrn);
2691adafc5f9SMasatake YAMATO 
2692adafc5f9SMasatake YAMATO 		BEGIN_VERBOSE(vfp);
2693adafc5f9SMasatake YAMATO 		{
2694adafc5f9SMasatake YAMATO 			char s[3];
2695adafc5f9SMasatake YAMATO 			if (*current == '\n')
2696adafc5f9SMasatake YAMATO 			{
2697adafc5f9SMasatake YAMATO 				s [0] = '\\';
2698adafc5f9SMasatake YAMATO 				s [1] = 'n';
2699adafc5f9SMasatake YAMATO 				s [2] = '\0';
2700adafc5f9SMasatake YAMATO 			}
2701adafc5f9SMasatake YAMATO 			else if (*current == '\t')
2702adafc5f9SMasatake YAMATO 			{
2703adafc5f9SMasatake YAMATO 				s [0] = '\\';
2704adafc5f9SMasatake YAMATO 				s [1] = 't';
2705adafc5f9SMasatake YAMATO 				s [2] = '\0';
2706adafc5f9SMasatake YAMATO 			}
2707adafc5f9SMasatake YAMATO 			else if (*current == '\\')
2708adafc5f9SMasatake YAMATO 			{
2709adafc5f9SMasatake YAMATO 				s [0] = '\\';
2710adafc5f9SMasatake YAMATO 				s [1] = '\\';
2711adafc5f9SMasatake YAMATO 				s [2] = '\0';
2712adafc5f9SMasatake YAMATO 			}
2713adafc5f9SMasatake YAMATO 			else
2714adafc5f9SMasatake YAMATO 			{
2715adafc5f9SMasatake YAMATO 				s[0] = *current;
2716adafc5f9SMasatake YAMATO 				s[1] = '\0';
2717adafc5f9SMasatake YAMATO 			}
2718adafc5f9SMasatake YAMATO 
2719adafc5f9SMasatake YAMATO 			if (s[1] == '\0')
2720adafc5f9SMasatake YAMATO 				fprintf (vfp, "match : '%s' %15s[%2u] /", s, table->name, i);
2721adafc5f9SMasatake YAMATO 			else if (s[0] == '\0')
2722adafc5f9SMasatake YAMATO 				fprintf (vfp, "match :  '' %15s[%2u] /", table->name, i);
2723adafc5f9SMasatake YAMATO 			else
2724adafc5f9SMasatake YAMATO 				fprintf (vfp, "match :'%s' %15s[%2u] / ", s, table->name, i);
2725adafc5f9SMasatake YAMATO 			fprintf (vfp, "%s/\n", ptrn->pattern_string);
2726adafc5f9SMasatake YAMATO 		}
2727adafc5f9SMasatake YAMATO 		END_VERBOSE();
2728adafc5f9SMasatake YAMATO 
272941e0b4f8SMasatake YAMATO 		int match = 0;
273041e0b4f8SMasatake YAMATO 
273141e0b4f8SMasatake YAMATO 		if (ptrn->disabled && *(ptrn->disabled))
273241e0b4f8SMasatake YAMATO 			continue;
273341e0b4f8SMasatake YAMATO 
2734c30b89acSMasatake YAMATO 		match = ptrn->pattern.backend->match (ptrn->pattern.backend,
2735c30b89acSMasatake YAMATO 											  ptrn->pattern.code, current,
2736c30b89acSMasatake YAMATO 											  vStringLength(start) - (current - cstart),
2737c30b89acSMasatake YAMATO 											  pmatch);
273841e0b4f8SMasatake YAMATO 		if (match == 0)
273941e0b4f8SMasatake YAMATO 		{
2740134629a0SHadriel Kaplan 			entry->statistics.match++;
27412bbd136eSMasatake YAMATO 			off_t offset_for_tag = (current
27422bbd136eSMasatake YAMATO 									+ pmatch [ptrn->mgroup.forLineNumberDetermination].rm_so)
27432bbd136eSMasatake YAMATO 				- cstart;
27442bbd136eSMasatake YAMATO 			scriptWindow window = {
27452bbd136eSMasatake YAMATO 				.line = current,
2746ed3202bdSMasatake YAMATO 				.start = cstart,
27472bbd136eSMasatake YAMATO 				.patbuf = ptrn,
27482bbd136eSMasatake YAMATO 				.pmatch = pmatch,
27492bbd136eSMasatake YAMATO 				.nmatch = BACK_REFERENCE_COUNT,
2750653692b7SMasatake YAMATO 				.advanceto = false,
27512bbd136eSMasatake YAMATO 			};
27522b8d4c66SMasatake YAMATO 			initTaction (&window.taction);
27532b8d4c66SMasatake YAMATO 
2754e8386a4eSMasatake YAMATO 			if (ptrn->optscript && (! hasNameSlot (ptrn)))
2755e8386a4eSMasatake YAMATO 			{
27562bbd136eSMasatake YAMATO 				scriptSetup (optvm, lcb, CORK_NIL, &window);
2757668e3666SMasatake YAMATO 				EsObject *e = scriptEval (optvm, ptrn->optscript);
2758e8386a4eSMasatake YAMATO 				if (es_error_p (e))
2759e8386a4eSMasatake YAMATO 					error (WARNING, "error when evaluating: %s", ptrn->optscript_src);
2760e8386a4eSMasatake YAMATO 				es_object_unref (e);
2761668e3666SMasatake YAMATO 				scriptTeardown (optvm, lcb);
2762e8386a4eSMasatake YAMATO 			}
27639a1e266aSHadriel Kaplan 
276441e0b4f8SMasatake YAMATO 			if (ptrn->type == PTRN_TAG)
276541e0b4f8SMasatake YAMATO 			{
27662bbd136eSMasatake YAMATO 				matchTagPattern (lcb, current, ptrn, pmatch, offset_for_tag,
27672bbd136eSMasatake YAMATO 								 (ptrn->optscript && hasNameSlot (ptrn))? &window: NULL);
27682b8d4c66SMasatake YAMATO 
27692b8d4c66SMasatake YAMATO 				struct mTableActionSpec *taction = (window.taction.action == TACTION_NOP)
27702b8d4c66SMasatake YAMATO 					? &(ptrn->taction)
27712b8d4c66SMasatake YAMATO 					: &window.taction;
27722b8d4c66SMasatake YAMATO 
2773adafc5f9SMasatake YAMATO 				BEGIN_VERBOSE(vfp);
2774adafc5f9SMasatake YAMATO 				{
2775e8dbee90SHadriel Kaplan 					fprintf(vfp, "result: matched %d bytes\n", (int)(pmatch[0].rm_eo));
2776adafc5f9SMasatake YAMATO 					dumpSstack (vfp, lcb->currentScope);
2777adafc5f9SMasatake YAMATO 				}
2778adafc5f9SMasatake YAMATO 				END_VERBOSE();
2779adafc5f9SMasatake YAMATO 
27809a1e266aSHadriel Kaplan 				if (hasMessage(ptrn))
27819a1e266aSHadriel Kaplan 					printMultitableMessage (lcb->owner, table->name, i, ptrn,
27829a1e266aSHadriel Kaplan 											*offset, current, pmatch);
27839a1e266aSHadriel Kaplan 
27846cdf5716SMasatake YAMATO 				if (fillGuestRequest (cstart, current, pmatch, guest, lcb->guest_req))
27856cdf5716SMasatake YAMATO 				{
27866cdf5716SMasatake YAMATO 					Assert (lcb->guest_req->lang != LANG_AUTO);
27876cdf5716SMasatake YAMATO 					if (isGuestRequestConsistent(lcb->guest_req))
27886cdf5716SMasatake YAMATO 						guestRequestSubmit (lcb->guest_req);
27896cdf5716SMasatake YAMATO 					guestRequestClear (lcb->guest_req);
27906cdf5716SMasatake YAMATO 				}
27916cdf5716SMasatake YAMATO 
2792653692b7SMasatake YAMATO 				if (window.advanceto)
2793653692b7SMasatake YAMATO 					delta = window.advanceto_delta;
2794653692b7SMasatake YAMATO 				else
27951f3437b7SMasatake YAMATO 					delta = (ptrn->mgroup.nextFromStart
279641e0b4f8SMasatake YAMATO 							 ? pmatch [ptrn->mgroup.forNextScanning].rm_so
279741e0b4f8SMasatake YAMATO 							 : pmatch [ptrn->mgroup.forNextScanning].rm_eo);
27981f3437b7SMasatake YAMATO 				*offset += delta;
279941e0b4f8SMasatake YAMATO 
280041e0b4f8SMasatake YAMATO 				switch (taction->action)
280141e0b4f8SMasatake YAMATO 				{
280241e0b4f8SMasatake YAMATO 				case TACTION_NOP:
2803adafc5f9SMasatake YAMATO 					BEGIN_VERBOSE(vfp);
2804adafc5f9SMasatake YAMATO 					{
2805adafc5f9SMasatake YAMATO 						fprintf(vfp, "action: NOP in {%s}, stack: /", table->name);
2806adafc5f9SMasatake YAMATO 						dumpTstack(vfp, lcb->tstack);
2807adafc5f9SMasatake YAMATO 					}
2808adafc5f9SMasatake YAMATO 					END_VERBOSE();
280941e0b4f8SMasatake YAMATO 					break;
281041e0b4f8SMasatake YAMATO 				case TACTION_ENTER:
2811bf809d1aSMasatake YAMATO 					/* TODO: Limit the depth of tstack.  */
281240177cd9SMasatake YAMATO 					ptrArrayAdd (lcb->tstack,
281340177cd9SMasatake YAMATO 								 taction->continuation_table
281440177cd9SMasatake YAMATO 								 ? taction->continuation_table
281540177cd9SMasatake YAMATO 								 : table);
281641e0b4f8SMasatake YAMATO 					next = taction->table;
2817adafc5f9SMasatake YAMATO 					BEGIN_VERBOSE(vfp);
2818adafc5f9SMasatake YAMATO 					{
2819adafc5f9SMasatake YAMATO 						if (taction->continuation_table)
2820adafc5f9SMasatake YAMATO 							fprintf(vfp, "action: [enter] to {%s}, cont: {%s}, stack: /",
2821adafc5f9SMasatake YAMATO 									next->name,
2822adafc5f9SMasatake YAMATO 									taction->continuation_table->name);
2823adafc5f9SMasatake YAMATO 						else
2824adafc5f9SMasatake YAMATO 							fprintf(vfp, "action: [enter] to {%s}, stack: /", next->name);
2825adafc5f9SMasatake YAMATO 						dumpTstack(vfp, lcb->tstack);
2826adafc5f9SMasatake YAMATO 					}
2827adafc5f9SMasatake YAMATO 					END_VERBOSE();
282841e0b4f8SMasatake YAMATO 					break;
282941e0b4f8SMasatake YAMATO 				case TACTION_LEAVE:
2830adafc5f9SMasatake YAMATO 					BEGIN_VERBOSE(vfp);
2831adafc5f9SMasatake YAMATO 					{
2832adafc5f9SMasatake YAMATO 						fprintf(vfp, "action: [leave] from {%s}, stack: /", table->name);
2833adafc5f9SMasatake YAMATO 						dumpTstack(vfp, lcb->tstack);
2834adafc5f9SMasatake YAMATO 					}
2835adafc5f9SMasatake YAMATO 					END_VERBOSE();
283641e0b4f8SMasatake YAMATO 					if (ptrArrayCount (lcb->tstack) == 0)
283741e0b4f8SMasatake YAMATO 					{
283841e0b4f8SMasatake YAMATO 						error (WARNING, "leave is specified as regex table action but the table stack is empty");
283941e0b4f8SMasatake YAMATO 						return NULL;
284041e0b4f8SMasatake YAMATO 					}
284141e0b4f8SMasatake YAMATO 					next = ptrArrayLast(lcb->tstack);
284241e0b4f8SMasatake YAMATO 					ptrArrayRemoveLast (lcb->tstack);
284341e0b4f8SMasatake YAMATO 					break;
284441e0b4f8SMasatake YAMATO 				case TACTION_JUMP:
284541e0b4f8SMasatake YAMATO 					next = taction->table;
2846adafc5f9SMasatake YAMATO 					BEGIN_VERBOSE(vfp);
2847adafc5f9SMasatake YAMATO 					{
2848adafc5f9SMasatake YAMATO 						fprintf(vfp, "action: [jump] from {%s} to {%s}, stack: /", table->name, next->name);
2849adafc5f9SMasatake YAMATO 						dumpTstack(vfp, lcb->tstack);
2850adafc5f9SMasatake YAMATO 					}
2851adafc5f9SMasatake YAMATO 					END_VERBOSE();
2852adafc5f9SMasatake YAMATO 
285341e0b4f8SMasatake YAMATO 					break;
285441e0b4f8SMasatake YAMATO 				case TACTION_RESET:
285541e0b4f8SMasatake YAMATO 					next = taction->table;
2856adafc5f9SMasatake YAMATO 					BEGIN_VERBOSE(vfp);
2857adafc5f9SMasatake YAMATO 					{
2858adafc5f9SMasatake YAMATO 						fprintf(vfp, "action: [reset] to {%s}, stack: /", next->name);
2859adafc5f9SMasatake YAMATO 					}
2860adafc5f9SMasatake YAMATO 					END_VERBOSE();
2861adafc5f9SMasatake YAMATO 
2862adafc5f9SMasatake YAMATO 					ptrArrayClear (lcb->tstack);
286341e0b4f8SMasatake YAMATO 					break;
286441e0b4f8SMasatake YAMATO 				case TACTION_QUIT:
2865adafc5f9SMasatake YAMATO 					BEGIN_VERBOSE(vfp);
2866adafc5f9SMasatake YAMATO 					{
2867adafc5f9SMasatake YAMATO 						fprintf(vfp, "action: [quit], stack: /");
2868adafc5f9SMasatake YAMATO 						dumpTstack(vfp, lcb->tstack);
2869adafc5f9SMasatake YAMATO 					}
2870adafc5f9SMasatake YAMATO 					END_VERBOSE();
287141e0b4f8SMasatake YAMATO 					return NULL;
287241e0b4f8SMasatake YAMATO 				}
287341e0b4f8SMasatake YAMATO 
287441e0b4f8SMasatake YAMATO 				if (next)
287541e0b4f8SMasatake YAMATO 					break;
28761f3437b7SMasatake YAMATO 
28771f3437b7SMasatake YAMATO 				if (delta == 0)
28781f3437b7SMasatake YAMATO 				{
28791f3437b7SMasatake YAMATO 					error (WARNING, "Forcefully advance the input pos because");
28801f3437b7SMasatake YAMATO 					error (WARNING, "following conditions for entering infinite loop are satisfied:");
28811f3437b7SMasatake YAMATO 					error (WARNING, "+ matching the pattern succeeds,");
28821f3437b7SMasatake YAMATO 					error (WARNING, "+ the next table is not given, and");
28831f3437b7SMasatake YAMATO 					error (WARNING, "+ the input file pos doesn't advance.");
28841f3437b7SMasatake YAMATO 					error (WARNING, "Language: %s, input file: %s, pos: %u",
28851f3437b7SMasatake YAMATO 						   getLanguageName (lcb->owner), getInputFileName(), *offset);
28861f3437b7SMasatake YAMATO 					++*offset;
28871f3437b7SMasatake YAMATO 				}
288841e0b4f8SMasatake YAMATO 			}
288941e0b4f8SMasatake YAMATO 			else if (ptrn->type == PTRN_CALLBACK)
289041e0b4f8SMasatake YAMATO 				;	/* Not implemented yet */
289141e0b4f8SMasatake YAMATO 			else
289241e0b4f8SMasatake YAMATO 			{
289341e0b4f8SMasatake YAMATO 				Assert ("invalid pattern type" == NULL);
289441e0b4f8SMasatake YAMATO 				break;
289541e0b4f8SMasatake YAMATO 			}
289641e0b4f8SMasatake YAMATO 			goto restart;
289741e0b4f8SMasatake YAMATO 		}
28981e923193SMasatake YAMATO 		else
2899134629a0SHadriel Kaplan 			entry->statistics.unmatch++;
290041e0b4f8SMasatake YAMATO 	}
290141e0b4f8SMasatake YAMATO  out:
290241e0b4f8SMasatake YAMATO 	if (next == NULL && ptrArrayCount (lcb->tstack) > 0)
290341e0b4f8SMasatake YAMATO 	{
2904adafc5f9SMasatake YAMATO 		static int apop_count = 0;
290541e0b4f8SMasatake YAMATO 		next = ptrArrayLast(lcb->tstack);
2906e8dbee90SHadriel Kaplan 		verbose("result: no match - autopop<%d> from {%s} to {%s} @ %lu\n", apop_count++, table->name, next->name,
2907adafc5f9SMasatake YAMATO 				getInputLineNumberForFileOffset(*offset));
290841e0b4f8SMasatake YAMATO 		ptrArrayRemoveLast (lcb->tstack);
290941e0b4f8SMasatake YAMATO 	}
291041e0b4f8SMasatake YAMATO 	return next;
291141e0b4f8SMasatake YAMATO }
291241e0b4f8SMasatake YAMATO 
extendRegexTable(struct lregexControlBlock * lcb,const char * src,const char * dist)2913bf809d1aSMasatake YAMATO extern void extendRegexTable (struct lregexControlBlock *lcb, const char *src, const char *dist)
2914bf809d1aSMasatake YAMATO {
2915bf809d1aSMasatake YAMATO 
2916bf809d1aSMasatake YAMATO 	int i;
2917bf809d1aSMasatake YAMATO 	struct regexTable * src_table;
2918bf809d1aSMasatake YAMATO 	struct regexTable * dist_table;
2919bf809d1aSMasatake YAMATO 
2920bf809d1aSMasatake YAMATO 	verbose ("extend regex table  \"%s\" with \"%s\"\n", dist, src);
2921bf809d1aSMasatake YAMATO 
2922bf809d1aSMasatake YAMATO 	i = getTableIndexForName (lcb, src);
2923bf809d1aSMasatake YAMATO 	if (i < 0)
2924bf809d1aSMasatake YAMATO 		error (FATAL, "no such regex table in %s: %s", getLanguageName(lcb->owner), src);
2925bf809d1aSMasatake YAMATO 	src_table = ptrArrayItem(lcb->tables, i);
2926bf809d1aSMasatake YAMATO 
2927bf809d1aSMasatake YAMATO 	i = getTableIndexForName (lcb, dist);
2928bf809d1aSMasatake YAMATO 	if (i < 0)
2929bf809d1aSMasatake YAMATO 		error (FATAL, "no such regex table in %s: %s", getLanguageName(lcb->owner), dist);
2930bf809d1aSMasatake YAMATO 	dist_table = ptrArrayItem(lcb->tables, i);
2931bf809d1aSMasatake YAMATO 
29324c64e833SMasatake YAMATO 	for (i = 0; i < (int)ptrArrayCount(src_table->entries); i++)
2933bf809d1aSMasatake YAMATO 	{
2934134629a0SHadriel Kaplan 		regexTableEntry *entry = ptrArrayItem (src_table->entries, i);
2935134629a0SHadriel Kaplan 		ptrArrayAdd(dist_table->entries, newRefPatternEntry(entry));
2936bf809d1aSMasatake YAMATO 	}
2937bf809d1aSMasatake YAMATO }
2938bf809d1aSMasatake YAMATO 
printMultitableStatistics(struct lregexControlBlock * lcb)2939d4318624SMasatake YAMATO extern void printMultitableStatistics (struct lregexControlBlock *lcb)
29401e923193SMasatake YAMATO {
29411e923193SMasatake YAMATO 	if (ptrArrayCount(lcb->tables) == 0)
29421e923193SMasatake YAMATO 		return;
29431e923193SMasatake YAMATO 
2944d4318624SMasatake YAMATO 	fprintf(stderr, "\nMTABLE REGEX STATISTICS of %s\n", getLanguageName (lcb->owner));
2945d4318624SMasatake YAMATO 	fputs("==============================================\n", stderr);
29461e923193SMasatake YAMATO 	for (unsigned int i = 0; i < ptrArrayCount(lcb->tables); i++)
29471e923193SMasatake YAMATO 	{
2948ba5ad3fbSAlan Barr 		struct regexTable *table = ptrArrayItem (lcb->tables, i);
2949d4318624SMasatake YAMATO 		fprintf(stderr, "%s\n", table->name);
2950d4318624SMasatake YAMATO 		fputs("-----------------------\n", stderr);
2951134629a0SHadriel Kaplan 		for (unsigned int j = 0; j < ptrArrayCount(table->entries); j++)
29521e923193SMasatake YAMATO 		{
2953134629a0SHadriel Kaplan 			regexTableEntry *entry = ptrArrayItem (table->entries, j);
2954134629a0SHadriel Kaplan 			Assert (entry && entry->pattern);
2955d4318624SMasatake YAMATO 			fprintf(stderr, "%10u/%-10u%-40s ref: %d\n",
2956134629a0SHadriel Kaplan 					entry->statistics.match,
2957134629a0SHadriel Kaplan 					entry->statistics.unmatch + entry->statistics.match,
2958134629a0SHadriel Kaplan 					entry->pattern->pattern_string,
2959134629a0SHadriel Kaplan 					entry->pattern->refcount);
29601e923193SMasatake YAMATO 		}
2961d4318624SMasatake YAMATO 		fputc('\n', stderr);
29621e923193SMasatake YAMATO 	}
29631e923193SMasatake YAMATO }
29641e923193SMasatake YAMATO 
matchMultitableRegex(struct lregexControlBlock * lcb,const vString * const allLines)296541e0b4f8SMasatake YAMATO extern bool matchMultitableRegex (struct lregexControlBlock *lcb, const vString* const allLines)
296641e0b4f8SMasatake YAMATO {
296741e0b4f8SMasatake YAMATO 	if (ptrArrayCount (lcb->tables) == 0)
296841e0b4f8SMasatake YAMATO 		return false;
296941e0b4f8SMasatake YAMATO 
297041e0b4f8SMasatake YAMATO 	struct regexTable *table = ptrArrayItem (lcb->tables, 0);
297141e0b4f8SMasatake YAMATO 	unsigned int offset = 0;
297241e0b4f8SMasatake YAMATO 
2973afcf38b2SMasatake YAMATO 	int motionless_counter = 0;
2974afcf38b2SMasatake YAMATO 	unsigned int last_offset;
2975afcf38b2SMasatake YAMATO 
2976afcf38b2SMasatake YAMATO 
297741e0b4f8SMasatake YAMATO 	while (table)
297841e0b4f8SMasatake YAMATO 	{
2979afcf38b2SMasatake YAMATO 		last_offset = offset;
298041e0b4f8SMasatake YAMATO 		table = matchMultitableRegexTable(lcb, table, allLines, &offset);
2981afcf38b2SMasatake YAMATO 
2982afcf38b2SMasatake YAMATO 		if (last_offset == offset)
2983afcf38b2SMasatake YAMATO 			motionless_counter++;
2984afcf38b2SMasatake YAMATO 		else
2985afcf38b2SMasatake YAMATO 			motionless_counter = 0;
2986afcf38b2SMasatake YAMATO 
2987afcf38b2SMasatake YAMATO 		if (motionless_counter > MTABLE_MOTIONLESS_MAX)
2988afcf38b2SMasatake YAMATO 		{
2989afcf38b2SMasatake YAMATO 			error (WARNING, "mtable<%s/%s>: the input cursor stays at %u in %s so long though the tables are switched",
2990afcf38b2SMasatake YAMATO 				   getLanguageName (lcb->owner),
2991afcf38b2SMasatake YAMATO 				   table->name, offset, getInputFileName ());
2992afcf38b2SMasatake YAMATO 			break;
2993afcf38b2SMasatake YAMATO 		}
2994afcf38b2SMasatake YAMATO 
2995042e4190SMasatake YAMATO 		if (table && (ptrArrayCount (lcb->tstack) > MTABLE_STACK_MAX_DEPTH))
2996042e4190SMasatake YAMATO 		{
2997042e4190SMasatake YAMATO 			unsigned int i;
2998042e4190SMasatake YAMATO 			struct regexTable *t;
2999042e4190SMasatake YAMATO 
3000042e4190SMasatake YAMATO 			error (WARNING, "mtable<%s/%s>: the tenter/tleave stack overflows at %u in %s",
3001042e4190SMasatake YAMATO 				   getLanguageName (lcb->owner),
3002042e4190SMasatake YAMATO 				   table->name, offset, getInputFileName ());
3003042e4190SMasatake YAMATO 			error (WARNING, "DUMP FROM THE TOP:");
3004ebdbd8e2SK.Takata 			/* TODO: use dumpTstack */
3005042e4190SMasatake YAMATO 			for (i = ptrArrayCount(lcb->tstack); 0 < i; --i)
3006042e4190SMasatake YAMATO 			{
3007042e4190SMasatake YAMATO 				t = ptrArrayItem (lcb->tstack, i - 1);
3008042e4190SMasatake YAMATO 				error (WARNING, "%3u %s", i - 1, t->name);
3009042e4190SMasatake YAMATO 			}
3010042e4190SMasatake YAMATO 
3011042e4190SMasatake YAMATO 			break;
3012042e4190SMasatake YAMATO 		}
301341e0b4f8SMasatake YAMATO 	}
301441e0b4f8SMasatake YAMATO 
301541e0b4f8SMasatake YAMATO 	return true;
301641e0b4f8SMasatake YAMATO }
301741e0b4f8SMasatake YAMATO 
makePromiseForAreaSpecifiedWithOffsets(const char * parser,off_t startOffset,off_t endOffset)3018b19716b4SMasatake YAMATO static int  makePromiseForAreaSpecifiedWithOffsets (const char *parser,
3019b19716b4SMasatake YAMATO 													off_t startOffset,
3020b19716b4SMasatake YAMATO 													off_t endOffset)
3021b19716b4SMasatake YAMATO {
30226cdf5716SMasatake YAMATO 	unsigned long startLine = getInputLineNumberForFileOffset(startOffset);
30236cdf5716SMasatake YAMATO 	unsigned long endLine = getInputLineNumberForFileOffset(endOffset);
3024b19716b4SMasatake YAMATO 	unsigned long startLineOffset = getInputFileOffsetForLine (startLine);
3025b19716b4SMasatake YAMATO 	unsigned long endLineOffset = getInputFileOffsetForLine (endLine);
3026b19716b4SMasatake YAMATO 
30278b459ed6SMasatake YAMATO 	Assert(startOffset >= startLineOffset);
30288b459ed6SMasatake YAMATO 	Assert(endOffset >= endLineOffset);
30298b459ed6SMasatake YAMATO 
3030b19716b4SMasatake YAMATO 	return makePromise (parser,
3031b19716b4SMasatake YAMATO 						startLine, startOffset - startLineOffset,
3032b19716b4SMasatake YAMATO 						endLine, endOffset - endLineOffset,
3033b19716b4SMasatake YAMATO 						startOffset - startLineOffset);
3034b19716b4SMasatake YAMATO }
3035b19716b4SMasatake YAMATO 
guestRequestNew(void)30366cdf5716SMasatake YAMATO static struct guestRequest *guestRequestNew (void)
30376cdf5716SMasatake YAMATO {
30386cdf5716SMasatake YAMATO 	struct guestRequest *r = xMalloc (1, struct guestRequest);
30396cdf5716SMasatake YAMATO 
30406cdf5716SMasatake YAMATO 
30416cdf5716SMasatake YAMATO 	guestRequestClear (r);
30426cdf5716SMasatake YAMATO 	return r;
30436cdf5716SMasatake YAMATO }
30446cdf5716SMasatake YAMATO 
guestRequestDelete(struct guestRequest * r)30456cdf5716SMasatake YAMATO static void   guestRequestDelete (struct guestRequest *r)
30466cdf5716SMasatake YAMATO {
30476cdf5716SMasatake YAMATO 	eFree (r);
30486cdf5716SMasatake YAMATO }
30496cdf5716SMasatake YAMATO 
guestRequestIsFilled(struct guestRequest * r)30506cdf5716SMasatake YAMATO static bool   guestRequestIsFilled(struct guestRequest *r)
30516cdf5716SMasatake YAMATO {
30526cdf5716SMasatake YAMATO 	return (r->lang_set && (r->boundary + 0)->offset_set && (r->boundary + 1)->offset_set);
30536cdf5716SMasatake YAMATO }
30546cdf5716SMasatake YAMATO 
guestRequestClear(struct guestRequest * r)30556cdf5716SMasatake YAMATO static void   guestRequestClear (struct guestRequest *r)
30566cdf5716SMasatake YAMATO {
30576cdf5716SMasatake YAMATO 	r->lang_set = false;
30586cdf5716SMasatake YAMATO 	r->boundary[BOUNDARY_START].offset_set = false;
30596cdf5716SMasatake YAMATO 	r->boundary[BOUNDARY_END].offset_set = false;
30606cdf5716SMasatake YAMATO }
30616cdf5716SMasatake YAMATO 
guestRequestSubmit(struct guestRequest * r)30626cdf5716SMasatake YAMATO static void   guestRequestSubmit (struct guestRequest *r)
30636cdf5716SMasatake YAMATO {
30646cdf5716SMasatake YAMATO 	const char *langName = getLanguageName (r->lang);
30656cdf5716SMasatake YAMATO 	verbose ("guestRequestSubmit: %s; "
3066540cbe83SK.Takata 			 "range: %"PRId64" - %"PRId64"\n",
30676cdf5716SMasatake YAMATO 			 langName,
3068540cbe83SK.Takata 			 (int64_t)r->boundary[BOUNDARY_START].offset,
3069540cbe83SK.Takata 			 (int64_t)r->boundary[BOUNDARY_END].offset);
30706cdf5716SMasatake YAMATO 	makePromiseForAreaSpecifiedWithOffsets (langName,
30716cdf5716SMasatake YAMATO 											r->boundary[BOUNDARY_START].offset,
30726cdf5716SMasatake YAMATO 											r->boundary[BOUNDARY_END].offset);
30736cdf5716SMasatake YAMATO }
30746cdf5716SMasatake YAMATO 
3075668e3666SMasatake YAMATO /*
3076668e3666SMasatake YAMATO  * Script related functions
3077668e3666SMasatake YAMATO  */
30783d644137SMasatake YAMATO 
3079668e3666SMasatake YAMATO /* This functions expects { code }} as input.
3080668e3666SMasatake YAMATO  * Be care that curly brackets must be unbalanced.
3081668e3666SMasatake YAMATO  */
scriptRead(OptVM * vm,const char * src)3082668e3666SMasatake YAMATO static EsObject *scriptRead (OptVM *vm, const char *src)
30833d644137SMasatake YAMATO {
3084668e3666SMasatake YAMATO 	size_t len = strlen (src);
3085668e3666SMasatake YAMATO 	Assert (len > 2);
3086668e3666SMasatake YAMATO 	Assert (src[len - 1] == '}');
3087668e3666SMasatake YAMATO 	Assert (src[len - 2] == '}');
3088668e3666SMasatake YAMATO 
3089668e3666SMasatake YAMATO 	EsObject *obj = optscriptRead (vm, src + 1, len - 1 - 1);
3090668e3666SMasatake YAMATO 	if (es_error_p (obj))
3091668e3666SMasatake YAMATO 		error (FATAL, "failed in loading an optscript: %s", src);
3092668e3666SMasatake YAMATO 	return obj;
30933d644137SMasatake YAMATO }
30943d644137SMasatake YAMATO 
scriptEval(OptVM * vm,EsObject * optscript)3095668e3666SMasatake YAMATO extern EsObject* scriptEval (OptVM *vm, EsObject *optscript)
30963d644137SMasatake YAMATO {
3097668e3666SMasatake YAMATO 	return optscriptEval (vm, optscript);
30983d644137SMasatake YAMATO }
30993d644137SMasatake YAMATO 
scriptEvalHook(OptVM * vm,struct lregexControlBlock * lcb,enum scriptHook hook)3100b6124a60SMasatake YAMATO static void scriptEvalHook (OptVM *vm, struct lregexControlBlock *lcb, enum scriptHook hook)
3101fba3677cSMasatake YAMATO {
31021409a195SMasatake YAMATO 	if (ptrArrayCount (lcb->hook_code[hook]) == 0)
3103fba3677cSMasatake YAMATO 	{
31041409a195SMasatake YAMATO 		for (int i = 0; i < ptrArrayCount (lcb->hook[hook]); i++)
3105cda2e6c3SMasatake YAMATO 		{
31061409a195SMasatake YAMATO 			const char *src = ptrArrayItem (lcb->hook[hook], i);
3107668e3666SMasatake YAMATO 			EsObject *code = scriptRead (vm, src);
3108cda2e6c3SMasatake YAMATO 			if (es_error_p (code))
31091409a195SMasatake YAMATO 				error (FATAL, "error when reading hook[%d] code: %s", hook, src);
31101409a195SMasatake YAMATO 			ptrArrayAdd (lcb->hook_code[hook], es_object_ref (code));
3111668e3666SMasatake YAMATO 			es_object_unref (code);
3112668e3666SMasatake YAMATO 		}
3113cda2e6c3SMasatake YAMATO 	}
31141409a195SMasatake YAMATO 	for (int i = 0; i < ptrArrayCount (lcb->hook_code[hook]); i++)
3115cda2e6c3SMasatake YAMATO 	{
31161409a195SMasatake YAMATO 		EsObject *code = ptrArrayItem (lcb->hook_code[hook], i);
3117cda2e6c3SMasatake YAMATO 		EsObject * e = optscriptEval (vm, code);
3118cda2e6c3SMasatake YAMATO 		if (es_error_p (e))
31191409a195SMasatake YAMATO 			error (WARNING, "error when evaluating hook[%d] code: %s",
31201409a195SMasatake YAMATO 				   hook, (char *)ptrArrayItem (lcb->hook[i], i));
3121cda2e6c3SMasatake YAMATO 	}
3122fba3677cSMasatake YAMATO }
3123fba3677cSMasatake YAMATO 
scriptSetup(OptVM * vm,struct lregexControlBlock * lcb,int corkIndex,scriptWindow * window)31242bbd136eSMasatake YAMATO static void scriptSetup (OptVM *vm, struct lregexControlBlock *lcb, int corkIndex, scriptWindow *window)
3125fba3677cSMasatake YAMATO {
31262bbd136eSMasatake YAMATO 	lcb->window = window;
3127668e3666SMasatake YAMATO 	optscriptSetup (vm, lcb->local_dict, corkIndex);
3128fba3677cSMasatake YAMATO }
3129fba3677cSMasatake YAMATO 
scriptTeardown(OptVM * vm,struct lregexControlBlock * lcb)3130668e3666SMasatake YAMATO static void scriptTeardown (OptVM *vm, struct lregexControlBlock *lcb)
3131fba3677cSMasatake YAMATO {
3132668e3666SMasatake YAMATO 	optscriptTeardown (vm, lcb->local_dict);
31332bbd136eSMasatake YAMATO 	lcb->window = NULL;
3134fba3677cSMasatake YAMATO }
3135fba3677cSMasatake YAMATO 
addOptscriptToHook(struct lregexControlBlock * lcb,enum scriptHook hook,const char * code)3136b6124a60SMasatake YAMATO extern void	addOptscriptToHook (struct lregexControlBlock *lcb, enum scriptHook hook, const char *code)
31375c872341SMasatake YAMATO {
3138b6124a60SMasatake YAMATO 	ptrArrayAdd (lcb->hook[hook], eStrdup (code));
31391409a195SMasatake YAMATO }
31401409a195SMasatake YAMATO 
3141ce990805SThomas Braun /* Return true if available. */
checkRegex(void)3142ce990805SThomas Braun extern bool checkRegex (void)
3143d4c6f1e6SMasatake YAMATO {
3144a656c9bfSMasatake YAMATO #if defined (CHECK_REGCOMP)
3145d4c6f1e6SMasatake YAMATO 	{
3146d4c6f1e6SMasatake YAMATO 		/* Check for broken regcomp() on Cygwin */
3147d4c6f1e6SMasatake YAMATO 		regex_t patbuf;
3148d4c6f1e6SMasatake YAMATO 		int errcode;
3149d4c6f1e6SMasatake YAMATO 		if (regcomp (&patbuf, "/hello/", 0) != 0)
3150d4c6f1e6SMasatake YAMATO 			error (WARNING, "Disabling broken regex");
3151d4c6f1e6SMasatake YAMATO 		else
3152ce990805SThomas Braun 			regexAvailable = true;
3153d4c6f1e6SMasatake YAMATO 	}
3154d4c6f1e6SMasatake YAMATO #else
3155d4c6f1e6SMasatake YAMATO 	/* We are using bundled regex engine. */
3156ce990805SThomas Braun 	regexAvailable = true;
3157d4c6f1e6SMasatake YAMATO #endif
3158e8386a4eSMasatake YAMATO 
3159d4c6f1e6SMasatake YAMATO 	return regexAvailable;
3160d4c6f1e6SMasatake YAMATO }
3161965b7025SMasatake YAMATO 
316234deb294SMasatake YAMATO static EsObject *OPTSCRIPT_ERR_UNKNOWNKIND;
316334deb294SMasatake YAMATO 
316434deb294SMasatake YAMATO /* name:str kind:name loc _TAG tag
316534deb294SMasatake YAMATO  * name:str kind:name     _TAG tag */
lrop_make_tag(OptVM * vm,EsObject * name)316634deb294SMasatake YAMATO static EsObject* lrop_make_tag (OptVM *vm, EsObject *name)
316734deb294SMasatake YAMATO {
316834deb294SMasatake YAMATO 	matchLoc *loc;
316934deb294SMasatake YAMATO 
317034deb294SMasatake YAMATO 	if (opt_vm_ostack_count (vm) < 1)
317134deb294SMasatake YAMATO 		return OPT_ERR_UNDERFLOW;
317234deb294SMasatake YAMATO 
317334deb294SMasatake YAMATO 	int index;
317434deb294SMasatake YAMATO 	EsObject *top = opt_vm_ostack_top (vm);
317534deb294SMasatake YAMATO 	if (es_object_get_type (top) == OPT_TYPE_MATCHLOC)
317634deb294SMasatake YAMATO 	{
317734deb294SMasatake YAMATO 		if (opt_vm_ostack_count (vm) < 3)
317834deb294SMasatake YAMATO 			return OPT_ERR_UNDERFLOW;
317934deb294SMasatake YAMATO 		loc = es_pointer_get (top);
318034deb294SMasatake YAMATO 		index = 1;
318134deb294SMasatake YAMATO 	}
318234deb294SMasatake YAMATO 	else
318334deb294SMasatake YAMATO 	{
318434deb294SMasatake YAMATO 		struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
318534deb294SMasatake YAMATO 		if (lcb->window->patbuf->regptype != REG_PARSER_SINGLE_LINE)
318634deb294SMasatake YAMATO 			return OPT_ERR_TYPECHECK;
318734deb294SMasatake YAMATO 		if (opt_vm_ostack_count (vm) < 2)
318834deb294SMasatake YAMATO 			return OPT_ERR_UNDERFLOW;
318934deb294SMasatake YAMATO 		loc = NULL;
319034deb294SMasatake YAMATO 		index = 0;
319134deb294SMasatake YAMATO 	}
319234deb294SMasatake YAMATO 
319334deb294SMasatake YAMATO 	EsObject *kind = opt_vm_ostack_peek (vm, index++);
319434deb294SMasatake YAMATO 	if (es_object_get_type (kind) != OPT_TYPE_NAME)
319534deb294SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
319634deb294SMasatake YAMATO 	EsObject *kind_sym = es_pointer_get (kind);
319734deb294SMasatake YAMATO 	const char *kind_str = es_symbol_get (kind_sym);
319834deb294SMasatake YAMATO 	kindDefinition* kind_def = getLanguageKindForName (getInputLanguage (),
319934deb294SMasatake YAMATO 													   kind_str);
320034deb294SMasatake YAMATO 	if (!kind_def)
320134deb294SMasatake YAMATO 		return OPTSCRIPT_ERR_UNKNOWNKIND;
320234deb294SMasatake YAMATO 	int kind_index = kind_def->id;
320334deb294SMasatake YAMATO 
320434deb294SMasatake YAMATO 	EsObject *tname = opt_vm_ostack_peek (vm, index++);
320534deb294SMasatake YAMATO 	if (es_object_get_type (tname) != OPT_TYPE_STRING)
320634deb294SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
320734deb294SMasatake YAMATO 	const char *n = opt_string_get_cstr (tname);
320834deb294SMasatake YAMATO 	if (n [0] == '\0')
3209820e8cc6SMasatake YAMATO 		return OPT_ERR_RANGECHECK; /* TODO */
321034deb294SMasatake YAMATO 
321134deb294SMasatake YAMATO 	tagEntryInfo *e = xMalloc (1, tagEntryInfo);
321234deb294SMasatake YAMATO 	initRegexTag (e, eStrdup (n),
321334deb294SMasatake YAMATO 				  kind_index, ROLE_DEFINITION_INDEX, CORK_NIL, 0,
321434deb294SMasatake YAMATO 				  loc? loc->line: 0, loc? &loc->pos: NULL, XTAG_UNKNOWN);
321534deb294SMasatake YAMATO 	EsObject *obj = es_pointer_new (OPT_TYPE_TAG, e);
321634deb294SMasatake YAMATO 	if (es_error_p (obj))
321734deb294SMasatake YAMATO 		return obj;
321834deb294SMasatake YAMATO 
321934deb294SMasatake YAMATO 	while (index-- > 0)
322034deb294SMasatake YAMATO 		opt_vm_ostack_pop (vm);
322134deb294SMasatake YAMATO 
322234deb294SMasatake YAMATO 	opt_vm_ostack_push (vm, obj);
322334deb294SMasatake YAMATO 	es_object_unref (obj);
322434deb294SMasatake YAMATO 	return es_false;
322534deb294SMasatake YAMATO }
322634deb294SMasatake YAMATO 
32277b347e74SMasatake YAMATO static EsObject *OPTSCRIPT_ERR_UNKNOWNROLE;
32287b347e74SMasatake YAMATO 
lrop_make_reftag(OptVM * vm,EsObject * name)32297b347e74SMasatake YAMATO static EsObject* lrop_make_reftag (OptVM *vm, EsObject *name)
32307b347e74SMasatake YAMATO {
32317b347e74SMasatake YAMATO 	matchLoc *loc;
32327b347e74SMasatake YAMATO 
32337b347e74SMasatake YAMATO 	if (opt_vm_ostack_count (vm) < 1)
32347b347e74SMasatake YAMATO 		return OPT_ERR_UNDERFLOW;
32357b347e74SMasatake YAMATO 
32367b347e74SMasatake YAMATO 	int index;
32377b347e74SMasatake YAMATO 	EsObject *top = opt_vm_ostack_top (vm);
32387b347e74SMasatake YAMATO 	if (es_object_get_type (top) == OPT_TYPE_MATCHLOC)
32397b347e74SMasatake YAMATO 	{
32407b347e74SMasatake YAMATO 		if (opt_vm_ostack_count (vm) < 4)
32417b347e74SMasatake YAMATO 			return OPT_ERR_UNDERFLOW;
32427b347e74SMasatake YAMATO 		loc = es_pointer_get (top);
32437b347e74SMasatake YAMATO 		index = 1;
32447b347e74SMasatake YAMATO 	}
32457b347e74SMasatake YAMATO 	else
32467b347e74SMasatake YAMATO 	{
32477b347e74SMasatake YAMATO 		struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
32487b347e74SMasatake YAMATO 		if (lcb->window->patbuf->regptype != REG_PARSER_SINGLE_LINE)
32497b347e74SMasatake YAMATO 			return OPT_ERR_TYPECHECK;
32507b347e74SMasatake YAMATO 		if (opt_vm_ostack_count (vm) < 3)
32517b347e74SMasatake YAMATO 			return OPT_ERR_UNDERFLOW;
32527b347e74SMasatake YAMATO 		loc = NULL;
32537b347e74SMasatake YAMATO 		index = 0;
32547b347e74SMasatake YAMATO 	}
32557b347e74SMasatake YAMATO 
32567b347e74SMasatake YAMATO 	EsObject *role = opt_vm_ostack_peek (vm, index++);
32577b347e74SMasatake YAMATO 	if (es_object_get_type (role) != OPT_TYPE_NAME)
32587b347e74SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
32597b347e74SMasatake YAMATO 
32607b347e74SMasatake YAMATO 	EsObject *kind = opt_vm_ostack_peek (vm, index++);
32617b347e74SMasatake YAMATO 	if (es_object_get_type (kind) != OPT_TYPE_NAME)
32627b347e74SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
32637b347e74SMasatake YAMATO 	EsObject *kind_sym = es_pointer_get (kind);
32647b347e74SMasatake YAMATO 	const char *kind_str = es_symbol_get (kind_sym);
32657b347e74SMasatake YAMATO 	langType lang = getInputLanguage ();
32667b347e74SMasatake YAMATO 	kindDefinition* kind_def = getLanguageKindForName (lang, kind_str);
32677b347e74SMasatake YAMATO 	if (!kind_def)
32687b347e74SMasatake YAMATO 		return OPTSCRIPT_ERR_UNKNOWNKIND;
32697b347e74SMasatake YAMATO 	int kind_index = kind_def->id;
32707b347e74SMasatake YAMATO 
32717b347e74SMasatake YAMATO 	EsObject *role_sym = es_pointer_get (role);
32727b347e74SMasatake YAMATO 	const char *role_str = es_symbol_get (role_sym);
32737b347e74SMasatake YAMATO 	roleDefinition* role_def = getLanguageRoleForName (lang, kind_index, role_str);
32747b347e74SMasatake YAMATO 	if (!role_def)
32757b347e74SMasatake YAMATO 		return OPTSCRIPT_ERR_UNKNOWNROLE;
32767b347e74SMasatake YAMATO 	int role_index = role_def->id;
32777b347e74SMasatake YAMATO 
32787b347e74SMasatake YAMATO 	EsObject *tname = opt_vm_ostack_peek (vm, index++);
32797b347e74SMasatake YAMATO 	if (es_object_get_type (tname) != OPT_TYPE_STRING)
32807b347e74SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
32817b347e74SMasatake YAMATO 	const char *n = opt_string_get_cstr (tname);
32827b347e74SMasatake YAMATO 	if (n [0] == '\0')
3283820e8cc6SMasatake YAMATO 		return OPT_ERR_RANGECHECK; /* TODO */
32847b347e74SMasatake YAMATO 
32857b347e74SMasatake YAMATO 	tagEntryInfo *e = xMalloc (1, tagEntryInfo);
32867b347e74SMasatake YAMATO 	initRegexTag (e, eStrdup (n),
32877b347e74SMasatake YAMATO 				  kind_index, role_index, CORK_NIL, 0,
32887b347e74SMasatake YAMATO 				  loc? loc->line: 0, loc? &loc->pos: NULL,
32897b347e74SMasatake YAMATO 				  role_index == ROLE_DEFINITION_INDEX
32907b347e74SMasatake YAMATO 				  ? XTAG_UNKNOWN
32917b347e74SMasatake YAMATO 				  : XTAG_REFERENCE_TAGS);
32927b347e74SMasatake YAMATO 	EsObject *obj = es_pointer_new (OPT_TYPE_TAG, e);
32937b347e74SMasatake YAMATO 	if (es_error_p (obj))
32947b347e74SMasatake YAMATO 		return obj;
32957b347e74SMasatake YAMATO 
32967b347e74SMasatake YAMATO 	while (index-- > 0)
32977b347e74SMasatake YAMATO 		opt_vm_ostack_pop (vm);
32987b347e74SMasatake YAMATO 
32997b347e74SMasatake YAMATO 	opt_vm_ostack_push (vm, obj);
33007b347e74SMasatake YAMATO 	es_object_unref (obj);
33017b347e74SMasatake YAMATO 	return es_false;
33027b347e74SMasatake YAMATO }
33037b347e74SMasatake YAMATO 
330434deb294SMasatake YAMATO /* tag COMMIT int */
lrop_commit_tag(OptVM * vm,EsObject * name)330534deb294SMasatake YAMATO static EsObject* lrop_commit_tag (OptVM *vm, EsObject *name)
330634deb294SMasatake YAMATO {
330734deb294SMasatake YAMATO 	EsObject *tag = opt_vm_ostack_top (vm);
330834deb294SMasatake YAMATO 	if (es_object_get_type (tag) != OPT_TYPE_TAG)
330934deb294SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
331034deb294SMasatake YAMATO 
331134deb294SMasatake YAMATO 	tagEntryInfo *e = es_pointer_get (tag);
331234deb294SMasatake YAMATO 	int corkIndex = makeTagEntry (e);
331334deb294SMasatake YAMATO 	EsObject *n = es_integer_new (corkIndex);
331434deb294SMasatake YAMATO 	if (es_error_p (n))
331534deb294SMasatake YAMATO 		return n;
331634deb294SMasatake YAMATO 	opt_vm_ostack_pop (vm);
331734deb294SMasatake YAMATO 	opt_vm_ostack_push (vm, n);
331834deb294SMasatake YAMATO 	es_object_unref (n);
331934deb294SMasatake YAMATO 	return es_false;
332034deb294SMasatake YAMATO }
332134deb294SMasatake YAMATO 
lrop_get_match_loc(OptVM * vm,EsObject * name)3322ed3202bdSMasatake YAMATO static EsObject* lrop_get_match_loc (OptVM *vm, EsObject *name)
3323ed3202bdSMasatake YAMATO {
3324ed3202bdSMasatake YAMATO 
3325ed3202bdSMasatake YAMATO 	bool start;
3326ed3202bdSMasatake YAMATO 	EsObject *group;
3327ed3202bdSMasatake YAMATO 
3328ed3202bdSMasatake YAMATO 	if (opt_vm_ostack_count (vm) < 1)
3329ed3202bdSMasatake YAMATO 		return OPT_ERR_UNDERFLOW;
3330ed3202bdSMasatake YAMATO 
3331ed3202bdSMasatake YAMATO 	EsObject *tmp = opt_vm_ostack_top (vm);
3332ed3202bdSMasatake YAMATO 
3333ed3202bdSMasatake YAMATO 	if (es_object_get_type (tmp) == ES_TYPE_INTEGER)
3334ed3202bdSMasatake YAMATO 	{
3335ed3202bdSMasatake YAMATO 		group = tmp;
3336ed3202bdSMasatake YAMATO 		start = true;
3337ed3202bdSMasatake YAMATO 	}
3338ed3202bdSMasatake YAMATO 	else
3339ed3202bdSMasatake YAMATO 	{
3340ed3202bdSMasatake YAMATO 		EsObject *pos = tmp;
3341ed3202bdSMasatake YAMATO 
3342ed3202bdSMasatake YAMATO 		static EsObject *start_name, *end_name;
3343ed3202bdSMasatake YAMATO 		if (!start_name)
3344ed3202bdSMasatake YAMATO 		{
3345ed3202bdSMasatake YAMATO 			start_name = opt_name_new_from_cstr ("start");
3346ed3202bdSMasatake YAMATO 			end_name = opt_name_new_from_cstr ("end");
3347ed3202bdSMasatake YAMATO 		}
3348ed3202bdSMasatake YAMATO 
3349ed3202bdSMasatake YAMATO 		if (es_object_equal (pos, start_name))
3350ed3202bdSMasatake YAMATO 			start = true;
3351ed3202bdSMasatake YAMATO 		else if (es_object_equal (pos, end_name))
3352ed3202bdSMasatake YAMATO 			start = false;
3353ed3202bdSMasatake YAMATO 		else
3354ed3202bdSMasatake YAMATO 			return OPT_ERR_TYPECHECK;
3355ed3202bdSMasatake YAMATO 
3356ed3202bdSMasatake YAMATO 		if (opt_vm_ostack_count (vm) < 2)
3357ed3202bdSMasatake YAMATO 			return OPT_ERR_UNDERFLOW;
3358ed3202bdSMasatake YAMATO 
3359ed3202bdSMasatake YAMATO 		group = opt_vm_ostack_peek (vm, 1);
3360ed3202bdSMasatake YAMATO 		if (es_object_get_type (group) != ES_TYPE_INTEGER)
3361ed3202bdSMasatake YAMATO 			return OPT_ERR_TYPECHECK;
3362ed3202bdSMasatake YAMATO 	}
3363ed3202bdSMasatake YAMATO 
3364ed3202bdSMasatake YAMATO 	int g = es_integer_get (group);
3365ed3202bdSMasatake YAMATO 	if (g < 1)
3366ed3202bdSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
3367ed3202bdSMasatake YAMATO 
3368ed3202bdSMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
3369ed3202bdSMasatake YAMATO 	scriptWindow *window = lcb->window;
3370ed3202bdSMasatake YAMATO 
3371cf6b3bb9SMasatake YAMATO 	matchLoc *mloc = make_mloc (window, g, start);
3372cf6b3bb9SMasatake YAMATO 	if (mloc == NULL)
3373ed3202bdSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
3374ed3202bdSMasatake YAMATO 
3375ed3202bdSMasatake YAMATO 	EsObject * mlocobj = es_pointer_new (OPT_TYPE_MATCHLOC, mloc);
3376ed3202bdSMasatake YAMATO 	if (es_error_p (mlocobj))
3377e02e1d1fSMasatake YAMATO 	{
3378e02e1d1fSMasatake YAMATO 		eFree (mloc);
3379ed3202bdSMasatake YAMATO 		return mlocobj;
3380e02e1d1fSMasatake YAMATO 	}
3381ed3202bdSMasatake YAMATO 
3382ed3202bdSMasatake YAMATO 	if (group != tmp)
3383ed3202bdSMasatake YAMATO 		opt_vm_ostack_pop (vm);
3384ed3202bdSMasatake YAMATO 	opt_vm_ostack_pop (vm);
3385ed3202bdSMasatake YAMATO 	opt_vm_ostack_push (vm, mlocobj);
3386ed3202bdSMasatake YAMATO 	es_object_unref (mlocobj);
3387ed3202bdSMasatake YAMATO 	return es_false;
3388ed3202bdSMasatake YAMATO }
3389ed3202bdSMasatake YAMATO 
ldrop_get_line_from_matchloc(OptVM * vm,EsObject * name)33901481c2d1SMasatake YAMATO static EsObject* ldrop_get_line_from_matchloc (OptVM *vm, EsObject *name)
33911481c2d1SMasatake YAMATO {
33921481c2d1SMasatake YAMATO 	EsObject *mlocobj = opt_vm_ostack_top (vm);
33931481c2d1SMasatake YAMATO 	if (es_object_get_type (mlocobj) != OPT_TYPE_MATCHLOC)
33941481c2d1SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
33951481c2d1SMasatake YAMATO 
33961481c2d1SMasatake YAMATO 	matchLoc *mloc = es_pointer_get (mlocobj);
33971481c2d1SMasatake YAMATO 	EsObject *lineobj = es_integer_new (mloc->line);
33981481c2d1SMasatake YAMATO 	if (es_error_p (lineobj))
33991481c2d1SMasatake YAMATO 		return lineobj;
34001481c2d1SMasatake YAMATO 
34011481c2d1SMasatake YAMATO 	opt_vm_ostack_pop (vm);
34021481c2d1SMasatake YAMATO 	opt_vm_ostack_push (vm, lineobj);
34031481c2d1SMasatake YAMATO 	es_object_unref (lineobj);
34041481c2d1SMasatake YAMATO 	return es_false;
34051481c2d1SMasatake YAMATO }
34061481c2d1SMasatake YAMATO 
make_mloc_from_tagEntryInfo(tagEntryInfo * e)340720b300feSMasatake YAMATO static matchLoc* make_mloc_from_tagEntryInfo(tagEntryInfo *e)
340820b300feSMasatake YAMATO {
340920b300feSMasatake YAMATO 	matchLoc *mloc = xMalloc (1, matchLoc);
341020b300feSMasatake YAMATO 	mloc->delta = 0;
341120b300feSMasatake YAMATO 	mloc->line = e->lineNumber;
341220b300feSMasatake YAMATO 	mloc->pos = e->filePosition;
341320b300feSMasatake YAMATO 
341420b300feSMasatake YAMATO 	return mloc;
341520b300feSMasatake YAMATO }
341620b300feSMasatake YAMATO 
lrop_get_tag_loc(OptVM * vm,EsObject * name)341720b300feSMasatake YAMATO static EsObject* lrop_get_tag_loc (OptVM *vm, EsObject *name)
341820b300feSMasatake YAMATO {
341920b300feSMasatake YAMATO 	EsObject *nobj = opt_vm_ostack_top (vm);
342020b300feSMasatake YAMATO 
342120b300feSMasatake YAMATO 	if (es_object_get_type (nobj) != ES_TYPE_INTEGER)
342220b300feSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
342320b300feSMasatake YAMATO 
342420b300feSMasatake YAMATO 	int n = es_integer_get(nobj);
342520b300feSMasatake YAMATO 	if (! (CORK_NIL < n && n < countEntryInCorkQueue()))
342620b300feSMasatake YAMATO 			return OPT_ERR_RANGECHECK;
342720b300feSMasatake YAMATO 
342820b300feSMasatake YAMATO 	tagEntryInfo *e = getEntryInCorkQueue (n);
342920b300feSMasatake YAMATO 	if (e == NULL)
343020b300feSMasatake YAMATO 		return OPT_ERR_TYPECHECK; /* ??? */
343120b300feSMasatake YAMATO 
343220b300feSMasatake YAMATO 	matchLoc *mloc = make_mloc_from_tagEntryInfo (e);
343320b300feSMasatake YAMATO 	EsObject * mlocobj = es_pointer_new (OPT_TYPE_MATCHLOC, mloc);
343420b300feSMasatake YAMATO 	if (es_error_p (mlocobj))
343520b300feSMasatake YAMATO 	{
343620b300feSMasatake YAMATO 		eFree (mloc);
343720b300feSMasatake YAMATO 		return mlocobj;
343820b300feSMasatake YAMATO 	}
343920b300feSMasatake YAMATO 
344020b300feSMasatake YAMATO 	opt_vm_ostack_pop (vm);
344120b300feSMasatake YAMATO 	opt_vm_ostack_push (vm, mlocobj);
344220b300feSMasatake YAMATO 	es_object_unref (mlocobj);
344320b300feSMasatake YAMATO 	return es_false;
344420b300feSMasatake YAMATO }
344520b300feSMasatake YAMATO 
lrop_get_match_string_common(OptVM * vm,int i,int npop)34461908e776SMasatake YAMATO static EsObject* lrop_get_match_string_common (OptVM *vm, int i, int npop)
34472bbd136eSMasatake YAMATO {
34482bbd136eSMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
34492bbd136eSMasatake YAMATO 	scriptWindow *window = lcb->window;
345077bd99b5SMasatake YAMATO 	const char *cstr = make_match_string (window, i);
345177bd99b5SMasatake YAMATO 	if (!cstr)
34522bbd136eSMasatake YAMATO 	{
34531908e776SMasatake YAMATO 		for (; npop > 0; npop--)
34541908e776SMasatake YAMATO 			opt_vm_ostack_pop (vm);
34552bbd136eSMasatake YAMATO 		opt_vm_ostack_push (vm, es_false);
34562bbd136eSMasatake YAMATO 		return es_false;
34572bbd136eSMasatake YAMATO 	}
34582bbd136eSMasatake YAMATO 	EsObject *str = opt_string_new_from_cstr (cstr);
34592bbd136eSMasatake YAMATO 	eFree ((void *)cstr);
34602bbd136eSMasatake YAMATO 
34611908e776SMasatake YAMATO 	for (; npop > 0; npop--)
34621908e776SMasatake YAMATO 		opt_vm_ostack_pop (vm);
34631908e776SMasatake YAMATO 
34642bbd136eSMasatake YAMATO 	opt_vm_ostack_push (vm, str);
34652bbd136eSMasatake YAMATO 	es_object_unref (str);
34662bbd136eSMasatake YAMATO 	return es_false;
34672bbd136eSMasatake YAMATO }
34682bbd136eSMasatake YAMATO 
34691908e776SMasatake YAMATO /* Handles \1, \2, ... */
lrop_get_match_string_named_group(OptVM * vm,EsObject * name)34701908e776SMasatake YAMATO static EsObject* lrop_get_match_string_named_group (OptVM *vm, EsObject *name)
34711908e776SMasatake YAMATO {
34721908e776SMasatake YAMATO 	void * data = es_symbol_get_data (name);
34731908e776SMasatake YAMATO 	int i = HT_PTR_TO_INT (data);
34741908e776SMasatake YAMATO 
34751908e776SMasatake YAMATO 	return lrop_get_match_string_common (vm, i, 0);
34761908e776SMasatake YAMATO }
34771908e776SMasatake YAMATO 
lrop_get_match_string_group_on_stack(OptVM * vm,EsObject * name)3478df8d88a5SMasatake YAMATO static EsObject* lrop_get_match_string_group_on_stack (OptVM *vm, EsObject *name)
34791908e776SMasatake YAMATO {
34801908e776SMasatake YAMATO 	EsObject *group = opt_vm_ostack_top (vm);
34811908e776SMasatake YAMATO 	if (!es_integer_p (group))
34821908e776SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
34831908e776SMasatake YAMATO 
34841908e776SMasatake YAMATO 	int g = es_integer_get (group);
34851908e776SMasatake YAMATO 	if (g < 1)
34861908e776SMasatake YAMATO 		return OPT_ERR_RANGECHECK;
34871908e776SMasatake YAMATO 
34881908e776SMasatake YAMATO 	EsObject *r = lrop_get_match_string_common (vm, g, 1);
34891908e776SMasatake YAMATO 	if (es_error_p (r))
34901908e776SMasatake YAMATO 		return r;
34911908e776SMasatake YAMATO 
34921908e776SMasatake YAMATO 	r = opt_vm_ostack_top (vm);
34931908e776SMasatake YAMATO 	if (es_object_get_type (r) == OPT_TYPE_STRING)
34941908e776SMasatake YAMATO 		opt_vm_ostack_push (vm, es_true);
34951908e776SMasatake YAMATO 	return es_false;
34961908e776SMasatake YAMATO }
34971908e776SMasatake YAMATO 
make_match_string(scriptWindow * window,int group)349877bd99b5SMasatake YAMATO static char* make_match_string (scriptWindow *window, int group)
349977bd99b5SMasatake YAMATO {
350077bd99b5SMasatake YAMATO 	if (window == NULL
350177bd99b5SMasatake YAMATO 		|| 0 >= group
350277bd99b5SMasatake YAMATO 		|| window->nmatch <= group
350377bd99b5SMasatake YAMATO 		|| window->pmatch [group].rm_so == -1)
350477bd99b5SMasatake YAMATO 		return NULL;
350577bd99b5SMasatake YAMATO 
350677bd99b5SMasatake YAMATO 	const int len = window->pmatch [group].rm_eo - window->pmatch [group].rm_so;
350777bd99b5SMasatake YAMATO 	const char *start = window->line + window->pmatch [group].rm_so;
350877bd99b5SMasatake YAMATO 
350977bd99b5SMasatake YAMATO 	return eStrndup (start, len);
351077bd99b5SMasatake YAMATO }
351177bd99b5SMasatake YAMATO 
make_mloc(scriptWindow * window,int group,bool start)3512cf6b3bb9SMasatake YAMATO static matchLoc *make_mloc (scriptWindow *window, int group, bool start)
3513cf6b3bb9SMasatake YAMATO {
3514cf6b3bb9SMasatake YAMATO 	if (window == NULL
3515cf6b3bb9SMasatake YAMATO 		|| 0 > group
3516cf6b3bb9SMasatake YAMATO 		|| window->nmatch <= group
3517cf6b3bb9SMasatake YAMATO 		|| window->pmatch [group].rm_so == -1)
3518cf6b3bb9SMasatake YAMATO 		return NULL;
3519cf6b3bb9SMasatake YAMATO 
3520cf6b3bb9SMasatake YAMATO 	matchLoc *mloc = xMalloc (1, matchLoc);
3521cf6b3bb9SMasatake YAMATO 	if (window->patbuf->regptype == REG_PARSER_SINGLE_LINE)
3522cf6b3bb9SMasatake YAMATO 	{
3523cf6b3bb9SMasatake YAMATO 		mloc->delta = 0;
3524cf6b3bb9SMasatake YAMATO 		mloc->line = getInputLineNumber ();
3525cf6b3bb9SMasatake YAMATO 		mloc->pos = getInputFilePosition ();
3526cf6b3bb9SMasatake YAMATO 	}
3527cf6b3bb9SMasatake YAMATO 	else
3528cf6b3bb9SMasatake YAMATO 	{
3529cf6b3bb9SMasatake YAMATO 		mloc->delta = (start
3530cf6b3bb9SMasatake YAMATO 					   ? window->pmatch [group].rm_so
3531cf6b3bb9SMasatake YAMATO 					   : window->pmatch [group].rm_eo);
3532cf6b3bb9SMasatake YAMATO 		off_t offset = (window->line + mloc->delta) - window->start;
3533cf6b3bb9SMasatake YAMATO 		mloc->line = getInputLineNumberForFileOffset (offset);
3534cf6b3bb9SMasatake YAMATO 		mloc->pos  = getInputFilePositionForLine (mloc->line);
3535cf6b3bb9SMasatake YAMATO 	}
3536cf6b3bb9SMasatake YAMATO 	return mloc;
3537cf6b3bb9SMasatake YAMATO }
3538cf6b3bb9SMasatake YAMATO 
lrop_set_scope(OptVM * vm,EsObject * name)35397f9e4f22SMasatake YAMATO static EsObject* lrop_set_scope (OptVM *vm, EsObject *name)
35407f9e4f22SMasatake YAMATO {
35417f9e4f22SMasatake YAMATO 	EsObject *corkIndex = opt_vm_ostack_top (vm);
35427f9e4f22SMasatake YAMATO 	if (!es_integer_p (corkIndex))
35437f9e4f22SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
35447f9e4f22SMasatake YAMATO 
35457f9e4f22SMasatake YAMATO 	int n = es_integer_get (corkIndex);
35467f9e4f22SMasatake YAMATO 	if (n < 0)
35477f9e4f22SMasatake YAMATO 		return OPT_ERR_RANGECHECK;
35487f9e4f22SMasatake YAMATO 
35497f9e4f22SMasatake YAMATO 	if (n >= countEntryInCorkQueue())
35507f9e4f22SMasatake YAMATO 		return OPT_ERR_RANGECHECK;
35517f9e4f22SMasatake YAMATO 
35527f9e4f22SMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
35537f9e4f22SMasatake YAMATO 	lcb->currentScope = n;
35547f9e4f22SMasatake YAMATO 
35557f9e4f22SMasatake YAMATO 	opt_vm_ostack_pop (vm);
35567f9e4f22SMasatake YAMATO 
35577f9e4f22SMasatake YAMATO 	return es_false;
35587f9e4f22SMasatake YAMATO }
35597f9e4f22SMasatake YAMATO 
lrop_pop_scope(OptVM * vm,EsObject * name)35607f9e4f22SMasatake YAMATO static EsObject* lrop_pop_scope (OptVM *vm, EsObject *name)
35617f9e4f22SMasatake YAMATO {
35627f9e4f22SMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
35637f9e4f22SMasatake YAMATO 	if (lcb->currentScope != CORK_NIL)
35647f9e4f22SMasatake YAMATO 	{
35657f9e4f22SMasatake YAMATO 		tagEntryInfo *e = getEntryInCorkQueue (lcb->currentScope);
35667f9e4f22SMasatake YAMATO 		if (e)
35677f9e4f22SMasatake YAMATO 			lcb->currentScope = e->extensionFields.scopeIndex;
35687f9e4f22SMasatake YAMATO 	}
35697f9e4f22SMasatake YAMATO 	return es_false;
35707f9e4f22SMasatake YAMATO }
35717f9e4f22SMasatake YAMATO 
lrop_clear_scope(OptVM * vm,EsObject * name)35727f9e4f22SMasatake YAMATO static EsObject* lrop_clear_scope (OptVM *vm, EsObject *name)
35737f9e4f22SMasatake YAMATO {
35747f9e4f22SMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
35757f9e4f22SMasatake YAMATO 	lcb->currentScope = CORK_NIL;
35767f9e4f22SMasatake YAMATO 	return es_false;
35777f9e4f22SMasatake YAMATO }
35787f9e4f22SMasatake YAMATO 
lrop_ref0_scope(OptVM * vm,EsObject * name)35797f9e4f22SMasatake YAMATO static EsObject* lrop_ref0_scope (OptVM *vm, EsObject *name)
35807f9e4f22SMasatake YAMATO {
35817f9e4f22SMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
35827f9e4f22SMasatake YAMATO 
35837f9e4f22SMasatake YAMATO 	if (lcb->currentScope == 0)
35847f9e4f22SMasatake YAMATO 	{
35857f9e4f22SMasatake YAMATO 		opt_vm_ostack_push (vm, es_false);
35867f9e4f22SMasatake YAMATO 		return es_false;
35877f9e4f22SMasatake YAMATO 	}
35887f9e4f22SMasatake YAMATO 
35897f9e4f22SMasatake YAMATO 	EsObject *q = es_integer_new (lcb->currentScope);
35907f9e4f22SMasatake YAMATO 
35917f9e4f22SMasatake YAMATO 	if (es_error_p (q))
35927f9e4f22SMasatake YAMATO 		return q;
35937f9e4f22SMasatake YAMATO 
35947f9e4f22SMasatake YAMATO 	opt_vm_ostack_push (vm, q);
35957f9e4f22SMasatake YAMATO 	es_object_unref (q);
35967f9e4f22SMasatake YAMATO 	opt_vm_ostack_push (vm, es_true);
35977f9e4f22SMasatake YAMATO 	return es_false;
35987f9e4f22SMasatake YAMATO }
35997f9e4f22SMasatake YAMATO 
lrop_refN_scope(OptVM * vm,EsObject * name)36007f9e4f22SMasatake YAMATO static EsObject* lrop_refN_scope (OptVM *vm, EsObject *name)
36017f9e4f22SMasatake YAMATO {
36027f9e4f22SMasatake YAMATO 	EsObject *nobj = opt_vm_ostack_top (vm);
36037f9e4f22SMasatake YAMATO 	if (!es_integer_p (nobj))
36047f9e4f22SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
36057f9e4f22SMasatake YAMATO 
36067f9e4f22SMasatake YAMATO 	int n = es_integer_get(nobj);
36077f9e4f22SMasatake YAMATO 
36087f9e4f22SMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
36097f9e4f22SMasatake YAMATO 	int scope = lcb->currentScope;
36107f9e4f22SMasatake YAMATO 
36117f9e4f22SMasatake YAMATO 	while (n--)
36127f9e4f22SMasatake YAMATO 	{
36137f9e4f22SMasatake YAMATO 		if (scope == CORK_NIL)
36147f9e4f22SMasatake YAMATO 			break;
36157f9e4f22SMasatake YAMATO 		tagEntryInfo *e = getEntryInCorkQueue (scope);
36167f9e4f22SMasatake YAMATO 		if (e == NULL)
36177f9e4f22SMasatake YAMATO 			break;
36187f9e4f22SMasatake YAMATO 
36197f9e4f22SMasatake YAMATO 		scope = e->extensionFields.scopeIndex;
36207f9e4f22SMasatake YAMATO 	}
36217f9e4f22SMasatake YAMATO 
36227f9e4f22SMasatake YAMATO 	EsObject *q = es_integer_new (scope);
36237f9e4f22SMasatake YAMATO 	if (es_error_p(q))
36247f9e4f22SMasatake YAMATO 		return q;
36257f9e4f22SMasatake YAMATO 
36267f9e4f22SMasatake YAMATO 	opt_vm_ostack_pop (vm);
36277f9e4f22SMasatake YAMATO 	opt_vm_ostack_push (vm, q);
36287f9e4f22SMasatake YAMATO 	es_object_unref (q);
36297f9e4f22SMasatake YAMATO 
36307f9e4f22SMasatake YAMATO 	return es_false;
36317f9e4f22SMasatake YAMATO }
36327f9e4f22SMasatake YAMATO 
lrop_get_scope_depth(OptVM * vm,EsObject * name)36337f9e4f22SMasatake YAMATO static EsObject* lrop_get_scope_depth (OptVM *vm, EsObject *name)
36347f9e4f22SMasatake YAMATO {
36357f9e4f22SMasatake YAMATO 	int n = 0;
36367f9e4f22SMasatake YAMATO 
36377f9e4f22SMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
36387f9e4f22SMasatake YAMATO 	int scope = lcb->currentScope;
36397f9e4f22SMasatake YAMATO 
36407f9e4f22SMasatake YAMATO 	while (scope != CORK_NIL)
36417f9e4f22SMasatake YAMATO 	{
36427f9e4f22SMasatake YAMATO 		tagEntryInfo *e = getEntryInCorkQueue (scope);
36437f9e4f22SMasatake YAMATO 		if (!e)
36447f9e4f22SMasatake YAMATO 			break;
36457f9e4f22SMasatake YAMATO 
36467f9e4f22SMasatake YAMATO 		scope = e->extensionFields.scopeIndex;
36477f9e4f22SMasatake YAMATO 		n++;
36487f9e4f22SMasatake YAMATO 	}
36497f9e4f22SMasatake YAMATO 
36507f9e4f22SMasatake YAMATO 	EsObject *q = es_integer_new (scope);
36517f9e4f22SMasatake YAMATO 	if (es_error_p(q))
36527f9e4f22SMasatake YAMATO 		return q;
36537f9e4f22SMasatake YAMATO 
36547f9e4f22SMasatake YAMATO 	opt_vm_ostack_push (vm, q);
36557f9e4f22SMasatake YAMATO 	es_object_unref (q);
36567f9e4f22SMasatake YAMATO 	return es_false;
36577f9e4f22SMasatake YAMATO }
36587f9e4f22SMasatake YAMATO 
lrop_repl(OptVM * vm,EsObject * name)365954bd7b53SMasatake YAMATO static EsObject* lrop_repl (OptVM *vm, EsObject *name)
366054bd7b53SMasatake YAMATO {
366154bd7b53SMasatake YAMATO 	char *old_prompt = opt_vm_set_prompt (vm, "\n% type \"quit\" for exiting from repl\nOPT");
366254bd7b53SMasatake YAMATO 
366354bd7b53SMasatake YAMATO 	opt_vm_print_prompt (vm);
366454bd7b53SMasatake YAMATO 	opt_vm_set_prompt (vm, "OPT");
366554bd7b53SMasatake YAMATO 
366654bd7b53SMasatake YAMATO 	while (true)
366754bd7b53SMasatake YAMATO 	{
366854bd7b53SMasatake YAMATO 		EsObject *o = opt_vm_read (vm, NULL);
366954bd7b53SMasatake YAMATO 		if (es_object_equal (o, ES_READER_EOF))
367054bd7b53SMasatake YAMATO 		{
367154bd7b53SMasatake YAMATO 			es_object_unref (o);
367254bd7b53SMasatake YAMATO 			break;
367354bd7b53SMasatake YAMATO 		}
367454bd7b53SMasatake YAMATO 		EsObject *e = opt_vm_eval (vm, o);
367554bd7b53SMasatake YAMATO 		es_object_unref (o);
367654bd7b53SMasatake YAMATO 
367754bd7b53SMasatake YAMATO 		if (es_error_p (e))
367854bd7b53SMasatake YAMATO 		{
367954bd7b53SMasatake YAMATO 			if (!es_object_equal (e, OPT_ERR_QUIT))
368054bd7b53SMasatake YAMATO 				opt_vm_report_error (vm, e, NULL);
368154bd7b53SMasatake YAMATO 			break;
368254bd7b53SMasatake YAMATO 		}
368354bd7b53SMasatake YAMATO 	}
368454bd7b53SMasatake YAMATO 
368554bd7b53SMasatake YAMATO 	opt_vm_set_prompt (vm, old_prompt);
368654bd7b53SMasatake YAMATO 	return es_false;
368754bd7b53SMasatake YAMATO }
368854bd7b53SMasatake YAMATO 
36892b8d4c66SMasatake YAMATO static EsObject *OPTSCRIPT_ERR_UNKNOWNTABLE;
36902b8d4c66SMasatake YAMATO static EsObject *OPTSCRIPT_ERR_NOTMTABLEPTRN;
36912b8d4c66SMasatake YAMATO 
getRegexTableForOptscriptName(struct lregexControlBlock * lcb,EsObject * tableName)36922b8d4c66SMasatake YAMATO static struct regexTable *getRegexTableForOptscriptName (struct lregexControlBlock *lcb,
36932b8d4c66SMasatake YAMATO 														 EsObject *tableName)
36942b8d4c66SMasatake YAMATO {
36952b8d4c66SMasatake YAMATO 	EsObject *table_sym = es_pointer_get (tableName);
36962b8d4c66SMasatake YAMATO 	const char *table_str = es_symbol_get (table_sym);
36972b8d4c66SMasatake YAMATO 	int n = getTableIndexForName (lcb, table_str);
36982b8d4c66SMasatake YAMATO 	if (n < 0)
36992b8d4c66SMasatake YAMATO 		return NULL;
37002b8d4c66SMasatake YAMATO 	return ptrArrayItem (lcb->tables, n);
37012b8d4c66SMasatake YAMATO }
37022b8d4c66SMasatake YAMATO 
lrop_tenter_common(OptVM * vm,EsObject * name,enum tableAction action)37032b8d4c66SMasatake YAMATO static EsObject* lrop_tenter_common (OptVM *vm, EsObject *name, enum tableAction action)
37042b8d4c66SMasatake YAMATO {
37052b8d4c66SMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
37062b8d4c66SMasatake YAMATO 	if (lcb->window->patbuf->regptype != REG_PARSER_MULTI_TABLE)
37072b8d4c66SMasatake YAMATO 	{
37082b8d4c66SMasatake YAMATO 		error (WARNING, "Use table related operators only with mtable regular expression");
37092b8d4c66SMasatake YAMATO 		return OPTSCRIPT_ERR_NOTMTABLEPTRN;
37102b8d4c66SMasatake YAMATO 	}
37112b8d4c66SMasatake YAMATO 
37122b8d4c66SMasatake YAMATO 	EsObject *table = opt_vm_ostack_top (vm);
37132b8d4c66SMasatake YAMATO 	if (es_object_get_type (table) != OPT_TYPE_NAME)
37142b8d4c66SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
37152b8d4c66SMasatake YAMATO 
37162b8d4c66SMasatake YAMATO 	struct regexTable *t = getRegexTableForOptscriptName (lcb, table);
37172b8d4c66SMasatake YAMATO 	if (t == NULL)
37182b8d4c66SMasatake YAMATO 		return OPTSCRIPT_ERR_UNKNOWNTABLE;
37192b8d4c66SMasatake YAMATO 
37202b8d4c66SMasatake YAMATO 	lcb->window->taction = (struct mTableActionSpec){
37212b8d4c66SMasatake YAMATO 		.action             = action,
37222b8d4c66SMasatake YAMATO 		.table              = t,
37232b8d4c66SMasatake YAMATO 		.continuation_table = NULL,
37242b8d4c66SMasatake YAMATO 	};
37252b8d4c66SMasatake YAMATO 
37262b8d4c66SMasatake YAMATO 	opt_vm_ostack_pop (vm);
37272b8d4c66SMasatake YAMATO 	return es_false;
37282b8d4c66SMasatake YAMATO }
37292b8d4c66SMasatake YAMATO 
lrop_tenter(OptVM * vm,EsObject * name)37302b8d4c66SMasatake YAMATO static EsObject* lrop_tenter (OptVM *vm, EsObject *name)
37312b8d4c66SMasatake YAMATO {
37322b8d4c66SMasatake YAMATO 	return lrop_tenter_common (vm, name, TACTION_ENTER);
37332b8d4c66SMasatake YAMATO }
37342b8d4c66SMasatake YAMATO 
lrop_tenter_with_continuation(OptVM * vm,EsObject * name)37352b8d4c66SMasatake YAMATO static EsObject* lrop_tenter_with_continuation (OptVM *vm, EsObject *name)
37362b8d4c66SMasatake YAMATO {
37372b8d4c66SMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
37382b8d4c66SMasatake YAMATO 	if (lcb->window->patbuf->regptype != REG_PARSER_MULTI_TABLE)
37392b8d4c66SMasatake YAMATO 	{
37402b8d4c66SMasatake YAMATO 		error (WARNING, "Use table related operators only with mtable regular expression");
37412b8d4c66SMasatake YAMATO 		return OPTSCRIPT_ERR_NOTMTABLEPTRN;
37422b8d4c66SMasatake YAMATO 	}
37432b8d4c66SMasatake YAMATO 
37442b8d4c66SMasatake YAMATO 	EsObject *cont = opt_vm_ostack_top (vm);
37452b8d4c66SMasatake YAMATO 	EsObject *table = opt_vm_ostack_peek (vm, 1);
37462b8d4c66SMasatake YAMATO 
37472b8d4c66SMasatake YAMATO 	if (es_object_get_type (table) != OPT_TYPE_NAME)
37482b8d4c66SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
37492b8d4c66SMasatake YAMATO 	if (es_object_get_type (cont) != OPT_TYPE_NAME)
37502b8d4c66SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
37512b8d4c66SMasatake YAMATO 
37522b8d4c66SMasatake YAMATO 	struct regexTable *t = getRegexTableForOptscriptName (lcb, table);
37532b8d4c66SMasatake YAMATO 	if (t == NULL)
37542b8d4c66SMasatake YAMATO 		return OPTSCRIPT_ERR_UNKNOWNTABLE;
37552b8d4c66SMasatake YAMATO 	struct regexTable *c = getRegexTableForOptscriptName (lcb, cont);
37562b8d4c66SMasatake YAMATO 	if (c == NULL)
37572b8d4c66SMasatake YAMATO 		return OPTSCRIPT_ERR_UNKNOWNTABLE;
37582b8d4c66SMasatake YAMATO 
37592b8d4c66SMasatake YAMATO 	lcb->window->taction = (struct mTableActionSpec){
37602b8d4c66SMasatake YAMATO 		.action             = TACTION_ENTER,
37612b8d4c66SMasatake YAMATO 		.table              = t,
37622b8d4c66SMasatake YAMATO 		.continuation_table = c,
37632b8d4c66SMasatake YAMATO 	};
37642b8d4c66SMasatake YAMATO 
37652b8d4c66SMasatake YAMATO 	opt_vm_ostack_pop (vm);
37662b8d4c66SMasatake YAMATO 	opt_vm_ostack_pop (vm);
37672b8d4c66SMasatake YAMATO 	return es_false;
37682b8d4c66SMasatake YAMATO }
37692b8d4c66SMasatake YAMATO 
lrop_tleave(OptVM * vm,EsObject * name)37702b8d4c66SMasatake YAMATO static EsObject* lrop_tleave (OptVM *vm, EsObject *name)
37712b8d4c66SMasatake YAMATO {
37722b8d4c66SMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
37732b8d4c66SMasatake YAMATO 	if (lcb->window->patbuf->regptype != REG_PARSER_MULTI_TABLE)
37742b8d4c66SMasatake YAMATO 	{
37752b8d4c66SMasatake YAMATO 		error (WARNING, "Use table related operators only with mtable regular expression");
37762b8d4c66SMasatake YAMATO 		return OPTSCRIPT_ERR_NOTMTABLEPTRN;
37772b8d4c66SMasatake YAMATO 	}
37782b8d4c66SMasatake YAMATO 
37792b8d4c66SMasatake YAMATO 	lcb->window->taction.action = TACTION_LEAVE;
37802b8d4c66SMasatake YAMATO 	return es_false;
37812b8d4c66SMasatake YAMATO }
37822b8d4c66SMasatake YAMATO 
lrop_tjump(OptVM * vm,EsObject * name)37832b8d4c66SMasatake YAMATO static EsObject* lrop_tjump (OptVM *vm, EsObject *name)
37842b8d4c66SMasatake YAMATO {
37852b8d4c66SMasatake YAMATO 	return lrop_tenter_common (vm, name, TACTION_JUMP);
37862b8d4c66SMasatake YAMATO }
37872b8d4c66SMasatake YAMATO 
lrop_treset(OptVM * vm,EsObject * name)37882b8d4c66SMasatake YAMATO static EsObject* lrop_treset (OptVM *vm, EsObject *name)
37892b8d4c66SMasatake YAMATO {
37902b8d4c66SMasatake YAMATO 	return lrop_tenter_common (vm, name, TACTION_RESET);
37912b8d4c66SMasatake YAMATO }
37922b8d4c66SMasatake YAMATO 
lrop_tquit(OptVM * vm,EsObject * name)37932b8d4c66SMasatake YAMATO static EsObject* lrop_tquit (OptVM *vm, EsObject *name)
37942b8d4c66SMasatake YAMATO {
37952b8d4c66SMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
37962b8d4c66SMasatake YAMATO 	if (lcb->window->patbuf->regptype != REG_PARSER_MULTI_TABLE)
37972b8d4c66SMasatake YAMATO 	{
37982b8d4c66SMasatake YAMATO 		error (WARNING, "Use table related operators only with mtable regular expression");
37992b8d4c66SMasatake YAMATO 		return OPTSCRIPT_ERR_NOTMTABLEPTRN;
38002b8d4c66SMasatake YAMATO 	}
38012b8d4c66SMasatake YAMATO 
38022b8d4c66SMasatake YAMATO 	lcb->window->taction.action = TACTION_QUIT;
38032b8d4c66SMasatake YAMATO 	return es_false;
38042b8d4c66SMasatake YAMATO }
38052b8d4c66SMasatake YAMATO 
lrop_traced(OptVM * vm,EsObject * name)380685021c5bSMasatake YAMATO static EsObject* lrop_traced (OptVM *vm, EsObject *name)
380785021c5bSMasatake YAMATO {
380885021c5bSMasatake YAMATO #ifdef DO_TRACING
380985021c5bSMasatake YAMATO 	langType lang = getInputLanguage ();
381085021c5bSMasatake YAMATO 	if (isLanguageTraced (lang))
381185021c5bSMasatake YAMATO 		opt_vm_ostack_push (vm, es_true);
381285021c5bSMasatake YAMATO 	else
381385021c5bSMasatake YAMATO 		opt_vm_ostack_push (vm, es_false);
381485021c5bSMasatake YAMATO #else
381585021c5bSMasatake YAMATO 	opt_vm_ostack_push (vm, es_false);
381685021c5bSMasatake YAMATO #endif
381785021c5bSMasatake YAMATO 	return false;
381885021c5bSMasatake YAMATO }
381985021c5bSMasatake YAMATO 
38208cfef1a8SMasatake YAMATO EsObject *OPTSCRIPT_ERR_UNKNOWNEXTRA;
lrop_extraenabled(OptVM * vm,EsObject * name)38218cfef1a8SMasatake YAMATO static EsObject* lrop_extraenabled (OptVM *vm, EsObject *name)
38228cfef1a8SMasatake YAMATO {
38238cfef1a8SMasatake YAMATO 	EsObject *extra = opt_vm_ostack_top (vm);
38248cfef1a8SMasatake YAMATO 	if (es_object_get_type (extra) != OPT_TYPE_NAME)
38258cfef1a8SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
38268cfef1a8SMasatake YAMATO 
38278cfef1a8SMasatake YAMATO 	xtagType xt = optscriptGetXtagType (extra);
38288cfef1a8SMasatake YAMATO 	if (xt == XTAG_UNKNOWN)
38298cfef1a8SMasatake YAMATO 		return OPTSCRIPT_ERR_UNKNOWNEXTRA;
38308cfef1a8SMasatake YAMATO 
38318cfef1a8SMasatake YAMATO 	EsObject *r = isXtagEnabled (xt)? es_true: es_false;
38328cfef1a8SMasatake YAMATO 	opt_vm_ostack_pop (vm);
38338cfef1a8SMasatake YAMATO 	opt_vm_ostack_push (vm, r);
38348cfef1a8SMasatake YAMATO 	return es_false;
38358cfef1a8SMasatake YAMATO }
38368cfef1a8SMasatake YAMATO 
lrop_markextra(OptVM * vm,EsObject * name)3837ecfb2683SMasatake YAMATO static EsObject *lrop_markextra (OptVM *vm, EsObject *name)
3838ecfb2683SMasatake YAMATO {
3839ecfb2683SMasatake YAMATO 	EsObject *tag = opt_vm_ostack_peek (vm, 1);
3840ecfb2683SMasatake YAMATO 	tagEntryInfo *e;
3841ecfb2683SMasatake YAMATO 	if (es_integer_p (tag))
3842ecfb2683SMasatake YAMATO 	{
3843ecfb2683SMasatake YAMATO 		int n = es_integer_get (tag);
3844ecfb2683SMasatake YAMATO 		if (! (CORK_NIL < n && n < countEntryInCorkQueue()))
3845ecfb2683SMasatake YAMATO 			return OPT_ERR_RANGECHECK;
3846ecfb2683SMasatake YAMATO 		e = getEntryInCorkQueue (n);
3847ecfb2683SMasatake YAMATO 	}
3848ecfb2683SMasatake YAMATO 	else if (es_object_get_type (tag) == OPT_TYPE_TAG)
3849ecfb2683SMasatake YAMATO 		e = es_pointer_get (tag);
3850ecfb2683SMasatake YAMATO 	else
3851ecfb2683SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3852ecfb2683SMasatake YAMATO 
3853ecfb2683SMasatake YAMATO 	if (e == NULL)
3854ecfb2683SMasatake YAMATO 		return OPTSCRIPT_ERR_NOTAGENTRY;
3855ecfb2683SMasatake YAMATO 
3856ecfb2683SMasatake YAMATO 	EsObject *extra = opt_vm_ostack_top (vm);
3857ecfb2683SMasatake YAMATO 	if (es_object_get_type (extra) != OPT_TYPE_NAME)
3858ecfb2683SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3859ecfb2683SMasatake YAMATO 
3860ecfb2683SMasatake YAMATO 	xtagType xt = optscriptGetXtagType (extra);
3861ecfb2683SMasatake YAMATO 	if (xt == XTAG_UNKNOWN)
3862ecfb2683SMasatake YAMATO 		return OPTSCRIPT_ERR_UNKNOWNEXTRA;
3863ecfb2683SMasatake YAMATO 
3864ecfb2683SMasatake YAMATO 	langType lang = getXtagOwner (xt);
3865ecfb2683SMasatake YAMATO 	if (lang != LANG_IGNORE && e->langType != lang)
3866ecfb2683SMasatake YAMATO 	{
3867ecfb2683SMasatake YAMATO 		error (WARNING,
3868ecfb2683SMasatake YAMATO 			   "mismatch in the language of the tag (%s) and the language of field (%s)",
3869ecfb2683SMasatake YAMATO 			   getLanguageName (e->langType), getLanguageName (lang));
3870ecfb2683SMasatake YAMATO 		return OPTSCRIPT_ERR_UNKNOWNEXTRA;
3871ecfb2683SMasatake YAMATO 	}
3872ecfb2683SMasatake YAMATO 
3873ecfb2683SMasatake YAMATO 	markTagExtraBit (e, xt);
3874ecfb2683SMasatake YAMATO 
3875ecfb2683SMasatake YAMATO 	opt_vm_ostack_pop (vm);
3876ecfb2683SMasatake YAMATO 	opt_vm_ostack_pop (vm);
3877ecfb2683SMasatake YAMATO 
3878ecfb2683SMasatake YAMATO 	return es_false;
3879ecfb2683SMasatake YAMATO }
3880ecfb2683SMasatake YAMATO 
lrop_advanceto(OptVM * vm,EsObject * name)3881653692b7SMasatake YAMATO static EsObject *lrop_advanceto (OptVM *vm, EsObject *name)
3882653692b7SMasatake YAMATO {
3883653692b7SMasatake YAMATO 	struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
3884653692b7SMasatake YAMATO 	if (lcb->window->patbuf->regptype == REG_PARSER_SINGLE_LINE)
3885820e8cc6SMasatake YAMATO 	{
3886820e8cc6SMasatake YAMATO 		error (WARNING, "don't use `%s' operator in --regex-<LANG> option",
3887820e8cc6SMasatake YAMATO 			   es_symbol_get (name));
3888820e8cc6SMasatake YAMATO 		return OPTSCRIPT_ERR_NOTMTABLEPTRN; /* TODO */
3889820e8cc6SMasatake YAMATO 	}
3890653692b7SMasatake YAMATO 
3891653692b7SMasatake YAMATO 	EsObject *mlocobj = opt_vm_ostack_top (vm);
3892653692b7SMasatake YAMATO 	if (es_object_get_type (mlocobj) != OPT_TYPE_MATCHLOC)
3893653692b7SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3894653692b7SMasatake YAMATO 
3895653692b7SMasatake YAMATO 	matchLoc *loc = es_pointer_get (mlocobj);
3896653692b7SMasatake YAMATO 	lcb->window->advanceto = true;
3897653692b7SMasatake YAMATO 	lcb->window->advanceto_delta = loc->delta;
3898653692b7SMasatake YAMATO 
3899653692b7SMasatake YAMATO 	return es_true;
3900653692b7SMasatake YAMATO }
3901653692b7SMasatake YAMATO 
lrop_markplaceholder(OptVM * vm,EsObject * name)3902d0d07afbSMasatake YAMATO static EsObject *lrop_markplaceholder (OptVM *vm, EsObject *name)
3903d0d07afbSMasatake YAMATO {
3904d0d07afbSMasatake YAMATO 	EsObject *tag = opt_vm_ostack_top (vm);
3905d0d07afbSMasatake YAMATO 
3906d0d07afbSMasatake YAMATO 	if (!es_integer_p (tag))
3907d0d07afbSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3908d0d07afbSMasatake YAMATO 
3909d0d07afbSMasatake YAMATO 	int n = es_integer_get (tag);
3910d0d07afbSMasatake YAMATO 	if (! (CORK_NIL < n && n < countEntryInCorkQueue()))
3911d0d07afbSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
3912d0d07afbSMasatake YAMATO 
3913d0d07afbSMasatake YAMATO 	tagEntryInfo *e = getEntryInCorkQueue (n);
3914d0d07afbSMasatake YAMATO 	if (e == NULL)
3915d0d07afbSMasatake YAMATO 		return OPTSCRIPT_ERR_NOTAGENTRY;
3916d0d07afbSMasatake YAMATO 
3917d0d07afbSMasatake YAMATO 	markTagPlaceholder (e, true);
3918d0d07afbSMasatake YAMATO 
3919d0d07afbSMasatake YAMATO 	opt_vm_ostack_pop (vm);
3920d0d07afbSMasatake YAMATO 	return es_false;
3921d0d07afbSMasatake YAMATO }
3922d0d07afbSMasatake YAMATO 
3923f13d16e1SMasatake YAMATO static struct optscriptOperatorRegistration lropOperators [] = {
3924f13d16e1SMasatake YAMATO 	{
39251908e776SMasatake YAMATO 		.name     = "_matchstr",
3926df8d88a5SMasatake YAMATO 		.fn       = lrop_get_match_string_group_on_stack,
39271908e776SMasatake YAMATO 		.arity    = 1,
39281908e776SMasatake YAMATO 		.help_str = "group:int _MATCHSTR string true%"
39291908e776SMasatake YAMATO 		"group:int _MATCHSTR false",
39301908e776SMasatake YAMATO 	},
39311908e776SMasatake YAMATO 	{
3932f13d16e1SMasatake YAMATO 		.name     = "_matchloc",
3933f13d16e1SMasatake YAMATO 		.fn       = lrop_get_match_loc,
3934f13d16e1SMasatake YAMATO 		.arity    = -1,
3935f13d16e1SMasatake YAMATO 		.help_str = "group:int /start|/end _MATCHLOC matchloc%"
3936f13d16e1SMasatake YAMATO 		"group:int _MATCHLOC matchloc",
3937f13d16e1SMasatake YAMATO 	},
3938f13d16e1SMasatake YAMATO 	{
39391481c2d1SMasatake YAMATO 		.name     = "_matchloc2line",
39401481c2d1SMasatake YAMATO 		.fn       = ldrop_get_line_from_matchloc,
39411481c2d1SMasatake YAMATO 		.arity    = 1,
39421481c2d1SMasatake YAMATO 		.help_str = "matchloc _MATCHLOC2LINE int:line",
39431481c2d1SMasatake YAMATO 	},
39441481c2d1SMasatake YAMATO 	{
394520b300feSMasatake YAMATO 		.name     = "_tagloc",
394620b300feSMasatake YAMATO 		.fn       = lrop_get_tag_loc,
394720b300feSMasatake YAMATO 		.arity    = 1,
394820b300feSMasatake YAMATO 		.help_str = "index:int _TAGLOC matchloc",
394920b300feSMasatake YAMATO 	},
395020b300feSMasatake YAMATO 	{
3951f13d16e1SMasatake YAMATO 		.name     = "_tag",
3952f13d16e1SMasatake YAMATO 		.fn       = lrop_make_tag,
3953f13d16e1SMasatake YAMATO 		.arity    = -1,
3954f13d16e1SMasatake YAMATO 		.help_str = "name:str kind:name matchloc _TAG tag%"
3955f13d16e1SMasatake YAMATO 		"name:str kind:name _TAG tag",
3956f13d16e1SMasatake YAMATO 	},
3957f13d16e1SMasatake YAMATO 	{
39587b347e74SMasatake YAMATO 		.name     = "_reftag",
39597b347e74SMasatake YAMATO 		.fn       = lrop_make_reftag,
39607b347e74SMasatake YAMATO 		.arity    = -1,
39617b347e74SMasatake YAMATO 		.help_str = "name:str kind:name role:name matchloc _REFTAG tag%"
39627b347e74SMasatake YAMATO 		"name:str kind:name role:name _REFTAG tag%",
39637b347e74SMasatake YAMATO 	},
39647b347e74SMasatake YAMATO 	{
3965f13d16e1SMasatake YAMATO 		.name     = "_commit",
3966f13d16e1SMasatake YAMATO 		.fn       = lrop_commit_tag,
3967f13d16e1SMasatake YAMATO 		.arity    = 1,
3968f13d16e1SMasatake YAMATO 		.help_str = "tag _COMMIT int",
3969f13d16e1SMasatake YAMATO 	},
39707f9e4f22SMasatake YAMATO 	{
39717f9e4f22SMasatake YAMATO 		.name     = "_scopeset",
39727f9e4f22SMasatake YAMATO 		.fn       = lrop_set_scope,
39737f9e4f22SMasatake YAMATO 		.arity    = 1,
39747f9e4f22SMasatake YAMATO 		.help_str = "int _SCOPESET -",
39757f9e4f22SMasatake YAMATO 	},
39767f9e4f22SMasatake YAMATO 	{
39777f9e4f22SMasatake YAMATO 		.name     = "_scopepop",
39787f9e4f22SMasatake YAMATO 		.fn       = lrop_pop_scope,
39797f9e4f22SMasatake YAMATO 		.arity    = 0,
39807f9e4f22SMasatake YAMATO 		.help_str = "- _SCOPEPOP -",
39817f9e4f22SMasatake YAMATO 	},
39827f9e4f22SMasatake YAMATO 	{
39837f9e4f22SMasatake YAMATO 		.name     = "_scopeclear",
39847f9e4f22SMasatake YAMATO 		.fn       = lrop_clear_scope,
39857f9e4f22SMasatake YAMATO 		.arity    = 0,
39867f9e4f22SMasatake YAMATO 		.help_str = "- _SCOPECLEAR -",
39877f9e4f22SMasatake YAMATO 	},
39887f9e4f22SMasatake YAMATO 	{
39897f9e4f22SMasatake YAMATO 		.name     = "_scopetop",
39907f9e4f22SMasatake YAMATO 		.fn       = lrop_ref0_scope,
39917f9e4f22SMasatake YAMATO 		.arity    = 0,
39927f9e4f22SMasatake YAMATO 		.help_str = "- _SCOPETOP int true%"
39937f9e4f22SMasatake YAMATO 		"- _SCOPETOP false",
39947f9e4f22SMasatake YAMATO 	},
39957f9e4f22SMasatake YAMATO 	{
39967f9e4f22SMasatake YAMATO 		.name     = "_scopeNth",
39977f9e4f22SMasatake YAMATO 		.fn       = lrop_refN_scope,
39987f9e4f22SMasatake YAMATO 		.arity    = 1,
39997f9e4f22SMasatake YAMATO 		.help_str = "index:int _SCOPENTH int",
40007f9e4f22SMasatake YAMATO 	},
40017f9e4f22SMasatake YAMATO 	{
40027f9e4f22SMasatake YAMATO 		.name     = "_scopedepth",
40037f9e4f22SMasatake YAMATO 		.fn       = lrop_get_scope_depth,
40047f9e4f22SMasatake YAMATO 		.arity    = 0,
40057f9e4f22SMasatake YAMATO 		.help_str = "- _SCOPEDEPTH int",
40067f9e4f22SMasatake YAMATO 	},
400754bd7b53SMasatake YAMATO 	{
400854bd7b53SMasatake YAMATO 		.name     = "_repl",
400954bd7b53SMasatake YAMATO 		.fn       = lrop_repl,
401054bd7b53SMasatake YAMATO 		.arity    = 0,
401154bd7b53SMasatake YAMATO 		.help_str = "- _repl -",
40122b8d4c66SMasatake YAMATO 	},
40132b8d4c66SMasatake YAMATO 	{
40142b8d4c66SMasatake YAMATO 		.name     = "_tenter",
40152b8d4c66SMasatake YAMATO 		.fn       = lrop_tenter,
40162b8d4c66SMasatake YAMATO 		.arity    = 1,
40172b8d4c66SMasatake YAMATO 		.help_str = "table:name _TENTER -",
40182b8d4c66SMasatake YAMATO 	},
40192b8d4c66SMasatake YAMATO 	{
40202b8d4c66SMasatake YAMATO 		.name     = "_tentercont",
40212b8d4c66SMasatake YAMATO 		.fn       = lrop_tenter_with_continuation,
40222b8d4c66SMasatake YAMATO 		.arity    = 2,
40232b8d4c66SMasatake YAMATO 		.help_str = "table:name cont:name _TENTERCONT -",
40242b8d4c66SMasatake YAMATO 	},
40252b8d4c66SMasatake YAMATO 	{
40262b8d4c66SMasatake YAMATO 		.name     = "_tleave",
40272b8d4c66SMasatake YAMATO 		.fn       = lrop_tleave,
40282b8d4c66SMasatake YAMATO 		.arity    = 0,
40292b8d4c66SMasatake YAMATO 		.help_str = "- _TLEAVE -",
40302b8d4c66SMasatake YAMATO 	},
40312b8d4c66SMasatake YAMATO 	{
40322b8d4c66SMasatake YAMATO 		.name     = "_tjump",
40332b8d4c66SMasatake YAMATO 		.fn       = lrop_tjump,
40342b8d4c66SMasatake YAMATO 		.arity    = 1,
40352b8d4c66SMasatake YAMATO 		.help_str = "table:name _TJUMP -",
40362b8d4c66SMasatake YAMATO 	},
40372b8d4c66SMasatake YAMATO 	{
40382b8d4c66SMasatake YAMATO 		.name     = "_treset",
40392b8d4c66SMasatake YAMATO 		.fn       = lrop_treset,
40402b8d4c66SMasatake YAMATO 		.arity    = 1,
40412b8d4c66SMasatake YAMATO 		.help_str = "table:name _TRESET -",
40422b8d4c66SMasatake YAMATO 	},
40432b8d4c66SMasatake YAMATO 	{
40442b8d4c66SMasatake YAMATO 		.name     = "_tquit",
40452b8d4c66SMasatake YAMATO 		.fn       = lrop_tquit,
40462b8d4c66SMasatake YAMATO 		.arity    = 0,
40472b8d4c66SMasatake YAMATO 		.help_str = "- _TQUIT -",
40482b8d4c66SMasatake YAMATO 	},
40498cfef1a8SMasatake YAMATO 	{
40508cfef1a8SMasatake YAMATO 		.name     = "_extraenabled",
40518cfef1a8SMasatake YAMATO 		.fn       = lrop_extraenabled,
40528cfef1a8SMasatake YAMATO 		.arity    = 1,
40538cfef1a8SMasatake YAMATO 		.help_str = "extra:name _extraenabled bool%"
40548cfef1a8SMasatake YAMATO 		"language.extra _extraenabled bool",
40558cfef1a8SMasatake YAMATO 	},
4056ecfb2683SMasatake YAMATO 	{
4057ecfb2683SMasatake YAMATO 		.name     = "_markextra",
4058ecfb2683SMasatake YAMATO 		.fn       = lrop_markextra,
4059ecfb2683SMasatake YAMATO 		.arity    = 2,
4060ecfb2683SMasatake YAMATO 		.help_str = "tag:int|tag:tag extra:name _MARKEXTRA -%"
4061ecfb2683SMasatake YAMATO 		"tag:int|tag:tag lang.extra:name _MARKEXTRA -",
4062653692b7SMasatake YAMATO 	},
4063653692b7SMasatake YAMATO 	{
4064653692b7SMasatake YAMATO 		.name     = "_advanceto",
4065653692b7SMasatake YAMATO 		.fn       = lrop_advanceto,
4066653692b7SMasatake YAMATO 		.arity    = 1,
40679de3d788SMasatake YAMATO 		.help_str = "matchloc _ADVANCETO -%"
4068653692b7SMasatake YAMATO 	},
406985021c5bSMasatake YAMATO 	{
407085021c5bSMasatake YAMATO 		.name     = "_traced",
407185021c5bSMasatake YAMATO 		.fn       = lrop_traced,
407285021c5bSMasatake YAMATO 		.arity    = 0,
407385021c5bSMasatake YAMATO 		.help_str = "- _TRACED true|false",
407485021c5bSMasatake YAMATO 	},
4075d0d07afbSMasatake YAMATO 	{
4076d0d07afbSMasatake YAMATO 		.name     = "_markplaceholder",
4077d0d07afbSMasatake YAMATO 		.fn       = lrop_markplaceholder,
4078d0d07afbSMasatake YAMATO 		.arity    = 1,
4079d0d07afbSMasatake YAMATO 		.help_str = "tag:int _MARKPLACEHOLDER -",
4080d0d07afbSMasatake YAMATO 	}
4081f13d16e1SMasatake YAMATO };
4082f13d16e1SMasatake YAMATO 
initRegexOptscript(void)4083965b7025SMasatake YAMATO extern void initRegexOptscript (void)
4084965b7025SMasatake YAMATO {
4085965b7025SMasatake YAMATO 	if (!regexAvailable)
4086965b7025SMasatake YAMATO 		return;
4087965b7025SMasatake YAMATO 
4088965b7025SMasatake YAMATO 	if (optvm)
4089965b7025SMasatake YAMATO 		return;
4090965b7025SMasatake YAMATO 
4091965b7025SMasatake YAMATO 	optvm = optscriptInit ();
4092965b7025SMasatake YAMATO 	lregex_dict = opt_dict_new (17);
409334deb294SMasatake YAMATO 
40942b8d4c66SMasatake YAMATO 	OPTSCRIPT_ERR_UNKNOWNTABLE = es_error_intern ("unknowntable");
40952b8d4c66SMasatake YAMATO 	OPTSCRIPT_ERR_NOTMTABLEPTRN = es_error_intern ("notmtableptrn");
40968cfef1a8SMasatake YAMATO 	OPTSCRIPT_ERR_UNKNOWNEXTRA = es_error_intern ("unknownextra");
40978cfef1a8SMasatake YAMATO 	OPTSCRIPT_ERR_UNKNOWNLANGUAGE = es_error_intern ("unknownlanguage");
409834deb294SMasatake YAMATO 	OPTSCRIPT_ERR_UNKNOWNKIND = es_error_intern ("unknownkind");
40997b347e74SMasatake YAMATO 	OPTSCRIPT_ERR_UNKNOWNROLE = es_error_intern ("unknownrole");
410034deb294SMasatake YAMATO 
41011908e776SMasatake YAMATO 	optscriptInstallProcs (lregex_dict, lrop_get_match_string_named_group);
4102ed3202bdSMasatake YAMATO 
4103f13d16e1SMasatake YAMATO 	optscriptRegisterOperators (lregex_dict,
4104f13d16e1SMasatake YAMATO 								lropOperators, ARRAY_SIZE(lropOperators));
4105431a587eSMasatake YAMATO 
4106431a587eSMasatake YAMATO 	extern const char ctagsCommonPrelude[];
4107431a587eSMasatake YAMATO 	opt_vm_dstack_push (optvm, lregex_dict);
4108431a587eSMasatake YAMATO 	MIO *mio = mio_new_memory ((unsigned char*)ctagsCommonPrelude, strlen (ctagsCommonPrelude), NULL, NULL);
4109431a587eSMasatake YAMATO 	EsObject *e = optscriptLoad (optvm, mio);
4110431a587eSMasatake YAMATO 	if (es_error_p (e))
4111431a587eSMasatake YAMATO 		error (FATAL, "failed in loading built-in procedures");
4112431a587eSMasatake YAMATO 	mio_unref (mio);
4113431a587eSMasatake YAMATO 	opt_vm_dstack_pop (optvm);
4114965b7025SMasatake YAMATO }
4115965b7025SMasatake YAMATO 
listRegexOpscriptOperators(FILE * fp)4116965b7025SMasatake YAMATO extern void	listRegexOpscriptOperators (FILE *fp)
4117965b7025SMasatake YAMATO {
4118f02ab9fbSMasatake YAMATO 	EsObject *procdocs;
4119f02ab9fbSMasatake YAMATO 	if (!opt_dict_known_and_get_cstr (lregex_dict,
4120f02ab9fbSMasatake YAMATO 									  "__procdocs",
4121f02ab9fbSMasatake YAMATO 									  &procdocs))
4122f02ab9fbSMasatake YAMATO 		procdocs = NULL;
4123f02ab9fbSMasatake YAMATO 
4124965b7025SMasatake YAMATO 	opt_vm_dstack_push (optvm, lregex_dict);
4125f02ab9fbSMasatake YAMATO 	optscriptHelp (optvm, fp, procdocs);
4126965b7025SMasatake YAMATO 	opt_vm_dstack_pop (optvm);
4127965b7025SMasatake YAMATO }
4128