xref: /freebsd/contrib/ncurses/form/fty_regex.c (revision 5ca44d1c)
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