diff options
Diffstat (limited to 'src/internal/argv')
-rw-r--r-- | src/internal/argv/argv.h | 942 |
1 files changed, 0 insertions, 942 deletions
diff --git a/src/internal/argv/argv.h b/src/internal/argv/argv.h deleted file mode 100644 index a730e76..0000000 --- a/src/internal/argv/argv.h +++ /dev/null @@ -1,942 +0,0 @@ -/****************************************************************************/ -/* argv.h: a thread-safe argument vector parser and usage screen generator */ -/* Copyright (C) 2015--2018 Z. Gilboa */ -/* Released under the Standard MIT License; see COPYING.SOFORT. */ -/* This file is (also) part of sofort: portable software project template. */ -/****************************************************************************/ - -#ifndef ARGV_H -#define ARGV_H - -#include <stdbool.h> -#include <stdint.h> -#include <stddef.h> -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> - -#define ARGV_VERBOSITY_NONE 0x00 -#define ARGV_VERBOSITY_ERRORS 0x01 -#define ARGV_VERBOSITY_STATUS 0x02 -#define ARGV_CLONE_VECTOR 0x80 - -#ifndef ARGV_TAB_WIDTH -#define ARGV_TAB_WIDTH 8 -#endif - -/*******************************************/ -/* */ -/* support of hybrid options */ -/* ------------------------- */ -/* hybrid options are very similar to */ -/* long options, yet are prefixed by */ -/* a single dash rather than two */ -/* (i.e. -std, -isystem). */ -/* hybrid options are supported by this */ -/* driver for compatibility with legacy */ -/* tools; note, however, that the use */ -/* of hybrid options should be strongly */ -/* discouraged due to the limitations */ -/* they impose on short options (for */ -/* example, a driver implementing -std */ -/* may not provide -s as a short option */ -/* that takes an arbitrary value). */ -/* */ -/* SPACE: -hybrid VALUE (i.e. -MF file) */ -/* EQUAL: -hybrid=VALUE (i.e. -std=c99) */ -/* COMMA: -hybrid,VALUE (i.e. -Wl,<arg>) */ -/* ONLY: -opt accepted, --opt rejected */ -/* JOINED: -optVALUE */ -/* */ -/*******************************************/ - - -#define ARGV_OPTION_HYBRID_NONE 0x00 -#define ARGV_OPTION_HYBRID_ONLY 0x01 -#define ARGV_OPTION_HYBRID_SPACE 0x02 -#define ARGV_OPTION_HYBRID_EQUAL 0x04 -#define ARGV_OPTION_HYBRID_COMMA 0x08 -#define ARGV_OPTION_HYBRID_JOINED 0x10 -#define ARGV_OPTION_HYBRID_CIRCUS (ARGV_OPTION_HYBRID_SPACE \ - | ARGV_OPTION_HYBRID_JOINED) -#define ARGV_OPTION_HYBRID_DUAL (ARGV_OPTION_HYBRID_SPACE \ - | ARGV_OPTION_HYBRID_EQUAL) -#define ARGV_OPTION_HYBRID_SWITCH (ARGV_OPTION_HYBRID_ONLY \ - | ARGV_OPTION_HYBRID_SPACE \ - | ARGV_OPTION_HYBRID_EQUAL \ - | ARGV_OPTION_HYBRID_COMMA \ - | ARGV_OPTION_HYBRID_JOINED) - -enum argv_optarg { - ARGV_OPTARG_NONE, - ARGV_OPTARG_REQUIRED, - ARGV_OPTARG_OPTIONAL, -}; - -enum argv_mode { - ARGV_MODE_SCAN, - ARGV_MODE_COPY, -}; - -enum argv_error { - ARGV_ERROR_OK, - ARGV_ERROR_INTERNAL, - ARGV_ERROR_SHORT_OPTION, - ARGV_ERROR_LONG_OPTION, - ARGV_ERROR_OPTARG_NONE, - ARGV_ERROR_OPTARG_REQUIRED, - ARGV_ERROR_OPTARG_PARADIGM, - ARGV_ERROR_HYBRID_NONE, - ARGV_ERROR_HYBRID_ONLY, - ARGV_ERROR_HYBRID_SPACE, - ARGV_ERROR_HYBRID_EQUAL, - ARGV_ERROR_HYBRID_COMMA, -}; - -struct argv_option { - const char * long_name; - const char short_name; - int tag; - enum argv_optarg optarg; - int flags; - const char * paradigm; - const char * argname; - const char * description; -}; - -struct argv_entry { - const char * arg; - int tag; - bool fopt; - bool fval; - bool fnoscan; - enum argv_error errcode; -}; - -struct argv_meta { - char ** argv; - struct argv_entry * entries; -}; - -struct argv_ctx { - int flags; - int mode; - int nentries; - intptr_t unitidx; - intptr_t erridx; - enum argv_error errcode; - const char * errch; - const struct argv_option * erropt; - const char * program; -}; - -#ifdef ARGV_DRIVER - -struct argv_meta_impl { - char ** argv; - char * strbuf; - struct argv_meta meta; -}; - -static int argv_optv_init( - const struct argv_option[], - const struct argv_option **); - -static const char * argv_program_name(const char *); - -static void argv_usage( - int fd, - const char * header, - const struct argv_option **, - const char * mode); - -static struct argv_meta * argv_get( - char **, - const struct argv_option **, - int flags, - int fd); - -static void argv_free(struct argv_meta *); - -#ifndef argv_dprintf -#define argv_dprintf dprintf -#endif - - - -/*------------------------------------*/ -/* implementation of static functions */ -/*------------------------------------*/ - -static int argv_optv_init( - const struct argv_option options[], - const struct argv_option ** optv) -{ - const struct argv_option * option; - int i; - - for (option=options,i=0; option->long_name || option->short_name; option++) - optv[i++] = option; - - optv[i] = 0; - return i; -} - -static const struct argv_option * argv_short_option( - const char * ch, - const struct argv_option ** optv, - struct argv_entry * entry) -{ - const struct argv_option * option; - - for (; *optv; optv++) { - option = *optv; - - if (option->short_name == *ch) { - entry->tag = option->tag; - entry->fopt = true; - return option; - } - } - - return 0; -} - -static const struct argv_option * argv_long_option( - const char * ch, - const struct argv_option ** optv, - struct argv_entry * entry) -{ - const struct argv_option * option; - const char * arg; - size_t len; - - for (; *optv; optv++) { - option = *optv; - len = option->long_name ? strlen(option->long_name) : 0; - - if (len && !(strncmp(option->long_name,ch,len))) { - arg = ch + len; - - if (!*arg - || (*arg == '=') - || (option->flags & ARGV_OPTION_HYBRID_JOINED) - || ((option->flags & ARGV_OPTION_HYBRID_COMMA) - && (*arg == ','))) { - entry->tag = option->tag; - entry->fopt = true; - return option; - } - } - } - - return 0; -} - -static inline bool is_short_option(const char * arg) -{ - return (arg[0]=='-') && arg[1] && (arg[1]!='-'); -} - -static inline bool is_long_option(const char * arg) -{ - return (arg[0]=='-') && (arg[1]=='-') && arg[2]; -} - -static inline bool is_last_option(const char * arg) -{ - return (arg[0]=='-') && (arg[1]=='-') && !arg[2]; -} - -static inline bool is_hybrid_option( - const char * arg, - const struct argv_option ** optv) -{ - const struct argv_option * option; - struct argv_entry entry; - - if (!is_short_option(arg)) - return false; - - if (!(option = argv_long_option(++arg,optv,&entry))) - return false; - - if (!(option->flags & ARGV_OPTION_HYBRID_SWITCH)) - if (argv_short_option(arg,optv,&entry)) - return false; - - return true; -} - -static inline bool is_arg_in_paradigm(const char * arg, const char * paradigm) -{ - size_t len; - const char * ch; - - for (ch=paradigm,len=strlen(arg); ch; ) { - if (!strncmp(arg,ch,len)) { - if (!*(ch += len)) - return true; - else if (*ch == '|') - return true; - } - - if ((ch = strchr(ch,'|'))) - ch++; - } - - return false; -} - -static inline const struct argv_option * option_from_tag( - const struct argv_option ** optv, - int tag) -{ - for (; *optv; optv++) - if (optv[0]->tag == tag) - return optv[0]; - return 0; -} - -static void argv_scan( - char ** argv, - const struct argv_option ** optv, - struct argv_ctx * ctx, - struct argv_meta * meta) -{ - char ** parg; - const char * ch; - const char * val; - const struct argv_option * option; - struct argv_entry entry; - struct argv_entry * mentry; - enum argv_error ferr; - bool fval; - bool fnext; - bool fshort; - bool fhybrid; - bool fnoscan; - - parg = &argv[1]; - ch = *parg; - ferr = ARGV_ERROR_OK; - fshort = false; - fnoscan = false; - fval = false; - mentry = meta ? meta->entries : 0; - - ctx->unitidx = 0; - ctx->erridx = 0; - - while (ch && (ferr == ARGV_ERROR_OK)) { - option = 0; - fhybrid = false; - - if (fnoscan) - fval = true; - - else if (is_last_option(ch)) - fnoscan = true; - - else if (!fshort && is_hybrid_option(ch,optv)) - fhybrid = true; - - if (!fnoscan && !fhybrid && (fshort || is_short_option(ch))) { - if (!fshort) - ch++; - - if ((option = argv_short_option(ch,optv,&entry))) { - if (ch[1]) { - ch++; - fnext = false; - fshort = (option->optarg == ARGV_OPTARG_NONE); - } else { - parg++; - ch = *parg; - fnext = true; - fshort = false; - } - - if (option->optarg == ARGV_OPTARG_NONE) { - if (!fnext && ch && (*ch == '-')) { - ferr = ARGV_ERROR_OPTARG_NONE; - } else { - fval = false; - } - - } else if (!fnext) { - fval = true; - - } else if (option->optarg == ARGV_OPTARG_REQUIRED) { - if (ch && is_short_option(ch)) - ferr = ARGV_ERROR_OPTARG_REQUIRED; - else if (ch && is_long_option(ch)) - ferr = ARGV_ERROR_OPTARG_REQUIRED; - else if (ch && is_last_option(ch)) - ferr = ARGV_ERROR_OPTARG_REQUIRED; - else if (ch) - fval = true; - else - ferr = ARGV_ERROR_OPTARG_REQUIRED; - } else { - /* ARGV_OPTARG_OPTIONAL */ - if (ch && is_short_option(ch)) - fval = false; - else if (ch && is_long_option(ch)) - fval = false; - else if (ch && is_last_option(ch)) - fval = false; - else if (fnext) - fval = false; - else - fval = ch; - } - } else { - ferr = ARGV_ERROR_SHORT_OPTION; - } - - } else if (!fnoscan && (fhybrid || is_long_option(ch))) { - ch += (fhybrid ? 1 : 2); - - if ((option = argv_long_option(ch,optv,&entry))) { - val = ch + strlen(option->long_name); - - /* val[0] is either '=' (or ',') or '\0' */ - if (!val[0]) { - parg++; - ch = *parg; - } - - if (fhybrid && !(option->flags & ARGV_OPTION_HYBRID_SWITCH)) - ferr = ARGV_ERROR_HYBRID_NONE; - else if (!fhybrid && (option->flags & ARGV_OPTION_HYBRID_ONLY)) - ferr = ARGV_ERROR_HYBRID_ONLY; - else if (option->optarg == ARGV_OPTARG_NONE) { - if (val[0]) { - ferr = ARGV_ERROR_OPTARG_NONE; - ctx->errch = val + 1; - } else - fval = false; - } else if (val[0] && (option->flags & ARGV_OPTION_HYBRID_JOINED)) { - fval = true; - ch = val; - } else if (fhybrid && !val[0] && !(option->flags & ARGV_OPTION_HYBRID_SPACE)) - ferr = ARGV_ERROR_HYBRID_SPACE; - else if (fhybrid && (val[0]=='=') && !(option->flags & ARGV_OPTION_HYBRID_EQUAL)) - ferr = ARGV_ERROR_HYBRID_EQUAL; - else if (fhybrid && (val[0]==',') && !(option->flags & ARGV_OPTION_HYBRID_COMMA)) - ferr = ARGV_ERROR_HYBRID_COMMA; - else if (!fhybrid && (val[0]==',')) - ferr = ARGV_ERROR_HYBRID_COMMA; - else if (val[0] && !val[1]) - ferr = ARGV_ERROR_OPTARG_REQUIRED; - else if (val[0] && val[1]) { - fval = true; - ch = ++val; - } else if (option->optarg == ARGV_OPTARG_REQUIRED) { - if (!val[0] && !*parg) - ferr = ARGV_ERROR_OPTARG_REQUIRED; - else if (*parg && is_short_option(*parg)) - ferr = ARGV_ERROR_OPTARG_REQUIRED; - else if (*parg && is_long_option(*parg)) - ferr = ARGV_ERROR_OPTARG_REQUIRED; - else if (*parg && is_last_option(*parg)) - ferr = ARGV_ERROR_OPTARG_REQUIRED; - else - fval = true; - } else { - /* ARGV_OPTARG_OPTIONAL */ - fval = val[0]; - } - } else - ferr = ARGV_ERROR_LONG_OPTION; - } - - if (ferr == ARGV_ERROR_OK) - if (option && fval && option->paradigm) - if (!is_arg_in_paradigm(ch,option->paradigm)) - ferr = ARGV_ERROR_OPTARG_PARADIGM; - - if (ferr == ARGV_ERROR_OK) - if (!option && !ctx->unitidx) - ctx->unitidx = parg - argv; - - if (ferr != ARGV_ERROR_OK) { - ctx->errcode = ferr; - ctx->errch = ctx->errch ? ctx->errch : ch; - ctx->erropt = option; - ctx->erridx = parg - argv; - return; - } else if (ctx->mode == ARGV_MODE_SCAN) { - if (!fnoscan) - ctx->nentries++; - else if (fval) - ctx->nentries++; - - if (fval || !option) { - parg++; - ch = *parg; - } - } else if (ctx->mode == ARGV_MODE_COPY) { - if (fnoscan) { - if (fval) { - mentry->arg = ch; - mentry->fnoscan = true; - mentry++; - } - - parg++; - ch = *parg; - } else if (option) { - mentry->arg = fval ? ch : 0; - mentry->tag = option->tag; - mentry->fopt = true; - mentry->fval = fval; - mentry++; - - if (fval) { - parg++; - ch = *parg; - } - } else { - mentry->arg = ch; - mentry++; - parg++; - ch = *parg; - } - } - } -} - -static const char * argv_program_name(const char * program_path) -{ - const char * ch; - - if (program_path) { - if ((ch = strrchr(program_path,'/'))) - return *(++ch) ? ch : 0; - - if ((ch = strrchr(program_path,'\\'))) - return *(++ch) ? ch : 0; - } - - return program_path; -} - -static void argv_show_error(int fd, struct argv_ctx * ctx) -{ - char opt_short_name[2] = {0,0}; - - if (ctx->erropt && ctx->erropt->short_name) - opt_short_name[0] = ctx->erropt->short_name; - - argv_dprintf(fd,"%s: error: ",ctx->program); - - switch (ctx->errcode) { - case ARGV_ERROR_SHORT_OPTION: - argv_dprintf(fd,"'-%c' is not a valid short option\n",*ctx->errch); - break; - - case ARGV_ERROR_LONG_OPTION: - argv_dprintf(fd,"'--%s' is not a valid long option\n",ctx->errch); - break; - - case ARGV_ERROR_OPTARG_NONE: - argv_dprintf(fd,"'%s' is not a valid option value for [%s%s%s%s%s] " - "(option values may not be specified)\n", - ctx->errch, - opt_short_name[0] ? "-" : "", - opt_short_name, - opt_short_name[0] ? "," : "", - ctx->erropt->long_name ? "--" : "", - ctx->erropt->long_name); - break; - - case ARGV_ERROR_OPTARG_REQUIRED: - argv_dprintf(fd,"option [%s%s%s%s%s] requires %s %s%s%s\n", - opt_short_name[0] ? "-" : "", - opt_short_name, - opt_short_name[0] ? "," : "", - ctx->erropt->long_name ? "--" : "", - ctx->erropt->long_name, - ctx->erropt->paradigm ? "one of the following values:" : "a value", - ctx->erropt->paradigm ? "{" : "", - ctx->erropt->paradigm ? ctx->erropt->paradigm : "", - ctx->erropt->paradigm ? "}" : ""); - break; - - case ARGV_ERROR_OPTARG_PARADIGM: - argv_dprintf(fd,"'%s' is not a valid option value for [%s%s%s%s%s]={%s}\n", - ctx->errch, - opt_short_name[0] ? "-" : "", - opt_short_name, - opt_short_name[0] ? "," : "", - ctx->erropt->long_name ? "--" : "", - ctx->erropt->long_name, - ctx->erropt->paradigm); - break; - - case ARGV_ERROR_HYBRID_NONE: - argv_dprintf(fd,"-%s is not a synonym for --%s\n", - ctx->erropt->long_name, - ctx->erropt->long_name); - break; - - case ARGV_ERROR_HYBRID_ONLY: - argv_dprintf(fd,"--%s is not a synonym for -%s\n", - ctx->erropt->long_name, - ctx->erropt->long_name); - break; - - case ARGV_ERROR_HYBRID_SPACE: - case ARGV_ERROR_HYBRID_EQUAL: - case ARGV_ERROR_HYBRID_COMMA: - argv_dprintf(fd,"-%s: illegal value assignment; valid syntax is " - "-%s%sVAL\n", - ctx->erropt->long_name, - ctx->erropt->long_name, - (ctx->erropt->flags & ARGV_OPTION_HYBRID_SPACE) - ? " " : (ctx->erropt->flags & ARGV_OPTION_HYBRID_EQUAL) - ? "=" : (ctx->erropt->flags & ARGV_OPTION_HYBRID_COMMA) - ? "," : ""); - - break; - - case ARGV_ERROR_INTERNAL: - argv_dprintf(fd,"internal error"); - break; - - default: - break; - } -} - -static void argv_show_status( - int fd, - const struct argv_option ** optv, - struct argv_ctx * ctx, - struct argv_meta * meta) -{ - int argc; - char ** argv; - struct argv_entry * entry; - const struct argv_option * option; - char short_name[2] = {0}; - const char * space = ""; - - (void)ctx; - - argv_dprintf(fd,"\n\nconcatenated command line:\n"); - for (argv=meta->argv; *argv; argv++) { - argv_dprintf(fd,"%s%s",space,*argv); - space = " "; - } - - argv_dprintf(fd,"\n\nargument vector:\n"); - for (argc=0,argv=meta->argv; *argv; argc++,argv++) - argv_dprintf(fd,"argv[%d]: %s\n",argc,*argv); - - argv_dprintf(fd,"\n\nparsed entries:\n"); - for (entry=meta->entries; entry->arg || entry->fopt; entry++) - if (entry->fopt) { - option = option_from_tag(optv,entry->tag); - short_name[0] = option->short_name; - - if (entry->fval) - argv_dprintf(fd,"[-%s,--%s] := %s\n", - short_name,option->long_name,entry->arg); - else - argv_dprintf(fd,"[-%s,--%s]\n", - short_name,option->long_name); - } else - argv_dprintf(fd,"<program arg> := %s\n",entry->arg); - - argv_dprintf(fd,"\n\n"); -} - -static struct argv_meta * argv_free_impl(struct argv_meta_impl * imeta) -{ - if (imeta->argv) - free(imeta->argv); - - if (imeta->strbuf) - free(imeta->strbuf); - - if (imeta->meta.entries) - free(imeta->meta.entries); - - free(imeta); - return 0; -} - -static struct argv_meta * argv_alloc(char ** argv, struct argv_ctx * ctx) -{ - struct argv_meta_impl * imeta; - char ** vector; - char * dst; - size_t size; - int argc; - int i; - - if (!(imeta = calloc(1,sizeof(*imeta)))) - return 0; - - if (ctx->flags & ARGV_CLONE_VECTOR) { - for (vector=argv,argc=0,size=0; *vector; vector++) { - size += strlen(*vector) + 1; - argc++; - } - - if (!(imeta->argv = calloc(argc+1,sizeof(char *)))) - return argv_free_impl(imeta); - else if (!(imeta->strbuf = calloc(1,size+1))) - return argv_free_impl(imeta); - - for (i=0,dst=imeta->strbuf; i<argc; i++) { - strcpy(dst,argv[i]); - imeta->argv[i] = dst; - dst += strlen(dst)+1; - } - - imeta->meta.argv = imeta->argv; - } else - imeta->meta.argv = argv; - - if (!(imeta->meta.entries = calloc( - ctx->nentries+1, - sizeof(struct argv_entry)))) - return argv_free_impl(imeta); - else - return &imeta->meta; -} - -static struct argv_meta * argv_get( - char ** argv, - const struct argv_option ** optv, - int flags, - int fd) -{ - struct argv_meta * meta; - struct argv_ctx ctx = {flags,ARGV_MODE_SCAN,0,0,0,0,0,0,0}; - - argv_scan(argv,optv,&ctx,0); - - if (ctx.errcode != ARGV_ERROR_OK) { - ctx.program = argv_program_name(argv[0]); - - if (ctx.flags & ARGV_VERBOSITY_ERRORS) - argv_show_error(fd,&ctx); - - return 0; - } - - if (!(meta = argv_alloc(argv,&ctx))) - return 0; - - ctx.mode = ARGV_MODE_COPY; - argv_scan(meta->argv,optv,&ctx,meta); - - if (ctx.errcode != ARGV_ERROR_OK) { - ctx.program = argv[0]; - ctx.errcode = ARGV_ERROR_INTERNAL; - argv_show_error(fd,&ctx); - argv_free(meta); - - return 0; - } - - if (ctx.flags & ARGV_VERBOSITY_STATUS) - argv_show_status(fd,optv,&ctx,meta); - - return meta; -} - -static void argv_free(struct argv_meta * xmeta) -{ - struct argv_meta_impl * imeta; - uintptr_t addr; - - if (xmeta) { - addr = (uintptr_t)xmeta - offsetof(struct argv_meta_impl,meta); - imeta = (struct argv_meta_impl *)addr; - argv_free_impl(imeta); - } -} - -static void argv_usage( - int fd, - const char * header, - const struct argv_option ** options, - const char * mode) -{ - const struct argv_option ** optv; - const struct argv_option * option; - bool fshort,flong,fboth; - size_t len,optlen,desclen; - char cache; - char * prefix; - char * desc; - char * mark; - char * cap; - char description[4096]; - char optstr [72]; - const size_t optcap = 64; - const size_t width = 80; - const char indent[] = " "; - const char creset[] = "\x1b[0m"; - const char cbold [] = "\x1b[1m"; - const char cgreen[] = "\x1b[32m"; - const char cblue [] = "\x1b[34m"; - const char ccyan [] = "\x1b[36m"; - const char * color = ccyan; - bool fcolor; - - fshort = mode ? !strcmp(mode,"short") : 0; - flong = fshort ? 0 : mode && !strcmp(mode,"long"); - fboth = !fshort && !flong; - fcolor = isatty(fd); - - if (fcolor) - argv_dprintf(fd,"%s%s",cbold,cgreen); - - if (header) - argv_dprintf(fd,"%s",header); - - for (optlen=0,optv=options; *optv; optv++) { - option = *optv; - - /* indent + comma */ - len = fboth ? sizeof(indent) + 1 : sizeof(indent); - - /* -o */ - if (fshort || fboth) - len += option->short_name - ? 2 : 0; - - /* --option */ - if (flong || fboth) - len += option->long_name - ? 2 + strlen(option->long_name) : 0; - - /* optlen */ - if (len > optlen) - optlen = len; - } - - if (optlen >= optcap) { - argv_dprintf(fd, - "Option strings exceed %zu characters, " - "please generate the usage screen manually.\n", - optcap); - return; - } - - optlen += ARGV_TAB_WIDTH; - optlen &= (~(ARGV_TAB_WIDTH-1)); - desclen = (optlen < width / 2) ? width - optlen : optlen; - - for (optv=options; *optv; optv++) { - option = *optv; - - /* color */ - if (fcolor) { - color = (color == ccyan) ? cblue : ccyan; - argv_dprintf(fd,color); - } - - /* description, using either paradigm or argname if applicable */ - snprintf(description,sizeof(description),option->description, - option->paradigm - ? option->paradigm - : option->argname ? option->argname : ""); - description[sizeof(description)-1] = 0; - - /* long/hybrid option prefix (-/--) */ - prefix = option->flags & ARGV_OPTION_HYBRID_ONLY - ? " -" : "--"; - - /* option string */ - if (fboth && option->short_name && option->long_name) - sprintf(optstr,"%s-%c,%s%s", - indent,option->short_name,prefix,option->long_name); - - else if ((fshort || fboth) && option->short_name) - sprintf(optstr,"%s-%c",indent,option->short_name); - - else if (flong && option->long_name) - sprintf(optstr,"%s%s%s", - indent,prefix,option->long_name); - - else if (fboth && option->long_name) - sprintf(optstr,"%s %s%s", - indent,prefix,option->long_name); - - else - optstr[0] = 0; - - /* right-indented option buffer */ - if (description[0]) { - len = strlen(optstr); - sprintf(&optstr[len],"%-*c",(int)(optlen-len),' '); - } - - /* single line? */ - if (optlen + strlen(description) < width) { - argv_dprintf(fd,"%s%s\n",optstr,description); - - } else { - desc = description; - cap = desc + strlen(description); - - while (desc < cap) { - mark = (desc + desclen >= cap) - ? cap : desc + desclen; - - while (*mark && (mark > desc) - && (*mark != ' ') - && (*mark != '|') - && (*mark != '\t') - && (*mark != '\n')) - mark--; - - if (mark == desc) { - mark = (desc + desclen >= cap) - ? cap : desc + desclen; - cache = *mark; - *mark = 0; - } else if (*mark == '|') { - cache = *mark; - *mark = 0; - } else { - cache = 0; - *mark = 0; - } - - /* first line? */ - if (desc == description) - argv_dprintf(fd,"%s%s\n",optstr,desc); - else - argv_dprintf(fd,"%-*c %s\n", - (*desc == '|') - ? (int)(optlen+1) - : (int)optlen, - ' ',desc); - - if (cache) - *mark = cache; - else - mark++; - - desc = mark; - } - } - } - - if (fcolor) - argv_dprintf(fd,creset); -} - -#endif - -#endif |