- merge changes from HEAD
[util-vserver.git] / lib / listparser.hc
1 // $Id: listparser.hc,v 1.5 2005/04/24 20:23:11 ensc Exp $    --*- c -*--
2
3 // Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 //  
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
8 //  
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //  
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <strings.h>
26
27 #define TONUMBER_uint64(S,E,B)          strtoll(S,E,B)
28 #define TONUMBER_uint32(S,E,B)          strtol (S,E,B)
29
30 #define ISNUMBER(TYPE,SHORT)                                            \
31   static inline ALWAYSINLINE bool                                       \
32   isNumber_##SHORT(char const **str,size_t *len,TYPE *res,char end_chr) \
33   {                                                                     \
34     char        *err_ptr;                                               \
35     if (**str=='^') {                                                   \
36       *res = ((TYPE)(1)) << TONUMBER_##SHORT(++*str, &err_ptr, 0);      \
37       if (len) --*len;                                                  \
38     }                                                                   \
39     else                                                                \
40       *res = TONUMBER_##SHORT(*str, &err_ptr, 0);                       \
41     return err_ptr>*str && *err_ptr==end_chr;                           \
42   }
43
44
45 #define LISTPARSER(TYPE,SHORT)                                          \
46   ISNUMBER(TYPE,SHORT)                                                  \
47   int                                                                   \
48   utilvserver_listparser_ ## SHORT(char const *str, size_t len,         \
49                                    char const **err_ptr,                \
50                                    size_t *err_len,                     \
51                                    TYPE * const flag,                   \
52                                    TYPE * const mask,                   \
53                                    TYPE (*func)(char const *,           \
54                                                 size_t, bool *))        \
55   {                                                                     \
56     if (len==0) len = strlen(str);                                      \
57     for (;len>0;) {                                                     \
58       char const        *ptr = strchr(str, ',');                        \
59       size_t            cnt;                                            \
60       TYPE              tmp = 0;                                        \
61       bool              is_neg     = false;                             \
62       bool              failed     = false;                             \
63                                                                         \
64       while (mask!=0 && len>0 && (*str=='!' || *str=='~')) {            \
65         is_neg = !is_neg;                                               \
66         ++str;                                                          \
67         --len;                                                          \
68       }                                                                 \
69                                                                         \
70       cnt = ptr ? (size_t)(ptr-str) : len;                              \
71       if (cnt>=len) { cnt=len; len=0; }                                 \
72       else len-=(cnt+1);                                                \
73                                                                         \
74       if (cnt==0)                                                       \
75         failed = true;                                                  \
76       else if (mask!=0 &&                                               \
77                (strncasecmp(str,"all",cnt)==0 ||                        \
78                 strncasecmp(str,"any",cnt)==0))                         \
79         tmp = ~(TYPE)(0);                                               \
80       else if (mask!=0 && strncasecmp(str,"none",cnt)==0) {}            \
81       else if (!isNumber_##SHORT(&str, &cnt, &tmp, str[cnt]))           \
82         tmp = (*func)(str,cnt, &failed);                                \
83                                                                         \
84       if (!failed) {                                                    \
85         if (!is_neg) *flag |=  tmp;                                     \
86         else         *flag &= ~tmp;                                     \
87         if (mask!=0) *mask |=  tmp;                                     \
88       }                                                                 \
89       else {                                                            \
90         if (err_ptr) *err_ptr = str;                                    \
91         if (err_len) *err_len = cnt;                                    \
92         return -1;                                                      \
93       }                                                                 \
94                                                                         \
95       if (ptr==0) break;                                                \
96       str = ptr+1;                                                      \
97     }                                                                   \
98                                                                         \
99     if (err_ptr) *err_ptr = 0;                                          \
100     if (err_len) *err_len = 0;                                          \
101     return 0;                                                           \
102   }