diff --git a/jnlib/Makefile.am b/jnlib/Makefile.am
new file mode 100644
index 000000000..b16724de2
--- /dev/null
+++ b/jnlib/Makefile.am
@@ -0,0 +1,19 @@
+## Process this file with automake to produce Makefile.in
+
+# Those 2 files are in the CVS but currently not used.
+EXTRA_DIST = README xmalloc.c xmalloc.h logging.c logging.c
+
+INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
+
+noinst_LTLIBRARIES = libjnlib.la
+
+
+libjnlib_la_LDFLAGS =
+libjnlib_la_SOURCES = libjnlib-config.h 	  \
+		      argparse.c argparse.h	\
+		      stringhelp.c stringhelp.h \
+		      dotlock.c dotlock.h \
+		      mischelp.h
+
+
+
diff --git a/jnlib/README b/jnlib/README
new file mode 100644
index 000000000..694c37835
--- /dev/null
+++ b/jnlib/README
@@ -0,0 +1,7 @@
+jnlib - this is a collection of utility function which are
+too small to put into a library.
+
+libjnlib-config.h should be be modified for each project
+to make these functions fit into the software.	Mainly these
+are memory functions in case you need another allocaort (like gcrypt).
+
diff --git a/jnlib/argparse.c b/jnlib/argparse.c
new file mode 100644
index 000000000..3f778053d
--- /dev/null
+++ b/jnlib/argparse.c
@@ -0,0 +1,994 @@
+/* [argparse.c wk 17.06.97] Argument Parser for option handling
+ *	Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ *  This file is part of GnuPG.
+ *
+ *  GnuPG 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.
+ *
+ *  GnuPG 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 <ctype.h>
+#include <string.h>
+
+#include "libjnlib-config.h"
+#include "mischelp.h"
+#include "stringhelp.h"
+#include "logging.h"
+#include "argparse.h"
+
+
+/*********************************
+ * @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 idx;
+ *	    const char *last;
+ *	    void *aliases;
+ *	} 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
+ *     Bit 6 : ignore --version
+ *     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.
+ *     Bit 7 : this is a command and not an option
+ *  You 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/-7 to indicate an unknown option/command.
+ * @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");
+ *
+ */
+
+typedef struct alias_def_s *ALIAS_DEF;
+struct alias_def_s {
+    ALIAS_DEF next;
+    char *name;   /* malloced buffer with name, \0, value */
+    const char *value; /* ptr into name */
+};
+
+static const char *(*strusage_handler)( int ) = NULL;
+
+static int  set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
+static void show_help(ARGPARSE_OPTS *opts, unsigned flags);
+static void show_version(void);
+
+
+static void
+initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
+{
+    if( !(arg->flags & (1<<15)) ) { /* initialize this instance */
+	arg->internal.idx = 0;
+	arg->internal.last = NULL;
+	arg->internal.inarg = 0;
+	arg->internal.stopped = 0;
+	arg->internal.aliases = NULL;
+	arg->internal.cur_alias = NULL;
+	arg->err = 0;
+	arg->flags |= 1<<15; /* mark initialized */
+	if( *arg->argc < 0 )
+	    jnlib_log_bug("Invalid argument for ArgParse\n");
+    }
+
+
+    if( arg->err ) { /* last option was erroneous */
+	const char *s;
+
+	if( filename ) {
+	    if( arg->r_opt == -6 )
+		s = "%s:%u: argument not expected\n";
+	    else if( arg->r_opt == -5 )
+		s = "%s:%u: read error\n";
+	    else if( arg->r_opt == -4 )
+		s = "%s:%u: keyword too long\n";
+	    else if( arg->r_opt == -3 )
+		s = "%s:%u: missing argument\n";
+	    else if( arg->r_opt == -7 )
+		s = "%s:%u: invalid command\n";
+	    else if( arg->r_opt == -10 )
+		s = "%s:%u: invalid alias definition\n";
+	    else
+		s = "%s:%u: invalid option\n";
+	    jnlib_log_error(s, filename, *lineno );
+	}
+	else {
+	    if( arg->r_opt == -3 )
+		s = "Missing argument for option \"%.50s\"\n";
+	    else if( arg->r_opt == -6 )
+		s = "Option \"%.50s\" does not expect an argument\n";
+	    else if( arg->r_opt == -7 )
+		s = "Invalid command \"%.50s\"\n";
+	    else if( arg->r_opt == -8 )
+		s = "Option \"%.50s\" is ambiguous\n";
+	    else if( arg->r_opt == -9 )
+		s = "Command \"%.50s\" is ambiguous\n";
+	    else
+		s = "Invalid option \"%.50s\"\n";
+	    jnlib_log_error(s, arg->internal.last? arg->internal.last:"[??]" );
+	}
+	if( arg->err != 1 )
+	    exit(2);
+	arg->err = 0;
+    }
+
+    /* clearout the return value union */
+    arg->r.ret_str = NULL;
+    arg->r.ret_long= 0;
+}
+
+
+static void
+store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
+{
+    /* TODO: replace this dummy function with a rea one
+     * and fix the probelms IRIX has with (ALIAS_DEV)arg..
+     * used as lvalue
+     */
+#if 0
+    ALIAS_DEF a = jnlib_xmalloc( sizeof *a );
+    a->name = name;
+    a->value = value;
+    a->next = (ALIAS_DEF)arg->internal.aliases;
+    (ALIAS_DEF)arg->internal.aliases = a;
+#endif
+}
+
+/****************
+ * Get options from a file.
+ * Lines starting with '#' are comment lines.
+ * Syntax is simply a keyword and the argument.
+ * Valid keywords are all keywords from the long_opt list without
+ * the leading dashes. The special keywords "help", "warranty" and "version"
+ * are not valid here.
+ * The special keyword "alias" may be used to store alias definitions,
+ * which are later expanded like long options.
+ * Caller must free returned strings.
+ * If called with FP set to NULL command line args are parse instead.
+ *
+ * Q: Should we allow the syntax
+ *     keyword = value
+ *    and accept for boolean options a value of 1/0, yes/no or true/false?
+ * Note: Abbreviation of options is here not allowed.
+ */
+int
+optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
+	       ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+    int state, i, c;
+    int idx=0;
+    char keyword[100];
+    char *buffer = NULL;
+    size_t buflen = 0;
+    int inverse=0;
+    int in_alias=0;
+
+    if( !fp ) /* same as arg_parse() in this case */
+	return arg_parse( arg, opts );
+
+    initialize( arg, filename, lineno );
+
+    /* find the next keyword */
+    state = i = 0;
+    for(;;) {
+	c=getc(fp);
+	if( c == '\n' || c== EOF ) {
+	    if( c != EOF )
+		++*lineno;
+	    if( state == -1 )
+		break;
+	    else if( state == 2 ) {
+		keyword[i] = 0;
+		for(i=0; opts[i].short_opt; i++ )
+		    if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
+			break;
+		idx = i;
+		arg->r_opt = opts[idx].short_opt;
+		if( inverse ) /* this does not have an effect, hmmm */
+		    arg->r_opt = -arg->r_opt;
+		if( !opts[idx].short_opt )   /* unknown command/option */
+		    arg->r_opt = (opts[idx].flags & 256)? -7:-2;
+		else if( (opts[idx].flags & 8) ) /* no argument */
+		    arg->r_opt = -3;	       /* error */
+		else			       /* no or optional argument */
+		    arg->r_type = 0;	       /* okay */
+		break;
+	    }
+	    else if( state == 3 ) {	       /* no argument found */
+		if( in_alias )
+		    arg->r_opt = -3;	       /* error */
+		else if( !(opts[idx].flags & 7) ) /* does not take an arg */
+		    arg->r_type = 0;	       /* okay */
+		else if( (opts[idx].flags & 8) )  /* no optional argument */
+		    arg->r_type = 0;	       /* okay */
+		else			       /* no required argument */
+		    arg->r_opt = -3;	       /* error */
+		break;
+	    }
+	    else if( state == 4 ) {	/* have an argument */
+		if( in_alias ) {
+		    if( !buffer )
+			arg->r_opt = -6;
+		    else {
+			char *p;
+
+			buffer[i] = 0;
+			p = strpbrk( buffer, " \t" );
+			if( p ) {
+			    *p++ = 0;
+			    trim_spaces( p );
+			}
+			if( !p || !*p ) {
+			    jnlib_free( buffer );
+			    arg->r_opt = -10;
+			}
+			else {
+			    store_alias( arg, buffer, p );
+			}
+		    }
+		}
+		else if( !(opts[idx].flags & 7) )  /* does not take an arg */
+		    arg->r_opt = -6;	    /* error */
+		else {
+		    char *p;
+		    if( !buffer ) {
+			keyword[i] = 0;
+			buffer = jnlib_xstrdup(keyword);
+		    }
+		    else
+			buffer[i] = 0;
+
+		    trim_spaces( buffer );
+		    p = buffer;
+		    if( *p == '"' ) { /* remove quotes */
+			p++;
+			if( *p && p[strlen(p)-1] == '"' )
+			    p[strlen(p)-1] = 0;
+		    }
+		    if( !set_opt_arg(arg, opts[idx].flags, p) )
+			jnlib_free(buffer);
+		}
+		break;
+	    }
+	    else if( c == EOF ) {
+		if( ferror(fp) )
+		    arg->r_opt = -5;   /* read error */
+		else
+		    arg->r_opt = 0;    /* eof */
+		break;
+	    }
+	    state = 0;
+	    i = 0;
+	}
+	else if( state == -1 )
+	    ; /* skip */
+	else if( !state && isspace(c) )
+	    ; /* skip leading white space */
+	else if( !state && c == '#' )
+	    state = 1;	/* start of a comment */
+	else if( state == 1 )
+	    ; /* skip comments */
+	else if( state == 2 && isspace(c) ) {
+	    keyword[i] = 0;
+	    for(i=0; opts[i].short_opt; i++ )
+		if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
+		    break;
+	    idx = i;
+	    arg->r_opt = opts[idx].short_opt;
+	    if( !opts[idx].short_opt ) {
+		if( !strcmp( keyword, "alias" ) ) {
+		    in_alias = 1;
+		    state = 3;
+		}
+		else {
+		    arg->r_opt = (opts[idx].flags & 256)? -7:-2;
+		    state = -1;        /* skip rest of line and leave */
+		}
+	    }
+	    else
+		state = 3;
+	}
+	else if( state == 3 ) { /* skip leading spaces of the argument */
+	    if( !isspace(c) ) {
+		i = 0;
+		keyword[i++] = c;
+		state = 4;
+	    }
+	}
+	else if( state == 4 ) { /* collect the argument */
+	    if( buffer ) {
+		if( i < buflen-1 )
+		    buffer[i++] = c;
+		else {
+		    buflen += 50;
+		    buffer = jnlib_xrealloc(buffer, buflen);
+		    buffer[i++] = c;
+		}
+	    }
+	    else if( i < DIM(keyword)-1 )
+		keyword[i++] = c;
+	    else {
+		buflen = DIM(keyword)+50;
+		buffer = jnlib_xmalloc(buflen);
+		memcpy(buffer, keyword, i);
+		buffer[i++] = c;
+	    }
+	}
+	else if( i >= DIM(keyword)-1 ) {
+	    arg->r_opt = -4;   /* keyword to long */
+	    state = -1;        /* skip rest of line and leave */
+	}
+	else {
+	    keyword[i++] = c;
+	    state = 2;
+	}
+    }
+
+    return arg->r_opt;
+}
+
+
+
+static int
+find_long_option( ARGPARSE_ARGS *arg,
+		  ARGPARSE_OPTS *opts, const char *keyword )
+{
+    int i;
+    size_t n;
+
+    /* Would be better if we can do a binary search, but it is not
+       possible to reorder our option table because we would mess
+       up our help strings - What we can do is: Build a nice option
+       lookup table wehn this function is first invoked */
+    if( !*keyword )
+	return -1;
+    for(i=0; opts[i].short_opt; i++ )
+	if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
+	    return i;
+  #if 0
+    {
+	ALIAS_DEF a;
+	/* see whether it is an alias */
+	for( a = args->internal.aliases; a; a = a->next ) {
+	    if( !strcmp( a->name, keyword) ) {
+		/* todo: must parse the alias here */
+		args->internal.cur_alias = a;
+		return -3; /* alias available */
+	    }
+	}
+    }
+  #endif
+    /* not found, see whether it is an abbreviation */
+    /* aliases may not be abbreviated */
+    n = strlen( keyword );
+    for(i=0; opts[i].short_opt; i++ ) {
+	if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) {
+	    int j;
+	    for(j=i+1; opts[j].short_opt; j++ ) {
+		if( opts[j].long_opt
+		    && !strncmp( opts[j].long_opt, keyword, n ) )
+		    return -2;	/* abbreviation is ambiguous */
+	    }
+	    return i;
+	}
+    }
+    return -1;
+}
+
+int
+arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+    int idx;
+    int argc;
+    char **argv;
+    char *s, *s2;
+    int i;
+
+    initialize( arg, NULL, NULL );
+    argc = *arg->argc;
+    argv = *arg->argv;
+    idx = arg->internal.idx;
+
+    if( !idx && argc && !(arg->flags & (1<<4)) ) { /* skip the first entry */
+	argc--; argv++; idx++;
+    }
+
+  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++; idx++; /* set to next one */
+    }
+    else if( arg->internal.stopped ) { /* ready */
+	arg->r_opt = 0;
+	goto leave;
+    }
+    else if( *s == '-' && s[1] == '-' ) { /* long option */
+	char *argpos;
+
+	arg->internal.inarg = 0;
+	if( !s[2] && !(arg->flags & (1<<3)) ) { /* stop option processing */
+	    arg->internal.stopped = 1;
+	    argc--; argv++; idx++;
+	    goto next_one;
+	}
+
+	argpos = strchr( s+2, '=' );
+	if( argpos )
+	    *argpos = 0;
+	i = find_long_option( arg, opts, s+2 );
+	if( argpos )
+	    *argpos = '=';
+
+	if( i < 0 && !strcmp( "help", s+2) )
+	    show_help(opts, arg->flags);
+	else if( i < 0 && !strcmp( "version", s+2) ) {
+	    if( !(arg->flags & (1<<6)) ) {
+		show_version();
+		exit(0);
+	    }
+	}
+	else if( i < 0 && !strcmp( "warranty", s+2) ) {
+	    puts( strusage(16) );
+	    exit(0);
+	}
+	else if( i < 0 && !strcmp( "dump-options", s+2) ) {
+	    for(i=0; opts[i].short_opt; i++ ) {
+		if( opts[i].long_opt )
+		    printf( "--%s\n", opts[i].long_opt );
+	    }
+	    fputs("--dump-options\n--help\n--version\n--warranty\n", stdout );
+	    exit(0);
+	}
+
+	if( i == -2 ) /* ambiguous option */
+	    arg->r_opt = -8;
+	else if( i == -1 ) {
+	    arg->r_opt = -2;
+	    arg->r.ret_str = s+2;
+	}
+	else
+	    arg->r_opt = opts[i].short_opt;
+	if( i < 0 )
+	    ;
+	else if( (opts[i].flags & 7) ) {
+	    if( argpos ) {
+		s2 = argpos+1;
+		if( !*s2 )
+		    s2 = NULL;
+	    }
+	    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( !argpos && *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);
+		if( !argpos ) {
+		    argc--; argv++; idx++; /* skip one */
+		}
+	    }
+	}
+	else { /* does not take an argument */
+	    if( argpos )
+		arg->r_type = -6; /* argument not expected */
+	    else
+		arg->r_type = 0;
+	}
+	argc--; argv++; idx++; /* 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' || *s == '?' ) )
+	    show_help(opts, arg->flags);
+
+	arg->r_opt = opts[i].short_opt;
+	if( !opts[i].short_opt ) {
+	    arg->r_opt = (opts[i].flags & 256)? -7:-2;
+	    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++; idx++; /* 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++; idx++;
+	}
+    }
+    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++; idx++; /* set to next one */
+    }
+    else {
+	arg->internal.stopped = 1; /* stop option processing */
+	goto next_one;
+    }
+
+  leave:
+    *arg->argc = argc;
+    *arg->argv = argv;
+    arg->internal.idx = idx;
+    return arg->r_opt;
+}
+
+
+
+static int
+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);
+	return 0;
+      case 3: /* takes long argument   */
+	arg->r.ret_long= strtol(s,NULL,base);
+	return 0;
+      case 4: /* takes ulong argument  */
+	arg->r.ret_ulong= strtoul(s,NULL,base);
+	return 0;
+      case 2: /* takes string argument */
+      default:
+	arg->r.ret_str = s;
+	return 1;
+    }
+}
+
+
+static size_t
+long_opt_strlen( ARGPARSE_OPTS *o )
+{
+    size_t n = strlen(o->long_opt);
+
+    if( o->description && *o->description == '|' ) {
+	const char *s;
+
+	s=o->description+1;
+	if( *s != '=' )
+	    n++;
+	for(; *s && *s != '|'; s++ )
+	    n++;
+    }
+    return n;
+}
+
+/****************
+ * Print formatted help. The description string has some special
+ * meanings:
+ *  - A description string which is "@" suppresses help output for
+ *    this option
+ *  - a description,ine which starts with a '@' and is followed by
+ *    any other characters is printed as is; this may be used for examples
+ *    ans such.
+ *  - A description which starts with a '|' outputs the string between this
+ *    bar and the next one as arguments of the long option.
+ */
+static void
+show_help( ARGPARSE_OPTS *opts, unsigned flags )
+{
+    const char *s;
+
+    show_version();
+    putchar('\n');
+    s = strusage(41);
+    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( !opts[i].description || *opts[i].description != '@' )
+		    if( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
+			 indent = j;
+	}
+	/* example: " -v, --verbose   Viele Sachen ausgeben" */
+	indent += 10;
+	if( *opts[0].description != '@' )
+	    puts("Options:");
+	for(i=0; opts[i].short_opt; i++ ) {
+	    s = _( opts[i].description );
+	    if( s && *s== '@' && !s[1] ) /* hide this line */
+		continue;
+	    if( s && *s == '@' ) { /* unindented comment only line */
+		for(s++; *s; s++ ) {
+		    if( *s == '\n' ) {
+			if( s[1] )
+			    putchar('\n');
+		    }
+		    else
+			putchar(*s);
+		}
+		putchar('\n');
+		continue;
+	    }
+
+	    j = 3;
+	    if( opts[i].short_opt < 256 ) {
+		printf(" -%c", opts[i].short_opt );
+		if( !opts[i].long_opt ) {
+		    if(s && *s == '|' ) {
+			putchar(' '); j++;
+			for(s++ ; *s && *s != '|'; s++, j++ )
+			    putchar(*s);
+			if( *s )
+			    s++;
+		    }
+		}
+	    }
+	    else
+		fputs("   ", stdout);
+	    if( opts[i].long_opt ) {
+		j += printf("%c --%s", opts[i].short_opt < 256?',':' ',
+				       opts[i].long_opt );
+		if(s && *s == '|' ) {
+		    if( *++s != '=' ) {
+			putchar(' ');
+			j++;
+		    }
+		    for( ; *s && *s != '|'; s++, j++ )
+			putchar(*s);
+		    if( *s )
+			s++;
+		}
+		fputs("   ", stdout);
+		j += 3;
+	    }
+	    for(;j < indent; j++ )
+		putchar(' ');
+	    if( s ) {
+		if( *s && j > indent ) {
+		    putchar('\n');
+		    for(j=0;j < indent; j++ )
+			putchar(' ');
+		}
+		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)");
+    }
+    if( (s=strusage(19)) ) {  /* bug reports to ... */
+	putchar('\n');
+	fputs(s, stdout);
+    }
+    fflush(stdout);
+    exit(0);
+}
+
+static void
+show_version()
+{
+    const char *s;
+    int i;
+    /* version line */
+    fputs(strusage(11), stdout);
+    if( (s=strusage(12)) )
+	printf(" (%s)", s );
+    printf(" %s\n", strusage(13) );
+    /* additional version lines */
+    for(i=20; i < 30; i++ )
+	if( (s=strusage(i)) )
+	    printf("%s\n", s );
+    /* copyright string */
+    if( (s=strusage(14)) )
+	printf("%s\n", s );
+    /* copying conditions */
+    if( (s=strusage(15)) )
+	fputs(s, stdout);
+    /* thanks */
+    if( (s=strusage(18)) )
+	fputs(s, stdout);
+    /* additional program info */
+    for(i=30; i < 40; i++ )
+	if( (s=strusage(i)) )
+	    fputs( (const byte*)s, stdout);
+    fflush(stdout);
+}
+
+
+void
+usage( int level )
+{
+    if( !level ) {
+	fprintf(stderr,"%s %s; %s\n", strusage(11), strusage(13),
+						     strusage(14) );
+	fflush(stderr);
+    }
+    else if( level == 1 ) {
+	fputs(strusage(40),stderr);
+	exit(2);
+    }
+    else if( level == 2 ) {
+	puts(strusage(41));
+	exit(0);
+    }
+}
+
+/* Level
+ *     0: Copyright String auf stderr ausgeben
+ *     1: Kurzusage auf stderr ausgeben und beenden
+ *     2: Langusage auf stdout ausgeben und beenden
+ *    11: name of program
+ *    12: optional name of package which includes this program.
+ *    13: version  string
+ *    14: copyright string
+ *    15: Short copying conditions (with LFs)
+ *    16: Long copying conditions (with LFs)
+ *    17: Optional printable OS name
+ *    18: Optional thanks list	 (with LFs)
+ *    19: Bug report info
+ *20..29: Additional lib version strings.
+ *30..39: Additional program info (with LFs)
+ *    40: short usage note (with LF)
+ *    41: long usage note (with LF)
+ */
+const char *
+strusage( int level )
+{
+    const char *p = strusage_handler? strusage_handler(level) : NULL;
+
+    if( p )
+	return p;
+
+    switch( level ) {
+      case 11: p = "foo"; break;
+      case 13: p = "0.0"; break;
+      case 14: p = "Copyright (C) 1999 Free Software Foundation, Inc."; break;
+      case 15: 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 16:	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"
+"It 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 40: /* short and long usage */
+      case 41: p = ""; break;
+    }
+
+    return p;
+}
+
+void
+set_strusage( const char *(*f)( int ) )
+{
+    strusage_handler = f;
+}
+
+
+#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/jnlib/argparse.h b/jnlib/argparse.h
new file mode 100644
index 000000000..3f5605b00
--- /dev/null
+++ b/jnlib/argparse.h
@@ -0,0 +1,64 @@
+/* argparse.h
+ *	Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+#ifndef LIBJNLIB_ARGPARSE_H
+#define LIBJNLIB_ARGPARSE_H
+
+typedef struct {
+     int  *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 idx;
+	 int inarg;
+	 int stopped;
+	 const char *last;
+	 void *aliases;
+	 const void *cur_alias;
+     } internal;	    /* DO NOT CHANGE */
+} ARGPARSE_ARGS;
+
+typedef struct {
+    int 	short_opt;
+    const char *long_opt;
+    unsigned flags;
+    const char *description; /* optional option description */
+} ARGPARSE_OPTS;
+
+
+
+int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
+int optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
+		   ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
+void usage( int level );
+const char *strusage( int level );
+void set_strusage( const char *(*f)( int ) );
+
+#endif /*LIBJNLIB_ARGPARSE_H*/
diff --git a/jnlib/dotlock.c b/jnlib/dotlock.c
new file mode 100644
index 000000000..8e61f7a03
--- /dev/null
+++ b/jnlib/dotlock.c
@@ -0,0 +1,346 @@
+/* dotlock.c - dotfile locking
+ *	Copyright (C) 1998,2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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 <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#ifndef  HAVE_DOSISH_SYSTEM
+#include <sys/utsname.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "libjnlib-config.h"
+#include "dotlock.h"
+
+struct dotlock_handle {
+    struct dotlock_handle *next;
+    char *tname;    /* name of lockfile template */
+    char *lockname; /* name of the real lockfile */
+    int locked;     /* lock status */
+};
+
+
+static DOTLOCK all_lockfiles;
+
+static int read_lockfile( const char *name );
+static void remove_lockfiles(void);
+
+/****************
+ * Create a lockfile with the given name and return an object of
+ * type DOTLOCK which may be used later to actually do the lock.
+ * A cleanup routine gets installed to cleanup left over locks
+ * or other files used together with the lockmechanism.
+ * Althoug the function is called dotlock, this does not necessarily
+ * mean that real lockfiles are used - the function may decide to
+ * use fcntl locking.  Calling the function with NULL only install
+ * the atexit handler and maybe used to assure that the cleanup
+ * is called after all other atexit handlers.
+ *
+ * Notes: This function creates a lock file in the same directory
+ *	  as file_to_lock with the name "file_to_lock.lock"
+ *	  A temporary file ".#lk.<hostname>.pid[.threadid] is used.
+ *	  This function does nothing for Windoze.
+ */
+DOTLOCK
+create_dotlock( const char *file_to_lock )
+{
+    static int initialized;
+    DOTLOCK h;
+    int  fd = -1;
+    char pidstr[16];
+  #ifndef  HAVE_DOSISH_SYSTEM
+    struct utsname utsbuf;
+  #endif
+    const char *nodename;
+    const char *dirpart;
+    int dirpartlen;
+
+    if( !initialized ) {
+	atexit( remove_lockfiles );
+	initialized = 1;
+    }
+    if( !file_to_lock )
+	return NULL;
+
+    h = jnlib_xcalloc( 1, sizeof *h );
+#ifndef HAVE_DOSISH_SYSTEM
+    sprintf( pidstr, "%10d\n", (int)getpid() );
+    /* fixme: add the hostname to the second line (FQDN or IP addr?) */
+
+    /* create a temporary file */
+    if( uname( &utsbuf ) )
+	nodename = "unknown";
+    else
+	nodename = utsbuf.nodename;
+
+    if( !(dirpart = strrchr( file_to_lock, '/' )) ) {
+	dirpart = ".";
+	dirpartlen = 1;
+    }
+    else {
+	dirpartlen = dirpart - file_to_lock;
+	dirpart = file_to_lock;
+    }
+
+  #ifdef _REENTRANT
+    /* fixme: aquire mutex on all_lockfiles */
+  #endif
+    h->next = all_lockfiles;
+    all_lockfiles = h;
+
+    h->tname = jnlib_xmalloc( dirpartlen + 6+30+ strlen(nodename) + 11 );
+    sprintf( h->tname, "%.*s/.#lk%p.%s.%d",
+	     dirpartlen, dirpart, h, nodename, (int)getpid() );
+
+    do {
+	errno = 0;
+	fd = open( h->tname, O_WRONLY|O_CREAT|O_EXCL,
+			  S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
+    } while( fd == -1 && errno == EINTR );
+    if( fd == -1 ) {
+	all_lockfiles = h->next;
+	log_error( "failed to create temporary file `%s': %s\n",
+					    h->tname, strerror(errno));
+	jnlib_free(h->tname);
+	jnlib_free(h);
+	return NULL;
+    }
+    if( write(fd, pidstr, 11 ) != 11 ) {
+	all_lockfiles = h->next;
+      #ifdef _REENTRANT
+	/* release mutex */
+      #endif
+	log_fatal( "error writing to `%s': %s\n", h->tname, strerror(errno) );
+	close(fd);
+	unlink(h->tname);
+	jnlib_free(h->tname);
+	jnlib_free(h);
+	return NULL;
+    }
+    if( close(fd) ) {
+	all_lockfiles = h->next;
+      #ifdef _REENTRANT
+	/* release mutex */
+      #endif
+	log_error( "error closing `%s': %s\n", h->tname, strerror(errno));
+	unlink(h->tname);
+	jnlib_free(h->tname);
+	jnlib_free(h);
+	return NULL;
+    }
+
+  #ifdef _REENTRANT
+    /* release mutex */
+  #endif
+#endif /* !HAVE_DOSISH_SYSTEM */
+    h->lockname = jnlib_xmalloc( strlen(file_to_lock) + 6 );
+    strcpy(stpcpy(h->lockname, file_to_lock), ".lock");
+    return h;
+}
+
+static int
+maybe_deadlock( DOTLOCK h )
+{
+    DOTLOCK r;
+
+    for( r=all_lockfiles; r; r = r->next ) {
+	if( r != h && r->locked )
+	    return 1;
+    }
+    return 0;
+}
+
+/****************
+ * Do a lock on H. A TIMEOUT of 0 returns immediately,
+ * -1 waits forever (hopefully not), other
+ * values are timeouts in milliseconds.
+ * Returns: 0 on success
+ */
+int
+make_dotlock( DOTLOCK h, long timeout )
+{
+#ifdef HAVE_DOSISH_SYSTEM
+    return 0;
+#else
+    int  pid;
+    const char *maybe_dead="";
+    int backoff=0;
+
+    if( h->locked ) {
+	log_debug("oops, `%s' is already locked\n", h->lockname );
+	return 0;
+    }
+
+    for(;;) {
+	if( !link(h->tname, h->lockname) ) {
+	    /* fixme: better use stat to check the link count */
+	    h->locked = 1;
+	    return 0; /* okay */
+	}
+	if( errno != EEXIST ) {
+	    log_error( "lock not made: link() failed: %s\n", strerror(errno) );
+	    return -1;
+	}
+	if( (pid = read_lockfile(h->lockname)) == -1 ) {
+	    if( errno != ENOENT ) {
+		log_info("cannot read lockfile\n");
+		return -1;
+	    }
+	    log_info( "lockfile disappeared\n");
+	    continue;
+	}
+	else if( pid == getpid() ) {
+	    log_info( "Oops: lock already hold by us\n");
+	    h->locked = 1;
+	    return 0; /* okay */
+	}
+	else if( kill(pid, 0) && errno == ESRCH ) {
+	    maybe_dead = " - probably dead";
+	 #if 0 /* we should not do this without checking the permissions */
+	       /* and the hostname */
+	    log_info( "removing stale lockfile (created by %d)", pid );
+	 #endif
+	}
+	if( timeout == -1 ) {
+	    struct timeval tv;
+	    log_info( "waiting for lock (hold by %d%s) %s...\n",
+		      pid, maybe_dead, maybe_deadlock(h)? "(deadlock?) ":"");
+
+
+	    /* can't use sleep, cause signals may be blocked */
+	    tv.tv_sec = 1 + backoff;
+	    tv.tv_usec = 0;
+	    select(0, NULL, NULL, NULL, &tv);
+	    if( backoff < 10 )
+		backoff++ ;
+	}
+	else
+	    return -1;
+    }
+    /*not reached */
+#endif /* !HAVE_DOSISH_SYSTEM */
+}
+
+
+/****************
+ * release a lock
+ * Returns: 0 := success
+ */
+int
+release_dotlock( DOTLOCK h )
+{
+#ifdef HAVE_DOSISH_SYSTEM
+    return 0;
+#else
+    int pid;
+
+    if( !h->locked ) {
+	log_debug("oops, `%s' is not locked\n", h->lockname );
+	return 0;
+    }
+
+    pid = read_lockfile( h->lockname );
+    if( pid == -1 ) {
+	log_error( "release_dotlock: lockfile error\n");
+	return -1;
+    }
+    if( pid != getpid() ) {
+	log_error( "release_dotlock: not our lock (pid=%d)\n", pid);
+	return -1;
+    }
+    if( unlink( h->lockname ) ) {
+	log_error( "release_dotlock: error removing lockfile `%s'",
+							h->lockname);
+	return -1;
+    }
+    /* fixme: check that the link count is now 1 */
+    h->locked = 0;
+    return 0;
+#endif /* !HAVE_DOSISH_SYSTEM */
+}
+
+
+/****************
+ * Read the lock file and return the pid, returns -1 on error.
+ */
+static int
+read_lockfile( const char *name )
+{
+  #ifdef HAVE_DOSISH_SYSTEM
+    return 0;
+  #else
+    int fd, pid;
+    char pidstr[16];
+
+    if( (fd = open(name, O_RDONLY)) == -1 ) {
+	int e = errno;
+	log_debug("error opening lockfile `%s': %s\n", name, strerror(errno) );
+	errno = e;
+	return -1;
+    }
+    if( read(fd, pidstr, 10 ) != 10 ) {  /* Read 10 digits w/o newline */
+	log_debug("error reading lockfile `%s'", name );
+	close(fd);
+	errno = 0;
+	return -1;
+    }
+    pidstr[10] = 0;  /* terminate pid string */
+    close(fd);
+    pid = atoi(pidstr);
+    if( !pid || pid == -1 ) {
+	log_error("invalid pid %d in lockfile `%s'", pid, name );
+	errno = 0;
+	return -1;
+    }
+    return pid;
+  #endif
+}
+
+
+static void
+remove_lockfiles()
+{
+  #ifndef HAVE_DOSISH_SYSTEM
+    DOTLOCK h, h2;
+
+    h = all_lockfiles;
+    all_lockfiles = NULL;
+
+    while( h ) {
+	h2 = h->next;
+	if( h->locked )
+	    unlink( h->lockname );
+	unlink(h->tname);
+	jnlib_free(h->tname);
+	jnlib_free(h->lockname);
+	jnlib_free(h);
+	h = h2;
+    }
+  #endif
+}
+
diff --git a/jnlib/dotlock.h b/jnlib/dotlock.h
new file mode 100644
index 000000000..d54219e23
--- /dev/null
+++ b/jnlib/dotlock.h
@@ -0,0 +1,32 @@
+/* dotlock.h
+ *	Copyright (C) 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+#ifndef LIBJNLIB_DOTLOCK_H
+#define LIBJNLIB_DOTLOCK_H
+
+struct dotlock_handle;
+typedef struct dotlock_handle *DOTLOCK;
+
+DOTLOCK create_dotlock( const char *file_to_lock );
+int make_dotlock( DOTLOCK h, long timeout );
+int release_dotlock( DOTLOCK h );
+
+
+#endif /*LIBJNLIB_DOTLOCK_H*/
diff --git a/jnlib/libjnlib-config.h b/jnlib/libjnlib-config.h
new file mode 100644
index 000000000..35cee6475
--- /dev/null
+++ b/jnlib/libjnlib-config.h
@@ -0,0 +1,49 @@
+/* libjnlib-config.h - local configuration of the jnlib functions
+ *	Copyright (C) 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+/****************
+ * This header is to be included only by the files in this directory
+ * it should not be used by other modules.
+ */
+
+#ifndef LIBJNLIB_CONFIG_H
+#define LIBJNLIB_CONFIG_H
+
+#define LIBJNLIB_LOGGING_H 1 /* don't include the jnlib logging */
+
+#include "types.h"
+#include <gcrypt.h>
+#include "util.h"
+#include "i18n.h"
+
+#define jnlib_xmalloc(a)    gcry_xmalloc( (a) )
+#define jnlib_xcalloc(a,b)  gcry_xcalloc( (a), (b) )
+#define jnlib_xrealloc(a,n) gcry_xrealloc( (a), (n) )
+#define jnlib_xstrdup(a)    gcry_xstrdup( (a) )
+#define jnlib_free(a)	    gcry_free( (a) )
+
+#define jnlib_log_debug    log_debug
+#define jnlib_log_info	   log_info
+#define jnlib_log_error    log_error
+#define jnlib_log_fatal    log_fatal
+#define jnlib_log_bug	   log_bug
+
+
+#endif /*LIBJNUTIL_CONFIG_H*/
diff --git a/jnlib/logging.c b/jnlib/logging.c
new file mode 100644
index 000000000..7de36fbc6
--- /dev/null
+++ b/jnlib/logging.c
@@ -0,0 +1,241 @@
+/* logging.c -	useful logging functions
+ *	Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+
+/* This file should replace logger.c in the future - for now it is not
+ * used GnuPG.
+ * It is a quite simple implemenation but sufficient for most purposes.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <time.h>
+
+#include "libjnlib-config.h"
+#include "logging.h"
+
+enum my_log_levels {
+    MY_LOG_BEGIN,  /* only print the timestamp if configured */
+    MY_LOG_CONT,
+    MY_LOG_INFO,
+    MY_LOG_WARN,
+    MY_LOG_ERROR,
+    MY_LOG_FATAL,
+    MY_LOG_BUG,
+    MY_LOG_DEBUG
+};
+
+static FILE *logstream;
+static int use_time;
+static int missing_lf;
+
+#if 0
+static void
+write2stderr( const char *s )
+{
+    write( 2, s, strlen(s) );
+}
+
+
+static void
+do_die(int rc, const char *text )
+{
+    write2stderr("\nFatal error: ");
+    write2stderr(text);
+    write2stderr("\n");
+    abort();
+}
+#endif
+
+void
+log_set_file( const char *name )
+{
+    FILE *fp = (name && strcmp(name,"-"))? fopen(name, "a") : stderr;
+    if( !fp ) {
+	fprintf(stderr, "failed to open log file `%s': %s\n",
+						name, strerror(errno));
+	return;
+    }
+    setvbuf( fp, NULL, _IOLBF, 0 );
+
+    if( logstream && logstream != stderr )
+	fclose( logstream );
+    logstream = fp;
+    use_time = fp != stderr;
+    missing_lf = 0;
+}
+
+
+int
+log_get_fd()
+{
+    return fileno(logstream?logstream:stderr);
+}
+
+static void
+do_logv( int level, const char *fmt, va_list arg_ptr )
+{
+    if( !logstream )
+	logstream = stderr;
+
+    if( missing_lf && level != MY_LOG_CONT )
+	putc('\n', logstream );
+    missing_lf = 0;
+
+    if( use_time && level != MY_LOG_CONT ) {
+	/* Note this does not work for multiple line logging as we would
+	 * need to print to a buffer first */
+	struct tm *tp;
+	time_t atime = time(NULL);
+
+	tp = localtime( &atime );
+	fprintf( logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
+		    1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+			 tp->tm_hour, tp->tm_min, tp->tm_sec );
+    }
+
+    switch ( level ) {
+      case MY_LOG_BEGIN: break;
+      case MY_LOG_CONT: break;
+      case MY_LOG_INFO: break;
+      case MY_LOG_WARN: break;
+      case MY_LOG_ERROR: break;
+      case MY_LOG_FATAL: fputs("Fatal: ",logstream ); break;
+      case MY_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break;
+      case MY_LOG_DEBUG: fputs("DBG: ", logstream ); break;
+      default: fprintf(logstream,"[Unknown log level %d]: ", level ); break;
+    }
+
+    if( fmt ) {
+	vfprintf(logstream,fmt,arg_ptr) ;
+	if( *fmt && fmt[strlen(fmt)-1] != '\n' )
+	    missing_lf = 1;
+    }
+
+    if( level == MY_LOG_FATAL )
+	exit(2);
+    if( level == MY_LOG_BUG )
+	abort();
+}
+
+static void
+do_log( int level, const char *fmt, ... )
+{
+    va_list arg_ptr ;
+
+    va_start( arg_ptr, fmt ) ;
+    do_logv( level, fmt, arg_ptr );
+    va_end(arg_ptr);
+}
+
+
+
+void
+log_info( const char *fmt, ... )
+{
+    va_list arg_ptr ;
+
+    va_start( arg_ptr, fmt ) ;
+    do_logv( MY_LOG_INFO, fmt, arg_ptr );
+    va_end(arg_ptr);
+}
+
+void
+log_error( const char *fmt, ... )
+{
+    va_list arg_ptr ;
+
+    va_start( arg_ptr, fmt ) ;
+    do_logv( MY_LOG_ERROR, fmt, arg_ptr );
+    va_end(arg_ptr);
+}
+
+
+void
+log_fatal( const char *fmt, ... )
+{
+    va_list arg_ptr ;
+
+    va_start( arg_ptr, fmt ) ;
+    do_logv( MY_LOG_FATAL, fmt, arg_ptr );
+    va_end(arg_ptr);
+    abort(); /* never called, bugs it makes the compiler happy */
+}
+
+void
+log_bug( const char *fmt, ... )
+{
+    va_list arg_ptr ;
+
+    va_start( arg_ptr, fmt ) ;
+    do_logv( MY_LOG_BUG, fmt, arg_ptr );
+    va_end(arg_ptr);
+    abort(); /* never called, but it makes the compiler happy */
+}
+
+void
+log_debug( const char *fmt, ... )
+{
+    va_list arg_ptr ;
+
+    va_start( arg_ptr, fmt ) ;
+    do_logv( MY_LOG_DEBUG, fmt, arg_ptr );
+    va_end(arg_ptr);
+}
+
+
+void
+log_printf( const char *fmt, ... )
+{
+    va_list arg_ptr ;
+
+    if( !fmt ) {
+	do_logv( MY_LOG_BEGIN, NULL, NULL );
+    }
+    else {
+	va_start( arg_ptr, fmt ) ;
+	do_logv( MY_LOG_CONT, fmt, arg_ptr );
+	va_end(arg_ptr);
+    }
+}
+
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
+void
+bug_at( const char *file, int line, const char *func )
+{
+    do_log( MY_LOG_BUG,
+	     ("... this is a bug (%s:%d:%s)\n"), file, line, func );
+    abort(); /* never called, but it makes the compiler happy */
+}
+#else
+void
+bug_at( const char *file, int line )
+{
+    do_log( MY_LOG_BUG,
+	     _("you found a bug ... (%s:%d)\n"), file, line);
+    abort(); /* never called, but it makes the compiler happy */
+}
+#endif
+
diff --git a/jnlib/logging.h b/jnlib/logging.h
new file mode 100644
index 000000000..2470c1c4e
--- /dev/null
+++ b/jnlib/logging.h
@@ -0,0 +1,46 @@
+/* logging.h
+ *	Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+#ifndef LIBJNLIB_LOGGING_H
+#define LIBJNLIB_LOGGING_H
+
+#include <stdio.h>
+#include "mischelp.h"
+
+void log_set_file( const char *name );
+int  log_get_fd(void);
+
+#ifdef JNLIB_GCC_M_FUNCTION
+  void bug_at( const char *file, int line, const char *func ) JNLIB_GCC_A_NR;
+# define BUG() bug_at( __FILE__ , __LINE__, __FUNCTION__ )
+#else
+  void bug_at( const char *file, int line );
+# define BUG() bug_at( __FILE__ , __LINE__ )
+#endif
+
+void log_bug( const char *fmt, ... )	JNLIB_GCC_A_NR_PRINTF(1,2);
+void log_fatal( const char *fmt, ... )	JNLIB_GCC_A_NR_PRINTF(1,2);
+void log_error( const char *fmt, ... )	JNLIB_GCC_A_PRINTF(1,2);
+void log_info( const char *fmt, ... )	JNLIB_GCC_A_PRINTF(1,2);
+void log_debug( const char *fmt, ... )	JNLIB_GCC_A_PRINTF(1,2);
+void log_printf( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
+
+
+#endif /*LIBJNLIB_LOGGING_H*/
diff --git a/jnlib/mischelp.h b/jnlib/mischelp.h
new file mode 100644
index 000000000..684a6973d
--- /dev/null
+++ b/jnlib/mischelp.h
@@ -0,0 +1,43 @@
+/* mischelp.h
+ *	Copyright (C) 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+#ifndef LIBJNLIB_MISCHELP_H
+#define LIBJNLIB_MISCHHELP_H
+
+
+#define DIM(v)		     (sizeof(v)/sizeof((v)[0]))
+#define DIMof(type,member)   DIM(((type *)0)->member)
+
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
+# define JNLIB_GCC_M_FUNCTION 1
+# define JNLIB_GCC_A_NR 	     __attribute__ ((noreturn))
+# define JNLIB_GCC_A_PRINTF( f, a )  __attribute__ ((format (printf,f,a)))
+# define JNLIB_GCC_A_NR_PRINTF( f, a ) \
+			    __attribute__ ((noreturn, format (printf,f,a)))
+#else
+# define JNLIB_GCC_A_NR
+# define JNLIB_GCC_A_PRINTF( f, a )
+# define JNLIB_GCC_A_NR_PRINTF( f, a )
+#endif
+
+
+
+#endif /*LIBJNLIB_MISCHELP_H*/
diff --git a/jnlib/stringhelp.c b/jnlib/stringhelp.c
new file mode 100644
index 000000000..f3dbedbd0
--- /dev/null
+++ b/jnlib/stringhelp.c
@@ -0,0 +1,219 @@
+/* stringhelp.c -  standard string helper functions
+ *	Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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 <string.h>
+#include <ctype.h>
+
+#include "libjnlib-config.h"
+#include "stringhelp.h"
+
+
+/****************
+ * look for the substring SUB in buffer and return a pointer to that
+ * substring in BUF or NULL if not found.
+ * Comparison is case-insensitive.
+ */
+const char *
+memistr( const 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=t++, buflen = n--, s++;
+		 n && toupper(*t) == toupper(*s); t++, s++, n-- )
+		;
+	    if( !*s )
+		return buf;
+	    t = buf; n = buflen; s = sub ;
+	}
+
+    return NULL ;
+}
+
+/****************
+ * Wie strncpy(), aber es werden maximal n-1 zeichen kopiert und ein
+ * '\0' angeh�ngt. Ist n = 0, so geschieht nichts, ist Destination
+ * gleich NULL, so wird via jnlib_xmalloc Speicher besorgt, ist dann nicht
+ * gen�gend Speicher vorhanden, so bricht die funktion ab.
+ */
+char *
+mem2str( char *dest , const void *src , size_t n )
+{
+    char *d;
+    const char *s;
+
+    if( n ) {
+	if( !dest )
+	    dest = jnlib_xmalloc( n ) ;
+	d = dest;
+	s = src ;
+	for(n--; n && *s; n-- )
+	    *d++ = *s++;
+	*d = '\0' ;
+    }
+
+    return dest ;
+}
+
+
+/****************
+ * remove leading and trailing white spaces
+ */
+char *
+trim_spaces( char *str )
+{
+    char *string, *p, *mark;
+
+    string = str;
+    /* find first non space character */
+    for( p=string; *p && isspace( *(byte*)p ) ; p++ )
+	;
+    /* move characters */
+    for( (mark = NULL); (*string = *p); string++, p++ )
+	if( isspace( *(byte*)p ) ) {
+	    if( !mark )
+		mark = string ;
+	}
+	else
+	    mark = NULL ;
+    if( mark )
+	*mark = '\0' ;  /* remove trailing spaces */
+
+    return str ;
+}
+
+/****************
+ * remove trailing white spaces
+ */
+char *
+trim_trailing_spaces( char *string )
+{
+    char *p, *mark;
+
+    for( mark = NULL, p = string; *p; p++ ) {
+	if( isspace( *(byte*)p ) ) {
+	    if( !mark )
+		mark = p;
+	}
+	else
+	    mark = NULL;
+    }
+    if( mark )
+	*mark = '\0' ;
+
+    return string ;
+}
+
+
+
+unsigned
+trim_trailing_chars( byte *line, unsigned len, const char *trimchars )
+{
+    byte *p, *mark;
+    unsigned n;
+
+    for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
+	if( strchr(trimchars, *p ) ) {
+	    if( !mark )
+		mark = p;
+	}
+	else
+	    mark = NULL;
+    }
+
+    if( mark ) {
+	*mark = 0;
+	return mark - line;
+    }
+    return len;
+}
+
+/****************
+ * remove trailing white spaces and return the length of the buffer
+ */
+unsigned
+trim_trailing_ws( byte *line, unsigned len )
+{
+    return trim_trailing_chars( line, len, " \t\r\n" );
+}
+
+
+
+/*********************************************
+ ********** missing string functions *********
+ *********************************************/
+
+#ifndef HAVE_STPCPY
+char *
+stpcpy(char *a,const char *b)
+{
+    while( *b )
+	*a++ = *b++;
+    *a = 0;
+
+    return (char*)a;
+}
+#endif
+
+#ifndef HAVE_STRLWR
+char *
+strlwr(char *s)
+{
+    char *p;
+    for(p=s; *p; p++ )
+	*p = tolower(*p);
+    return s;
+}
+#endif
+
+
+#ifndef HAVE_STRCASECMP
+int
+strcasecmp( const char *a, const char *b )
+{
+    for( ; *a && *b; a++, b++ ) {
+	if( *a != *b && toupper(*a) != toupper(*b) )
+	    break;
+    }
+    return *(const byte*)a - *(const byte*)b;
+}
+#endif
+
+
+/****************
+ * mingw32/cpd has a memicmp()
+ */
+#ifndef HAVE_MEMICMP
+int
+memicmp( const char *a, const char *b, size_t n )
+{
+    for( ; n; n--, a++, b++ )
+	if( *a != *b  && toupper(*(const byte*)a) != toupper(*(const byte*)b) )
+	    return *(const byte *)a - *(const byte*)b;
+    return 0;
+}
+#endif
+
+
+
diff --git a/jnlib/stringhelp.h b/jnlib/stringhelp.h
new file mode 100644
index 000000000..9aed12427
--- /dev/null
+++ b/jnlib/stringhelp.h
@@ -0,0 +1,60 @@
+/* stringhelp.h
+ *	Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+#ifndef LIBJNLIB_STRINGHELP_H
+#define LIBJNLIB_STRINGHELP_H
+
+
+const char *memistr( const char *buf, size_t buflen, const char *sub );
+char *mem2str( char *, const void *, size_t);
+char *trim_spaces( char *string );
+char *trim_trailing_spaces( char *string );
+unsigned int trim_trailing_chars( unsigned char *line, unsigned len,
+					      const char *trimchars);
+unsigned int trim_trailing_ws( unsigned char *line, unsigned len );
+
+
+#ifndef HAVE_MEMICMP
+int memicmp( const char *a, const char *b, size_t n );
+#endif
+#ifndef HAVE_STPCPY
+char *stpcpy(char *a,const char *b);
+#endif
+#ifndef HAVE_STRLWR
+char *strlwr(char *a);
+#endif
+#ifndef HAVE_STRTOUL
+  #define strtoul(a,b,c)  ((unsigned long)strtol((a),(b),(c)))
+#endif
+#ifndef HAVE_MEMMOVE
+  #define memmove(d, s, n) bcopy((s), (d), (n))
+#endif
+#ifndef HAVE_STRICMP
+  #define stricmp(a,b)	 strcasecmp( (a), (b) )
+#endif
+
+
+#ifndef STR
+  #define STR(v) #v
+#endif
+#define STR2(v) STR(v)
+
+
+#endif /*LIBJNLIB_STRINGHELP_H*/
diff --git a/jnlib/xmalloc.c b/jnlib/xmalloc.c
new file mode 100644
index 000000000..fa016d85b
--- /dev/null
+++ b/jnlib/xmalloc.c
@@ -0,0 +1,70 @@
+/* xmalloc.c -	standard malloc wrappers
+ *	Copyright (C) 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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 <stdio.h>
+
+#include "libjnlib-config.h"
+#include "xmalloc.h"
+
+static void
+out_of_core(void)
+{
+    fputs("\nfatal: out of memory\n", stderr );
+    exit(2);
+}
+
+
+void *
+xmalloc( size_t n )
+{
+    void *p = malloc( n );
+    if( !p )
+	out_of_core();
+    return p;
+}
+
+void *
+xrealloc( void *a, size_t n )
+{
+    void *p = realloc( a, n );
+    if( !p )
+	out_of_core();
+    return p;
+}
+
+void *
+xcalloc( size_t n, size_t m )
+{
+    void *p = calloc( n, m );
+    if( !p )
+	out_of_core();
+    return p;
+}
+
+char *
+xstrdup( const char *string )
+{
+    void *p = xmalloc( strlen(string)+1 );
+    strcpy( p, string );
+    return p;
+}
+
diff --git a/jnlib/xmalloc.h b/jnlib/xmalloc.h
new file mode 100644
index 000000000..95489c5a2
--- /dev/null
+++ b/jnlib/xmalloc.h
@@ -0,0 +1,30 @@
+/* xmalloc.h
+ *	Copyright (C) 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+#ifndef LIBJNLIB_XMALLOC_H
+#define LIBJNLIB_XMALLOC_H
+
+void *xmalloc( size_t n );
+void *xrealloc( void *a, size_t n );
+void *xcalloc( size_t n, size_t m );
+char *xstrdup( const char *string );
+
+
+#endif /*LIBJNLIB_XMALLOC_H*/