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

📄 lregex.c

📁 ultraEdit的Ctag标签工具的实现源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
*   $Id: lregex.c,v 1.6 2003/07/11 01:21:53 darren Exp $
*
*   Copyright (c) 2000-2003, Darren Hiebert
*
*   This source code is released for free distribution under the terms of the
*   GNU General Public License.
*
*   This module contains functions for applying regular expression matching.
*
*   The code for utlizing the Gnu regex package with regards to processing the
*   regex option and checking for regex matches was adapted from routines in
*   Gnu etags.
*/

/*
*   INCLUDE FILES
*/
#include "general.h"	/* must always come first */

#include <string.h>

#ifdef HAVE_REGCOMP
# include <ctype.h>
# include <stddef.h>
# ifdef HAVE_SYS_TYPES_H
#  include <sys/types.h> /* declare off_t (not known to regex.h on FreeBSD) */
# endif
# include "regex.h"
#endif

#include "debug.h"
#include "entry.h"
#include "parse.h"
#include "read.h"
#include "routines.h"

#ifdef HAVE_REGEX

/*
*   MACROS
*/

/* Back-references \0 through \9 */
#define BACK_REFERENCE_COUNT 10

#if defined (HAVE_REGCOMP) && !defined (REGCOMP_BROKEN)
# define POSIX_REGEX
#endif

#define REGEX_NAME "Regex"

/*
*   DATA DECLARATIONS
*/
#if defined (POSIX_REGEX)

struct sKind {
    boolean enabled;
    char letter;
    char* name;
    char* description;
};

enum pType { PTRN_TAG, PTRN_CALLBACK };

typedef struct {
    regex_t *pattern;
    enum pType type;
    union {
	struct {
	    char *name_pattern;
	    struct sKind kind;
	} tag;
	struct {
	    regexCallback function;
	} callback;
    } u;
} regexPattern;

#endif

typedef struct {
    regexPattern *patterns;
    unsigned int count;
} patternSet;

/*
*   DATA DEFINITIONS
*/

static boolean regexBroken = FALSE;

/* Array of pattern sets, indexed by language */
static patternSet* Sets = NULL;
static int SetUpper = -1;	/* upper language index in list */

/*
*   FUNCTION DEFINITIONS
*/

static void clearPatternSet (const langType language)
{
    if (language < SetUpper)
    {
	patternSet* const set = Sets + language;
	unsigned int i;
	for (i = 0  ;  i < set->count  ;  ++i)
	{
#if defined (POSIX_REGEX)
	    regfree (set->patterns [i].pattern);
#endif
	    eFree (set->patterns [i].pattern);
	    set->patterns [i].pattern = NULL;

	    if (set->patterns [i].type == PTRN_TAG)
	    {
		eFree (set->patterns [i].u.tag.name_pattern);
		set->patterns [i].u.tag.name_pattern = NULL;
	    }
	}
	if (set->patterns != NULL)
	    eFree (set->patterns);
	set->patterns = NULL;
	set->count = 0;
    }
}

/*
*   Regex psuedo-parser
*/

static void makeRegexTag (
	const vString* const name, const struct sKind* const kind)
{
    if (kind->enabled)
    {
	tagEntryInfo e;
	Assert (name != NULL  &&  vStringLength (name) > 0);
	Assert (kind != NULL);
	initTagEntry (&e, vStringValue (name));
	e.kind     = kind->letter;
	e.kindName = kind->name;
	makeTagEntry (&e);
    }
}

/*
*   Regex pattern definition
*/

/* Take a string like "/blah/" and turn it into "blah", making sure
 * that the first and last characters are the same, and handling
 * quoted separator characters.  Actually, stops on the occurrence of
 * an unquoted separator.  Also turns "\t" into a Tab character.
 * Returns pointer to terminating separator.  Works in place.  Null
 * terminates name string.
 */
static char* scanSeparators (char* name)
{
    char sep = name [0];
    char *copyto = name;
    boolean quoted = FALSE;

    for (++name ; *name != '\0' ; ++name)
    {
	if (quoted)
	{
	    if (*name == sep)
		*copyto++ = sep;
	    else if (*name == 't')
		*copyto++ = '\t';
	    else
	    {
		/* Something else is quoted, so preserve the quote. */
		*copyto++ = '\\';
		*copyto++ = *name;
	    }
	    quoted = FALSE;
	}
	else if (*name == '\\')
	    quoted = TRUE;
	else if (*name == sep)
	{
	    break;
	}
	else
	    *copyto++ = *name;
    }
    *copyto = '\0';
    return name;
}

/* Parse `regexp', in form "/regex/name/[k,Kind/]flags" (where the separator
 * character is whatever the first character of `regexp' is), by breaking it
 * up into null terminated strings, removing the separators, and expanding
 * '\t' into tabs. When complete, `regexp' points to the line matching
 * pattern, a pointer to the name matching pattern is written to `name', a
 * pointer to the kinds is written to `kinds' (possibly NULL), and a pointer
 * to the trailing flags is written to `flags'. If the pattern is not in the
 * correct format, a false value is returned.
 */
static boolean parseTagRegex (
	char* const regexp, char** const name,
	char** const kinds, char** const flags)
{
    boolean result = FALSE;
    const int separator = (unsigned char) regexp [0];

    *name = scanSeparators (regexp);
    if (*regexp == '\0')
	error (WARNING, "empty regexp");
    else if (**name != separator)
	error (WARNING, "%s: incomplete regexp", regexp);
    else
    {
	char* const third = scanSeparators (*name);
	if (**name == '\0')
	    error (WARNING, "%s: regexp missing name pattern", regexp);
	if ((*name) [strlen (*name) - 1] == '\\')
	    error (WARNING, "error in name pattern: \"%s\"", *name);
	if (*third != separator)
	    error (WARNING, "%s: regexp missing final separator", regexp);
	else
	{
	    char* const fourth = scanSeparators (third);
	    if (*fourth == separator)
	    {
		*kinds = third;
		scanSeparators (fourth);
		*flags = fourth;
	    }
	    else
	    {
		*flags = third;
		*kinds = NULL;
	    }
	    result = TRUE;
	}
    }
    return result;
}

static void addCompiledTagPattern (
	const langType language, regex_t* const pattern,
	char* const name, const char kind, char* const kindName,
	char *const description)
{
    patternSet* set;
    regexPattern *ptrn;
    if (language > SetUpper)
    {
	int i;
	Sets = xRealloc (Sets, (language + 1), patternSet);
	for (i = SetUpper + 1  ;  i <= language  ;  ++i)
	{
	    Sets [i].patterns = NULL;
	    Sets [i].count = 0;
	}
	SetUpper = language;
    }
    set = Sets + language;
    set->patterns = xRealloc (set->patterns, (set->count + 1), regexPattern);
    ptrn = &set->patterns [set->count];
    set->count += 1;

    ptrn->pattern = pattern;
    ptrn->type    = PTRN_TAG;
    ptrn->u.tag.name_pattern = name;
    ptrn->u.tag.kind.enabled = TRUE;
    ptrn->u.tag.kind.letter  = kind;
    ptrn->u.tag.kind.name    = kindName;
    ptrn->u.tag.kind.description = description;
}

static void addCompiledCallbackPattern (
	const langType language, regex_t* const pattern,
	const regexCallback callback)
{
    patternSet* set;
    regexPattern *ptrn;
    if (language > SetUpper)
    {
	int i;
	Sets = xRealloc (Sets, (language + 1), patternSet);
	for (i = SetUpper + 1  ;  i <= language  ;  ++i)
	{
	    Sets [i].patterns = NULL;
	    Sets [i].count = 0;
	}
	SetUpper = language;
    }
    set = Sets + language;
    set->patterns = xRealloc (set->patterns, (set->count + 1), regexPattern);
    ptrn = &set->patterns [set->count];
    set->count += 1;

    ptrn->pattern = pattern;
    ptrn->type    = PTRN_CALLBACK;
    ptrn->u.callback.function = callback;
}

#if defined (POSIX_REGEX)

static regex_t* compileRegex (const char* const regexp, const char* const flags)
{
    int cflags = REG_EXTENDED | REG_NEWLINE;
    regex_t *result = NULL;
    int errcode;
    int i;
    for (i = 0  ; flags != NULL  &&  flags [i] != '\0'  ;  ++i)
    {
	switch ((int) flags [i])
	{
	    case 'b': cflags &= ~REG_EXTENDED; break;
	    case 'e': cflags |= REG_EXTENDED;  break;
	    case 'i': cflags |= REG_ICASE;     break;
	    default: error (WARNING, "unknown regex flag: '%c'", *flags); break;
	}
    }
    result = xMalloc (1, regex_t);
    errcode = regcomp (result, regexp, cflags);
    if (errcode != 0)
    {
	char errmsg[256];
	regerror (errcode, result, errmsg, 256);
	error (WARNING, "%s", errmsg);
	regfree (result);
	eFree (result);
	result = NULL;
    }
    return result;
}

#endif

static void parseKinds (
	const char* const kinds, char* const kind, char** const kindName,
	char **description)
{
    *kind = '\0';
    *kindName = NULL;
    *description = NULL;
    if (kinds == NULL  ||  kinds [0] == '\0')
    {
	*kind = 'r';
	*kindName = eStrdup ("regex");
    }
    else if (kinds [0] != '\0')

⌨️ 快捷键说明

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