Adopted case-as-label style in switch statements

So:

  switch (cond) {
  case 0:;
      // first case
      break;

  case 1:;
      // second case
      break;

  default:;
      // default case
      break;
  }

This basically adopts our current label style for the case statements in
switch statements. It initially looks like quite a monstrosity, but I
think it does a good job at highlighting that case statements in C are
no safer than labels and gotos.

I would not use this style in a language with better scoping in switch
statements.

I'd prefer not to use switch statements, their scoping rules in C are
just too error-prone, and the compiler usually optimizes things out
anyways, but there are some places where switch statements are clearly
the correct organization -- state machines such as lfsr_traversal_read
for example.

If you're curious about the ':;' ending, this is used in our current
style for labels to avoid "declaration is not a statement" warnings.
Which I think is just a bit of leftover from C historically not having
mixed statements/declarations.
This commit is contained in:
Christopher Haster
2024-01-20 22:00:59 -06:00
parent 6fc040db1a
commit 4ce582bf9b
3 changed files with 738 additions and 712 deletions
+6 -6
View File
@@ -9313,7 +9313,7 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
0, file->buffer, lfsr_bshrub_size(&file->bshrub)); 0, file->buffer, lfsr_bshrub_size(&file->bshrub));
if (d < 0) { if (d < 0) {
err = d; err = d;
goto failed_with_buffer; goto failed;
} }
// small files remain perpetually unflushed // small files remain perpetually unflushed
@@ -9327,7 +9327,7 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
lfsr_addopened(lfs, &file->m); lfsr_addopened(lfs, &file->m);
return 0; return 0;
failed_with_buffer:; failed:;
// clean up memory // clean up memory
if (!file->cfg->buffer) { if (!file->cfg->buffer) {
lfs_free(file->buffer); lfs_free(file->buffer);
@@ -14777,7 +14777,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->rcache.buffer = lfs_malloc(lfs->cfg->cache_size); lfs->rcache.buffer = lfs_malloc(lfs->cfg->cache_size);
if (!lfs->rcache.buffer) { if (!lfs->rcache.buffer) {
err = LFS_ERR_NOMEM; err = LFS_ERR_NOMEM;
goto cleanup; goto failed;
} }
} }
@@ -14788,7 +14788,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->pcache.buffer = lfs_malloc(lfs->cfg->cache_size); lfs->pcache.buffer = lfs_malloc(lfs->cfg->cache_size);
if (!lfs->pcache.buffer) { if (!lfs->pcache.buffer) {
err = LFS_ERR_NOMEM; err = LFS_ERR_NOMEM;
goto cleanup; goto failed;
} }
} }
@@ -14805,7 +14805,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->lookahead.buffer = lfs_malloc(lfs->cfg->lookahead_size); lfs->lookahead.buffer = lfs_malloc(lfs->cfg->lookahead_size);
if (!lfs->lookahead.buffer) { if (!lfs->lookahead.buffer) {
err = LFS_ERR_NOMEM; err = LFS_ERR_NOMEM;
goto cleanup; goto failed;
} }
} }
lfs->lookahead.start = 0; lfs->lookahead.start = 0;
@@ -14881,7 +14881,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
return 0; return 0;
cleanup: failed:;
lfs_deinit(lfs); lfs_deinit(lfs);
return err; return err;
} }
+299 -286
View File
@@ -1505,131 +1505,152 @@ int main(int argc, char **argv) {
while (true) { while (true) {
int c = getopt_long(argc, argv, short_opts, long_opts, NULL); int c = getopt_long(argc, argv, short_opts, long_opts, NULL);
switch (c) { switch (c) {
// generate help message // generate help message
case OPT_HELP: { case OPT_HELP:;
printf("usage: %s [options] [bench_id]\n", argv[0]); printf("usage: %s [options] [bench_id]\n", argv[0]);
printf("\n"); printf("\n");
printf("options:\n"); printf("options:\n");
size_t i = 0; size_t i = 0;
while (long_opts[i].name) { while (long_opts[i].name) {
size_t indent; size_t indent;
if (long_opts[i].has_arg == no_argument) { if (long_opts[i].has_arg == no_argument) {
if (long_opts[i].val >= '0' && long_opts[i].val < 'z') { if (long_opts[i].val >= '0' && long_opts[i].val < 'z') {
indent = printf(" -%c, --%s ", indent = printf(" -%c, --%s ",
long_opts[i].val, long_opts[i].val,
long_opts[i].name); long_opts[i].name);
} else {
indent = printf(" --%s ",
long_opts[i].name);
}
} else { } else {
if (long_opts[i].val >= '0' && long_opts[i].val < 'z') { indent = printf(" --%s ",
indent = printf(" -%c %s, --%s %s ", long_opts[i].name);
long_opts[i].val,
long_opts[i].name,
long_opts[i].name,
long_opts[i].name);
} else {
indent = printf(" --%s %s ",
long_opts[i].name,
long_opts[i].name);
}
} }
} else {
// a quick, hacky, byte-level method for text wrapping if (long_opts[i].val >= '0' && long_opts[i].val < 'z') {
size_t len = strlen(help_text[i]); indent = printf(" -%c %s, --%s %s ",
size_t j = 0; long_opts[i].val,
if (indent < 24) { long_opts[i].name,
printf("%*s %.80s\n", long_opts[i].name,
(int)(24-1-indent), long_opts[i].name);
"",
&help_text[i][j]);
j += 80;
} else { } else {
printf("\n"); indent = printf(" --%s %s ",
long_opts[i].name,
long_opts[i].name);
} }
while (j < len) {
printf("%24s%.80s\n", "", &help_text[i][j]);
j += 80;
}
i += 1;
} }
printf("\n"); // a quick, hacky, byte-level method for text wrapping
exit(0); size_t len = strlen(help_text[i]);
size_t j = 0;
if (indent < 24) {
printf("%*s %.80s\n",
(int)(24-1-indent),
"",
&help_text[i][j]);
j += 80;
} else {
printf("\n");
}
while (j < len) {
printf("%24s%.80s\n", "", &help_text[i][j]);
j += 80;
}
i += 1;
} }
// summary/list flags
case OPT_SUMMARY:
op = summary;
break;
case OPT_LIST_SUITES:
op = list_suites;
break;
case OPT_LIST_CASES:
op = list_cases;
break;
case OPT_LIST_SUITE_PATHS:
op = list_suite_paths;
break;
case OPT_LIST_CASE_PATHS:
op = list_case_paths;
break;
case OPT_LIST_DEFINES:
op = list_defines;
break;
case OPT_LIST_PERMUTATION_DEFINES:
op = list_permutation_defines;
break;
case OPT_LIST_IMPLICIT_DEFINES:
op = list_implicit_defines;
break;
// configuration
case OPT_DEFINE: {
// allocate space
bench_override_t *override = mappend(
(void**)&bench_overrides,
sizeof(bench_override_t),
&bench_override_count,
&bench_override_capacity);
// parse into string key/intmax_t value, cannibalizing the printf("\n");
// arg in the process exit(0);
char *sep = strchr(optarg, '=');
char *parsed = NULL;
if (!sep) {
goto invalid_define;
}
*sep = '\0';
override->name = optarg;
optarg = sep+1;
// parse comma-separated permutations // summary/list flags
{ case OPT_SUMMARY:;
bench_override_value_t *override_values = NULL; op = summary;
size_t override_value_count = 0; break;
size_t override_value_capacity = 0;
size_t override_permutations = 0; case OPT_LIST_SUITES:;
while (true) { op = list_suites;
break;
case OPT_LIST_CASES:;
op = list_cases;
break;
case OPT_LIST_SUITE_PATHS:;
op = list_suite_paths;
break;
case OPT_LIST_CASE_PATHS:;
op = list_case_paths;
break;
case OPT_LIST_DEFINES:;
op = list_defines;
break;
case OPT_LIST_PERMUTATION_DEFINES:;
op = list_permutation_defines;
break;
case OPT_LIST_IMPLICIT_DEFINES:;
op = list_implicit_defines;
break;
// configuration
case OPT_DEFINE:;
// allocate space
bench_override_t *override = mappend(
(void**)&bench_overrides,
sizeof(bench_override_t),
&bench_override_count,
&bench_override_capacity);
// parse into string key/intmax_t value, cannibalizing the
// arg in the process
char *sep = strchr(optarg, '=');
char *parsed = NULL;
if (!sep) {
goto invalid_define;
}
*sep = '\0';
override->name = optarg;
optarg = sep+1;
// parse comma-separated permutations
{
bench_override_value_t *override_values = NULL;
size_t override_value_count = 0;
size_t override_value_capacity = 0;
size_t override_permutations = 0;
while (true) {
optarg += strspn(optarg, " ");
if (strncmp(optarg, "range", strlen("range")) == 0) {
// range of values
optarg += strlen("range");
optarg += strspn(optarg, " "); optarg += strspn(optarg, " ");
if (*optarg != '(') {
goto invalid_define;
}
optarg += 1;
if (strncmp(optarg, "range", strlen("range")) == 0) { intmax_t start = strtoumax(optarg, &parsed, 0);
// range of values intmax_t stop = -1;
optarg += strlen("range"); intmax_t step = 1;
optarg += strspn(optarg, " "); // allow empty string for start=0
if (*optarg != '(') { if (parsed == optarg) {
goto invalid_define; start = 0;
} }
optarg = parsed + strspn(parsed, " ");
if (*optarg != ',' && *optarg != ')') {
goto invalid_define;
}
if (*optarg == ',') {
optarg += 1; optarg += 1;
stop = strtoumax(optarg, &parsed, 0);
intmax_t start = strtoumax(optarg, &parsed, 0); // allow empty string for stop=end
intmax_t stop = -1;
intmax_t step = 1;
// allow empty string for start=0
if (parsed == optarg) { if (parsed == optarg) {
start = 0; stop = -1;
} }
optarg = parsed + strspn(parsed, " "); optarg = parsed + strspn(parsed, " ");
@@ -1639,111 +1660,111 @@ int main(int argc, char **argv) {
if (*optarg == ',') { if (*optarg == ',') {
optarg += 1; optarg += 1;
stop = strtoumax(optarg, &parsed, 0); step = strtoumax(optarg, &parsed, 0);
// allow empty string for stop=end // allow empty string for stop=1
if (parsed == optarg) { if (parsed == optarg) {
stop = -1; step = 1;
} }
optarg = parsed + strspn(parsed, " "); optarg = parsed + strspn(parsed, " ");
if (*optarg != ',' && *optarg != ')') { if (*optarg != ')') {
goto invalid_define; goto invalid_define;
} }
if (*optarg == ',') {
optarg += 1;
step = strtoumax(optarg, &parsed, 0);
// allow empty string for stop=1
if (parsed == optarg) {
step = 1;
}
optarg = parsed + strspn(parsed, " ");
if (*optarg != ')') {
goto invalid_define;
}
}
} else {
// single value = stop only
stop = start;
start = 0;
} }
if (*optarg != ')') {
goto invalid_define;
}
optarg += 1;
// append range
*(bench_override_value_t*)mappend(
(void**)&override_values,
sizeof(bench_override_value_t),
&override_value_count,
&override_value_capacity)
= (bench_override_value_t){
.start = start,
.stop = stop,
.step = step,
};
if (step > 0) {
override_permutations += (stop-1 - start)
/ step + 1;
} else {
override_permutations += (start-1 - stop)
/ -step + 1;
}
} else if (*optarg != '\0') {
// single value
intmax_t define = strtoumax(optarg, &parsed, 0);
if (parsed == optarg) {
goto invalid_define;
}
optarg = parsed + strspn(parsed, " ");
// append value
*(bench_override_value_t*)mappend(
(void**)&override_values,
sizeof(bench_override_value_t),
&override_value_count,
&override_value_capacity)
= (bench_override_value_t){
.start = define,
.step = 0,
};
override_permutations += 1;
} else { } else {
break; // single value = stop only
stop = start;
start = 0;
} }
if (*optarg == ',') { if (*optarg != ')') {
optarg += 1; goto invalid_define;
} }
optarg += 1;
// append range
*(bench_override_value_t*)mappend(
(void**)&override_values,
sizeof(bench_override_value_t),
&override_value_count,
&override_value_capacity)
= (bench_override_value_t){
.start = start,
.stop = stop,
.step = step,
};
if (step > 0) {
override_permutations += (stop-1 - start)
/ step + 1;
} else {
override_permutations += (start-1 - stop)
/ -step + 1;
}
} else if (*optarg != '\0') {
// single value
intmax_t define = strtoumax(optarg, &parsed, 0);
if (parsed == optarg) {
goto invalid_define;
}
optarg = parsed + strspn(parsed, " ");
// append value
*(bench_override_value_t*)mappend(
(void**)&override_values,
sizeof(bench_override_value_t),
&override_value_count,
&override_value_capacity)
= (bench_override_value_t){
.start = define,
.step = 0,
};
override_permutations += 1;
} else {
break;
} }
override->define.cb = bench_override_cb; if (*optarg == ',') {
override->define.data = malloc( optarg += 1;
sizeof(bench_override_data_t)); }
*(bench_override_data_t*)override->define.data
= (bench_override_data_t){
.values = override_values,
.value_count = override_value_count,
};
override->define.permutations = override_permutations;
} }
break;
invalid_define: override->define.cb = bench_override_cb;
fprintf(stderr, "error: invalid define: %s\n", optarg); override->define.data = malloc(
exit(-1); sizeof(bench_override_data_t));
*(bench_override_data_t*)override->define.data
= (bench_override_data_t){
.values = override_values,
.value_count = override_value_count,
};
override->define.permutations = override_permutations;
} }
case OPT_STEP: { break;
char *parsed = NULL;
bench_step_start = strtoumax(optarg, &parsed, 0); invalid_define:;
bench_step_stop = -1; fprintf(stderr, "error: invalid define: %s\n", optarg);
bench_step_step = 1; exit(-1);
// allow empty string for start=0
case OPT_STEP:;
parsed = NULL;
bench_step_start = strtoumax(optarg, &parsed, 0);
bench_step_stop = -1;
bench_step_step = 1;
// allow empty string for start=0
if (parsed == optarg) {
bench_step_start = 0;
}
optarg = parsed + strspn(parsed, " ");
if (*optarg != ',' && *optarg != '\0') {
goto step_unknown;
}
if (*optarg == ',') {
optarg += 1;
bench_step_stop = strtoumax(optarg, &parsed, 0);
// allow empty string for stop=end
if (parsed == optarg) { if (parsed == optarg) {
bench_step_start = 0; bench_step_stop = -1;
} }
optarg = parsed + strspn(parsed, " "); optarg = parsed + strspn(parsed, " ");
@@ -1753,104 +1774,96 @@ invalid_define:
if (*optarg == ',') { if (*optarg == ',') {
optarg += 1; optarg += 1;
bench_step_stop = strtoumax(optarg, &parsed, 0); bench_step_step = strtoumax(optarg, &parsed, 0);
// allow empty string for stop=end // allow empty string for stop=1
if (parsed == optarg) { if (parsed == optarg) {
bench_step_stop = -1; bench_step_step = 1;
} }
optarg = parsed + strspn(parsed, " "); optarg = parsed + strspn(parsed, " ");
if (*optarg != ',' && *optarg != '\0') { if (*optarg != '\0') {
goto step_unknown; goto step_unknown;
} }
if (*optarg == ',') {
optarg += 1;
bench_step_step = strtoumax(optarg, &parsed, 0);
// allow empty string for stop=1
if (parsed == optarg) {
bench_step_step = 1;
}
optarg = parsed + strspn(parsed, " ");
if (*optarg != '\0') {
goto step_unknown;
}
}
} else {
// single value = stop only
bench_step_stop = bench_step_start;
bench_step_start = 0;
} }
} else {
// single value = stop only
bench_step_stop = bench_step_start;
bench_step_start = 0;
}
break; break;
step_unknown:
fprintf(stderr, "error: invalid step: %s\n", optarg); step_unknown:;
fprintf(stderr, "error: invalid step: %s\n", optarg);
exit(-1);
case OPT_DISK:;
bench_disk_path = optarg;
break;
case OPT_TRACE:;
bench_trace_path = optarg;
break;
case OPT_TRACE_BACKTRACE:;
bench_trace_backtrace = true;
break;
case OPT_TRACE_PERIOD:;
parsed = NULL;
bench_trace_period = strtoumax(optarg, &parsed, 0);
if (parsed == optarg) {
fprintf(stderr, "error: invalid trace-period: %s\n", optarg);
exit(-1); exit(-1);
} }
case OPT_DISK: break;
bench_disk_path = optarg;
break; case OPT_TRACE_FREQ:;
case OPT_TRACE: parsed = NULL;
bench_trace_path = optarg; bench_trace_freq = strtoumax(optarg, &parsed, 0);
break; if (parsed == optarg) {
case OPT_TRACE_BACKTRACE: fprintf(stderr, "error: invalid trace-freq: %s\n", optarg);
bench_trace_backtrace = true;
break;
case OPT_TRACE_PERIOD: {
char *parsed = NULL;
bench_trace_period = strtoumax(optarg, &parsed, 0);
if (parsed == optarg) {
fprintf(stderr, "error: invalid trace-period: %s\n", optarg);
exit(-1);
}
break;
}
case OPT_TRACE_FREQ: {
char *parsed = NULL;
bench_trace_freq = strtoumax(optarg, &parsed, 0);
if (parsed == optarg) {
fprintf(stderr, "error: invalid trace-freq: %s\n", optarg);
exit(-1);
}
break;
}
case OPT_READ_SLEEP: {
char *parsed = NULL;
double read_sleep = strtod(optarg, &parsed);
if (parsed == optarg) {
fprintf(stderr, "error: invalid read-sleep: %s\n", optarg);
exit(-1);
}
bench_read_sleep = read_sleep*1.0e9;
break;
}
case OPT_PROG_SLEEP: {
char *parsed = NULL;
double prog_sleep = strtod(optarg, &parsed);
if (parsed == optarg) {
fprintf(stderr, "error: invalid prog-sleep: %s\n", optarg);
exit(-1);
}
bench_prog_sleep = prog_sleep*1.0e9;
break;
}
case OPT_ERASE_SLEEP: {
char *parsed = NULL;
double erase_sleep = strtod(optarg, &parsed);
if (parsed == optarg) {
fprintf(stderr, "error: invalid erase-sleep: %s\n", optarg);
exit(-1);
}
bench_erase_sleep = erase_sleep*1.0e9;
break;
}
// done parsing
case -1:
goto getopt_done;
// unknown arg, getopt prints a message for us
default:
exit(-1); exit(-1);
}
break;
case OPT_READ_SLEEP:;
parsed = NULL;
double read_sleep = strtod(optarg, &parsed);
if (parsed == optarg) {
fprintf(stderr, "error: invalid read-sleep: %s\n", optarg);
exit(-1);
}
bench_read_sleep = read_sleep*1.0e9;
break;
case OPT_PROG_SLEEP:;
parsed = NULL;
double prog_sleep = strtod(optarg, &parsed);
if (parsed == optarg) {
fprintf(stderr, "error: invalid prog-sleep: %s\n", optarg);
exit(-1);
}
bench_prog_sleep = prog_sleep*1.0e9;
break;
case OPT_ERASE_SLEEP:;
parsed = NULL;
double erase_sleep = strtod(optarg, &parsed);
if (parsed == optarg) {
fprintf(stderr, "error: invalid erase-sleep: %s\n", optarg);
exit(-1);
}
bench_erase_sleep = erase_sleep*1.0e9;
break;
// done parsing
case -1:;
goto getopt_done;
// unknown arg, getopt prints a message for us
default:;
exit(-1);
} }
} }
getopt_done: ; getopt_done: ;
+433 -420
View File
@@ -1945,134 +1945,156 @@ int main(int argc, char **argv) {
while (true) { while (true) {
int c = getopt_long(argc, argv, short_opts, long_opts, NULL); int c = getopt_long(argc, argv, short_opts, long_opts, NULL);
switch (c) { switch (c) {
// generate help message // generate help message
case OPT_HELP: { case OPT_HELP:;
printf("usage: %s [options] [test_id]\n", argv[0]); printf("usage: %s [options] [test_id]\n", argv[0]);
printf("\n"); printf("\n");
printf("options:\n"); printf("options:\n");
size_t i = 0; size_t i = 0;
while (long_opts[i].name) { while (long_opts[i].name) {
size_t indent; size_t indent;
if (long_opts[i].has_arg == no_argument) { if (long_opts[i].has_arg == no_argument) {
if (long_opts[i].val >= '0' && long_opts[i].val < 'z') { if (long_opts[i].val >= '0' && long_opts[i].val < 'z') {
indent = printf(" -%c, --%s ", indent = printf(" -%c, --%s ",
long_opts[i].val, long_opts[i].val,
long_opts[i].name); long_opts[i].name);
} else {
indent = printf(" --%s ",
long_opts[i].name);
}
} else { } else {
if (long_opts[i].val >= '0' && long_opts[i].val < 'z') { indent = printf(" --%s ",
indent = printf(" -%c %s, --%s %s ", long_opts[i].name);
long_opts[i].val,
long_opts[i].name,
long_opts[i].name,
long_opts[i].name);
} else {
indent = printf(" --%s %s ",
long_opts[i].name,
long_opts[i].name);
}
} }
} else {
// a quick, hacky, byte-level method for text wrapping if (long_opts[i].val >= '0' && long_opts[i].val < 'z') {
size_t len = strlen(help_text[i]); indent = printf(" -%c %s, --%s %s ",
size_t j = 0; long_opts[i].val,
if (indent < 24) { long_opts[i].name,
printf("%*s %.80s\n", long_opts[i].name,
(int)(24-1-indent), long_opts[i].name);
"",
&help_text[i][j]);
j += 80;
} else { } else {
printf("\n"); indent = printf(" --%s %s ",
long_opts[i].name,
long_opts[i].name);
} }
while (j < len) {
printf("%24s%.80s\n", "", &help_text[i][j]);
j += 80;
}
i += 1;
} }
printf("\n"); // a quick, hacky, byte-level method for text wrapping
exit(0); size_t len = strlen(help_text[i]);
size_t j = 0;
if (indent < 24) {
printf("%*s %.80s\n",
(int)(24-1-indent),
"",
&help_text[i][j]);
j += 80;
} else {
printf("\n");
}
while (j < len) {
printf("%24s%.80s\n", "", &help_text[i][j]);
j += 80;
}
i += 1;
} }
// summary/list flags
case OPT_SUMMARY:
op = summary;
break;
case OPT_LIST_SUITES:
op = list_suites;
break;
case OPT_LIST_CASES:
op = list_cases;
break;
case OPT_LIST_SUITE_PATHS:
op = list_suite_paths;
break;
case OPT_LIST_CASE_PATHS:
op = list_case_paths;
break;
case OPT_LIST_DEFINES:
op = list_defines;
break;
case OPT_LIST_PERMUTATION_DEFINES:
op = list_permutation_defines;
break;
case OPT_LIST_IMPLICIT_DEFINES:
op = list_implicit_defines;
break;
case OPT_LIST_POWERLOSSES:
op = list_powerlosses;
break;
// configuration
case OPT_DEFINE: {
// allocate space
test_override_t *override = mappend(
(void**)&test_overrides,
sizeof(test_override_t),
&test_override_count,
&test_override_capacity);
// parse into string key/intmax_t value, cannibalizing the printf("\n");
// arg in the process exit(0);
char *sep = strchr(optarg, '=');
char *parsed = NULL;
if (!sep) {
goto invalid_define;
}
*sep = '\0';
override->name = optarg;
optarg = sep+1;
// parse comma-separated permutations // summary/list flags
{ case OPT_SUMMARY:;
test_override_value_t *override_values = NULL; op = summary;
size_t override_value_count = 0; break;
size_t override_value_capacity = 0;
size_t override_permutations = 0; case OPT_LIST_SUITES:;
while (true) { op = list_suites;
break;
case OPT_LIST_CASES:;
op = list_cases;
break;
case OPT_LIST_SUITE_PATHS:;
op = list_suite_paths;
break;
case OPT_LIST_CASE_PATHS:;
op = list_case_paths;
break;
case OPT_LIST_DEFINES:;
op = list_defines;
break;
case OPT_LIST_PERMUTATION_DEFINES:;
op = list_permutation_defines;
break;
case OPT_LIST_IMPLICIT_DEFINES:;
op = list_implicit_defines;
break;
case OPT_LIST_POWERLOSSES:;
op = list_powerlosses;
break;
// configuration
case OPT_DEFINE:;
// allocate space
test_override_t *override = mappend(
(void**)&test_overrides,
sizeof(test_override_t),
&test_override_count,
&test_override_capacity);
// parse into string key/intmax_t value, cannibalizing the
// arg in the process
char *sep = strchr(optarg, '=');
char *parsed = NULL;
if (!sep) {
goto invalid_define;
}
*sep = '\0';
override->name = optarg;
optarg = sep+1;
// parse comma-separated permutations
{
test_override_value_t *override_values = NULL;
size_t override_value_count = 0;
size_t override_value_capacity = 0;
size_t override_permutations = 0;
while (true) {
optarg += strspn(optarg, " ");
if (strncmp(optarg, "range", strlen("range")) == 0) {
// range of values
optarg += strlen("range");
optarg += strspn(optarg, " "); optarg += strspn(optarg, " ");
if (*optarg != '(') {
goto invalid_define;
}
optarg += 1;
if (strncmp(optarg, "range", strlen("range")) == 0) { intmax_t start = strtoumax(optarg, &parsed, 0);
// range of values intmax_t stop = -1;
optarg += strlen("range"); intmax_t step = 1;
optarg += strspn(optarg, " "); // allow empty string for start=0
if (*optarg != '(') { if (parsed == optarg) {
goto invalid_define; start = 0;
} }
optarg = parsed + strspn(parsed, " ");
if (*optarg != ',' && *optarg != ')') {
goto invalid_define;
}
if (*optarg == ',') {
optarg += 1; optarg += 1;
stop = strtoumax(optarg, &parsed, 0);
intmax_t start = strtoumax(optarg, &parsed, 0); // allow empty string for stop=end
intmax_t stop = -1;
intmax_t step = 1;
// allow empty string for start=0
if (parsed == optarg) { if (parsed == optarg) {
start = 0; stop = -1;
} }
optarg = parsed + strspn(parsed, " "); optarg = parsed + strspn(parsed, " ");
@@ -2082,163 +2104,205 @@ int main(int argc, char **argv) {
if (*optarg == ',') { if (*optarg == ',') {
optarg += 1; optarg += 1;
stop = strtoumax(optarg, &parsed, 0); step = strtoumax(optarg, &parsed, 0);
// allow empty string for stop=end // allow empty string for stop=1
if (parsed == optarg) { if (parsed == optarg) {
stop = -1; step = 1;
} }
optarg = parsed + strspn(parsed, " "); optarg = parsed + strspn(parsed, " ");
if (*optarg != ',' && *optarg != ')') { if (*optarg != ')') {
goto invalid_define; goto invalid_define;
} }
if (*optarg == ',') {
optarg += 1;
step = strtoumax(optarg, &parsed, 0);
// allow empty string for stop=1
if (parsed == optarg) {
step = 1;
}
optarg = parsed + strspn(parsed, " ");
if (*optarg != ')') {
goto invalid_define;
}
}
} else {
// single value = stop only
stop = start;
start = 0;
} }
if (*optarg != ')') {
goto invalid_define;
}
optarg += 1;
// append range
*(test_override_value_t*)mappend(
(void**)&override_values,
sizeof(test_override_value_t),
&override_value_count,
&override_value_capacity)
= (test_override_value_t){
.start = start,
.stop = stop,
.step = step,
};
if (step > 0) {
override_permutations += (stop-1 - start)
/ step + 1;
} else {
override_permutations += (start-1 - stop)
/ -step + 1;
}
} else if (*optarg != '\0') {
// single value
intmax_t define = strtoumax(optarg, &parsed, 0);
if (parsed == optarg) {
goto invalid_define;
}
optarg = parsed + strspn(parsed, " ");
// append value
*(test_override_value_t*)mappend(
(void**)&override_values,
sizeof(test_override_value_t),
&override_value_count,
&override_value_capacity)
= (test_override_value_t){
.start = define,
.step = 0,
};
override_permutations += 1;
} else { } else {
break; // single value = stop only
stop = start;
start = 0;
} }
if (*optarg == ',') { if (*optarg != ')') {
optarg += 1; goto invalid_define;
} }
optarg += 1;
// append range
*(test_override_value_t*)mappend(
(void**)&override_values,
sizeof(test_override_value_t),
&override_value_count,
&override_value_capacity)
= (test_override_value_t){
.start = start,
.stop = stop,
.step = step,
};
if (step > 0) {
override_permutations += (stop-1 - start)
/ step + 1;
} else {
override_permutations += (start-1 - stop)
/ -step + 1;
}
} else if (*optarg != '\0') {
// single value
intmax_t define = strtoumax(optarg, &parsed, 0);
if (parsed == optarg) {
goto invalid_define;
}
optarg = parsed + strspn(parsed, " ");
// append value
*(test_override_value_t*)mappend(
(void**)&override_values,
sizeof(test_override_value_t),
&override_value_count,
&override_value_capacity)
= (test_override_value_t){
.start = define,
.step = 0,
};
override_permutations += 1;
} else {
break;
} }
override->define.cb = test_override_cb; if (*optarg == ',') {
override->define.data = malloc( optarg += 1;
sizeof(test_override_data_t)); }
*(test_override_data_t*)override->define.data
= (test_override_data_t){
.values = override_values,
.value_count = override_value_count,
};
override->define.permutations = override_permutations;
} }
break;
invalid_define: override->define.cb = test_override_cb;
fprintf(stderr, "error: invalid define: %s\n", optarg); override->define.data = malloc(
exit(-1); sizeof(test_override_data_t));
*(test_override_data_t*)override->define.data
= (test_override_data_t){
.values = override_values,
.value_count = override_value_count,
};
override->define.permutations = override_permutations;
} }
case OPT_POWERLOSS: { break;
// reset our powerloss scenarios
if (test_powerloss_capacity > 0) { invalid_define:;
free((test_powerloss_t*)test_powerlosses); fprintf(stderr, "error: invalid define: %s\n", optarg);
exit(-1);
case OPT_POWERLOSS:;
// reset our powerloss scenarios
if (test_powerloss_capacity > 0) {
free((test_powerloss_t*)test_powerlosses);
}
test_powerlosses = NULL;
test_powerloss_count = 0;
test_powerloss_capacity = 0;
// parse the comma separated list of power-loss scenarios
while (*optarg) {
// allocate space
test_powerloss_t *powerloss = mappend(
(void**)&test_powerlosses,
sizeof(test_powerloss_t),
&test_powerloss_count,
&test_powerloss_capacity);
// parse the power-loss scenario
optarg += strspn(optarg, " ");
// named power-loss scenario
size_t len = strcspn(optarg, " ,");
for (size_t i = 0; builtin_powerlosses[i].name; i++) {
if (len == strlen(builtin_powerlosses[i].name)
&& memcmp(optarg,
builtin_powerlosses[i].name,
len) == 0) {
*powerloss = builtin_powerlosses[i];
optarg += len;
goto powerloss_next;
}
} }
test_powerlosses = NULL;
test_powerloss_count = 0;
test_powerloss_capacity = 0;
// parse the comma separated list of power-loss scenarios // comma-separated permutation
while (*optarg) { if (*optarg == '{') {
// allocate space lfs_emubd_powercycles_t *cycles = NULL;
test_powerloss_t *powerloss = mappend( size_t cycle_count = 0;
(void**)&test_powerlosses, size_t cycle_capacity = 0;
sizeof(test_powerloss_t),
&test_powerloss_count,
&test_powerloss_capacity);
// parse the power-loss scenario char *s = optarg + 1;
optarg += strspn(optarg, " "); while (true) {
parsed = NULL;
*(lfs_emubd_powercycles_t*)mappend(
(void**)&cycles,
sizeof(lfs_emubd_powercycles_t),
&cycle_count,
&cycle_capacity)
= strtoumax(s, &parsed, 0);
// named power-loss scenario s = parsed + strspn(parsed, " ");
size_t len = strcspn(optarg, " ,"); if (*s == ',') {
for (size_t i = 0; builtin_powerlosses[i].name; i++) { s += 1;
if (len == strlen(builtin_powerlosses[i].name) continue;
&& memcmp(optarg, } else if (*s == '}') {
builtin_powerlosses[i].name, s += 1;
len) == 0) { break;
*powerloss = builtin_powerlosses[i]; } else {
optarg += len; goto powerloss_unknown;
goto powerloss_next;
} }
} }
// comma-separated permutation *powerloss = (test_powerloss_t){
if (*optarg == '{') { "explicit",
run_powerloss_cycles,
cycles,
cycle_count};
optarg = s;
goto powerloss_next;
}
// leb16-encoded permutation
if (*optarg == ':') {
// special case for linear power cycles
if (optarg[1] == 'x') {
size_t cycle_count = leb16_parse(optarg+2, &optarg);
*powerloss = (test_powerloss_t){
"linear",
run_powerloss_linear,
NULL,
cycle_count};
goto powerloss_next;
// special case for log power cycles
} else if (optarg[1] == 'y') {
size_t cycle_count = leb16_parse(optarg+2, &optarg);
*powerloss = (test_powerloss_t){
"log",
run_powerloss_log,
NULL,
cycle_count};
goto powerloss_next;
// otherwise explicit power cycles
} else {
lfs_emubd_powercycles_t *cycles = NULL; lfs_emubd_powercycles_t *cycles = NULL;
size_t cycle_count = 0; size_t cycle_count = 0;
size_t cycle_capacity = 0; size_t cycle_capacity = 0;
char *s = optarg + 1; char *s = optarg + 1;
while (true) { while (true) {
char *parsed = NULL; parsed = NULL;
uintmax_t x = leb16_parse(s, &parsed);
if (parsed == s) {
break;
}
*(lfs_emubd_powercycles_t*)mappend( *(lfs_emubd_powercycles_t*)mappend(
(void**)&cycles, (void**)&cycles,
sizeof(lfs_emubd_powercycles_t), sizeof(lfs_emubd_powercycles_t),
&cycle_count, &cycle_count,
&cycle_capacity) &cycle_capacity) = x;
= strtoumax(s, &parsed, 0); s = parsed;
s = parsed + strspn(parsed, " ");
if (*s == ',') {
s += 1;
continue;
} else if (*s == '}') {
s += 1;
break;
} else {
goto powerloss_unknown;
}
} }
*powerloss = (test_powerloss_t){ *powerloss = (test_powerloss_t){
@@ -2249,105 +2313,63 @@ invalid_define:
optarg = s; optarg = s;
goto powerloss_next; goto powerloss_next;
} }
}
// leb16-encoded permutation // exhaustive permutations
if (*optarg == ':') { {
// special case for linear power cycles parsed = NULL;
if (optarg[1] == 'x') { size_t count = strtoumax(optarg, &parsed, 0);
size_t cycle_count = leb16_parse(optarg+2, &optarg); if (parsed == optarg) {
*powerloss = (test_powerloss_t){
"linear",
run_powerloss_linear,
NULL,
cycle_count};
goto powerloss_next;
// special case for log power cycles
} else if (optarg[1] == 'y') {
size_t cycle_count = leb16_parse(optarg+2, &optarg);
*powerloss = (test_powerloss_t){
"log",
run_powerloss_log,
NULL,
cycle_count};
goto powerloss_next;
// otherwise explicit power cycles
} else {
lfs_emubd_powercycles_t *cycles = NULL;
size_t cycle_count = 0;
size_t cycle_capacity = 0;
char *s = optarg + 1;
while (true) {
char *parsed = NULL;
uintmax_t x = leb16_parse(s, &parsed);
if (parsed == s) {
break;
}
*(lfs_emubd_powercycles_t*)mappend(
(void**)&cycles,
sizeof(lfs_emubd_powercycles_t),
&cycle_count,
&cycle_capacity) = x;
s = parsed;
}
*powerloss = (test_powerloss_t){
"explicit",
run_powerloss_cycles,
cycles,
cycle_count};
optarg = s;
goto powerloss_next;
}
}
// exhaustive permutations
{
char *parsed = NULL;
size_t count = strtoumax(optarg, &parsed, 0);
if (parsed == optarg) {
goto powerloss_unknown;
}
*powerloss = (test_powerloss_t){
"exhaustive",
run_powerloss_exhaustive,
NULL,
count};
optarg = (char*)parsed;
goto powerloss_next;
}
powerloss_unknown:
// unknown scenario?
fprintf(stderr, "error: unknown power-loss scenario: %s\n",
optarg);
exit(-1);
powerloss_next:
optarg += strspn(optarg, " ");
if (*optarg == ',') {
optarg += 1;
} else if (*optarg == '\0') {
break;
} else {
goto powerloss_unknown; goto powerloss_unknown;
} }
*powerloss = (test_powerloss_t){
"exhaustive",
run_powerloss_exhaustive,
NULL,
count};
optarg = (char*)parsed;
goto powerloss_next;
}
powerloss_unknown:;
// unknown scenario?
fprintf(stderr, "error: unknown power-loss scenario: %s\n",
optarg);
exit(-1);
powerloss_next:;
optarg += strspn(optarg, " ");
if (*optarg == ',') {
optarg += 1;
} else if (*optarg == '\0') {
break;
} else {
goto powerloss_unknown;
} }
break;
} }
case OPT_STEP: { break;
char *parsed = NULL;
test_step_start = strtoumax(optarg, &parsed, 0); case OPT_STEP:;
test_step_stop = -1; parsed = NULL;
test_step_step = 1; test_step_start = strtoumax(optarg, &parsed, 0);
// allow empty string for start=0 test_step_stop = -1;
test_step_step = 1;
// allow empty string for start=0
if (parsed == optarg) {
test_step_start = 0;
}
optarg = parsed + strspn(parsed, " ");
if (*optarg != ',' && *optarg != '\0') {
goto step_unknown;
}
if (*optarg == ',') {
optarg += 1;
test_step_stop = strtoumax(optarg, &parsed, 0);
// allow empty string for stop=end
if (parsed == optarg) { if (parsed == optarg) {
test_step_start = 0; test_step_stop = -1;
} }
optarg = parsed + strspn(parsed, " "); optarg = parsed + strspn(parsed, " ");
@@ -2357,108 +2379,99 @@ powerloss_next:
if (*optarg == ',') { if (*optarg == ',') {
optarg += 1; optarg += 1;
test_step_stop = strtoumax(optarg, &parsed, 0); test_step_step = strtoumax(optarg, &parsed, 0);
// allow empty string for stop=end // allow empty string for stop=1
if (parsed == optarg) { if (parsed == optarg) {
test_step_stop = -1; test_step_step = 1;
} }
optarg = parsed + strspn(parsed, " "); optarg = parsed + strspn(parsed, " ");
if (*optarg != ',' && *optarg != '\0') { if (*optarg != '\0') {
goto step_unknown; goto step_unknown;
} }
if (*optarg == ',') {
optarg += 1;
test_step_step = strtoumax(optarg, &parsed, 0);
// allow empty string for stop=1
if (parsed == optarg) {
test_step_step = 1;
}
optarg = parsed + strspn(parsed, " ");
if (*optarg != '\0') {
goto step_unknown;
}
}
} else {
// single value = stop only
test_step_stop = test_step_start;
test_step_start = 0;
} }
} else {
// single value = stop only
test_step_stop = test_step_start;
test_step_start = 0;
}
break;
break; step_unknown:;
step_unknown: fprintf(stderr, "error: invalid step: %s\n", optarg);
fprintf(stderr, "error: invalid step: %s\n", optarg); exit(-1);
case OPT_DISK:;
test_disk_path = optarg;
break;
case OPT_TRACE:;
test_trace_path = optarg;
break;
case OPT_TRACE_BACKTRACE:;
test_trace_backtrace = true;
break;
case OPT_TRACE_PERIOD:;
parsed = NULL;
test_trace_period = strtoumax(optarg, &parsed, 0);
if (parsed == optarg) {
fprintf(stderr, "error: invalid trace-period: %s\n",
optarg);
exit(-1); exit(-1);
} }
case OPT_DISK: break;
test_disk_path = optarg;
break; case OPT_TRACE_FREQ:;
case OPT_TRACE: parsed = NULL;
test_trace_path = optarg; test_trace_freq = strtoumax(optarg, &parsed, 0);
break; if (parsed == optarg) {
case OPT_TRACE_BACKTRACE: fprintf(stderr, "error: invalid trace-freq: %s\n", optarg);
test_trace_backtrace = true;
break;
case OPT_TRACE_PERIOD: {
char *parsed = NULL;
test_trace_period = strtoumax(optarg, &parsed, 0);
if (parsed == optarg) {
fprintf(stderr, "error: invalid trace-period: %s\n",
optarg);
exit(-1);
}
break;
}
case OPT_TRACE_FREQ: {
char *parsed = NULL;
test_trace_freq = strtoumax(optarg, &parsed, 0);
if (parsed == optarg) {
fprintf(stderr, "error: invalid trace-freq: %s\n", optarg);
exit(-1);
}
break;
}
case OPT_READ_SLEEP: {
char *parsed = NULL;
double read_sleep = strtod(optarg, &parsed);
if (parsed == optarg) {
fprintf(stderr, "error: invalid read-sleep: %s\n", optarg);
exit(-1);
}
test_read_sleep = read_sleep*1.0e9;
break;
}
case OPT_PROG_SLEEP: {
char *parsed = NULL;
double prog_sleep = strtod(optarg, &parsed);
if (parsed == optarg) {
fprintf(stderr, "error: invalid prog-sleep: %s\n", optarg);
exit(-1);
}
test_prog_sleep = prog_sleep*1.0e9;
break;
}
case OPT_ERASE_SLEEP: {
char *parsed = NULL;
double erase_sleep = strtod(optarg, &parsed);
if (parsed == optarg) {
fprintf(stderr, "error: invalid erase-sleep: %s\n", optarg);
exit(-1);
}
test_erase_sleep = erase_sleep*1.0e9;
break;
}
// done parsing
case -1:
goto getopt_done;
// unknown arg, getopt prints a message for us
default:
exit(-1); exit(-1);
}
break;
case OPT_READ_SLEEP:;
parsed = NULL;
double read_sleep = strtod(optarg, &parsed);
if (parsed == optarg) {
fprintf(stderr, "error: invalid read-sleep: %s\n", optarg);
exit(-1);
}
test_read_sleep = read_sleep*1.0e9;
break;
case OPT_PROG_SLEEP:;
parsed = NULL;
double prog_sleep = strtod(optarg, &parsed);
if (parsed == optarg) {
fprintf(stderr, "error: invalid prog-sleep: %s\n", optarg);
exit(-1);
}
test_prog_sleep = prog_sleep*1.0e9;
break;
case OPT_ERASE_SLEEP:;
parsed = NULL;
double erase_sleep = strtod(optarg, &parsed);
if (parsed == optarg) {
fprintf(stderr, "error: invalid erase-sleep: %s\n", optarg);
exit(-1);
}
test_erase_sleep = erase_sleep*1.0e9;
break;
// done parsing
case -1:;
goto getopt_done;
// unknown arg, getopt prints a message for us
default:;
exit(-1);
} }
} }
getopt_done: ; getopt_done:;
if (argc > optind) { if (argc > optind) {
// reset our test identifier list // reset our test identifier list