3 * Conversion tool for handling the different flavours of sexp
6 /* nettle, low-level cryptographics library
8 * Copyright (C) 2002 Niels Möller
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.
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.
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,
36 #if HAVE_FCNTL_LOCKING
38 # include <sys/types.h>
47 #include "nettle-meta.h"
55 #define BUG_ADDRESS "nettle-bugs@lists.lysator.liu.se"
60 void *p = malloc(size);
63 fprintf(stderr, "Virtual memory exhausted.\n");
71 /* Conversion functions. */
73 /* Should be called with input->token being the first token of the
74 * expression, to be converted, and return with input->token being the
75 * last token of the expression. */
77 sexp_convert_item(struct sexp_parser *parser,
78 struct sexp_compound_token *token,
79 struct sexp_output *output, enum sexp_mode mode_out,
82 if (mode_out == SEXP_TRANSPORT)
84 sexp_put_char(output, '{');
85 sexp_put_code_start(output, &nettle_base64);
86 sexp_convert_item(parser, token, output, SEXP_CANONICAL, 0);
87 sexp_put_code_end(output);
88 sexp_put_char(output, '}');
90 else switch(token->type)
93 die("Unmatched end of list.\n");
95 die("Unexpected end of file.\n");
97 die("Unexpected end of coding.\n");
103 sexp_put_char(output, '(');
106 sexp_parse(parser, token), token->type != SEXP_LIST_END;
109 if (mode_out == SEXP_ADVANCED)
111 /* FIXME: Adapt pretty printing to handle a big first
116 if (token->type == SEXP_COMMENT)
118 indent = output->pos;
119 /* Disable the indentation setup for next item */
125 sexp_put_char(output, ' ');
126 indent = output->pos;
130 sexp_put_newline(output, indent);
135 sexp_convert_item(parser, token, output, mode_out, indent);
137 sexp_put_char(output, ')');
143 sexp_put_string(output, mode_out, &token->string);
147 sexp_put_char(output, '[');
148 sexp_put_string(output, mode_out, &token->display);
149 sexp_put_char(output, ']');
150 sexp_put_string(output, mode_out, &token->string);
154 if (mode_out == SEXP_ADVANCED)
156 sexp_put_data(output, token->string.size, token->string.contents);
157 sexp_put_soft_newline(output, indent);
167 /* Argument parsing and main program */
169 /* The old lsh sexp-conv program took the following options:
171 * Usage: sexp-conv [OPTION...]
172 * Conversion: sexp-conv [options] <INPUT-SEXP >OUTPUT
173 * or: sexp-conv [OPTION...]
174 * Fingerprinting: sexp-conv --raw-hash [ --hash=ALGORITHM ]
176 * Reads an s-expression on stdin, and outputs the same s-expression on stdout,
177 * possibly using a different encoding. By default, output uses the advanced
180 * --hash=Algorithm Hash algorithm (default sha1).
181 * --once Process exactly one s-expression.
182 * --raw-hash Output the hash for the canonical representation
183 * of the object, in hexadecimal.
184 * --replace=Substitution An expression `/before/after/' replaces all
185 * occurances of the atom `before' with `after'. The
186 * delimiter `/' can be any single character.
187 * --select=Operator Select a subexpression (e.g `caddr') for
189 * --spki-hash Output an SPKI hash for the object.
190 * --debug Print huge amounts of debug information
191 * --log-file=File name Append messages to this file.
192 * -q, --quiet Suppress all warnings and diagnostic messages
193 * --trace Detailed trace
194 * -v, --verbose Verbose diagnostic messages
196 * Valid sexp-formats are transport, canonical, advanced, and international.
198 * Valid sexp-formats are transport, canonical, advanced, advanced-hex and
200 * -f, --output-format=format Variant of the s-expression syntax to generate.
201 * -i, --input-format=format Variant of the s-expression syntax to accept.
203 * -?, --help Give this help list
204 * --usage Give a short usage message
205 * -V, --version Print program version
216 const struct nettle_hash *hash;
219 enum { OPT_ONCE = 300, OPT_HASH, OPT_LOCK };
222 match_argument(const char *given, const char *name)
224 /* FIXME: Allow abbreviations */
225 return !strcmp(given, name);
229 parse_options(struct conv_options *o,
230 int argc, char **argv)
232 o->mode = SEXP_ADVANCED;
241 static const struct nettle_hash *hashes[] =
242 { &nettle_md5, &nettle_sha1, &nettle_sha256, NULL };
244 static const struct option options[] =
246 /* Name, args, flag, val */
247 { "help", no_argument, NULL, '?' },
248 { "version", no_argument, NULL, 'V' },
249 { "once", no_argument, NULL, OPT_ONCE },
250 { "syntax", required_argument, NULL, 's' },
251 { "hash", optional_argument, NULL, OPT_HASH },
252 { "raw-hash", optional_argument, NULL, OPT_HASH },
253 { "width", required_argument, NULL, 'w' },
254 #if HAVE_FCNTL_LOCKING
255 { "lock", no_argument, NULL, OPT_LOCK },
258 /* Not yet implemented */
259 { "replace", required_argument, NULL, OPT_REPLACE },
260 { "select", required_argument, NULL, OPT_SELECT },
261 { "spki-hash", optional_argument, NULL, OPT_SPKI_HASH },
266 int option_index = 0;
269 c = getopt_long(argc, argv, "V?s:w:", options, &option_index);
278 die("sexp-conv: Command line takes no arguments, only options.\n");
284 int width = strtol(optarg, &end , 0);
285 if (!*optarg || *end || width < 0)
286 die("sexp-conv: Invalid width `%s'.\n", optarg);
293 werror("sexp-conv: Combining --hash and -s usually makes no sense.\n");
294 if (match_argument(optarg, "advanced"))
295 o->mode = SEXP_ADVANCED;
296 else if (match_argument(optarg, "transport"))
297 o->mode = SEXP_TRANSPORT;
298 else if (match_argument(optarg, "canonical"))
299 o->mode = SEXP_CANONICAL;
300 else if (match_argument(optarg, "hex"))
302 o->mode = SEXP_ADVANCED;
306 die("Available syntax variants: advanced, transport, canonical\n");
314 o->mode = SEXP_CANONICAL;
316 o->hash = &nettle_sha1;
321 die("sexp_conv: Unknown hash algorithm `%s'\n",
324 if (match_argument(optarg, hashes[i]->name))
331 #if HAVE_FCNTL_LOCKING
337 printf("Usage: sexp-conv [OPTION...]\n"
338 " Conversion: sexp-conv [OPTION...] <INPUT-SEXP\n"
339 " Fingerprinting: sexp-conv --hash=HASH <INPUT-SEXP\n\n"
340 "Reads an s-expression on stdin, and outputs the same\n"
341 "sexp on stdout, possibly with a different syntax.\n\n"
342 " --hash[=ALGORITHM] Outputs only the hash of the expression.\n"
343 " Available hash algorithms:\n"
345 for(i = 0; hashes[i]; i++)
348 printf("%s", hashes[i]->name);
350 printf(" (default is sha1).\n"
351 " -s, --syntax=SYNTAX The syntax used for the output. Available\n"
352 " variants: advanced, hex, transport, canonical\n"
353 " --once Process only the first s-expression.\n"
354 " -w, --width=WIDTH Linewidth for base64 encoded data.\n"
355 " Zero means no limit.\n"
356 #if HAVE_FCNTL_LOCKING
357 " --lock Lock output file.\n"
359 " --raw-hash Alias for --hash, for compatibility\n"
361 "Report bugs to " BUG_ADDRESS ".\n");
365 printf("sexp-conv (" PACKAGE_STRING ")\n");
372 main(int argc, char **argv)
374 struct conv_options options;
375 struct sexp_input input;
376 struct sexp_parser parser;
377 struct sexp_compound_token token;
378 struct sexp_output output;
380 parse_options(&options, argc, argv);
382 sexp_input_init(&input, stdin);
383 sexp_parse_init(&parser, &input, SEXP_ADVANCED);
384 sexp_compound_token_init(&token);
385 sexp_output_init(&output, stdout,
386 options.width, options.prefer_hex);
388 #if HAVE_FCNTL_LOCKING
393 memset(&fl, 0, sizeof(fl));
395 fl.l_whence = SEEK_SET;
397 fl.l_len = 0; /* Means entire file. */
399 if (fcntl(STDOUT_FILENO, F_SETLKW, &fl) == -1)
400 die("Locking output file failed: %s\n", strerror(errno));
402 #endif /* HAVE_FCNTL_LOCKING */
405 /* Leaks the context, but that doesn't matter */
406 void *ctx = xalloc(options.hash->context_size);
407 sexp_output_hash_init(&output, options.hash, ctx);
410 sexp_get_char(&input);
412 sexp_parse(&parser, &token);
414 if (token.type == SEXP_EOF)
417 die("sexp-conv: No input expression.\n");
423 sexp_convert_item(&parser, &token, &output, options.mode, 0);
426 sexp_put_digest(&output);
427 sexp_put_newline(&output, 0);
429 else if (options.mode != SEXP_CANONICAL)
430 sexp_put_newline(&output, 0);
432 sexp_parse(&parser, &token);
434 while (!options.once && token.type != SEXP_EOF);
436 sexp_compound_token_clear(&token);
438 if (fflush(output.f) < 0)
439 die("Final fflush failed: %s.\n", strerror(errno));