Subversion Repositories pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /* striter.c */
  2. /*****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  4. /*                                                                           */
  5. /* AS                                                                        */
  6. /*                                                                           */
  7. /* String Iteration                                                          */
  8. /*                                                                           */
  9. /*****************************************************************************/
  10.  
  11. #include "striter.h"
  12.  
  13. /* iterator state variables, used in loop */
  14.  
  15. typedef struct
  16. {
  17.   Boolean this_escaped, next_escaped;
  18. } iter_data_t;
  19.  
  20. /*!------------------------------------------------------------------------
  21.  * \fn     iterate_quote_core(const char *p_run, as_quoted_iterator_cb_data_t *p_cb_data, iter_data_t *p_iter_data)
  22.  * \brief  common quoting/escaping character handling while iterating string
  23.  * \param  p_run current position in string
  24.  * \param  p_cb_data, p_iter_data iteration callback
  25.  * \return True if this was a special character
  26.  * ------------------------------------------------------------------------ */
  27.  
  28. static Boolean iterate_quote_core(const char *p_run, as_quoted_iterator_cb_data_t *p_cb_data, iter_data_t *p_iter_data)
  29. {
  30.   p_iter_data->next_escaped = False;
  31.   switch(*p_run)
  32.   {
  33.     case '\\':
  34.       if ((p_cb_data->in_single_quote || p_cb_data->in_double_quote) && !p_iter_data->this_escaped)
  35.         p_iter_data->next_escaped = True;
  36.       return True;
  37.     case '\'':
  38.       if (p_cb_data->in_double_quote) { }
  39.       else if (!p_cb_data->in_single_quote && (!p_cb_data->qualify_quote || p_cb_data->qualify_quote(p_cb_data->p_str, p_run)))
  40.         p_cb_data->in_single_quote = True;
  41.       else if (!p_iter_data->this_escaped) /* skip escaped ' in '...' */
  42.         p_cb_data->in_single_quote = False;
  43.       return True;
  44.     case '"':
  45.       if (p_cb_data->in_single_quote) { }
  46.       else if (!p_cb_data->in_double_quote)
  47.         p_cb_data->in_double_quote = True;
  48.       else if (!p_iter_data->this_escaped) /* skip escaped " in "..." */
  49.         p_cb_data->in_double_quote = False;
  50.       return True;
  51.     default:
  52.       return False;
  53.   }
  54. }
  55.  
  56. /*!------------------------------------------------------------------------
  57.  * \fn     as_iterate_str(const char *p_str, as_quoted_iterator_cb_t callback, as_quoted_iterator_cb_data_t *p_cb_data)
  58.  * \brief  iterate through string, detecting quoted areas
  59.  * \param  p_str string to iterate through
  60.  * \param  callback is called for all characters outside quoted areas
  61.  * \param  p_cb_data callback data
  62.  * ------------------------------------------------------------------------ */
  63.  
  64. void as_iterate_str(const char *p_str, as_quoted_iterator_cb_t callback, as_quoted_iterator_cb_data_t *p_cb_data)
  65. {
  66.   iter_data_t iter_data;
  67.   int n_extra_skip;
  68.   const char *p_run;
  69.  
  70.   p_cb_data->p_str = p_str;
  71.   p_cb_data->in_single_quote =
  72.   p_cb_data->in_double_quote = False;
  73.  
  74.   for (p_run = p_str, iter_data.this_escaped = False;
  75.        *p_run;
  76.        p_run += (1 + n_extra_skip), iter_data.this_escaped = iter_data.next_escaped)
  77.   {
  78.     n_extra_skip = 0;
  79.  
  80.     (void)iterate_quote_core(p_run, p_cb_data, &iter_data);
  81.     n_extra_skip = callback(p_run, p_cb_data);
  82.     if (n_extra_skip < 0)
  83.       return;
  84.   }
  85. }
  86.  
  87. /*!------------------------------------------------------------------------
  88.  * \fn     as_iterate_str_quoted(const char *p_str, as_quoted_iterator_cb_t callback, as_quoted_iterator_cb_data_t *p_cb_data)
  89.  * \brief  iterate through string, skipping quoted areas
  90.  * \param  p_str string to iterate through
  91.  * \param  callback is called for all characters outside quoted areas
  92.  * \param  p_cb_data callback data
  93.  * ------------------------------------------------------------------------ */
  94.  
  95. void as_iterate_str_quoted(const char *p_str, as_quoted_iterator_cb_t callback, as_quoted_iterator_cb_data_t *p_cb_data)
  96. {
  97.   iter_data_t iter_data;
  98.   int n_extra_skip;
  99.   const char *p_run;
  100.  
  101.   p_cb_data->p_str = p_str;
  102.   p_cb_data->in_single_quote =
  103.   p_cb_data->in_double_quote = False;
  104.  
  105.   for (p_run = p_str, iter_data.this_escaped = False;
  106.        *p_run;
  107.        p_run += (1 + n_extra_skip), iter_data.this_escaped = iter_data.next_escaped)
  108.   {
  109.     if (p_cb_data->callback_before && !p_cb_data->in_single_quote && !p_cb_data->in_double_quote)
  110.     {
  111.       n_extra_skip = callback(p_run, p_cb_data);
  112.       if (n_extra_skip < 0)
  113.         return;
  114.     }
  115.     else
  116.       n_extra_skip = 0;
  117.  
  118.     if (!iterate_quote_core(p_run, p_cb_data, &iter_data)
  119.      && !p_cb_data->callback_before
  120.      && !p_cb_data->in_single_quote
  121.      && !p_cb_data->in_double_quote)
  122.     {
  123.       n_extra_skip = callback(p_run, p_cb_data);
  124.       if (n_extra_skip < 0)
  125.         return;
  126.     }
  127.   }
  128. }
  129.