File indexing completed on 2024-04-28 11:21:08

0001 /*
0002  * gehopt;  options processing with both single-character and whole-word
0003  *           options both introduced with -
0004  */
0005 
0006 #include <stdio.h>
0007 #include <string.h>
0008 
0009 #include "gethopt.h"
0010 
0011 
0012 void
0013 hoptset(ctx, argc, argv)
0014 struct h_context *ctx;
0015 int argc;
0016 char **argv;
0017 {
0018     memset(ctx, 0, sizeof *ctx);
0019     ctx->argc = argc;
0020     ctx->argv = argv;
0021     ctx->optind = 1;
0022 }
0023 
0024 
0025 char *
0026 hoptarg(ctx)
0027 struct h_context *ctx;
0028 {
0029     return ctx->optarg;
0030 }
0031 
0032 int
0033 hoptind(ctx)
0034 struct h_context *ctx;
0035 {
0036     return ctx->optind;
0037 }
0038 
0039 char
0040 hoptopt(ctx)
0041 struct h_context *ctx;
0042 {
0043     return ctx->optopt;
0044 }
0045 
0046 
0047 int
0048 hopterr(ctx,val)
0049 struct h_context *ctx;
0050 {
0051     int old = ctx->opterr;
0052     
0053     ctx->opterr = !!val;
0054     return old;
0055 }
0056 
0057 
0058 struct h_opt *
0059 gethopt(ctx, opts, nropts)
0060 struct h_context *ctx;
0061 struct h_opt *opts;
0062 int nropts;
0063 {
0064     int i;
0065     int dashes;
0066     
0067 
0068     if ( (ctx == 0) || ctx->optend || (ctx->optind >= ctx->argc) )
0069     return 0;
0070     
0071     ctx->optarg = 0;
0072     ctx->optopt = 0;
0073     
0074     if ( ctx->optchar == 0) {
0075     /* check for leading -
0076      */
0077     if ( ctx->argv[ctx->optind][0] != '-' ) {
0078         /* out of arguments */
0079         ctx->optend = 1;
0080         return 0;
0081     }
0082 
0083     if ( ctx->argv[ctx->optind][1] == 0
0084       || strcmp(ctx->argv[ctx->optind], "--") == 0 ) {
0085         /* option list finishes with - or -- token
0086          */
0087         ctx->optend = 1;
0088         ctx->optind++;
0089         return 0;
0090     }
0091 
0092     dashes = 1;
0093     if ( ctx->argv[ctx->optind][dashes] == '-' ) {
0094         /* support GNU-style long option double-dash prefix
0095          * (if gethopt is passed an unknown option with a double-dash
0096          *  prefix, it won't match a word and then the second dash
0097          *  will be scanned as if it was a regular old single-character
0098          *  option.)
0099          */
0100         dashes = 2;
0101     }
0102     
0103     for ( i=0; i < nropts; i++ ) {
0104         if ( ! opts[i].optword ) 
0105         continue;
0106 
0107         if (strcmp(opts[i].optword, dashes+(ctx->argv[ctx->optind]) ) == 0 ) {
0108         if ( opts[i].opthasarg ) {
0109             if ( ctx->argc > ctx->optind ) {
0110             ctx->optarg = ctx->argv[ctx->optind+1];
0111             ctx->optind += 2;
0112             }
0113             else {
0114             /* word argument with required arg at end of
0115              *command line
0116              */
0117             if ( ctx->opterr )
0118                 fprintf(stderr,
0119                     "%s: option requires an argument -- %s\n",
0120                     ctx->argv[0], opts[i].optword);
0121             ctx->optind ++;
0122             return HOPTERR;
0123             }
0124         }
0125         else {
0126             ctx->optind ++;
0127         }
0128         return &opts[i];
0129         }
0130     }
0131     ctx->optchar = 1;
0132     }
0133 
0134     ctx->optopt = ctx->argv[ctx->optind][ctx->optchar++];
0135 
0136     if ( !ctx->optopt ) {
0137     /* fell off the end of this argument */
0138     ctx->optind ++;
0139     ctx->optchar = 0;
0140     return gethopt(ctx, opts, nropts);
0141     }
0142 
0143     for ( i=0; i<nropts; i++ ) {
0144     if ( opts[i].optchar == ctx->optopt ) {
0145         /* found a single-char option!
0146          */
0147         if ( opts[i].opthasarg ) {
0148         if ( ctx->argv[ctx->optind][ctx->optchar] ) {
0149             /* argument immediately follows this options (-Oc)
0150              */
0151             ctx->optarg = &ctx->argv[ctx->optind][ctx->optchar];
0152             ctx->optind ++;
0153             ctx->optchar = 0;
0154         }
0155         else if ( ctx->optind < ctx->argc-1 ) {
0156             /* argument is next arg (-O c)
0157              */
0158             ctx->optarg = &ctx->argv[ctx->optind+1][0];
0159             ctx->optind += 2;
0160             ctx->optchar = 0;
0161         }
0162         else {
0163             /* end of arg string (-O); set optarg to null, return
0164              * (should it opterr on me?)
0165              */
0166             ctx->optarg = 0;
0167             ctx->optind ++;
0168             ctx->optchar = 0;
0169             if ( ctx->opterr )
0170             fprintf(stderr,
0171                 "%s: option requires an argument -- %c\n",
0172                 ctx->argv[0], opts[i].optchar);
0173             return HOPTERR;
0174         }
0175         }
0176         else {
0177         if ( !ctx->argv[ctx->optind][ctx->optchar] ) {
0178             ctx->optind ++;
0179             ctx->optchar = 0;
0180         }
0181         }
0182         return &opts[i];
0183     }
0184     }
0185     if ( ctx->opterr )
0186     fprintf(stderr, "%s: illegal option -- %c\n", ctx->argv[0], ctx->optopt);
0187     return HOPTERR;
0188 }
0189 
0190 
0191 void
0192 hoptusage(char *pgm, struct h_opt opts[], int nropts, char *arguments)
0193 {
0194     int i;
0195     int optcount;
0196     
0197     fprintf(stderr, "usage: %s", pgm);
0198 
0199     /* print out the options that don't have flags first */
0200     
0201     for ( optcount=i=0; i < nropts; i++ ) {
0202     if ( opts[i].optchar && !opts[i].opthasarg) {
0203         if (optcount == 0 )
0204         fputs(" [-", stderr);
0205         fputc(opts[i].optchar, stderr);
0206         optcount++;
0207     }
0208     }
0209     if ( optcount )
0210     fputc(']', stderr);
0211 
0212     /* print out the options WITH flags */
0213     for ( i = 0; i < nropts; i++ )
0214     if ( opts[i].optchar && opts[i].opthasarg)
0215         fprintf(stderr, " [-%c %s]", opts[i].optchar, opts[i].opthasarg);
0216 
0217     /* print out the long options */
0218     for ( i = 0; i < nropts; i++ )
0219     if ( opts[i].optword ) {
0220         fprintf(stderr, " [-%s", opts[i].optword);
0221         if ( opts[i].opthasarg )
0222         fprintf(stderr, " %s", opts[i].opthasarg);
0223         fputc(']', stderr);
0224     }
0225 
0226     /* print out the arguments string, if any */
0227 
0228     if ( arguments )
0229     fprintf(stderr, " %s", arguments);
0230 
0231     /* and we're done */
0232     fputc('\n', stderr);
0233 }
0234 
0235 
0236 #if DEBUG
0237 struct h_opt opts[] = {
0238     { 0, "css",    0,  1, "css file" },
0239     { 1, "header", 0,  1, "header file" },
0240     { 2, 0,       'a', 0, "option a (no arg)" },
0241     { 3, 0,       'b', 1, "option B (with arg)" },
0242     { 4, "help",  '?', 0, "help message" },
0243 } ;
0244 
0245 #define NROPT (sizeof opts/sizeof opts[0])
0246 
0247 
0248 int
0249 main(argc, argv)
0250 char **argv;
0251 {
0252     struct h_opt *ret;
0253     struct h_context ctx;
0254     int i;
0255 
0256 
0257     hoptset(&ctx, argc, argv);
0258     hopterr(&ctx, 1);
0259 
0260     while (( ret = gethopt(&ctx, opts, NROPT) )) {
0261 
0262     if ( ret != HOPTERR ) {
0263         if ( ret->optword )
0264         printf("%s", ret->optword);
0265         else
0266         printf("%c", ret->optchar);
0267 
0268         if ( ret->opthasarg ) {
0269         if ( hoptarg(&ctx) )
0270             printf(" with argument \"%s\"", hoptarg(&ctx));
0271         else
0272             printf(" with no argument?");
0273         }
0274         printf(" (%s)\n", ret->optdesc);
0275     }
0276     }
0277 
0278     argc -= hoptind(&ctx);
0279     argv += hoptind(&ctx);
0280 
0281     for ( i=0; i < argc; i++ )
0282     printf("%d: %s\n", i, argv[i]);
0283     return 0;
0284 }
0285 
0286 #endif /*DEBUG*/