1/** regex - regular expression functions related to POSIX regex lib. */
2
3/*  This file is part of flex. */
4
5/*  Redistribution and use in source and binary forms, with or without */
6/*  modification, are permitted provided that the following conditions */
7/*  are met: */
8
9/*  1. Redistributions of source code must retain the above copyright */
10/*     notice, this list of conditions and the following disclaimer. */
11/*  2. Redistributions in binary form must reproduce the above copyright */
12/*     notice, this list of conditions and the following disclaimer in the */
13/*     documentation and/or other materials provided with the distribution. */
14
15/*  Neither the name of the University nor the names of its contributors */
16/*  may be used to endorse or promote products derived from this software */
17/*  without specific prior written permission. */
18
19/*  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */
20/*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
21/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
22/*  PURPOSE. */
23
24#include "flexdef.h"
25
26
27static const char* REGEXP_LINEDIR = "^#line ([[:digit:]]+) \"(.*)\"";
28static const char* REGEXP_BLANK_LINE = "^[[:space:]]*$";
29
30regex_t regex_linedir; /**< matches line directives */
31regex_t regex_blank_line; /**< matches blank lines */
32
33
34/** Initialize the regular expressions.
35 * @return true upon success.
36 */
37bool flex_init_regex(void)
38{
39    flex_regcomp(&regex_linedir, REGEXP_LINEDIR, REG_EXTENDED);
40    flex_regcomp(&regex_blank_line, REGEXP_BLANK_LINE, REG_EXTENDED);
41
42    return true;
43}
44
45/** Compiles a regular expression or dies trying.
46 * @param preg  Same as for regcomp().
47 * @param regex Same as for regcomp().
48 * @param cflags Same as for regcomp().
49 */
50void flex_regcomp(regex_t *preg, const char *regex, int cflags)
51{
52    int err;
53
54	memset (preg, 0, sizeof (regex_t));
55
56	if ((err = regcomp (preg, regex, cflags)) != 0) {
57		const size_t errbuf_sz = 200;
58		char *errbuf;
59		int n;
60
61		errbuf = malloc(errbuf_sz * sizeof(char));
62		if (!errbuf)
63			flexfatal(_("Unable to allocate buffer to report regcomp"));
64		n = snprintf(errbuf, errbuf_sz, "regcomp for \"%s\" failed: ", regex);
65		regerror(err, preg, errbuf+n, errbuf_sz-(size_t)n);
66
67		flexfatal (errbuf); /* never returns - no need to free(errbuf) */
68	}
69}
70
71/** Extract a copy of the match, or NULL if no match.
72 * @param m A match as returned by regexec().
73 * @param src The source string that was passed to regexec().
74 * @return The allocated string.
75 */
76char   *regmatch_dup (regmatch_t * m, const char *src)
77{
78	char   *str;
79	size_t  len;
80
81	if (m == NULL || m->rm_so < 0 || m->rm_eo < m->rm_so)
82		return NULL;
83	len = (size_t) (m->rm_eo - m->rm_so);
84	str = malloc((len + 1) * sizeof(char));
85	if (!str)
86		flexfatal(_("Unable to allocate a copy of the match"));
87	strncpy (str, src + m->rm_so, len);
88	str[len] = 0;
89	return str;
90}
91
92/** Copy the match.
93 * @param m A match as returned by regexec().
94 * @param dest The destination buffer.
95 * @param src The source string that was passed to regexec().
96 * @return dest
97 */
98char   *regmatch_cpy (regmatch_t * m, char *dest, const char *src)
99{
100	if (m == NULL || m->rm_so < 0) {
101		if (dest)
102			dest[0] = '\0';
103		return dest;
104	}
105
106	snprintf (dest, (size_t) regmatch_len(m), "%s", src + m->rm_so);
107    return dest;
108}
109
110/** Get the length in characters of the match.
111 * @param m A match as returned by regexec().
112 * @return The length of the match.
113 */
114int regmatch_len (regmatch_t * m)
115{
116	if (m == NULL || m->rm_so < 0) {
117		return 0;
118	}
119
120	return m->rm_eo - m->rm_so;
121}
122
123
124
125/** Convert a regmatch_t object to an integer using the strtol() function.
126 * @param m A match as returned by regexec().
127 * @param src The source string that was passed to regexec().
128 * @param endptr Same as the second argument to strtol().
129 * @param base   Same as the third argument to strtol().
130 * @return The converted integer or error (Return value is the same as for strtol()).
131 */
132int regmatch_strtol (regmatch_t * m, const char *src, char **endptr,
133		     int base)
134{
135	int     n = 0;
136
137#define bufsz 20
138	char    buf[bufsz];
139	char   *s;
140
141	if (m == NULL || m->rm_so < 0)
142		return 0;
143
144	if (regmatch_len (m) < bufsz)
145		s = regmatch_cpy (m, buf, src);
146	else
147		s = regmatch_dup (m, src);
148
149	n = (int) strtol (s, endptr, base);
150
151	if (s != buf)
152		free (s);
153
154	return n;
155}
156
157/** Check for empty or non-existent match.
158 * @param m A match as returned by regexec().
159 * @return false if match length is non-zero.
160 * Note that reg_empty returns true even if match did not occur at all.
161 */
162bool regmatch_empty (regmatch_t * m)
163{
164	return (m == NULL || m->rm_so < 0 || m->rm_so == m->rm_eo);
165}
166
167/* vim:set expandtab cindent tabstop=4 softtabstop=4 shiftwidth=4 textwidth=0: */
168