aboutsummaryrefslogtreecommitdiffstats
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to 'util')
-rw-r--r--util/Makefile.am13
-rw-r--r--util/Makefile.in248
-rw-r--r--util/argparse.c653
-rw-r--r--util/errors.c69
-rw-r--r--util/fileutil.c31
-rw-r--r--util/iobuf.c762
-rw-r--r--util/logger.c139
-rw-r--r--util/memory.c460
-rw-r--r--util/miscutil.c33
-rw-r--r--util/strgutil.c63
-rw-r--r--util/ttyio.c114
11 files changed, 2585 insertions, 0 deletions
diff --git a/util/Makefile.am b/util/Makefile.am
new file mode 100644
index 000000000..5fd3e59ca
--- /dev/null
+++ b/util/Makefile.am
@@ -0,0 +1,13 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -I$(top_srcdir)/include
+
+noinst_LIBRARIES = util
+
+
+util_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \
+ ttyio.c argparse.c memory.c errors.c iobuf.c
+
+
+
+
diff --git a/util/Makefile.in b/util/Makefile.in
new file mode 100644
index 000000000..ca24380d6
--- /dev/null
+++ b/util/Makefile.in
@@ -0,0 +1,248 @@
+# Makefile.in generated automatically by automake 1.0 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+INCLUDES = -I$(top_srcdir)/include
+
+noinst_LIBRARIES = util
+
+util_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \
+ ttyio.c argparse.c memory.c errors.c iobuf.c
+mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs
+CONFIG_HEADER = ../config.h
+LIBRARIES = $(noinst_LIBRARIES)
+
+noinst_LIBFILES = libutil.a
+
+CC = @CC@
+LEX = @LEX@
+YACC = @YACC@
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+util_LIBADD =
+util_OBJECTS = logger.o fileutil.o miscutil.o strgutil.o ttyio.o \
+argparse.o memory.o errors.o iobuf.o
+EXTRA_util_SOURCES =
+LIBFILES = libutil.a
+AR = ar
+RANLIB = @RANLIB@
+DIST_COMMON = Makefile.am Makefile.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA)
+DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA)
+
+TAR = tar
+DEP_FILES = $(srcdir)/.deps/argparse.P $(srcdir)/.deps/errors.P \
+$(srcdir)/.deps/fileutil.P $(srcdir)/.deps/iobuf.P \
+$(srcdir)/.deps/logger.P $(srcdir)/.deps/memory.P \
+$(srcdir)/.deps/miscutil.P $(srcdir)/.deps/strgutil.P \
+$(srcdir)/.deps/ttyio.P
+SOURCES = $(util_SOURCES)
+OBJECTS = $(util_OBJECTS)
+
+default: all
+
+
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+ cd $(top_srcdir) && automake $(subdir)/Makefile
+
+Makefile: $(top_builddir)/config.status Makefile.in
+ cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+ rm -f $(noinst_LIBFILES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+ $(COMPILE) $<
+
+mostlyclean-compile:
+ rm -f *.o core
+
+clean-compile:
+
+distclean-compile:
+ rm -f *.tab.c
+
+maintainer-clean-compile:
+$(util_OBJECTS): ../config.h
+
+libutil.a: $(util_OBJECTS) $(util_LIBADD)
+ rm -f libutil.a
+ $(AR) cru libutil.a $(util_OBJECTS) $(util_LIBADD)
+ $(RANLIB) libutil.a
+
+ID: $(HEADERS) $(SOURCES)
+ here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
+
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
+ here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ rm -f TAGS ID
+
+maintainer-clean-tags:
+
+subdir = util
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+distdir: $(DEP_DISTFILES)
+ @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \
+ test -f $(distdir)/$$file \
+ || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $(srcdir)/$$file $(distdir)/$$file; \
+ done
+
+# This fragment is probably only useful for maintainers. It relies on
+# GNU make and gcc. It is only included in the generated Makefile.in
+# if `automake' is not passed the `--include-deps' flag.
+
+MKDEP = gcc -MM $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+
+-include $(srcdir)/.deps/.P
+$(srcdir)/.deps/.P: $(BUILT_SOURCES)
+ cd $(srcdir) && test -d .deps || mkdir .deps
+ echo > $@
+
+-include $(DEP_FILES)
+$(DEP_FILES): $(srcdir)/.deps/.P
+
+$(srcdir)/.deps/%.P: $(srcdir)/%.c
+ @echo "mkdeps $< > $@"
+ @re=`echo 's,^$(srcdir)//*,,g;s, $(srcdir)//*, ,g' | sed 's,\.,\\\\.,g'`; \
+ $(MKDEP) $< | sed "$$re" > $@-tmp
+ @if test -n "$o"; then \
+ sed 's/\.o:/$$o:/' $@-tmp > $@; \
+ rm $@-tmp; \
+ else \
+ mv $@-tmp $@; \
+ fi
+
+# End of maintainer-only section
+info:
+
+dvi:
+
+check: all
+
+installcheck:
+
+install-exec:
+
+install-data:
+
+install: install-exec install-data all
+ @:
+
+uninstall:
+
+all: $(LIBFILES) Makefile
+
+install-strip:
+ $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
+installdirs:
+
+
+mostlyclean-generic:
+ test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ rm -f Makefile $(DISTCLEANFILES)
+ rm -f config.cache config.log $(CONFIG_HEADER) stamp-h
+
+maintainer-clean-generic:
+ test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+ test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean: mostlyclean-noinstLIBRARIES mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+clean: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+ mostlyclean
+
+distclean: distclean-noinstLIBRARIES distclean-compile distclean-tags \
+ distclean-generic clean
+ rm -f config.status
+
+maintainer-clean: maintainer-clean-noinstLIBRARIES \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-generic distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: default mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info dvi check installcheck \
+install-exec install-data install uninstall all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/util/argparse.c b/util/argparse.c
new file mode 100644
index 000000000..3d51d014c
--- /dev/null
+++ b/util/argparse.c
@@ -0,0 +1,653 @@
+/* [argparse.c wk 17.06.97] Argument Parser for option handling
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ * This file is part of WkLib.
+ *
+ * WkLib 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.
+ *
+ * WkLib 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ *
+ * Note: This is an independent version of the one in WkLib
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+
+#ifdef DOCUMENTATION
+@Summary arg_parse
+ #include <wk/lib.h>
+
+ typedef struct {
+ char *argc; /* pointer to argc (value subject to change) */
+ char ***argv; /* pointer to argv (value subject to change) */
+ unsigned flags; /* Global flags (DO NOT CHANGE) */
+ int err; /* print error about last option */
+ /* 1 = warning, 2 = abort */
+ int r_opt; /* return option */
+ int r_type; /* type of return value (0 = no argument found)*/
+ union {
+ int ret_int;
+ long ret_long
+ ulong ret_ulong;
+ char *ret_str;
+ } r; /* Return values */
+ struct {
+ int index;
+ const char *last;
+ } internal; /* DO NOT CHANGE */
+ } ARGPARSE_ARGS;
+
+ typedef struct {
+ int short_opt;
+ const char *long_opt;
+ unsigned flags;
+ } ARGPARSE_OPTS;
+
+ int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
+
+@Description
+ This is my replacement for getopt(). See the example for a typical usage.
+ Global flags are:
+ Bit 0 : Do not remove options form argv
+ Bit 1 : Do not stop at last option but return other args
+ with r_opt set to -1.
+ Bit 2 : Assume options and real args are mixed.
+ Bit 3 : Do not use -- to stop option processing.
+ Bit 4 : Do not skip the first arg.
+ Bit 5 : allow usage of long option with only one dash
+ all other bits must be set to zero, this value is modified by the function
+ so assume this is write only.
+ Local flags (for each option):
+ Bit 2-0 : 0 = does not take an argument
+ 1 = takes int argument
+ 2 = takes string argument
+ 3 = takes long argument
+ 4 = takes ulong argument
+ Bit 3 : argument is optional (r_type will the be set to 0)
+ Bit 4 : allow 0x etc. prefixed values.
+ If can stop the option processing by setting opts to NULL, the function will
+ then return 0.
+@Return Value
+ Returns the args.r_opt or 0 if ready
+ r_opt may be -2 to indicate an unknown option.
+@See Also
+ ArgExpand
+@Notes
+ You do not need to process the options 'h', '--help' or '--version'
+ because this function includes standard help processing; but if you
+ specify '-h', '--help' or '--version' you have to do it yourself.
+ The option '--' stops argument processing; if bit 1 is set the function
+ continues to return normal arguments.
+ To process float args or unsigned args you must use a string args and do
+ the conversion yourself.
+@Example
+
+ ARGPARSE_OPTS opts[] = {
+ { 'v', "verbose", 0 },
+ { 'd', "debug", 0 },
+ { 'o', "output", 2 },
+ { 'c', "cross-ref", 2|8 },
+ { 'm', "my-option", 1|8 },
+ { 500, "have-no-short-option-for-this-long-option", 0 },
+ {0} };
+ ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
+
+ while( ArgParse( &pargs, &opts) ) {
+ switch( pargs.r_opt ) {
+ case 'v': opt.verbose++; break;
+ case 'd': opt.debug++; break;
+ case 'o': opt.outfile = pargs.r.ret_str; break;
+ case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
+ case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
+ case 500: opt.a_long_one++; break
+ default : pargs.err = 1; break; /* force warning output */
+ }
+ }
+ if( argc > 1 )
+ log_fatal( "Too many args");
+
+#endif /*DOCUMENTATION*/
+
+
+
+static void set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
+static void show_help(ARGPARSE_OPTS *opts, unsigned flags);
+static void show_version(void);
+
+
+int
+arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+ int index;
+ int argc;
+ char **argv;
+ char *s, *s2;
+ int i;
+
+ if( !(arg->flags & (1<<15)) ) { /* initialize this instance */
+ arg->internal.index = 0;
+ arg->internal.last = NULL;
+ arg->internal.inarg = 0;
+ arg->internal.stopped= 0;
+ arg->err = 0;
+ arg->flags |= 1<<15; /* mark initialized */
+ if( *arg->argc < 0 )
+ log_bug("Invalid argument for ArgParse\n");
+ }
+ argc = *arg->argc;
+ argv = *arg->argv;
+ index = arg->internal.index;
+
+ if( arg->err ) { /* last option was erroneous */
+ if( arg->r_opt == -3 )
+ s = "Missing argument for option \"%.50s\"\n";
+ else
+ s = "Invalid option \"%.50s\"\n";
+ log_error(s, arg->internal.last? arg->internal.last:"[??]" );
+ if( arg->err != 1 )
+ exit(2);
+ arg->err = 0;
+ }
+
+ if( !index && argc && !(arg->flags & (1<<4)) ) { /* skip the first entry */
+ argc--; argv++; index++;
+ }
+
+ next_one:
+ if( !argc ) { /* no more args */
+ arg->r_opt = 0;
+ goto leave; /* ready */
+ }
+
+ s = *argv;
+ arg->internal.last = s;
+
+ if( arg->internal.stopped && (arg->flags & (1<<1)) ) {
+ arg->r_opt = -1; /* not an option but a argument */
+ arg->r_type = 2;
+ arg->r.ret_str = s;
+ argc--; argv++; index++; /* set to next one */
+ }
+ else if( arg->internal.stopped ) { /* ready */
+ arg->r_opt = 0;
+ goto leave;
+ }
+ else if( *s == '-' && s[1] == '-' ) { /* long option */
+ arg->internal.inarg = 0;
+ if( !s[2] && !(arg->flags & (1<<3)) ) { /* stop option processing */
+ arg->internal.stopped = 1;
+ argc--; argv++; index++;
+ goto next_one;
+ }
+
+ for(i=0; opts[i].short_opt; i++ )
+ if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+2) )
+ break;
+
+ if( !opts[i].short_opt && !strcmp( "help", s+2) )
+ show_help(opts, arg->flags);
+ else if( !opts[i].short_opt && !strcmp( "version", s+2) )
+ show_version();
+ else if( !opts[i].short_opt && !strcmp( "warranty", s+2) ) {
+ puts( strusage(10) );
+ puts( strusage(31) );
+ exit(0);
+ }
+
+ arg->r_opt = opts[i].short_opt;
+ if( !opts[i].short_opt ) {
+ arg->r_opt = -2; /* unknown option */
+ arg->r.ret_str = s+2;
+ }
+ else if( (opts[i].flags & 7) ) {
+ s2 = argv[1];
+ if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/
+ arg->r_type = 0; /* because it is optional */
+ }
+ else if( !s2 ) {
+ arg->r_opt = -3; /* missing argument */
+ }
+ else if( *s2 == '-' && (opts[i].flags & 8) ) {
+ /* the argument is optional and the next seems to be
+ * an option. We do not check this possible option
+ * but assume no argument */
+ arg->r_type = 0;
+ }
+ else {
+ set_opt_arg(arg, opts[i].flags, s2);
+ argc--; argv++; index++; /* skip one */
+ }
+ }
+ else { /* does not take an argument */
+ arg->r_type = 0;
+ }
+ argc--; argv++; index++; /* set to next one */
+ }
+ else if( (*s == '-' && s[1]) || arg->internal.inarg ) { /* short option */
+ int dash_kludge = 0;
+ i = 0;
+ if( !arg->internal.inarg ) {
+ arg->internal.inarg++;
+ if( arg->flags & (1<<5) ) {
+ for(i=0; opts[i].short_opt; i++ )
+ if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+1)) {
+ dash_kludge=1;
+ break;
+ }
+ }
+ }
+ s += arg->internal.inarg;
+
+ if( !dash_kludge ) {
+ for(i=0; opts[i].short_opt; i++ )
+ if( opts[i].short_opt == *s )
+ break;
+ }
+
+ if( !opts[i].short_opt && *s == 'h' )
+ show_help(opts, arg->flags);
+
+ arg->r_opt = opts[i].short_opt;
+ if( !opts[i].short_opt ) {
+ arg->r_opt = -2; /* unknown option */
+ arg->internal.inarg++; /* point to the next arg */
+ arg->r.ret_str = s;
+ }
+ else if( (opts[i].flags & 7) ) {
+ if( s[1] && !dash_kludge ) {
+ s2 = s+1;
+ set_opt_arg(arg, opts[i].flags, s2);
+ }
+ else {
+ s2 = argv[1];
+ if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/
+ arg->r_type = 0; /* because it is optional */
+ }
+ else if( !s2 ) {
+ arg->r_opt = -3; /* missing argument */
+ }
+ else if( *s2 == '-' && s2[1] && (opts[i].flags & 8) ) {
+ /* the argument is optional and the next seems to be
+ * an option. We do not check this possible option
+ * but assume no argument */
+ arg->r_type = 0;
+ }
+ else {
+ set_opt_arg(arg, opts[i].flags, s2);
+ argc--; argv++; index++; /* skip one */
+ }
+ }
+ s = "x"; /* so that !s[1] yields false */
+ }
+ else { /* does not take an argument */
+ arg->r_type = 0;
+ arg->internal.inarg++; /* point to the next arg */
+ }
+ if( !s[1] || dash_kludge ) { /* no more concatenated short options */
+ arg->internal.inarg = 0;
+ argc--; argv++; index++;
+ }
+ }
+ else if( arg->flags & (1<<2) ) {
+ arg->r_opt = -1; /* not an option but a argument */
+ arg->r_type = 2;
+ arg->r.ret_str = s;
+ argc--; argv++; index++; /* set to next one */
+ }
+ else {
+ arg->internal.stopped = 1; /* stop option processing */
+ goto next_one;
+ }
+
+ leave:
+ *arg->argc = argc;
+ *arg->argv = argv;
+ arg->internal.index = index;
+ return arg->r_opt;
+}
+
+
+
+static void
+set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s)
+{
+ int base = (flags & 16)? 0 : 10;
+
+ switch( arg->r_type = (flags & 7) ) {
+ case 1: /* takes int argument */
+ arg->r.ret_int = (int)strtol(s,NULL,base);
+ break;
+ default:
+ case 2: /* takes string argument */
+ arg->r.ret_str = s;
+ break;
+ case 3: /* takes long argument */
+ arg->r.ret_long= strtol(s,NULL,base);
+ break;
+ case 4: /* takes ulong argument */
+ arg->r.ret_ulong= strtoul(s,NULL,base);
+ break;
+ }
+}
+
+static void
+show_help( ARGPARSE_OPTS *opts, unsigned flags )
+{
+ const char *s;
+
+ puts( strusage(10) );
+ s = strusage(12);
+ if( *s == '\n' )
+ s++;
+ puts(s);
+ if( opts[0].description ) { /* auto format the option description */
+ int i,j, indent;
+ /* get max. length of long options */
+ for(i=indent=0; opts[i].short_opt; i++ ) {
+ if( opts[i].long_opt )
+ if( (j=strlen(opts[i].long_opt)) > indent && j < 35 )
+ indent = j;
+ }
+ /* example: " -v, --verbose Viele Sachen ausgeben" */
+ indent += 10;
+ puts("Options:");
+ for(i=0; opts[i].short_opt; i++ ) {
+ if( opts[i].short_opt < 256 )
+ printf(" -%c", opts[i].short_opt );
+ else
+ fputs(" ", stdout);
+ j = 3;
+ if( opts[i].long_opt )
+ j += printf("%c --%s ", opts[i].short_opt < 256?',':' ',
+ opts[i].long_opt );
+ for(;j < indent; j++ )
+ putchar(' ');
+ if( (s = opts[i].description) ) {
+ for(; *s; s++ ) {
+ if( *s == '\n' ) {
+ if( s[1] ) {
+ putchar('\n');
+ for(j=0;j < indent; j++ )
+ putchar(' ');
+ }
+ }
+ else
+ putchar(*s);
+ }
+ }
+ putchar('\n');
+ }
+ if( flags & 32 )
+ puts("\n(A single dash may be used instead of the double ones)");
+ }
+ fflush(stdout);
+ exit(0);
+}
+
+static void
+show_version()
+{
+ const char *s;
+ printf("%s version %s (%s", strusage(13), strusage(14), strusage(45) );
+ if( (s = strusage(24)) && *s ) {
+ #ifdef DEBUG
+ printf(", %s, dbg)\n", s);
+ #else
+ printf(", %s)\n", s);
+ #endif
+ }
+ else {
+ #ifdef DEBUG
+ printf(", dbg)\n");
+ #else
+ printf(")\n");
+ #endif
+ }
+ fflush(stdout);
+ exit(0);
+}
+
+
+
+void
+usage( int level )
+{
+ static int sentinel=0;
+
+ if( sentinel )
+ return;
+
+ sentinel++;
+ if( !level ) {
+ fputs( strusage(level), stderr ); putc( '\n', stderr );
+ fputs( strusage(31), stderr);
+ #if DEBUG
+ fprintf(stderr, "%s (%s - Debug)\n", strusage(32), strusage(24) );
+ #else
+ fprintf(stderr, "%s (%s)\n", strusage(32), strusage(24) );
+ #endif
+ fflush(stderr);
+ }
+ else if( level == 1 ) {
+ fputs(strusage(level),stderr);putc('\n',stderr);
+ exit(2);}
+ else if( level == 2 ) {
+ puts(strusage(level)); exit(0);}
+ sentinel--;
+}
+
+
+const char *
+default_strusage( int level )
+{
+ const char *p;
+ switch( level ) {
+ case 0: p = strusage(10); break;
+ case 1: p = strusage(11); break;
+ case 2: p = strusage(12); break;
+ case 10: p = "WkLib"
+ #if DOS386 && __WATCOMC__
+ " (DOS4G)"
+ #elif DOS386
+ " (DOSX)"
+ #elif DOS16RM
+ " (DOS16RM)"
+ #elif M_I86VM
+ " (VCM)"
+ #elif UNIX || POSIX
+ " (Posix)"
+ #elif OS2
+ " (OS/2)"
+ #elif WINNT && __CYGWIN32__
+ " (CygWin)"
+ #elif WINNT
+ " (WinNT)"
+ #elif NETWARE
+ " (Netware)"
+ #elif VMS
+ " (VMS)"
+ #endif
+ "; Copyright (c) 1997 by Werner Koch (dd9jn)" ; break;
+ case 11: p = "usage: ?"; break;
+ case 16:
+ case 15: p = "[Untitled]"; break;
+ case 23: p = "[unknown]"; break;
+ case 24: p = ""; break;
+ case 12: p =
+ "This is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation; either version 2 of the License, or\n"
+ "(at your option) any later version.\n\n"
+ "WkLib is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,"
+ " USA.\n" ;
+ break;
+ case 22:
+ #if MSDOS
+ #if USE_EMS
+ p = "MSDOS+EMS";
+ #else
+ p = "MSDOS";
+ #endif
+ #elif OS2
+ p = "OS/2";
+ #elif WINNT && __CYGWIN32__
+ p = "CygWin";
+ #elif WINNT
+ p = "WinNT";
+ #elif DOS386
+ p = "DOS386";
+ #elif EMX
+ p = "EMX";
+ #elif DOS16RM
+ p = "DOS16RM";
+ #elif NETWARE
+ p = "Netware";
+ #elif __linux__
+ p = "Linux";
+ #elif UNIX || M_UNIX || M_XENIX
+ p = "UNIX";
+ #elif VMS
+ p = "VMS";
+ #else
+ p = "UnknownOS";
+ #endif
+ break;
+ case 31: p =
+ "This program comes with ABSOLUTELY NO WARRANTY.\n"
+ "This is free software, and you are welcome to redistribute it\n"
+ "under certain conditions. See the file COPYING for details.\n";
+ break;
+ case 32: p = "["
+ #if MSDOS
+ "MSDOS Version"
+ #elif DOS386 && __ZTC__
+ "32-Bit MSDOS Version (Zortech's DOSX)"
+ #elif DOS386
+ "32-Bit MSDOS Version"
+ #elif OS20 && EMX
+ "OS/2 2.x EMX Version"
+ #elif OS20
+ "OS/2 2.x Version"
+ #elif OS2
+ "OS/2 1.x Version"
+ #elif WINNT && __CYGWIN32__
+ "Cygnus WinAPI Version"
+ #elif WINNT
+ "Windoze NT Version"
+ #elif EMX
+ "EMX Version"
+ #elif NETWARE
+ "NLM Version"
+ #elif DOS16RM
+ "DOS16RM Version"
+ #elif __linux__
+ "Linux Version"
+ #elif VMS
+ "OpenVMS Version"
+ #elif POSIX
+ "POSIX Version"
+ #elif M_UNIX || M_XENIX
+ "*IX Version"
+ #endif
+ "]";
+ break;
+ case 33: p =
+ #ifdef MULTI_THREADED
+ "mt"
+ #else
+ ""
+ #endif
+ ; break;
+ case 42:
+ case 43:
+ case 44:
+ case 45: p = ""; break;
+ default: p = "?";
+ }
+
+ return p;
+}
+
+
+
+#ifdef TEST
+static struct {
+ int verbose;
+ int debug;
+ char *outfile;
+ char *crf;
+ int myopt;
+ int echo;
+ int a_long_one;
+}opt;
+
+int
+main(int argc, char **argv)
+{
+ ARGPARSE_OPTS opts[] = {
+ { 'v', "verbose", 0 , "Laut sein"},
+ { 'e', "echo" , 0 , "Zeile ausgeben, damit wir sehen, was wir einegegeben haben"},
+ { 'd', "debug", 0 , "Debug\nfalls mal etasws\nSchief geht"},
+ { 'o', "output", 2 },
+ { 'c', "cross-ref", 2|8, "cross-reference erzeugen\n" },
+ { 'm', "my-option", 1|8 },
+ { 500, "a-long-option", 0 },
+ {0} };
+ ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 };
+ int i;
+
+ while( ArgParse( &pargs, opts) ) {
+ switch( pargs.r_opt ) {
+ case -1 : printf( "arg='%s'\n", pargs.r.ret_str); break;
+ case 'v': opt.verbose++; break;
+ case 'e': opt.echo++; break;
+ case 'd': opt.debug++; break;
+ case 'o': opt.outfile = pargs.r.ret_str; break;
+ case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
+ case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
+ case 500: opt.a_long_one++; break;
+ default : pargs.err = 1; break; /* force warning output */
+ }
+ }
+ for(i=0; i < argc; i++ )
+ printf("%3d -> (%s)\n", i, argv[i] );
+ puts("Options:");
+ if( opt.verbose )
+ printf(" verbose=%d\n", opt.verbose );
+ if( opt.debug )
+ printf(" debug=%d\n", opt.debug );
+ if( opt.outfile )
+ printf(" outfile='%s'\n", opt.outfile );
+ if( opt.crf )
+ printf(" crffile='%s'\n", opt.crf );
+ if( opt.myopt )
+ printf(" myopt=%d\n", opt.myopt );
+ if( opt.a_long_one )
+ printf(" a-long-one=%d\n", opt.a_long_one );
+ if( opt.echo )
+ printf(" echo=%d\n", opt.echo );
+ return 0;
+}
+#endif
+
+/**** bottom of file ****/
diff --git a/util/errors.c b/util/errors.c
new file mode 100644
index 000000000..1e4579fc4
--- /dev/null
+++ b/util/errors.c
@@ -0,0 +1,69 @@
+/* errors.c - error strings
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "errors.h"
+
+const char *
+g10_errstr( int err )
+{
+ static char buf[50];
+ const char *p;
+
+ #define X(n,s) case G10ERR_##n : p = s; break;
+ switch( err ) {
+ X(GENERAL, "General error")
+ X(UNKNOWN_PACKET, "Unknown packet type")
+ X(UNKNOWN_VERSION,"Unknown version")
+ X(PUBKEY_ALGO ,"Unknown pubkey algorithm")
+ X(DIGEST_ALGO ,"Unknown digest algorithm")
+ X(BAD_PUBKEY ,"Bad public key")
+ X(BAD_SECKEY ,"Bad secret key")
+ X(BAD_SIGN ,"Bad signature")
+ X(CHECKSUM , "Checksum error")
+ X(BAD_PASS , "Bad passphrase")
+ X(NO_PUBKEY ,"Public key not found")
+ X(CIPHER_ALGO ,"Unknown cipher algorithm")
+ X(KEYRING_OPEN ,"Can't open the keyring")
+ X(BAD_RING ,"Broken keyring")
+ X(NO_USER_ID ,"No such user id found")
+ X(NO_SECKEY ,"Secret key not available")
+ X(WRONG_SECKEY ,"Wrong secret key used")
+ X(UNSUPPORTED ,"Not supported")
+ X(BAD_KEY ,"Bad key")
+ X(READ_FILE ,"File read error")
+ X(WRITE_FILE ,"File write error")
+ X(COMPR_ALGO ,"Unknown compress algorithm")
+ X(OPEN_FILE ,"File open error")
+ X(CREATE_FILE ,"File create error")
+ X(PASSPHRASE ,"Invalid passphrase")
+ X(NI_PUBKEY ,"Unimplemented pubkey algorithm")
+ X(NI_CIPHER ,"Unimplemented cipher algorithm")
+
+ default: p = buf; sprintf(buf, "Error code %d", err); break;
+ }
+ #undef X
+ return p;
+}
+
diff --git a/util/fileutil.c b/util/fileutil.c
new file mode 100644
index 000000000..e2ea9b20e
--- /dev/null
+++ b/util/fileutil.c
@@ -0,0 +1,31 @@
+/* fileutil.c - file utilities
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include "util.h"
+#include "memory.h"
+#include "ttyio.h"
+
+
diff --git a/util/iobuf.c b/util/iobuf.c
new file mode 100644
index 000000000..12fc74ff6
--- /dev/null
+++ b/util/iobuf.c
@@ -0,0 +1,762 @@
+/* iobuf.c - file handling
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "memory.h"
+#include "util.h"
+#include "iobuf.h"
+
+typedef struct {
+ FILE *fp; /* open file handle */
+ char fname[1]; /* name of the file */
+} file_filter_ctx_t ;
+
+typedef struct {
+ int usage;
+ size_t size;
+ size_t count;
+ int eof;
+} block_filter_ctx_t;
+
+static int underflow(IOBUF a);
+
+/****************
+ * Read data from a file into buf which has an allocated length of *LEN.
+ * return the number of read bytes in *LEN. OPAQUE is the FILE * of
+ * the stream. A is not used.
+ * control maybe:
+ * IOBUFCTRL_INIT: called just before the function is linked into the
+ * list of function. This can be used to prepare internal
+ * data structures of the function.
+ * IOBUFCTRL_FREE: called just before the function is removed from the
+ * list of functions and can be used to release internal
+ * data structures or close a file etc.
+ * IOBUFCTRL_UNDERFLOW: called by iobuf_underflow to fill the buffer
+ * with new stuff. *RET_LEN is the available size of the
+ * buffer, and should be set to the number of bytes
+ * which were put into the buffer. The function
+ * returns 0 to indicate success, -1 on EOF and
+ * G10ERR_xxxxx for other errors.
+ *
+ * IOBUFCTRL_FLUSH: called by iobuf_flush() to write out the collected stuff.
+ * *RET_LAN is the number of bytes in BUF.
+ *
+ */
+static int
+file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
+{
+ file_filter_ctx_t *a = opaque;
+ FILE *fp = a->fp;
+ size_t size = *ret_len;
+ size_t nbytes = 0;
+ int c, rc = 0;
+ char *p;
+
+ if( control == IOBUFCTRL_UNDERFLOW ) {
+ assert( size ); /* need a buffer */
+ for(; size; size-- ) {
+ if( (c=getc(fp)) == EOF ) {
+ if( ferror(fp) ) {
+ log_error("%s: read error: %s\n",
+ a->fname, strerror(errno));
+ rc = G10ERR_READ_FILE;
+ }
+ else if( !nbytes )
+ rc = -1; /* okay: we can return EOF now. */
+ break;
+ }
+ buf[nbytes++] = c & 0xff;
+ }
+ *ret_len = nbytes;
+ }
+ else if( control == IOBUFCTRL_FLUSH ) {
+ for(p=buf; nbytes < size; nbytes++, p++ ) {
+ if( putc(*p, fp) == EOF ) {
+ log_error("%s: write error: %s\n",
+ a->fname, strerror(errno));
+ rc = G10ERR_WRITE_FILE;
+ break;
+ }
+ }
+ *ret_len = nbytes;
+ }
+ else if( control == IOBUFCTRL_INIT ) {
+ }
+ else if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "file_filter";
+ }
+ else if( control == IOBUFCTRL_FREE ) {
+ if( fp != stdin && fp != stdout )
+ fclose(fp);
+ fp = NULL;
+ m_free(a); /* we can free our context now */
+ }
+
+ return rc;
+}
+
+
+/****************
+ * This is used to implement the block write mode.
+ * Block reading is done on a byte by byte basis in readbyte(),
+ * without a filter
+ */
+static int
+block_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len)
+{
+ block_filter_ctx_t *a = opaque;
+ size_t size = *ret_len;
+ int c, rc = 0;
+ char *p;
+
+ if( control == IOBUFCTRL_UNDERFLOW ) {
+ size_t n=0;
+
+ p = buf;
+ assert( size ); /* need a buffer */
+ if( a->eof ) /* don't read any further */
+ rc = -1;
+ while( !rc && size ) {
+ if( !a->size ) { /* get the length bytes */
+ c = iobuf_get(chain);
+ a->size = c << 8;
+ c = iobuf_get(chain);
+ a->size |= c;
+ if( c == -1 ) {
+ log_error("block_filter: error reading length info\n");
+ rc = G10ERR_READ_FILE;
+ }
+ if( !a->size ) {
+ a->eof = 1;
+ if( !n )
+ rc = -1;
+ break;
+ }
+ }
+
+ for(; !rc && size && a->size; size--, a->size-- ) {
+ if( (c=iobuf_get(chain)) == -1 ) {
+ log_error("block_filter %p: read error (size=%lu,a->size=%lu)\n",
+ a, (ulong)size, (ulong)a->size);
+ rc = G10ERR_READ_FILE;
+ }
+ else {
+ *p++ = c;
+ n++;
+ }
+ }
+ }
+ *ret_len = n;
+ }
+ else if( control == IOBUFCTRL_FLUSH ) {
+ size_t avail, n;
+
+ for(p=buf; !rc && size; ) {
+ n = size;
+ avail = a->size - a->count;
+ if( !avail ) {
+ if( n > a->size ) {
+ iobuf_put( chain, (a->size >> 8) & 0xff );
+ iobuf_put( chain, a->size & 0xff );
+ avail = a->size;
+ a->count = 0;
+ }
+ else {
+ iobuf_put( chain, (n >> 8) & 0xff );
+ iobuf_put( chain, n & 0xff );
+ avail = n;
+ a->count = a->size - n;
+ }
+ }
+ if( n > avail )
+ n = avail;
+ if( iobuf_write(chain, p, n ) )
+ rc = G10ERR_WRITE_FILE;
+ a->count += n;
+ p += n;
+ size -= n;
+ }
+ }
+ else if( control == IOBUFCTRL_INIT ) {
+ if( DBG_IOBUF )
+ log_debug("init block_filter %p\n", a );
+ if( a->usage == 1 )
+ a->count = a->size = 0;
+ else
+ a->count = a->size; /* force first length bytes */
+ a->eof = 0;
+ }
+ else if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "block_filter";
+ }
+ else if( control == IOBUFCTRL_FREE ) {
+ if( a->usage == 2 ) { /* write the end markers */
+ iobuf_writebyte(chain, 0);
+ iobuf_writebyte(chain, 0);
+ }
+ else if( a->size ) {
+ log_error("block_filter: pending bytes!\n");
+ }
+ if( DBG_IOBUF )
+ log_debug("free block_filter %p\n", a );
+ m_free(a); /* we can free our context now */
+ }
+
+ return rc;
+}
+
+
+
+/****************
+ * Allocate a new io buffer, with no function assigned.
+ * Usage is the desired usage: 1 for input, 2 for output, 3 for temp buffer
+ * BUFSIZE is a suggested buffer size.
+ */
+IOBUF
+iobuf_alloc(int usage, size_t bufsize)
+{
+ IOBUF a;
+ static int number=0;
+
+ a = m_alloc_clear(sizeof *a);
+ a->usage = usage;
+ a->d.buf = m_alloc( bufsize );
+ a->d.size = bufsize;
+ a->no = ++number;
+ a->subno = 0;
+ return a;
+}
+
+
+int
+iobuf_close( IOBUF a )
+{
+ IOBUF a2;
+ size_t dummy_len;
+ int rc=0;
+
+ for( ; a; a = a2 ) {
+ a2 = a->chain;
+ if( a->usage == 2 && (rc=iobuf_flush(a)) )
+ log_error("iobuf_flush failed on close: %s\n", g10_errstr(rc));
+
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: close '%s'\n", a->no, a->subno, a->desc );
+ if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE,
+ a->chain, NULL, &dummy_len)) )
+ log_error("IOBUFCTRL_FREE failed on close: %s\n", g10_errstr(rc) );
+ m_free(a->recorder.buf);
+ m_free(a->d.buf);
+ m_free(a);
+ }
+ return rc;
+}
+
+int
+iobuf_cancel( IOBUF a )
+{
+ /* FIXME: do an unlink if usage is 2 */
+ return iobuf_close(a);
+}
+
+
+/****************
+ * create a temporary iobuf, which can be used to collect stuff
+ * in an iobuf and later be written by iobuf_write_temp() to another
+ * iobuf.
+ */
+IOBUF
+iobuf_temp()
+{
+ IOBUF a;
+
+ a = iobuf_alloc(3, 8192 );
+
+ return a;
+}
+
+
+/****************
+ * Create a head iobuf for reading from a file
+ * returns: NULL if an error occures and sets errno
+ */
+IOBUF
+iobuf_open( const char *fname )
+{
+ IOBUF a;
+ FILE *fp;
+ file_filter_ctx_t *fcx;
+ size_t len;
+
+ if( !fname ) {
+ fp = stdin; /* fixme: set binary mode for msdoze */
+ fname = "[stdin]";
+ }
+ else if( !(fp = fopen(fname, "rb")) )
+ return NULL;
+ a = iobuf_alloc(1, 8192 );
+ fcx = m_alloc( sizeof *fcx + strlen(fname) );
+ fcx->fp = fp;
+ strcpy(fcx->fname, fname );
+ a->filter = file_filter;
+ a->filter_ov = fcx;
+ file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
+ file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: open '%s'\n", a->no, a->subno, fname );
+
+ return a;
+}
+
+/****************
+ * create a iobuf for writing to a file; the file will be created.
+ */
+IOBUF
+iobuf_create( const char *fname )
+{
+ IOBUF a;
+ FILE *fp;
+ file_filter_ctx_t *fcx;
+ size_t len;
+
+ if( !fname ) {
+ fp = stdout;
+ fname = "[stdout]";
+ }
+ else if( !(fp = fopen(fname, "wb")) )
+ return NULL;
+ a = iobuf_alloc(2, 8192 );
+ fcx = m_alloc( sizeof *fcx + strlen(fname) );
+ fcx->fp = fp;
+ strcpy(fcx->fname, fname );
+ a->filter = file_filter;
+ a->filter_ov = fcx;
+ file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
+ file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: create '%s'\n", a->no, a->subno, a->desc );
+
+ return a;
+}
+
+/****************
+ * Register an i/o filter.
+ */
+int
+iobuf_push_filter( IOBUF a,
+ int (*f)(void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *len), void *ov )
+{
+ IOBUF b;
+ size_t dummy_len=0;
+ int rc=0;
+
+ if( a->usage == 2 && (rc=iobuf_flush(a)) )
+ return rc;
+ /* make a copy of the current stream, so that
+ * A is the new stream and B the original one.
+ * The contents of the buffers are transferred to the
+ * new stream.
+ */
+ b = m_alloc(sizeof *b);
+ memcpy(b, a, sizeof *b );
+ /* remove the filter stuff from the new stream */
+ a->filter = NULL;
+ a->filter_ov = NULL;
+ if( a->usage == 2 ) { /* allocate a fresh buffer for the original stream */
+ b->d.buf = m_alloc( a->d.size );
+ b->d.len = 0;
+ b->d.start = 0;
+ }
+ else { /* allocate a fresh buffer for the new stream */
+ a->d.buf = m_alloc( a->d.size );
+ a->d.len = 0;
+ a->d.start = 0;
+ }
+ /* disable nlimit for the new stream */
+ a->nlimit = a->nbytes = 0;
+ /* disable recorder for the original stream */
+ b->recorder.buf = NULL;
+ /* make a link from the new stream to the original stream */
+ a->chain = b;
+
+ /* setup the function on the new stream */
+ a->filter = f;
+ a->filter_ov = ov;
+
+ a->subno = b->subno + 1;
+ f( ov, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &dummy_len );
+
+ if( DBG_IOBUF ) {
+ log_debug("iobuf-%d.%d: push '%s'\n", a->no, a->subno, a->desc );
+ for(b=a; b; b = b->chain )
+ log_debug("\tchain: %d.%d '%s'\n", b->no, b->subno, b->desc );
+ }
+
+ /* now we can initialize the new function if we have one */
+ if( a->filter && (rc = a->filter(a->filter_ov, IOBUFCTRL_INIT, a->chain,
+ NULL, &dummy_len)) )
+ log_error("IOBUFCTRL_INIT failed: %s\n", g10_errstr(rc) );
+ return rc;
+}
+
+/****************
+ * Remove an i/o filter.
+ */
+int
+iobuf_pop_filter( IOBUF a, int (*f)(void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *len), void *ov )
+{
+ IOBUF b;
+ size_t dummy_len=0;
+ int rc=0;
+
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: pop '%s'\n", a->no, a->subno, a->desc );
+ if( !a->filter ) { /* this is simple */
+ b = a->chain;
+ assert(b);
+ m_free(a->d.buf);
+ memcpy(a,b, sizeof *a);
+ m_free(b);
+ return 0;
+ }
+ for(b=a ; b; b = b->chain )
+ if( b->filter == f && (!ov || b->filter_ov == ov) )
+ break;
+ if( !b )
+ log_bug("iobuf_pop_filter(): filter function not found\n");
+
+ /* flush this stream if it is an output stream */
+ if( a->usage == 2 && (rc=iobuf_flush(b)) ) {
+ log_error("iobuf_flush failed in pop_filter: %s\n", g10_errstr(rc));
+ return rc;
+ }
+ /* and tell the filter to free it self */
+ if( (rc = b->filter(b->filter_ov, IOBUFCTRL_FREE, b->chain,
+ NULL, &dummy_len)) ) {
+ log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
+ return rc;
+ }
+
+ /* and look how to remove it */
+ if( a == b && !b->chain )
+ log_bug("can't remove the last filter from the chain\n");
+ else if( a == b ) { /* remove the first iobuf from the chain */
+ /* everything from b is copied to a. This is save because
+ * a flush has been done on the to be removed entry
+ */
+ b = a->chain;
+ m_free(a->d.buf);
+ memcpy(a,b, sizeof *a);
+ m_free(b);
+ }
+ else if( !b->chain ) { /* remove the last iobuf from the chain */
+ log_bug("Ohh jeee, trying to a head filter\n");
+ }
+ else { /* remove an intermediate iobuf from the chain */
+ log_bug("Ohh jeee, trying to remove an intermediate filter\n");
+ }
+
+ return rc;
+}
+
+
+
+/****************
+ * read underflow: read more bytes into the buffer and return
+ * the first byte or -1 on EOF.
+ */
+static int
+underflow(IOBUF a)
+{
+ size_t len;
+ int rc;
+
+ /*log_debug("iobuf-%d.%d: underflow: start=%lu len=%lu\n",
+ a->no, a->subno, (ulong)a->d.start, (ulong)a->d.len );*/
+ assert( a->d.start == a->d.len );
+ if( a->usage == 3 )
+ return -1; /* EOF because a temp buffer can't do an underflow */
+ if( a->filter_eof ) {
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: filter eof\n", a->no, a->subno );
+ return -1;
+ }
+
+ if( a->filter ) {
+ len = a->d.size;
+ rc = a->filter( a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain,
+ a->d.buf, &len );
+ if( a->usage == 1 && rc == -1 ) { /* EOF: we can remove the filter */
+ size_t dummy_len;
+
+ /* and tell the filter to free it self */
+ if( (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain,
+ NULL, &dummy_len)) )
+ log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
+ a->filter = NULL;
+ a->desc = NULL;
+ a->filter_ov = NULL;
+ a->filter_eof = 1;
+ }
+
+ if( !len )
+ return -1;
+ a->d.len = len;
+ a->d.start = 0;
+ return a->d.buf[a->d.start++];
+ }
+ else
+ return -1; /* no filter; return EOF */
+}
+
+
+void
+iobuf_clear_eof(IOBUF a)
+{
+ assert(a->usage == 1);
+
+ if( a->filter )
+ log_info("iobuf-%d.%d: clear_eof '%s' with enabled filter\n", a->no, a->subno, a->desc );
+ if( !a->filter_eof )
+ log_info("iobuf-%d.%d: clear_eof '%s' with no EOF pending\n", a->no, a->subno, a->desc );
+ iobuf_pop_filter(a, NULL, NULL);
+}
+
+
+int
+iobuf_flush(IOBUF a)
+{
+ size_t len;
+ int rc;
+
+ /*log_debug("iobuf-%d.%d: flush\n", a->no, a->subno );*/
+ if( a->usage == 3 )
+ log_bug("temp buffer too short\n");
+ else if( a->usage != 2 )
+ log_bug("flush on non-output iobuf\n");
+ else if( !a->filter )
+ log_bug("iobuf_flush: no filter\n");
+ len = a->d.len;
+ rc = a->filter( a->filter_ov, IOBUFCTRL_FLUSH, a->chain, a->d.buf, &len );
+ if( !rc && len != a->d.len ) {
+ log_info("iobuf_flush did not write all!\n");
+ rc = G10ERR_WRITE_FILE;
+ }
+ a->d.len = 0;
+
+ return rc;
+}
+
+
+/****************
+ * Read a byte from the iobuf; returns -1 on EOF
+ */
+int
+iobuf_readbyte(IOBUF a)
+{
+ int c;
+
+ if( a->nlimit && a->nbytes >= a->nlimit )
+ return -1; /* forced EOF */
+
+ if( a->d.start < a->d.len ) {
+ c = a->d.buf[a->d.start++];
+ }
+ else if( (c=underflow(a)) == -1 )
+ return -1; /* EOF */
+
+ a->nbytes++;
+
+ if( a->recorder.buf ) {
+ if( a->recorder.len >= a->recorder.size ) {
+ a->recorder.size += 500;
+ a->recorder.buf = m_realloc( a->recorder.buf, a->recorder.size );
+ }
+ ((byte*)a->recorder.buf)[a->recorder.len++] = c;
+ }
+ return c;
+}
+
+
+int
+iobuf_writebyte(IOBUF a, unsigned c)
+{
+ if( a->d.len == a->d.size )
+ if( iobuf_flush(a) )
+ return -1;
+
+ assert( a->d.len < a->d.size );
+ a->d.buf[a->d.len++] = c;
+ return 0;
+}
+
+
+int
+iobuf_write(IOBUF a, byte *buf, unsigned buflen )
+{
+ for( ; buflen; buflen--, buf++ )
+ if( iobuf_writebyte(a, *buf) )
+ return -1;
+ return 0;
+}
+
+
+
+/****************
+ * copy the contents of TEMP to A.
+ */
+int
+iobuf_write_temp( IOBUF a, IOBUF temp )
+{
+ return iobuf_write(a, temp->d.buf, temp->d.len );
+}
+
+/****************
+ * copy the contents of the temp io stream to BUFFER.
+ */
+size_t
+iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen )
+{
+ size_t n = a->d.len;
+
+ if( n > buflen )
+ n = buflen;
+ memcpy( buffer, a->d.buf, n );
+ return n;
+}
+
+
+/****************
+ * Set a limit, how much bytes may be read from the input stream A.
+ * Setting the limit to 0 disables this feature.
+ */
+void
+iobuf_set_limit( IOBUF a, unsigned long nlimit )
+{
+ a->nlimit = nlimit;
+ a->nbytes = 0;
+}
+
+
+
+void
+iobuf_start_recorder( IOBUF a )
+{
+ m_free(a->recorder.buf);
+ a->recorder.size = 500;
+ a->recorder.buf = m_alloc(a->recorder.size);
+ a->recorder.len = 0;
+}
+
+void
+iobuf_push_recorder( IOBUF a, int c )
+{
+ if( a->recorder.buf ) {
+ if( a->recorder.len >= a->recorder.size ) {
+ a->recorder.size += 500;
+ a->recorder.buf = m_realloc( a->recorder.buf, a->recorder.size );
+ }
+ ((byte*)a->recorder.buf)[a->recorder.len++] = c;
+ }
+}
+
+
+char *
+iobuf_stop_recorder( IOBUF a, size_t *n )
+{
+ char *p;
+ if( !a->recorder.buf )
+ log_bug("iobuf_recorder not started\n");
+ p = a->recorder.buf;
+ if( n )
+ *n = a->recorder.len;
+ a->recorder.buf = NULL;
+ return p;
+}
+
+
+/****************
+ * Return the length of an open file
+ */
+u32
+iobuf_get_filelength( IOBUF a )
+{
+ struct stat st;
+
+ for( ; a; a = a->chain )
+ if( !a->chain && a->filter == file_filter ) {
+ file_filter_ctx_t *b = a->filter_ov;
+ FILE *fp = b->fp;
+
+ if( !fstat(fileno(fp), &st) )
+ return st.st_size;
+ log_error("fstat() failed: %s\n", strerror(errno) );
+ break;
+ }
+
+ return 0;
+}
+
+/****************
+ * Start the block write mode, see rfc1991.new for details.
+ * A value of 0 for N stops this mode (flushes and writes
+ * the end marker)
+ */
+void
+iobuf_set_block_mode( IOBUF a, size_t n )
+{
+ block_filter_ctx_t *ctx = m_alloc_clear( sizeof *ctx );
+
+ assert( a->usage == 1 || a->usage == 2 );
+ ctx->usage = a->usage;
+ if( !n ) {
+ iobuf_pop_filter(a, block_filter, NULL );
+ }
+ else {
+ ctx->size = n; /* only needed for usage 2 */
+ iobuf_push_filter(a, block_filter, ctx );
+ }
+}
+
+
+/****************
+ * checks wether the stream is in block mode
+ */
+int
+iobuf_in_block_mode( IOBUF a )
+{
+ for(; a; a = a->chain )
+ if( a->filter == block_filter )
+ return 1; /* yes */
+ return 0; /* no */
+}
+
+
+
diff --git a/util/logger.c b/util/logger.c
new file mode 100644
index 000000000..803420cd8
--- /dev/null
+++ b/util/logger.c
@@ -0,0 +1,139 @@
+/* logger.c - log functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "util.h"
+
+/****************
+ * General interface for printing a line
+ * level 0 := print to /dev/null
+ * 1 := print to stdout
+ * 2 := print as info to stderr
+ * 3 := ditto but as error
+ */
+void
+printstr( int level, const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ if( !level )
+ return;
+
+ if( !fmt ) {
+ putc('\n', level? stderr: stdout);
+ return;
+ }
+
+ va_start( arg_ptr, fmt ) ;
+ if( level < 2 ) {
+ vfprintf(stdout,fmt,arg_ptr) ;
+ }
+ else {
+ fprintf(stderr, level==2? "%s: ": "%s: error: ", strusage(13) ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ }
+ va_end(arg_ptr);
+}
+
+
+void
+log_info( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "info: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+}
+
+void
+log_error( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "error: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+}
+
+void
+log_fatal( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "Fatal: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+ exit(2);
+}
+
+void
+log_bug( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "\nInternal Error: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+ fflush(stderr);
+ abort();
+}
+
+void
+log_debug( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "DBG: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+}
+
+
+
+void
+log_hexdump( const char *text, char *buf, size_t len )
+{
+ int i;
+
+ fprintf(stderr, "DBG: %s", text );
+ for(i=0; i < len; i++ )
+ fprintf(stderr, " %02X", ((byte*)buf)[i] );
+ fputc('\n', stderr);
+}
+
+
+void
+log_mpidump( const char *text, MPI a )
+{
+ fprintf(stderr, "DBG: %s", text );
+ mpi_print(stderr, a, 1 );
+ fputc('\n', stderr);
+}
+
diff --git a/util/memory.c b/util/memory.c
new file mode 100644
index 000000000..6ad57f9b0
--- /dev/null
+++ b/util/memory.c
@@ -0,0 +1,460 @@
+/* memory.c - memory allocation
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * We use our own memory allocation functions instead of plain malloc(),
+ * so that we can provide some special enhancements:
+ * a) functions to provide memory from a secure memory.
+ * Don't know how to handle it yet, but it may be possible to
+ * use memory which can't be swapped out.
+ * b) By looking at the requested allocation size we
+ * can reuse memory very quickly (e.g. MPI storage)
+ * c) A controlbyte gives us the opportunity to use only one
+ * free() function and do some overflow checking.
+ * d) memory checking and reporting if compiled with M_DEBUG
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "types.h"
+#include "memory.h"
+#include "util.h"
+
+
+#define MAGIC_NOR_BYTE 0x55
+#define MAGIC_SEC_BYTE 0xcc
+#define MAGIC_END_BYTE 0xaa
+
+const void membug( const char *fmt, ... );
+
+#ifdef M_DEBUG
+ #undef m_alloc
+ #undef m_alloc_clear
+ #undef m_alloc_secure
+ #undef m_alloc_secure_clear
+ #undef m_realloc
+ #undef m_free
+ #undef m_check
+ #define FNAME(a) m_debug_ ##a
+ #define FNAMEPRT , const char *info
+ #define FNAMEARG , info
+ #define store_len(p,n,m) do { add_entry(p,n,m, \
+ info, __FUNCTION__); } while(0)
+#else
+ #define FNAME(a) m_ ##a
+ #define FNAMEPRT
+ #define FNAMEARG
+ #define store_len(p,n,m) do { ((byte*))p[0] = n; \
+ ((byte*))p[2] = n >> 8 ; \
+ ((byte*))p[3] = n >> 16 ; \
+ ((byte*))p[4] = m? MAGIC_SEC_BYTE \
+ : MAGIC_NOR_BYTE; \
+ } while(0)
+#endif
+
+
+#ifdef M_DEBUG /* stuff used for memory debuging */
+
+struct info_entry {
+ struct info_entry *next;
+ unsigned count; /* call count */
+ const char *info; /* the reference to the info string */
+};
+
+struct memtbl_entry {
+ const void *user_p; /* for reference: the pointer given to the user */
+ size_t user_n; /* length requested by the user */
+ struct memtbl_entry *next; /* to build a list of unused entries */
+ const struct info_entry *info; /* points into the table with */
+ /* the info strings */
+ unsigned inuse:1; /* this entry is in use */
+ unsigned count:31;
+};
+
+
+#define INFO_BUCKETS 53
+#define info_hash(p) ( *(u32*)((p)) % INFO_BUCKETS )
+static struct info_entry *info_strings[INFO_BUCKETS]; /* hash table */
+
+static struct memtbl_entry *memtbl; /* the table with the memory infos */
+static unsigned memtbl_size; /* number of allocated entries */
+static unsigned memtbl_len; /* number of used entries */
+static struct memtbl_entry *memtbl_unused;/* to keep track of unused entries */
+
+static void dump_table(void);
+static void check_allmem( const char *info );
+
+/****************
+ * Put the new P into the debug table and return a pointer to the table entry.
+ * mode is true for security. BY is the name of the function which called us.
+ */
+static void
+add_entry( byte *p, unsigned n, int mode, const char *info, const char *by )
+{
+ unsigned index;
+ struct memtbl_entry *e;
+ struct info_entry *ie;
+
+ if( memtbl_len < memtbl_size )
+ index = memtbl_len++;
+ else {
+ struct memtbl_entry *e;
+ /* look for an used entry in the table. We take the first one,
+ * so that freed entries remain as long as possible in the table
+ * (free appends a new one)
+ */
+ if( (e = memtbl_unused) ) {
+ index = e - memtbl;
+ memtbl_unused = e->next;
+ e->next = NULL;
+ }
+ else { /* no free entries in the table: extend the table */
+ if( !memtbl_size ) { /* first time */
+ memtbl_size = 100;
+ if( !(memtbl = calloc( memtbl_size, sizeof *memtbl )) )
+ membug("memory debug table malloc failed\n");
+ index = 0;
+ memtbl_len = 1;
+ if( DBG_MEMSTAT )
+ atexit( dump_table );
+ }
+ else { /* realloc */
+ unsigned n = memtbl_size / 4; /* enlarge by 25% */
+ if(!(memtbl = realloc(memtbl, (memtbl_size+n)*sizeof *memtbl)))
+ membug("memory debug table realloc failed\n");
+ memset(memtbl+memtbl_size, 0, n*sizeof *memtbl );
+ memtbl_size += n;
+ index = memtbl_len++;
+ }
+ }
+ }
+ e = memtbl+index;
+ if( e->inuse )
+ membug("Ooops: entry %u is flagged as in use\n", index);
+ e->user_p = p + 4;
+ e->user_n = n;
+ e->count++;
+ if( e->next )
+ membug("Ooops: entry is in free entry list\n");
+ /* do we already have this info string */
+ for( ie = info_strings[info_hash(info)]; ie; ie = ie->next )
+ if( ie->info == info )
+ break;
+ if( !ie ) { /* no: make a new entry */
+ if( !(ie = malloc( sizeof *ie )) )
+ membug("can't allocate info entry\n");
+ ie->next = info_strings[info_hash(info)];
+ info_strings[info_hash(info)] = ie;
+ ie->info = info;
+ ie->count = 0;
+ }
+ ie->count++;
+ e->info = ie;
+ e->inuse = 1;
+
+ /* put the index at the start of the memory */
+ p[0] = index;
+ p[1] = index >> 8 ;
+ p[2] = index >> 16 ;
+ p[3] = mode? MAGIC_SEC_BYTE : MAGIC_NOR_BYTE ;
+ if( DBG_MEMORY )
+ log_debug( "%s allocates %u bytes using %s\n", info, e->user_n, by );
+}
+
+
+
+/****************
+ * Check that the memory block is correct. The magic byte has already been
+ * checked. Checks which are done here:
+ * - see wether the index points into our memory table
+ * - see wether P is the same as the one stored in the table
+ * - see wether we have already freed this block.
+ */
+struct memtbl_entry *
+check_mem( const byte *p, const char *info )
+{
+ unsigned n;
+ struct memtbl_entry *e;
+
+ n = p[0];
+ n |= p[1] << 8;
+ n |= p[2] << 16;
+
+ if( n >= memtbl_len )
+ membug("memory at %p corrupted: index=%u table_len=%u (%s)\n",
+ p+4, n, memtbl_len, info );
+ e = memtbl+n;
+
+ if( e->user_p != p+4 )
+ membug("memory at %p corrupted: reference mismatch (%s)\n", p+4, info );
+ if( !e->inuse )
+ membug("memory at %p corrupted: marked as free (%s)\n", p+4, info );
+
+ if( !(p[3] == MAGIC_NOR_BYTE || p[3] == MAGIC_SEC_BYTE) )
+ membug("memory at %p corrupted: underflow=%02x (%s)\n", p+4, p[3], info );
+ if( p[4+e->user_n] != MAGIC_END_BYTE )
+ membug("memory at %p corrupted: overflow=%02x (%s)\n", p+4, p[4+e->user_n], info );
+ if( e->info->count > 20000 )
+ membug("memory at %p corrupted: count too high (%s)\n", p+4, info );
+ return e;
+}
+
+
+/****************
+ * free the entry and the memory (replaces free)
+ */
+static void
+free_entry( byte *p, const char *info )
+{
+ struct memtbl_entry *e, *e2;
+
+ check_allmem("add_entry");
+
+ e = check_mem(p, info);
+ if( DBG_MEMORY )
+ log_debug( "%s frees %u bytes alloced by %s\n",
+ info, e->user_n, e->info->info );
+ if( !e->inuse ) {
+ if( e->user_p == p + 4 )
+ membug("freeing an already freed pointer at %p\n", p+4 );
+ else
+ membug("freeing pointer %p which is flagged as freed\n", p+4 );
+ }
+
+ e->inuse = 0;
+ e->next = NULL;
+ if( !memtbl_unused )
+ memtbl_unused = e;
+ else {
+ for(e2=memtbl_unused; e2->next; e2 = e2->next )
+ ;
+ e2->next = e;
+ }
+ memset(p,'f', e->user_n+5);
+ free(p);
+}
+
+static void
+dump_entry(struct memtbl_entry *e )
+{
+ unsigned n = e - memtbl;
+
+ fprintf(stderr, "mem %4u%c %5u %p %5u %s (%u)\n",
+ n, e->inuse?'a':'u', e->count, e->user_p, e->user_n,
+ e->info->info, e->info->count );
+
+
+}
+
+static void
+dump_table(void)
+{
+ unsigned n;
+ struct memtbl_entry *e;
+ ulong sum = 0, chunks =0;
+
+ for( e = memtbl, n = 0; n < memtbl_len; n++, e++ ) {
+ dump_entry(e);
+ if(e->inuse) {
+ sum += e->user_n;
+ chunks++;
+ }
+ }
+ fprintf(stderr, " memory used: %8lu bytes in %ld chunks\n",
+ sum, chunks );
+}
+
+static void
+check_allmem( const char *info )
+{
+ unsigned n;
+ struct memtbl_entry *e;
+
+ for( e = memtbl, n = 0; n < memtbl_len; n++, e++ )
+ if( e->inuse )
+ check_mem(e->user_p-4, info);
+}
+
+#endif /* M_DEBUG */
+
+const void
+membug( const char *fmt, ... )
+{
+ va_list arg_ptr ;
+
+ fprintf(stderr, "\nMemory Error: " ) ;
+ va_start( arg_ptr, fmt ) ;
+ vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+ fflush(stderr);
+ #ifdef M_DEBUG
+ if( DBG_MEMSTAT )
+ dump_table();
+ #endif
+ abort();
+}
+
+
+static void
+out_of_core(size_t n)
+{
+ log_fatal("out of memory while allocating %u bytes\n", (unsigned)n );
+}
+
+/****************
+ * Allocate memory of size n.
+ * This function gives up if we do not have enough memory
+ */
+void *
+FNAME(alloc)( size_t n FNAMEPRT )
+{
+ char *p;
+
+ if( !(p = malloc( n + 5 )) )
+ out_of_core(n);
+ store_len(p,n,0);
+ p[4+n] = MAGIC_END_BYTE; /* need to add the length somewhere */
+ return p+4;
+}
+
+/****************
+ * Allocate memory of size n from the secure memory pool.
+ * This function gives up if we do not have enough memory
+ */
+void *
+FNAME(alloc_secure)( size_t n FNAMEPRT )
+{
+ char *p;
+
+ if( !(p = malloc( n + 5 )) ) /* fixme: should alloc from the secure heap*/
+ out_of_core(n);
+ store_len(p,n,1);
+ p[4+n] = MAGIC_END_BYTE;
+ return p+4;
+}
+
+void *
+FNAME(alloc_clear)( size_t n FNAMEPRT )
+{
+ void *p;
+ p = FNAME(alloc)( n FNAMEARG );
+ memset(p, 0, n );
+ return p;
+}
+
+void *
+FNAME(alloc_secure_clear)( size_t n FNAMEPRT)
+{
+ void *p;
+ p = FNAME(alloc_secure)( n FNAMEARG );
+ memset(p, 0, n );
+ return p;
+}
+
+
+/****************
+ * realloc and clear the new space
+ */
+void *
+FNAME(realloc)( void *a, size_t n FNAMEPRT )
+{ /* FIXME: should be optimized :-) */
+ unsigned char *p = a;
+ void *b;
+ size_t len = m_size(a);
+
+ if( len >= n ) /* we don't shrink for now */
+ return a;
+ if( p[-1] == MAGIC_SEC_BYTE )
+ b = FNAME(alloc_secure_clear)(n FNAMEARG);
+ else
+ b = FNAME(alloc_clear)(n FNAMEARG);
+ FNAME(check)(NULL FNAMEARG);
+ memcpy(b, a, len );
+ FNAME(free)(p FNAMEARG);
+ return b;
+}
+
+
+
+/****************
+ * Free a pointer
+ */
+void
+FNAME(free)( void *a FNAMEPRT )
+{
+ byte *p = a;
+
+ if( !p )
+ return;
+ #ifdef M_DEBUG
+ free_entry(p-4, info);
+ #else
+ m_check(p);
+ free(p-4);
+ #endif
+}
+
+
+void
+FNAME(check)( const void *a FNAMEPRT )
+{
+ const byte *p = a;
+
+ #ifdef M_DEBUG
+ if( p )
+ check_mem(p-4, info);
+ else
+ check_allmem(info);
+ #else
+ if( !p )
+ return;
+ if( !(p[-1] == MAGIC_NOR_BYTE || p[-1] == MAGIC_SEC_BYTE) )
+ membug("memory at %p corrupted (underflow=%02x)\n", p, p[-1] );
+ else if( p[m_size(p)] != MAGIC_END_BYTE )
+ membug("memory at %p corrupted (overflow=%02x)\n", p, p[-1] );
+ #endif
+}
+
+
+size_t
+m_size( const void *a )
+{
+ const byte *p = a;
+ size_t n;
+
+ #ifdef M_DEBUG
+ n = check_mem(p-4, "m_size")->user_n;
+ #else
+ n = ((byte*)p[-4];
+ n |= ((byte*)p[-3] << 8;
+ n |= ((byte*)p[-2] << 16;
+ #endif
+ return n;
+}
+
+
+int
+m_is_secure( const void *p )
+{
+ return p && ((byte*)p)[-1] == MAGIC_SEC_BYTE;
+}
+
diff --git a/util/miscutil.c b/util/miscutil.c
new file mode 100644
index 000000000..9fecf4488
--- /dev/null
+++ b/util/miscutil.c
@@ -0,0 +1,33 @@
+/* miscutil.c - miscellaneous utilities
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <time.h>
+#include "types.h"
+#include "util.h"
+
+u32
+make_timestamp()
+{
+ return time(NULL);
+}
+
+
diff --git a/util/strgutil.c b/util/strgutil.c
new file mode 100644
index 000000000..b517ed5b6
--- /dev/null
+++ b/util/strgutil.c
@@ -0,0 +1,63 @@
+/* strgutil.c - miscellaneous utilities
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "types.h"
+#include "util.h"
+#include "memory.h"
+
+
+void
+free_strlist( STRLIST sl )
+{
+ STRLIST sl2;
+
+ for(; sl; sl = sl2 ) {
+ sl2 = sl->next;
+ m_free(sl);
+ }
+}
+
+/****************
+ * look for the substring SUB in buffer and return a pointer to that
+ * substring in BUF or NULL if not found.
+ * Comparison is case-in-sensitive.
+ */
+char *
+memistr( char *buf, size_t buflen, const char *sub )
+{
+ const byte *t, *s ;
+ size_t n;
+
+ for( t=buf, n=buflen, s=sub ; n ; t++, n-- )
+ if( toupper(*t) == toupper(*s) ) {
+ for( buf=(char*)t++, buflen = n--, s++;
+ n && toupper(*t) == toupper(*s); t++, s++, n-- )
+ ;
+ if( !*s )
+ return buf;
+ t = buf; n = buflen; s = sub ;
+ }
+
+ return NULL ;
+}
+
diff --git a/util/ttyio.c b/util/ttyio.c
new file mode 100644
index 000000000..39ad5a666
--- /dev/null
+++ b/util/ttyio.c
@@ -0,0 +1,114 @@
+/* ttyio.c - tty i/O functions
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <ctype.h>
+#include "util.h"
+#include "memory.h"
+#include "ttyio.h"
+
+static int last_prompt_len;
+
+static FILE *
+open_tty(void)
+{
+ FILE *tty = fopen("/dev/tty", "r");
+ if( !tty )
+ log_fatal("cannot open /dev/tty: %s\n", strerror(errno) );
+ return tty;
+}
+
+static void
+close_tty( FILE *tty )
+{
+ fclose(tty);
+}
+
+
+
+void
+tty_printf( const char *fmt, ... )
+{
+ va_list arg_ptr;
+
+ va_start( arg_ptr, fmt ) ;
+ last_prompt_len += vfprintf(stderr,fmt,arg_ptr) ;
+ va_end(arg_ptr);
+ fflush(stderr);
+}
+
+
+char *
+tty_get( const char *prompt )
+{
+ char *buf;
+ int c, n, i;
+ FILE *fp;
+
+ last_prompt_len = 0;
+ tty_printf( prompt );
+ buf = m_alloc(n=50);
+ i = 0;
+ fp = open_tty();
+ while( (c=getc(fp)) != EOF && c != '\n' ) {
+ last_prompt_len++;
+ if( c == '\t' )
+ c = ' ';
+ else if( iscntrl(c) )
+ continue;
+ if( !(i < n-1) ) {
+ n += 50;
+ buf = m_realloc( buf, n );
+ }
+ buf[i++] = c;
+ }
+ close_tty(fp);
+ buf[i] = 0;
+ return buf;
+}
+
+char *
+tty_get_hidden( const char *prompt )
+{
+ return tty_get( prompt ); /* fixme */
+}
+
+
+void
+tty_kill_prompt()
+{
+ int i;
+#if 0
+ for(i=0; i < last_prompt_len; i ++ )
+ fputc('\b', stderr);
+ for(i=0; i < last_prompt_len; i ++ )
+ fputc(' ', stderr);
+ for(i=0; i < last_prompt_len; i ++ )
+ fputc('\b', stderr);
+#endif
+ last_prompt_len = 0;
+ fflush(stderr);
+}
+