]> git.ipfire.org Git - thirdparty/nettle.git/blame - sexp-format.c
More NEWS entries for nettle-3.10.
[thirdparty/nettle.git] / sexp-format.c
CommitLineData
a8ff1805 1/* sexp-format.c
90112edb
NM
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*/
fd6af34b
NM
33
34#if HAVE_CONFIG_H
c5c15385 35# include "config.h"
fd6af34b
NM
36#endif
37
fe5c484c 38#include <assert.h>
fd6af34b
NM
39#include <stdarg.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43
c5c15385
NM
44#include "sexp.h"
45#include "buffer.h"
46
3e82a29d 47#include "bignum.h"
fd6af34b 48
fe5c484c 49static unsigned
dc652126 50format_prefix(struct nettle_buffer *buffer,
86fdb2ce 51 size_t length)
fd6af34b 52{
86fdb2ce 53 size_t digit = 1;
fe5c484c
NM
54 unsigned prefix_length = 1;
55
56 for (;;)
57 {
86fdb2ce 58 size_t next = digit * 10;
fe5c484c
NM
59 if (next > length)
60 break;
fd6af34b 61
fe5c484c
NM
62 prefix_length++;
63 digit = next;
64 }
fd6af34b 65
fe5c484c
NM
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;
fd6af34b
NM
77}
78
86fdb2ce 79static size_t
e01516ec 80format_string(struct nettle_buffer *buffer,
86fdb2ce 81 size_t length, const uint8_t *s)
e01516ec
NM
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
abe959a3
NM
93static inline size_t
94strlen_u8 (const uint8_t *s)
95{
96 return strlen((const char*) s);
97}
98
86fdb2ce 99size_t
fe5c484c 100sexp_vformat(struct nettle_buffer *buffer, const char *format, va_list args)
fd6af34b 101{
fd6af34b 102 unsigned nesting = 0;
86fdb2ce 103 size_t done = 0;
e1f802b1 104
fd6af34b
NM
105 for (;;)
106 switch (*format++)
107 {
a8ff1805 108 default:
e01516ec
NM
109 {
110 const char *start = format - 1;
86fdb2ce 111 size_t length = 1 + strcspn(format, "()% \t");
abe959a3
NM
112 size_t output_length
113 = format_string(buffer, length, (const uint8_t *) start);
e01516ec
NM
114 if (!output_length)
115 return 0;
116
117 done += output_length;
118 format = start + length;
119
120 break;
121 }
2039f20a
NM
122 case ' ': case '\t':
123 break;
124
fd6af34b 125 case '\0':
fe5c484c
NM
126 assert(!nesting);
127
128 return done;
129
fd6af34b 130 case '(':
fe5c484c
NM
131 if (buffer && !NETTLE_BUFFER_PUTC(buffer, '('))
132 return 0;
fd6af34b 133
fe5c484c 134 done++;
fd6af34b
NM
135 nesting++;
136 break;
137
138 case ')':
fe5c484c
NM
139 assert (nesting);
140 if (buffer && !NETTLE_BUFFER_PUTC(buffer, ')'))
141 return 0;
142
143 done++;
fd6af34b
NM
144 nesting--;
145 break;
146
147 case '%':
1c323788
NM
148 {
149 int nul_flag = 0;
fe5c484c 150
1c323788
NM
151 if (*format == '0')
152 {
153 format++;
154 nul_flag = 1;
fe5c484c 155 }
1c323788 156 switch (*format++)
fd6af34b 157 {
1c323788
NM
158 default:
159 abort();
fe5c484c 160
3fe07807
NM
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
1c323788
NM
169 case 's':
170 {
abe959a3 171 const uint8_t *s;
86fdb2ce
NM
172 size_t length;
173 size_t output_length;
1c323788
NM
174
175 if (nul_flag)
176 {
abe959a3
NM
177 s = va_arg(args, const uint8_t *);
178 length = strlen_u8(s);
1c323788
NM
179 }
180 else
181 {
86fdb2ce 182 length = va_arg(args, size_t);
abe959a3 183 s = va_arg(args, const uint8_t *);
1c323788
NM
184 }
185
e01516ec
NM
186 output_length = format_string(buffer, length, s);
187 if (!output_length)
1c323788
NM
188 return 0;
189
e01516ec 190 done += output_length;
1c323788
NM
191 break;
192 }
193 case 't':
194 {
abe959a3 195 const uint8_t *s;
86fdb2ce
NM
196 size_t length;
197 size_t output_length;
1c323788
NM
198
199 if (nul_flag)
200 {
abe959a3 201 s = va_arg(args, const uint8_t *);
1c323788
NM
202 if (!s)
203 break;
204
abe959a3 205 length = strlen_u8(s);
1c323788
NM
206 }
207 else
208 {
86fdb2ce 209 length = va_arg(args, size_t);
abe959a3 210 s = va_arg(args, const uint8_t *);
1c323788
NM
211 if (!s)
212 break;
213 }
214
215 if (buffer && !NETTLE_BUFFER_PUTC(buffer, '['))
216 return 0;
217 done++;
218
e01516ec 219 output_length = format_string(buffer, length, s);
1c323788 220
e01516ec 221 if (!output_length)
1c323788 222 return 0;
fe5c484c 223
e01516ec
NM
224 done += output_length;
225
1c323788
NM
226 if (buffer && !NETTLE_BUFFER_PUTC(buffer, ']'))
227 return 0;
228 done++;
229
230 break;
231 }
fe5c484c 232
1c323788
NM
233 case 'l':
234 {
abe959a3 235 const uint8_t *s;
86fdb2ce 236 size_t length;
1c323788
NM
237
238 if (nul_flag)
239 {
abe959a3
NM
240 s = va_arg(args, const uint8_t *);
241 length = strlen_u8(s);
1c323788
NM
242 }
243 else
244 {
86fdb2ce 245 length = va_arg(args, size_t);
abe959a3 246 s = va_arg(args, const uint8_t *);
1c323788
NM
247 }
248
249 if (buffer && !nettle_buffer_write(buffer, length, s))
250 return 0;
fe5c484c 251
1c323788
NM
252 done += length;
253 break;
254 }
255 case 'i':
256 {
257 uint32_t x = va_arg(args, uint32_t);
258 unsigned length;
f75832a1 259
1c323788
NM
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 {
9deeaa4f 308 mpz_srcptr n = va_arg(args, mpz_srcptr);
86fdb2ce 309 size_t length;
1c323788 310 unsigned prefix_length;
fd6af34b 311
1c323788
NM
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;
fe5c484c 324
1c323788
NM
325 nettle_mpz_get_str_256(length, space, n);
326 }
fe5c484c 327
1c323788 328 done += length;
fe5c484c 329
1c323788
NM
330 break;
331 }
fd6af34b 332 }
1c323788 333 }
fd6af34b
NM
334 }
335}
fe5c484c 336
86fdb2ce 337size_t
fe5c484c
NM
338sexp_format(struct nettle_buffer *buffer, const char *format, ...)
339{
340 va_list args;
86fdb2ce 341 size_t done;
fe5c484c
NM
342
343 va_start(args, format);
344 done = sexp_vformat(buffer, format, args);
345 va_end(args);
346
347 return done;
348}