14a1a9510SRong-En Fan /****************************************************************************
25ca44d1cSRong-En Fan * Copyright 2018,2020 Thomas E. Dickey *
34a1a9510SRong-En Fan * Copyright 1998-2012,2015 Free Software Foundation, Inc. *
44a1a9510SRong-En Fan * *
54a1a9510SRong-En Fan * Permission is hereby granted, free of charge, to any person obtaining a *
64a1a9510SRong-En Fan * copy of this software and associated documentation files (the *
74a1a9510SRong-En Fan * "Software"), to deal in the Software without restriction, including *
84a1a9510SRong-En Fan * without limitation the rights to use, copy, modify, merge, publish, *
94a1a9510SRong-En Fan * distribute, distribute with modifications, sublicense, and/or sell *
104a1a9510SRong-En Fan * copies of the Software, and to permit persons to whom the Software is *
114a1a9510SRong-En Fan * furnished to do so, subject to the following conditions: *
124a1a9510SRong-En Fan * *
134a1a9510SRong-En Fan * The above copyright notice and this permission notice shall be included *
144a1a9510SRong-En Fan * in all copies or substantial portions of the Software. *
154a1a9510SRong-En Fan * *
164a1a9510SRong-En Fan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
174a1a9510SRong-En Fan * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
184a1a9510SRong-En Fan * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
194a1a9510SRong-En Fan * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
204a1a9510SRong-En Fan * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
214a1a9510SRong-En Fan * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
224a1a9510SRong-En Fan * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
234a1a9510SRong-En Fan * *
244a1a9510SRong-En Fan * Except as contained in this notice, the name(s) of the above copyright *
254a1a9510SRong-En Fan * holders shall not be used in advertising or otherwise to promote the *
264a1a9510SRong-En Fan * sale, use or other dealings in this Software without prior written *
274a1a9510SRong-En Fan * authorization. *
280e3d5408SPeter Wemm ****************************************************************************/
290e3d5408SPeter Wemm
300e3d5408SPeter Wemm /***************************************************************************
314a1a9510SRong-En Fan * *
320e3d5408SPeter Wemm * Author : Juergen Pfeifer *
330e3d5408SPeter Wemm * *
340e3d5408SPeter Wemm ***************************************************************************/
350e3d5408SPeter Wemm
360e3d5408SPeter Wemm #include "form.priv.h"
375ca44d1cSRong-En Fan
380e3d5408SPeter Wemm MODULE_ID("$Id: fty_regex.c,v 1.32 2020/12/12 01:15:37 tom Exp $")
390e3d5408SPeter Wemm
400e3d5408SPeter Wemm #if HAVE_REGEX_H_FUNCS || HAVE_LIB_PCRE2 /* We prefer POSIX regex */
410e3d5408SPeter Wemm
420e3d5408SPeter Wemm #if HAVE_PCRE2POSIX_H
430e3d5408SPeter Wemm #include <pcre2posix.h>
440e3d5408SPeter Wemm #elif HAVE_PCREPOSIX_H
450e3d5408SPeter Wemm #include <pcreposix.h>
464a1a9510SRong-En Fan #else
474a1a9510SRong-En Fan #include <regex.h>
480e3d5408SPeter Wemm #endif
490e3d5408SPeter Wemm
500e3d5408SPeter Wemm typedef struct
510e3d5408SPeter Wemm {
520e3d5408SPeter Wemm regex_t *pRegExp;
534a1a9510SRong-En Fan unsigned long *refCount;
544a1a9510SRong-En Fan }
550e3d5408SPeter Wemm RegExp_Arg;
560e3d5408SPeter Wemm
570e3d5408SPeter Wemm #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
580e3d5408SPeter Wemm #undef RETURN
590e3d5408SPeter Wemm static int reg_errno;
604a1a9510SRong-En Fan
614a1a9510SRong-En Fan static char *
620e3d5408SPeter Wemm RegEx_Init(char *instring)
630e3d5408SPeter Wemm {
640e3d5408SPeter Wemm reg_errno = 0;
650e3d5408SPeter Wemm return instring;
660e3d5408SPeter Wemm }
670e3d5408SPeter Wemm
680e3d5408SPeter Wemm static char *
690e3d5408SPeter Wemm RegEx_Error(int code)
700e3d5408SPeter Wemm {
710e3d5408SPeter Wemm reg_errno = code;
720e3d5408SPeter Wemm return 0;
730e3d5408SPeter Wemm }
740e3d5408SPeter Wemm
750e3d5408SPeter Wemm #define INIT register char *sp = RegEx_Init(instring);
760e3d5408SPeter Wemm #define GETC() (*sp++)
770e3d5408SPeter Wemm #define PEEKC() (*sp)
780e3d5408SPeter Wemm #define UNGETC(c) (--sp)
790e3d5408SPeter Wemm #define RETURN(c) return(c)
800e3d5408SPeter Wemm #define ERROR(c) return RegEx_Error(c)
810e3d5408SPeter Wemm
820e3d5408SPeter Wemm #if HAVE_REGEXP_H_FUNCS
830e3d5408SPeter Wemm #include <regexp.h>
844a1a9510SRong-En Fan #else
854a1a9510SRong-En Fan #include <regexpr.h>
860e3d5408SPeter Wemm #endif
870e3d5408SPeter Wemm
880e3d5408SPeter Wemm typedef struct
890e3d5408SPeter Wemm {
900e3d5408SPeter Wemm char *compiled_expression;
910e3d5408SPeter Wemm unsigned long *refCount;
920e3d5408SPeter Wemm }
930e3d5408SPeter Wemm RegExp_Arg;
940e3d5408SPeter Wemm
950e3d5408SPeter Wemm /* Maximum Length we allow for a compiled regular expression */
960e3d5408SPeter Wemm #define MAX_RX_LEN (2048)
970e3d5408SPeter Wemm #define RX_INCREMENT (256)
980e3d5408SPeter Wemm
990e3d5408SPeter Wemm #endif
1000e3d5408SPeter Wemm
1014a1a9510SRong-En Fan #if HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
1024a1a9510SRong-En Fan # define MAYBE_UNUSED
1030e3d5408SPeter Wemm #else
1040e3d5408SPeter Wemm # define MAYBE_UNUSED GCC_UNUSED
1050e3d5408SPeter Wemm #endif
1060e3d5408SPeter Wemm
1070e3d5408SPeter Wemm /*---------------------------------------------------------------------------
1085ca44d1cSRong-En Fan | Facility : libnform
1094a1a9510SRong-En Fan | Function : static void *Generic_RegularExpression_Type(void * arg)
1100e3d5408SPeter Wemm |
1110e3d5408SPeter Wemm | Description : Allocate structure for regex type argument.
1125ca44d1cSRong-En Fan |
1135ca44d1cSRong-En Fan | Return Values : Pointer to argument structure or NULL on error
1140e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
1150e3d5408SPeter Wemm static void *
Generic_RegularExpression_Type(void * arg MAYBE_UNUSED)1160e3d5408SPeter Wemm Generic_RegularExpression_Type(void *arg MAYBE_UNUSED)
1175ca44d1cSRong-En Fan {
1185ca44d1cSRong-En Fan #if HAVE_REGEX_H_FUNCS
1194a1a9510SRong-En Fan char *rx = (char *)arg;
1200e3d5408SPeter Wemm RegExp_Arg *preg = (RegExp_Arg *)0;
1210e3d5408SPeter Wemm
1220e3d5408SPeter Wemm if (rx)
1230e3d5408SPeter Wemm {
1240e3d5408SPeter Wemm preg = typeCalloc(RegExp_Arg, 1);
1250e3d5408SPeter Wemm
1260e3d5408SPeter Wemm if (preg)
1270e3d5408SPeter Wemm {
1280e3d5408SPeter Wemm T((T_CREATE("RegExp_Arg %p"), (void *)preg));
1290e3d5408SPeter Wemm if (((preg->pRegExp = typeMalloc(regex_t, 1)) != 0)
1300e3d5408SPeter Wemm && !regcomp(preg->pRegExp, rx,
1310e3d5408SPeter Wemm (REG_EXTENDED | REG_NOSUB | REG_NEWLINE)))
1320e3d5408SPeter Wemm {
1330e3d5408SPeter Wemm T((T_CREATE("regex_t %p"), (void *)preg->pRegExp));
1340e3d5408SPeter Wemm if ((preg->refCount = typeMalloc(unsigned long, 1)) != 0)
1355ca44d1cSRong-En Fan *(preg->refCount) = 1;
1360e3d5408SPeter Wemm }
1370e3d5408SPeter Wemm else
1380e3d5408SPeter Wemm {
1390e3d5408SPeter Wemm if (preg->pRegExp)
1404a1a9510SRong-En Fan free(preg->pRegExp);
1415ca44d1cSRong-En Fan free(preg);
1420e3d5408SPeter Wemm preg = (RegExp_Arg *)0;
1435ca44d1cSRong-En Fan }
1444a1a9510SRong-En Fan }
1450e3d5408SPeter Wemm }
1460e3d5408SPeter Wemm return ((void *)preg);
1474a1a9510SRong-En Fan #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
1484a1a9510SRong-En Fan char *rx = (char *)arg;
1495ca44d1cSRong-En Fan RegExp_Arg *pArg = (RegExp_Arg *)0;
1504a1a9510SRong-En Fan
1510e3d5408SPeter Wemm if (rx)
1520e3d5408SPeter Wemm {
1530e3d5408SPeter Wemm pArg = typeMalloc(RegExp_Arg, 1);
1540e3d5408SPeter Wemm
1554a1a9510SRong-En Fan if (pArg)
1560e3d5408SPeter Wemm {
1570e3d5408SPeter Wemm int blen = RX_INCREMENT;
1580e3d5408SPeter Wemm
1590e3d5408SPeter Wemm T((T_CREATE("RegExp_Arg %p"), pArg));
1600e3d5408SPeter Wemm pArg->compiled_expression = NULL;
1610e3d5408SPeter Wemm if ((pArg->refCount = typeMalloc(unsigned long, 1)) != 0)
1620e3d5408SPeter Wemm *(pArg->refCount) = 1;
1630e3d5408SPeter Wemm
1640e3d5408SPeter Wemm do
1650e3d5408SPeter Wemm {
1660e3d5408SPeter Wemm char *buf = typeMalloc(char, blen);
1670e3d5408SPeter Wemm
1680e3d5408SPeter Wemm if (buf)
1690e3d5408SPeter Wemm {
1700e3d5408SPeter Wemm #if HAVE_REGEXP_H_FUNCS
1710e3d5408SPeter Wemm char *last_pos = compile(rx, buf, &buf[blen], '\0');
1720e3d5408SPeter Wemm
1730e3d5408SPeter Wemm #else /* HAVE_REGEXPR_H_FUNCS */
1740e3d5408SPeter Wemm char *last_pos = compile(rx, buf, &buf[blen]);
1750e3d5408SPeter Wemm #endif
1760e3d5408SPeter Wemm if (reg_errno)
1774a1a9510SRong-En Fan {
1784a1a9510SRong-En Fan free(buf);
1790e3d5408SPeter Wemm if (reg_errno == 50)
1800e3d5408SPeter Wemm blen += RX_INCREMENT;
1810e3d5408SPeter Wemm else
1820e3d5408SPeter Wemm {
1830e3d5408SPeter Wemm free(pArg);
1840e3d5408SPeter Wemm pArg = NULL;
1850e3d5408SPeter Wemm break;
1860e3d5408SPeter Wemm }
1870e3d5408SPeter Wemm }
1880e3d5408SPeter Wemm else
1890e3d5408SPeter Wemm {
1900e3d5408SPeter Wemm pArg->compiled_expression = buf;
1910e3d5408SPeter Wemm break;
1920e3d5408SPeter Wemm }
1930e3d5408SPeter Wemm }
1940e3d5408SPeter Wemm }
1950e3d5408SPeter Wemm while (blen <= MAX_RX_LEN);
1960e3d5408SPeter Wemm }
1970e3d5408SPeter Wemm if (pArg && !pArg->compiled_expression)
1980e3d5408SPeter Wemm {
1990e3d5408SPeter Wemm free(pArg);
2004a1a9510SRong-En Fan pArg = NULL;
2014a1a9510SRong-En Fan }
2020e3d5408SPeter Wemm }
2030e3d5408SPeter Wemm return (void *)pArg;
2040e3d5408SPeter Wemm #else
2050e3d5408SPeter Wemm return 0;
2060e3d5408SPeter Wemm #endif
2070e3d5408SPeter Wemm }
2080e3d5408SPeter Wemm
2090e3d5408SPeter Wemm /*---------------------------------------------------------------------------
2100e3d5408SPeter Wemm | Facility : libnform
2110e3d5408SPeter Wemm | Function : static void *Make_RegularExpression_Type(va_list * ap)
2120e3d5408SPeter Wemm |
2130e3d5408SPeter Wemm | Description : Allocate structure for regex type argument.
2140e3d5408SPeter Wemm |
2150e3d5408SPeter Wemm | Return Values : Pointer to argument structure or NULL on error
2160e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
2170e3d5408SPeter Wemm static void *
Make_RegularExpression_Type(va_list * ap)2180e3d5408SPeter Wemm Make_RegularExpression_Type(va_list *ap)
2190e3d5408SPeter Wemm {
2200e3d5408SPeter Wemm char *rx = va_arg(*ap, char *);
2210e3d5408SPeter Wemm
2220e3d5408SPeter Wemm return Generic_RegularExpression_Type((void *)rx);
2230e3d5408SPeter Wemm }
2240e3d5408SPeter Wemm
2250e3d5408SPeter Wemm /*---------------------------------------------------------------------------
2264a1a9510SRong-En Fan | Facility : libnform
2274a1a9510SRong-En Fan | Function : static void *Copy_RegularExpression_Type(
2280e3d5408SPeter Wemm | const void * argp)
2290e3d5408SPeter Wemm |
2300e3d5408SPeter Wemm | Description : Copy structure for regex type argument.
2314a1a9510SRong-En Fan |
2320e3d5408SPeter Wemm | Return Values : Pointer to argument structure or NULL on error.
2330e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
2340e3d5408SPeter Wemm static void *
Copy_RegularExpression_Type(const void * argp MAYBE_UNUSED)2350e3d5408SPeter Wemm Copy_RegularExpression_Type(const void *argp MAYBE_UNUSED)
2360e3d5408SPeter Wemm {
2370e3d5408SPeter Wemm #if (HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS)
2380e3d5408SPeter Wemm const RegExp_Arg *ap = (const RegExp_Arg *)argp;
2390e3d5408SPeter Wemm const RegExp_Arg *result = (const RegExp_Arg *)0;
2400e3d5408SPeter Wemm
2410e3d5408SPeter Wemm if (ap)
2420e3d5408SPeter Wemm {
2430e3d5408SPeter Wemm *(ap->refCount) += 1;
2440e3d5408SPeter Wemm result = ap;
2450e3d5408SPeter Wemm }
2460e3d5408SPeter Wemm return (void *)result;
2470e3d5408SPeter Wemm #else
2480e3d5408SPeter Wemm return 0;
2490e3d5408SPeter Wemm #endif
2500e3d5408SPeter Wemm }
2510e3d5408SPeter Wemm
2520e3d5408SPeter Wemm /*---------------------------------------------------------------------------
2530e3d5408SPeter Wemm | Facility : libnform
2540e3d5408SPeter Wemm | Function : static void Free_RegularExpression_Type(void * argp)
2550e3d5408SPeter Wemm |
2560e3d5408SPeter Wemm | Description : Free structure for regex type argument.
2570e3d5408SPeter Wemm |
2580e3d5408SPeter Wemm | Return Values : -
2590e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
2600e3d5408SPeter Wemm static void
Free_RegularExpression_Type(void * argp MAYBE_UNUSED)2610e3d5408SPeter Wemm Free_RegularExpression_Type(void *argp MAYBE_UNUSED)
2620e3d5408SPeter Wemm {
2630e3d5408SPeter Wemm #if HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
2640e3d5408SPeter Wemm RegExp_Arg *ap = (RegExp_Arg *)argp;
2650e3d5408SPeter Wemm
2664a1a9510SRong-En Fan if (ap)
2674a1a9510SRong-En Fan {
2680e3d5408SPeter Wemm if (--(*(ap->refCount)) == 0)
2690e3d5408SPeter Wemm {
2704a1a9510SRong-En Fan #if HAVE_REGEX_H_FUNCS
2710e3d5408SPeter Wemm if (ap->pRegExp)
2720e3d5408SPeter Wemm {
2734a1a9510SRong-En Fan free(ap->refCount);
2740e3d5408SPeter Wemm regfree(ap->pRegExp);
2754a1a9510SRong-En Fan free(ap->pRegExp);
2764a1a9510SRong-En Fan }
2774a1a9510SRong-En Fan #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
2780e3d5408SPeter Wemm if (ap->compiled_expression)
2790e3d5408SPeter Wemm {
2804a1a9510SRong-En Fan free(ap->refCount);
2810e3d5408SPeter Wemm free(ap->compiled_expression);
2824a1a9510SRong-En Fan }
2834a1a9510SRong-En Fan #endif
2844a1a9510SRong-En Fan free(ap);
2850e3d5408SPeter Wemm }
2860e3d5408SPeter Wemm }
2870e3d5408SPeter Wemm #endif
2880e3d5408SPeter Wemm }
2894a1a9510SRong-En Fan
2904a1a9510SRong-En Fan /*---------------------------------------------------------------------------
2910e3d5408SPeter Wemm | Facility : libnform
2920e3d5408SPeter Wemm | Function : static bool Check_RegularExpression_Field(
2930e3d5408SPeter Wemm | FIELD * field,
2940e3d5408SPeter Wemm | const void * argp)
2950e3d5408SPeter Wemm |
2960e3d5408SPeter Wemm | Description : Validate buffer content to be a valid regular expression
2970e3d5408SPeter Wemm |
2980e3d5408SPeter Wemm | Return Values : TRUE - field is valid
2990e3d5408SPeter Wemm | FALSE - field is invalid
3000e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
3010e3d5408SPeter Wemm static bool
Check_RegularExpression_Field(FIELD * field MAYBE_UNUSED,const void * argp MAYBE_UNUSED)3020e3d5408SPeter Wemm Check_RegularExpression_Field(FIELD *field MAYBE_UNUSED,
3030e3d5408SPeter Wemm const void *argp MAYBE_UNUSED)
3047a69bbfbSPeter Wemm {
3050e3d5408SPeter Wemm bool match = FALSE;
3060e3d5408SPeter Wemm
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 *)
_nc_TYPE_REGEXP(void)351 _nc_TYPE_REGEXP(void)
352 {
353 return TYPE_REGEXP;
354 }
355 #endif
356
357 /* fty_regex.c ends here */
358