new release
[gnupg.git] / util / argparse.c
index 3d51d01..ce1dbc6 100644 (file)
@@ -1,5 +1,5 @@
 /* [argparse.c wk 17.06.97] Argument Parser for option handling
- *     Copyright (c) 1997 by Werner Koch (dd9jn)
+ *     Copyright (C) 1998 Free Software Foundation, Inc.
  *  This file is part of WkLib.
  *
  *  WkLib is free software; you can redistribute it and/or modify
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <ctype.h>
 #include <string.h>
 
 #include "util.h"
+#include "i18n.h"
 
-#ifdef DOCUMENTATION
-@Summary arg_parse
- #include <wk/lib.h>
-
- typedef struct {
-     char *argc;           /* pointer to argc (value subject to change) */
-     char ***argv;         /* pointer to argv (value subject to change) */
-     unsigned flags;       /* Global flags (DO NOT CHANGE) */
-     int err;              /* print error about last option */
-                           /* 1 = warning, 2 = abort */
-     int r_opt;            /* return option */
-     int r_type;           /* type of return value (0 = no argument found)*/
-     union {
-        int   ret_int;
-        long  ret_long
-        ulong ret_ulong;
-        char *ret_str;
-     } r;                  /* Return values */
-     struct {
-        int index;
-        const char *last;
-     } internal;           /* DO NOT CHANGE */
- } ARGPARSE_ARGS;
-
- typedef struct {
-     int        short_opt;
-     const char *long_opt;
-     unsigned flags;
- } ARGPARSE_OPTS;
-
- int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
-
-@Description
- This is my replacement for getopt(). See the example for a typical usage.
- Global flags are:
-    Bit 0 : Do not remove options form argv
-    Bit 1 : Do not stop at last option but return other args
-           with r_opt set to -1.
-    Bit 2 : Assume options and real args are mixed.
-    Bit 3 : Do not use -- to stop option processing.
-    Bit 4 : Do not skip the first arg.
-    Bit 5 : allow usage of long option with only one dash
-    all other bits must be set to zero, this value is modified by the function
-    so assume this is write only.
- Local flags (for each option):
-    Bit 2-0 : 0 = does not take an argument
-             1 = takes int argument
-             2 = takes string argument
-             3 = takes long argument
-             4 = takes ulong argument
-    Bit 3 : argument is optional (r_type will the be set to 0)
-    Bit 4 : allow 0x etc. prefixed values.
- If can stop the option processing by setting opts to NULL, the function will
- then return 0.
-@Return Value
-  Returns the args.r_opt or 0 if ready
-  r_opt may be -2 to indicate an unknown option.
-@See Also
-  ArgExpand
-@Notes
- You do not need to process the options 'h', '--help' or '--version'
- because this function includes standard help processing; but if you
- specify '-h', '--help' or '--version' you have to do it yourself.
- The option '--' stops argument processing; if bit 1 is set the function
- continues to return normal arguments.
- To process float args or unsigned args you must use a string args and do
- the conversion yourself.
-@Example
-
-    ARGPARSE_OPTS opts[] = {
-    { 'v', "verbose",   0 },
-    { 'd', "debug",     0 },
-    { 'o', "output",    2 },
-    { 'c', "cross-ref", 2|8 },
-    { 'm', "my-option", 1|8 },
-    { 500, "have-no-short-option-for-this-long-option", 0 },
-    {0} };
-    ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
-
-    while( ArgParse( &pargs, &opts) ) {
-       switch( pargs.r_opt ) {
-         case 'v': opt.verbose++; break;
-         case 'd': opt.debug++; break;
-         case 'o': opt.outfile = pargs.r.ret_str; break;
-         case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
-         case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
-         case 500: opt.a_long_one++;  break
-         default : pargs.err = 1; break; /* force warning output */
-       }
-    }
-    if( argc > 1 )
-       log_fatal( "Too many args");
-
-#endif /*DOCUMENTATION*/
 
+/*********************************
+ * @Summary arg_parse
+ *  #include <wk/lib.h>
+ *
+ *  typedef struct {
+ *     char *argc;               pointer to argc (value subject to change)
+ *     char ***argv;             pointer to argv (value subject to change)
+ *     unsigned flags;           Global flags (DO NOT CHANGE)
+ *     int err;                  print error about last option
+ *                               1 = warning, 2 = abort
+ *     int r_opt;                return option
+ *     int r_type;               type of return value (0 = no argument found)
+ *     union {
+ *         int   ret_int;
+ *         long  ret_long
+ *         ulong ret_ulong;
+ *         char *ret_str;
+ *     } r;                      Return values
+ *     struct {
+ *         int index;
+ *         const char *last;
+ *     } internal;               DO NOT CHANGE
+ *  } ARGPARSE_ARGS;
+ *
+ *  typedef struct {
+ *     int         short_opt;
+ *     const char *long_opt;
+ *     unsigned flags;
+ *  } ARGPARSE_OPTS;
+ *
+ *  int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
+ *
+ * @Description
+ *  This is my replacement for getopt(). See the example for a typical usage.
+ *  Global flags are:
+ *     Bit 0 : Do not remove options form argv
+ *     Bit 1 : Do not stop at last option but return other args
+ *            with r_opt set to -1.
+ *     Bit 2 : Assume options and real args are mixed.
+ *     Bit 3 : Do not use -- to stop option processing.
+ *     Bit 4 : Do not skip the first arg.
+ *     Bit 5 : allow usage of long option with only one dash
+ *     all other bits must be set to zero, this value is modified by the function
+ *     so assume this is write only.
+ *  Local flags (for each option):
+ *     Bit 2-0 : 0 = does not take an argument
+ *              1 = takes int argument
+ *              2 = takes string argument
+ *              3 = takes long argument
+ *              4 = takes ulong argument
+ *     Bit 3 : argument is optional (r_type will the be set to 0)
+ *     Bit 4 : allow 0x etc. prefixed values.
+ *  If can stop the option processing by setting opts to NULL, the function will
+ *  then return 0.
+ * @Return Value
+ *   Returns the args.r_opt or 0 if ready
+ *   r_opt may be -2 to indicate an unknown option.
+ * @See Also
+ *   ArgExpand
+ * @Notes
+ *  You do not need to process the options 'h', '--help' or '--version'
+ *  because this function includes standard help processing; but if you
+ *  specify '-h', '--help' or '--version' you have to do it yourself.
+ *  The option '--' stops argument processing; if bit 1 is set the function
+ *  continues to return normal arguments.
+ *  To process float args or unsigned args you must use a string args and do
+ *  the conversion yourself.
+ * @Example
+ *
+ *     ARGPARSE_OPTS opts[] = {
+ *     { 'v', "verbose",   0 },
+ *     { 'd', "debug",     0 },
+ *     { 'o', "output",    2 },
+ *     { 'c', "cross-ref", 2|8 },
+ *     { 'm', "my-option", 1|8 },
+ *     { 500, "have-no-short-option-for-this-long-option", 0 },
+ *     {0} };
+ *     ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
+ *
+ *     while( ArgParse( &pargs, &opts) ) {
+ *        switch( pargs.r_opt ) {
+ *          case 'v': opt.verbose++; break;
+ *          case 'd': opt.debug++; break;
+ *          case 'o': opt.outfile = pargs.r.ret_str; break;
+ *          case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
+ *          case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
+ *          case 500: opt.a_long_one++;  break
+ *          default : pargs.err = 1; break; -- force warning output --
+ *        }
+ *     }
+ *     if( argc > 1 )
+ *        log_fatal( "Too many args");
+ *
+ */
 
 
-static void set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
+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);
 
-
-int
-arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+static void
+initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
 {
-    int index;
-    int argc;
-    char **argv;
-    char *s, *s2;
-    int i;
-
     if( !(arg->flags & (1<<15)) ) { /* initialize this instance */
        arg->internal.index = 0;
        arg->internal.last = NULL;
@@ -148,20 +143,201 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
        if( *arg->argc < 0 )
            log_bug("Invalid argument for ArgParse\n");
     }
-    argc = *arg->argc;
-    argv = *arg->argv;
-    index = arg->internal.index;
 
     if( arg->err ) { /* last option was erroneous */
-       if( arg->r_opt == -3 )
-           s = "Missing argument for option \"%.50s\"\n";
-       else
-           s = "Invalid option \"%.50s\"\n";
-       log_error(s, arg->internal.last? arg->internal.last:"[??]" );
+       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
+               s = "%s:%u: invalid option\n";
+           log_error(s, filename, *lineno );
+       }
+       else {
+           if( arg->r_opt == -3 )
+               s = "Missing argument for option \"%.50s\"\n";
+           else
+               s = "Invalid option \"%.50s\"\n";
+           log_error(s, arg->internal.last? arg->internal.last:"[??]" );
+       }
        if( arg->err != 1 )
            exit(2);
        arg->err = 0;
     }
+}
+
+
+
+/****************
+ * 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.
+ * Caller must free returned strings.
+ * If called with FP set to NULL command line args are parse instead.
+ */
+int
+optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
+              ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+    int state, i, c;
+    int index=0;
+    char keyword[100];
+    char *buffer = NULL;
+    size_t buflen = 0;
+    int inverse=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;
+               index = i;
+               arg->r_opt = opts[index].short_opt;
+               if( inverse )
+                   arg->r_opt = -arg->r_opt;
+               if( !opts[index].short_opt )
+                   arg->r_opt = -2;           /* unknown option */
+               else if( (opts[index].flags & 8) ) /* no argument */
+                   arg->r_opt = -3;           /* error */
+               else                           /* no or optiona argument */
+                   arg->r_type = 0;           /* okay */
+               break;
+           }
+           else if( state == 3 ) {            /* no argument found */
+               if( !(opts[index].flags & 7) ) /* does not take an argument */
+                   arg->r_type = 0;           /* okay */
+               else if( (opts[index].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( !(opts[index].flags & 7) )  /* does not take an argument */
+                   arg->r_opt = -6;        /* error */
+               else {
+                   if( !buffer ) {
+                       keyword[i] = 0;
+                       buffer = m_strdup(keyword);
+                   }
+                   else
+                       buffer[i] = 0;
+
+                   if( !set_opt_arg(arg, opts[index].flags, buffer) )
+                       m_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;
+           index = i;
+           arg->r_opt = opts[index].short_opt;
+           if( !opts[index].short_opt ) {
+               arg->r_opt = -2;   /* unknown option */
+               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 = m_realloc(buffer, buflen);
+                   buffer[i++] = c;
+               }
+           }
+           else if( i < DIM(keyword)-1 )
+               keyword[i++] = c;
+           else {
+               buflen = DIM(keyword)+50;
+               buffer = m_alloc(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;
+}
+
+
+
+int
+arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+    int index;
+    int argc;
+    char **argv;
+    char *s, *s2;
+    int i;
+
+    initialize( arg, NULL, NULL );
+    argc = *arg->argc;
+    argv = *arg->argv;
+    index = arg->internal.index;
 
     if( !index && argc && !(arg->flags & (1<<4)) ) { /* skip the first entry */
        argc--; argv++; index++;
@@ -200,11 +376,12 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
 
        if( !opts[i].short_opt && !strcmp( "help", s+2) )
            show_help(opts, arg->flags);
-       else if( !opts[i].short_opt && !strcmp( "version", s+2) )
+       else if( !opts[i].short_opt && !strcmp( "version", s+2) ) {
            show_version();
+           exit(0);
+       }
        else if( !opts[i].short_opt && !strcmp( "warranty", s+2) ) {
-           puts( strusage(10) );
-           puts( strusage(31) );
+           puts( strusage(16) );
            exit(0);
        }
 
@@ -322,7 +499,7 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
 
 
 
-static void
+static int
 set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s)
 {
     int base = (flags & 16)? 0 : 10;
@@ -330,53 +507,127 @@ set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s)
     switch( arg->r_type = (flags & 7) ) {
       case 1: /* takes int argument */
        arg->r.ret_int = (int)strtol(s,NULL,base);
-       break;
-      default:
-      case 2: /* takes string argument */
-       arg->r.ret_str = s;
-       break;
+       return 0;
       case 3: /* takes long argument   */
        arg->r.ret_long= strtol(s,NULL,base);
-       break;
+       return 0;
       case 4: /* takes ulong argument  */
        arg->r.ret_ulong= strtoul(s,NULL,base);
-       break;
+       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;
 
-    puts( strusage(10) );
-    s = strusage(12);
-    if( *s == '\n' )
-       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( (j=strlen(opts[i].long_opt)) > indent && j < 35 )
-                   indent = j;
+               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;
-       puts("Options:");
+       if( *opts[0].description != '@' )
+           puts("Options:");
        for(i=0; opts[i].short_opt; i++ ) {
-           if( opts[i].short_opt < 256 )
+           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);
-           j = 3;
-           if( opts[i].long_opt )
-               j += printf("%c --%s   ", opts[i].short_opt < 256?',':' ',
-                                         opts[i].long_opt );
+           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 = opts[i].description) ) {
+           if( s ) {
+               if( *s && j > indent ) {
+                   putchar('\n');
+                   for(j=0;j < indent; j++ )
+                       putchar(' ');
+               }
                for(; *s; s++ ) {
                    if( *s == '\n' ) {
                        if( s[1] ) {
@@ -394,6 +645,10 @@ show_help( ARGPARSE_OPTS *opts, unsigned flags )
        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);
 }
@@ -402,187 +657,96 @@ static void
 show_version()
 {
     const char *s;
-    printf("%s version %s (%s", strusage(13), strusage(14), strusage(45) );
-    if( (s = strusage(24)) && *s ) {
-      #ifdef DEBUG
-       printf(", %s, dbg)\n", s);
-      #else
-       printf(", %s)\n", s);
-      #endif
-    }
-    else {
-      #ifdef DEBUG
-       printf(", dbg)\n");
-      #else
-       printf(")\n");
-      #endif
-    }
+    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(s, stdout);
     fflush(stdout);
-    exit(0);
 }
 
 
-
 void
 usage( int level )
 {
-    static int sentinel=0;
-
-    if( sentinel )
-       return;
-
-    sentinel++;
     if( !level ) {
-       fputs( strusage(level), stderr ); putc( '\n', stderr );
-       fputs( strusage(31), stderr);
-      #if DEBUG
-       fprintf(stderr, "%s (%s - Debug)\n", strusage(32), strusage(24) );
-      #else
-       fprintf(stderr, "%s (%s)\n", strusage(32), strusage(24) );
-      #endif
+       fprintf(stderr,"%s %s; %s\n", strusage(11), strusage(13),
+                                                    strusage(14) );
        fflush(stderr);
     }
     else if( level == 1 ) {
-       fputs(strusage(level),stderr);putc('\n',stderr);
-       exit(2);}
+       fputs(strusage(40),stderr);
+       exit(2);
+    }
     else if( level == 2 ) {
-       puts(strusage(level)); exit(0);}
-    sentinel--;
+       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 *
 default_strusage( int level )
 {
-    const char *p;
+    const char *p = NULL;
     switch( level ) {
-      case  0: p = strusage(10); break;
-      case  1: p = strusage(11); break;
-      case  2: p = strusage(12); break;
-      case 10: p = "WkLib"
-                 #if DOS386 && __WATCOMC__
-                   " (DOS4G)"
-                 #elif DOS386
-                   " (DOSX)"
-                 #elif DOS16RM
-                   " (DOS16RM)"
-                 #elif M_I86VM
-                   " (VCM)"
-                 #elif UNIX || POSIX
-                   " (Posix)"
-                 #elif OS2
-                   " (OS/2)"
-                 #elif WINNT && __CYGWIN32__
-                   " (CygWin)"
-                 #elif WINNT
-                   " (WinNT)"
-                 #elif NETWARE
-                   " (Netware)"
-                 #elif VMS
-                   " (VMS)"
-                 #endif
-                   "; Copyright (c) 1997 by Werner Koch (dd9jn)" ; break;
-      case 11: p = "usage: ?"; break;
-      case 16:
-      case 15: p = "[Untitled]"; break;
-      case 23: p = "[unknown]"; break;
-      case 24: p = ""; break;
-      case 12: p =
-   "This is free software; you can redistribute it and/or modify\n"
-   "it under the terms of the GNU General Public License as published by\n"
-   "the Free Software Foundation; either version 2 of the License, or\n"
-   "(at your option) any later version.\n\n"
-   "WkLib is distributed in the hope that it will be useful,\n"
-   "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-   "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
-   "GNU General Public License for more details.\n\n"
-   "You should have received a copy of the GNU General Public License\n"
-   "along with this program; if not, write to the Free Software\n"
-   "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,"
-                                                                 " USA.\n" ;
+      case 11: p = "foo"; break;
+      case 13: p = "0.0"; break;
+      case 14: p = "Copyright (C) 1998 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 22:
-         #if MSDOS
-           #if USE_EMS
-             p = "MSDOS+EMS";
-           #else
-             p = "MSDOS";
-           #endif
-         #elif OS2
-           p = "OS/2";
-         #elif WINNT && __CYGWIN32__
-           p = "CygWin";
-         #elif WINNT
-           p = "WinNT";
-         #elif DOS386
-           p = "DOS386";
-         #elif EMX
-           p = "EMX";
-         #elif DOS16RM
-           p = "DOS16RM";
-         #elif NETWARE
-           p = "Netware";
-         #elif __linux__
-           p = "Linux";
-         #elif UNIX || M_UNIX || M_XENIX
-           p = "UNIX";
-         #elif VMS
-           p = "VMS";
-         #else
-           p = "UnknownOS";
-         #endif
-           break;
-      case 31: p =
-    "This program comes with ABSOLUTELY NO WARRANTY.\n"
-    "This is free software, and you are welcome to redistribute it\n"
-    "under certain conditions. See the file COPYING for details.\n";
-           break;
-      case 32: p = "["
-         #if MSDOS
-             "MSDOS Version"
-         #elif DOS386 && __ZTC__
-           "32-Bit MSDOS Version (Zortech's DOSX)"
-         #elif DOS386
-           "32-Bit MSDOS Version"
-         #elif OS20 && EMX
-           "OS/2 2.x EMX Version"
-         #elif OS20
-           "OS/2 2.x Version"
-         #elif OS2
-           "OS/2 1.x Version"
-         #elif WINNT && __CYGWIN32__
-           "Cygnus WinAPI Version"
-         #elif WINNT
-           "Windoze NT Version"
-         #elif EMX
-           "EMX Version"
-         #elif NETWARE
-           "NLM Version"
-         #elif DOS16RM
-           "DOS16RM Version"
-         #elif __linux__
-           "Linux Version"
-         #elif VMS
-           "OpenVMS Version"
-         #elif POSIX
-           "POSIX Version"
-         #elif M_UNIX || M_XENIX
-           "*IX Version"
-         #endif
-           "]";
-           break;
-      case 33: p =
-         #ifdef MULTI_THREADED
-           "mt"
-         #else
-           ""
-         #endif
-           ; break;
-      case 42:
-      case 43:
-      case 44:
-      case 45: p = ""; break;
-      default: p = "?";
+      case 40: /* short and long usage */
+      case 41: p = ""; break;
     }
 
     return p;