1 /**************************************************************************** 2 * Copyright 2018-2020,2021 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.33 2021/08/14 15:01:52 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 45 /* pcre2 used to provide its "POSIX" entrypoints using the same names as the 46 * standard ones in the C runtime, but that never worked because the linker 47 * would use the C runtime. Debian patched the library to fix this symbol 48 * conflict, but overlooked the header file, and Debian's patch was made 49 * obsolete when pcre2 was changed early in 2019 to provide different names. 50 * 51 * Here is a workaround to make the older version of Debian's package work. 52 */ 53 #if !defined(PCRE2regcomp) && defined(HAVE_PCRE2REGCOMP) 54 55 #undef regcomp 56 #undef regexec 57 #undef regfree 58 59 #ifdef __cplusplus 60 extern "C" 61 { 62 #endif 63 PCRE2POSIX_EXP_DECL int PCRE2regcomp(regex_t *, const char *, int); 64 PCRE2POSIX_EXP_DECL int PCRE2regexec(const regex_t *, const char *, size_t, 65 regmatch_t *, int); 66 PCRE2POSIX_EXP_DECL void PCRE2regfree(regex_t *); 67 #ifdef __cplusplus 68 } /* extern "C" */ 69 #endif 70 #define regcomp(r,s,n) PCRE2regcomp(r,s,n) 71 #define regexec(r,s,n,m,x) PCRE2regexec(r,s,n,m,x) 72 #define regfree(r) PCRE2regfree(r) 73 #endif 74 /* end workaround... */ 75 #elif HAVE_PCREPOSIX_H 76 #include <pcreposix.h> 77 #else 78 #include <regex.h> 79 #endif 80 81 typedef struct 82 { 83 regex_t *pRegExp; 84 unsigned long *refCount; 85 } 86 RegExp_Arg; 87 88 #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 89 #undef RETURN 90 static int reg_errno; 91 92 static char * 93 RegEx_Init(char *instring) 94 { 95 reg_errno = 0; 96 return instring; 97 } 98 99 static char * 100 RegEx_Error(int code) 101 { 102 reg_errno = code; 103 return 0; 104 } 105 106 #define INIT register char *sp = RegEx_Init(instring); 107 #define GETC() (*sp++) 108 #define PEEKC() (*sp) 109 #define UNGETC(c) (--sp) 110 #define RETURN(c) return(c) 111 #define ERROR(c) return RegEx_Error(c) 112 113 #if HAVE_REGEXP_H_FUNCS 114 #include <regexp.h> 115 #else 116 #include <regexpr.h> 117 #endif 118 119 typedef struct 120 { 121 char *compiled_expression; 122 unsigned long *refCount; 123 } 124 RegExp_Arg; 125 126 /* Maximum Length we allow for a compiled regular expression */ 127 #define MAX_RX_LEN (2048) 128 #define RX_INCREMENT (256) 129 130 #endif 131 132 #if HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 133 # define MAYBE_UNUSED 134 #else 135 # define MAYBE_UNUSED GCC_UNUSED 136 #endif 137 138 /*--------------------------------------------------------------------------- 139 | Facility : libnform 140 | Function : static void *Generic_RegularExpression_Type(void * arg) 141 | 142 | Description : Allocate structure for regex type argument. 143 | 144 | Return Values : Pointer to argument structure or NULL on error 145 +--------------------------------------------------------------------------*/ 146 static void * 147 Generic_RegularExpression_Type(void *arg MAYBE_UNUSED) 148 { 149 #if HAVE_REGEX_H_FUNCS 150 char *rx = (char *)arg; 151 RegExp_Arg *preg = (RegExp_Arg *)0; 152 153 if (rx) 154 { 155 preg = typeCalloc(RegExp_Arg, 1); 156 157 if (preg) 158 { 159 T((T_CREATE("RegExp_Arg %p"), (void *)preg)); 160 if (((preg->pRegExp = typeMalloc(regex_t, 1)) != 0) 161 && !regcomp(preg->pRegExp, rx, 162 (REG_EXTENDED | REG_NOSUB | REG_NEWLINE))) 163 { 164 T((T_CREATE("regex_t %p"), (void *)preg->pRegExp)); 165 if ((preg->refCount = typeMalloc(unsigned long, 1)) != 0) 166 *(preg->refCount) = 1; 167 } 168 else 169 { 170 if (preg->pRegExp) 171 free(preg->pRegExp); 172 free(preg); 173 preg = (RegExp_Arg *)0; 174 } 175 } 176 } 177 return ((void *)preg); 178 #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 179 char *rx = (char *)arg; 180 RegExp_Arg *pArg = (RegExp_Arg *)0; 181 182 if (rx) 183 { 184 pArg = typeMalloc(RegExp_Arg, 1); 185 186 if (pArg) 187 { 188 int blen = RX_INCREMENT; 189 190 T((T_CREATE("RegExp_Arg %p"), pArg)); 191 pArg->compiled_expression = NULL; 192 if ((pArg->refCount = typeMalloc(unsigned long, 1)) != 0) 193 *(pArg->refCount) = 1; 194 195 do 196 { 197 char *buf = typeMalloc(char, blen); 198 199 if (buf) 200 { 201 #if HAVE_REGEXP_H_FUNCS 202 char *last_pos = compile(rx, buf, &buf[blen], '\0'); 203 204 #else /* HAVE_REGEXPR_H_FUNCS */ 205 char *last_pos = compile(rx, buf, &buf[blen]); 206 #endif 207 if (reg_errno) 208 { 209 free(buf); 210 if (reg_errno == 50) 211 blen += RX_INCREMENT; 212 else 213 { 214 free(pArg); 215 pArg = NULL; 216 break; 217 } 218 } 219 else 220 { 221 pArg->compiled_expression = buf; 222 break; 223 } 224 } 225 } 226 while (blen <= MAX_RX_LEN); 227 } 228 if (pArg && !pArg->compiled_expression) 229 { 230 free(pArg); 231 pArg = NULL; 232 } 233 } 234 return (void *)pArg; 235 #else 236 return 0; 237 #endif 238 } 239 240 /*--------------------------------------------------------------------------- 241 | Facility : libnform 242 | Function : static void *Make_RegularExpression_Type(va_list * ap) 243 | 244 | Description : Allocate structure for regex type argument. 245 | 246 | Return Values : Pointer to argument structure or NULL on error 247 +--------------------------------------------------------------------------*/ 248 static void * 249 Make_RegularExpression_Type(va_list *ap) 250 { 251 char *rx = va_arg(*ap, char *); 252 253 return Generic_RegularExpression_Type((void *)rx); 254 } 255 256 /*--------------------------------------------------------------------------- 257 | Facility : libnform 258 | Function : static void *Copy_RegularExpression_Type( 259 | const void * argp) 260 | 261 | Description : Copy structure for regex type argument. 262 | 263 | Return Values : Pointer to argument structure or NULL on error. 264 +--------------------------------------------------------------------------*/ 265 static void * 266 Copy_RegularExpression_Type(const void *argp MAYBE_UNUSED) 267 { 268 #if (HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS) 269 const RegExp_Arg *ap = (const RegExp_Arg *)argp; 270 const RegExp_Arg *result = (const RegExp_Arg *)0; 271 272 if (ap) 273 { 274 *(ap->refCount) += 1; 275 result = ap; 276 } 277 return (void *)result; 278 #else 279 return 0; 280 #endif 281 } 282 283 /*--------------------------------------------------------------------------- 284 | Facility : libnform 285 | Function : static void Free_RegularExpression_Type(void * argp) 286 | 287 | Description : Free structure for regex type argument. 288 | 289 | Return Values : - 290 +--------------------------------------------------------------------------*/ 291 static void 292 Free_RegularExpression_Type(void *argp MAYBE_UNUSED) 293 { 294 #if HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 295 RegExp_Arg *ap = (RegExp_Arg *)argp; 296 297 if (ap) 298 { 299 if (--(*(ap->refCount)) == 0) 300 { 301 #if HAVE_REGEX_H_FUNCS 302 if (ap->pRegExp) 303 { 304 free(ap->refCount); 305 regfree(ap->pRegExp); 306 free(ap->pRegExp); 307 } 308 #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 309 if (ap->compiled_expression) 310 { 311 free(ap->refCount); 312 free(ap->compiled_expression); 313 } 314 #endif 315 free(ap); 316 } 317 } 318 #endif 319 } 320 321 /*--------------------------------------------------------------------------- 322 | Facility : libnform 323 | Function : static bool Check_RegularExpression_Field( 324 | FIELD * field, 325 | const void * argp) 326 | 327 | Description : Validate buffer content to be a valid regular expression 328 | 329 | Return Values : TRUE - field is valid 330 | FALSE - field is invalid 331 +--------------------------------------------------------------------------*/ 332 static bool 333 Check_RegularExpression_Field(FIELD *field MAYBE_UNUSED, 334 const void *argp MAYBE_UNUSED) 335 { 336 bool match = FALSE; 337 338 #if HAVE_REGEX_H_FUNCS 339 const RegExp_Arg *ap = (const RegExp_Arg *)argp; 340 341 if (ap && ap->pRegExp) 342 match = (regexec(ap->pRegExp, field_buffer(field, 0), 0, NULL, 0) 343 ? FALSE 344 : TRUE); 345 #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 346 RegExp_Arg *ap = (RegExp_Arg *)argp; 347 348 if (ap && ap->compiled_expression) 349 match = (step(field_buffer(field, 0), ap->compiled_expression) 350 ? TRUE 351 : FALSE); 352 #endif 353 return match; 354 } 355 356 static FIELDTYPE typeREGEXP = 357 { 358 _HAS_ARGS | _RESIDENT, 359 1, /* this is mutable, so we can't be const */ 360 (FIELDTYPE *)0, 361 (FIELDTYPE *)0, 362 Make_RegularExpression_Type, 363 Copy_RegularExpression_Type, 364 Free_RegularExpression_Type, 365 INIT_FT_FUNC(Check_RegularExpression_Field), 366 INIT_FT_FUNC(NULL), 367 INIT_FT_FUNC(NULL), 368 INIT_FT_FUNC(NULL), 369 #if NCURSES_INTEROP_FUNCS 370 Generic_RegularExpression_Type 371 #endif 372 }; 373 374 FORM_EXPORT_VAR(FIELDTYPE *) TYPE_REGEXP = &typeREGEXP; 375 376 #if NCURSES_INTEROP_FUNCS 377 /* The next routines are to simplify the use of ncurses from 378 programming languages with restrictions on interop with C level 379 constructs (e.g. variable access or va_list + ellipsis constructs) 380 */ 381 FORM_EXPORT(FIELDTYPE *) 382 _nc_TYPE_REGEXP(void) 383 { 384 return TYPE_REGEXP; 385 } 386 #endif 387 388 /* fty_regex.c ends here */ 389