Skip to content

Commit 0bb2810

Browse files
committed
rework the --help output
shows a more detailed list of options now via the `--list-options` flag.
1 parent 09f05a8 commit 0bb2810

File tree

1 file changed

+127
-125
lines changed

1 file changed

+127
-125
lines changed

src/options.c

Lines changed: 127 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,85 @@ struct ScrotOptions opt = {
7676
.lineColor = "gray",
7777
};
7878

79+
enum { /* long opt only */
80+
/* ensure these don't collide with single byte opts. */
81+
OPT_FORMAT = UCHAR_MAX + 1,
82+
OPT_LIST_OPTS,
83+
};
84+
static const char stropts[] = "a:bC:cD:d:e:F:fhik::l:M:mn:opq:S:s::t:uvw:Z:z";
85+
// NOTE: make sure lopts and opt_description indexes are kept in sync
86+
static const struct option lopts[] = {
87+
{"autoselect", required_argument, NULL, 'a'},
88+
{"border", no_argument, NULL, 'b'},
89+
{"class", required_argument, NULL, 'C'},
90+
{"count", no_argument, NULL, 'c'},
91+
{"display", required_argument, NULL, 'D'},
92+
{"delay", required_argument, NULL, 'd'},
93+
{"exec", required_argument, NULL, 'e'},
94+
{"file", required_argument, NULL, 'F'},
95+
{"freeze", no_argument, NULL, 'f'},
96+
{"help", no_argument, NULL, 'h'},
97+
{"ignorekeyboard", no_argument, NULL, 'i'},
98+
{"stack", optional_argument, NULL, 'k'},
99+
{"line", required_argument, NULL, 'l'},
100+
{"monitor", required_argument, NULL, 'M'},
101+
{"multidisp", no_argument, NULL, 'm'},
102+
{"note", required_argument, NULL, 'n'},
103+
{"overwrite", no_argument, NULL, 'o'},
104+
{"pointer", no_argument, NULL, 'p'},
105+
{"quality", required_argument, NULL, 'q'},
106+
{"script", required_argument, NULL, 'S'},
107+
{"select", optional_argument, NULL, 's'},
108+
{"thumb", required_argument, NULL, 't'},
109+
{"focused", no_argument, NULL, 'u'},
110+
/* macquarie dictionary has both spellings */
111+
{"focussed", no_argument, NULL, 'u'},
112+
{"version", no_argument, NULL, 'v'},
113+
{"window", required_argument, NULL, 'w'},
114+
{"compression", required_argument, NULL, 'Z'},
115+
{"silent", no_argument, NULL, 'z'},
116+
{"format", required_argument, NULL, OPT_FORMAT},
117+
{"list-options", optional_argument, NULL, OPT_LIST_OPTS},
118+
{0}
119+
};
120+
static const char OPT_DEPRECATED[] = "";
121+
static const struct option_desc {
122+
const char *description, *arg_description;
123+
} opt_description[] = {
124+
/* a */ { "autoselect provided region", "x,y,w,h" },
125+
/* b */ { "capture the window borders as well", "" },
126+
/* C */ { "capture specified window class", "NAME" },
127+
/* c */ { "display a countdown for delay", "" },
128+
/* D */ { "capture specified display", "DISPLAY" },
129+
/* d */ { "add delay before screenshot", "[b]SEC" },
130+
/* e */ { "execute command on saved image", "CMD" },
131+
/* F */ { "specify output file", "FILE" },
132+
/* f */ { "freeze the screen when -s is used", "" },
133+
/* h */ { "display help and exit", "" },
134+
/* i */ { "ignore keyboard", "" },
135+
/* k */ { "capture overlapped window and join them", "v|h" },
136+
/* l */ { "specify the style of the selection line", "STYLE" },
137+
/* M */ { "capture monitor", "NUM" },
138+
/* m */ { "capture all monitors", "" },
139+
/* n */ { OPT_DEPRECATED, OPT_DEPRECATED },
140+
/* o */ { "overwrite the output file if needed", "" },
141+
/* p */ { "capture the mouse pointer as well", "" },
142+
/* q */ { "image quality", "NUM" },
143+
/* S */ { OPT_DEPRECATED, OPT_DEPRECATED },
144+
/* s */ { "interactively select a region to capture", "OPTS" },
145+
/* t */ { "also generate a thumbnail", "% | WxH" },
146+
/* u */ { "capture the currently focused window", "" },
147+
/* u */ { "capture the currently focused window", "" },
148+
/* v */ { "output version and exit", "" },
149+
/* w */ { "X window ID to capture", "WID" },
150+
/* Z */ { "image compression level", "LVL" },
151+
/* z */ { "prevent beeping", "" },
152+
/* OPT_FORMAT */ { "specify output file format", "FMT" },
153+
/* OPT_LIST_OPTS */ { "list all options", "human|tsv" },
154+
};
155+
79156
static void showUsage(void);
157+
static void showOptions(bool human);
80158
static void showVersion(void);
81159
static long long optionsParseNumBase(const char *, long long, long long,
82160
const char *[static 1], int);
@@ -302,82 +380,6 @@ static const char *getPathOfStdout(void)
302380

303381
void optionsParse(int argc, char *argv[])
304382
{
305-
enum { /* long opt only */
306-
/* ensure these don't collude with single byte opts. */
307-
OPT_FORMAT = UCHAR_MAX + 1,
308-
OPT_LIST_OPTS,
309-
};
310-
static const char stropts[] = "a:bC:cD:d:e:F:fhik::l:M:mn:opq:S:s::t:uvw:Z:z";
311-
// NOTE: make sure lopts and opt_description indexes are kept in sync
312-
static const struct option lopts[] = {
313-
{"autoselect", required_argument, NULL, 'a'},
314-
{"border", no_argument, NULL, 'b'},
315-
{"class", required_argument, NULL, 'C'},
316-
{"count", no_argument, NULL, 'c'},
317-
{"display", required_argument, NULL, 'D'},
318-
{"delay", required_argument, NULL, 'd'},
319-
{"exec", required_argument, NULL, 'e'},
320-
{"file", required_argument, NULL, 'F'},
321-
{"freeze", no_argument, NULL, 'f'},
322-
{"help", no_argument, NULL, 'h'},
323-
{"ignorekeyboard", no_argument, NULL, 'i'},
324-
{"stack", optional_argument, NULL, 'k'},
325-
{"line", required_argument, NULL, 'l'},
326-
{"monitor", required_argument, NULL, 'M'},
327-
{"multidisp", no_argument, NULL, 'm'},
328-
{"note", required_argument, NULL, 'n'},
329-
{"overwrite", no_argument, NULL, 'o'},
330-
{"pointer", no_argument, NULL, 'p'},
331-
{"quality", required_argument, NULL, 'q'},
332-
{"script", required_argument, NULL, 'S'},
333-
{"select", optional_argument, NULL, 's'},
334-
{"thumb", required_argument, NULL, 't'},
335-
{"focused", no_argument, NULL, 'u'},
336-
/* macquarie dictionary has both spellings */
337-
{"focussed", no_argument, NULL, 'u'},
338-
{"version", no_argument, NULL, 'v'},
339-
{"window", required_argument, NULL, 'w'},
340-
{"compression", required_argument, NULL, 'Z'},
341-
{"silent", no_argument, NULL, 'z'},
342-
{"format", required_argument, NULL, OPT_FORMAT},
343-
{"list-options", optional_argument, NULL, OPT_LIST_OPTS},
344-
{0}
345-
};
346-
static const char OPT_DEPRECATED[] = "";
347-
static const struct option_desc {
348-
const char *description, *arg_description;
349-
} opt_description[] = {
350-
/* a */ { "autoselect provided region", "x,y,w,h" },
351-
/* b */ { "capture the window borders as well", "" },
352-
/* C */ { "capture specified window class", "NAME" },
353-
/* c */ { "display a countdown for delay", "" },
354-
/* D */ { "capture specified display", "DISPLAY" },
355-
/* d */ { "add delay before screenshot", "[b]SEC" },
356-
/* e */ { "execute command on saved image", "CMD" },
357-
/* F */ { "specify output file", "FILE" },
358-
/* f */ { "freeze the screen when -s is used", "" },
359-
/* h */ { "display help and exit", "" },
360-
/* i */ { "ignore keyboard", "" },
361-
/* k */ { "capture overlapped window and join them", "v|h" },
362-
/* l */ { "specify the style of the selection line", "STYLE" },
363-
/* M */ { "capture monitor", "NUM" },
364-
/* m */ { "capture all monitors", "" },
365-
/* n */ { OPT_DEPRECATED, OPT_DEPRECATED },
366-
/* o */ { "overwrite the output file if needed", "" },
367-
/* p */ { "capture the mouse pointer as well", "" },
368-
/* q */ { "image quality", "NUM" },
369-
/* S */ { OPT_DEPRECATED, OPT_DEPRECATED },
370-
/* s */ { "interactively select a region to capture", "OPTS" },
371-
/* t */ { "also generate a thumbnail", "% | WxH" },
372-
/* u */ { "capture the currently focused window", "" },
373-
/* u */ { "capture the currently focused window", "" },
374-
/* v */ { "output version and exit", "" },
375-
/* w */ { "X window ID to capture", "WID" },
376-
/* Z */ { "image compression level", "LVL" },
377-
/* z */ { "prevent beeping", "" },
378-
/* OPT_FORMAT */ { "specify output file format", "FMT" },
379-
/* OPT_LIST_OPTS */ { "list all options", "human|tsv" },
380-
};
381383
int optch;
382384
const char *errmsg;
383385
bool FFlagSet = false;
@@ -502,51 +504,16 @@ void optionsParse(int argc, char *argv[])
502504
case OPT_FORMAT:
503505
opt.format = optarg;
504506
break;
505-
case OPT_LIST_OPTS: {
506-
bool tsv = false;
507-
if (optarg != NULL) {
508-
if (strcmp(optarg, "tsv") == 0) {
509-
tsv = true;
510-
} else if (strcmp(optarg, "human") == 0) {
511-
// no-op
512-
} else {
513-
errx(EXIT_FAILURE,
514-
"unknown argument for --list-options: `%s`", optarg);
515-
}
516-
}
517-
518-
for (size_t i = 0; i < ARRAY_COUNT(opt_description); ++i) {
519-
const struct option *o = &lopts[i];
520-
const struct option_desc *d = &opt_description[i];
521-
if (d->description == OPT_DEPRECATED)
522-
continue;
523-
524-
if (!tsv) {
525-
int n = 0;
526-
if (o->val <= UCHAR_MAX)
527-
n += printf("-%c, ", o->val);
528-
n += printf("--%s", o->name);
529-
if (o->has_arg == required_argument)
530-
n += printf(" <%s>", d->arg_description);
531-
else if (o->has_arg == optional_argument)
532-
n += printf("[=%s]", d->arg_description);
533-
for (; n >= 0 && n < 32; ++n)
534-
putchar(' ');
535-
printf("%s\n", d->description);
536-
} else {
537-
printf("%c\t", o->val <= UCHAR_MAX ? o->val : ' ');
538-
printf("%s\t", o->name);
539-
if (o->has_arg == required_argument)
540-
printf("R:%s\t", d->arg_description);
541-
else if (o->has_arg == optional_argument)
542-
printf("O:%s\t", d->arg_description);
543-
else
544-
printf("N:\t");
545-
printf("%s\n", d->description);
546-
}
507+
case OPT_LIST_OPTS:
508+
if (optarg == NULL || strcmp(optarg, "human") == 0)
509+
showOptions(true);
510+
else if (strcmp(optarg, "tsv") == 0)
511+
showOptions(false);
512+
else {
513+
errx(EXIT_FAILURE,
514+
"unknown argument for --list-options: `%s`", optarg);
547515
}
548-
exit(EXIT_SUCCESS);
549-
} break;
516+
break;
550517
default:
551518
exit(EXIT_FAILURE);
552519
}
@@ -595,14 +562,49 @@ void optionsParse(int argc, char *argv[])
595562

596563
static void showUsage(void)
597564
{
598-
fputs("usage: " /* Check that everything lines up after any changes. */
599-
PACKAGE_NAME " [-bcfhimopuvz] [-a X,Y,W,H] [-C NAME] [-D DISPLAY]\n"
600-
" [-d SEC] [-e CMD] [-k OPT] [-l STYLE] [-M NUM] [-q NUM]\n"
601-
" [-s OPTS] [-t % | WxH] [[-F] FILE]\n",
602-
stdout);
565+
fputs("Usage: " PACKAGE_NAME " [OPTIONS...] [FILE]\n\n"
566+
"A list of options with brief description is given below.\n"
567+
"For more detailed description, "
568+
"consult the "PACKAGE_NAME"(1) manpage.\n\n", stdout);
569+
showOptions(true);
603570
exit(0);
604571
}
605572

573+
static void showOptions(bool human)
574+
{
575+
for (size_t i = 0; i < ARRAY_COUNT(opt_description); ++i) {
576+
const struct option *o = &lopts[i];
577+
const struct option_desc *d = &opt_description[i];
578+
if (d->description == OPT_DEPRECATED)
579+
continue;
580+
581+
if (human) {
582+
int n = 0;
583+
if (o->val <= UCHAR_MAX)
584+
n += printf("-%c, ", o->val);
585+
n += printf("--%s", o->name);
586+
if (o->has_arg == required_argument)
587+
n += printf(" <%s>", d->arg_description);
588+
else if (o->has_arg == optional_argument)
589+
n += printf("[=%s]", d->arg_description);
590+
for (; n >= 0 && n < 32; ++n)
591+
putchar(' ');
592+
printf("%s\n", d->description);
593+
} else {
594+
printf("%c\t", o->val <= UCHAR_MAX ? o->val : ' ');
595+
printf("%s\t", o->name);
596+
if (o->has_arg == required_argument)
597+
printf("R:%s\t", d->arg_description);
598+
else if (o->has_arg == optional_argument)
599+
printf("O:%s\t", d->arg_description);
600+
else
601+
printf("N:\t");
602+
printf("%s\n", d->description);
603+
}
604+
}
605+
exit(EXIT_SUCCESS);
606+
}
607+
606608
static void showVersion(void)
607609
{
608610
puts(PACKAGE_NAME " version " PACKAGE_VERSION);

0 commit comments

Comments
 (0)