Skip to content

Commit

Permalink
rework the --help output
Browse files Browse the repository at this point in the history
shows a more detailed list of options now via the
`--list-options` flag.
  • Loading branch information
N-R-K committed May 28, 2024
1 parent ed51e51 commit 78c748a
Showing 1 changed file with 122 additions and 117 deletions.
239 changes: 122 additions & 117 deletions src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -502,51 +504,20 @@ 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 {
errx(EXIT_FAILURE,
"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);
}
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 78c748a

Please sign in to comment.