sexp-format.c 6.43 KB
Newer Older
1
/* sexp-format.c
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

   Writing s-expressions.

   Copyright (C) 2002 Niels Möller

   This file is part of GNU Nettle.

   GNU Nettle is free software: you can redistribute it and/or
   modify it under the terms of either:

     * the GNU Lesser General Public License as published by the Free
       Software Foundation; either version 3 of the License, or (at your
       option) any later version.

   or

     * the GNU General Public License as published by the Free
       Software Foundation; either version 2 of the License, or (at your
       option) any later version.

   or both in parallel, as here.

   GNU Nettle is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received copies of the GNU General Public License and
   the GNU Lesser General Public License along with this program.  If
   not, see http://www.gnu.org/licenses/.
*/
33 34

#if HAVE_CONFIG_H
35
# include "config.h"
36 37
#endif

38
#include <assert.h>
39 40 41 42 43
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

44 45 46
#include "sexp.h"
#include "buffer.h"

47
#include "bignum.h"
48

49
static unsigned
Niels Möller's avatar
Niels Möller committed
50
format_prefix(struct nettle_buffer *buffer,
51
	      size_t length)
52
{
53
  size_t digit = 1;
54 55 56 57
  unsigned prefix_length = 1;
  
  for (;;)
    {
58
      size_t next = digit * 10;
59 60
      if (next > length)
	break;
61

62 63 64
      prefix_length++;
      digit = next;
    }
65

66 67 68 69 70 71 72 73 74 75 76
  if (buffer)
    {
      for (; digit; length %= digit, digit /= 10)
	if (!NETTLE_BUFFER_PUTC(buffer, '0' + length / digit))
	  return 0;
      
      if (!NETTLE_BUFFER_PUTC(buffer, ':'))
	return 0;
    }

  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 84 85 86 87 88 89 90 91 92
{
  unsigned prefix_length = format_prefix(buffer, length);
  if (!prefix_length)
    return 0;

  if (buffer && !nettle_buffer_write(buffer, length, s))
    return 0;

  return prefix_length + length;
}

93 94 95 96 97 98
static inline size_t
strlen_u8 (const uint8_t *s)
{
  return strlen((const char*) s);
}

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 106 107
  for (;;)
    switch (*format++)
      {
108
      default:
109 110
	{
	  const char *start = format - 1;
111
	  size_t length = 1 + strcspn(format, "()% \t");
112 113
	  size_t output_length
	    = format_string(buffer, length, (const uint8_t *) start);
114 115 116 117 118 119 120 121
	  if (!output_length)
	    return 0;
	  
	  done += output_length;
	  format = start + length;

	  break;
	}
122 123 124
      case ' ': case '\t':
	break;
	
125
      case '\0':
126 127 128 129
	assert(!nesting);
	    
	return done;

130
      case '(':
131 132
	if (buffer && !NETTLE_BUFFER_PUTC(buffer, '('))
	  return 0;
133

134
	done++;
135 136 137 138
	nesting++;
	break;

      case ')':
139 140 141 142 143
	assert (nesting);
	if (buffer && !NETTLE_BUFFER_PUTC(buffer, ')'))
	  return 0;

	done++;
144 145 146 147
	nesting--;
	break;

      case '%':
148 149
	{
	  int nul_flag = 0;
150

151 152 153 154
	  if (*format == '0')
	    {
	      format++;
	      nul_flag = 1;
155
	    }
156
	  switch (*format++)
157
	    {
158 159
	    default:
	      abort();
160

161 162 163 164 165 166 167 168
	    case '(':
	    case ')':
	      /* Allow unbalanced parenthesis */
	      if (buffer && !NETTLE_BUFFER_PUTC(buffer, format[-1]))
		return 0;
	      done++;
	      break;
	      
169 170
	    case 's':
	      {
171
		const uint8_t *s;
172 173
		size_t length;
		size_t output_length;
174 175 176
		
		if (nul_flag)
		  {
177 178
		    s = va_arg(args, const uint8_t *);
		    length = strlen_u8(s);
179 180 181
		  }
		else
		  {
182
		    length = va_arg(args, size_t);
183
		    s = va_arg(args, const uint8_t *);
184 185
		  }
		
186 187
		output_length = format_string(buffer, length, s);
		if (!output_length)
188 189
		  return 0;

190
		done += output_length;
191 192 193 194
		break;
	      }
	    case 't':
	      {
195
		const uint8_t *s;
196 197
		size_t length;
		size_t output_length;
198 199 200
		
		if (nul_flag)
		  {
201
		    s = va_arg(args, const uint8_t *);
202 203 204
		    if (!s)
		      break;
		    
205
		    length = strlen_u8(s);
206 207 208
		  }
		else
		  {
209
		    length = va_arg(args, size_t);
210
		    s = va_arg(args, const uint8_t *);
211 212 213 214 215 216 217 218
		    if (!s)
		      break;
		  }
		
		if (buffer && !NETTLE_BUFFER_PUTC(buffer, '['))
		  return 0;
		done++;
		
219
		output_length = format_string(buffer, length, s);
220
	      
221
		if (!output_length)
222
		  return 0;
223

224 225
		done += output_length;
		
226 227 228 229 230 231
		if (buffer && !NETTLE_BUFFER_PUTC(buffer, ']'))
		  return 0;
		done++;
		
		break;
	      }
232
	      
233 234
	    case 'l':
	      {
235
		const uint8_t *s;
236
		size_t length;
237 238 239
		
		if (nul_flag)
		  {
240 241
		    s = va_arg(args, const uint8_t *);
		    length = strlen_u8(s);
242 243 244
		  }
		else
		  {
245
		    length = va_arg(args, size_t);
246
		    s = va_arg(args, const uint8_t *);
247 248 249 250
		  }

		if (buffer && !nettle_buffer_write(buffer, length, s))
		  return 0;
251
	      
252 253 254 255 256 257 258
		done += length;
		break;
	      }
	    case 'i':
	      {
		uint32_t x = va_arg(args, uint32_t);
		unsigned length;
259
	      
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
		if (x < 0x80)
		  length = 1;
		else if (x < 0x8000L)
		  length = 2;
		else if (x < 0x800000L)
		  length = 3;
		else if (x < 0x80000000L)
		  length = 4;
		else
		  length = 5;
	      
		if (buffer && !(NETTLE_BUFFER_PUTC(buffer, '0' + length)
				&& NETTLE_BUFFER_PUTC(buffer, ':')))
		  return 0;

		done += (2 + length);

		if (buffer)
		  switch(length)
		    {
		    case 5:
		      /* Leading byte needed for the sign. */
		      if (!NETTLE_BUFFER_PUTC(buffer, 0))
			return 0;
		      /* Fall through */
		    case 4:
		      if (!NETTLE_BUFFER_PUTC(buffer, x >> 24))
			return 0;
		      /* Fall through */
		    case 3:
		      if (!NETTLE_BUFFER_PUTC(buffer, (x >> 16) & 0xff))
			return 0;
		      /* Fall through */
		    case 2:
		      if (!NETTLE_BUFFER_PUTC(buffer, (x >> 8) & 0xff))
			return 0;
		      /* Fall through */
		    case 1:
		      if (!NETTLE_BUFFER_PUTC(buffer, x & 0xff))
			return 0;
		      break;
		    default:
		      abort();
		    }
		break;
	      }
	    case 'b':
	      {
308
		mpz_srcptr n = va_arg(args, mpz_srcptr);
309
		size_t length;
310
		unsigned prefix_length;
311
	      
312 313 314 315 316 317 318 319 320 321 322 323
		length = nettle_mpz_sizeinbase_256_s(n);
		prefix_length = format_prefix(buffer, length);
		if (!prefix_length)
		  return 0;

		done += prefix_length;

		if (buffer)
		  {
		    uint8_t *space = nettle_buffer_space(buffer, length);
		    if (!space)
		      return 0;
324
		  
325 326
		    nettle_mpz_get_str_256(length, space, n);
		  }
327

328
		done += length;
329
	      
330 331
		break;
	      }
332
	    }
333
	}
334 335
      }
}
336

337
size_t
338 339 340
sexp_format(struct nettle_buffer *buffer, const char *format, ...)
{
  va_list args;
341
  size_t done;
342 343 344 345 346 347 348
  
  va_start(args, format);
  done = sexp_vformat(buffer, format, args);
  va_end(args);

  return done;
}