LCOV - code coverage report
Current view: top level - src/backend/tsearch - regis.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 98 125 78.4 %
Date: 2019-11-21 14:06:36 Functions: 5 6 83.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * regis.c
       4             :  *      Fast regex subset
       5             :  *
       6             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
       7             :  *
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *    src/backend/tsearch/regis.c
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : 
      15             : #include "postgres.h"
      16             : 
      17             : #include "tsearch/dicts/regis.h"
      18             : #include "tsearch/ts_locale.h"
      19             : 
      20             : #define RS_IN_ONEOF 1
      21             : #define RS_IN_ONEOF_IN  2
      22             : #define RS_IN_NONEOF    3
      23             : #define RS_IN_WAIT  4
      24             : 
      25             : 
      26             : /*
      27             :  * Test whether a regex is of the subset supported here.
      28             :  * Keep this in sync with RS_compile!
      29             :  */
      30             : bool
      31         564 : RS_isRegis(const char *str)
      32             : {
      33         564 :     int         state = RS_IN_WAIT;
      34         564 :     const char *c = str;
      35             : 
      36        3984 :     while (*c)
      37             :     {
      38        2948 :         if (state == RS_IN_WAIT)
      39             :         {
      40         746 :             if (t_isalpha(c))
      41             :                  /* okay */ ;
      42         586 :             else if (t_iseq(c, '['))
      43         494 :                 state = RS_IN_ONEOF;
      44             :             else
      45          92 :                 return false;
      46             :         }
      47        2202 :         else if (state == RS_IN_ONEOF)
      48             :         {
      49         494 :             if (t_iseq(c, '^'))
      50         494 :                 state = RS_IN_NONEOF;
      51           0 :             else if (t_isalpha(c))
      52           0 :                 state = RS_IN_ONEOF_IN;
      53             :             else
      54           0 :                 return false;
      55             :         }
      56        1708 :         else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
      57             :         {
      58        3416 :             if (t_isalpha(c))
      59             :                  /* okay */ ;
      60         494 :             else if (t_iseq(c, ']'))
      61         494 :                 state = RS_IN_WAIT;
      62             :             else
      63           0 :                 return false;
      64             :         }
      65             :         else
      66           0 :             elog(ERROR, "internal error in RS_isRegis: state %d", state);
      67        2856 :         c += pg_mblen(c);
      68             :     }
      69             : 
      70         472 :     return (state == RS_IN_WAIT);
      71             : }
      72             : 
      73             : static RegisNode *
      74         540 : newRegisNode(RegisNode *prev, int len)
      75             : {
      76             :     RegisNode  *ptr;
      77             : 
      78         540 :     ptr = (RegisNode *) palloc0(RNHDRSZ + len + 1);
      79         540 :     if (prev)
      80          68 :         prev->next = ptr;
      81         540 :     return ptr;
      82             : }
      83             : 
      84             : void
      85         472 : RS_compile(Regis *r, bool issuffix, const char *str)
      86             : {
      87         472 :     int         len = strlen(str);
      88         472 :     int         state = RS_IN_WAIT;
      89         472 :     const char *c = str;
      90         472 :     RegisNode  *ptr = NULL;
      91             : 
      92         472 :     memset(r, 0, sizeof(Regis));
      93         472 :     r->issuffix = (issuffix) ? 1 : 0;
      94             : 
      95        3532 :     while (*c)
      96             :     {
      97        2588 :         if (state == RS_IN_WAIT)
      98             :         {
      99         540 :             if (t_isalpha(c))
     100             :             {
     101          68 :                 if (ptr)
     102          68 :                     ptr = newRegisNode(ptr, len);
     103             :                 else
     104           0 :                     ptr = r->node = newRegisNode(NULL, len);
     105          68 :                 COPYCHAR(ptr->data, c);
     106          68 :                 ptr->type = RSF_ONEOF;
     107          68 :                 ptr->len = pg_mblen(c);
     108             :             }
     109         472 :             else if (t_iseq(c, '['))
     110             :             {
     111         472 :                 if (ptr)
     112           0 :                     ptr = newRegisNode(ptr, len);
     113             :                 else
     114         472 :                     ptr = r->node = newRegisNode(NULL, len);
     115         472 :                 ptr->type = RSF_ONEOF;
     116         472 :                 state = RS_IN_ONEOF;
     117             :             }
     118             :             else                /* shouldn't get here */
     119           0 :                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     120             :         }
     121        2048 :         else if (state == RS_IN_ONEOF)
     122             :         {
     123         472 :             if (t_iseq(c, '^'))
     124             :             {
     125         472 :                 ptr->type = RSF_NONEOF;
     126         472 :                 state = RS_IN_NONEOF;
     127             :             }
     128           0 :             else if (t_isalpha(c))
     129             :             {
     130           0 :                 COPYCHAR(ptr->data, c);
     131           0 :                 ptr->len = pg_mblen(c);
     132           0 :                 state = RS_IN_ONEOF_IN;
     133             :             }
     134             :             else                /* shouldn't get here */
     135           0 :                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     136             :         }
     137        1576 :         else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
     138             :         {
     139        3152 :             if (t_isalpha(c))
     140             :             {
     141        1104 :                 COPYCHAR(ptr->data + ptr->len, c);
     142        1104 :                 ptr->len += pg_mblen(c);
     143             :             }
     144         472 :             else if (t_iseq(c, ']'))
     145         472 :                 state = RS_IN_WAIT;
     146             :             else                /* shouldn't get here */
     147           0 :                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     148             :         }
     149             :         else
     150           0 :             elog(ERROR, "internal error in RS_compile: state %d", state);
     151        2588 :         c += pg_mblen(c);
     152             :     }
     153             : 
     154         472 :     if (state != RS_IN_WAIT)    /* shouldn't get here */
     155           0 :         elog(ERROR, "invalid regis pattern: \"%s\"", str);
     156             : 
     157         472 :     ptr = r->node;
     158        1484 :     while (ptr)
     159             :     {
     160         540 :         r->nchar++;
     161         540 :         ptr = ptr->next;
     162             :     }
     163         472 : }
     164             : 
     165             : void
     166           0 : RS_free(Regis *r)
     167             : {
     168           0 :     RegisNode  *ptr = r->node,
     169             :                *tmp;
     170             : 
     171           0 :     while (ptr)
     172             :     {
     173           0 :         tmp = ptr->next;
     174           0 :         pfree(ptr);
     175           0 :         ptr = tmp;
     176             :     }
     177             : 
     178           0 :     r->node = NULL;
     179           0 : }
     180             : 
     181             : static bool
     182         472 : mb_strchr(char *str, char *c)
     183             : {
     184             :     int         clen,
     185             :                 plen,
     186             :                 i;
     187         472 :     char       *ptr = str;
     188         472 :     bool        res = false;
     189             : 
     190         472 :     clen = pg_mblen(c);
     191        2024 :     while (*ptr && !res)
     192             :     {
     193        1080 :         plen = pg_mblen(ptr);
     194        1080 :         if (plen == clen)
     195             :         {
     196        1080 :             i = plen;
     197        1080 :             res = true;
     198        2184 :             while (i--)
     199        1080 :                 if (*(ptr + i) != *(c + i))
     200             :                 {
     201        1056 :                     res = false;
     202        1056 :                     break;
     203             :                 }
     204             :         }
     205             : 
     206        1080 :         ptr += plen;
     207             :     }
     208             : 
     209         472 :     return res;
     210             : }
     211             : 
     212             : bool
     213         472 : RS_execute(Regis *r, char *str)
     214             : {
     215         472 :     RegisNode  *ptr = r->node;
     216         472 :     char       *c = str;
     217         472 :     int         len = 0;
     218             : 
     219        3592 :     while (*c)
     220             :     {
     221        2648 :         len++;
     222        2648 :         c += pg_mblen(c);
     223             :     }
     224             : 
     225         472 :     if (len < r->nchar)
     226          24 :         return 0;
     227             : 
     228         448 :     c = str;
     229         448 :     if (r->issuffix)
     230             :     {
     231         448 :         len -= r->nchar;
     232        3072 :         while (len-- > 0)
     233        2176 :             c += pg_mblen(c);
     234             :     }
     235             : 
     236             : 
     237        1368 :     while (ptr)
     238             :     {
     239         472 :         switch (ptr->type)
     240             :         {
     241             :             case RSF_ONEOF:
     242          24 :                 if (!mb_strchr((char *) ptr->data, c))
     243           0 :                     return false;
     244          24 :                 break;
     245             :             case RSF_NONEOF:
     246         448 :                 if (mb_strchr((char *) ptr->data, c))
     247           0 :                     return false;
     248         448 :                 break;
     249             :             default:
     250           0 :                 elog(ERROR, "unrecognized regis node type: %d", ptr->type);
     251             :         }
     252         472 :         ptr = ptr->next;
     253         472 :         c += pg_mblen(c);
     254             :     }
     255             : 
     256         448 :     return true;
     257             : }

Generated by: LCOV version 1.13