Basic Runtime Facilities
*/
-/* rename user's main routine so GC is auto-initialized */
+/* rename user's main routine so GC is auto-initialized and options parsed */
extern int usermain(int, char**);
#define main usermain
-/* This variable contains the value of argv[0] so that it can be referenced
- * again once the option parsing is done. This variable must be defined by the
- * program. */
-extern char* ARGV0;
-
+/*
+ Garbage Collector Interface
+*/
void* gc_alloc(size_t sz);
void gc_addref(void* p);
void gc_delref(void* p);
+/*
+ Option Parsing
+*/
typedef struct {
char* name;
char* desc;
} Option_T;
-/*
- { .name = "v" } // Error
- { .name = "v," }
- { .name = ",foo" }
- { .name = "b,bar" }
- { .name = ":b,bar" }
- { .name = ":,bar" }
- { .name = ":b," }
-*/
-
-extern Option_T Options[];
+typedef struct {
+ char* lname;
+ char sname;
+ int hasarg : 1;
+} OptionDescriptor_T;
void opts_parse(int argc, char** argv);
+void opts_parsespec(char* spec, OptionDescriptor_T* opt);
+void opts_printhelp(void);
/*
Standard Library Helpers
char* estrdup(const char *s);
int forkexec(char** cmd);
char* strmcat(char* first, ...);
+
+extern char* ARGV0;
+extern char* Usage;
+extern Option_T Options[];
--- /dev/null
+#include <liba.h>
+
+void opts_parsespec(char* spec, OptionDescriptor_T* opt)
+{
+ char* fullspec = spec;
+ memset(opt, 0, sizeof(OptionDescriptor_T));
+
+ /* parse optional arg specifier */
+ if (*spec == ':')
+ {
+ opt->hasarg = 1;
+ spec++;
+ }
+
+ /* parse optional short name */
+ if (*spec != ',')
+ {
+ opt->sname = *(spec++);
+ }
+
+ /* we need a comma at a minimum and if no short name was parsed,a
+ long name must be provided. bail if we don't meet these constraints */
+ if (*spec != ',' || (!opt->sname && spec[1] == '\0'))
+ {
+ fatal("opts_parsespec(): bad option specification '%s'", fullspec);
+ }
+
+ if (*(++spec))
+ {
+ opt->lname = spec;
+ }
+}
--- /dev/null
+#include <liba.h>
+
+void opts_printhelp(void)
+{
+ Option_T* opts = Options;
+ OptionDescriptor_T od = {0};
+ size_t padding = 0;
+
+ /* calculate padding */
+ for (Option_T* curr = opts; curr->name; curr++)
+ {
+ size_t pad = 4;
+ opts_parsespec(curr->name, &od);
+ if (od.sname)
+ {
+ pad += 2;
+ }
+ if (od.lname)
+ {
+ pad += (od.sname ? 2 : 0) + 2 + strlen(od.lname);
+ }
+ if (od.hasarg)
+ {
+ pad += 4;
+ }
+ if (pad > padding)
+ {
+ padding = pad;
+ }
+ }
+
+ /* print option help messages */
+ printf("usage: %s\n\n", Usage);
+ for (Option_T* curr = opts; curr->name; curr++)
+ {
+ int remain = padding;
+ opts_parsespec(curr->name, &od);
+ if (od.sname)
+ {
+ remain -= printf("-%c", od.sname);
+ }
+ if (od.lname)
+ {
+ remain -= printf("%s--%s", (od.sname ? ", " : ""), od.lname);
+ }
+ if (od.hasarg)
+ {
+ remain -= printf(" ARG");
+ }
+ printf("%*c%s\n", remain, ' ', (curr->desc ? curr->desc : ""));
+ }
+}