BEGIN { opt_count = 0; FIELDS["short"] = 0; # short option FIELDS["long"] = 0; # long option FIELDS["arg"] = 0; # option argument FIELDS["desc"] = 0; # description FIELDS["func"] = 0; # callback function } func PrintShell() { printf "OPTIONS=(\n# callback short long argument\n" for (i = 0; i < opt_count; i++) printf("'%s' '%s' '%s' '%s' '%s'\n", OPTIONS["func", i], OPTIONS["short", i], OPTIONS["long", i], OPTIONS["arg", i], OPTIONS["desc", i]); printf(")\n"); } func PrintMan() { for (i = 0; i < opt_count; i++) { short = OPTIONS["short", i]; long = OPTIONS["long", i]; arg = OPTIONS["arg", i]; desc = OPTIONS["desc", i]; if (arg) printf(".TP\n.BI \"-%1s \" %s \", --%s=\" %s", short, arg, long, arg); else printf(".TP\n-%1s, --%s", short, long); printf("\n%s\n\n", desc); } } func EmptyEntry(entry) { #printf("Checking for empty entry at [%d]...\n", entry); for (type in FIELDS) { #printf(" Checking for empty field '%s'\n", type); if (OPTIONS[type, entry]) return 0; } return 1; } /^\s*#/ { # comment next; } /^\s*$/ { # end of entry if (!EmptyEntry(opt_count)) opt_count++; next; } /^\s*-/ { # option line for (i = 1; i <= NF; i++) { switch ($i) { case /^-+$/: # ignore fields with only dashes continue; case /^--\w[\w-]*/: # long option sub(/^--/, "", $i); type = "long"; break; case /^-\w+/: # short option sub(/^-/, "", $i); type = "short"; break; case /^\w+/: # option argument type = "arg"; break; } OPTIONS[type, opt_count] = $i; } } /^\s*@/ { # function callback line sub(/^\s*@\s*/, ""); OPTIONS["func", opt_count] = $1; next; } /^\s*"/ { sub(/^\s*"\s*/, ""); if (OPTIONS["desc", opt_count] !~ /\s$/) OPTIONS["desc", opt_count] += " "; OPTIONS["desc", opt_count] = $0; next; } END { if (!EmptyEntry(opt_count)) opt_count++; if (!OUTPUT) OUTPUT = "shell"; switch (OUTPUT) { case "shell": PrintShell(); break; case "man": PrintMan(); break; default: printf("Unknown format '%s'", OUTPUT) > "/dev/stderr"; } }