1/*
2 * Legal Notice
3 *
4 * This document and associated source code (the "Work") is a part of a
5 * benchmark specification maintained by the TPC.
6 *
7 * The TPC reserves all right, title, and interest to the Work as provided
8 * under U.S. and international laws, including without limitation all patent
9 * and trademark rights therein.
10 *
11 * No Warranty
12 *
13 * 1.1 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE INFORMATION
14 * CONTAINED HEREIN IS PROVIDED "AS IS" AND WITH ALL FAULTS, AND THE
15 * AUTHORS AND DEVELOPERS OF THE WORK HEREBY DISCLAIM ALL OTHER
16 * WARRANTIES AND CONDITIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
17 * INCLUDING, BUT NOT LIMITED TO, ANY (IF ANY) IMPLIED WARRANTIES,
18 * DUTIES OR CONDITIONS OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR
19 * PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OF
20 * WORKMANLIKE EFFORT, OF LACK OF VIRUSES, AND OF LACK OF NEGLIGENCE.
21 * ALSO, THERE IS NO WARRANTY OR CONDITION OF TITLE, QUIET ENJOYMENT,
22 * QUIET POSSESSION, CORRESPONDENCE TO DESCRIPTION OR NON-INFRINGEMENT
23 * WITH REGARD TO THE WORK.
24 * 1.2 IN NO EVENT WILL ANY AUTHOR OR DEVELOPER OF THE WORK BE LIABLE TO
25 * ANY OTHER PARTY FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO THE
26 * COST OF PROCURING SUBSTITUTE GOODS OR SERVICES, LOST PROFITS, LOSS
27 * OF USE, LOSS OF DATA, OR ANY INCIDENTAL, CONSEQUENTIAL, DIRECT,
28 * INDIRECT, OR SPECIAL DAMAGES WHETHER UNDER CONTRACT, TORT, WARRANTY,
29 * OR OTHERWISE, ARISING IN ANY WAY OUT OF THIS OR ANY OTHER AGREEMENT
30 * RELATING TO THE WORK, WHETHER OR NOT SUCH AUTHOR OR DEVELOPER HAD
31 * ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.
32 *
33 * Contributors:
34 * Gradient Systems
35 */
36/*
37 * parameter handling functions
38 */
39#include <stdlib.h>
40#include <string.h>
41#include <stdio.h>
42#include <time.h>
43#include "config.h"
44#include "porting.h"
45#include "r_params.h"
46#include "tdefs.h"
47#include "release.h"
48
49#define PARAM_MAX_LEN 80
50
51#ifndef TEST
52extern option_t options[];
53extern char *params[];
54#else
55option_t options[] = {{"PROG", OPT_STR | OPT_HIDE, 0, NULL, NULL, "tester"},
56 {"PARAMS", OPT_STR, 1, "read parameters from file <s>", read_file, ""},
57 {"DISTRIBUTIONS", OPT_STR, 2, "read distributions from file <s>", NULL, "tester_dist.idx"},
58 {"OUTDIR", OPT_STR, 3, "generate files in directory <s>", NULL, "./"},
59 {"VERBOSE", OPT_FLG, 4, "enable verbose output", NULL, "N"},
60 {"HELP", OPT_FLG, 5, "display this message", usage, "N"},
61 {"scale", OPT_INT, 6, "set scale to <i>", NULL, "1"},
62 NULL};
63char *params[9];
64#endif
65
66static int param_init = 0;
67
68#define MAX_LINE_LEN 120
69#ifdef WIN32
70#define OPTION_START '/'
71#else
72#define OPTION_START '-'
73#endif
74
75int read_file(char *param_name, char *option);
76int fnd_param(char *name);
77void print_params(void);
78
79/*
80 * Routine: load_params()
81 * Purpose:
82 * Algorithm:
83 * Data Structures:
84 *
85 * Params:
86 * Returns:
87 * Called By:
88 * Calls:
89 * Assumptions:
90 * Side Effects:
91 * TODO:
92 * 20010621 JMS shared memory not yet implemented
93 */
94void load_params() {
95 /*
96 int i=0;
97 while (options[i].name != NULL)
98 {
99 load_param(i, GetSharedMemoryParam(options[i].index));
100 i++;
101 }
102 SetSharedMemoryStat(STAT_ROWCOUNT, get_int("STEP"), 0);
103 */
104 return;
105}
106
107/*
108 * Routine: set_flag(int f)
109 * Purpose: set a toggle parameter
110 * Algorithm:
111 * Data Structures:
112 *
113 * Params:
114 * Returns:
115 * Called By:
116 * Calls:
117 * Assumptions:
118 * Side Effects:
119 * TODO: None
120 */
121void set_flg(char *flag) {
122 int nParam;
123
124 init_params();
125 nParam = fnd_param(flag);
126 if (nParam >= 0)
127 strcpy(params[options[nParam].index], "Y");
128
129 return;
130}
131
132/*
133 * Routine: clr_flg(f)
134 * Purpose: clear a toggle parameter
135 * Algorithm:
136 * Data Structures:
137 *
138 * Params:
139 * Returns:
140 * Called By:
141 * Calls:
142 * Assumptions:
143 * Side Effects:
144 * TODO: None
145 */
146void clr_flg(char *flag) {
147 int nParam;
148
149 init_params();
150 nParam = fnd_param(flag);
151 if (nParam >= 0)
152 strcpy(params[options[nParam].index], "N");
153 return;
154}
155
156/*
157 * Routine: is_set(int f)
158 * Purpose: return the state of a toggle parameter, or whether or not a string
159 * or int parameter has been set Algorithm: Data Structures:
160 *
161 * Params:
162 * Returns:
163 * Called By:
164 * Calls:
165 * Assumptions:
166 * Side Effects:
167 * TODO: None
168 */
169int is_set(char *flag) {
170 int nParam, bIsSet = 0;
171
172 init_params();
173 nParam = fnd_param(flag);
174 if (nParam >= 0) {
175 if ((options[nParam].flags & TYPE_MASK) == OPT_FLG)
176 bIsSet = (params[options[nParam].index][0] == 'Y') ? 1 : 0;
177 else
178 bIsSet = (options[nParam].flags & OPT_SET) || (strlen(options[nParam].dflt) > 0);
179 }
180
181 return (bIsSet); /* better a false negative than a false positive ? */
182}
183
184/*
185 * Routine: set_int(int var, char *value)
186 * Purpose: set an integer parameter
187 * Algorithm:
188 * Data Structures:
189 *
190 * Params:
191 * Returns:
192 * Called By:
193 * Calls:
194 * Assumptions:
195 * Side Effects:
196 * TODO: None
197 */
198void set_int(char *var, char *val) {
199 int nParam;
200
201 init_params();
202 nParam = fnd_param(var);
203 if (nParam >= 0) {
204 strcpy(params[options[nParam].index], val);
205 options[nParam].flags |= OPT_SET;
206 }
207 return;
208}
209
210/*
211 * Routine: get_int(char *var)
212 * Purpose: return the value of an integer parameter
213 * Algorithm:
214 * Data Structures:
215 *
216 * Params:
217 * Returns:
218 * Called By:
219 * Calls:
220 * Assumptions:
221 * Side Effects:
222 * TODO: None
223 */
224int get_int(char *var) {
225 int nParam;
226
227 init_params();
228 nParam = fnd_param(var);
229 if (nParam >= 0)
230 return (atoi(params[options[nParam].index]));
231 else
232 return (0);
233}
234
235/*
236 * Routine: set_str(int var, char *value)
237 * Purpose: set a character parameter
238 * Algorithm:
239 * Data Structures:
240 *
241 * Params:
242 * Returns:
243 * Called By:
244 * Calls:
245 * Assumptions:
246 * Side Effects:
247 * TODO: None
248 */
249void set_str(char *var, char *val) {
250 int nParam;
251
252 init_params();
253 nParam = fnd_param(var);
254 if (nParam >= 0) {
255 strcpy(params[options[nParam].index], val);
256 options[nParam].flags |= OPT_SET;
257 }
258
259 return;
260}
261
262/*
263 * Routine: get_str(char * var)
264 * Purpose: return the value of a character parameter
265 * Algorithm:
266 * Data Structures:
267 *
268 * Params:
269 * Returns:
270 * Called By:
271 * Calls:
272 * Assumptions:
273 * Side Effects:
274 * TODO: None
275 */
276char *get_str(char *var) {
277 int nParam;
278
279 init_params();
280 nParam = fnd_param(var);
281 if (nParam >= 0)
282 return (params[options[nParam].index]);
283 else
284 return (NULL);
285}
286
287/*
288 * Routine: init_params(void)
289 * Purpose: initialize a parameter set, setting default values
290 * Algorithm:
291 * Data Structures:
292 *
293 * Params:
294 * Returns:
295 * Called By:
296 * Calls:
297 * Assumptions:
298 * Side Effects:
299 * TODO: None
300 */
301int init_params(void) {
302 int i;
303 static int init = 0;
304
305 if (init)
306 return (0);
307
308 for (i = 0; options[i].name != NULL; i++) {
309 params[options[i].index] = (char *)malloc(PARAM_MAX_LEN * sizeof(char));
310 MALLOC_CHECK(params[options[i].index]);
311 strncpy(params[options[i].index], options[i].dflt, 80);
312 if (*options[i].dflt)
313 options[i].flags |= OPT_DFLT;
314 }
315
316 init = 1;
317 param_init = 1;
318
319 return (0);
320}
321
322/*
323 * Routine: print_options(struct OPTION_T *o, int file, int depth)
324 * Purpose: print a summary of options
325 * Algorithm:
326 * Data Structures:
327 *
328 * Params:
329 * Returns:
330 * Called By:
331 * Calls:
332 * Assumptions:
333 * Side Effects:
334 * TODO: None
335 */
336static void print_options(struct OPTION_T *o, int bShowOptional) {
337 int i, w_adjust, bShow = 0, nCount = 0;
338
339 for (i = 0; options[i].name != NULL; i++) {
340 /*
341 * options come in two groups, general and "hidden". Decide which group
342 * to show in this pass, and ignore others
343 */
344 bShow = 0;
345 if (bShowOptional && (o[i].flags & OPT_ADV))
346 bShow = 1;
347 if (!bShowOptional && !(o[i].flags & OPT_ADV))
348 bShow = 1;
349
350 if (!bShow || (o[i].flags & OPT_HIDE))
351 continue;
352
353 nCount += 1;
354 printf("%s = ", o[i].name);
355 w_adjust = 15 - strlen(o[i].name);
356 if (o[i].flags & OPT_INT)
357 printf(" <n> ");
358 else if (o[i].flags & OPT_STR)
359 printf(" <s> ");
360 else if (o[i].flags & OPT_SUB)
361 printf(" <opt> ");
362 else if (o[i].flags & OPT_FLG)
363 printf(" [Y|N] ");
364 else
365 printf(" ");
366 printf("%*s-- %s", w_adjust, " ", o[i].usage);
367 if (o[i].flags & OPT_NOP)
368 printf(" NOT IMPLEMENTED");
369 printf("\n");
370 }
371
372 if (nCount == 0)
373 printf("None defined.\n");
374
375 return;
376}
377/*
378 * Routine: save_file(char *path)
379 * Purpose: print a summary of options
380 * Algorithm:
381 * Data Structures:
382 *
383 * Params:
384 * Returns:
385 * Called By:
386 * Calls:
387 * Assumptions:
388 * Side Effects:
389 * TODO: None
390 */
391int save_file(char *path) {
392 int i, w_adjust;
393 FILE *ofp;
394 time_t timestamp;
395
396 init_params();
397 time(&timestamp);
398
399 if ((ofp = fopen(path, "w")) == NULL)
400 return (-1);
401
402 fprintf(ofp, "--\n-- %s Benchmark Parameter File\n-- Created: %s", get_str("PROG"), ctime(&timestamp));
403 fprintf(ofp, "--\n-- Each entry is of the form: '<parameter> = <value> -- "
404 "optional comment'\n");
405 fprintf(ofp, "-- Refer to benchmark documentation for more details\n--\n");
406
407 for (i = 0; options[i].name != NULL; i++) {
408 if (options[i].flags & OPT_HIDE) /* hidden option */
409 continue;
410 if (strlen(params[options[i].index]) == 0)
411 continue;
412
413 fprintf(ofp, "%s = ", options[i].name);
414 w_adjust = strlen(options[i].name) + 3;
415 if (options[i].flags & OPT_STR) {
416 fprintf(ofp, "\"%s\"", params[options[i].index]);
417 w_adjust += 2;
418 } else
419 fprintf(ofp, "%s", params[options[i].index]);
420 w_adjust += strlen(params[options[i].index]) + 3;
421 w_adjust = 60 - w_adjust;
422 fprintf(ofp, "%*s-- %s", w_adjust, " ", options[i].usage);
423 if (options[i].flags & OPT_NOP)
424 fprintf(ofp, " NOT IMPLEMENTED");
425 fprintf(ofp, "\n");
426 }
427
428 fclose(ofp);
429
430 return (0);
431}
432
433/*
434 * Routine: usage(char *param_name, char *msg)
435 * Purpose: display a usage message, with an optional error message
436 * Algorithm:
437 * Data Structures:
438 *
439 * Params:
440 * Returns:
441 * Called By:
442 * Calls:
443 * Assumptions:
444 * Side Effects:
445 * TODO: None
446 */
447int usage(char *param_name, char *msg) {
448 init_params();
449
450 fprintf(stderr, "%s Population Generator (Version %d.%d.%d%s)\n", get_str("PROG"), VERSION, RELEASE, MODIFICATION,
451 PATCH);
452 fprintf(stderr, "Copyright %s %s\n", COPYRIGHT, C_DATES);
453
454 if (msg != NULL)
455 printf("\nERROR: %s\n\n", msg);
456
457 printf("\n\nUSAGE: %s [options]\n", get_str("PROG"));
458 printf("\nNote: When defined in a parameter file (using -p), parmeters "
459 "should\n");
460 printf("use the form below. Each option can also be set from the command\n");
461 printf("line, using a form of '%cparam [optional argument]'\n", OPTION_START);
462 printf("Unique anchored substrings of options are also recognized, and \n");
463 printf("case is ignored, so '%csc' is equivalent to '%cSCALE'\n\n", OPTION_START, OPTION_START);
464 printf("General Options\n===============\n");
465 print_options(options, 0);
466 printf("\n");
467 printf("Advanced Options\n===============\n");
468 print_options(options, 1);
469 printf("\n");
470 exit((msg == NULL) ? 0 : 1);
471}
472
473/*
474 * Routine: set_option(int var, char *value)
475 * Purpose: set a particular parameter; main entry point for the module
476 * Algorithm:
477 * Data Structures:
478 *
479 * Params:
480 * Returns:
481 * Called By:
482 * Calls:
483 * Assumptions:
484 * Side Effects:
485 * TODO: None
486 */
487int set_option(char *name, char *param) {
488 int res = 1;
489 option_t *o;
490 char parse_int[15];
491 char *cp;
492
493 init_params();
494
495 res = fnd_param(name);
496 if (res == -1)
497 return (res);
498
499 o = &options[res];
500
501 if (o->flags & OPT_NOP) {
502 printf("ERROR: Cannot accept %s.\tNot Implemented!\n", o->name);
503 return (0);
504 }
505
506 /* option is already set from the command line or hard-coded */
507 /* and doesn't allow multiple settings */
508
509 switch (o->flags & TYPE_MASK) {
510 case OPT_FLG:
511 if ((param && (*param == 'Y' || *param == 'Y' || *param == OPTION_START)) || (param == NULL)) {
512 if (o->action)
513 if (o->action(o->name, NULL) < 0)
514 usage(o->name, "Cannot process option");
515 set_flg(name);
516 } else
517 clr_flg(name);
518 res = 1;
519 break;
520 case OPT_INT:
521 if (o->action) {
522 if ((res = o->action(o->name, param)) < 0)
523 usage(NULL, "Bad parameter argument");
524 else
525 sprintf(parse_int, "%d", res);
526 }
527 set_int(name, (o->action) ? parse_int : param);
528 res = 2;
529 break;
530 case OPT_STR:
531 if (*param == '"') {
532 cp = strchr((param + 1), '"');
533 if (cp == NULL) /* non-terminated string literal */
534 usage(NULL, "Non-terminated string");
535 *cp = '\0';
536 param += 1;
537 } else {
538 cp = strpbrk(param, " \t\n");
539 if (cp != NULL)
540 *cp = '\0';
541 }
542 if (o->action && strlen(param))
543 if (o->action(o->name, param) < 0)
544 usage(o->name, "Cannot process option");
545 set_str(name, param);
546 res = 2;
547 break;
548 default:
549 fprintf(stderr, "Invalid option/type (%d/%s)\n", o->flags & TYPE_MASK, o->name);
550 exit(0);
551 break;
552 }
553
554 o->flags |= OPT_SET; /* marked as set */
555
556 return (res);
557}
558
559/*
560 * Routine: process_options(int count, char **vector)
561 * Purpose: process a set of command line options
562 * Algorithm:
563 * Data Structures:
564 *
565 * Params:
566 * Returns:
567 * Called By:
568 * Calls:
569 * Assumptions:
570 * Side Effects:
571 * TODO: 20000309 need to return integer to allow processing of left-over args
572 */
573int process_options(int count, char **vector) {
574 int option_num = 1, res = 1;
575
576 init_params();
577
578 while (option_num < count) {
579 if (*vector[option_num] == OPTION_START) {
580 if (option_num == (count - 1))
581 res = set_option(vector[option_num] + 1, NULL);
582 else
583 res = set_option(vector[option_num] + 1, vector[option_num + 1]);
584 }
585
586 if (res < 0) {
587 printf("ERROR: option '%s' or its argument unknown.\n", (vector[option_num] + 1));
588 usage(NULL, NULL);
589 exit(1);
590 } else
591 option_num += res;
592 }
593
594#ifdef JMS
595 if (is_set("VERBOSE"))
596 print_params();
597#endif
598
599 return (option_num);
600}
601
602/*
603 * Routine: read_file(char *param_name, char *fname)
604 * Purpose: process a parameter file
605 * Algorithm:
606 * Data Structures:
607 *
608 * Params:
609 * Returns:
610 * Called By:
611 * Calls:
612 * Assumptions:
613 * Side Effects:
614 * TODO: None
615 */
616int read_file(char *param_name, char *optarg) {
617 FILE *fp;
618 char *cp;
619 char line[MAX_LINE_LEN];
620 char name[100];
621 int index;
622
623 init_params();
624
625 if ((fp = fopen(optarg, "r")) == NULL)
626 return (-1);
627 while (fgets(line, MAX_LINE_LEN, fp) != NULL) {
628 if ((cp = strchr(line, '\n')) != NULL)
629 *cp = '\0';
630 if ((cp = strchr(line, '-')) != NULL)
631 if (*(cp + 1) == '-')
632 *cp = '\0';
633 if ((cp = strtok(line, " \t=\n")) != NULL) {
634 strcpy(name, cp);
635 index = fnd_param(name);
636 if (index == -1)
637 continue; /* JMS: errors are silently ignored */
638 cp += strlen(cp) + 1;
639 while (*cp && strchr(" \t =", *cp))
640 cp++;
641
642 /* command line options over-ride those in a file */
643 if (options[index].flags & OPT_SET)
644 continue;
645
646 if (*cp) {
647 switch (options[index].flags & TYPE_MASK) {
648 case OPT_INT:
649 if ((cp = strtok(cp, " \t\n")) != NULL)
650 set_option(name, cp);
651 break;
652 case OPT_STR:
653 case OPT_FLG:
654 set_option(name, cp);
655 break;
656 }
657 }
658 }
659 }
660
661 fclose(fp);
662
663 return (0);
664}
665
666/*
667 * Routine: print_params(void)
668 * Purpose: print a parameter summary to display current settings
669 * Algorithm:
670 * Data Structures:
671 *
672 * Params:
673 * Returns:
674 * Called By:
675 * Calls:
676 * Assumptions:
677 * Side Effects:
678 * TODO: None
679 */
680void print_params(void) {
681 int i;
682
683 init_params();
684
685 for (i = 0; options[i].name != NULL; i++)
686 if (options[i].name != NULL) {
687 printf("%s = ", options[i].name);
688 switch (options[i].flags & TYPE_MASK) {
689 case OPT_INT:
690 printf("%d\n", get_int(options[i].name));
691 break;
692 case OPT_STR:
693 printf("%s\n", get_str(options[i].name));
694 break;
695 case OPT_FLG:
696 printf("%c\n", is_set(options[i].name) ? 'Y' : 'N');
697 break;
698 }
699 }
700
701 return;
702}
703
704/*
705 * Routine: fnd_param(char *name, int *type, char *value)
706 * Purpose: traverse the defined parameters, looking for a match
707 * Algorithm:
708 * Data Structures:
709 *
710 * Params:
711 * Returns: index of option
712 * Called By:
713 * Calls:
714 * Assumptions:
715 * Side Effects:
716 * TODO: None
717 */
718int fnd_param(char *name) {
719 int i, res = -1;
720
721 for (i = 0; options[i].name != NULL; i++) {
722 if (strncasecmp(name, options[i].name, strlen(name)) == 0) {
723 if (res == -1)
724 res = i;
725 else
726 return (-1);
727 }
728 }
729
730 return (res);
731}
732
733/*
734 * Routine: GetParamName(int nParam)
735 * Purpose: Translate between a parameter index and its name
736 * Algorithm:
737 * Data Structures:
738 *
739 * Params:
740 * Returns:
741 * Called By:
742 * Calls:
743 * Assumptions:
744 * Side Effects:
745 * TODO: None
746 */
747char *GetParamName(int nParam) {
748 init_params();
749
750 return (options[nParam].name);
751}
752
753/*
754 * Routine: GetParamValue(int nParam)
755 * Purpose: Retrieve a parameters string value based on an index
756 * Algorithm:
757 * Data Structures:
758 *
759 * Params:
760 * Returns:
761 * Called By:
762 * Calls:
763 * Assumptions:
764 * Side Effects:
765 * TODO: None
766 */
767char *GetParamValue(int nParam) {
768 init_params();
769
770 return (params[options[nParam].index]);
771}
772
773/*
774 * Routine: load_param(char *szValue, int nParam)
775 * Purpose: Set a parameter based on an index
776 * Algorithm:
777 * Data Structures:
778 *
779 * Params:
780 * Returns:
781 * Called By:
782 * Calls:
783 * Assumptions:
784 * Side Effects:
785 * TODO: None
786 */
787int load_param(int nParam, char *szValue) {
788 init_params();
789
790 if (options[nParam].flags & OPT_SET) /* already set from the command line */
791 return (0);
792 else
793 strcpy(params[options[nParam].index], szValue);
794
795 return (0);
796}
797
798/*
799 * Routine: IsIntParam(char *szValue, int nParam)
800 * Purpose: Boolean test for integer parameter
801 * Algorithm:
802 * Data Structures:
803 *
804 * Params:
805 * Returns:
806 * Called By:
807 * Calls:
808 * Assumptions:
809 * Side Effects:
810 * TODO: None
811 */
812int IsIntParam(char *szParam) {
813 int nParam;
814
815 if ((nParam = fnd_param(szParam)) == -1)
816 return (nParam);
817
818 return ((options[nParam].flags & OPT_INT) ? 1 : 0);
819}
820
821/*
822 * Routine: IsStrParam(char *szValue, int nParam)
823 * Purpose: Boolean test for string parameter
824 * Algorithm:
825 * Data Structures:
826 *
827 * Params:
828 * Returns:
829 * Called By:
830 * Calls:
831 * Assumptions:
832 * Side Effects:
833 * TODO: None
834 */
835int IsStrParam(char *szParam) {
836 int nParam;
837
838 if ((nParam = fnd_param(szParam)) == -1)
839 return (nParam);
840
841 return ((options[nParam].flags & OPT_STR) ? 1 : 0);
842}
843
844#ifdef TEST
845
846main() {
847 init_params();
848 set_int("SCALE", "7");
849 set_flg("VERBOSE");
850 set_str("DISTRIBUTIONS", "'some file name'");
851 print_params();
852 set_int("s", "8");
853 clr_flg("VERBOSE");
854 printf("DIST is %s\n", get_str("DISTRIBUTIONS"));
855 print_params();
856 usage(NULL, NULL);
857}
858#endif /* TEST_PARAMS */
859