root/opal/mca/pmix/pmix4x/pmix/src/util/argv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pmix_argv_append
  2. pmix_argv_append_nosize
  3. pmix_argv_prepend_nosize
  4. pmix_argv_append_unique_idx
  5. pmix_argv_append_unique_nosize
  6. pmix_argv_free
  7. pmix_argv_split_inter
  8. pmix_argv_split
  9. pmix_argv_split_with_empty
  10. pmix_argv_count
  11. pmix_argv_join
  12. pmix_argv_join_range
  13. pmix_argv_len
  14. pmix_argv_copy
  15. pmix_argv_delete
  16. pmix_argv_insert
  17. pmix_argv_insert_element

   1 /*
   2  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
   3  *                         University Research and Technology
   4  *                         Corporation.  All rights reserved.
   5  * Copyright (c) 2004-2005 The University of Tennessee and The University
   6  *                         of Tennessee Research Foundation.  All rights
   7  *                         reserved.
   8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
   9  *                         University of Stuttgart.  All rights reserved.
  10  * Copyright (c) 2004-2005 The Regents of the University of California.
  11  *                         All rights reserved.
  12  * Copyright (c) 2007      Voltaire. All rights reserved.
  13  * Copyright (c) 2012      Los Alamos National Security, LLC. All rights reserved.
  14  * Copyright (c) 2014-2018 Intel, Inc.  All rights reserved.
  15  *
  16  * Copyright (c) 2015      Research Organization for Information Science
  17  *                         and Technology (RIST). All rights reserved.
  18  * $COPYRIGHT$
  19  *
  20  * Additional copyrights may follow
  21  *
  22  * $HEADER$
  23  */
  24 
  25 #include <src/include/pmix_config.h>
  26 
  27 
  28 #ifdef HAVE_STDLIB_H
  29 #include <stdlib.h>
  30 #endif  /* HAVE_STDLIB_H */
  31 #ifdef HAVE_STRING_H
  32 #include <string.h>
  33 #endif  /* HAVE_STRING_H */
  34 
  35 #include "src/util/argv.h"
  36 
  37 #define ARGSIZE 128
  38 
  39 
  40 /*
  41  * Append a string to the end of a new or existing argv array.
  42  */
  43 pmix_status_t pmix_argv_append(int *argc, char ***argv, const char *arg)
  44 {
  45     pmix_status_t rc;
  46 
  47     /* add the new element */
  48     if (PMIX_SUCCESS != (rc = pmix_argv_append_nosize(argv, arg))) {
  49         return rc;
  50     }
  51 
  52     *argc = pmix_argv_count(*argv);
  53 
  54     return PMIX_SUCCESS;
  55 }
  56 
  57 pmix_status_t pmix_argv_append_nosize(char ***argv, const char *arg)
  58 {
  59     int argc;
  60 
  61   /* Create new argv. */
  62 
  63   if (NULL == *argv) {
  64     *argv = (char**) malloc(2 * sizeof(char *));
  65     if (NULL == *argv) {
  66         return PMIX_ERR_OUT_OF_RESOURCE;
  67     }
  68     argc = 0;
  69     (*argv)[0] = NULL;
  70     (*argv)[1] = NULL;
  71   }
  72 
  73   /* Extend existing argv. */
  74   else {
  75         /* count how many entries currently exist */
  76         argc = pmix_argv_count(*argv);
  77 
  78         *argv = (char**) realloc(*argv, (argc + 2) * sizeof(char *));
  79         if (NULL == *argv) {
  80             return PMIX_ERR_OUT_OF_RESOURCE;
  81         }
  82     }
  83 
  84     /* Set the newest element to point to a copy of the arg string */
  85 
  86     (*argv)[argc] = strdup(arg);
  87     if (NULL == (*argv)[argc]) {
  88         return PMIX_ERR_OUT_OF_RESOURCE;
  89     }
  90 
  91     argc = argc + 1;
  92     (*argv)[argc] = NULL;
  93 
  94     return PMIX_SUCCESS;
  95 }
  96 
  97 pmix_status_t pmix_argv_prepend_nosize(char ***argv, const char *arg)
  98 {
  99     int argc;
 100     int i;
 101 
 102     /* Create new argv. */
 103 
 104     if (NULL == *argv) {
 105         *argv = (char**) malloc(2 * sizeof(char *));
 106         if (NULL == *argv) {
 107             return PMIX_ERR_OUT_OF_RESOURCE;
 108         }
 109         (*argv)[0] = strdup(arg);
 110         (*argv)[1] = NULL;
 111     } else {
 112         /* count how many entries currently exist */
 113         argc = pmix_argv_count(*argv);
 114 
 115         *argv = (char**) realloc(*argv, (argc + 2) * sizeof(char *));
 116         if (NULL == *argv) {
 117             return PMIX_ERR_OUT_OF_RESOURCE;
 118         }
 119         (*argv)[argc+1] = NULL;
 120 
 121         /* shift all existing elements down 1 */
 122         for (i=argc; 0 < i; i--) {
 123             (*argv)[i] = (*argv)[i-1];
 124         }
 125         (*argv)[0] = strdup(arg);
 126     }
 127 
 128     return PMIX_SUCCESS;
 129 }
 130 
 131 pmix_status_t pmix_argv_append_unique_idx(int *idx, char ***argv, const char *arg)
 132 {
 133     int i;
 134     pmix_status_t rc;
 135 
 136     /* if the provided array is NULL, then the arg cannot be present,
 137      * so just go ahead and append
 138      */
 139     if (NULL == *argv) {
 140         goto add;
 141     }
 142     /* see if this arg is already present in the array */
 143     for (i=0; NULL != (*argv)[i]; i++) {
 144         if (0 == strcmp(arg, (*argv)[i])) {
 145             /* already exists */
 146             *idx = i;
 147             return PMIX_SUCCESS;
 148         }
 149     }
 150 add:
 151     if (PMIX_SUCCESS != (rc = pmix_argv_append_nosize(argv, arg))) {
 152         return rc;
 153     }
 154     *idx = pmix_argv_count(*argv)-1;
 155 
 156     return PMIX_SUCCESS;
 157 }
 158 
 159 pmix_status_t pmix_argv_append_unique_nosize(char ***argv, const char *arg)
 160 {
 161     int i;
 162 
 163     /* if the provided array is NULL, then the arg cannot be present,
 164      * so just go ahead and append
 165      */
 166     if (NULL == *argv) {
 167         return pmix_argv_append_nosize(argv, arg);
 168     }
 169 
 170     /* see if this arg is already present in the array */
 171     for (i=0; NULL != (*argv)[i]; i++) {
 172         if (0 == strcmp(arg, (*argv)[i])) {
 173             /* already exists */
 174             return PMIX_SUCCESS;
 175         }
 176     }
 177 
 178     /* we get here if the arg is not in the array - so add it */
 179     return pmix_argv_append_nosize(argv, arg);
 180 }
 181 
 182 /*
 183  * Free a NULL-terminated argv array.
 184  */
 185 void pmix_argv_free(char **argv)
 186 {
 187   char **p;
 188 
 189   if (NULL == argv)
 190     return;
 191 
 192   for (p = argv; NULL != *p; ++p) {
 193     free(*p);
 194   }
 195 
 196   free(argv);
 197 }
 198 
 199 
 200 /*
 201  * Split a string into a NULL-terminated argv array.
 202  */
 203 static char **pmix_argv_split_inter(const char *src_string, int delimiter,
 204         int include_empty)
 205 {
 206   char arg[ARGSIZE];
 207   char **argv = NULL;
 208   const char *p;
 209   char *argtemp;
 210   int argc = 0;
 211   size_t arglen;
 212 
 213   while (src_string && *src_string) {
 214     p = src_string;
 215     arglen = 0;
 216 
 217     while (('\0' != *p) && (*p != delimiter)) {
 218       ++p;
 219       ++arglen;
 220     }
 221 
 222     /* zero length argument, skip */
 223 
 224     if (src_string == p) {
 225       if (include_empty) {
 226         arg[0] = '\0';
 227         if (PMIX_SUCCESS != pmix_argv_append(&argc, &argv, arg))
 228           return NULL;
 229       }
 230     }
 231 
 232     /* tail argument, add straight from the original string */
 233 
 234     else if ('\0' == *p) {
 235       if (PMIX_SUCCESS != pmix_argv_append(&argc, &argv, src_string))
 236         return NULL;
 237       src_string = p;
 238       continue;
 239     }
 240 
 241     /* long argument, malloc buffer, copy and add */
 242 
 243     else if (arglen > (ARGSIZE - 1)) {
 244         argtemp = (char*) malloc(arglen + 1);
 245       if (NULL == argtemp)
 246         return NULL;
 247 
 248       pmix_strncpy(argtemp, src_string, arglen);
 249       argtemp[arglen] = '\0';
 250 
 251       if (PMIX_SUCCESS != pmix_argv_append(&argc, &argv, argtemp)) {
 252         free(argtemp);
 253         return NULL;
 254       }
 255 
 256       free(argtemp);
 257     }
 258 
 259     /* short argument, copy to buffer and add */
 260 
 261     else {
 262       pmix_strncpy(arg, src_string, arglen);
 263       arg[arglen] = '\0';
 264 
 265       if (PMIX_SUCCESS != pmix_argv_append(&argc, &argv, arg))
 266         return NULL;
 267     }
 268 
 269     src_string = p + 1;
 270   }
 271 
 272   /* All done */
 273 
 274   return argv;
 275 }
 276 
 277 char **pmix_argv_split(const char *src_string, int delimiter)
 278 {
 279     return pmix_argv_split_inter(src_string, delimiter, 0);
 280 }
 281 
 282 char **pmix_argv_split_with_empty(const char *src_string, int delimiter)
 283 {
 284     return pmix_argv_split_inter(src_string, delimiter, 1);
 285 }
 286 
 287 /*
 288  * Return the length of a NULL-terminated argv array.
 289  */
 290 int pmix_argv_count(char **argv)
 291 {
 292   char **p;
 293   int i;
 294 
 295   if (NULL == argv)
 296     return 0;
 297 
 298   for (i = 0, p = argv; *p; i++, p++)
 299     continue;
 300 
 301   return i;
 302 }
 303 
 304 
 305 /*
 306  * Join all the elements of an argv array into a single
 307  * newly-allocated string.
 308  */
 309 char *pmix_argv_join(char **argv, int delimiter)
 310 {
 311   char **p;
 312   char *pp;
 313   char *str;
 314   size_t str_len = 0;
 315   size_t i;
 316 
 317   /* Bozo case */
 318 
 319   if (NULL == argv || NULL == argv[0]) {
 320       return strdup("");
 321   }
 322 
 323   /* Find the total string length in argv including delimiters.  The
 324      last delimiter is replaced by the NULL character. */
 325 
 326   for (p = argv; *p; ++p) {
 327     str_len += strlen(*p) + 1;
 328   }
 329 
 330   /* Allocate the string. */
 331 
 332   if (NULL == (str = (char*) malloc(str_len)))
 333     return NULL;
 334 
 335   /* Loop filling in the string. */
 336 
 337   str[--str_len] = '\0';
 338   p = argv;
 339   pp = *p;
 340 
 341   for (i = 0; i < str_len; ++i) {
 342     if ('\0' == *pp) {
 343 
 344       /* End of a string, fill in a delimiter and go to the next
 345          string. */
 346 
 347       str[i] = (char) delimiter;
 348       ++p;
 349       pp = *p;
 350     } else {
 351       str[i] = *pp++;
 352     }
 353   }
 354 
 355   /* All done */
 356 
 357   return str;
 358 }
 359 
 360 
 361 /*
 362  * Join all the elements of an argv array from within a
 363  * specified range into a single newly-allocated string.
 364  */
 365 char *pmix_argv_join_range(char **argv, size_t start, size_t end, int delimiter)
 366 {
 367     char **p;
 368     char *pp;
 369     char *str;
 370     size_t str_len = 0;
 371     size_t i;
 372 
 373     /* Bozo case */
 374 
 375     if (NULL == argv || NULL == argv[0] || (int)start > pmix_argv_count(argv)) {
 376         return strdup("");
 377     }
 378 
 379     /* Find the total string length in argv including delimiters.  The
 380      last delimiter is replaced by the NULL character. */
 381 
 382     for (p = &argv[start], i=start; *p && i < end; ++p, ++i) {
 383         str_len += strlen(*p) + 1;
 384     }
 385 
 386     /* Allocate the string. */
 387 
 388     if (NULL == (str = (char*) malloc(str_len)))
 389         return NULL;
 390 
 391     /* Loop filling in the string. */
 392 
 393     str[--str_len] = '\0';
 394     p = &argv[start];
 395     pp = *p;
 396 
 397     for (i = 0; i < str_len; ++i) {
 398         if ('\0' == *pp) {
 399 
 400             /* End of a string, fill in a delimiter and go to the next
 401              string. */
 402 
 403             str[i] = (char) delimiter;
 404             ++p;
 405             pp = *p;
 406         } else {
 407             str[i] = *pp++;
 408         }
 409     }
 410 
 411     /* All done */
 412 
 413     return str;
 414 }
 415 
 416 
 417 /*
 418  * Return the number of bytes consumed by an argv array.
 419  */
 420 size_t pmix_argv_len(char **argv)
 421 {
 422   char **p;
 423   size_t length;
 424 
 425   if (NULL == argv)
 426     return (size_t) 0;
 427 
 428   length = sizeof(char *);
 429 
 430   for (p = argv; *p; ++p) {
 431     length += strlen(*p) + 1 + sizeof(char *);
 432   }
 433 
 434   return length;
 435 }
 436 
 437 
 438 /*
 439  * Copy a NULL-terminated argv array.
 440  */
 441 char **pmix_argv_copy(char **argv)
 442 {
 443   char **dupv = NULL;
 444   int dupc = 0;
 445 
 446   if (NULL == argv)
 447     return NULL;
 448 
 449   /* create an "empty" list, so that we return something valid if we
 450      were passed a valid list with no contained elements */
 451   dupv = (char**) malloc(sizeof(char*));
 452   dupv[0] = NULL;
 453 
 454   while (NULL != *argv) {
 455     if (PMIX_SUCCESS != pmix_argv_append(&dupc, &dupv, *argv)) {
 456       pmix_argv_free(dupv);
 457       return NULL;
 458     }
 459 
 460     ++argv;
 461   }
 462 
 463   /* All done */
 464 
 465   return dupv;
 466 }
 467 
 468 
 469 pmix_status_t pmix_argv_delete(int *argc, char ***argv, int start, int num_to_delete)
 470 {
 471     int i;
 472     int count;
 473     int suffix_count;
 474     char **tmp;
 475 
 476     /* Check for the bozo cases */
 477     if (NULL == argv || NULL == *argv || 0 == num_to_delete) {
 478         return PMIX_SUCCESS;
 479     }
 480     count = pmix_argv_count(*argv);
 481     if (start > count) {
 482         return PMIX_SUCCESS;
 483     } else if (start < 0 || num_to_delete < 0) {
 484         return PMIX_ERR_BAD_PARAM;
 485     }
 486 
 487     /* Ok, we have some tokens to delete.  Calculate the new length of
 488        the argv array. */
 489 
 490     suffix_count = count - (start + num_to_delete);
 491     if (suffix_count < 0) {
 492         suffix_count = 0;
 493     }
 494 
 495     /* Free all items that are being deleted */
 496 
 497     for (i = start; i < count && i < start + num_to_delete; ++i) {
 498         free((*argv)[i]);
 499     }
 500 
 501     /* Copy the suffix over the deleted items */
 502 
 503     for (i = start; i < start + suffix_count; ++i) {
 504         (*argv)[i] = (*argv)[i + num_to_delete];
 505     }
 506 
 507     /* Add the trailing NULL */
 508 
 509     (*argv)[i] = NULL;
 510 
 511     /* adjust the argv array */
 512     tmp = (char**)realloc(*argv, sizeof(char*) * (i + 1));
 513     if (NULL != tmp) *argv = tmp;
 514 
 515     /* adjust the argc */
 516     (*argc) -= num_to_delete;
 517 
 518     return PMIX_SUCCESS;
 519 }
 520 
 521 
 522 pmix_status_t pmix_argv_insert(char ***target, int start, char **source)
 523 {
 524     int i, source_count, target_count;
 525     int suffix_count;
 526 
 527     /* Check for the bozo cases */
 528 
 529     if (NULL == target || NULL == *target || start < 0) {
 530         return PMIX_ERR_BAD_PARAM;
 531     } else if (NULL == source) {
 532         return PMIX_SUCCESS;
 533     }
 534 
 535     /* Easy case: appending to the end */
 536 
 537     target_count = pmix_argv_count(*target);
 538     source_count = pmix_argv_count(source);
 539     if (start > target_count) {
 540         for (i = 0; i < source_count; ++i) {
 541             pmix_argv_append(&target_count, target, source[i]);
 542         }
 543     }
 544 
 545     /* Harder: insertting into the middle */
 546 
 547     else {
 548 
 549         /* Alloc out new space */
 550 
 551         *target = (char**) realloc(*target,
 552                                    sizeof(char *) * (target_count + source_count + 1));
 553 
 554         /* Move suffix items down to the end */
 555 
 556         suffix_count = target_count - start;
 557         for (i = suffix_count - 1; i >= 0; --i) {
 558             (*target)[start + source_count + i] =
 559                 (*target)[start + i];
 560         }
 561         (*target)[start + suffix_count + source_count] = NULL;
 562 
 563         /* Strdup in the source argv */
 564 
 565         for (i = start; i < start + source_count; ++i) {
 566             (*target)[i] = strdup(source[i - start]);
 567         }
 568     }
 569 
 570     /* All done */
 571 
 572     return PMIX_SUCCESS;
 573 }
 574 
 575 pmix_status_t pmix_argv_insert_element(char ***target, int location, char *source)
 576 {
 577     int i, target_count;
 578     int suffix_count;
 579 
 580     /* Check for the bozo cases */
 581 
 582     if (NULL == target || NULL == *target || location < 0) {
 583         return PMIX_ERR_BAD_PARAM;
 584     } else if (NULL == source) {
 585         return PMIX_SUCCESS;
 586     }
 587 
 588     /* Easy case: appending to the end */
 589     target_count = pmix_argv_count(*target);
 590     if (location > target_count) {
 591         pmix_argv_append(&target_count, target, source);
 592         return PMIX_SUCCESS;
 593     }
 594 
 595     /* Alloc out new space */
 596     *target = (char**) realloc(*target,
 597                                sizeof(char*) * (target_count + 2));
 598 
 599     /* Move suffix items down to the end */
 600     suffix_count = target_count - location;
 601     for (i = suffix_count - 1; i >= 0; --i) {
 602         (*target)[location + 1 + i] =
 603         (*target)[location + i];
 604     }
 605     (*target)[location + suffix_count + 1] = NULL;
 606 
 607     /* Strdup in the source */
 608     (*target)[location] = strdup(source);
 609 
 610     /* All done */
 611     return PMIX_SUCCESS;
 612 }

/* [<][>][^][v][top][bottom][index][help] */