diff --git a/src/options.c b/src/options.c index fce046b..56a2794 100644 --- a/src/options.c +++ b/src/options.c @@ -76,7 +76,85 @@ struct ScrotOptions opt = { .lineColor = "gray", }; +enum { /* long opt only */ + /* ensure these don't collude with single byte opts. */ + OPT_FORMAT = UCHAR_MAX + 1, + OPT_LIST_OPTS, +}; +static const char stropts[] = "a:bC:cD:d:e:F:fhik::l:M:mn:opq:S:s::t:uvw:Z:z"; +// NOTE: make sure lopts and opt_description indexes are kept in sync +static const struct option lopts[] = { + {"autoselect", required_argument, NULL, 'a'}, + {"border", no_argument, NULL, 'b'}, + {"class", required_argument, NULL, 'C'}, + {"count", no_argument, NULL, 'c'}, + {"display", required_argument, NULL, 'D'}, + {"delay", required_argument, NULL, 'd'}, + {"exec", required_argument, NULL, 'e'}, + {"file", required_argument, NULL, 'F'}, + {"freeze", no_argument, NULL, 'f'}, + {"help", no_argument, NULL, 'h'}, + {"ignorekeyboard", no_argument, NULL, 'i'}, + {"stack", optional_argument, NULL, 'k'}, + {"line", required_argument, NULL, 'l'}, + {"monitor", required_argument, NULL, 'M'}, + {"multidisp", no_argument, NULL, 'm'}, + {"note", required_argument, NULL, 'n'}, + {"overwrite", no_argument, NULL, 'o'}, + {"pointer", no_argument, NULL, 'p'}, + {"quality", required_argument, NULL, 'q'}, + {"script", required_argument, NULL, 'S'}, + {"select", optional_argument, NULL, 's'}, + {"thumb", required_argument, NULL, 't'}, + {"focused", no_argument, NULL, 'u'}, + /* macquarie dictionary has both spellings */ + {"focussed", no_argument, NULL, 'u'}, + {"version", no_argument, NULL, 'v'}, + {"window", required_argument, NULL, 'w'}, + {"compression", required_argument, NULL, 'Z'}, + {"silent", no_argument, NULL, 'z'}, + {"format", required_argument, NULL, OPT_FORMAT}, + {"list-options", optional_argument, NULL, OPT_LIST_OPTS}, + {0} +}; +static const char OPT_DEPRECATED[] = ""; +static const struct option_desc { + const char *description, *arg_description; +} opt_description[] = { + /* a */ { "autoselect provided region", "x,y,w,h" }, + /* b */ { "capture the window borders as well", "" }, + /* C */ { "capture specified window class", "NAME" }, + /* c */ { "display a countdown for delay", "" }, + /* D */ { "capture specified display", "DISPLAY" }, + /* d */ { "add delay before screenshot", "[b]SEC" }, + /* e */ { "execute command on saved image", "CMD" }, + /* F */ { "specify output file", "FILE" }, + /* f */ { "freeze the screen when -s is used", "" }, + /* h */ { "display help and exit", "" }, + /* i */ { "ignore keyboard", "" }, + /* k */ { "capture overlapped window and join them", "v|h" }, + /* l */ { "specify the style of the selection line", "STYLE" }, + /* M */ { "capture monitor", "NUM" }, + /* m */ { "capture all monitors", "" }, + /* n */ { OPT_DEPRECATED, OPT_DEPRECATED }, + /* o */ { "overwrite the output file if needed", "" }, + /* p */ { "capture the mouse pointer as well", "" }, + /* q */ { "image quality", "NUM" }, + /* S */ { OPT_DEPRECATED, OPT_DEPRECATED }, + /* s */ { "interactively select a region to capture", "OPTS" }, + /* t */ { "also generate a thumbnail", "% | WxH" }, + /* u */ { "capture the currently focused window", "" }, + /* u */ { "capture the currently focused window", "" }, + /* v */ { "output version and exit", "" }, + /* w */ { "X window ID to capture", "WID" }, + /* Z */ { "image compression level", "LVL" }, + /* z */ { "prevent beeping", "" }, + /* OPT_FORMAT */ { "specify output file format", "FMT" }, + /* OPT_LIST_OPTS */ { "list all options", "human|tsv" }, +}; + static void showUsage(void); +static void showOptions(bool human); static void showVersion(void); static long long optionsParseNumBase(const char *, long long, long long, const char *[static 1], int); @@ -302,82 +380,6 @@ static const char *getPathOfStdout(void) void optionsParse(int argc, char *argv[]) { - enum { /* long opt only */ - /* ensure these don't collude with single byte opts. */ - OPT_FORMAT = UCHAR_MAX + 1, - OPT_LIST_OPTS, - }; - static const char stropts[] = "a:bC:cD:d:e:F:fhik::l:M:mn:opq:S:s::t:uvw:Z:z"; - // NOTE: make sure lopts and opt_description indexes are kept in sync - static const struct option lopts[] = { - {"autoselect", required_argument, NULL, 'a'}, - {"border", no_argument, NULL, 'b'}, - {"class", required_argument, NULL, 'C'}, - {"count", no_argument, NULL, 'c'}, - {"display", required_argument, NULL, 'D'}, - {"delay", required_argument, NULL, 'd'}, - {"exec", required_argument, NULL, 'e'}, - {"file", required_argument, NULL, 'F'}, - {"freeze", no_argument, NULL, 'f'}, - {"help", no_argument, NULL, 'h'}, - {"ignorekeyboard", no_argument, NULL, 'i'}, - {"stack", optional_argument, NULL, 'k'}, - {"line", required_argument, NULL, 'l'}, - {"monitor", required_argument, NULL, 'M'}, - {"multidisp", no_argument, NULL, 'm'}, - {"note", required_argument, NULL, 'n'}, - {"overwrite", no_argument, NULL, 'o'}, - {"pointer", no_argument, NULL, 'p'}, - {"quality", required_argument, NULL, 'q'}, - {"script", required_argument, NULL, 'S'}, - {"select", optional_argument, NULL, 's'}, - {"thumb", required_argument, NULL, 't'}, - {"focused", no_argument, NULL, 'u'}, - /* macquarie dictionary has both spellings */ - {"focussed", no_argument, NULL, 'u'}, - {"version", no_argument, NULL, 'v'}, - {"window", required_argument, NULL, 'w'}, - {"compression", required_argument, NULL, 'Z'}, - {"silent", no_argument, NULL, 'z'}, - {"format", required_argument, NULL, OPT_FORMAT}, - {"list-options", optional_argument, NULL, OPT_LIST_OPTS}, - {0} - }; - static const char OPT_DEPRECATED[] = ""; - static const struct option_desc { - const char *description, *arg_description; - } opt_description[] = { - /* a */ { "autoselect provided region", "x,y,w,h" }, - /* b */ { "capture the window borders as well", "" }, - /* C */ { "capture specified window class", "NAME" }, - /* c */ { "display a countdown for delay", "" }, - /* D */ { "capture specified display", "DISPLAY" }, - /* d */ { "add delay before screenshot", "[b]SEC" }, - /* e */ { "execute command on saved image", "CMD" }, - /* F */ { "specify output file", "FILE" }, - /* f */ { "freeze the screen when -s is used", "" }, - /* h */ { "display help and exit", "" }, - /* i */ { "ignore keyboard", "" }, - /* k */ { "capture overlapped window and join them", "v|h" }, - /* l */ { "specify the style of the selection line", "STYLE" }, - /* M */ { "capture monitor", "NUM" }, - /* m */ { "capture all monitors", "" }, - /* n */ { OPT_DEPRECATED, OPT_DEPRECATED }, - /* o */ { "overwrite the output file if needed", "" }, - /* p */ { "capture the mouse pointer as well", "" }, - /* q */ { "image quality", "NUM" }, - /* S */ { OPT_DEPRECATED, OPT_DEPRECATED }, - /* s */ { "interactively select a region to capture", "OPTS" }, - /* t */ { "also generate a thumbnail", "% | WxH" }, - /* u */ { "capture the currently focused window", "" }, - /* u */ { "capture the currently focused window", "" }, - /* v */ { "output version and exit", "" }, - /* w */ { "X window ID to capture", "WID" }, - /* Z */ { "image compression level", "LVL" }, - /* z */ { "prevent beeping", "" }, - /* OPT_FORMAT */ { "specify output file format", "FMT" }, - /* OPT_LIST_OPTS */ { "list all options", "human|tsv" }, - }; int optch; const char *errmsg; bool FFlagSet = false; @@ -502,11 +504,11 @@ void optionsParse(int argc, char *argv[]) case OPT_FORMAT: opt.format = optarg; break; - case OPT_LIST_OPTS: { - bool tsv = false; + case OPT_LIST_OPTS: + bool human = true; if (optarg != NULL) { if (strcmp(optarg, "tsv") == 0) { - tsv = true; + human = false; } else if (strcmp(optarg, "human") == 0) { // no-op } else { @@ -514,39 +516,8 @@ void optionsParse(int argc, char *argv[]) "unknown argument for --list-options: `%s`", optarg); } } - - for (size_t i = 0; i < ARRAY_COUNT(opt_description); ++i) { - const struct option *o = &lopts[i]; - const struct option_desc *d = &opt_description[i]; - if (d->description == OPT_DEPRECATED) - continue; - - if (!tsv) { - int n = 0; - if (o->val <= UCHAR_MAX) - n += printf("-%c, ", o->val); - n += printf("--%s", o->name); - if (o->has_arg == required_argument) - n += printf(" <%s>", d->arg_description); - else if (o->has_arg == optional_argument) - n += printf("[=%s]", d->arg_description); - for (; n >= 0 && n < 32; ++n) - putchar(' '); - printf("%s\n", d->description); - } else { - printf("%c\t", o->val <= UCHAR_MAX ? o->val : ' '); - printf("%s\t", o->name); - if (o->has_arg == required_argument) - printf("R:%s\t", d->arg_description); - else if (o->has_arg == optional_argument) - printf("O:%s\t", d->arg_description); - else - printf("N:\t"); - printf("%s\n", d->description); - } - } - exit(EXIT_SUCCESS); - } break; + showOptions(human); + break; default: exit(EXIT_FAILURE); } @@ -592,14 +563,48 @@ void optionsParse(int argc, char *argv[]) static void showUsage(void) { - fputs("usage: " /* Check that everything lines up after any changes. */ - PACKAGE_NAME " [-bcfhimopuvz] [-a X,Y,W,H] [-C NAME] [-D DISPLAY]\n" - " [-d SEC] [-e CMD] [-k OPT] [-l STYLE] [-M NUM] [-q NUM]\n" - " [-s OPTS] [-t % | WxH] [[-F] FILE]\n", - stdout); + fputs("Usage: " PACKAGE_NAME " [OPTIONS...] [FILE]\n\n" + "OPTIONS\n" + "=======\n", stdout); + showOptions(true); exit(0); } +static void showOptions(bool human) +{ + for (size_t i = 0; i < ARRAY_COUNT(opt_description); ++i) { + const struct option *o = &lopts[i]; + const struct option_desc *d = &opt_description[i]; + if (d->description == OPT_DEPRECATED) + continue; + + if (human) { + int n = 0; + if (o->val <= UCHAR_MAX) + n += printf("-%c, ", o->val); + n += printf("--%s", o->name); + if (o->has_arg == required_argument) + n += printf(" <%s>", d->arg_description); + else if (o->has_arg == optional_argument) + n += printf("[=%s]", d->arg_description); + for (; n >= 0 && n < 32; ++n) + putchar(' '); + printf("%s\n", d->description); + } else { + printf("%c\t", o->val <= UCHAR_MAX ? o->val : ' '); + printf("%s\t", o->name); + if (o->has_arg == required_argument) + printf("R:%s\t", d->arg_description); + else if (o->has_arg == optional_argument) + printf("O:%s\t", d->arg_description); + else + printf("N:\t"); + printf("%s\n", d->description); + } + } + exit(EXIT_SUCCESS); +} + static void showVersion(void) { puts(PACKAGE_NAME " version " PACKAGE_VERSION);