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 38MODULE_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 50typedef struct 51 { 52 regex_t *pRegExp; 53 unsigned long *refCount; 54 } 55RegExp_Arg; 56 57#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS 58#undef RETURN 59static int reg_errno; 60 61static char * 62RegEx_Init(char *instring) 63{ 64 reg_errno = 0; 65 return instring; 66} 67 68static char * 69RegEx_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 88typedef struct 89{ 90 char *compiled_expression; 91 unsigned long *refCount; 92} 93RegExp_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+--------------------------------------------------------------------------*/ 115static void * 116Generic_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+--------------------------------------------------------------------------*/ 217static void * 218Make_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+--------------------------------------------------------------------------*/ 234static void * 235Copy_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+--------------------------------------------------------------------------*/ 260static void 261Free_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+--------------------------------------------------------------------------*/ 301static bool 302Check_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 325static 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 343FORM_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*/ 350FORM_EXPORT(FIELDTYPE *) 351_nc_TYPE_REGEXP(void) 352{ 353 return TYPE_REGEXP; 354} 355#endif 356 357/* fty_regex.c ends here */ 358