1 /**************************************************************************** 2 * Copyright 2018,2020 Thomas E. Dickey * 3 * Copyright 1998-2012,2015 Free Software Foundation, Inc. * 4 * * 5 * Permission is hereby granted, free of charge, to any person obtaining a * 6 * copy of this software and associated documentation files (the * 7 * "Software"), to deal in the Software without restriction, including * 8 * without limitation the rights to use, copy, modify, merge, publish, * 9 * distribute, distribute with modifications, sublicense, and/or sell * 10 * copies of the Software, and to permit persons to whom the Software is * 11 * furnished to do so, subject to the following conditions: * 12 * * 13 * The above copyright notice and this permission notice shall be included * 14 * in all copies or substantial portions of the Software. * 15 * * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 23 * * 24 * Except as contained in this notice, the name(s) of the above copyright * 25 * holders shall not be used in advertising or otherwise to promote the * 26 * sale, use or other dealings in this Software without prior written * 27 * authorization. * 28 ****************************************************************************/ 29 30 /*************************************************************************** 31 * * 32 * Author : Juergen Pfeifer * 33 * * 34 ***************************************************************************/ 35 36 #include "form.priv.h" 37 38 MODULE_ID("$Id: fty_regex.c,v 1.32 2020/12/12 01:15:37 tom Exp $") 39 40 #if HAVE_REGEX_H_FUNCS || HAVE_LIB_PCRE2 /* We prefer POSIX regex */ 41 42 #if HAVE_PCRE2POSIX_H 43 #include <pcre2posix.h> 44 #elif HAVE_PCREPOSIX_H 45 #include <pcreposix.h> 46 #else 47 #include <regex.h> 48 #endif 49 50 typedef struct 51 { 52 regex_t *pRegExp; 53 unsigned long *refCount; 54 } 55 RegExp_Arg; 56 57 #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 58 #undef RETURN 59 static int reg_errno; 60 61 static char * 62 RegEx_Init(char *instring) 63 { 64 reg_errno = 0; 65 return instring; 66 } 67 68 static char * 69 RegEx_Error(int code) 70 { 71 reg_errno = code; 72 return 0; 73 } 74 75 #define INIT register char *sp = RegEx_Init(instring); 76 #define GETC() (*sp++) 77 #define PEEKC() (*sp) 78 #define UNGETC(c) (--sp) 79 #define RETURN(c) return(c) 80 #define ERROR(c) return RegEx_Error(c) 81 82 #if HAVE_REGEXP_H_FUNCS 83 #include <regexp.h> 84 #else 85 #include <regexpr.h> 86 #endif 87 88 typedef struct 89 { 90 char *compiled_expression; 91 unsigned long *refCount; 92 } 93 RegExp_Arg; 94 95 /* Maximum Length we allow for a compiled regular expression */ 96 #define MAX_RX_LEN (2048) 97 #define RX_INCREMENT (256) 98 99 #endif 100 101 #if HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 102 # define MAYBE_UNUSED 103 #else 104 # define MAYBE_UNUSED GCC_UNUSED 105 #endif 106 107 /*--------------------------------------------------------------------------- 108 | Facility : libnform 109 | Function : static void *Generic_RegularExpression_Type(void * arg) 110 | 111 | Description : Allocate structure for regex type argument. 112 | 113 | Return Values : Pointer to argument structure or NULL on error 114 +--------------------------------------------------------------------------*/ 115 static void * 116 Generic_RegularExpression_Type(void *arg MAYBE_UNUSED) 117 { 118 #if HAVE_REGEX_H_FUNCS 119 char *rx = (char *)arg; 120 RegExp_Arg *preg = (RegExp_Arg *)0; 121 122 if (rx) 123 { 124 preg = typeCalloc(RegExp_Arg, 1); 125 126 if (preg) 127 { 128 T((T_CREATE("RegExp_Arg %p"), (void *)preg)); 129 if (((preg->pRegExp = typeMalloc(regex_t, 1)) != 0) 130 && !regcomp(preg->pRegExp, rx, 131 (REG_EXTENDED | REG_NOSUB | REG_NEWLINE))) 132 { 133 T((T_CREATE("regex_t %p"), (void *)preg->pRegExp)); 134 if ((preg->refCount = typeMalloc(unsigned long, 1)) != 0) 135 *(preg->refCount) = 1; 136 } 137 else 138 { 139 if (preg->pRegExp) 140 free(preg->pRegExp); 141 free(preg); 142 preg = (RegExp_Arg *)0; 143 } 144 } 145 } 146 return ((void *)preg); 147 #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 148 char *rx = (char *)arg; 149 RegExp_Arg *pArg = (RegExp_Arg *)0; 150 151 if (rx) 152 { 153 pArg = typeMalloc(RegExp_Arg, 1); 154 155 if (pArg) 156 { 157 int blen = RX_INCREMENT; 158 159 T((T_CREATE("RegExp_Arg %p"), pArg)); 160 pArg->compiled_expression = NULL; 161 if ((pArg->refCount = typeMalloc(unsigned long, 1)) != 0) 162 *(pArg->refCount) = 1; 163 164 do 165 { 166 char *buf = typeMalloc(char, blen); 167 168 if (buf) 169 { 170 #if HAVE_REGEXP_H_FUNCS 171 char *last_pos = compile(rx, buf, &buf[blen], '\0'); 172 173 #else /* HAVE_REGEXPR_H_FUNCS */ 174 char *last_pos = compile(rx, buf, &buf[blen]); 175 #endif 176 if (reg_errno) 177 { 178 free(buf); 179 if (reg_errno == 50) 180 blen += RX_INCREMENT; 181 else 182 { 183 free(pArg); 184 pArg = NULL; 185 break; 186 } 187 } 188 else 189 { 190 pArg->compiled_expression = buf; 191 break; 192 } 193 } 194 } 195 while (blen <= MAX_RX_LEN); 196 } 197 if (pArg && !pArg->compiled_expression) 198 { 199 free(pArg); 200 pArg = NULL; 201 } 202 } 203 return (void *)pArg; 204 #else 205 return 0; 206 #endif 207 } 208 209 /*--------------------------------------------------------------------------- 210 | Facility : libnform 211 | Function : static void *Make_RegularExpression_Type(va_list * ap) 212 | 213 | Description : Allocate structure for regex type argument. 214 | 215 | Return Values : Pointer to argument structure or NULL on error 216 +--------------------------------------------------------------------------*/ 217 static void * 218 Make_RegularExpression_Type(va_list *ap) 219 { 220 char *rx = va_arg(*ap, char *); 221 222 return Generic_RegularExpression_Type((void *)rx); 223 } 224 225 /*--------------------------------------------------------------------------- 226 | Facility : libnform 227 | Function : static void *Copy_RegularExpression_Type( 228 | const void * argp) 229 | 230 | Description : Copy structure for regex type argument. 231 | 232 | Return Values : Pointer to argument structure or NULL on error. 233 +--------------------------------------------------------------------------*/ 234 static void * 235 Copy_RegularExpression_Type(const void *argp MAYBE_UNUSED) 236 { 237 #if (HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS) 238 const RegExp_Arg *ap = (const RegExp_Arg *)argp; 239 const RegExp_Arg *result = (const RegExp_Arg *)0; 240 241 if (ap) 242 { 243 *(ap->refCount) += 1; 244 result = ap; 245 } 246 return (void *)result; 247 #else 248 return 0; 249 #endif 250 } 251 252 /*--------------------------------------------------------------------------- 253 | Facility : libnform 254 | Function : static void Free_RegularExpression_Type(void * argp) 255 | 256 | Description : Free structure for regex type argument. 257 | 258 | Return Values : - 259 +--------------------------------------------------------------------------*/ 260 static void 261 Free_RegularExpression_Type(void *argp MAYBE_UNUSED) 262 { 263 #if HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 264 RegExp_Arg *ap = (RegExp_Arg *)argp; 265 266 if (ap) 267 { 268 if (--(*(ap->refCount)) == 0) 269 { 270 #if HAVE_REGEX_H_FUNCS 271 if (ap->pRegExp) 272 { 273 free(ap->refCount); 274 regfree(ap->pRegExp); 275 free(ap->pRegExp); 276 } 277 #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 278 if (ap->compiled_expression) 279 { 280 free(ap->refCount); 281 free(ap->compiled_expression); 282 } 283 #endif 284 free(ap); 285 } 286 } 287 #endif 288 } 289 290 /*--------------------------------------------------------------------------- 291 | Facility : libnform 292 | Function : static bool Check_RegularExpression_Field( 293 | FIELD * field, 294 | const void * argp) 295 | 296 | Description : Validate buffer content to be a valid regular expression 297 | 298 | Return Values : TRUE - field is valid 299 | FALSE - field is invalid 300 +--------------------------------------------------------------------------*/ 301 static bool 302 Check_RegularExpression_Field(FIELD *field MAYBE_UNUSED, 303 const void *argp MAYBE_UNUSED) 304 { 305 bool match = FALSE; 306 307 #if HAVE_REGEX_H_FUNCS 308 const RegExp_Arg *ap = (const RegExp_Arg *)argp; 309 310 if (ap && ap->pRegExp) 311 match = (regexec(ap->pRegExp, field_buffer(field, 0), 0, NULL, 0) 312 ? FALSE 313 : TRUE); 314 #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 315 RegExp_Arg *ap = (RegExp_Arg *)argp; 316 317 if (ap && ap->compiled_expression) 318 match = (step(field_buffer(field, 0), ap->compiled_expression) 319 ? TRUE 320 : FALSE); 321 #endif 322 return match; 323 } 324 325 static FIELDTYPE typeREGEXP = 326 { 327 _HAS_ARGS | _RESIDENT, 328 1, /* this is mutable, so we can't be const */ 329 (FIELDTYPE *)0, 330 (FIELDTYPE *)0, 331 Make_RegularExpression_Type, 332 Copy_RegularExpression_Type, 333 Free_RegularExpression_Type, 334 INIT_FT_FUNC(Check_RegularExpression_Field), 335 INIT_FT_FUNC(NULL), 336 INIT_FT_FUNC(NULL), 337 INIT_FT_FUNC(NULL), 338 #if NCURSES_INTEROP_FUNCS 339 Generic_RegularExpression_Type 340 #endif 341 }; 342 343 FORM_EXPORT_VAR(FIELDTYPE *) TYPE_REGEXP = &typeREGEXP; 344 345 #if NCURSES_INTEROP_FUNCS 346 /* The next routines are to simplify the use of ncurses from 347 programming languages with restrictions on interop with C level 348 constructs (e.g. variable access or va_list + ellipsis constructs) 349 */ 350 FORM_EXPORT(FIELDTYPE *) 351 _nc_TYPE_REGEXP(void) 352 { 353 return TYPE_REGEXP; 354 } 355 #endif 356 357 /* fty_regex.c ends here */ 358