rangetest.c (2170B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <err.h> 4 #include <limits.h> 5 #include <string.h> 6 #include <unistd.h> 7 8 #include "util.h" 9 10 #define VALUESTR "@VAL@" 11 12 static void 13 usage(void) 14 { 15 errx(1, "usage: rangetest [-n maxiter] cmd min_val max_val\n" 16 "where cmd must contain the string '" VALUESTR "'"); 17 } 18 19 static int 20 launch(char *cmd, char *cmd0, double val) 21 { 22 char *c; 23 24 if ((c = strstr(cmd0, VALUESTR)) == NULL) 25 errx(1, VALUESTR " not found in cmd"); 26 if (strlcpy(cmd, cmd0, PATH_MAX) >= PATH_MAX) 27 err(1, "cmd too long"); 28 sprintf(cmd + (c - cmd0), "%.17g%s >/dev/null", 29 val, c + strnlen(VALUESTR, sizeof(cmd))); 30 if (system(cmd)) { 31 fprintf(stderr, "%.17g\n", val); 32 return 1; 33 } else 34 printf("%.17g\n", val); 35 36 return 0; 37 } 38 39 static void 40 binary_search(char *cmd, char *cmd0, double minv, double maxv, int maxiter) 41 { 42 int minfail, maxfail, iter = 0; 43 double val; 44 45 minfail = launch(cmd, cmd0, minv); 46 maxfail = launch(cmd, cmd0, maxv); 47 if (minfail && maxfail) 48 errx(2, "both min_val and max_val runs errored"); 49 else if (!minfail && !maxfail) 50 errx(3, "both min_val and max_val ran successfully"); 51 52 while (minv <= maxv && iter < maxiter) { 53 val = minv + 0.5 * (maxv - minv); 54 if (launch(cmd, cmd0, val)) { 55 if (maxfail) { 56 maxv = val; 57 maxfail = 1; 58 } else { 59 minv = val; 60 } 61 } else { 62 if (maxfail) { 63 minv = val; 64 } else { 65 maxv = val; 66 maxfail = 0; 67 } 68 } 69 iter++; 70 } 71 } 72 73 int 74 main(int argc, char *argv[]) 75 { 76 int ch, maxiter = 10; 77 double minv, maxv; 78 char cmd0[PATH_MAX] = "", cmd[PATH_MAX] = ""; 79 const char *errstr; 80 81 while ((ch = getopt(argc, argv, "N:")) != -1) { 82 switch (ch) { 83 case 'N': 84 maxiter = strtonum(optarg, 0, INT_MAX, &errstr); 85 if (errstr != NULL) 86 errx(1, "bad maxiter value, %s: %s", errstr, optarg); 87 break; 88 default: 89 usage(); 90 } 91 } 92 argc -= optind; 93 argv += optind; 94 if (argc == 3) { 95 if (strlcpy(cmd0, argv[0], sizeof(cmd0)) >= sizeof(cmd0)) 96 err(1, "cmd too long"); 97 minv = atof(argv[1]); 98 maxv = atof(argv[2]); 99 if (minv >= maxv) 100 errx(1, "min_val must be smaller than max_val"); 101 binary_search(cmd, cmd0, minv, maxv, maxiter); 102 } else 103 usage(); 104 105 return 0; 106 }