LCOV - code coverage report
Current view: top level - src/backend/tsearch - regis.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 97 125 77.6 %
Date: 2017-09-29 15:12:54 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-2017, 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          65 : RS_isRegis(const char *str)
      32             : {
      33          65 :     int         state = RS_IN_WAIT;
      34          65 :     const char *c = str;
      35             : 
      36         507 :     while (*c)
      37             :     {
      38         377 :         if (state == RS_IN_WAIT)
      39             :         {
      40          78 :             if (t_isalpha(c))
      41             :                  /* okay */ ;
      42          65 :             else if (t_iseq(c, '['))
      43          65 :                 state = RS_IN_ONEOF;
      44             :             else
      45           0 :                 return false;
      46             :         }
      47         299 :         else if (state == RS_IN_ONEOF)
      48             :         {
      49          65 :             if (t_iseq(c, '^'))
      50          65 :                 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         234 :         else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
      57             :         {
      58         468 :             if (t_isalpha(c))
      59             :                  /* okay */ ;
      60          65 :             else if (t_iseq(c, ']'))
      61          65 :                 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         377 :         c += pg_mblen(c);
      68             :     }
      69             : 
      70          65 :     return (state == RS_IN_WAIT);
      71             : }
      72             : 
      73             : static RegisNode *
      74          78 : newRegisNode(RegisNode *prev, int len)
      75             : {
      76             :     RegisNode  *ptr;
      77             : 
      78          78 :     ptr = (RegisNode *) palloc0(RNHDRSZ + len + 1);
      79          78 :     if (prev)
      80          13 :         prev->next = ptr;
      81          78 :     return ptr;
      82             : }
      83             : 
      84             : void
      85          65 : RS_compile(Regis *r, bool issuffix, const char *str)
      86             : {
      87          65 :     int         len = strlen(str);
      88          65 :     int         state = RS_IN_WAIT;
      89          65 :     const char *c = str;
      90          65 :     RegisNode  *ptr = NULL;
      91             : 
      92          65 :     memset(r, 0, sizeof(Regis));
      93          65 :     r->issuffix = (issuffix) ? 1 : 0;
      94             : 
      95         507 :     while (*c)
      96             :     {
      97         377 :         if (state == RS_IN_WAIT)
      98             :         {
      99          78 :             if (t_isalpha(c))
     100             :             {
     101          13 :                 if (ptr)
     102          13 :                     ptr = newRegisNode(ptr, len);
     103             :                 else
     104           0 :                     ptr = r->node = newRegisNode(NULL, len);
     105          13 :                 COPYCHAR(ptr->data, c);
     106          13 :                 ptr->type = RSF_ONEOF;
     107          13 :                 ptr->len = pg_mblen(c);
     108             :             }
     109          65 :             else if (t_iseq(c, '['))
     110             :             {
     111          65 :                 if (ptr)
     112           0 :                     ptr = newRegisNode(ptr, len);
     113             :                 else
     114          65 :                     ptr = r->node = newRegisNode(NULL, len);
     115          65 :                 ptr->type = RSF_ONEOF;
     116          65 :                 state = RS_IN_ONEOF;
     117             :             }
     118             :             else                /* shouldn't get here */
     119           0 :                 elog(ERROR, "invalid regis pattern: \"%s\"", str);
     120             :         }
     121         299 :         else if (state == RS_IN_ONEOF)
     122             :         {
     123          65 :             if (t_iseq(c, '^'))
     124             :             {
     125          65 :                 ptr->type = RSF_NONEOF;
     126          65 :                 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         234 :         else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
     138             :         {
     139         468 :             if (t_isalpha(c))
     140             :             {
     141         169 :                 COPYCHAR(ptr->data + ptr->len, c);
     142         169 :                 ptr->len += pg_mblen(c);
     143             :             }
     144          65 :             else if (t_iseq(c, ']'))
     145          65 :                 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         377 :         c += pg_mblen(c);
     152             :     }
     153             : 
     154          65 :     if (state != RS_IN_WAIT)    /* shouldn't get here */
     155           0 :         elog(ERROR, "invalid regis pattern: \"%s\"", str);
     156             : 
     157          65 :     ptr = r->node;
     158         208 :     while (ptr)
     159             :     {
     160          78 :         r->nchar++;
     161          78 :         ptr = ptr->next;
     162             :     }
     163          65 : }
     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             : #ifdef USE_WIDE_UPPER_LOWER
     182             : static bool
     183         108 : mb_strchr(char *str, char *c)
     184             : {
     185             :     int         clen,
     186             :                 plen,
     187             :                 i;
     188         108 :     char       *ptr = str;
     189         108 :     bool        res = false;
     190             : 
     191         108 :     clen = pg_mblen(c);
     192         484 :     while (*ptr && !res)
     193             :     {
     194         268 :         plen = pg_mblen(ptr);
     195         268 :         if (plen == clen)
     196             :         {
     197         268 :             i = plen;
     198         268 :             res = true;
     199         544 :             while (i--)
     200         268 :                 if (*(ptr + i) != *(c + i))
     201             :                 {
     202         260 :                     res = false;
     203         260 :                     break;
     204             :                 }
     205             :         }
     206             : 
     207         268 :         ptr += plen;
     208             :     }
     209             : 
     210         108 :     return res;
     211             : }
     212             : #else
     213             : #define mb_strchr(s,c)  ( (strchr((s),*(c)) == NULL) ? false : true )
     214             : #endif
     215             : 
     216             : 
     217             : bool
     218         104 : RS_execute(Regis *r, char *str)
     219             : {
     220         104 :     RegisNode  *ptr = r->node;
     221         104 :     char       *c = str;
     222         104 :     int         len = 0;
     223             : 
     224         780 :     while (*c)
     225             :     {
     226         572 :         len++;
     227         572 :         c += pg_mblen(c);
     228             :     }
     229             : 
     230         104 :     if (len < r->nchar)
     231           4 :         return 0;
     232             : 
     233         100 :     c = str;
     234         100 :     if (r->issuffix)
     235             :     {
     236         100 :         len -= r->nchar;
     237         664 :         while (len-- > 0)
     238         464 :             c += pg_mblen(c);
     239             :     }
     240             : 
     241             : 
     242         308 :     while (ptr)
     243             :     {
     244         108 :         switch (ptr->type)
     245             :         {
     246             :             case RSF_ONEOF:
     247           8 :                 if (!mb_strchr((char *) ptr->data, c))
     248           0 :                     return false;
     249           8 :                 break;
     250             :             case RSF_NONEOF:
     251         100 :                 if (mb_strchr((char *) ptr->data, c))
     252           0 :                     return false;
     253         100 :                 break;
     254             :             default:
     255           0 :                 elog(ERROR, "unrecognized regis node type: %d", ptr->type);
     256             :         }
     257         108 :         ptr = ptr->next;
     258         108 :         c += pg_mblen(c);
     259             :     }
     260             : 
     261         100 :     return true;
     262             : }

Generated by: LCOV version 1.11