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