]> git.ipfire.org Git - thirdparty/nettle.git/blob - sexp-format.c
Avoid warnings for assert_maybe.
[thirdparty/nettle.git] / sexp-format.c
1 /* sexp-format.c
2
3 Writing s-expressions.
4
5 Copyright (C) 2002 Niels Möller
6
7 This file is part of GNU Nettle.
8
9 GNU Nettle is free software: you can redistribute it and/or
10 modify it under the terms of either:
11
12 * the GNU Lesser General Public License as published by the Free
13 Software Foundation; either version 3 of the License, or (at your
14 option) any later version.
15
16 or
17
18 * the GNU General Public License as published by the Free
19 Software Foundation; either version 2 of the License, or (at your
20 option) any later version.
21
22 or both in parallel, as here.
23
24 GNU Nettle is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 General Public License for more details.
28
29 You should have received copies of the GNU General Public License and
30 the GNU Lesser General Public License along with this program. If
31 not, see http://www.gnu.org/licenses/.
32 */
33
34 #if HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <assert.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "sexp.h"
45 #include "buffer.h"
46
47 #include "bignum.h"
48
49 static unsigned
50 format_prefix(struct nettle_buffer *buffer,
51 size_t length)
52 {
53 size_t digit = 1;
54 unsigned prefix_length = 1;
55
56 for (;;)
57 {
58 size_t next = digit * 10;
59 if (next > length)
60 break;
61
62 prefix_length++;
63 digit = next;
64 }
65
66 if (buffer)
67 {
68 for (; digit; length %= digit, digit /= 10)
69 if (!NETTLE_BUFFER_PUTC(buffer, '0' + length / digit))
70 return 0;
71
72 if (!NETTLE_BUFFER_PUTC(buffer, ':'))
73 return 0;
74 }
75
76 return prefix_length + 1;
77 }
78
79 static size_t
80 format_string(struct nettle_buffer *buffer,
81 size_t length, const uint8_t *s)
82 {
83 unsigned prefix_length = format_prefix(buffer, length);
84 if (!prefix_length)
85 return 0;
86
87 if (buffer && !nettle_buffer_write(buffer, length, s))
88 return 0;
89
90 return prefix_length + length;
91 }
92
93 static inline size_t
94 strlen_u8 (const uint8_t *s)
95 {
96 return strlen((const char*) s);
97 }
98
99 size_t
100 sexp_vformat(struct nettle_buffer *buffer, const char *format, va_list args)
101 {
102 unsigned nesting = 0;
103 size_t done = 0;
104
105 for (;;)
106 switch (*format++)
107 {
108 default:
109 {
110 const char *start = format - 1;
111 size_t length = 1 + strcspn(format, "()% \t");
112 size_t output_length
113 = format_string(buffer, length, (const uint8_t *) start);
114 if (!output_length)
115 return 0;
116
117 done += output_length;
118 format = start + length;
119
120 break;
121 }
122 case ' ': case '\t':
123 break;
124
125 case '\0':
126 assert(!nesting);
127
128 return done;
129
130 case '(':
131 if (buffer && !NETTLE_BUFFER_PUTC(buffer, '('))
132 return 0;
133
134 done++;
135 nesting++;
136 break;
137
138 case ')':
139 assert (nesting);
140 if (buffer && !NETTLE_BUFFER_PUTC(buffer, ')'))
141 return 0;
142
143 done++;
144 nesting--;
145 break;
146
147 case '%':
148 {
149 int nul_flag = 0;
150
151 if (*format == '0')
152 {
153 format++;
154 nul_flag = 1;
155 }
156 switch (*format++)
157 {
158 default:
159 abort();
160
161 case '(':
162 case ')':
163 /* Allow unbalanced parenthesis */
164 if (buffer && !NETTLE_BUFFER_PUTC(buffer, format[-1]))
165 return 0;
166 done++;
167 break;
168
169 case 's':
170 {
171 const uint8_t *s;
172 size_t length;
173 size_t output_length;
174
175 if (nul_flag)
176 {
177 s = va_arg(args, const uint8_t *);
178 length = strlen_u8(s);
179 }
180 else
181 {
182 length = va_arg(args, size_t);
183 s = va_arg(args, const uint8_t *);
184 }
185
186 output_length = format_string(buffer, length, s);
187 if (!output_length)
188 return 0;
189
190 done += output_length;
191 break;
192 }
193 case 't':
194 {
195 const uint8_t *s;
196 size_t length;
197 size_t output_length;
198
199 if (nul_flag)
200 {
201 s = va_arg(args, const uint8_t *);
202 if (!s)
203 break;
204
205 length = strlen_u8(s);
206 }
207 else
208 {
209 length = va_arg(args, size_t);
210 s = va_arg(args, const uint8_t *);
211 if (!s)
212 break;
213 }
214
215 if (buffer && !NETTLE_BUFFER_PUTC(buffer, '['))
216 return 0;
217 done++;
218
219 output_length = format_string(buffer, length, s);
220
221 if (!output_length)
222 return 0;
223
224 done += output_length;
225
226 if (buffer && !NETTLE_BUFFER_PUTC(buffer, ']'))
227 return 0;
228 done++;
229
230 break;
231 }
232
233 case 'l':
234 {
235 const uint8_t *s;
236 size_t length;
237
238 if (nul_flag)
239 {
240 s = va_arg(args, const uint8_t *);
241 length = strlen_u8(s);
242 }
243 else
244 {
245 length = va_arg(args, size_t);
246 s = va_arg(args, const uint8_t *);
247 }
248
249 if (buffer && !nettle_buffer_write(buffer, length, s))
250 return 0;
251
252 done += length;
253 break;
254 }
255 case 'i':
256 {
257 uint32_t x = va_arg(args, uint32_t);
258 unsigned length;
259
260 if (x < 0x80)
261 length = 1;
262 else if (x < 0x8000L)
263 length = 2;
264 else if (x < 0x800000L)
265 length = 3;
266 else if (x < 0x80000000L)
267 length = 4;
268 else
269 length = 5;
270
271 if (buffer && !(NETTLE_BUFFER_PUTC(buffer, '0' + length)
272 && NETTLE_BUFFER_PUTC(buffer, ':')))
273 return 0;
274
275 done += (2 + length);
276
277 if (buffer)
278 switch(length)
279 {
280 case 5:
281 /* Leading byte needed for the sign. */
282 if (!NETTLE_BUFFER_PUTC(buffer, 0))
283 return 0;
284 /* Fall through */
285 case 4:
286 if (!NETTLE_BUFFER_PUTC(buffer, x >> 24))
287 return 0;
288 /* Fall through */
289 case 3:
290 if (!NETTLE_BUFFER_PUTC(buffer, (x >> 16) & 0xff))
291 return 0;
292 /* Fall through */
293 case 2:
294 if (!NETTLE_BUFFER_PUTC(buffer, (x >> 8) & 0xff))
295 return 0;
296 /* Fall through */
297 case 1:
298 if (!NETTLE_BUFFER_PUTC(buffer, x & 0xff))
299 return 0;
300 break;
301 default:
302 abort();
303 }
304 break;
305 }
306 case 'b':
307 {
308 mpz_srcptr n = va_arg(args, mpz_srcptr);
309 size_t length;
310 unsigned prefix_length;
311
312 length = nettle_mpz_sizeinbase_256_s(n);
313 prefix_length = format_prefix(buffer, length);
314 if (!prefix_length)
315 return 0;
316
317 done += prefix_length;
318
319 if (buffer)
320 {
321 uint8_t *space = nettle_buffer_space(buffer, length);
322 if (!space)
323 return 0;
324
325 nettle_mpz_get_str_256(length, space, n);
326 }
327
328 done += length;
329
330 break;
331 }
332 }
333 }
334 }
335 }
336
337 size_t
338 sexp_format(struct nettle_buffer *buffer, const char *format, ...)
339 {
340 va_list args;
341 size_t done;
342
343 va_start(args, format);
344 done = sexp_vformat(buffer, format, args);
345 va_end(args);
346
347 return done;
348 }