s3-lib: add srprs, primitives to build simple recursive parsers
[obnox/samba-ctdb.git] / source3 / lib / srprs.c
1 /*
2  * Samba Unix/Linux SMB client library
3  *
4  * Copyright (C) Gregor Beck 2010
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /**
21  * @file   srprs.c
22  * @author Gregor Beck <gb@sernet.de>
23  * @date   Aug 2010
24  * @brief  A simple recursive parser.
25  */
26
27 #include "srprs.h"
28 #include "cbuf.h"
29 #include <ctype.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <stdio.h>
33
34 bool srprs_skipws(const char** ptr) {
35         while (isspace(**ptr))
36                 ++(*ptr);
37         return true;
38 }
39
40 bool srprs_char(const char** ptr, char c) {
41         if (**ptr == c) {
42                 ++(*ptr);
43                 return true;
44         }
45         return false;
46 }
47
48 bool srprs_str(const char** ptr, const char* str, size_t len)
49 {
50         if (len == -1)
51                 len = strlen(str);
52
53         if (memcmp(*ptr, str, len) == 0) {
54                 *ptr += len;
55                 return true;
56         }
57         return false;
58 }
59
60 bool srprs_charset(const char** ptr, const char* set, cbuf* oss)
61 {
62         const char* p = strchr(set, **ptr);
63         if (p != NULL && *p != '\0') {
64                 cbuf_putc(oss, **ptr);
65                 ++(*ptr);
66                 return true;
67         }
68         return false;
69 }
70
71 bool srprs_charsetinv(const char** ptr, const char* set, cbuf* oss)
72 {
73         if ((**ptr != '\0') && (strchr(set, **ptr) == NULL)) {
74                 cbuf_putc(oss, **ptr);
75                 ++(*ptr);
76                 return true;
77         }
78         return false;
79 }
80
81
82
83 bool srprs_quoted_string(const char** ptr, cbuf* str, bool* cont)
84 {
85         const char* pos = *ptr;
86         const size_t spos = cbuf_getpos(str);
87
88         if (cont == NULL || *cont == false) {
89                 if (!srprs_char(&pos, '\"'))
90                         goto fail;
91         }
92
93         while (true) {
94                 while (srprs_charsetinv(&pos, "\\\"", str))
95                         ;
96
97                 switch (*pos) {
98                 case '\0':
99                         if (cont == NULL) {
100                                 goto fail;
101                         } else {
102                                 *ptr = pos;
103                                 *cont = true;
104                                 return true;
105                         }
106                 case '\"':
107                         *ptr  = pos+1;
108                         if (cont != NULL) {
109                                 *cont = false;
110                         }
111                         return true;
112
113                 case '\\':
114                         pos++;
115                         if (!srprs_charset(&pos, "\\\"", str))
116                                 goto fail;
117                         break;
118
119                 default:
120                         assert(false);
121                 }
122         }
123
124 fail:
125         cbuf_setpos(str, spos);
126         return false;
127 }
128
129 bool srprs_hex(const char** ptr, size_t len, unsigned* u)
130 {
131         static const char* FMT[] = {
132                 "%1x","%2x","%3x","%4x","%5x","%6x","%7x","%8x",
133                 "%9x","%10x","%11x","%12x","%13x","%14x","%15x","%16x"
134         };
135
136         const char* pos = *ptr;
137         int ret;
138         int i;
139
140         assert((len > 0)
141                && (len <= 2*sizeof(unsigned))
142                && (len <= sizeof(FMT)/sizeof(const char*)));
143
144         for (i=0; i<len; i++) {
145                 if (!srprs_charset(&pos, "0123456789abcdefABCDEF", NULL)) {
146                         break;
147                 }
148         }
149
150         ret = sscanf(*ptr, FMT[len-1], u);
151
152         if ( ret != 1 ) {
153                 return false;
154         }
155
156         *ptr = pos;
157         return true;
158 }
159
160 bool srprs_nl(const char** ptr, cbuf* nl)
161 {
162         static const char CRLF[] = "\r\n";
163         if (srprs_str(ptr, CRLF, sizeof(CRLF) - 1)) {
164                 cbuf_puts(nl, CRLF, sizeof(CRLF) - 1);
165                 return true;
166         }
167         return srprs_charset(ptr, "\n\r", nl);
168 }
169
170 bool srprs_eos(const char** ptr)
171 {
172         return (**ptr == '\0');
173 }
174
175 bool srprs_eol(const char** ptr, cbuf* nl)
176 {
177         return  srprs_eos(ptr) || srprs_nl(ptr, nl);
178 }
179
180 bool srprs_line(const char** ptr, cbuf* str)
181 {
182         while (srprs_charsetinv(ptr, "\n\r", str))
183                 ;
184         return true;
185 }