⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lregex.c

📁 ultraEdit的Ctag标签工具的实现源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
    {
	const char* k = kinds;
	if (k [0] != ','  &&  (k [1] == ','  ||  k [1] == '\0'))
	    *kind = *k++;
	else
	    *kind = 'r';
	if (*k == ',')
	    ++k;
	if (k [0] == '\0')
	    *kindName = eStrdup ("regex");
	else
	{
	    const char *const comma = strchr (k, ',');
	    if (comma == NULL)
		*kindName = eStrdup (k);
	    else
	    {
		*kindName = (char*) eMalloc (comma - k + 1);
		strncpy (*kindName, k, comma - k);
		(*kindName) [comma - k] = '\0';
		k = comma + 1;
		if (k [0] != '\0')
		    *description = eStrdup (k);
	    }
	}
    }
}

static void printRegexKind (const regexPattern *pat, unsigned int i, boolean indent)
{
    const struct sKind *const kind = &pat [i].u.tag.kind;
    const char *const indentation = indent ? "    " : "";
    Assert (pat [i].type == PTRN_TAG);
    printf ("%s%c  %s %s\n", indentation,
	    kind->letter != '\0' ? kind->letter : '?',
	    kind->description != NULL ? kind->description : kind->name,
	    kind->enabled ? "" : " [off]");
}

static void processLanguageRegex (const langType language,
	const char* const parameter)
{
    if (parameter == NULL  ||  parameter [0] == '\0')
	clearPatternSet (language);
    else if (parameter [0] != '@')
	addLanguageRegex (language, parameter);
    else if (! doesFileExist (parameter + 1))
	error (WARNING, "cannot open regex file");
    else
    {
	const char* regexfile = parameter + 1;
	FILE* const fp = fopen (regexfile, "r");
	if (fp == NULL)
	    error (WARNING | PERROR, regexfile);
	else
	{
	    vString* const regex = vStringNew ();
	    while (readLine (regex, fp))
		addLanguageRegex (language, vStringValue (regex));
	    fclose (fp);
	    vStringDelete (regex);
	}
    }
}

/*
*   Regex pattern matching
*/

#if defined (POSIX_REGEX)

static vString* substitute (
	const char* const in, const char* out,
	const int nmatch, const regmatch_t* const pmatch)
{
    vString* result = vStringNew ();
    const char* p;
    for (p = out  ;  *p != '\0'  ;  p++)
    {
	if (*p == '\\'  &&  isdigit ((int) *++p))
	{
	    const int dig = *p - '0';
	    if (0 < dig  &&  dig < nmatch  &&  pmatch [dig].rm_so != -1)
	    {
		const int diglen = pmatch [dig].rm_eo - pmatch [dig].rm_so;
		vStringNCatS (result, in + pmatch [dig].rm_so, diglen);
	    }
	}
	else if (*p != '\n'  &&  *p != '\r')
	    vStringPut (result, *p);
    }
    vStringTerminate (result);
    return result;
}

static void matchTagPattern (const vString* const line,
	const regexPattern* const patbuf,
	const regmatch_t* const pmatch)
{
    vString *const name = substitute (vStringValue (line),
	    patbuf->u.tag.name_pattern, BACK_REFERENCE_COUNT, pmatch);
    vStringStripLeading (name);
    vStringStripTrailing (name);
    if (vStringLength (name) > 0)
	makeRegexTag (name, &patbuf->u.tag.kind);
    else
	error (WARNING, "%s:%ld: null expansion of name pattern \"%s\"",
	    getInputFileName (), getInputLineNumber (),
	    patbuf->u.tag.name_pattern);
    vStringDelete (name);
}

static void matchCallbackPattern (
	const vString* const line, const regexPattern* const patbuf,
	const regmatch_t* const pmatch)
{
    regexMatch matches [BACK_REFERENCE_COUNT];
    unsigned int count = 0;
    int i;
    for (i = 0  ;  i < BACK_REFERENCE_COUNT  &&  pmatch [i].rm_so != -1  ;  ++i)
    {
	matches [i].start  = pmatch [i].rm_so;
	matches [i].length = pmatch [i].rm_eo - pmatch [i].rm_so;
	++count;
    }
    patbuf->u.callback.function (vStringValue (line), matches, count);
}

static boolean matchRegexPattern (const vString* const line,
	const regexPattern* const patbuf)
{
    boolean result = FALSE;
    regmatch_t pmatch [BACK_REFERENCE_COUNT];
    const int match = regexec (patbuf->pattern, vStringValue (line),
			       BACK_REFERENCE_COUNT, pmatch, 0);
    if (match == 0)
    {
	result = TRUE;
	if (patbuf->type == PTRN_TAG)
	    matchTagPattern (line, patbuf, pmatch);
	else if (patbuf->type == PTRN_CALLBACK)
	    matchCallbackPattern (line, patbuf, pmatch);
	else
	{
	    Assert ("invalid pattern type" == NULL);
	    result = FALSE;
	}
    }
    return result;
}

#endif

/* PUBLIC INTERFACE */

/* Match against all patterns for specified language. Returns true if at least
 * on pattern matched.
 */
extern boolean matchRegex (const vString* const line, const langType language)
{
    boolean result = FALSE;
    if (language != LANG_IGNORE  &&  language <= SetUpper  &&
	Sets [language].count > 0)
    {
	const patternSet* const set = Sets + language;
	unsigned int i;
	for (i = 0  ;  i < set->count  ;  ++i)
	    if (matchRegexPattern (line, set->patterns + i))
		result = TRUE;
    }
    return result;
}

extern void findRegexTags (void)
{
    /* merely read all lines of the file */
    while (fileReadLine () != NULL)
	;
}

#endif /* HAVE_REGEX */

extern void addTagRegex (
	const langType language __unused__,
	const char* const regex __unused__,
	const char* const name __unused__,
	const char* const kinds __unused__,
	const char* const flags __unused__)
{
#ifdef HAVE_REGEX
    Assert (regex != NULL);
    Assert (name != NULL);
    if (! regexBroken)
    {
	regex_t* const cp = compileRegex (regex, flags);
	if (cp != NULL)
	{
	    char kind;
	    char* kindName;
	    char* description;
	    parseKinds (kinds, &kind, &kindName, &description);
	    addCompiledTagPattern (language, cp, eStrdup (name),
		    kind, kindName, description);
	}
    }
#endif
}

extern void addCallbackRegex (
	const langType language __unused__,
	const char* const regex __unused__,
	const char* const flags __unused__,
	const regexCallback callback __unused__)
{
#ifdef HAVE_REGEX
    Assert (regex != NULL);
    if (! regexBroken)
    {
	regex_t* const cp = compileRegex (regex, flags);
	if (cp != NULL)
	    addCompiledCallbackPattern (language, cp, callback);
    }
#endif
}

extern void addLanguageRegex (
	const langType language __unused__, const char* const regex __unused__)
{
#ifdef HAVE_REGEX
    if (! regexBroken)
    {
	char *const regex_pat = eStrdup (regex);
	char *name, *kinds, *flags;
	if (parseTagRegex (regex_pat, &name, &kinds, &flags))
	{
	    addTagRegex (language, regex_pat, name, kinds, flags);
	    eFree (regex_pat);
	}
    }
#endif
}

/*
*   Regex option parsing
*/

extern boolean processRegexOption (const char *const option,
				   const char *const parameter __unused__)
{
    boolean handled = FALSE;
    const char* const dash = strchr (option, '-');
    if (dash != NULL  &&  strncmp (option, "regex", dash - option) == 0)
    {
#ifdef HAVE_REGEX
	langType language;
	language = getNamedLanguage (dash + 1);
	if (language == LANG_IGNORE)
	    error (WARNING, "unknown language in --%s option", option);
	else
	    processLanguageRegex (language, parameter);
#else
	error (WARNING, "regex support not available; required for --%s option",
	   option);
#endif
	handled = TRUE;
    }
    return handled;
}

extern void disableRegexKinds (const langType language __unused__)
{
#ifdef HAVE_REGEX
    if (language <= SetUpper  &&  Sets [language].count > 0)
    {
	patternSet* const set = Sets + language;
	unsigned int i;
	for (i = 0  ;  i < set->count  ;  ++i)
	    if (set->patterns [i].type == PTRN_TAG)
		set->patterns [i].u.tag.kind.enabled = FALSE;
    }
#endif
}

extern boolean enableRegexKind (
	const langType language __unused__,
	const int kind __unused__, const boolean mode __unused__)
{
    boolean result = FALSE;
#ifdef HAVE_REGEX
    if (language <= SetUpper  &&  Sets [language].count > 0)
    {
	patternSet* const set = Sets + language;
	unsigned int i;
	for (i = 0  ;  i < set->count  ;  ++i)
	    if (set->patterns [i].type == PTRN_TAG &&
		set->patterns [i].u.tag.kind.letter == kind)
	    {
		set->patterns [i].u.tag.kind.enabled = mode;
		result = TRUE;
	    }
    }
#endif
    return result;
}

extern void printRegexKinds (const langType language __unused__, boolean indent)
{
#ifdef HAVE_REGEX
    if (language <= SetUpper  &&  Sets [language].count > 0)
    {
	patternSet* const set = Sets + language;
	unsigned int i;
	for (i = 0  ;  i < set->count  ;  ++i)
	    if (set->patterns [i].type == PTRN_TAG)
		printRegexKind (set->patterns, i, indent);
    }
#endif
}

extern void freeRegexResources (void)
{
#ifdef HAVE_REGEX
    int i;
    for (i = 0  ;  i <= SetUpper  ;  ++i)
	clearPatternSet (i);
    if (Sets != NULL)
	eFree (Sets);
    Sets = NULL;
    SetUpper = -1;
#endif
}

/* Check for broken regcomp() on Cygwin */
extern void checkRegex (void)
{
#if defined (HAVE_REGEX) && defined (CHECK_REGCOMP)
    regex_t patbuf;
    int errcode;
    if (regcomp (&patbuf, "/hello/", 0) != 0)
    {
	error (WARNING, "Disabling broken regex");
	regexBroken = TRUE;
    }
#endif
}

/* vi:set tabstop=8 shiftwidth=4: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -