LCOV - code coverage report
Current view: directory - libdm/regex - parse_rx.c (source / functions) Found Hit Coverage
Test: unnamed Lines: 179 82 45.8 %
Date: 2010-04-13 Functions: 9 7 77.8 %

       1                 : /*
       2                 :  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
       3                 :  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
       4                 :  *
       5                 :  * This file is part of the device-mapper userspace tools.
       6                 :  *
       7                 :  * This copyrighted material is made available to anyone wishing to use,
       8                 :  * modify, copy, or redistribute it subject to the terms and conditions
       9                 :  * of the GNU Lesser General Public License v.2.1.
      10                 :  *
      11                 :  * You should have received a copy of the GNU Lesser General Public License
      12                 :  * along with this program; if not, write to the Free Software Foundation,
      13                 :  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      14                 :  */
      15                 : 
      16                 : #include "dmlib.h"
      17                 : #include "parse_rx.h"
      18                 : 
      19                 : struct parse_sp {               /* scratch pad for the parsing process */
      20                 :         struct dm_pool *mem;
      21                 :         int type;               /* token type, 0 indicates a charset */
      22                 :         dm_bitset_t charset;    /* The current charset */
      23                 :         const char *cursor;     /* where we are in the regex */
      24                 :         const char *rx_end;     /* 1pte for the expression being parsed */
      25                 : };
      26                 : 
      27                 : static struct rx_node *_or_term(struct parse_sp *ps);
      28                 : 
      29               0 : static void _single_char(struct parse_sp *ps, unsigned int c, const char *ptr)
      30                 : {
      31               0 :         ps->type = 0;
      32               0 :         ps->cursor = ptr + 1;
      33               0 :         dm_bit_clear_all(ps->charset);
      34               0 :         dm_bit_set(ps->charset, c);
      35               0 : }
      36                 : 
      37                 : /*
      38                 :  * Get the next token from the regular expression.
      39                 :  * Returns: 1 success, 0 end of input, -1 error.
      40                 :  */
      41            5504 : static int _rx_get_token(struct parse_sp *ps)
      42                 : {
      43            5504 :         int neg = 0, range = 0;
      44            5504 :         char c, lc = 0;
      45            5504 :         const char *ptr = ps->cursor;
      46            5504 :         if (ptr == ps->rx_end) {     /* end of input ? */
      47               3 :                 ps->type = -1;
      48               3 :                 return 0;
      49                 :         }
      50                 : 
      51            5501 :         switch (*ptr) {
      52                 :                 /* charsets and ncharsets */
      53                 :         case '[':
      54               0 :                 ptr++;
      55               0 :                 if (*ptr == '^') {
      56               0 :                         dm_bit_set_all(ps->charset);
      57                 : 
      58                 :                         /* never transition on zero */
      59               0 :                         dm_bit_clear(ps->charset, 0);
      60               0 :                         neg = 1;
      61               0 :                         ptr++;
      62                 : 
      63                 :                 } else
      64               0 :                         dm_bit_clear_all(ps->charset);
      65                 : 
      66               0 :                 while ((ptr < ps->rx_end) && (*ptr != ']')) {
      67               0 :                         if (*ptr == '\\') {
      68                 :                                 /* an escaped character */
      69               0 :                                 ptr++;
      70               0 :                                 switch (*ptr) {
      71                 :                                 case 'n':
      72               0 :                                         c = '\n';
      73               0 :                                         break;
      74                 :                                 case 'r':
      75               0 :                                         c = '\r';
      76               0 :                                         break;
      77                 :                                 case 't':
      78               0 :                                         c = '\t';
      79               0 :                                         break;
      80                 :                                 default:
      81               0 :                                         c = *ptr;
      82                 :                                 }
      83               0 :                         } else if (*ptr == '-' && lc) {
      84                 :                                 /* we've got a range on our hands */
      85               0 :                                 range = 1;
      86               0 :                                 ptr++;
      87               0 :                                 if (ptr == ps->rx_end) {
      88               0 :                                         log_error("Incomplete range"
      89                 :                                                   "specification");
      90               0 :                                         return -1;
      91                 :                                 }
      92               0 :                                 c = *ptr;
      93                 :                         } else
      94               0 :                                 c = *ptr;
      95                 : 
      96               0 :                         if (range) {
      97                 :                                 /* add lc - c into the bitset */
      98               0 :                                 if (lc > c) {
      99               0 :                                         char tmp = c;
     100               0 :                                         c = lc;
     101               0 :                                         lc = tmp;
     102                 :                                 }
     103                 : 
     104               0 :                                 for (; lc <= c; lc++) {
     105               0 :                                         if (neg)
     106               0 :                                                 dm_bit_clear(ps->charset, lc);
     107                 :                                         else
     108               0 :                                                 dm_bit_set(ps->charset, lc);
     109                 :                                 }
     110               0 :                                 range = 0;
     111                 :                         } else {
     112                 :                                 /* add c into the bitset */
     113               0 :                                 if (neg)
     114               0 :                                         dm_bit_clear(ps->charset, c);
     115                 :                                 else
     116               0 :                                         dm_bit_set(ps->charset, c);
     117                 :                         }
     118               0 :                         ptr++;
     119               0 :                         lc = c;
     120                 :                 }
     121                 : 
     122               0 :                 if (ptr >= ps->rx_end) {
     123               0 :                         ps->type = -1;
     124               0 :                         return -1;
     125                 :                 }
     126                 : 
     127               0 :                 ps->type = 0;
     128               0 :                 ps->cursor = ptr + 1;
     129               0 :                 break;
     130                 : 
     131                 :                 /* These characters are special, we just return their ASCII
     132                 :                    codes as the type.  Sorted into ascending order to help the
     133                 :                    compiler */
     134                 :         case '(':
     135                 :         case ')':
     136                 :         case '*':
     137                 :         case '+':
     138                 :         case '?':
     139                 :         case '|':
     140            1850 :                 ps->type = (int) *ptr;
     141            1850 :                 ps->cursor = ptr + 1;
     142            1850 :                 break;
     143                 : 
     144                 :         case '^':
     145               0 :                 _single_char(ps, HAT_CHAR, ptr);
     146               0 :                 break;
     147                 : 
     148                 :         case '$':
     149               0 :                 _single_char(ps, DOLLAR_CHAR, ptr);
     150               0 :                 break;
     151                 : 
     152                 :         case '.':
     153                 :                 /* The 'all but newline' character set */
     154             311 :                 ps->type = 0;
     155             311 :                 ps->cursor = ptr + 1;
     156             311 :                 dm_bit_set_all(ps->charset);
     157             311 :                 dm_bit_clear(ps->charset, (int) '\n');
     158             311 :                 dm_bit_clear(ps->charset, (int) '\r');
     159             311 :                 dm_bit_clear(ps->charset, 0);
     160             311 :                 break;
     161                 : 
     162                 :         case '\\':
     163                 :                 /* escaped character */
     164               0 :                 ptr++;
     165               0 :                 if (ptr >= ps->rx_end) {
     166               0 :                         log_error("Badly quoted character at end "
     167                 :                                   "of expression");
     168               0 :                         ps->type = -1;
     169               0 :                         return -1;
     170                 :                 }
     171                 : 
     172               0 :                 ps->type = 0;
     173               0 :                 ps->cursor = ptr + 1;
     174               0 :                 dm_bit_clear_all(ps->charset);
     175               0 :                 switch (*ptr) {
     176                 :                 case 'n':
     177               0 :                         dm_bit_set(ps->charset, (int) '\n');
     178               0 :                         break;
     179                 :                 case 'r':
     180               0 :                         dm_bit_set(ps->charset, (int) '\r');
     181               0 :                         break;
     182                 :                 case 't':
     183               0 :                         dm_bit_set(ps->charset, (int) '\t');
     184               0 :                         break;
     185                 :                 default:
     186               0 :                         dm_bit_set(ps->charset, (int) *ptr);
     187                 :                 }
     188               0 :                 break;
     189                 : 
     190                 :         default:
     191                 :                 /* add a single character to the bitset */
     192            3340 :                 ps->type = 0;
     193            3340 :                 ps->cursor = ptr + 1;
     194            3340 :                 dm_bit_clear_all(ps->charset);
     195            3340 :                 dm_bit_set(ps->charset, (int) *ptr);
     196                 :                 break;
     197                 :         }
     198                 : 
     199            5501 :         return 1;
     200                 : }
     201                 : 
     202            7612 : static struct rx_node *_node(struct dm_pool *mem, int type,
     203                 :                              struct rx_node *l, struct rx_node *r)
     204                 : {
     205            7612 :         struct rx_node *n = dm_pool_zalloc(mem, sizeof(*n));
     206                 : 
     207            7612 :         if (n) {
     208            7612 :                 if (!(n->charset = dm_bitset_create(mem, 256))) {
     209               0 :                         dm_pool_free(mem, n);
     210               0 :                         return NULL;
     211                 :                 }
     212                 : 
     213            7612 :                 n->type = type;
     214            7612 :                 n->left = l;
     215            7612 :                 n->right = r;
     216                 :         }
     217                 : 
     218            7612 :         return n;
     219                 : }
     220                 : 
     221            4886 : static struct rx_node *_term(struct parse_sp *ps)
     222                 : {
     223                 :         struct rx_node *n;
     224                 : 
     225            4886 :         switch (ps->type) {
     226                 :         case 0:
     227            3651 :                 if (!(n = _node(ps->mem, CHARSET, NULL, NULL))) {
     228               0 :                         stack;
     229               0 :                         return NULL;
     230                 :                 }
     231                 : 
     232            3651 :                 dm_bit_copy(n->charset, ps->charset);
     233            3651 :                 _rx_get_token(ps);      /* match charset */
     234            3651 :                 break;
     235                 : 
     236                 :         case '(':
     237             616 :                 _rx_get_token(ps);      /* match '(' */
     238             616 :                 n = _or_term(ps);
     239             616 :                 if (ps->type != ')') {
     240               0 :                         log_error("missing ')' in regular expression");
     241               0 :                         return 0;
     242                 :                 }
     243             616 :                 _rx_get_token(ps);      /* match ')' */
     244             616 :                 break;
     245                 : 
     246                 :         default:
     247             619 :                 n = 0;
     248                 :         }
     249                 : 
     250            4886 :         return n;
     251                 : }
     252                 : 
     253            4886 : static struct rx_node *_closure_term(struct parse_sp *ps)
     254                 : {
     255                 :         struct rx_node *l, *n;
     256                 : 
     257            4886 :         if (!(l = _term(ps)))
     258             619 :                 return NULL;
     259                 : 
     260                 :         for (;;) {
     261            4580 :                 switch (ps->type) {
     262                 :                 case '*':
     263             313 :                         n = _node(ps->mem, STAR, l, NULL);
     264             313 :                         break;
     265                 : 
     266                 :                 case '+':
     267               0 :                         n = _node(ps->mem, PLUS, l, NULL);
     268               0 :                         break;
     269                 : 
     270                 :                 case '?':
     271               0 :                         n = _node(ps->mem, QUEST, l, NULL);
     272               0 :                         break;
     273                 : 
     274                 :                 default:
     275            4267 :                         return l;
     276                 :                 }
     277                 : 
     278             313 :                 if (!n) {
     279               0 :                         stack;
     280               0 :                         return NULL;
     281                 :                 }
     282                 : 
     283             313 :                 _rx_get_token(ps);
     284             313 :                 l = n;
     285             313 :         }
     286                 : 
     287                 :         return n;
     288                 : }
     289                 : 
     290            4886 : static struct rx_node *_cat_term(struct parse_sp *ps)
     291                 : {
     292                 :         struct rx_node *l, *r, *n;
     293                 : 
     294            4886 :         if (!(l = _closure_term(ps)))
     295             619 :                 return NULL;
     296                 : 
     297            4267 :         if (ps->type == '|')
     298             305 :                 return l;
     299                 : 
     300            3962 :         if (!(r = _cat_term(ps)))
     301             619 :                 return l;
     302                 : 
     303            3343 :         if (!(n = _node(ps->mem, CAT, l, r)))
     304               0 :                 stack;
     305                 : 
     306            3343 :         return n;
     307                 : }
     308                 : 
     309             924 : static struct rx_node *_or_term(struct parse_sp *ps)
     310                 : {
     311                 :         struct rx_node *l, *r, *n;
     312                 : 
     313             924 :         if (!(l = _cat_term(ps)))
     314               0 :                 return NULL;
     315                 : 
     316             924 :         if (ps->type != '|')
     317             619 :                 return l;
     318                 : 
     319             305 :         _rx_get_token(ps);              /* match '|' */
     320                 : 
     321             305 :         if (!(r = _or_term(ps))) {
     322               0 :                 log_error("Badly formed 'or' expression");
     323               0 :                 return NULL;
     324                 :         }
     325                 : 
     326             305 :         if (!(n = _node(ps->mem, OR, l, r)))
     327               0 :                 stack;
     328                 : 
     329             305 :         return n;
     330                 : }
     331                 : 
     332               3 : struct rx_node *rx_parse_tok(struct dm_pool *mem,
     333                 :                              const char *begin, const char *end)
     334                 : {
     335                 :         struct rx_node *r;
     336               3 :         struct parse_sp *ps = dm_pool_zalloc(mem, sizeof(*ps));
     337                 : 
     338               3 :         if (!ps) {
     339               0 :                 stack;
     340               0 :                 return NULL;
     341                 :         }
     342                 : 
     343               3 :         ps->mem = mem;
     344               3 :         ps->charset = dm_bitset_create(mem, 256);
     345               3 :         ps->cursor = begin;
     346               3 :         ps->rx_end = end;
     347               3 :         _rx_get_token(ps);              /* load the first token */
     348                 : 
     349               3 :         if (!(r = _or_term(ps))) {
     350               0 :                 log_error("Parse error in regex");
     351               0 :                 dm_pool_free(mem, ps);
     352                 :         }
     353                 : 
     354               3 :         return r;
     355                 : }
     356                 : 
     357               0 : struct rx_node *rx_parse_str(struct dm_pool *mem, const char *str)
     358                 : {
     359               0 :         return rx_parse_tok(mem, str, str + strlen(str));
     360                 : }

Generated by: LCOV version 1.7