/* ========================================================================== */
/*! \file
 * \brief Test of \c posix_regcomp() and \c posix_regexec() implementation
 *
 * Copyright (c) 2015-2024 by the developers. See the LICENSE file for details.
 */


/* ========================================================================== */
/* Include headers */

#include "posix.h"  /* Include this first because of feature test macros */

#include <stdio.h>
#include <string.h>

#include "config.h"

#include "test.h"
#include "test_regex.h"


/* ========================================================================== */
/*! \addtogroup TEST */
/*! @{ */


/* ========================================================================== */
/* Print error message if system failed to compile a regular expression
 *
 * \param[in] code  Error code
 * \param[in] ere   Pointer to compiled ERE
 */

#if CFG_USE_CLB || CFG_USE_XSI
static void  print_ere_error(int  code, api_posix_regex_t*  ere)
{
   size_t  len;
   char*  buf = NULL;

#  if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI
   /* Don't use NLS for error messages on stderr */
   api_posix_setlocale(API_POSIX_LC_MESSAGES, "POSIX");
#  endif  /* CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI */
   len = api_posix_regerror(code, ere, buf, 0);
   buf = (char*) api_posix_malloc(len);
   if(NULL == buf)
   {
      fprintf(stderr, TEST_TAB "Out of memory\n");
   }
   else
   {
      api_posix_regerror(code, ere, buf, len);
      fprintf(stderr, TEST_TAB "%s\n", buf);
      api_posix_free((void*) buf);
   }
#  if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI
   api_posix_setlocale(API_POSIX_LC_MESSAGES, "");
#  endif  /* CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI */
}
#endif  /* CFG_USE_CLB || CFG_USE_XSI */


/* ========================================================================== */
/*! \brief Test \c api_posix_regcomp() and \c api_posix_regexec() implementation
 *
 * The following cases are tested:
 * - Single field with arbitrary characters
 * - Literal dot character
 * - Bracket expression (first element)
 * - Bracket expression (second element)
 * - Start and end of line
 *
 * \return
 * - \c EXIT_SUCCESS on success
 * - \c EXIT_FAILURE on error
 */

int  test_regex(void)
{
   int  res = API_POSIX_EXIT_SUCCESS;
#if CFG_USE_CLB || CFG_USE_XSI
#  define TS_NUM  (size_t) 5  /* Number of patterns and test strings */
   static const char*  pat[TS_NUM] =  {
      "This.*string",
      "This \\. is a dot",
      "Bracket expression: [Xa]",
      "Bracket expression: [Xa]",
      "^Test$"
   };
   static const char*  ts[TS_NUM] =
   {
      "This is an ASCII string",
      "This . is a dot",
      "Bracket expression: X",
      "Bracket expression: a",
      "Test"
   };
   size_t  i;
   api_posix_regex_t  ere[TS_NUM];
   int  rv;

   /* Compile extended regular expression */
   for(i = 0; i < TS_NUM; ++i)
   {
      /* Compile regular expression if required */
      rv = api_posix_regcomp(&ere[i], pat[i],
                             API_POSIX_REG_EXTENDED | API_POSIX_REG_NOSUB);
      if(rv)
      {
         print_error("'api_posix_regcomp()' reported error");
         fprintf(stderr, TEST_TAB "Pattern: \"%s\"\n", pat[i]);
         print_ere_error(rv, &ere[i]);
         res = API_POSIX_EXIT_FAILURE;
         break;
      }
   }

   if(API_POSIX_EXIT_SUCCESS == res)
   {
      /* Check extended regular expression matching */
      for(i = 0; i < TS_NUM; ++i)
      {
         rv = api_posix_regexec(&ere[i], ts[i], 0, NULL, 0);
         if(rv)
         {
            print_error("'api_posix_regexec()' reported error");
            fprintf(stderr, TEST_TAB "Pattern: \"%s\"\n", pat[i]);
            fprintf(stderr, TEST_TAB "String : \"%s\"\n", ts[i]);
            print_ere_error(rv, &ere[i]);
            res = API_POSIX_EXIT_FAILURE;
            break;
         }
      }
      /* Release ressourced for regular expressions */
      for(i = 0; i < TS_NUM; ++i)  { api_posix_regfree(&ere[i]); }
   }
#else  /* CFG_USE_CLB || CFG_USE_XSI */
   /* Not supported */
   res = API_POSIX_EXIT_FAILURE;
#endif  /* CFG_USE_CLB || CFG_USE_XSI */

   return(res);
}


/*! @} */

/* EOF */
