summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ChangeLog3
-rw-r--r--src/Makefile.am7
-rw-r--r--src/dumpsexp.c560
3 files changed, 569 insertions, 1 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 7d5f726a..3cae0f0b 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,8 @@
2007-08-22 Werner Koch <wk@g10code.com>
+ * dumpsexp.c: New.
+ * Makefile.am (bin_PROGRAMS): Install it.
+
* getrandom.c (print_version): Use new standard license line.
* gcryptrnd.c (print_version): Ditto.
diff --git a/src/Makefile.am b/src/Makefile.am
index e021e4fe..ba6963e7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,11 +28,13 @@ m4data_DATA = libgcrypt.m4
include_HEADERS = gcrypt.h gcrypt-module.h
lib_LTLIBRARIES = libgcrypt.la
+bin_PROGRAMS = dumpsexp
if USE_RANDOM_DAEMON
sbin_PROGRAMS = gcryptrnd
-bin_PROGRAMS = getrandom
+bin_PROGRAMS += getrandom
endif USE_RANDOM_DAEMON
+
if HAVE_LD_VERSION_SCRIPT
libgcrypt_version_script_cmd = -Wl,--version-script=$(srcdir)/libgcrypt.vers
else
@@ -92,6 +94,9 @@ libgcrypt_la_LIBADD = ../cipher/libcipher.la ../mpi/libmpi.la \
@LTLIBOBJS@ @GPG_ERROR_LIBS@
+dumpsexp_SOURCES = dumpsexp.c
+dumpsexp_LDADD =
+
if USE_RANDOM_DAEMON
gcryptrnd_SOURCES = gcryptrnd.c
gcryptrnd_CFLAGS = $(GPG_ERROR_CFLAGS) $(PTH_CFLAGS)
diff --git a/src/dumpsexp.c b/src/dumpsexp.c
new file mode 100644
index 00000000..6f031047
--- /dev/null
+++ b/src/dumpsexp.c
@@ -0,0 +1,560 @@
+/* dumpsexp.c - Dump S-expressions.
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * Getrandom is free software; you can redistribute it and/or modify
+ * it under the terms of 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.
+ *
+ * Getrandom 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 a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#define PGM "dumpsexp"
+#define MYVERSION_LINE PGM " (Libgcrypt) " VERSION
+#define BUGREPORT_LINE "\nReport bugs to <bug-libgcrypt@gnupg.org>.\n"
+
+
+static int verbose; /* Verbose mode. */
+static int decimal; /* Print addresses in decimal. */
+
+static void
+print_version (int with_help)
+{
+ fputs (MYVERSION_LINE "\n"
+ "Copyright (C) 2007 Free Software Foundation, Inc.\n"
+ "License GPLv2+: GNU GPL version 2 or later "
+ "<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>\n"
+ "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n",
+ stdout);
+
+ if (with_help)
+ fputs ("\n"
+ "Usage: " PGM " [OPTIONS] [file]\n"
+ "Debug tool for S-expressions\n"
+ "\n"
+ " --verbose Show what we are doing\n"
+ " --version Print version of the program and exit\n"
+ " --help Display this help and exit\n"
+ BUGREPORT_LINE, stdout );
+
+ exit (0);
+}
+
+static int
+print_usage (void)
+{
+ fputs ("usage: " PGM " [OPTIONS] NBYTES\n", stderr);
+ fputs (" (use --help to display options)\n", stderr);
+ exit (1);
+}
+
+
+#define digit_p(a) ((a) >= '0' && (a) <= '9')
+#define octdigit_p(a) ((a) >= '0' && (a) <= '7')
+#define alpha_p(a) ( ((a) >= 'A' && (a) <= 'Z') \
+ || ((a) >= 'a' && (a) <= 'z'))
+#define hexdigit_p(a) (digit_p (a) \
+ || ((a) >= 'A' && (a) <= 'F') \
+ || ((a) >= 'a' && (a) <= 'f'))
+
+
+/* Return true if P points to a byte containing a whitespace according
+ to the S-expressions definition. */
+static inline int
+whitespace_p (int c)
+{
+ switch (c)
+ {
+ case ' ': case '\t': case '\v': case '\f': case '\r': case '\n': return 1;
+ default: return 0;
+ }
+}
+
+static void
+logit (const char *format, ...)
+{
+ va_list arg_ptr;
+
+ va_start (arg_ptr, format) ;
+ fputs (PGM ": ", stderr);
+ vfprintf (stderr, format, arg_ptr);
+ putc ('\n', stderr);
+ va_end (arg_ptr);
+}
+
+/* The raw data buffer and its current length */
+static unsigned char databuffer[16];
+static int databufferlen;
+/* The number of bytes in databuffer which should be skipped at a flush. */
+static int skipdatabufferlen;
+/* The number of raw bytes printed on the last line. */
+static int nbytesprinted;
+/* The file offset of the current data buffer . */
+static unsigned long databufferoffset;
+
+/* Flush the raw data buffer. */
+static void
+flushdatabuffer (void)
+{
+ int i;
+
+ if (!databufferlen)
+ return;
+ nbytesprinted = 0;
+ if (decimal)
+ printf ("%08lu ", databufferoffset);
+ else
+ printf ("%08lx ", databufferoffset);
+ for (i=0; i < databufferlen; i++)
+ {
+ if (i == 8)
+ putchar (' ');
+ if (i < skipdatabufferlen)
+ fputs (" ", stdout);
+ else
+ {
+ printf (" %02x", databuffer[i]);
+ databufferoffset++;
+ }
+ nbytesprinted++;
+ }
+ for (; i < sizeof (databuffer); i++)
+ {
+ if (i == 8)
+ putchar (' ');
+ fputs (" ", stdout);
+ }
+ fputs (" |", stdout);
+ for (i=0; i < databufferlen; i++)
+ {
+ if (i < skipdatabufferlen)
+ putchar (' ');
+ else if (databuffer[i] >= ' ' && databuffer[i] <= '~'
+ && databuffer[i] != '|')
+ putchar (databuffer[i]);
+ else
+ putchar ('.');
+ }
+ putchar ('|');
+ putchar ('\n');
+ databufferlen = 0;
+ skipdatabufferlen = 0;
+}
+
+
+/* Add C to the raw data buffer and flush as needed. */
+static void
+addrawdata (int c)
+{
+ if ( databufferlen >= sizeof databuffer )
+ flushdatabuffer ();
+ databuffer[databufferlen++] = c;
+}
+
+
+static void
+printcursor (int both)
+{
+ int i;
+
+ flushdatabuffer ();
+ printf ("%8s ", "");
+ for (i=0; i < sizeof (databuffer); i++)
+ {
+ if (i == 8)
+ putchar (' ');
+ if (i+1 == nbytesprinted)
+ {
+ fputs (" ^ ", stdout);
+ if (!both)
+ break;
+ }
+ else
+ fputs (" ", stdout);
+ }
+ if (both)
+ {
+ fputs (" ", stdout);
+ for (i=0; i < nbytesprinted-1; i++)
+ putchar (' ');
+ putchar ('^');
+ }
+ databufferlen = skipdatabufferlen = nbytesprinted;
+}
+
+static void
+printerr (const char *text)
+{
+ printcursor (1);
+ printf ("\n Error: %s\n", text);
+}
+
+static void
+printctl (const char *text)
+{
+ if (verbose)
+ {
+ printcursor (0);
+ printf ("%s\n", text);
+ }
+}
+
+static void
+printchr (int c)
+{
+}
+
+static void
+printhex (int c)
+{
+}
+
+
+
+
+static int
+parse_and_print (FILE *fp)
+{
+ static const char tokenchars[] =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789-./_:*+=";
+ int c;
+ int level = 0;
+ int tokenc = 0;
+ int hexcount = 0;
+ int disphint = 0;
+ unsigned long datalen = 0;
+ char quote_buf[10];
+ int quote_idx = 0;
+ enum
+ {
+ INIT_STATE = 0, IN_NUMBER, PRE_DATA, IN_DATA, IN_STRING,
+ IN_ESCAPE, IN_OCT_ESC, IN_HEX_ESC,
+ CR_ESC, LF_ESC, IN_HEXFMT, IN_BASE64
+ }
+ state = INIT_STATE;
+
+
+ while ((c = getc (fp)) != EOF )
+ {
+ addrawdata (c);
+ switch (state)
+ {
+ case INIT_STATE:
+ if (tokenc)
+ {
+ if (strchr (tokenchars, c))
+ {
+ printchr (c);
+ continue;
+ }
+ tokenc = 0;
+ }
+ parse_init_state:
+ if (c == '(')
+ {
+ if (disphint)
+ {
+ printerr ("unmatched display hint");
+ disphint = 0;
+ }
+ printctl ("open");
+ level++;
+ }
+ else if (c == ')')
+ {
+ if (disphint)
+ {
+ printerr ("unmatched display hint");
+ disphint = 0;
+ }
+ printctl ("close");
+ level--;
+ }
+ else if (c == '\"')
+ {
+ state = IN_STRING;
+ printctl ("beginstring");
+ }
+ else if (c == '#')
+ {
+ state = IN_HEXFMT;
+ hexcount = 0;
+ printctl ("beginhex");
+ }
+ else if (c == '|')
+ {
+ state = IN_BASE64;
+ printctl ("beginbase64");
+ }
+ else if (c == '[')
+ {
+ if (disphint)
+ printerr ("nested display hint");
+ disphint = c;
+ }
+ else if (c == ']')
+ {
+ if (!disphint)
+ printerr ("no open display hint");
+ disphint = 0;
+ }
+ else if (c >= '0' && c <= '9')
+ {
+ if (c == '0')
+ printerr ("zero prefixed length");
+ state = IN_NUMBER;
+ datalen = (c - '0');
+ }
+ else if (strchr (tokenchars, c))
+ {
+ printchr (c);
+ tokenc = c;
+ }
+ else if (whitespace_p (c))
+ ;
+ else if (c == '{')
+ {
+ printerr ("rescanning is not supported");
+ }
+ else if (c == '&' || c == '\\')
+ {
+ printerr ("reserved punctuation detected");
+ }
+ else
+ {
+ printerr ("bad character detected");
+ }
+ break;
+
+ case IN_NUMBER:
+ if (digit_p (c))
+ {
+ unsigned long tmp = datalen * 10 + (c - '0');
+ if (tmp < datalen)
+ {
+ printerr ("overflow in data length");
+ state = INIT_STATE;
+ datalen = 0;
+ }
+ else
+ datalen = tmp;
+ }
+ else if (c == ':')
+ {
+ if (!datalen)
+ {
+ printerr ("no data length");
+ state = INIT_STATE;
+ }
+ else
+ state = PRE_DATA;
+ }
+ else if (c == '\"' || c == '#' || c == '|' )
+ {
+ /* We ignore the optional length and divert to the init
+ state parser code. */
+ goto parse_init_state;
+ }
+ else
+ printerr ("invalid length specification");
+ break;
+
+ case PRE_DATA:
+ state = IN_DATA;
+ printctl ("begindata");
+ case IN_DATA:
+ if (datalen)
+ {
+ printhex (c);
+ datalen--;
+ }
+ if (!datalen)
+ {
+ state = INIT_STATE;
+ printctl ("enddata");
+ }
+ break;
+
+ case IN_STRING:
+ if (c == '\"')
+ {
+ printctl ("endstring");
+ state = INIT_STATE;
+ }
+ else if (c == '\\')
+ state = IN_ESCAPE;
+ else
+ printchr (c);
+ break;
+
+ case IN_ESCAPE:
+ switch (c)
+ {
+ case 'b': case 't': case 'v': case 'n': case 'f':
+ case 'r': case '"': case '\'': case '\\':
+ printhex (c);
+ state = IN_STRING;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ state = IN_OCT_ESC;
+ quote_idx = 0;
+ quote_buf[quote_idx++] = c;
+ break;
+
+ case 'x':
+ state = IN_HEX_ESC;
+ quote_idx = 0;
+ break;
+
+ case '\r':
+ state = CR_ESC;
+ break;
+
+ case '\n':
+ state = LF_ESC;
+ break;
+
+ default:
+ printerr ("invalid escape sequence");
+ state = IN_STRING;
+ break;
+ }
+
+ case IN_OCT_ESC:
+ state = IN_STRING;
+ break;
+ case IN_HEX_ESC:
+ state = IN_STRING;
+ break;
+ case CR_ESC:
+ state = IN_STRING;
+ break;
+ case LF_ESC:
+ state = IN_STRING;
+ break;
+
+ case IN_HEXFMT:
+ if (hexdigit_p (c))
+ {
+ printchr (c);
+ hexcount++;
+ }
+ else if (c == '#')
+ {
+ if ((hexcount & 1))
+ printerr ("odd number of hex digits");
+ printctl ("endhex");
+ state = INIT_STATE;
+ }
+ else if (!whitespace_p (c))
+ printerr ("bad hex character");
+ break;
+
+ case IN_BASE64:
+ if (c == '|')
+ {
+ printctl ("endbase64");
+ state = INIT_STATE;
+ }
+ else
+ printchr (c);
+ break;
+
+ default:
+ logit ("invalid state %d detected", state);
+ exit (1);
+ }
+ }
+ flushdatabuffer ();
+ if (ferror (fp))
+ {
+ logit ("error reading input: %s\n", strerror (errno));
+ return -1;
+ }
+ return 0;
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+ int rc;
+
+ if (argc)
+ {
+ argc--; argv++;
+ }
+ while (argc && **argv == '-' && (*argv)[1] == '-')
+ {
+ if (!(*argv)[2])
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--version"))
+ print_version (0);
+ else if (!strcmp (*argv, "--help"))
+ print_version (1);
+ else if (!strcmp (*argv, "--verbose"))
+ {
+ argc--; argv++;
+ verbose = 1;
+ }
+ else if (!strcmp (*argv, "--decimal"))
+ {
+ argc--; argv++;
+ decimal = 1;
+ }
+ else
+ print_usage ();
+ }
+
+ if (!argc)
+ {
+ rc = parse_and_print (stdin);
+ }
+ else
+ {
+ for (; argc; argc--)
+ {
+ FILE *fp = fopen (*argv, "rb");
+ if (!fp)
+ {
+ logit ("can't open `%s': %s\n", *argv, strerror (errno));
+ rc = 1;
+ }
+ else
+ {
+ if ( parse_and_print (fp) )
+ rc = 1;
+ fclose (fp);
+ }
+ }
+ }
+
+
+ return !rc;
+}
+