Add missing jnlib directory
authorWerner Koch <wk@gnupg.org>
Tue, 19 Dec 2000 10:09:11 +0000 (10:09 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 19 Dec 2000 10:09:11 +0000 (10:09 +0000)
15 files changed:
trunk/jnlib/ChangeLog [new file with mode: 0644]
trunk/jnlib/README [new file with mode: 0644]
trunk/jnlib/argparse.c [new file with mode: 0644]
trunk/jnlib/argparse.h [new file with mode: 0644]
trunk/jnlib/dotlock.c [new file with mode: 0644]
trunk/jnlib/dotlock.h [new file with mode: 0644]
trunk/jnlib/libjnlib-config.h [new file with mode: 0644]
trunk/jnlib/logging.c [new file with mode: 0644]
trunk/jnlib/logging.h [new file with mode: 0644]
trunk/jnlib/mischelp.h [new file with mode: 0644]
trunk/jnlib/stringhelp.c [new file with mode: 0644]
trunk/jnlib/stringhelp.h [new file with mode: 0644]
trunk/jnlib/types.h [new file with mode: 0644]
trunk/jnlib/xmalloc.c [new file with mode: 0644]
trunk/jnlib/xmalloc.h [new file with mode: 0644]

diff --git a/trunk/jnlib/ChangeLog b/trunk/jnlib/ChangeLog
new file mode 100644 (file)
index 0000000..ed5e20a
--- /dev/null
@@ -0,0 +1,41 @@
+2000-07-26 10:02:51  Werner Koch  (wk@habibti.openit.de)
+
+  * stringhelp.c.: Add stdarg.h
+  * argparse.h: s/ulong/unsigned long/ although this should be defined
+  by types.h.
+
+2000-06-28 19:40:23  Werner Koch  (wk@habibti.openit.de)
+
+  * Makefile.am: Replaced second logging.c by .h
+
+2000-05-24 08:58:15  Werner Koch  (wk@habibti.openit.de)
+
+  * logging.c (log_get_errorcount): New.
+
+2000-05-24 08:44:47  Werner Koch  (wk@habibti.openit.de)
+
+  * stringhelp.c: Added a few filename related helper functions.
+
+2000-05-11 18:04:43  Werner Koch  (wk@habibti.openit.de)
+
+  * xmalloc.c (xstrcat2):  Replaced stpcpy to quickly address W32
+    problems.
+
+2000-05-02 19:43:38  Werner Koch  (wk@habibti.openit.de)
+
+  * xmalloc.c (xstrcat2): New.
+
+Mon Jan 24 13:04:28 CET 2000  Werner Koch  <wk@gnupg.de>
+
+  * README: New.
+  * Makefile.am: new.
+  * argparse.c argparse.h logging.c logging.h
+    mischelp.h stringhelp.c stringhelp.h xmalloc.c
+    xmalloc.h dotlock.c: Moved from ../util to here.
+  * dotlock.h: New.
+  * libjnlib-config.h: New.
+
+  * logging.c (log_set_file): New.
+  (log_printf): New.
+  (do_logv): Add kludge to insert LFs.
+
diff --git a/trunk/jnlib/README b/trunk/jnlib/README
new file mode 100644 (file)
index 0000000..e49ef44
--- /dev/null
@@ -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 allocator.
+
diff --git a/trunk/jnlib/argparse.c b/trunk/jnlib/argparse.c
new file mode 100644 (file)
index 0000000..0384c5d
--- /dev/null
@@ -0,0 +1,995 @@
+/* [argparse.c wk 17.06.97] Argument Parser for option handling
+ *     Copyright (C) 1998, 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
+ */
+
+#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) 2000 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/trunk/jnlib/argparse.h b/trunk/jnlib/argparse.h
new file mode 100644 (file)
index 0000000..3668a21
--- /dev/null
@@ -0,0 +1,67 @@
+/* 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
+
+#include <stdio.h>
+#include "types.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;
+        unsigned long 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/trunk/jnlib/dotlock.c b/trunk/jnlib/dotlock.c
new file mode 100644 (file)
index 0000000..8e61f7a
--- /dev/null
@@ -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/trunk/jnlib/dotlock.h b/trunk/jnlib/dotlock.h
new file mode 100644 (file)
index 0000000..d54219e
--- /dev/null
@@ -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/trunk/jnlib/libjnlib-config.h b/trunk/jnlib/libjnlib-config.h
new file mode 100644 (file)
index 0000000..4cc57b2
--- /dev/null
@@ -0,0 +1,75 @@
+/* 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
+
+#include "xmalloc.h"
+#include "logging.h"
+
+
+
+#ifdef USE_SIMPLE_GETTEXT
+  int set_gettext_file( const char *filename );
+  const char *gettext( const char *msgid );
+
+  #define _(a) gettext (a)
+  #define N_(a) (a)
+
+#else
+#ifdef HAVE_LOCALE_H
+  #include <locale.h>
+#endif
+
+#ifdef ENABLE_NLS
+  #include <libintl.h>
+  #define _(a) gettext (a)
+  #ifdef gettext_noop
+    #define N_(a) gettext_noop (a)
+  #else
+    #define N_(a) (a)
+  #endif
+#else
+  #define _(a) (a)
+  #define N_(a) (a)
+#endif
+#endif /* !USE_SIMPLE_GETTEXT */
+
+
+#define jnlib_xmalloc(a)    xmalloc( (a) )
+#define jnlib_xcalloc(a,b)  xcalloc( (a), (b) )
+#define jnlib_xrealloc(a,n) xrealloc( (a), (n) )
+#define jnlib_xstrdup(a)    xstrdup( (a) )
+#define jnlib_free(a)      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/trunk/jnlib/logging.c b/trunk/jnlib/logging.c
new file mode 100644 (file)
index 0000000..7ab2cb5
--- /dev/null
@@ -0,0 +1,257 @@
+/* logging.c - useful logging functions
+ *     Copyright (C) 1998, 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
+ */
+
+
+/* This file should replace logger.c in the future - for now it is not
+ * used by GnuPG but by GPA.
+ * 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>
+#ifdef __MINGW32__
+  #include <io.h>
+#endif
+
+#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;
+static int errorcount;
+
+#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
+
+int
+log_get_errorcount (int clear)
+{
+    int n = errorcount;
+    if( clear )
+       errorcount = 0;
+    return n;
+}
+
+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);
+    /* protect against counter overflow */
+    if( errorcount < 30000 )
+       errorcount++;
+}
+
+
+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/trunk/jnlib/logging.h b/trunk/jnlib/logging.h
new file mode 100644 (file)
index 0000000..5084b71
--- /dev/null
@@ -0,0 +1,47 @@
+/* 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"
+
+int  log_get_errorcount (int clear);
+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/trunk/jnlib/mischelp.h b/trunk/jnlib/mischelp.h
new file mode 100644 (file)
index 0000000..684a697
--- /dev/null
@@ -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/trunk/jnlib/stringhelp.c b/trunk/jnlib/stringhelp.c
new file mode 100644 (file)
index 0000000..59345f2
--- /dev/null
@@ -0,0 +1,323 @@
+/* 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 <stdarg.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" );
+}
+
+
+/***************
+ * Extract from a given path the filename component.
+ *
+ */
+char *
+make_basename(const char *filepath)
+{
+    char *p;
+
+    if ( !(p=strrchr(filepath, '/')) )
+      #ifdef HAVE_DRIVE_LETTERS
+       if ( !(p=strrchr(filepath, '\\')) )
+           if ( !(p=strrchr(filepath, ':')) )
+      #endif
+             {
+               return jnlib_xstrdup(filepath);
+             }
+
+    return jnlib_xstrdup(p+1);
+}
+
+
+
+/***************
+ * Extract from a given filename the path prepended to it.
+ * If their isn't a path prepended to the filename, a dot
+ * is returned ('.').
+ *
+ */
+char *
+make_dirname(const char *filepath)
+{
+    char *dirname;
+    int  dirname_length;
+    char *p;
+
+    if ( !(p=strrchr(filepath, '/')) )
+      #ifdef HAVE_DRIVE_LETTERS
+       if ( !(p=strrchr(filepath, '\\')) )
+           if ( !(p=strrchr(filepath, ':')) )
+      #endif
+             {
+               return jnlib_xstrdup(".");
+             }
+
+    dirname_length = p-filepath;
+    dirname = jnlib_xmalloc(dirname_length+1);
+    strncpy(dirname, filepath, dirname_length);
+    dirname[dirname_length] = 0;
+
+    return dirname;
+}
+
+
+
+/****************
+ * Construct a filename from the NULL terminated list of parts.
+ * Tilde expansion is done here.
+ */
+char *
+make_filename( const char *first_part, ... )
+{
+    va_list arg_ptr ;
+    size_t n;
+    const char *s;
+    char *name, *home, *p;
+
+    va_start( arg_ptr, first_part ) ;
+    n = strlen(first_part)+1;
+    while( (s=va_arg(arg_ptr, const char *)) )
+       n += strlen(s) + 1;
+    va_end(arg_ptr);
+
+    home = NULL;
+    if( *first_part == '~' && first_part[1] == '/'
+                          && (home = getenv("HOME")) && *home )
+       n += strlen(home);
+
+    name = jnlib_xmalloc(n);
+    p = home ? stpcpy(stpcpy(name,home), first_part+1)
+            : stpcpy(name, first_part);
+    va_start( arg_ptr, first_part ) ;
+    while( (s=va_arg(arg_ptr, const char *)) )
+       p = stpcpy(stpcpy(p,"/"), s);
+    va_end(arg_ptr);
+
+    return name;
+}
+
+
+int
+compare_filenames( const char *a, const char *b )
+{
+    /* ? check whether this is an absolute filename and
+     * resolve symlinks?
+     */
+  #ifdef HAVE_DRIVE_LETTERS
+    return stricmp(a,b);
+  #else
+    return strcmp(a,b);
+  #endif
+}
+
+
+/*********************************************
+ ********** 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/trunk/jnlib/stringhelp.h b/trunk/jnlib/stringhelp.h
new file mode 100644 (file)
index 0000000..ebdd7b2
--- /dev/null
@@ -0,0 +1,65 @@
+/* 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
+
+#include "types.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 );
+
+
+char *make_basename(const char *filepath);
+char *make_dirname(const char *filepath);
+char *make_filename( const char *first_part, ... );
+int compare_filenames( const char *a, const char *b );
+
+#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/trunk/jnlib/types.h b/trunk/jnlib/types.h
new file mode 100644 (file)
index 0000000..a5d0e42
--- /dev/null
@@ -0,0 +1,101 @@
+/* types.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_TYPES_H
+#define LIBJNLIB_TYPES_H
+
+/* The AC_CHECK_SIZEOF() in configure fails for some machines.
+ * we provide some fallback values here */
+#if !SIZEOF_UNSIGNED_SHORT
+  #undef SIZEOF_UNSIGNED_SHORT
+  #define SIZEOF_UNSIGNED_SHORT 2
+#endif
+#if !SIZEOF_UNSIGNED_INT
+  #undef SIZEOF_UNSIGNED_INT
+  #define SIZEOF_UNSIGNED_INT 4
+#endif
+#if !SIZEOF_UNSIGNED_LONG
+  #undef SIZEOF_UNSIGNED_LONG
+  #define SIZEOF_UNSIGNED_LONG 4
+#endif
+
+
+#include <sys/types.h>
+
+
+#ifndef HAVE_BYTE_TYPEDEF
+  #undef byte      /* maybe there is a macro with this name */
+  typedef unsigned char byte;
+  #define HAVE_BYTE_TYPEDEF
+#endif
+
+#ifndef HAVE_USHORT_TYPEDEF
+  #undef ushort     /* maybe there is a macro with this name */
+  typedef unsigned short ushort;
+  #define HAVE_USHORT_TYPEDEF
+#endif
+
+#ifndef HAVE_ULONG_TYPEDEF
+  #undef ulong     /* maybe there is a macro with this name */
+  typedef unsigned long ulong;
+  #define HAVE_ULONG_TYPEDEF
+#endif
+
+#ifndef HAVE_U16_TYPEDEF
+  #undef u16       /* maybe there is a macro with this name */
+  #if SIZEOF_UNSIGNED_INT == 2
+    typedef unsigned int   u16;
+  #elif SIZEOF_UNSIGNED_SHORT == 2
+    typedef unsigned short u16;
+  #else
+    #error no typedef for u16
+  #endif
+  #define HAVE_U16_TYPEDEF
+#endif
+
+#ifndef HAVE_U32_TYPEDEF
+  #undef u32       /* maybe there is a macro with this name */
+  #if SIZEOF_UNSIGNED_INT == 4
+    typedef unsigned int u32;
+  #elif SIZEOF_UNSIGNED_LONG == 4
+    typedef unsigned long u32;
+  #else
+    #error no typedef for u32
+  #endif
+  #define HAVE_U32_TYPEDEF
+#endif
+
+#ifndef HAVE_U64_TYPEDEF
+  #undef u64       /* maybe there is a macro with this name */
+  #if SIZEOF_UNSIGNED_INT == 8
+    typedef unsigned int u64;
+    #define HAVE_U64_TYPEDEF
+  #elif SIZEOF_UNSIGNED_LONG == 8
+    typedef unsigned long u64;
+    #define HAVE_U64_TYPEDEF
+  #elif __GNUC__ >= 2 || defined(__SUNPRO_C)
+    typedef unsigned long long u64;
+    #define HAVE_U64_TYPEDEF
+  #endif
+#endif
+
+
+
+#endif /*LIBJNLIB_TYPES_H*/
diff --git a/trunk/jnlib/xmalloc.c b/trunk/jnlib/xmalloc.c
new file mode 100644 (file)
index 0000000..34ecc28
--- /dev/null
@@ -0,0 +1,88 @@
+/* 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 <string.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;
+}
+
+
+char *
+xstrcat2( const char *a, const char *b )
+{
+    size_t n1;
+    char *p;
+
+    if( !b )
+       return xstrdup( a );
+
+    n1 = strlen(a);
+    p = xmalloc( n1 + strlen(b) + 1 );
+    memcpy(p, a, n1 );
+    strcpy(p+n1, b );
+    return p;
+}
+
diff --git a/trunk/jnlib/xmalloc.h b/trunk/jnlib/xmalloc.h
new file mode 100644 (file)
index 0000000..4dd88ec
--- /dev/null
@@ -0,0 +1,31 @@
+/* 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 );
+char *xstrcat2( const char *a, const char *b );
+
+
+#endif /*LIBJNLIB_XMALLOC_H*/