static int __handle_option(struct fio_option *o, const char *ptr, void *data, int first, int more, int curr) { int il=0, *ilp; fio_fp64_t *flp; long long ull, *ullp; long ul1, ul2; double uf; char **cp = NULL; int ret = 0, is_time = 0; const struct value_pair *vp; struct value_pair posval[PARSE_MAX_VP]; int i, all_skipped = 1; dprint(FD_PARSE, "__handle_option=%s, type=%d, ptr=%s\n", o->name, o->type, ptr); if (!ptr && o->type != FIO_OPT_STR_SET && o->type != FIO_OPT_STR) { log_err("Option %s requires an argument\n", o->name); return 1; } switch (o->type) { case FIO_OPT_STR: case FIO_OPT_STR_MULTI: { fio_opt_str_fn *fn = o->cb; posval_sort(o, posval); ret = 1; for (i = 0; i < PARSE_MAX_VP; i++) { vp = &posval[i]; if (!vp->ival || vp->ival[0] == '\0') continue; all_skipped = 0; if (!strncmp(vp->ival, ptr, str_match_len(vp, ptr))) { ret = 0; if (o->off1) val_store(ilp, vp->oval, o->off1, vp->orval, data, o); continue; } } if (ret && !all_skipped) show_option_values(o); else if (fn) ret = fn(data, ptr); break; } case FIO_OPT_STR_VAL_TIME: is_time = 1; case FIO_OPT_INT: case FIO_OPT_STR_VAL: { fio_opt_str_val_fn *fn = o->cb; char tmp[128], *p; if (!is_time && o->is_time) is_time = o->is_time; tmp[sizeof(tmp) - 1] = '\0'; strncpy(tmp, ptr, sizeof(tmp) - 1); p = strchr(tmp, ','); if (p) *p = '\0'; if (is_time) ret = check_str_time(tmp, &ull, o->is_seconds); else ret = check_str_bytes(tmp, &ull, data); dprint(FD_PARSE, " ret=%d, out=%llu\n", ret, ull); if (ret) break; if (o->maxval && ull > o->maxval) { log_err("max value out of range: %llu" " (%u max)\n", ull, o->maxval); return 1; } if (o->minval && ull < o->minval) { log_err("min value out of range: %llu" " (%u min)\n", ull, o->minval); return 1; } if (o->posval[0].ival) { posval_sort(o, posval); ret = 1; for (i = 0; i < PARSE_MAX_VP; i++) { vp = &posval[i]; if (!vp->ival || vp->ival[0] == '\0') continue; if (vp->oval == ull) { ret = 0; break; } } if (ret) { log_err("fio: value %llu not allowed:\n", ull); show_option_values(o); return 1; } } if (fn) ret = fn(data, &ull); else { if (o->type == FIO_OPT_INT) { if (first) val_store(ilp, ull, o->off1, 0, data, o); if (curr == 1) { if (o->off2) val_store(ilp, ull, o->off2, 0, data, o); } if (curr == 2) { if (o->off3) val_store(ilp, ull, o->off3, 0, data, o); } if (!more) { if (curr < 1) { if (o->off2) val_store(ilp, ull, o->off2, 0, data, o); } if (curr < 2) { if (o->off3) val_store(ilp, ull, o->off3, 0, data, o); } } } else { if (first) val_store(ullp, ull, o->off1, 0, data, o); if (!more) { if (o->off2) val_store(ullp, ull, o->off2, 0, data, o); } } } break; } case FIO_OPT_FLOAT_LIST: { char *cp2; if (first) { /* ** Initialize precision to 0 and zero out list ** in case specified list is shorter than default */ if (o->off2) { ul2 = 0; ilp = td_var(data, o, o->off2); *ilp = ul2; } flp = td_var(data, o, o->off1); for(i = 0; i < o->maxlen; i++) flp[i].u.f = 0.0; } if (curr >= o->maxlen) { log_err("the list exceeding max length %d\n", o->maxlen); return 1; } if (!str_to_float(ptr, &uf, 0)) { /* this breaks if we ever have lists of times */ log_err("not a floating point value: %s\n", ptr); return 1; } if (uf > o->maxfp) { log_err("value out of range: %f" " (range max: %f)\n", uf, o->maxfp); return 1; } if (uf < o->minfp) { log_err("value out of range: %f" " (range min: %f)\n", uf, o->minfp); return 1; } flp = td_var(data, o, o->off1); flp[curr].u.f = uf; dprint(FD_PARSE, " out=%f\n", uf); /* ** Calculate precision for output by counting ** number of digits after period. Find first ** period in entire remaining list each time */ cp2 = strchr(ptr, '.'); if (cp2 != NULL) { int len = 0; while (*++cp2 != '\0' && *cp2 >= '0' && *cp2 <= '9') len++; if (o->off2) { ilp = td_var(data, o, o->off2); if (len > *ilp) *ilp = len; } } break; } case FIO_OPT_STR_STORE: { fio_opt_str_fn *fn = o->cb; if (!strlen(ptr)) return 1; if (o->off1) { cp = td_var(data, o, o->off1); *cp = strdup(ptr); } if (fn) ret = fn(data, ptr); else if (o->posval[0].ival) { posval_sort(o, posval); ret = 1; for (i = 0; i < PARSE_MAX_VP; i++) { vp = &posval[i]; if (!vp->ival || vp->ival[0] == '\0' || !cp) continue; all_skipped = 0; if (!strncmp(vp->ival, ptr, str_match_len(vp, ptr))) { char *rest; ret = 0; if (vp->cb) fn = vp->cb; rest = strstr(*cp ?: ptr, ":"); if (rest) { if (*cp) *rest = '\0'; ptr = rest + 1; } else ptr = NULL; break; } } } if (!all_skipped) { if (ret && !*cp) show_option_values(o); else if (ret && *cp) ret = 0; else if (fn && ptr) ret = fn(data, ptr); } break; }
static int __handle_option(struct fio_option *o, const char *ptr, void *data, int first, int more) { int il, *ilp; long long ull, *ullp; long ul1, ul2; char **cp; int ret = 0, is_time = 0; dprint(FD_PARSE, "__handle_option=%s, type=%d, ptr=%s\n", o->name, o->type, ptr); if (!ptr && o->type != FIO_OPT_STR_SET && o->type != FIO_OPT_STR) { fprintf(stderr, "Option %s requires an argument\n", o->name); return 1; } switch (o->type) { case FIO_OPT_STR: { fio_opt_str_fn *fn = o->cb; const struct value_pair *vp; struct value_pair posval[PARSE_MAX_VP]; int i; posval_sort(o, posval); for (i = 0; i < PARSE_MAX_VP; i++) { vp = &posval[i]; if (!vp->ival || vp->ival[0] == '\0') break; ret = 1; if (!strncmp(vp->ival, ptr, strlen(vp->ival))) { ret = 0; if (!o->off1) break; val_store(ilp, vp->oval, o->off1, data); break; } } if (ret) show_option_values(o); else if (fn) ret = fn(data, ptr); break; } case FIO_OPT_STR_VAL_TIME: is_time = 1; case FIO_OPT_INT: case FIO_OPT_STR_VAL: { fio_opt_str_val_fn *fn = o->cb; if (is_time) ret = check_str_time(ptr, &ull); else ret = check_str_bytes(ptr, &ull, data); if (ret) break; if (o->maxval && ull > o->maxval) { fprintf(stderr, "max value out of range: %lld" " (%d max)\n", ull, o->maxval); return 1; } if (o->minval && ull < o->minval) { fprintf(stderr, "min value out of range: %lld" " (%d min)\n", ull, o->minval); return 1; } if (fn) ret = fn(data, &ull); else { if (o->type == FIO_OPT_INT) { if (first) val_store(ilp, ull, o->off1, data); if (!more && o->off2) val_store(ilp, ull, o->off2, data); } else { if (first) val_store(ullp, ull, o->off1, data); if (!more && o->off2) val_store(ullp, ull, o->off2, data); } } break; } case FIO_OPT_STR_STORE: { fio_opt_str_fn *fn = o->cb; cp = td_var(data, o->off1); *cp = strdup(ptr); if (fn) { ret = fn(data, ptr); if (ret) { free(*cp); *cp = NULL; } } break; } case FIO_OPT_RANGE: { char tmp[128]; char *p1, *p2; strncpy(tmp, ptr, sizeof(tmp) - 1); p1 = strchr(tmp, '-'); if (!p1) { p1 = strchr(tmp, ':'); if (!p1) { ret = 1; break; } } p2 = p1 + 1; *p1 = '\0'; p1 = tmp; ret = 1; if (!check_range_bytes(p1, &ul1, data) && !check_range_bytes(p2, &ul2, data)) { ret = 0; if (ul1 > ul2) { unsigned long foo = ul1; ul1 = ul2; ul2 = foo; } if (first) { val_store(ilp, ul1, o->off1, data); val_store(ilp, ul2, o->off2, data); } if (o->off3 && o->off4) { val_store(ilp, ul1, o->off3, data); val_store(ilp, ul2, o->off4, data); } } break; } case FIO_OPT_BOOL: { fio_opt_int_fn *fn = o->cb; ret = check_int(ptr, &il); if (ret) break; if (o->maxval && il > (int) o->maxval) { fprintf(stderr, "max value out of range: %d (%d max)\n", il, o->maxval); return 1; } if (o->minval && il < o->minval) { fprintf(stderr, "min value out of range: %d (%d min)\n", il, o->minval); return 1; } if (o->neg) il = !il; if (fn) ret = fn(data, &il); else { if (first) val_store(ilp, il, o->off1, data); if (!more && o->off2) val_store(ilp, il, o->off2, data); } break; } case FIO_OPT_STR_SET: { fio_opt_str_set_fn *fn = o->cb; if (fn) ret = fn(data); else { if (first) val_store(ilp, 1, o->off1, data); if (!more && o->off2) val_store(ilp, 1, o->off2, data); } break; } case FIO_OPT_DEPRECATED: fprintf(stdout, "Option %s is deprecated\n", o->name); break; default: fprintf(stderr, "Bad option type %u\n", o->type); ret = 1; } if (ret) return ret; if (o->verify) { ret = o->verify(o, data); if (ret) { fprintf(stderr,"Correct format for offending option\n"); fprintf(stderr, "%20s: %s\n", o->name, o->help); show_option_help(o, stderr); } } return ret; }