This source file includes following definitions.
- generate_node_regex
- generate_ppn
- parse_nodes
- parse_procs
- resolve_peers
- resolve_nodes
- pmix_regex_extract_nodes
- regex_parse_value_ranges
- regex_parse_value_range
- pmix_regex_extract_ppn
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 #include <src/include/pmix_config.h>
  15 
  16 #ifdef HAVE_STRING_H
  17 #include <string.h>
  18 #endif
  19 #include <fcntl.h>
  20 #ifdef HAVE_UNISTD_H
  21 #include <unistd.h>
  22 #endif
  23 #ifdef HAVE_SYS_TYPES_H
  24 #include <sys/types.h>
  25 #endif
  26 #include <ctype.h>
  27 
  28 
  29 #include <pmix_common.h>
  30 #include <pmix.h>
  31 
  32 #include "src/include/pmix_socket_errno.h"
  33 #include "src/include/pmix_globals.h"
  34 #include "src/util/argv.h"
  35 #include "src/util/error.h"
  36 #include "src/util/output.h"
  37 #include "src/class/pmix_list.h"
  38 #include "src/mca/gds/gds.h"
  39 #include "src/client/pmix_client_ops.h"
  40 
  41 #include "src/mca/preg/preg.h"
  42 #include "preg_native.h"
  43 
  44 static pmix_status_t generate_node_regex(const char *input,
  45                                          char **regex);
  46 static pmix_status_t generate_ppn(const char *input,
  47                                   char **ppn);
  48 static pmix_status_t parse_nodes(const char *regexp,
  49                                  char ***names);
  50 static pmix_status_t parse_procs(const char *regexp,
  51                                  char ***procs);
  52 static pmix_status_t resolve_peers(const char *nodename,
  53                                    const char *nspace,
  54                                    pmix_proc_t **procs, size_t *nprocs);
  55 static pmix_status_t resolve_nodes(const char *nspace,
  56                                    char **nodelist);
  57 
  58 pmix_preg_module_t pmix_preg_native_module = {
  59     .name = "pmix",
  60     .generate_node_regex = generate_node_regex,
  61     .generate_ppn = generate_ppn,
  62     .parse_nodes = parse_nodes,
  63     .parse_procs = parse_procs,
  64     .resolve_peers = resolve_peers,
  65     .resolve_nodes = resolve_nodes
  66 };
  67 
  68 static pmix_status_t regex_parse_value_ranges(char *base, char *ranges,
  69                                               int num_digits, char *suffix,
  70                                               char ***names);
  71 static pmix_status_t regex_parse_value_range(char *base, char *range,
  72                                              int num_digits, char *suffix,
  73                                              char ***names);
  74 static pmix_status_t pmix_regex_extract_nodes(char *regexp, char ***names);
  75 static pmix_status_t pmix_regex_extract_ppn(char *regexp, char ***procs);
  76 
  77 
  78 static pmix_status_t generate_node_regex(const char *input,
  79                                          char **regexp)
  80 {
  81     char *vptr, *vsave;
  82     char prefix[PMIX_MAX_NODE_PREFIX];
  83     int i, j, len, startnum, vnum, numdigits;
  84     bool found, fullval;
  85     char *suffix, *sfx;
  86     pmix_regex_value_t *vreg;
  87     pmix_regex_range_t *range;
  88     pmix_list_t vids;
  89     char **regexargs = NULL, *tmp, *tmp2;
  90     char *cptr;
  91 
  92     
  93     *regexp = NULL;
  94 
  95     
  96     PMIX_CONSTRUCT(&vids, pmix_list_t);
  97 
  98     
  99 
 100     vsave = strdup(input);
 101     vptr = vsave;
 102     while (NULL != (cptr = strchr(vptr, ',')) || 0 < strlen(vptr)) {
 103         if (NULL != cptr) {
 104             *cptr = '\0';
 105         }
 106         
 107         fullval = false;
 108         len = strlen(vptr);
 109         startnum = -1;
 110         memset(prefix, 0, PMIX_MAX_NODE_PREFIX);
 111         for (i=0, j=0; i < len; i++) {
 112             if (!isalpha(vptr[i])) {
 113                 
 114                 if (!isdigit(vptr[i])) {
 115                     
 116 
 117 
 118                     fullval = true;
 119                     break;
 120                 }
 121                 
 122 
 123 
 124                 if (startnum < 0) {
 125                     
 126                     startnum = i;
 127                 }
 128                 continue;
 129             }
 130             if (startnum < 0) {
 131                 prefix[j++] = vptr[i];
 132             }
 133         }
 134         if (fullval || startnum < 0) {
 135             
 136             vreg = PMIX_NEW(pmix_regex_value_t);
 137             vreg->prefix = strdup(vptr);
 138             pmix_list_append(&vids, &vreg->super);
 139             
 140             if (NULL == cptr) {
 141                 break;
 142             }
 143             vptr = cptr + 1;
 144             continue;
 145         }
 146         
 147         vnum = strtol(&vptr[startnum], &sfx, 10);
 148         if (NULL != sfx) {
 149             suffix = strdup(sfx);
 150             numdigits = (int)(sfx - &vptr[startnum]);
 151         } else {
 152             suffix = NULL;
 153             numdigits = (int)strlen(&vptr[startnum]);
 154         }
 155 
 156         
 157         found = false;
 158         PMIX_LIST_FOREACH(vreg, &vids, pmix_regex_value_t) {
 159             
 160             
 161             
 162             
 163             
 164             
 165             
 166             
 167             if( vreg->skip ) {
 168                 continue;
 169             }
 170 
 171             if (0 < strlen(prefix) && NULL == vreg->prefix) {
 172                 continue;
 173             }
 174             if (0 == strlen(prefix) && NULL != vreg->prefix) {
 175                 continue;
 176             }
 177             if (0 < strlen(prefix) && NULL != vreg->prefix
 178                 && 0 != strcmp(prefix, vreg->prefix)) {
 179                 vreg->skip = true;
 180                 continue;
 181             }
 182             if (NULL == suffix && NULL != vreg->suffix) {
 183                 continue;
 184             }
 185             if (NULL != suffix && NULL == vreg->suffix) {
 186                 continue;
 187             }
 188             if (NULL != suffix && NULL != vreg->suffix &&
 189                 0 != strcmp(suffix, vreg->suffix)) {
 190                 vreg->skip = true;
 191                 continue;
 192             }
 193             if (numdigits != vreg->num_digits) {
 194                 vreg->skip = true;
 195                 continue;
 196             }
 197             
 198             found = true;
 199             
 200 
 201 
 202             range = (pmix_regex_range_t*)pmix_list_get_last(&vreg->ranges);
 203             if (NULL == range) {
 204                 
 205                 range = PMIX_NEW(pmix_regex_range_t);
 206                 range->start = vnum;
 207                 range->cnt = 1;
 208                 pmix_list_append(&vreg->ranges, &range->super);
 209                 break;
 210             }
 211             
 212             if (vnum != (range->start + range->cnt)) {
 213                 
 214                 range = PMIX_NEW(pmix_regex_range_t);
 215                 range->start = vnum;
 216                 range->cnt = 1;
 217                 pmix_list_append(&vreg->ranges, &range->super);
 218                 break;
 219             }
 220             
 221             range->cnt++;
 222             break;
 223         }
 224         if (!found) {
 225             
 226             vreg = PMIX_NEW(pmix_regex_value_t);
 227             if (0 < strlen(prefix)) {
 228                 vreg->prefix = strdup(prefix);
 229             }
 230             if (NULL != suffix) {
 231                 vreg->suffix = strdup(suffix);
 232             }
 233             vreg->num_digits = numdigits;
 234             pmix_list_append(&vids, &vreg->super);
 235             
 236 
 237 
 238             range = PMIX_NEW(pmix_regex_range_t);
 239             range->start = vnum;
 240             range->cnt = 1;
 241             pmix_list_append(&vreg->ranges, &range->super);
 242         }
 243         if (NULL != suffix) {
 244             free(suffix);
 245         }
 246         
 247         if (NULL == cptr) {
 248             break;
 249         }
 250         vptr = cptr + 1;
 251     }
 252     free(vsave);
 253 
 254     
 255     while (NULL != (vreg = (pmix_regex_value_t*)pmix_list_remove_first(&vids))) {
 256         
 257         if (0 == pmix_list_get_size(&vreg->ranges)) {
 258             if (NULL != vreg->prefix) {
 259                 pmix_argv_append_nosize(®exargs, vreg->prefix);
 260             }
 261             PMIX_RELEASE(vreg);
 262             continue;
 263         }
 264         
 265         if (NULL != vreg->prefix) {
 266             if (0 > asprintf(&tmp, "%s[%d:", vreg->prefix, vreg->num_digits)) {
 267                 return PMIX_ERR_NOMEM;
 268             }
 269         } else {
 270             if (0 > asprintf(&tmp, "[%d:", vreg->num_digits)) {
 271                 return PMIX_ERR_NOMEM;
 272             }
 273         }
 274         
 275         while (NULL != (range = (pmix_regex_range_t*)pmix_list_remove_first(&vreg->ranges))) {
 276             if (1 == range->cnt) {
 277                 if (0 > asprintf(&tmp2, "%s%d,", tmp, range->start)) {
 278                     return PMIX_ERR_NOMEM;
 279                 }
 280             } else {
 281                 if (0 > asprintf(&tmp2, "%s%d-%d,", tmp, range->start, range->start + range->cnt - 1)) {
 282                     return PMIX_ERR_NOMEM;
 283                 }
 284             }
 285             free(tmp);
 286             tmp = tmp2;
 287             PMIX_RELEASE(range);
 288         }
 289         
 290         tmp[strlen(tmp)-1] = ']';
 291         if (NULL != vreg->suffix) {
 292             
 293             if (0 > asprintf(&tmp2, "%s%s", tmp, vreg->suffix)) {
 294                 return PMIX_ERR_NOMEM;
 295             }
 296             free(tmp);
 297             tmp = tmp2;
 298         }
 299         pmix_argv_append_nosize(®exargs, tmp);
 300         free(tmp);
 301         PMIX_RELEASE(vreg);
 302     }
 303 
 304     
 305     tmp = pmix_argv_join(regexargs, ',');
 306     if (0 > asprintf(regexp, "pmix[%s]", tmp)) {
 307         return PMIX_ERR_NOMEM;
 308     }
 309     free(tmp);
 310 
 311     
 312     pmix_argv_free(regexargs);
 313 
 314     PMIX_DESTRUCT(&vids);
 315     return PMIX_SUCCESS;
 316 }
 317 
 318 static pmix_status_t generate_ppn(const char *input,
 319                                   char **regexp)
 320 {
 321     char **ppn, **npn;
 322     int i, j, start, end;
 323     pmix_regex_value_t *vreg;
 324     pmix_regex_range_t *rng;
 325     pmix_list_t nodes;
 326     char *tmp, *tmp2;
 327     char *cptr;
 328 
 329     
 330     *regexp = NULL;
 331 
 332     
 333     PMIX_CONSTRUCT(&nodes, pmix_list_t);
 334 
 335     
 336     ppn = pmix_argv_split(input, ';');
 337 
 338     
 339     for (i=0; NULL != ppn[i]; i++) {
 340         rng = NULL;
 341         
 342         vreg = PMIX_NEW(pmix_regex_value_t);
 343         pmix_list_append(&nodes, &vreg->super);
 344         
 345         npn = pmix_argv_split(ppn[i], ',');
 346         
 347         for (j=0; NULL != npn[j]; j++) {
 348             
 349             if (NULL != (cptr = strchr(npn[j], '-'))) {
 350                 
 351                 *cptr = '\0';
 352                 ++cptr;
 353                 start = strtol(npn[j], NULL, 10);
 354                 end = strtol(cptr, NULL, 10);
 355                 
 356                 if (NULL == rng) {
 357                     
 358                     rng = PMIX_NEW(pmix_regex_range_t);
 359                     rng->start = start;
 360                     rng->cnt = end - start + 1;
 361                     pmix_list_append(&vreg->ranges, &rng->super);
 362                 } else {
 363                     
 364                     if (start == (rng->start + rng->cnt)) {
 365                         
 366                         rng->cnt++;
 367                     } else {
 368                         
 369                         rng = PMIX_NEW(pmix_regex_range_t);
 370                         rng->start = start;
 371                         rng->cnt = end - start + 1;
 372                         pmix_list_append(&vreg->ranges, &rng->super);
 373                     }
 374                 }
 375             } else {
 376                 
 377                 start = strtol(npn[j], NULL, 10);
 378                 
 379                 if (NULL == rng) {
 380                     
 381                     rng = PMIX_NEW(pmix_regex_range_t);
 382                     rng->start = start;
 383                     rng->cnt = 1;
 384                     pmix_list_append(&vreg->ranges, &rng->super);
 385                 } else {
 386                     
 387                     if (start == (rng->start + rng->cnt)) {
 388                         
 389                         rng->cnt++;
 390                     } else {
 391                         
 392                         rng = PMIX_NEW(pmix_regex_range_t);
 393                         rng->start = start;
 394                         rng->cnt = 1;
 395                         pmix_list_append(&vreg->ranges, &rng->super);
 396                     }
 397                 }
 398             }
 399         }
 400         pmix_argv_free(npn);
 401     }
 402     pmix_argv_free(ppn);
 403 
 404 
 405     
 406     tmp = strdup("pmix[");
 407     PMIX_LIST_FOREACH(vreg, &nodes, pmix_regex_value_t) {
 408         while (NULL != (rng = (pmix_regex_range_t*)pmix_list_remove_first(&vreg->ranges))) {
 409             if (1 == rng->cnt) {
 410                 if (0 > asprintf(&tmp2, "%s%d,", tmp, rng->start)) {
 411                     return PMIX_ERR_NOMEM;
 412                 }
 413             } else {
 414                 if (0 > asprintf(&tmp2, "%s%d-%d,", tmp, rng->start, rng->start + rng->cnt - 1)) {
 415                     return PMIX_ERR_NOMEM;
 416                 }
 417             }
 418             free(tmp);
 419             tmp = tmp2;
 420             PMIX_RELEASE(rng);
 421         }
 422         
 423         tmp[strlen(tmp)-1] = ';';
 424     }
 425 
 426     
 427     tmp[strlen(tmp)-1] = ']';
 428 
 429     
 430     *regexp = tmp;
 431 
 432     PMIX_LIST_DESTRUCT(&nodes);
 433     return PMIX_SUCCESS;
 434 }
 435 
 436 static pmix_status_t parse_nodes(const char *regexp,
 437                                  char ***names)
 438 {
 439     char *tmp, *ptr;
 440     pmix_status_t rc;
 441 
 442     
 443     *names = NULL;
 444 
 445     
 446     if (NULL == regexp) {
 447         return PMIX_SUCCESS;
 448     }
 449 
 450     
 451     tmp = strdup(regexp);
 452     
 453     tmp[strlen(tmp)-1] = '\0';
 454 
 455     
 456 
 457     if (NULL == (ptr = strchr(tmp, '['))) {
 458         PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
 459         free(tmp);
 460         return PMIX_ERR_BAD_PARAM;
 461     }
 462     *ptr = '\0';
 463     ++ptr;
 464 
 465     
 466     if (0 == strcmp(tmp, "pmix")) {
 467         if (PMIX_SUCCESS != (rc = pmix_regex_extract_nodes(ptr, names))) {
 468             PMIX_ERROR_LOG(rc);
 469         }
 470     } else {
 471         
 472         rc = PMIX_ERR_TAKE_NEXT_OPTION;
 473     }
 474     free(tmp);
 475     return rc;
 476 
 477 }
 478 static pmix_status_t parse_procs(const char *regexp,
 479                                  char ***procs)
 480 {
 481     char *tmp, *ptr;
 482     pmix_status_t rc;
 483 
 484     
 485     *procs = NULL;
 486 
 487     
 488     if (NULL == regexp) {
 489         return PMIX_SUCCESS;
 490     }
 491 
 492     
 493     tmp = strdup(regexp);
 494     
 495     tmp[strlen(tmp)-1] = '\0';
 496 
 497     
 498 
 499     if (NULL == (ptr = strchr(tmp, '['))) {
 500         PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
 501         free(tmp);
 502         return PMIX_ERR_BAD_PARAM;
 503     }
 504     *ptr = '\0';
 505     ++ptr;
 506 
 507     
 508     if (0 == strcmp(tmp, "pmix")) {
 509         if (PMIX_SUCCESS != (rc = pmix_regex_extract_ppn(ptr, procs))) {
 510             PMIX_ERROR_LOG(rc);
 511         }
 512     } else {
 513         
 514         rc = PMIX_ERR_TAKE_NEXT_OPTION;
 515     }
 516     free(tmp);
 517     return rc;
 518 }
 519 
 520 static pmix_status_t resolve_peers(const char *nodename,
 521                                    const char *nspace,
 522                                    pmix_proc_t **procs, size_t *nprocs)
 523 {
 524     pmix_cb_t cb;
 525     pmix_status_t rc;
 526     pmix_kval_t *kv;
 527     pmix_proc_t proc;
 528     char **ptr;
 529     pmix_info_t *info;
 530     pmix_proc_t *p=NULL;
 531     size_t ninfo, np=0, n, j;
 532 
 533     PMIX_CONSTRUCT(&cb, pmix_cb_t);
 534 
 535     cb.key = strdup(nodename);
 536     
 537     cb.copy = false;
 538     
 539     cb.scope = PMIX_SCOPE_UNDEF;
 540     
 541     pmix_strncpy(proc.nspace, nspace, PMIX_MAX_NSLEN);
 542     proc.rank = PMIX_RANK_WILDCARD;
 543     cb.proc = &proc;
 544 
 545     PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb);
 546     if (PMIX_SUCCESS != rc) {
 547         if (PMIX_ERR_INVALID_NAMESPACE != rc) {
 548             PMIX_ERROR_LOG(rc);
 549         }
 550         goto complete;
 551     }
 552     
 553     if (1 != pmix_list_get_size(&cb.kvs)) {
 554         PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
 555         rc = PMIX_ERR_BAD_PARAM;
 556         goto complete;
 557     }
 558     kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs);
 559     
 560 
 561     if (NULL == kv->value ||
 562         PMIX_DATA_ARRAY != kv->value->type ||
 563         NULL == kv->value->data.darray ||
 564         PMIX_INFO != kv->value->data.darray->type) {
 565         PMIX_ERROR_LOG(PMIX_ERR_DATA_VALUE_NOT_FOUND);
 566         rc = PMIX_ERR_DATA_VALUE_NOT_FOUND;
 567         goto complete;
 568     }
 569     info = (pmix_info_t*)kv->value->data.darray->array;
 570     ninfo = kv->value->data.darray->size;
 571     
 572     for (n=0; n < ninfo; n++) {
 573         if (0 == strncmp(info[n].key, PMIX_LOCAL_PEERS, PMIX_MAX_KEYLEN)) {
 574             
 575             ptr = pmix_argv_split(info[n].value.data.string, ',');
 576             np = pmix_argv_count(ptr);
 577             PMIX_PROC_CREATE(p, np);
 578             if (NULL == p) {
 579                 rc = PMIX_ERR_NOMEM;
 580                 pmix_argv_free(ptr);
 581                 goto complete;
 582             }
 583             for (j=0; j < np; j++) {
 584                 pmix_strncpy(p[j].nspace, nspace, PMIX_MAX_NSLEN);
 585                 p[j].rank = strtoul(ptr[j], NULL, 10);
 586             }
 587             rc = PMIX_SUCCESS;
 588             pmix_argv_free(ptr);
 589             break;
 590         }
 591     }
 592 
 593   complete:
 594     if (NULL != cb.info) {
 595         PMIX_INFO_FREE(cb.info, cb.ninfo);
 596     }
 597     if (NULL != cb.key) {
 598         free(cb.key);
 599         cb.key = NULL;
 600     }
 601     PMIX_DESTRUCT(&cb);
 602     *procs = p;
 603     *nprocs = np;
 604 
 605     return rc;
 606 }
 607 
 608 static pmix_status_t resolve_nodes(const char *nspace,
 609                                    char **nodelist)
 610 {
 611     pmix_cb_t cb;
 612     pmix_status_t rc;
 613     pmix_kval_t *kv;
 614     pmix_proc_t proc;
 615 
 616     PMIX_CONSTRUCT(&cb, pmix_cb_t);
 617 
 618     
 619     *nodelist = NULL;
 620 
 621     
 622 
 623     PMIX_INFO_CREATE(cb.info, 1);
 624     if (NULL == cb.info) {
 625         PMIX_DESTRUCT(&cb);
 626         return PMIX_ERR_NOMEM;
 627     }
 628     cb.ninfo = 1;
 629     PMIX_INFO_LOAD(&cb.info[0], PMIX_NSPACE, nspace, PMIX_STRING);
 630 
 631     
 632     cb.key = PMIX_NODE_MAP;
 633     
 634     cb.copy = false;
 635     
 636     cb.scope = PMIX_SCOPE_UNDEF;
 637     
 638     pmix_strncpy(proc.nspace, nspace, PMIX_MAX_NSLEN);
 639     
 640     proc.rank = PMIX_RANK_WILDCARD;
 641     cb.proc = &proc;
 642 
 643     PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb);
 644     if (PMIX_SUCCESS != rc) {
 645         PMIX_ERROR_LOG(rc);
 646         goto complete;
 647     }
 648     
 649     if (1 != pmix_list_get_size(&cb.kvs)) {
 650         PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
 651         rc = PMIX_ERR_BAD_PARAM;
 652         goto complete;
 653     }
 654     kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs);
 655     
 656 
 657     if (NULL == kv->value ||
 658         PMIX_STRING != kv->value->type) {
 659         PMIX_ERROR_LOG(PMIX_ERR_DATA_VALUE_NOT_FOUND);
 660         rc = PMIX_ERR_DATA_VALUE_NOT_FOUND;
 661         goto complete;
 662     }
 663     
 664     if (NULL != kv->value->data.string) {
 665         *nodelist = strdup(kv->value->data.string);
 666     }
 667 
 668   complete:
 669     if (NULL != cb.info) {
 670       PMIX_INFO_FREE(cb.info, cb.ninfo);
 671     }
 672     return rc;
 673 }
 674 
 675 static pmix_status_t pmix_regex_extract_nodes(char *regexp, char ***names)
 676 {
 677     int i, j, k, len;
 678     pmix_status_t ret;
 679     char *base;
 680     char *orig, *suffix;
 681     bool found_range = false;
 682     bool more_to_come = false;
 683     int num_digits;
 684 
 685     
 686     *names = NULL;
 687 
 688     if (NULL == regexp) {
 689         return PMIX_SUCCESS;
 690     }
 691 
 692     orig = base = strdup(regexp);
 693     if (NULL == base) {
 694         PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE);
 695         return PMIX_ERR_OUT_OF_RESOURCE;
 696     }
 697 
 698     PMIX_OUTPUT_VERBOSE((1, pmix_globals.debug_output,
 699                          "pmix:extract:nodes: checking list: %s", regexp));
 700 
 701     do {
 702         
 703         len = strlen(base);
 704         for (i = 0; i <= len; ++i) {
 705             if (base[i] == '[') {
 706                 
 707                 base[i] = '\0';
 708                 found_range = true;
 709                 break;
 710             }
 711             if (base[i] == ',') {
 712                 
 713                 base[i] = '\0';
 714                 found_range = false;
 715                 more_to_come = true;
 716                 break;
 717             }
 718             if (base[i] == '\0') {
 719                 
 720                 found_range = false;
 721                 more_to_come = false;
 722                 break;
 723             }
 724         }
 725         if (i == 0 && !found_range) {
 726             
 727             free(orig);
 728             return PMIX_ERR_BAD_PARAM;
 729         }
 730 
 731         if (found_range) {
 732             
 733             i++;  
 734             for (j=i; j < len; j++) {
 735                 if (base[j] == ':') {
 736                     base[j] = '\0';
 737                     break;
 738                 }
 739             }
 740             if (j >= len) {
 741                 
 742                 free(orig);
 743                 return PMIX_ERR_BAD_PARAM;
 744             }
 745             num_digits = strtol(&base[i], NULL, 10);
 746             i = j + 1;  
 747             
 748             for (j = i; j < len; ++j) {
 749                 if (base[j] == ']') {
 750                     base[j] = '\0';
 751                     break;
 752                 }
 753             }
 754             if (j >= len) {
 755                 
 756                 free(orig);
 757                 return PMIX_ERR_BAD_PARAM;
 758             }
 759             
 760             if (j+1 < len && base[j+1] != ',') {
 761                 
 762                 for (k=j+1; k < len && base[k] != ','; k++);
 763                 if (k < len) {
 764                     base[k] = '\0';
 765                 }
 766                 suffix = strdup(&base[j+1]);
 767                 if (k < len) {
 768                     base[k] = ',';
 769                 }
 770                 j = k-1;
 771             } else {
 772                 suffix = NULL;
 773             }
 774             PMIX_OUTPUT_VERBOSE((1, pmix_globals.debug_output,
 775                                  "regex:extract:nodes: parsing range %s %s %s",
 776                                  base, base + i, suffix));
 777 
 778             ret = regex_parse_value_ranges(base, base + i, num_digits, suffix, names);
 779             if (NULL != suffix) {
 780                 free(suffix);
 781             }
 782             if (PMIX_SUCCESS != ret) {
 783                 free(orig);
 784                 return ret;
 785             }
 786             if (j+1 < len && base[j + 1] == ',') {
 787                 more_to_come = true;
 788                 base = &base[j + 2];
 789             } else {
 790                 more_to_come = false;
 791             }
 792         } else {
 793             
 794             if(PMIX_SUCCESS != (ret = pmix_argv_append_nosize(names, base))) {
 795                 PMIX_ERROR_LOG(ret);
 796                 free(orig);
 797                 return ret;
 798             }
 799             
 800             i++;
 801             
 802             base = &base[i];
 803         }
 804     } while(more_to_come);
 805 
 806     free(orig);
 807 
 808     
 809     return ret;
 810 }
 811 
 812 
 813 
 814 
 815 
 816 
 817 
 818 
 819 
 820 
 821 static pmix_status_t regex_parse_value_ranges(char *base, char *ranges,
 822                                               int num_digits, char *suffix,
 823                                               char ***names)
 824 {
 825     int i, len;
 826     pmix_status_t ret;
 827     char *start, *orig;
 828 
 829     
 830 
 831     len = strlen(ranges);
 832     for (orig = start = ranges, i = 0; i < len; ++i) {
 833         if (',' == ranges[i]) {
 834             ranges[i] = '\0';
 835             ret = regex_parse_value_range(base, start, num_digits, suffix, names);
 836             if (PMIX_SUCCESS != ret) {
 837                 PMIX_ERROR_LOG(ret);
 838                 return ret;
 839             }
 840             start = ranges + i + 1;
 841         }
 842     }
 843 
 844     
 845 
 846     if (start < orig + len) {
 847 
 848         PMIX_OUTPUT_VERBOSE((1, pmix_globals.debug_output,
 849                              "regex:parse:ranges: parse range %s (2)", start));
 850 
 851         ret = regex_parse_value_range(base, start, num_digits, suffix, names);
 852         if (PMIX_SUCCESS != ret) {
 853             PMIX_ERROR_LOG(ret);
 854             return ret;
 855         }
 856     }
 857 
 858     
 859     return PMIX_SUCCESS;
 860 }
 861 
 862 
 863 
 864 
 865 
 866 
 867 
 868 
 869 
 870 
 871 static pmix_status_t regex_parse_value_range(char *base, char *range,
 872                                              int num_digits, char *suffix,
 873                                              char ***names)
 874 {
 875     char *str, tmp[132];
 876     size_t i, k, start, end;
 877     size_t base_len, len;
 878     bool found;
 879     pmix_status_t ret;
 880 
 881     if (NULL == base || NULL == range) {
 882         return PMIX_ERROR;
 883     }
 884 
 885     len = strlen(range);
 886     base_len = strlen(base);
 887     
 888 
 889     start = end = 0;
 890 
 891     
 892 
 893     for (found = false, i = 0; i < len; ++i) {
 894         if (isdigit((int) range[i])) {
 895             if (!found) {
 896                 start = atoi(range + i);
 897                 found = true;
 898                 break;
 899             }
 900         }
 901     }
 902     if (!found) {
 903         PMIX_ERROR_LOG(PMIX_ERR_NOT_FOUND);
 904         return PMIX_ERR_NOT_FOUND;
 905     }
 906 
 907     
 908 
 909     for (found = false; i < len; ++i) {
 910         if (!isdigit(range[i])) {
 911             break;
 912         }
 913     }
 914 
 915     
 916 
 917     if (i >= len) {
 918         end = start;
 919         found = true;
 920     } else {
 921         
 922 
 923 
 924         for (; i < len; ++i) {
 925             if (isdigit(range[i])) {
 926                 end = strtol(range + i, NULL, 10);
 927                 found = true;
 928                 break;
 929             }
 930         }
 931     }
 932     if (!found) {
 933         PMIX_ERROR_LOG(PMIX_ERR_NOT_FOUND);
 934         return PMIX_ERR_NOT_FOUND;
 935     }
 936 
 937     
 938 
 939     len = base_len + num_digits + 32;
 940     if (NULL != suffix) {
 941         len += strlen(suffix);
 942     }
 943     str = (char *) malloc(len);
 944     if (NULL == str) {
 945         PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE);
 946         return PMIX_ERR_OUT_OF_RESOURCE;
 947     }
 948     for (i = start; i <= end; ++i) {
 949         memset(str, 0, len);
 950         strcpy(str, base);
 951         
 952         for (k=0; k < (size_t)num_digits; k++) {
 953             str[k+base_len] = '0';
 954         }
 955         memset(tmp, 0, 132);
 956         snprintf(tmp, 132, "%lu", (unsigned long)i);
 957         for (k=0; k < strlen(tmp); k++) {
 958             str[base_len + num_digits - k - 1] = tmp[strlen(tmp)-k-1];
 959         }
 960         
 961         if (NULL != suffix) {
 962             strcat(str, suffix);
 963         }
 964         ret = pmix_argv_append_nosize(names, str);
 965         if(PMIX_SUCCESS != ret) {
 966             PMIX_ERROR_LOG(ret);
 967             free(str);
 968             return ret;
 969         }
 970     }
 971     free(str);
 972 
 973     
 974     return PMIX_SUCCESS;
 975 }
 976 
 977 static pmix_status_t pmix_regex_extract_ppn(char *regexp, char ***procs)
 978 {
 979     char **rngs, **nds, *t, **ps=NULL;
 980     int i, j, k, start, end;
 981 
 982     
 983     nds = pmix_argv_split(regexp, ';');
 984     for (j=0; NULL != nds[j]; j++) {
 985         
 986         rngs = pmix_argv_split(nds[j], ',');
 987         
 988         for (i=0; NULL != rngs[i]; i++) {
 989             
 990             if (NULL == (t = strchr(rngs[i], '-'))) {
 991                 
 992                 pmix_argv_append_nosize(&ps, rngs[i]);
 993             } else {
 994                 
 995                 *t = '\0';
 996                 start = strtol(rngs[i], NULL, 10);
 997                 ++t;
 998                 end = strtol(t, NULL, 10);
 999                 for (k=start; k <= end; k++) {
1000                     if (0 > asprintf(&t, "%d", k)) {
1001                         pmix_argv_free(nds);
1002                         pmix_argv_free(rngs);
1003                         return PMIX_ERR_NOMEM;
1004                     }
1005                     pmix_argv_append_nosize(&ps, t);
1006                     free(t);
1007                 }
1008             }
1009         }
1010         pmix_argv_free(rngs);
1011         
1012         t = pmix_argv_join(ps, ',');
1013         pmix_argv_append_nosize(procs, t);
1014         free(t);
1015         pmix_argv_free(ps);
1016         ps = NULL;
1017     }
1018 
1019     pmix_argv_free(nds);
1020     return PMIX_SUCCESS;
1021 }