1228072Sbapt/** regex - regular expression functions related to POSIX regex lib. */
2228072Sbapt
3228072Sbapt/*  This file is part of flex. */
4228072Sbapt
5228072Sbapt/*  Redistribution and use in source and binary forms, with or without */
6228072Sbapt/*  modification, are permitted provided that the following conditions */
7228072Sbapt/*  are met: */
8228072Sbapt
9228072Sbapt/*  1. Redistributions of source code must retain the above copyright */
10228072Sbapt/*     notice, this list of conditions and the following disclaimer. */
11228072Sbapt/*  2. Redistributions in binary form must reproduce the above copyright */
12228072Sbapt/*     notice, this list of conditions and the following disclaimer in the */
13228072Sbapt/*     documentation and/or other materials provided with the distribution. */
14228072Sbapt
15228072Sbapt/*  Neither the name of the University nor the names of its contributors */
16228072Sbapt/*  may be used to endorse or promote products derived from this software */
17228072Sbapt/*  without specific prior written permission. */
18228072Sbapt
19228072Sbapt/*  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */
20228072Sbapt/*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
21228072Sbapt/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
22228072Sbapt/*  PURPOSE. */
23228072Sbapt
24228072Sbapt#include "flexdef.h"
25228072Sbapt
26228072Sbapt
27228072Sbaptstatic const char* REGEXP_LINEDIR = "^#line ([[:digit:]]+) \"(.*)\"";
28228072Sbaptstatic const char* REGEXP_BLANK_LINE = "^[[:space:]]*$";
29228072Sbapt
30228072Sbaptregex_t regex_linedir; /**< matches line directives */
31228072Sbaptregex_t regex_blank_line; /**< matches blank lines */
32228072Sbapt
33228072Sbapt
34228072Sbapt/** Initialize the regular expressions.
35228072Sbapt * @return true upon success.
36228072Sbapt */
37228072Sbaptbool flex_init_regex(void)
38228072Sbapt{
39228072Sbapt    flex_regcomp(&regex_linedir, REGEXP_LINEDIR, REG_EXTENDED);
40228072Sbapt    flex_regcomp(&regex_blank_line, REGEXP_BLANK_LINE, REG_EXTENDED);
41228072Sbapt
42228072Sbapt    return true;
43228072Sbapt}
44228072Sbapt
45228072Sbapt/** Compiles a regular expression or dies trying.
46228072Sbapt * @param preg  Same as for regcomp().
47228072Sbapt * @param regex Same as for regcomp().
48228072Sbapt * @param cflags Same as for regcomp().
49228072Sbapt */
50228072Sbaptvoid flex_regcomp(regex_t *preg, const char *regex, int cflags)
51228072Sbapt{
52228072Sbapt    int err;
53228072Sbapt
54228072Sbapt	memset (preg, 0, sizeof (regex_t));
55228072Sbapt
56228072Sbapt	if ((err = regcomp (preg, regex, cflags)) != 0) {
57228072Sbapt        const int errbuf_sz = 200;
58250125Sjkim        char *errbuf, *rxerr;
59228072Sbapt
60250125Sjkim		errbuf = (char*)flex_alloc(errbuf_sz *sizeof(char));
61250125Sjkim		if (!errbuf)
62250125Sjkim			flexfatal(_("Unable to allocate buffer to report regcomp"));
63250125Sjkim		rxerr = (char*)flex_alloc(errbuf_sz *sizeof(char));
64250125Sjkim		if (!rxerr)
65250125Sjkim			flexfatal(_("Unable to allocate buffer for regerror"));
66250125Sjkim		regerror (err, preg, rxerr, errbuf_sz);
67250125Sjkim		snprintf (errbuf, errbuf_sz, "regcomp for \"%s\" failed: %s", regex, rxerr);
68228072Sbapt
69228072Sbapt		flexfatal (errbuf);
70228072Sbapt        free(errbuf);
71250125Sjkim        free(rxerr);
72228072Sbapt	}
73228072Sbapt}
74228072Sbapt
75228072Sbapt/** Extract a copy of the match, or NULL if no match.
76228072Sbapt * @param m A match as returned by regexec().
77228072Sbapt * @param src The source string that was passed to regexec().
78228072Sbapt * @return The allocated string.
79228072Sbapt */
80228072Sbaptchar   *regmatch_dup (regmatch_t * m, const char *src)
81228072Sbapt{
82228072Sbapt	char   *str;
83228072Sbapt	int     len;
84228072Sbapt
85228072Sbapt	if (m == NULL || m->rm_so < 0)
86228072Sbapt		return NULL;
87228072Sbapt	len = m->rm_eo - m->rm_so;
88228072Sbapt	str = (char *) flex_alloc ((len + 1) * sizeof (char));
89250125Sjkim	if (!str)
90250125Sjkim		flexfatal(_("Unable to allocate a copy of the match"));
91228072Sbapt	strncpy (str, src + m->rm_so, len);
92228072Sbapt	str[len] = 0;
93228072Sbapt	return str;
94228072Sbapt}
95228072Sbapt
96228072Sbapt/** Copy the match.
97228072Sbapt * @param m A match as returned by regexec().
98228072Sbapt * @param dest The destination buffer.
99228072Sbapt * @param src The source string that was passed to regexec().
100228072Sbapt * @return dest
101228072Sbapt */
102228072Sbaptchar   *regmatch_cpy (regmatch_t * m, char *dest, const char *src)
103228072Sbapt{
104228072Sbapt	if (m == NULL || m->rm_so < 0) {
105228072Sbapt		if (dest)
106228072Sbapt			dest[0] = '\0';
107228072Sbapt		return dest;
108228072Sbapt	}
109228072Sbapt
110228072Sbapt	snprintf (dest, regmatch_len(m), "%s", src + m->rm_so);
111228072Sbapt    return dest;
112228072Sbapt}
113228072Sbapt
114228072Sbapt/** Get the length in characters of the match.
115228072Sbapt * @param m A match as returned by regexec().
116228072Sbapt * @param src The source string that was passed to regexec().
117228072Sbapt * @return The length of the match.
118228072Sbapt */
119228072Sbaptint regmatch_len (regmatch_t * m)
120228072Sbapt{
121228072Sbapt	if (m == NULL || m->rm_so < 0) {
122228072Sbapt		return 0;
123228072Sbapt	}
124228072Sbapt
125228072Sbapt	return m->rm_eo - m->rm_so;
126228072Sbapt}
127228072Sbapt
128228072Sbapt
129228072Sbapt
130228072Sbapt/** Convert a regmatch_t object to an integer using the strtol() function.
131228072Sbapt * @param m A match as returned by regexec().
132228072Sbapt * @param src The source string that was passed to regexec().
133228072Sbapt * @param endptr Same as the second argument to strtol().
134228072Sbapt * @param base   Same as the third argument to strtol().
135228072Sbapt * @return The converted integer or error (Return value is the same as for strtol()).
136228072Sbapt */
137228072Sbaptint regmatch_strtol (regmatch_t * m, const char *src, char **endptr,
138228072Sbapt		     int base)
139228072Sbapt{
140228072Sbapt	int     n = 0;
141228072Sbapt
142228072Sbapt#define bufsz 20
143228072Sbapt	char    buf[bufsz];
144228072Sbapt	char   *s;
145228072Sbapt
146228072Sbapt	if (m == NULL || m->rm_so < 0)
147228072Sbapt		return 0;
148228072Sbapt
149228072Sbapt	if (regmatch_len (m) < bufsz)
150228072Sbapt		s = regmatch_cpy (m, buf, src);
151228072Sbapt	else
152228072Sbapt		s = regmatch_dup (m, src);
153228072Sbapt
154228072Sbapt	n = strtol (s, endptr, base);
155228072Sbapt
156228072Sbapt	if (s != buf)
157228072Sbapt		free (s);
158228072Sbapt
159228072Sbapt	return n;
160228072Sbapt}
161228072Sbapt
162228072Sbapt/** Check for empty or non-existent match.
163228072Sbapt * @param m A match as returned by regexec().
164228072Sbapt * @return false if match length is non-zero.
165228072Sbapt * Note that reg_empty returns true even if match did not occur at all.
166228072Sbapt */
167228072Sbaptbool regmatch_empty (regmatch_t * m)
168228072Sbapt{
169228072Sbapt	return (m == NULL || m->rm_so < 0 || m->rm_so == m->rm_eo);
170228072Sbapt}
171228072Sbapt
172228072Sbapt/* vim:set expandtab cindent tabstop=4 softtabstop=4 shiftwidth=4 textwidth=0: */
173