This source file includes following definitions.
- find_option
- pmix_cmd_line_add
- pmix_cmd_line_make_opt_mca
- pmix_cmd_line_make_opt3
- pmix_cmd_line_parse
- pmix_cmd_line_get_usage_msg
- pmix_cmd_line_is_taken
- pmix_cmd_line_get_ninsts
- pmix_cmd_line_get_param
- pmix_cmd_line_get_argc
- pmix_cmd_line_get_argv
- pmix_cmd_line_get_tail
- option_constructor
- option_destructor
- param_constructor
- param_destructor
- cmd_line_constructor
- cmd_line_destructor
- make_opt
- free_parse_results
- split_shorts
- find_option
- set_dest
- fill
- qsort_callback
- get_help_otype
- build_parsable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 #include "pmix_config.h"
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <ctype.h>
32
33 #include "src/class/pmix_object.h"
34 #include "src/class/pmix_list.h"
35 #include "src/threads/mutex.h"
36 #include "src/util/argv.h"
37 #include "src/util/cmd_line.h"
38 #include "src/util/output.h"
39 #include "src/util/pmix_environ.h"
40
41 #include "src/mca/base/pmix_mca_base_var.h"
42 #include "pmix_common.h"
43
44
45
46
47
48
49
50
51 #define PARAM_WIDTH 25
52
53
54
55 #define MAX_WIDTH 76
56
57
58
59
60 struct pmix_cmd_line_option_t {
61 pmix_list_item_t super;
62
63 char clo_short_name;
64 char *clo_single_dash_name;
65 char *clo_long_name;
66
67 int clo_num_params;
68 char *clo_description;
69
70 pmix_cmd_line_type_t clo_type;
71 char *clo_mca_param_env_var;
72 void *clo_variable_dest;
73 bool clo_variable_set;
74 pmix_cmd_line_otype_t clo_otype;
75 };
76 typedef struct pmix_cmd_line_option_t pmix_cmd_line_option_t;
77 static void option_constructor(pmix_cmd_line_option_t *cmd);
78 static void option_destructor(pmix_cmd_line_option_t *cmd);
79
80 PMIX_CLASS_INSTANCE(pmix_cmd_line_option_t,
81 pmix_list_item_t,
82 option_constructor, option_destructor);
83
84
85
86
87 struct pmix_cmd_line_param_t {
88 pmix_list_item_t super;
89
90
91
92
93
94 char *clp_arg;
95
96
97
98
99 pmix_cmd_line_option_t *clp_option;
100
101
102
103
104
105 int clp_argc;
106 char **clp_argv;
107 };
108 typedef struct pmix_cmd_line_param_t pmix_cmd_line_param_t;
109 static void param_constructor(pmix_cmd_line_param_t *cmd);
110 static void param_destructor(pmix_cmd_line_param_t *cmd);
111 PMIX_CLASS_INSTANCE(pmix_cmd_line_param_t,
112 pmix_list_item_t,
113 param_constructor, param_destructor);
114
115
116
117
118 static void cmd_line_constructor(pmix_cmd_line_t *cmd);
119 static void cmd_line_destructor(pmix_cmd_line_t *cmd);
120 PMIX_CLASS_INSTANCE(pmix_cmd_line_t,
121 pmix_object_t,
122 cmd_line_constructor,
123 cmd_line_destructor);
124
125
126
127
128 static char special_empty_token[] = {
129 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, '\0'
130 };
131
132
133
134
135 static int make_opt(pmix_cmd_line_t *cmd, pmix_cmd_line_init_t *e);
136 static void free_parse_results(pmix_cmd_line_t *cmd);
137 static int split_shorts(pmix_cmd_line_t *cmd,
138 char *token, char **args,
139 int *output_argc, char ***output_argv,
140 int *num_args_used, bool ignore_unknown);
141 static pmix_cmd_line_option_t *find_option(pmix_cmd_line_t *cmd,
142 const char *option_name) __pmix_attribute_nonnull__(1) __pmix_attribute_nonnull__(2);
143 static int set_dest(pmix_cmd_line_option_t *option, char *sval);
144 static void fill(const pmix_cmd_line_option_t *a, char result[3][BUFSIZ]);
145 static int qsort_callback(const void *a, const void *b);
146 static pmix_cmd_line_otype_t get_help_otype(pmix_cmd_line_t *cmd);
147 static char *build_parsable(pmix_cmd_line_option_t *option);
148
149
150
151
152
153 int pmix_cmd_line_create(pmix_cmd_line_t *cmd,
154 pmix_cmd_line_init_t *table)
155 {
156 int ret = PMIX_SUCCESS;
157
158
159
160 if (NULL == cmd) {
161 return PMIX_ERR_BAD_PARAM;
162 }
163 PMIX_CONSTRUCT(cmd, pmix_cmd_line_t);
164
165 if (NULL != table) {
166 ret = pmix_cmd_line_add(cmd, table);
167 }
168 return ret;
169 }
170
171
172 int pmix_cmd_line_add(pmix_cmd_line_t *cmd,
173 pmix_cmd_line_init_t *table)
174 {
175 int i, ret;
176
177
178 if (NULL == table) {
179 return PMIX_SUCCESS;
180 }
181
182
183
184 for (i = 0; ; ++i) {
185
186 if ('\0' == table[i].ocl_cmd_short_name &&
187 NULL == table[i].ocl_cmd_single_dash_name &&
188 NULL == table[i].ocl_cmd_long_name) {
189 break;
190 }
191
192
193 ret = make_opt(cmd, &table[i]);
194 if (PMIX_SUCCESS != ret) {
195 return ret;
196 }
197 }
198
199 return PMIX_SUCCESS;
200 }
201
202
203
204 int pmix_cmd_line_make_opt_mca(pmix_cmd_line_t *cmd,
205 pmix_cmd_line_init_t entry)
206 {
207
208 if ('\0' == entry.ocl_cmd_short_name &&
209 NULL == entry.ocl_cmd_single_dash_name &&
210 NULL == entry.ocl_cmd_long_name) {
211 return PMIX_SUCCESS;
212 }
213
214 return make_opt(cmd, &entry);
215 }
216
217
218
219
220
221 int pmix_cmd_line_make_opt3(pmix_cmd_line_t *cmd, char short_name,
222 const char *sd_name, const char *long_name,
223 int num_params, const char *desc)
224 {
225 pmix_cmd_line_init_t e;
226
227 e.ocl_mca_param_name = NULL;
228
229 e.ocl_cmd_short_name = short_name;
230 e.ocl_cmd_single_dash_name = sd_name;
231 e.ocl_cmd_long_name = long_name;
232
233 e.ocl_num_params = num_params;
234
235 e.ocl_variable_dest = NULL;
236 e.ocl_variable_type = PMIX_CMD_LINE_TYPE_NULL;
237
238 e.ocl_description = desc;
239
240 return make_opt(cmd, &e);
241 }
242
243
244
245
246
247
248 int pmix_cmd_line_parse(pmix_cmd_line_t *cmd, bool ignore_unknown, bool ignore_unknown_option,
249 int argc, char **argv)
250 {
251 int i, j, orig, ret;
252 pmix_cmd_line_option_t *option;
253 pmix_cmd_line_param_t *param;
254 bool is_unknown_option;
255 bool is_unknown_token;
256 bool is_option;
257 char **shortsv;
258 int shortsc;
259 int num_args_used;
260 bool have_help_option = false;
261 bool printed_error = false;
262 bool help_without_arg = false;
263
264
265
266 if (0 == argc || NULL == argv) {
267 return PMIX_SUCCESS;
268 }
269
270
271
272 pmix_mutex_lock(&cmd->lcl_mutex);
273
274
275
276 free_parse_results(cmd);
277
278
279
280 cmd->lcl_argc = argc;
281 cmd->lcl_argv = pmix_argv_copy(argv);
282
283
284
285 option = find_option(cmd, "help");
286 if (NULL != option) {
287 have_help_option = true;
288 }
289
290
291
292
293
294 param = NULL;
295 option = NULL;
296 for (i = 1; i < cmd->lcl_argc; ) {
297 is_unknown_option = false;
298 is_unknown_token = false;
299 is_option = false;
300
301
302
303
304
305 if (0 == strcmp(cmd->lcl_argv[i], "--")) {
306 ++i;
307 while (i < cmd->lcl_argc) {
308 pmix_argv_append(&cmd->lcl_tail_argc, &cmd->lcl_tail_argv,
309 cmd->lcl_argv[i]);
310 ++i;
311 }
312
313 break;
314 }
315
316
317
318
319
320 else if ('-' != cmd->lcl_argv[i][0]) {
321 is_unknown_token = true;
322 }
323
324
325
326 else if (0 == strncmp(cmd->lcl_argv[i], "--", 2)) {
327 is_option = true;
328 option = find_option(cmd, cmd->lcl_argv[i] + 2);
329 }
330
331
332
333 else {
334 option = find_option(cmd, cmd->lcl_argv[i] + 1);
335
336
337
338
339
340
341
342
343 if (NULL == option) {
344 shortsv = NULL;
345 shortsc = 0;
346 ret = split_shorts(cmd, cmd->lcl_argv[i] + 1,
347 &(cmd->lcl_argv[i + 1]),
348 &shortsc, &shortsv,
349 &num_args_used, ignore_unknown);
350 if (PMIX_SUCCESS == ret) {
351 option = find_option(cmd, shortsv[0] + 1);
352
353 if (NULL != option) {
354 pmix_argv_delete(&cmd->lcl_argc,
355 &cmd->lcl_argv, i,
356 1 + num_args_used);
357 pmix_argv_insert(&cmd->lcl_argv, i, shortsv);
358 cmd->lcl_argc = pmix_argv_count(cmd->lcl_argv);
359 } else {
360 is_unknown_option = true;
361 }
362 pmix_argv_free(shortsv);
363 } else {
364 is_unknown_option = true;
365 }
366 }
367
368 if (NULL != option) {
369 is_option = true;
370 }
371 }
372
373
374
375 if (is_option) {
376 if (NULL == option) {
377 is_unknown_option = true;
378 } else {
379 is_unknown_option = false;
380 orig = i;
381 ++i;
382
383
384
385
386
387
388
389 param = PMIX_NEW(pmix_cmd_line_param_t);
390 if (NULL == param) {
391 pmix_mutex_unlock(&cmd->lcl_mutex);
392 return PMIX_ERR_OUT_OF_RESOURCE;
393 }
394 param->clp_arg = cmd->lcl_argv[i];
395 param->clp_option = option;
396
397
398
399
400
401 for (j = 0; j < option->clo_num_params; ++j, ++i) {
402
403
404 if (i >= cmd->lcl_argc) {
405
406 if((NULL != option->clo_single_dash_name &&
407 0 == strcmp(option->clo_single_dash_name, "h")) ||
408 (NULL != option->clo_long_name &&
409 0 == strcmp(option->clo_long_name, "help"))) {
410 help_without_arg = true;
411 continue;
412 }
413 fprintf(stderr, "%s: Error: option \"%s\" did not "
414 "have enough parameters (%d)\n",
415 cmd->lcl_argv[0],
416 cmd->lcl_argv[orig],
417 option->clo_num_params);
418 if (have_help_option) {
419 fprintf(stderr, "Type '%s --help' for usage.\n",
420 cmd->lcl_argv[0]);
421 }
422 PMIX_RELEASE(param);
423 printed_error = true;
424 goto error;
425 } else {
426 if (0 == strcmp(cmd->lcl_argv[i],
427 special_empty_token)) {
428 fprintf(stderr, "%s: Error: option \"%s\" did not "
429 "have enough parameters (%d)\n",
430 cmd->lcl_argv[0],
431 cmd->lcl_argv[orig],
432 option->clo_num_params);
433 if (have_help_option) {
434 fprintf(stderr, "Type '%s --help' for usage.\n",
435 cmd->lcl_argv[0]);
436 }
437 if (NULL != param->clp_argv) {
438 pmix_argv_free(param->clp_argv);
439 }
440 PMIX_RELEASE(param);
441 printed_error = true;
442 goto error;
443 }
444
445
446
447 else {
448
449
450 pmix_argv_append(¶m->clp_argc,
451 ¶m->clp_argv,
452 cmd->lcl_argv[i]);
453
454
455
456
457 if (0 == j &&
458 (NULL != option->clo_mca_param_env_var ||
459 NULL != option->clo_variable_dest)) {
460 if (PMIX_SUCCESS != (ret = set_dest(option, cmd->lcl_argv[i]))) {
461 pmix_mutex_unlock(&cmd->lcl_mutex);
462 return ret;
463 }
464 }
465 }
466 }
467 }
468
469
470
471
472
473 if (0 == option->clo_num_params || help_without_arg) {
474 if (PMIX_SUCCESS != (ret = set_dest(option, "1"))) {
475 pmix_mutex_unlock(&cmd->lcl_mutex);
476 return ret;
477 }
478 }
479
480
481
482
483 if (NULL != param) {
484 pmix_list_append(&cmd->lcl_params, ¶m->super);
485 }
486 }
487 }
488
489
490
491
492
493 if (is_unknown_option || is_unknown_token) {
494 if (!ignore_unknown || (is_unknown_option && !ignore_unknown_option)) {
495 fprintf(stderr, "%s: Error: unknown option \"%s\"\n",
496 cmd->lcl_argv[0], cmd->lcl_argv[i]);
497 printed_error = true;
498 if (have_help_option) {
499 fprintf(stderr, "Type '%s --help' for usage.\n",
500 cmd->lcl_argv[0]);
501 }
502 }
503 error:
504 while (i < cmd->lcl_argc) {
505 pmix_argv_append(&cmd->lcl_tail_argc, &cmd->lcl_tail_argv,
506 cmd->lcl_argv[i]);
507 ++i;
508 }
509
510
511 }
512 }
513
514
515
516 pmix_mutex_unlock(&cmd->lcl_mutex);
517
518
519 if (printed_error) {
520 return PMIX_ERR_SILENT;
521 }
522
523 return PMIX_SUCCESS;
524 }
525
526
527
528
529
530 char *pmix_cmd_line_get_usage_msg(pmix_cmd_line_t *cmd)
531 {
532 size_t i, len;
533 int argc;
534 size_t j;
535 char **argv;
536 char *ret, temp[MAX_WIDTH * 2], line[MAX_WIDTH * 2];
537 char *start, *desc, *ptr;
538 pmix_list_item_t *item;
539 pmix_cmd_line_option_t *option, **sorted;
540 pmix_cmd_line_otype_t otype;
541
542
543
544 pmix_mutex_lock(&cmd->lcl_mutex);
545
546
547
548 argc = 0;
549 argv = NULL;
550 ret = NULL;
551
552
553
554 sorted = (pmix_cmd_line_option_t**)malloc(sizeof(pmix_cmd_line_option_t *) *
555 pmix_list_get_size(&cmd->lcl_options));
556 if (NULL == sorted) {
557 pmix_mutex_unlock(&cmd->lcl_mutex);
558 return NULL;
559 }
560 i = 0;
561 PMIX_LIST_FOREACH(item, &cmd->lcl_options, pmix_list_item_t) {
562 sorted[i++] = (pmix_cmd_line_option_t *) item;
563 }
564 qsort(sorted, i, sizeof(pmix_cmd_line_option_t*), qsort_callback);
565
566
567
568 otype = get_help_otype(cmd);
569
570
571
572 for (j = 0; j < pmix_list_get_size(&cmd->lcl_options); ++j) {
573 option = sorted[j];
574 if(otype == PMIX_CMD_LINE_OTYPE_PARSABLE) {
575 ret = build_parsable(option);
576 pmix_argv_append(&argc, &argv, ret);
577 free(ret);
578 ret = NULL;
579 } else if(otype == PMIX_CMD_LINE_OTYPE_NULL || option->clo_otype == otype) {
580 if (NULL != option->clo_description) {
581 bool filled = false;
582
583
584
585 memset(line, 0, sizeof(line));
586 if ('\0' != option->clo_short_name) {
587 line[0] = '-';
588 line[1] = option->clo_short_name;
589 filled = true;
590 } else {
591 line[0] = ' ';
592 line[1] = ' ';
593 }
594 if (NULL != option->clo_single_dash_name) {
595 line[2] = (filled) ? '|' : ' ';
596 strncat(line, "-", sizeof(line) - 1);
597 strncat(line, option->clo_single_dash_name, sizeof(line) - 1);
598 filled = true;
599 }
600 if (NULL != option->clo_long_name) {
601 if (filled) {
602 strncat(line, "|", sizeof(line) - 1);
603 } else {
604 strncat(line, " ", sizeof(line) - 1);
605 }
606 strncat(line, "--", sizeof(line) - 1);
607 strncat(line, option->clo_long_name, sizeof(line) - 1);
608 }
609 strncat(line, " ", sizeof(line) - 1);
610 for (i = 0; (int)i < option->clo_num_params; ++i) {
611 len = sizeof(temp);
612 snprintf(temp, len, "<arg%d> ", (int)i);
613 strncat(line, temp, sizeof(line) - 1);
614 }
615 if (option->clo_num_params > 0) {
616 strncat(line, " ", sizeof(line) - 1);
617 }
618
619
620
621
622
623 if (strlen(line) > PARAM_WIDTH) {
624 pmix_argv_append(&argc, &argv, line);
625
626
627
628
629
630 memset(line, ' ', PARAM_WIDTH);
631 line[PARAM_WIDTH] = '\0';
632 } else {
633
634
635
636
637 for (i = strlen(line); i < PARAM_WIDTH; ++i) {
638 line[i] = ' ';
639 }
640 line[i] = '\0';
641 }
642
643
644
645
646
647
648
649
650 desc = strdup(option->clo_description);
651 if (NULL == desc) {
652 free(sorted);
653 pmix_mutex_unlock(&cmd->lcl_mutex);
654 return strdup("");
655 }
656 start = desc;
657 len = strlen(desc);
658 do {
659
660
661
662 while (isspace(*start) && start < desc + len) {
663 ++start;
664 }
665 if (start >= desc + len) {
666 break;
667 }
668
669
670
671 if (strlen(start) < (MAX_WIDTH - PARAM_WIDTH)) {
672 strncat(line, start, sizeof(line) - 1);
673 pmix_argv_append(&argc, &argv, line);
674 break;
675 }
676
677
678
679
680
681 for (ptr = start + (MAX_WIDTH - PARAM_WIDTH);
682 ptr > start; --ptr) {
683 if (isspace(*ptr)) {
684 *ptr = '\0';
685 strncat(line, start, sizeof(line) - 1);
686 pmix_argv_append(&argc, &argv, line);
687
688 start = ptr + 1;
689 memset(line, ' ', PARAM_WIDTH);
690 line[PARAM_WIDTH] = '\0';
691 break;
692 }
693 }
694
695
696
697
698
699 if (ptr == start) {
700 for (ptr = start + (MAX_WIDTH - PARAM_WIDTH);
701 ptr < start + len; ++ptr) {
702 if (isspace(*ptr)) {
703 *ptr = '\0';
704
705 strncat(line, start, sizeof(line) - 1);
706 pmix_argv_append(&argc, &argv, line);
707
708 start = ptr + 1;
709 memset(line, ' ', PARAM_WIDTH);
710 line[PARAM_WIDTH] = '\0';
711 break;
712 }
713 }
714
715
716
717
718 if (ptr >= start + len) {
719 strncat(line, start, sizeof(line) - 1);
720 pmix_argv_append(&argc, &argv, line);
721 start = desc + len + 1;
722 }
723 }
724 } while (start < desc + len);
725 free(desc);
726 }
727 }
728 }
729 if (NULL != argv) {
730 ret = pmix_argv_join(argv, '\n');
731 pmix_argv_free(argv);
732 } else {
733 ret = strdup("");
734 }
735 free(sorted);
736
737
738 pmix_mutex_unlock(&cmd->lcl_mutex);
739
740
741 return ret;
742 }
743
744
745
746
747
748 bool pmix_cmd_line_is_taken(pmix_cmd_line_t *cmd, const char *opt)
749 {
750 return (pmix_cmd_line_get_ninsts(cmd, opt) > 0);
751 }
752
753
754
755
756
757 int pmix_cmd_line_get_ninsts(pmix_cmd_line_t *cmd, const char *opt)
758 {
759 int ret;
760 pmix_cmd_line_param_t *param;
761 pmix_cmd_line_option_t *option;
762
763
764
765 pmix_mutex_lock(&cmd->lcl_mutex);
766
767
768
769
770 ret = 0;
771 option = find_option(cmd, opt);
772 if (NULL != option) {
773 PMIX_LIST_FOREACH(param, &cmd->lcl_params, pmix_cmd_line_param_t) {
774 if (param->clp_option == option) {
775 ++ret;
776 }
777 }
778 }
779
780
781
782 pmix_mutex_unlock(&cmd->lcl_mutex);
783
784
785
786 return ret;
787 }
788
789
790
791
792
793
794 char *pmix_cmd_line_get_param(pmix_cmd_line_t *cmd, const char *opt, int inst,
795 int idx)
796 {
797 int num_found;
798 pmix_cmd_line_param_t *param;
799 pmix_cmd_line_option_t *option;
800
801
802
803 pmix_mutex_lock(&cmd->lcl_mutex);
804
805
806
807
808 num_found = 0;
809 option = find_option(cmd, opt);
810 if (NULL != option) {
811
812
813
814
815 if (idx < option->clo_num_params) {
816 PMIX_LIST_FOREACH(param, &cmd->lcl_params, pmix_cmd_line_param_t) {
817 if (param->clp_argc > 0 && param->clp_option == option) {
818 if (num_found == inst) {
819 pmix_mutex_unlock(&cmd->lcl_mutex);
820 return param->clp_argv[idx];
821 }
822 ++num_found;
823 }
824 }
825 }
826 }
827
828
829
830 pmix_mutex_unlock(&cmd->lcl_mutex);
831
832
833
834 return NULL;
835 }
836
837
838
839
840
841 int pmix_cmd_line_get_argc(pmix_cmd_line_t *cmd)
842 {
843 return (NULL != cmd) ? cmd->lcl_argc : PMIX_ERROR;
844 }
845
846
847
848
849
850 char *pmix_cmd_line_get_argv(pmix_cmd_line_t *cmd, int index)
851 {
852 return (NULL == cmd) ? NULL :
853 (index >= cmd->lcl_argc || index < 0) ? NULL : cmd->lcl_argv[index];
854 }
855
856
857
858
859
860
861 int pmix_cmd_line_get_tail(pmix_cmd_line_t *cmd, int *tailc, char ***tailv)
862 {
863 if (NULL != cmd) {
864 pmix_mutex_lock(&cmd->lcl_mutex);
865 *tailc = cmd->lcl_tail_argc;
866 *tailv = pmix_argv_copy(cmd->lcl_tail_argv);
867 pmix_mutex_unlock(&cmd->lcl_mutex);
868 return PMIX_SUCCESS;
869 } else {
870 return PMIX_ERROR;
871 }
872 }
873
874
875
876
877
878
879 static void option_constructor(pmix_cmd_line_option_t *o)
880 {
881 o->clo_short_name = '\0';
882 o->clo_single_dash_name = NULL;
883 o->clo_long_name = NULL;
884 o->clo_num_params = 0;
885 o->clo_description = NULL;
886
887 o->clo_type = PMIX_CMD_LINE_TYPE_NULL;
888 o->clo_mca_param_env_var = NULL;
889 o->clo_variable_dest = NULL;
890 o->clo_variable_set = false;
891 o->clo_otype = PMIX_CMD_LINE_OTYPE_NULL;
892 }
893
894
895 static void option_destructor(pmix_cmd_line_option_t *o)
896 {
897 if (NULL != o->clo_single_dash_name) {
898 free(o->clo_single_dash_name);
899 }
900 if (NULL != o->clo_long_name) {
901 free(o->clo_long_name);
902 }
903 if (NULL != o->clo_description) {
904 free(o->clo_description);
905 }
906 if (NULL != o->clo_mca_param_env_var) {
907 free(o->clo_mca_param_env_var);
908 }
909 }
910
911
912 static void param_constructor(pmix_cmd_line_param_t *p)
913 {
914 p->clp_arg = NULL;
915 p->clp_option = NULL;
916 p->clp_argc = 0;
917 p->clp_argv = NULL;
918 }
919
920
921 static void param_destructor(pmix_cmd_line_param_t *p)
922 {
923 if (NULL != p->clp_argv) {
924 pmix_argv_free(p->clp_argv);
925 }
926 }
927
928
929 static void cmd_line_constructor(pmix_cmd_line_t *cmd)
930 {
931
932
933
934
935 PMIX_CONSTRUCT(&cmd->lcl_mutex, pmix_recursive_mutex_t);
936
937
938
939 PMIX_CONSTRUCT(&cmd->lcl_options, pmix_list_t);
940 PMIX_CONSTRUCT(&cmd->lcl_params, pmix_list_t);
941
942
943
944 cmd->lcl_argc = 0;
945 cmd->lcl_argv = NULL;
946 cmd->lcl_tail_argc = 0;
947 cmd->lcl_tail_argv = NULL;
948 }
949
950
951 static void cmd_line_destructor(pmix_cmd_line_t *cmd)
952 {
953 pmix_list_item_t *item;
954
955
956
957
958 for (item = pmix_list_remove_first(&cmd->lcl_options);
959 NULL != item;
960 item = pmix_list_remove_first(&cmd->lcl_options)) {
961 PMIX_RELEASE(item);
962 }
963
964
965
966 free_parse_results(cmd);
967
968
969
970 PMIX_DESTRUCT(&cmd->lcl_options);
971 PMIX_DESTRUCT(&cmd->lcl_params);
972
973
974
975 PMIX_DESTRUCT(&cmd->lcl_mutex);
976 }
977
978
979 static int make_opt(pmix_cmd_line_t *cmd, pmix_cmd_line_init_t *e)
980 {
981 pmix_cmd_line_option_t *option;
982
983
984
985 if (NULL == cmd) {
986 return PMIX_ERR_BAD_PARAM;
987 } else if ('\0' == e->ocl_cmd_short_name &&
988 NULL == e->ocl_cmd_single_dash_name &&
989 NULL == e->ocl_cmd_long_name) {
990 return PMIX_ERR_BAD_PARAM;
991 } else if (e->ocl_num_params < 0) {
992 return PMIX_ERR_BAD_PARAM;
993 }
994
995
996 if (NULL != e->ocl_cmd_single_dash_name &&
997 NULL != find_option(cmd, e->ocl_cmd_single_dash_name)) {
998 pmix_output(0, "Duplicate cmd line entry %s", e->ocl_cmd_single_dash_name);
999 return PMIX_ERR_BAD_PARAM;
1000 }
1001 if (NULL != e->ocl_cmd_long_name &&
1002 NULL != find_option(cmd, e->ocl_cmd_long_name)) {
1003 pmix_output(0, "Duplicate cmd line entry %s", e->ocl_cmd_long_name);
1004 return PMIX_ERR_BAD_PARAM;
1005 }
1006
1007
1008 option = PMIX_NEW(pmix_cmd_line_option_t);
1009 if (NULL == option) {
1010 return PMIX_ERR_OUT_OF_RESOURCE;
1011 }
1012
1013 option->clo_short_name = e->ocl_cmd_short_name;
1014 if (NULL != e->ocl_cmd_single_dash_name) {
1015 option->clo_single_dash_name = strdup(e->ocl_cmd_single_dash_name);
1016 }
1017 if (NULL != e->ocl_cmd_long_name) {
1018 option->clo_long_name = strdup(e->ocl_cmd_long_name);
1019 }
1020 option->clo_num_params = e->ocl_num_params;
1021 if (NULL != e->ocl_description) {
1022 option->clo_description = strdup(e->ocl_description);
1023 }
1024
1025 option->clo_type = e->ocl_variable_type;
1026 option->clo_variable_dest = e->ocl_variable_dest;
1027 if (NULL != e->ocl_mca_param_name) {
1028 (void) pmix_mca_base_var_env_name (e->ocl_mca_param_name,
1029 &option->clo_mca_param_env_var);
1030 }
1031
1032 option->clo_otype = e->ocl_otype;
1033
1034
1035
1036 pmix_mutex_lock(&cmd->lcl_mutex);
1037 pmix_list_append(&cmd->lcl_options, &option->super);
1038 pmix_mutex_unlock(&cmd->lcl_mutex);
1039
1040
1041
1042 return PMIX_SUCCESS;
1043 }
1044
1045
1046 static void free_parse_results(pmix_cmd_line_t *cmd)
1047 {
1048 pmix_list_item_t *item;
1049
1050
1051
1052
1053 for (item = pmix_list_remove_first(&cmd->lcl_params);
1054 NULL != item;
1055 item = pmix_list_remove_first(&cmd->lcl_params)) {
1056 PMIX_RELEASE(item);
1057 }
1058
1059
1060
1061 if (NULL != cmd->lcl_argv) {
1062 pmix_argv_free(cmd->lcl_argv);
1063 }
1064 cmd->lcl_argv = NULL;
1065 cmd->lcl_argc = 0;
1066
1067 if (NULL != cmd->lcl_tail_argv) {
1068 pmix_argv_free(cmd->lcl_tail_argv);
1069 }
1070 cmd->lcl_tail_argv = NULL;
1071 cmd->lcl_tail_argc = 0;
1072 }
1073
1074
1075
1076
1077
1078
1079
1080
1081 static int split_shorts(pmix_cmd_line_t *cmd, char *token, char **args,
1082 int *output_argc, char ***output_argv,
1083 int *num_args_used, bool ignore_unknown)
1084 {
1085 int i, j, len;
1086 pmix_cmd_line_option_t *option;
1087 char fake_token[3];
1088 int num_args;
1089
1090
1091
1092 num_args = pmix_argv_count(args);
1093 *num_args_used = 0;
1094
1095
1096
1097
1098
1099
1100 len = (int)strlen(token);
1101 if (0 == len) {
1102 return PMIX_ERR_BAD_PARAM;
1103 }
1104 fake_token[0] = '-';
1105 fake_token[2] = '\0';
1106 for (i = 0; i < len; ++i) {
1107 fake_token[1] = token[i];
1108 option = find_option(cmd, fake_token + 1);
1109
1110
1111
1112
1113 if (NULL == option) {
1114 if (!ignore_unknown) {
1115 return PMIX_ERR_BAD_PARAM;
1116 } else {
1117 pmix_argv_append(output_argc, output_argv, fake_token);
1118 }
1119 }
1120
1121
1122
1123
1124
1125
1126 else {
1127 pmix_argv_append(output_argc, output_argv, fake_token);
1128 for (j = 0; j < option->clo_num_params; ++j) {
1129 if (*num_args_used < num_args) {
1130 pmix_argv_append(output_argc, output_argv,
1131 args[*num_args_used]);
1132 ++(*num_args_used);
1133 } else {
1134 pmix_argv_append(output_argc, output_argv,
1135 special_empty_token);
1136 }
1137 }
1138 }
1139 }
1140
1141
1142
1143 return PMIX_SUCCESS;
1144 }
1145
1146
1147 static pmix_cmd_line_option_t *find_option(pmix_cmd_line_t *cmd,
1148 const char *option_name)
1149 {
1150 pmix_cmd_line_option_t *option;
1151
1152
1153
1154
1155
1156 PMIX_LIST_FOREACH(option, &cmd->lcl_options, pmix_cmd_line_option_t) {
1157 if ((NULL != option->clo_long_name &&
1158 0 == strcmp(option_name, option->clo_long_name)) ||
1159 (NULL != option->clo_single_dash_name &&
1160 0 == strcmp(option_name, option->clo_single_dash_name)) ||
1161 (strlen(option_name) == 1 &&
1162 option_name[0] == option->clo_short_name)) {
1163 return option;
1164 }
1165 }
1166
1167
1168
1169 return NULL;
1170 }
1171
1172
1173 static int set_dest(pmix_cmd_line_option_t *option, char *sval)
1174 {
1175 int ival = atol(sval);
1176 long lval = strtoul(sval, NULL, 10);
1177 size_t i;
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189 if (NULL != option->clo_mca_param_env_var) {
1190 switch(option->clo_type) {
1191 case PMIX_CMD_LINE_TYPE_STRING:
1192 case PMIX_CMD_LINE_TYPE_INT:
1193 case PMIX_CMD_LINE_TYPE_SIZE_T:
1194 pmix_setenv(option->clo_mca_param_env_var, sval, true, &environ);
1195 break;
1196 case PMIX_CMD_LINE_TYPE_BOOL:
1197 pmix_setenv(option->clo_mca_param_env_var, "1", true, &environ);
1198 break;
1199 default:
1200 break;
1201 }
1202 }
1203
1204
1205
1206 if (NULL != option->clo_variable_dest) {
1207 switch(option->clo_type) {
1208 case PMIX_CMD_LINE_TYPE_STRING:
1209 *((char**) option->clo_variable_dest) = strdup(sval);
1210 break;
1211 case PMIX_CMD_LINE_TYPE_INT:
1212
1213 for (i=0; i < strlen(sval); i++) {
1214 if (!isdigit(sval[i]) && '-' != sval[i]) {
1215
1216
1217
1218 fprintf(stderr, "----------------------------------------------------------------------------\n");
1219 fprintf(stderr, "Open MPI has detected that a parameter given to a command line\n");
1220 fprintf(stderr, "option does not match the expected format:\n\n");
1221 if (NULL != option->clo_long_name) {
1222 fprintf(stderr, " Option: %s\n", option->clo_long_name);
1223 } else if ('\0' != option->clo_short_name) {
1224 fprintf(stderr, " Option: %c\n", option->clo_short_name);
1225 } else {
1226 fprintf(stderr, " Option: <unknown>\n");
1227 }
1228 fprintf(stderr, " Param: %s\n\n", sval);
1229 fprintf(stderr, "This is frequently caused by omitting to provide the parameter\n");
1230 fprintf(stderr, "to an option that requires one. Please check the command line and try again.\n");
1231 fprintf(stderr, "----------------------------------------------------------------------------\n");
1232 return PMIX_ERR_SILENT;
1233 }
1234 }
1235 *((int*) option->clo_variable_dest) = ival;
1236 break;
1237 case PMIX_CMD_LINE_TYPE_SIZE_T:
1238
1239 for (i=0; i < strlen(sval); i++) {
1240 if (!isdigit(sval[i]) && '-' != sval[i]) {
1241
1242
1243
1244 fprintf(stderr, "----------------------------------------------------------------------------\n");
1245 fprintf(stderr, "Open MPI has detected that a parameter given to a command line\n");
1246 fprintf(stderr, "option does not match the expected format:\n\n");
1247 if (NULL != option->clo_long_name) {
1248 fprintf(stderr, " Option: %s\n", option->clo_long_name);
1249 } else if ('\0' != option->clo_short_name) {
1250 fprintf(stderr, " Option: %c\n", option->clo_short_name);
1251 } else {
1252 fprintf(stderr, " Option: <unknown>\n");
1253 }
1254 fprintf(stderr, " Param: %s\n\n", sval);
1255 fprintf(stderr, "This is frequently caused by omitting to provide the parameter\n");
1256 fprintf(stderr, "to an option that requires one. Please check the command line and try again.\n");
1257 fprintf(stderr, "----------------------------------------------------------------------------\n");
1258 return PMIX_ERR_SILENT;
1259 }
1260 }
1261 *((size_t*) option->clo_variable_dest) = lval;
1262 break;
1263 case PMIX_CMD_LINE_TYPE_BOOL:
1264 *((bool*) option->clo_variable_dest) = 1;
1265 break;
1266 default:
1267 break;
1268 }
1269 }
1270 return PMIX_SUCCESS;
1271 }
1272
1273
1274
1275
1276
1277 static void fill(const pmix_cmd_line_option_t *a, char result[3][BUFSIZ])
1278 {
1279 int i = 0;
1280
1281 result[0][0] = '\0';
1282 result[1][0] = '\0';
1283 result[2][0] = '\0';
1284
1285 if ('\0' != a->clo_short_name) {
1286 snprintf(&result[i][0], BUFSIZ, "%c", a->clo_short_name);
1287 ++i;
1288 }
1289 if (NULL != a->clo_single_dash_name) {
1290 snprintf(&result[i][0], BUFSIZ, "%s", a->clo_single_dash_name);
1291 ++i;
1292 }
1293 if (NULL != a->clo_long_name) {
1294 snprintf(&result[i][0], BUFSIZ, "%s", a->clo_long_name);
1295 ++i;
1296 }
1297 }
1298
1299
1300 static int qsort_callback(const void *aa, const void *bb)
1301 {
1302 int ret, i;
1303 char str1[3][BUFSIZ], str2[3][BUFSIZ];
1304 const pmix_cmd_line_option_t *a = *((const pmix_cmd_line_option_t**) aa);
1305 const pmix_cmd_line_option_t *b = *((const pmix_cmd_line_option_t**) bb);
1306
1307
1308
1309
1310
1311
1312 fill(a, str1);
1313 fill(b, str2);
1314
1315 for (i = 0; i < 3; ++i) {
1316 if (0 != (ret = strcasecmp(str1[i], str2[i]))) {
1317 return ret;
1318 }
1319 }
1320
1321
1322
1323 return 0;
1324 }
1325
1326
1327
1328
1329
1330
1331 static pmix_cmd_line_otype_t get_help_otype(pmix_cmd_line_t *cmd)
1332 {
1333
1334
1335 pmix_cmd_line_otype_t otype = PMIX_CMD_LINE_OTYPE_NULL;
1336 char *arg;
1337
1338 arg = pmix_cmd_line_get_param(cmd, "help", 0, 0);
1339
1340
1341 if(NULL == arg) {
1342 arg = pmix_cmd_line_get_param(cmd, "h", 0, 0);
1343 }
1344
1345
1346 if(NULL == arg) {
1347 arg = "general";
1348 }
1349
1350 if (0 == strcmp(arg, "debug")) {
1351 otype = PMIX_CMD_LINE_OTYPE_DEBUG;
1352 } else if (0 == strcmp(arg, "output")) {
1353 otype = PMIX_CMD_LINE_OTYPE_OUTPUT;
1354 } else if (0 == strcmp(arg, "input")) {
1355 otype = PMIX_CMD_LINE_OTYPE_INPUT;
1356 } else if (0 == strcmp(arg, "mapping")) {
1357 otype = PMIX_CMD_LINE_OTYPE_MAPPING;
1358 } else if (0 == strcmp(arg, "ranking")) {
1359 otype = PMIX_CMD_LINE_OTYPE_RANKING;
1360 } else if (0 == strcmp(arg, "binding")) {
1361 otype = PMIX_CMD_LINE_OTYPE_BINDING;
1362 } else if (0 == strcmp(arg, "devel")) {
1363 otype = PMIX_CMD_LINE_OTYPE_DEVEL;
1364 } else if (0 == strcmp(arg, "compatibility")) {
1365 otype = PMIX_CMD_LINE_OTYPE_COMPAT;
1366 } else if (0 == strcmp(arg, "launch")) {
1367 otype = PMIX_CMD_LINE_OTYPE_LAUNCH;
1368 } else if (0 == strcmp(arg, "dvm")) {
1369 otype = PMIX_CMD_LINE_OTYPE_DVM;
1370 } else if (0 == strcmp(arg, "general")) {
1371 otype = PMIX_CMD_LINE_OTYPE_GENERAL;
1372 } else if (0 == strcmp(arg, "parsable")) {
1373 otype = PMIX_CMD_LINE_OTYPE_PARSABLE;
1374 }
1375
1376 return otype;
1377 }
1378
1379
1380
1381
1382
1383 static char *build_parsable(pmix_cmd_line_option_t *option) {
1384 char *line;
1385 int length;
1386
1387 length = snprintf(NULL, 0, "%c:%s:%s:%d:%s\n", option->clo_short_name, option->clo_single_dash_name,
1388 option->clo_long_name, option->clo_num_params, option->clo_description);
1389
1390 line = (char *)malloc(length * sizeof(char));
1391
1392 if('\0' == option->clo_short_name) {
1393 snprintf(line, length, "0:%s:%s:%d:%s\n", option->clo_single_dash_name, option->clo_long_name,
1394 option->clo_num_params, option->clo_description);
1395 } else {
1396 snprintf(line, length, "%c:%s:%s:%d:%s\n", option->clo_short_name, option->clo_single_dash_name,
1397 option->clo_long_name, option->clo_num_params, option->clo_description);
1398 }
1399
1400 return line;
1401 }