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