]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/ministat/ministat.c
Add two missing eventhandler.h headers
[FreeBSD/FreeBSD.git] / usr.bin / ministat / ministat.c
1 /*-
2  * SPDX-License-Identifier: Beerware
3  *
4  * ----------------------------------------------------------------------------
5  * "THE BEER-WARE LICENSE" (Revision 42):
6  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
7  * can do whatever you want with this stuff. If we meet some day, and you think
8  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
9  * ----------------------------------------------------------------------------
10  *
11  */
12
13 #include <sys/cdefs.h>
14 __FBSDID("$FreeBSD$");
15
16 #include <sys/capsicum.h>
17 #include <sys/ioctl.h>
18 #include <sys/queue.h>
19 #include <sys/ttycom.h>
20
21 #include <capsicum_helpers.h>
22 #include <ctype.h>
23 #include <err.h>
24 #include <errno.h>
25 #include <math.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 #define NSTUDENT 100
32 #define NCONF 6
33 static double const studentpct[] = { 80, 90, 95, 98, 99, 99.5 };
34 static double student[NSTUDENT + 1][NCONF] = {
35 /* inf */       {       1.282,  1.645,  1.960,  2.326,  2.576,  3.090  },
36 /* 1. */        {       3.078,  6.314,  12.706, 31.821, 63.657, 318.313  },
37 /* 2. */        {       1.886,  2.920,  4.303,  6.965,  9.925,  22.327  },
38 /* 3. */        {       1.638,  2.353,  3.182,  4.541,  5.841,  10.215  },
39 /* 4. */        {       1.533,  2.132,  2.776,  3.747,  4.604,  7.173  },
40 /* 5. */        {       1.476,  2.015,  2.571,  3.365,  4.032,  5.893  },
41 /* 6. */        {       1.440,  1.943,  2.447,  3.143,  3.707,  5.208  },
42 /* 7. */        {       1.415,  1.895,  2.365,  2.998,  3.499,  4.782  },
43 /* 8. */        {       1.397,  1.860,  2.306,  2.896,  3.355,  4.499  },
44 /* 9. */        {       1.383,  1.833,  2.262,  2.821,  3.250,  4.296  },
45 /* 10. */       {       1.372,  1.812,  2.228,  2.764,  3.169,  4.143  },
46 /* 11. */       {       1.363,  1.796,  2.201,  2.718,  3.106,  4.024  },
47 /* 12. */       {       1.356,  1.782,  2.179,  2.681,  3.055,  3.929  },
48 /* 13. */       {       1.350,  1.771,  2.160,  2.650,  3.012,  3.852  },
49 /* 14. */       {       1.345,  1.761,  2.145,  2.624,  2.977,  3.787  },
50 /* 15. */       {       1.341,  1.753,  2.131,  2.602,  2.947,  3.733  },
51 /* 16. */       {       1.337,  1.746,  2.120,  2.583,  2.921,  3.686  },
52 /* 17. */       {       1.333,  1.740,  2.110,  2.567,  2.898,  3.646  },
53 /* 18. */       {       1.330,  1.734,  2.101,  2.552,  2.878,  3.610  },
54 /* 19. */       {       1.328,  1.729,  2.093,  2.539,  2.861,  3.579  },
55 /* 20. */       {       1.325,  1.725,  2.086,  2.528,  2.845,  3.552  },
56 /* 21. */       {       1.323,  1.721,  2.080,  2.518,  2.831,  3.527  },
57 /* 22. */       {       1.321,  1.717,  2.074,  2.508,  2.819,  3.505  },
58 /* 23. */       {       1.319,  1.714,  2.069,  2.500,  2.807,  3.485  },
59 /* 24. */       {       1.318,  1.711,  2.064,  2.492,  2.797,  3.467  },
60 /* 25. */       {       1.316,  1.708,  2.060,  2.485,  2.787,  3.450  },
61 /* 26. */       {       1.315,  1.706,  2.056,  2.479,  2.779,  3.435  },
62 /* 27. */       {       1.314,  1.703,  2.052,  2.473,  2.771,  3.421  },
63 /* 28. */       {       1.313,  1.701,  2.048,  2.467,  2.763,  3.408  },
64 /* 29. */       {       1.311,  1.699,  2.045,  2.462,  2.756,  3.396  },
65 /* 30. */       {       1.310,  1.697,  2.042,  2.457,  2.750,  3.385  },
66 /* 31. */       {       1.309,  1.696,  2.040,  2.453,  2.744,  3.375  },
67 /* 32. */       {       1.309,  1.694,  2.037,  2.449,  2.738,  3.365  },
68 /* 33. */       {       1.308,  1.692,  2.035,  2.445,  2.733,  3.356  },
69 /* 34. */       {       1.307,  1.691,  2.032,  2.441,  2.728,  3.348  },
70 /* 35. */       {       1.306,  1.690,  2.030,  2.438,  2.724,  3.340  },
71 /* 36. */       {       1.306,  1.688,  2.028,  2.434,  2.719,  3.333  },
72 /* 37. */       {       1.305,  1.687,  2.026,  2.431,  2.715,  3.326  },
73 /* 38. */       {       1.304,  1.686,  2.024,  2.429,  2.712,  3.319  },
74 /* 39. */       {       1.304,  1.685,  2.023,  2.426,  2.708,  3.313  },
75 /* 40. */       {       1.303,  1.684,  2.021,  2.423,  2.704,  3.307  },
76 /* 41. */       {       1.303,  1.683,  2.020,  2.421,  2.701,  3.301  },
77 /* 42. */       {       1.302,  1.682,  2.018,  2.418,  2.698,  3.296  },
78 /* 43. */       {       1.302,  1.681,  2.017,  2.416,  2.695,  3.291  },
79 /* 44. */       {       1.301,  1.680,  2.015,  2.414,  2.692,  3.286  },
80 /* 45. */       {       1.301,  1.679,  2.014,  2.412,  2.690,  3.281  },
81 /* 46. */       {       1.300,  1.679,  2.013,  2.410,  2.687,  3.277  },
82 /* 47. */       {       1.300,  1.678,  2.012,  2.408,  2.685,  3.273  },
83 /* 48. */       {       1.299,  1.677,  2.011,  2.407,  2.682,  3.269  },
84 /* 49. */       {       1.299,  1.677,  2.010,  2.405,  2.680,  3.265  },
85 /* 50. */       {       1.299,  1.676,  2.009,  2.403,  2.678,  3.261  },
86 /* 51. */       {       1.298,  1.675,  2.008,  2.402,  2.676,  3.258  },
87 /* 52. */       {       1.298,  1.675,  2.007,  2.400,  2.674,  3.255  },
88 /* 53. */       {       1.298,  1.674,  2.006,  2.399,  2.672,  3.251  },
89 /* 54. */       {       1.297,  1.674,  2.005,  2.397,  2.670,  3.248  },
90 /* 55. */       {       1.297,  1.673,  2.004,  2.396,  2.668,  3.245  },
91 /* 56. */       {       1.297,  1.673,  2.003,  2.395,  2.667,  3.242  },
92 /* 57. */       {       1.297,  1.672,  2.002,  2.394,  2.665,  3.239  },
93 /* 58. */       {       1.296,  1.672,  2.002,  2.392,  2.663,  3.237  },
94 /* 59. */       {       1.296,  1.671,  2.001,  2.391,  2.662,  3.234  },
95 /* 60. */       {       1.296,  1.671,  2.000,  2.390,  2.660,  3.232  },
96 /* 61. */       {       1.296,  1.670,  2.000,  2.389,  2.659,  3.229  },
97 /* 62. */       {       1.295,  1.670,  1.999,  2.388,  2.657,  3.227  },
98 /* 63. */       {       1.295,  1.669,  1.998,  2.387,  2.656,  3.225  },
99 /* 64. */       {       1.295,  1.669,  1.998,  2.386,  2.655,  3.223  },
100 /* 65. */       {       1.295,  1.669,  1.997,  2.385,  2.654,  3.220  },
101 /* 66. */       {       1.295,  1.668,  1.997,  2.384,  2.652,  3.218  },
102 /* 67. */       {       1.294,  1.668,  1.996,  2.383,  2.651,  3.216  },
103 /* 68. */       {       1.294,  1.668,  1.995,  2.382,  2.650,  3.214  },
104 /* 69. */       {       1.294,  1.667,  1.995,  2.382,  2.649,  3.213  },
105 /* 70. */       {       1.294,  1.667,  1.994,  2.381,  2.648,  3.211  },
106 /* 71. */       {       1.294,  1.667,  1.994,  2.380,  2.647,  3.209  },
107 /* 72. */       {       1.293,  1.666,  1.993,  2.379,  2.646,  3.207  },
108 /* 73. */       {       1.293,  1.666,  1.993,  2.379,  2.645,  3.206  },
109 /* 74. */       {       1.293,  1.666,  1.993,  2.378,  2.644,  3.204  },
110 /* 75. */       {       1.293,  1.665,  1.992,  2.377,  2.643,  3.202  },
111 /* 76. */       {       1.293,  1.665,  1.992,  2.376,  2.642,  3.201  },
112 /* 77. */       {       1.293,  1.665,  1.991,  2.376,  2.641,  3.199  },
113 /* 78. */       {       1.292,  1.665,  1.991,  2.375,  2.640,  3.198  },
114 /* 79. */       {       1.292,  1.664,  1.990,  2.374,  2.640,  3.197  },
115 /* 80. */       {       1.292,  1.664,  1.990,  2.374,  2.639,  3.195  },
116 /* 81. */       {       1.292,  1.664,  1.990,  2.373,  2.638,  3.194  },
117 /* 82. */       {       1.292,  1.664,  1.989,  2.373,  2.637,  3.193  },
118 /* 83. */       {       1.292,  1.663,  1.989,  2.372,  2.636,  3.191  },
119 /* 84. */       {       1.292,  1.663,  1.989,  2.372,  2.636,  3.190  },
120 /* 85. */       {       1.292,  1.663,  1.988,  2.371,  2.635,  3.189  },
121 /* 86. */       {       1.291,  1.663,  1.988,  2.370,  2.634,  3.188  },
122 /* 87. */       {       1.291,  1.663,  1.988,  2.370,  2.634,  3.187  },
123 /* 88. */       {       1.291,  1.662,  1.987,  2.369,  2.633,  3.185  },
124 /* 89. */       {       1.291,  1.662,  1.987,  2.369,  2.632,  3.184  },
125 /* 90. */       {       1.291,  1.662,  1.987,  2.368,  2.632,  3.183  },
126 /* 91. */       {       1.291,  1.662,  1.986,  2.368,  2.631,  3.182  },
127 /* 92. */       {       1.291,  1.662,  1.986,  2.368,  2.630,  3.181  },
128 /* 93. */       {       1.291,  1.661,  1.986,  2.367,  2.630,  3.180  },
129 /* 94. */       {       1.291,  1.661,  1.986,  2.367,  2.629,  3.179  },
130 /* 95. */       {       1.291,  1.661,  1.985,  2.366,  2.629,  3.178  },
131 /* 96. */       {       1.290,  1.661,  1.985,  2.366,  2.628,  3.177  },
132 /* 97. */       {       1.290,  1.661,  1.985,  2.365,  2.627,  3.176  },
133 /* 98. */       {       1.290,  1.661,  1.984,  2.365,  2.627,  3.175  },
134 /* 99. */       {       1.290,  1.660,  1.984,  2.365,  2.626,  3.175  },
135 /* 100. */      {       1.290,  1.660,  1.984,  2.364,  2.626,  3.174  }
136 };
137
138 #define MAX_DS  8
139 static char symbol[MAX_DS] = { ' ', 'x', '+', '*', '%', '#', '@', 'O' };
140
141 struct dataset {
142         char *name;
143         double  *points;
144         unsigned lpoints;
145         double sy, syy;
146         unsigned n;
147 };
148
149 static struct dataset *
150 NewSet(void)
151 {
152         struct dataset *ds;
153
154         ds = calloc(1, sizeof *ds);
155         ds->lpoints = 100000;
156         ds->points = calloc(sizeof *ds->points, ds->lpoints);
157         return(ds);
158 }
159
160 static void
161 AddPoint(struct dataset *ds, double a)
162 {
163         double *dp;
164
165         if (ds->n >= ds->lpoints) {
166                 dp = ds->points;
167                 ds->lpoints *= 4;
168                 ds->points = calloc(sizeof *ds->points, ds->lpoints);
169                 memcpy(ds->points, dp, sizeof *dp * ds->n);
170                 free(dp);
171         }
172         ds->points[ds->n++] = a;
173         ds->sy += a;
174         ds->syy += a * a;
175 }
176
177 static double
178 Min(struct dataset *ds)
179 {
180
181         return (ds->points[0]);
182 }
183
184 static double
185 Max(struct dataset *ds)
186 {
187
188         return (ds->points[ds->n -1]);
189 }
190
191 static double
192 Avg(struct dataset *ds)
193 {
194
195         return(ds->sy / ds->n);
196 }
197
198 static double
199 Median(struct dataset *ds)
200 {
201         if ((ds->n % 2) == 0)
202                 return ((ds->points[ds->n / 2] + (ds->points[(ds->n / 2) - 1])) / 2);
203         else
204                 return (ds->points[ds->n / 2]);
205 }
206
207 static double
208 Var(struct dataset *ds)
209 {
210
211         /*
212          * Due to limited precision it is possible that sy^2/n > syy,
213          * but variance cannot actually be negative.
214          */
215         if (ds->syy <= ds->sy * ds->sy / ds->n)
216                 return (0);
217         return (ds->syy - ds->sy * ds->sy / ds->n) / (ds->n - 1.0);
218 }
219
220 static double
221 Stddev(struct dataset *ds)
222 {
223
224         return sqrt(Var(ds));
225 }
226
227 static void
228 VitalsHead(void)
229 {
230
231         printf("    N           Min           Max        Median           Avg        Stddev\n");
232 }
233
234 static void
235 Vitals(struct dataset *ds, int flag)
236 {
237
238         printf("%c %3d %13.8g %13.8g %13.8g %13.8g %13.8g", symbol[flag],
239             ds->n, Min(ds), Max(ds), Median(ds), Avg(ds), Stddev(ds));
240         printf("\n");
241 }
242
243 static void
244 Relative(struct dataset *ds, struct dataset *rs, int confidx)
245 {
246         double spool, s, d, e, t;
247         double re;
248         int i;
249
250         i = ds->n + rs->n - 2;
251         if (i > NSTUDENT)
252                 t = student[0][confidx];
253         else
254                 t = student[i][confidx];
255         spool = (ds->n - 1) * Var(ds) + (rs->n - 1) * Var(rs);
256         spool /= ds->n + rs->n - 2;
257         spool = sqrt(spool);
258         s = spool * sqrt(1.0 / ds->n + 1.0 / rs->n);
259         d = Avg(ds) - Avg(rs);
260         e = t * s;
261
262         re = (ds->n - 1) * Var(ds) + (rs->n - 1) * Var(rs) *
263             (Avg(ds) * Avg(ds)) / (Avg(rs) * Avg(rs));
264         re *= (ds->n + rs->n) / (ds->n * rs->n * (ds->n + rs->n - 2.0));
265         re = t * sqrt(re);
266
267         if (fabs(d) > e) {
268         
269                 printf("Difference at %.1f%% confidence\n", studentpct[confidx]);
270                 printf("        %g +/- %g\n", d, e);
271                 printf("        %g%% +/- %g%%\n", d * 100 / Avg(rs), re * 100 / Avg(rs));
272                 printf("        (Student's t, pooled s = %g)\n", spool);
273         } else {
274                 printf("No difference proven at %.1f%% confidence\n",
275                     studentpct[confidx]);
276         }
277 }
278
279 struct plot {
280         double          min;
281         double          max;
282         double          span;
283         int             width;
284
285         double          x0, dx;
286         int             height;
287         char            *data;
288         char            **bar;
289         int             separate_bars;
290         int             num_datasets;
291 };
292
293 static struct plot plot;
294
295 static void
296 SetupPlot(int width, int separate, int num_datasets)
297 {
298         struct plot *pl;
299
300         pl = &plot;
301         pl->width = width;
302         pl->height = 0;
303         pl->data = NULL;
304         pl->bar = NULL;
305         pl->separate_bars = separate;
306         pl->num_datasets = num_datasets;
307         pl->min = 999e99;
308         pl->max = -999e99;
309 }
310
311 static void
312 AdjPlot(double a)
313 {
314         struct plot *pl;
315
316         pl = &plot;
317         if (a < pl->min)
318                 pl->min = a;
319         if (a > pl->max)
320                 pl->max = a;
321         pl->span = pl->max - pl->min;
322         pl->dx = pl->span / (pl->width - 1.0);
323         pl->x0 = pl->min - .5 * pl->dx;
324 }
325
326 static void
327 DimPlot(struct dataset *ds)
328 {
329         AdjPlot(Min(ds));
330         AdjPlot(Max(ds));
331         AdjPlot(Avg(ds) - Stddev(ds));
332         AdjPlot(Avg(ds) + Stddev(ds));
333 }
334
335 static void
336 PlotSet(struct dataset *ds, int val)
337 {
338         struct plot *pl;
339         int i, j, m, x;
340         unsigned n;
341         int bar;
342
343         pl = &plot;
344         if (pl->span == 0)
345                 return;
346
347         if (pl->separate_bars)
348                 bar = val-1;
349         else
350                 bar = 0;
351
352         if (pl->bar == NULL)
353                 pl->bar = calloc(sizeof(char *), pl->num_datasets);
354         if (pl->bar[bar] == NULL) {
355                 pl->bar[bar] = malloc(pl->width);
356                 memset(pl->bar[bar], 0, pl->width);
357         }
358         
359         m = 1;
360         i = -1;
361         j = 0;
362         for (n = 0; n < ds->n; n++) {
363                 x = (ds->points[n] - pl->x0) / pl->dx;
364                 if (x == i) {
365                         j++;
366                         if (j > m)
367                                 m = j;
368                 } else {
369                         j = 1;
370                         i = x;
371                 }
372         }
373         m += 1;
374         if (m > pl->height) {
375                 pl->data = realloc(pl->data, pl->width * m);
376                 memset(pl->data + pl->height * pl->width, 0,
377                     (m - pl->height) * pl->width);
378         }
379         pl->height = m;
380         i = -1;
381         for (n = 0; n < ds->n; n++) {
382                 x = (ds->points[n] - pl->x0) / pl->dx;
383                 if (x == i) {
384                         j++;
385                 } else {
386                         j = 1;
387                         i = x;
388                 }
389                 pl->data[j * pl->width + x] |= val;
390         }
391         if (!isnan(Stddev(ds))) {
392                 x = ((Avg(ds) - Stddev(ds)) - pl->x0) / pl->dx;
393                 m = ((Avg(ds) + Stddev(ds)) - pl->x0) / pl->dx;
394                 pl->bar[bar][m] = '|';
395                 pl->bar[bar][x] = '|';
396                 for (i = x + 1; i < m; i++)
397                         if (pl->bar[bar][i] == 0)
398                                 pl->bar[bar][i] = '_';
399         }
400         x = (Median(ds) - pl->x0) / pl->dx;
401         pl->bar[bar][x] = 'M';
402         x = (Avg(ds) - pl->x0) / pl->dx;
403         pl->bar[bar][x] = 'A';
404 }
405
406 static void
407 DumpPlot(void)
408 {
409         struct plot *pl;
410         int i, j, k;
411
412         pl = &plot;
413         if (pl->span == 0) {
414                 printf("[no plot, span is zero width]\n");
415                 return;
416         }
417
418         putchar('+');
419         for (i = 0; i < pl->width; i++)
420                 putchar('-');
421         putchar('+');
422         putchar('\n');
423         for (i = 1; i < pl->height; i++) {
424                 putchar('|');
425                 for (j = 0; j < pl->width; j++) {
426                         k = pl->data[(pl->height - i) * pl->width + j];
427                         if (k >= 0 && k < MAX_DS)
428                                 putchar(symbol[k]);
429                         else
430                                 printf("[%02x]", k);
431                 }
432                 putchar('|');
433                 putchar('\n');
434         }
435         for (i = 0; i < pl->num_datasets; i++) {
436                 if (pl->bar[i] == NULL)
437                         continue;
438                 putchar('|');
439                 for (j = 0; j < pl->width; j++) {
440                         k = pl->bar[i][j];
441                         if (k == 0)
442                                 k = ' ';
443                         putchar(k);
444                 }
445                 putchar('|');
446                 putchar('\n');
447         }
448         putchar('+');
449         for (i = 0; i < pl->width; i++)
450                 putchar('-');
451         putchar('+');
452         putchar('\n');
453 }
454
455 static int
456 dbl_cmp(const void *a, const void *b)
457 {
458         const double *aa = a;
459         const double *bb = b;
460
461         if (*aa < *bb)
462                 return (-1);
463         else if (*aa > *bb)
464                 return (1);
465         else
466                 return (0);
467 }
468
469 static struct dataset *
470 ReadSet(FILE *f, const char *n, int column, const char *delim)
471 {
472         char buf[BUFSIZ], *p, *t;
473         struct dataset *s;
474         double d;
475         int line;
476         int i;
477
478         s = NewSet();
479         s->name = strdup(n);
480         line = 0;
481         while (fgets(buf, sizeof buf, f) != NULL) {
482                 line++;
483
484                 i = strlen(buf);
485                 while (i > 0 && isspace(buf[i - 1]))
486                         buf[--i] = '\0';
487                 for (i = 1, t = strtok(buf, delim);
488                      t != NULL && *t != '#';
489                      i++, t = strtok(NULL, delim)) {
490                         if (i == column)
491                                 break;
492                 }
493                 if (t == NULL || *t == '#')
494                         continue;
495
496                 d = strtod(t, &p);
497                 if (p != NULL && *p != '\0')
498                         errx(2, "Invalid data on line %d in %s", line, n);
499                 if (*buf != '\0')
500                         AddPoint(s, d);
501         }
502         if (s->n < 3) {
503                 fprintf(stderr,
504                     "Dataset %s must contain at least 3 data points\n", n);
505                 exit (2);
506         }
507         qsort(s->points, s->n, sizeof *s->points, dbl_cmp);
508         return (s);
509 }
510
511 static void
512 usage(char const *whine)
513 {
514         int i;
515
516         fprintf(stderr, "%s\n", whine);
517         fprintf(stderr,
518             "Usage: ministat [-C column] [-c confidence] [-d delimiter(s)] [-Ans] [-w width] [file [file ...]]\n");
519         fprintf(stderr, "\tconfidence = {");
520         for (i = 0; i < NCONF; i++) {
521                 fprintf(stderr, "%s%g%%",
522                     i ? ", " : "",
523                     studentpct[i]);
524         }
525         fprintf(stderr, "}\n");
526         fprintf(stderr, "\t-A : print statistics only. suppress the graph.\n");
527         fprintf(stderr, "\t-C : column number to extract (starts and defaults to 1)\n");
528         fprintf(stderr, "\t-d : delimiter(s) string, default to \" \\t\"\n");
529         fprintf(stderr, "\t-n : print summary statistics only, no graph/test\n");
530         fprintf(stderr, "\t-s : print avg/median/stddev bars on separate lines\n");
531         fprintf(stderr, "\t-w : width of graph/test output (default 74 or terminal width)\n");
532         exit (2);
533 }
534
535 int
536 main(int argc, char **argv)
537 {
538         const char *setfilenames[MAX_DS - 1];
539         struct dataset *ds[MAX_DS - 1];
540         FILE *setfiles[MAX_DS - 1];
541         int nds;
542         double a;
543         const char *delim = " \t";
544         char *p;
545         int c, i, ci;
546         int column = 1;
547         int flag_s = 0;
548         int flag_n = 0;
549         int termwidth = 74;
550         int suppress_plot = 0;
551
552         if (isatty(STDOUT_FILENO)) {
553                 struct winsize wsz;
554
555                 if ((p = getenv("COLUMNS")) != NULL && *p != '\0')
556                         termwidth = atoi(p);
557                 else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsz) != -1 &&
558                          wsz.ws_col > 0)
559                         termwidth = wsz.ws_col - 2;
560         }
561
562         ci = -1;
563         while ((c = getopt(argc, argv, "AC:c:d:snw:")) != -1)
564                 switch (c) {
565                 case 'A':
566                         suppress_plot = 1;
567                         break;
568                 case 'C':
569                         column = strtol(optarg, &p, 10);
570                         if (p != NULL && *p != '\0')
571                                 usage("Invalid column number.");
572                         if (column <= 0)
573                                 usage("Column number should be positive.");
574                         break;
575                 case 'c':
576                         a = strtod(optarg, &p);
577                         if (p != NULL && *p != '\0')
578                                 usage("Not a floating point number");
579                         for (i = 0; i < NCONF; i++)
580                                 if (a == studentpct[i])
581                                         ci = i;
582                         if (ci == -1)
583                                 usage("No support for confidence level");
584                         break;
585                 case 'd':
586                         if (*optarg == '\0')
587                                 usage("Can't use empty delimiter string");
588                         delim = optarg;
589                         break;
590                 case 'n':
591                         flag_n = 1;
592                         break;
593                 case 's':
594                         flag_s = 1;
595                         break;
596                 case 'w':
597                         termwidth = strtol(optarg, &p, 10);
598                         if (p != NULL && *p != '\0')
599                                 usage("Invalid width, not a number.");
600                         if (termwidth < 0)
601                                 usage("Unable to move beyond left margin.");
602                         break;
603                 default:
604                         usage("Unknown option");
605                         break;
606                 }
607         if (ci == -1)
608                 ci = 2;
609         argc -= optind;
610         argv += optind;
611
612         if (argc == 0) {
613                 setfilenames[0] = "<stdin>";
614                 setfiles[0] = stdin;
615                 nds = 1;
616         } else {
617                 if (argc > (MAX_DS - 1))
618                         usage("Too many datasets.");
619                 nds = argc;
620                 for (i = 0; i < nds; i++) {
621                         setfilenames[i] = argv[i];
622                         setfiles[i] = fopen(argv[i], "r");
623                         if (setfiles[i] == NULL)
624                                 err(2, "Cannot open %s", argv[i]);
625                 }
626         }
627
628         if (caph_limit_stdio() < 0)
629                 err(2, "capsicum");
630
631         for (i = 0; i < nds; i++)
632                 if (caph_limit_stream(fileno(setfiles[i]), CAPH_READ) < 0)
633                         err(2, "unable to limit rights for %s",
634                             setfilenames[i]);
635
636         /* Enter Capsicum sandbox. */
637         if (caph_enter() < 0)
638                 err(2, "unable to enter capability mode");
639
640         for (i = 0; i < nds; i++) {
641                 ds[i] = ReadSet(setfiles[i], setfilenames[i], column, delim);
642                 fclose(setfiles[i]);
643         }
644
645         for (i = 0; i < nds; i++) 
646                 printf("%c %s\n", symbol[i+1], ds[i]->name);
647
648         if (!flag_n && !suppress_plot) {
649                 SetupPlot(termwidth, flag_s, nds);
650                 for (i = 0; i < nds; i++)
651                         DimPlot(ds[i]);
652                 for (i = 0; i < nds; i++)
653                         PlotSet(ds[i], i + 1);
654                 DumpPlot();
655         }
656         VitalsHead();
657         Vitals(ds[0], 1);
658         for (i = 1; i < nds; i++) {
659                 Vitals(ds[i], i + 1);
660                 if (!flag_n)
661                         Relative(ds[i], ds[0], ci);
662         }
663         exit(0);
664 }