static void nn_parse_short_option (struct nn_parse_context *ctx) { int i; struct nn_option *opt; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (!opt->shortname) continue; if (opt->shortname == *ctx->data) { ctx->last_option_usage[i] = ctx->data; if (nn_has_arg (opt)) { if (ctx->data[1]) { nn_process_option (ctx, i, ctx->data+1); } else { if (nn_get_arg (ctx)) { nn_process_option (ctx, i, ctx->data); } else { nn_option_error ("requires an argument", ctx, i); } } ctx->data = ""; /* end of short options anyway */ } else { nn_process_option (ctx, i, NULL); ctx->data += 1; } return; } } nn_error_unknown_short_option (ctx); }
static void nn_parse_arg0 (struct nn_parse_context *ctx) { int i; struct nn_option *opt; char *arg0; arg0 = strrchr (ctx->argv[0], '/'); if (arg0 == NULL) { arg0 = ctx->argv[0]; } else { arg0 += 1; /* Skip slash itself */ } for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) return; if (opt->arg0name && !strcmp (arg0, opt->arg0name)) { assert (!nn_has_arg (opt)); ctx->last_option_usage[i] = ctx->argv[0]; nn_process_option (ctx, i, NULL); } } }
static void nn_print_help (struct nn_parse_context *ctx, FILE *stream) { int i; size_t optlen; struct nn_option *opt; char *last_group; char *cursor; fprintf (stream, "Usage:\n"); nn_print_usage (ctx, stream); fprintf (stream, "\n%s\n", ctx->def->short_description); last_group = NULL; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (!last_group || last_group != opt->group || strcmp (last_group, opt->group)) { fprintf (stream, "\n"); fprintf (stream, "%s:\n", opt->group); last_group = opt->group; } fprintf (stream, " --%s", opt->longname); optlen = 3 + strlen (opt->longname); if (opt->shortname) { fprintf (stream, ",-%c", opt->shortname); optlen += 3; } if (nn_has_arg (opt)) { if (opt->metavar) { fprintf (stream, " %s", opt->metavar); optlen += strlen (opt->metavar) + 1; } else { fprintf (stream, " ARG"); optlen += 4; } } if (optlen < 23) { fputs (&" "[optlen], stream); cursor = nn_print_line (stream, opt->description, 80-24); } else { cursor = opt->description; } while (*cursor) { fprintf (stream, "\n "); cursor = nn_print_line (stream, cursor, 80-24); } fprintf (stream, "\n"); } }
static void nn_print_usage (struct nn_parse_context *ctx, FILE *stream) { int i; int first; struct nn_option *opt; fprintf (stream, " %s ", ctx->argv[0]); /* Print required options (long names) */ first = 1; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (opt->mask_set & ctx->requires) { if (first) { first = 0; fprintf (stream, "{--%s", opt->longname); } else { fprintf (stream, "|--%s", opt->longname); } } } if (!first) { fprintf (stream, "} "); } /* Print flag short options */ first = 1; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (opt->mask_set & ctx->requires) continue; /* already printed */ if (opt->shortname && !nn_has_arg (opt)) { if (first) { first = 0; fprintf (stream, "[-%c", opt->shortname); } else { fprintf (stream, "%c", opt->shortname); } } } if (!first) { fprintf (stream, "] "); } /* Print short options with arguments */ for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (opt->mask_set & ctx->requires) continue; /* already printed */ if (opt->shortname && nn_has_arg (opt) && opt->metavar) { fprintf (stream, "[-%c %s] ", opt->shortname, opt->metavar); } } fprintf (stream, "[options] \n"); /* There may be long options too */ }
static void nn_parse_long_option (struct nn_parse_context *ctx) { struct nn_option *opt; char *a, *b; size_t longest_prefix; size_t cur_prefix; int best_match; char *arg; int i; arg = ctx->data+2; longest_prefix = 0; best_match = -1; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; for (a = opt->longname, b = arg;; ++a, ++b) { if (*b == 0 || *b == '=') { /* End of option on command-line */ cur_prefix = a - opt->longname; if (!*a) { /* Matches end of option name */ best_match = i; longest_prefix = cur_prefix; goto finish; } if (cur_prefix == longest_prefix) { best_match = -1; /* Ambiguity */ } else if (cur_prefix > longest_prefix) { best_match = i; longest_prefix = cur_prefix; } break; } else if (*b != *a) { break; } } } finish: if (best_match >= 0) { opt = &ctx->options[best_match]; ctx->last_option_usage[best_match] = ctx->data; if (arg[longest_prefix] == '=') { if (nn_has_arg (opt)) { nn_process_option (ctx, best_match, arg + longest_prefix + 1); } else { nn_option_error ("does not accept argument", ctx, best_match); } } else { if (nn_has_arg (opt)) { if (nn_get_arg (ctx)) { nn_process_option (ctx, best_match, ctx->data); } else { nn_option_error ("requires an argument", ctx, best_match); } } else { nn_process_option (ctx, best_match, NULL); } } } else if (longest_prefix > 0) { nn_error_ambiguous_option (ctx); } else { nn_error_unknown_long_option (ctx); } }
static void nn_process_option (struct nn_parse_context *ctx, int opt_index, char *argument) { struct nn_option *opt; struct nn_enum_item *items; char *endptr; struct nn_blob *blob; FILE *file; char *data; size_t data_len; size_t data_buf; int bytes_read; opt = &ctx->options[opt_index]; if (ctx->mask & opt->conflicts_mask) { nn_option_conflict (ctx, opt_index); } ctx->mask |= opt->mask_set; switch (opt->type) { case NN_OPT_HELP: nn_print_help (ctx, stdout); exit (0); return; case NN_OPT_INT: *(long *)(((char *)ctx->target) + opt->offset) = strtol (argument, &endptr, 0); if (endptr == argument || *endptr != 0) { nn_option_error ("requires integer argument", ctx, opt_index); } return; case NN_OPT_INCREMENT: *(int *)(((char *)ctx->target) + opt->offset) += 1; return; case NN_OPT_DECREMENT: *(int *)(((char *)ctx->target) + opt->offset) -= 1; return; case NN_OPT_ENUM: items = (struct nn_enum_item *)opt->pointer; for (;items->name; ++items) { if (!strcmp (items->name, argument)) { *(int *)(((char *)ctx->target) + opt->offset) = \ items->value; return; } } nn_invalid_enum_value (ctx, opt_index, argument); return; case NN_OPT_SET_ENUM: *(int *)(((char *)ctx->target) + opt->offset) = \ *(int *)(opt->pointer); return; case NN_OPT_STRING: *(char **)(((char *)ctx->target) + opt->offset) = argument; return; case NN_OPT_BLOB: blob = (struct nn_blob *)(((char *)ctx->target) + opt->offset); blob->data = argument; blob->length = strlen (argument); blob->need_free = 0; return; case NN_OPT_FLOAT: #if defined NN_HAVE_WINDOWS *(float *)(((char *)ctx->target) + opt->offset) = (float) atof (argument); #else *(float *)(((char *)ctx->target) + opt->offset) = strtof (argument, &endptr); if (endptr == argument || *endptr != 0) { nn_option_error ("requires float point argument", ctx, opt_index); } #endif return; case NN_OPT_LIST_APPEND: nn_append_string (ctx, opt, argument); return; case NN_OPT_LIST_APPEND_FMT: data_buf = strlen (argument) + strlen (opt->pointer); data = malloc (data_buf); #if defined NN_HAVE_WINDOWS data_len = _snprintf_s (data, data_buf, data_buf, opt->pointer, argument); #else data_len = snprintf (data, data_buf, opt->pointer, argument); #endif assert (data_len < data_buf); nn_append_string (ctx, opt, data); nn_append_string_to_free (ctx, opt, data); return; case NN_OPT_READ_FILE: if (!strcmp (argument, "-")) { file = stdin; } else { #if defined NN_HAVE_WINDOWS if (fopen_s (&file, argument, "r") != 0) { #else file = fopen (argument, "r"); if (!file) { #endif #if defined _MSC_VER #pragma warning (push) #pragma warning (disable:4996) #endif fprintf (stderr, "Error opening file ``%s'': %s\n", argument, strerror (errno)); #if defined _MSC_VER #pragma warning (pop) #endif exit (2); } } data = malloc (4096); if (!data) nn_memory_error (ctx); data_len = 0; data_buf = 4096; for (;;) { bytes_read = fread (data + data_len, 1, data_buf - data_len, file); data_len += bytes_read; if (feof (file)) break; if (data_buf - data_len < 1024) { if (data_buf < (1 << 20)) { data_buf *= 2; /* grow twice until not too big */ } else { data_buf += 1 << 20; /* grow 1 Mb each time */ } data = realloc (data, data_buf); if (!data) nn_memory_error (ctx); } } if (data_len != data_buf) { data = realloc (data, data_len); assert (data); } if (ferror (file)) { #if defined _MSC_VER #pragma warning (push) #pragma warning (disable:4996) #endif fprintf (stderr, "Error reading file ``%s'': %s\n", argument, strerror (errno)); #if defined _MSC_VER #pragma warning (pop) #endif exit (2); } if (file != stdin) { fclose (file); } blob = (struct nn_blob *)(((char *)ctx->target) + opt->offset); blob->data = data; blob->length = data_len; blob->need_free = 1; return; } abort (); } static void nn_parse_arg0 (struct nn_parse_context *ctx) { int i; struct nn_option *opt; char *arg0; arg0 = strrchr (ctx->argv[0], '/'); if (arg0 == NULL) { arg0 = ctx->argv[0]; } else { arg0 += 1; /* Skip slash itself */ } for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) return; if (opt->arg0name && !strcmp (arg0, opt->arg0name)) { assert (!nn_has_arg (opt)); ctx->last_option_usage[i] = ctx->argv[0]; nn_process_option (ctx, i, NULL); } } }