diff options
author | Werner Koch <wk@gnupg.org> | 2000-01-24 13:05:50 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2000-01-24 13:05:50 +0100 |
commit | 54b141f63e3fda38b6e780d0f47c192c6542a49b (patch) | |
tree | e80be78a69a8dc5c9286da4d4590ec7491c63b39 | |
parent | See ChangeLog: Mon Jan 24 13:04:28 CET 2000 Werner Koch (diff) | |
download | gnupg2-54b141f63e3fda38b6e780d0f47c192c6542a49b.tar.xz gnupg2-54b141f63e3fda38b6e780d0f47c192c6542a49b.zip |
Add files to new directory.
This is mainly stuff moved from ../util
to here.
-rw-r--r-- | jnlib/Makefile.am | 19 | ||||
-rw-r--r-- | jnlib/README | 7 | ||||
-rw-r--r-- | jnlib/argparse.c | 994 | ||||
-rw-r--r-- | jnlib/argparse.h | 64 | ||||
-rw-r--r-- | jnlib/dotlock.c | 346 | ||||
-rw-r--r-- | jnlib/dotlock.h | 32 | ||||
-rw-r--r-- | jnlib/libjnlib-config.h | 49 | ||||
-rw-r--r-- | jnlib/logging.c | 241 | ||||
-rw-r--r-- | jnlib/logging.h | 46 | ||||
-rw-r--r-- | jnlib/mischelp.h | 43 | ||||
-rw-r--r-- | jnlib/stringhelp.c | 219 | ||||
-rw-r--r-- | jnlib/stringhelp.h | 60 | ||||
-rw-r--r-- | jnlib/xmalloc.c | 70 | ||||
-rw-r--r-- | jnlib/xmalloc.h | 30 |
14 files changed, 2220 insertions, 0 deletions
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*/ |