~ubuntu-branches/ubuntu/quantal/nettle/quantal

« back to all changes in this revision

Viewing changes to sexp-format.c

  • Committer: Bazaar Package Importer
  • Author(s): Marek Habersack
  • Date: 2004-05-04 15:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20040504155602-7jbhw5mabvwksl3j
Tags: upstream-1.10
Import upstream version 1.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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., 59 Temple Place - Suite 330, Boston,
 
23
 * MA 02111-1307, 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
#if HAVE_LIBGMP
 
40
# include "bignum.h"
 
41
#endif
 
42
 
 
43
/* Code copied from sexp-conv.c: sexp_put_length */
 
44
static unsigned
 
45
format_prefix(struct nettle_buffer *buffer,
 
46
              unsigned length)
 
47
{
 
48
  unsigned digit = 1;
 
49
  unsigned prefix_length = 1;
 
50
  
 
51
  for (;;)
 
52
    {
 
53
      unsigned next = digit * 10;
 
54
      if (next > length)
 
55
        break;
 
56
 
 
57
      prefix_length++;
 
58
      digit = next;
 
59
    }
 
60
 
 
61
  if (buffer)
 
62
    {
 
63
      for (; digit; length %= digit, digit /= 10)
 
64
        if (!NETTLE_BUFFER_PUTC(buffer, '0' + length / digit))
 
65
          return 0;
 
66
      
 
67
      if (!NETTLE_BUFFER_PUTC(buffer, ':'))
 
68
        return 0;
 
69
    }
 
70
 
 
71
  return prefix_length + 1;
 
72
}
 
73
 
 
74
static unsigned
 
75
format_string(struct nettle_buffer *buffer,
 
76
              unsigned length, const uint8_t *s)
 
77
{
 
78
  unsigned prefix_length = format_prefix(buffer, length);
 
79
  if (!prefix_length)
 
80
    return 0;
 
81
 
 
82
  if (buffer && !nettle_buffer_write(buffer, length, s))
 
83
    return 0;
 
84
 
 
85
  return prefix_length + length;
 
86
}
 
87
 
 
88
unsigned
 
89
sexp_vformat(struct nettle_buffer *buffer, const char *format, va_list args)
 
90
{
 
91
  unsigned nesting = 0;
 
92
  unsigned done = 0;
 
93
 
 
94
  for (;;)
 
95
    switch (*format++)
 
96
      {
 
97
      default:
 
98
        {
 
99
          const char *start = format - 1;
 
100
          unsigned length = 1 + strcspn(format, "()% \t");
 
101
          unsigned output_length = format_string(buffer, length, start);
 
102
          if (!output_length)
 
103
            return 0;
 
104
          
 
105
          done += output_length;
 
106
          format = start + length;
 
107
 
 
108
          break;
 
109
        }
 
110
      case ' ': case '\t':
 
111
        break;
 
112
        
 
113
      case '\0':
 
114
        assert(!nesting);
 
115
            
 
116
        return done;
 
117
 
 
118
      case '(':
 
119
        if (buffer && !NETTLE_BUFFER_PUTC(buffer, '('))
 
120
          return 0;
 
121
 
 
122
        done++;
 
123
        nesting++;
 
124
        break;
 
125
 
 
126
      case ')':
 
127
        assert (nesting);
 
128
        if (buffer && !NETTLE_BUFFER_PUTC(buffer, ')'))
 
129
          return 0;
 
130
 
 
131
        done++;
 
132
        nesting--;
 
133
        break;
 
134
 
 
135
      case '%':
 
136
        {
 
137
          int nul_flag = 0;
 
138
 
 
139
          if (*format == '0')
 
140
            {
 
141
              format++;
 
142
              nul_flag = 1;
 
143
            }
 
144
          switch (*format++)
 
145
            {
 
146
            default:
 
147
              abort();
 
148
 
 
149
            case '(':
 
150
            case ')':
 
151
              /* Allow unbalanced parenthesis */
 
152
              if (buffer && !NETTLE_BUFFER_PUTC(buffer, format[-1]))
 
153
                return 0;
 
154
              done++;
 
155
              break;
 
156
              
 
157
            case 's':
 
158
              {
 
159
                const char *s;
 
160
                unsigned length;
 
161
                unsigned output_length;
 
162
                
 
163
                if (nul_flag)
 
164
                  {
 
165
                    s = va_arg(args, const char *);
 
166
                    length = strlen(s);
 
167
                  }
 
168
                else
 
169
                  {
 
170
                    length = va_arg(args, unsigned);
 
171
                    s = va_arg(args, const char *);
 
172
                  }
 
173
                
 
174
                output_length = format_string(buffer, length, s);
 
175
                if (!output_length)
 
176
                  return 0;
 
177
 
 
178
                done += output_length;
 
179
                break;
 
180
              }
 
181
            case 't':
 
182
              {
 
183
                const char *s;
 
184
                unsigned length;
 
185
                unsigned output_length;
 
186
                
 
187
                if (nul_flag)
 
188
                  {
 
189
                    s = va_arg(args, const char *);
 
190
                    if (!s)
 
191
                      break;
 
192
                    
 
193
                    length = strlen(s);
 
194
                  }
 
195
                else
 
196
                  {
 
197
                    length = va_arg(args, unsigned);
 
198
                    s = va_arg(args, const char *);
 
199
                    if (!s)
 
200
                      break;
 
201
                  }
 
202
                
 
203
                if (buffer && !NETTLE_BUFFER_PUTC(buffer, '['))
 
204
                  return 0;
 
205
                done++;
 
206
                
 
207
                output_length = format_string(buffer, length, s);
 
208
              
 
209
                if (!output_length)
 
210
                  return 0;
 
211
 
 
212
                done += output_length;
 
213
                
 
214
                if (buffer && !NETTLE_BUFFER_PUTC(buffer, ']'))
 
215
                  return 0;
 
216
                done++;
 
217
                
 
218
                break;
 
219
              }
 
220
              
 
221
            case 'l':
 
222
              {
 
223
                const char *s;
 
224
                unsigned length;
 
225
                
 
226
                if (nul_flag)
 
227
                  {
 
228
                    s = va_arg(args, const char *);
 
229
                    length = strlen(s);
 
230
                  }
 
231
                else
 
232
                  {
 
233
                    length = va_arg(args, unsigned);
 
234
                    s = va_arg(args, const char *);
 
235
                  }
 
236
 
 
237
                if (buffer && !nettle_buffer_write(buffer, length, s))
 
238
                  return 0;
 
239
              
 
240
                done += length;
 
241
                break;
 
242
              }
 
243
            case 'i':
 
244
              {
 
245
                uint32_t x = va_arg(args, uint32_t);
 
246
                unsigned length;
 
247
              
 
248
                if (x < 0x80)
 
249
                  length = 1;
 
250
                else if (x < 0x8000L)
 
251
                  length = 2;
 
252
                else if (x < 0x800000L)
 
253
                  length = 3;
 
254
                else if (x < 0x80000000L)
 
255
                  length = 4;
 
256
                else
 
257
                  length = 5;
 
258
              
 
259
                if (buffer && !(NETTLE_BUFFER_PUTC(buffer, '0' + length)
 
260
                                && NETTLE_BUFFER_PUTC(buffer, ':')))
 
261
                  return 0;
 
262
 
 
263
                done += (2 + length);
 
264
 
 
265
                if (buffer)
 
266
                  switch(length)
 
267
                    {
 
268
                    case 5:
 
269
                      /* Leading byte needed for the sign. */
 
270
                      if (!NETTLE_BUFFER_PUTC(buffer, 0))
 
271
                        return 0;
 
272
                      /* Fall through */
 
273
                    case 4:
 
274
                      if (!NETTLE_BUFFER_PUTC(buffer, x >> 24))
 
275
                        return 0;
 
276
                      /* Fall through */
 
277
                    case 3:
 
278
                      if (!NETTLE_BUFFER_PUTC(buffer, (x >> 16) & 0xff))
 
279
                        return 0;
 
280
                      /* Fall through */
 
281
                    case 2:
 
282
                      if (!NETTLE_BUFFER_PUTC(buffer, (x >> 8) & 0xff))
 
283
                        return 0;
 
284
                      /* Fall through */
 
285
                    case 1:
 
286
                      if (!NETTLE_BUFFER_PUTC(buffer, x & 0xff))
 
287
                        return 0;
 
288
                      break;
 
289
                    default:
 
290
                      abort();
 
291
                    }
 
292
                break;
 
293
              }
 
294
            case 'b':
 
295
              {
 
296
#if HAVE_LIBGMP
 
297
                const MP_INT *n = va_arg(args, const MP_INT *);
 
298
                unsigned length;
 
299
                unsigned prefix_length;
 
300
              
 
301
                length = nettle_mpz_sizeinbase_256_s(n);
 
302
                prefix_length = format_prefix(buffer, length);
 
303
                if (!prefix_length)
 
304
                  return 0;
 
305
 
 
306
                done += prefix_length;
 
307
 
 
308
                if (buffer)
 
309
                  {
 
310
                    uint8_t *space = nettle_buffer_space(buffer, length);
 
311
                    if (!space)
 
312
                      return 0;
 
313
                  
 
314
                    nettle_mpz_get_str_256(length, space, n);
 
315
                  }
 
316
 
 
317
                done += length;
 
318
              
 
319
#else /* ! HAVE_LIBGMP */
 
320
                abort();
 
321
#endif /* ! HAVE_LIBGMP */
 
322
                break;
 
323
              }
 
324
            }
 
325
        }
 
326
      }
 
327
}
 
328
 
 
329
unsigned
 
330
sexp_format(struct nettle_buffer *buffer, const char *format, ...)
 
331
{
 
332
  va_list args;
 
333
  unsigned done;
 
334
  
 
335
  va_start(args, format);
 
336
  done = sexp_vformat(buffer, format, args);
 
337
  va_end(args);
 
338
 
 
339
  return done;
 
340
}