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., 51 Franklin Street, Fifth Floor, 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"
58 /* Conversion functions. */
60 /* Should be called with input->token being the first token of the
61 * expression, to be converted, and return with input->token being the
62 * last token of the expression. */
64 sexp_convert_item(struct sexp_parser *parser,
65 struct sexp_compound_token *token,
66 struct sexp_output *output, enum sexp_mode mode_out,
69 if (mode_out == SEXP_TRANSPORT)
71 sexp_put_char(output, '{');
72 sexp_put_code_start(output, &nettle_base64);
73 sexp_convert_item(parser, token, output, SEXP_CANONICAL, 0);
74 sexp_put_code_end(output);
75 sexp_put_char(output, '}');
77 else switch(token->type)
80 die("Unmatched end of list.\n");
82 die("Unexpected end of file.\n");
84 die("Unexpected end of coding.\n");
90 sexp_put_char(output, '(');
93 sexp_parse(parser, token), token->type != SEXP_LIST_END;
96 if (mode_out == SEXP_ADVANCED)
98 /* FIXME: Adapt pretty printing to handle a big first
103 if (token->type == SEXP_COMMENT)
105 indent = output->pos;
106 /* Disable the indentation setup for next item */
112 sexp_put_char(output, ' ');
113 indent = output->pos;
117 sexp_put_newline(output, indent);
122 sexp_convert_item(parser, token, output, mode_out, indent);
124 sexp_put_char(output, ')');
130 sexp_put_string(output, mode_out, &token->string);
134 sexp_put_char(output, '[');
135 sexp_put_string(output, mode_out, &token->display);
136 sexp_put_char(output, ']');
137 sexp_put_string(output, mode_out, &token->string);
141 if (mode_out == SEXP_ADVANCED)
143 sexp_put_data(output, token->string.size, token->string.contents);
144 sexp_put_soft_newline(output, indent);
154 /* Argument parsing and main program */
156 /* The old lsh sexp-conv program took the following options:
158 * Usage: sexp-conv [OPTION...]
159 * Conversion: sexp-conv [options] <INPUT-SEXP >OUTPUT
160 * or: sexp-conv [OPTION...]
161 * Fingerprinting: sexp-conv --raw-hash [ --hash=ALGORITHM ]
163 * Reads an s-expression on stdin, and outputs the same s-expression on stdout,
164 * possibly using a different encoding. By default, output uses the advanced
167 * --hash=Algorithm Hash algorithm (default sha1).
168 * --once Process exactly one s-expression.
169 * --raw-hash Output the hash for the canonical representation
170 * of the object, in hexadecimal.
171 * --replace=Substitution An expression `/before/after/' replaces all
172 * occurances of the atom `before' with `after'. The
173 * delimiter `/' can be any single character.
174 * --select=Operator Select a subexpression (e.g `caddr') for
176 * --spki-hash Output an SPKI hash for the object.
177 * --debug Print huge amounts of debug information
178 * --log-file=File name Append messages to this file.
179 * -q, --quiet Suppress all warnings and diagnostic messages
180 * --trace Detailed trace
181 * -v, --verbose Verbose diagnostic messages
183 * Valid sexp-formats are transport, canonical, advanced, and international.
185 * Valid sexp-formats are transport, canonical, advanced, advanced-hex and
187 * -f, --output-format=format Variant of the s-expression syntax to generate.
188 * -i, --input-format=format Variant of the s-expression syntax to accept.
190 * -?, --help Give this help list
191 * --usage Give a short usage message
192 * -V, --version Print program version
203 const struct nettle_hash *hash;
206 enum { OPT_ONCE = 300, OPT_HASH, OPT_LOCK, OPT_HELP };
209 match_argument(const char *given, const char *name)
211 /* FIXME: Allow abbreviations */
212 return !strcmp(given, name);
216 parse_options(struct conv_options *o,
217 int argc, char **argv)
219 o->mode = SEXP_ADVANCED;
228 static const struct nettle_hash *hashes[] =
229 { &nettle_md5, &nettle_sha1, &nettle_sha256, NULL };
231 static const struct option options[] =
233 /* Name, args, flag, val */
234 { "help", no_argument, NULL, OPT_HELP },
235 { "version", no_argument, NULL, 'V' },
236 { "once", no_argument, NULL, OPT_ONCE },
237 { "syntax", required_argument, NULL, 's' },
238 { "hash", optional_argument, NULL, OPT_HASH },
239 { "raw-hash", optional_argument, NULL, OPT_HASH },
240 { "width", required_argument, NULL, 'w' },
241 #if HAVE_FCNTL_LOCKING
242 { "lock", no_argument, NULL, OPT_LOCK },
245 /* Not yet implemented */
246 { "replace", required_argument, NULL, OPT_REPLACE },
247 { "select", required_argument, NULL, OPT_SELECT },
248 { "spki-hash", optional_argument, NULL, OPT_SPKI_HASH },
253 int option_index = 0;
256 c = getopt_long(argc, argv, "Vs:w:", options, &option_index);
265 die("sexp-conv: Command line takes no arguments, only options.\n");
274 int width = strtol(optarg, &end , 0);
275 if (!*optarg || *end || width < 0)
276 die("sexp-conv: Invalid width `%s'.\n", optarg);
283 werror("sexp-conv: Combining --hash and -s usually makes no sense.\n");
284 if (match_argument(optarg, "advanced"))
285 o->mode = SEXP_ADVANCED;
286 else if (match_argument(optarg, "transport"))
287 o->mode = SEXP_TRANSPORT;
288 else if (match_argument(optarg, "canonical"))
289 o->mode = SEXP_CANONICAL;
290 else if (match_argument(optarg, "hex"))
292 o->mode = SEXP_ADVANCED;
296 die("Available syntax variants: advanced, transport, canonical\n");
304 o->mode = SEXP_CANONICAL;
306 o->hash = &nettle_sha1;
311 die("sexp_conv: Unknown hash algorithm `%s'\n",
314 if (match_argument(optarg, hashes[i]->name))
321 #if HAVE_FCNTL_LOCKING
327 printf("Usage: sexp-conv [OPTION...]\n"
328 " Conversion: sexp-conv [OPTION...] <INPUT-SEXP\n"
329 " Fingerprinting: sexp-conv --hash=HASH <INPUT-SEXP\n\n"
330 "Reads an s-expression on stdin, and outputs the same\n"
331 "sexp on stdout, possibly with a different syntax.\n\n"
332 " --hash[=ALGORITHM] Outputs only the hash of the expression.\n"
333 " Available hash algorithms:\n"
335 for(i = 0; hashes[i]; i++)
338 printf("%s", hashes[i]->name);
340 printf(" (default is sha1).\n"
341 " -s, --syntax=SYNTAX The syntax used for the output. Available\n"
342 " variants: advanced, hex, transport, canonical\n"
343 " --once Process only the first s-expression.\n"
344 " -w, --width=WIDTH Linewidth for base64 encoded data.\n"
345 " Zero means no limit.\n"
346 #if HAVE_FCNTL_LOCKING
347 " --lock Lock output file.\n"
349 " --raw-hash Alias for --hash, for compatibility\n"
351 "Report bugs to " BUG_ADDRESS ".\n");
355 printf("sexp-conv (" PACKAGE_STRING ")\n");
362 main(int argc, char **argv)
364 struct conv_options options;
365 struct sexp_input input;
366 struct sexp_parser parser;
367 struct sexp_compound_token token;
368 struct sexp_output output;
370 parse_options(&options, argc, argv);
372 sexp_input_init(&input, stdin);
373 sexp_parse_init(&parser, &input, SEXP_ADVANCED);
374 sexp_compound_token_init(&token);
375 sexp_output_init(&output, stdout,
376 options.width, options.prefer_hex);
378 #if HAVE_FCNTL_LOCKING
383 memset(&fl, 0, sizeof(fl));
385 fl.l_whence = SEEK_SET;
387 fl.l_len = 0; /* Means entire file. */
389 if (fcntl(STDOUT_FILENO, F_SETLKW, &fl) == -1)
390 die("Locking output file failed: %s\n", strerror(errno));
392 #endif /* HAVE_FCNTL_LOCKING */
395 /* Leaks the context, but that doesn't matter */
396 void *ctx = xalloc(options.hash->context_size);
397 sexp_output_hash_init(&output, options.hash, ctx);
400 sexp_get_char(&input);
402 sexp_parse(&parser, &token);
404 if (token.type == SEXP_EOF)
407 die("sexp-conv: No input expression.\n");
413 sexp_convert_item(&parser, &token, &output, options.mode, 0);
416 sexp_put_digest(&output);
417 sexp_put_newline(&output, 0);
419 else if (options.mode != SEXP_CANONICAL)
420 sexp_put_newline(&output, 0);
422 sexp_parse(&parser, &token);
424 while (!options.once && token.type != SEXP_EOF);
426 sexp_compound_token_clear(&token);
428 if (fflush(output.f) < 0)
429 die("Final fflush failed: %s.\n", strerror(errno));