LCOV - code coverage report
Current view: top level - lib/util - util_strlist.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 221 254 87.0 %
Date: 2024-05-31 13:13:24 Functions: 21 22 95.5 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Copyright (C) Andrew Tridgell 2005
       5             :    Copyright (C) Jelmer Vernooij 2005
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "replace.h"
      22             : #include "debug.h"
      23             : #include "tsort.h"
      24             : 
      25             : #include "util_strlist.h"
      26             : 
      27             : #undef strcasecmp
      28             : 
      29             : /**
      30             :  * @file
      31             :  * @brief String list manipulation
      32             :  */
      33             : 
      34             : /**
      35             :   build an empty (only NULL terminated) list of strings (for expansion with str_list_add() etc)
      36             : */
      37    31567765 : _PUBLIC_ char **str_list_make_empty(TALLOC_CTX *mem_ctx)
      38             : {
      39    31567765 :         char **ret = talloc_zero_array(mem_ctx, char *, 1);
      40    31567765 :         return ret;
      41             : }
      42             : 
      43             : /**
      44             :   place the only element 'entry' into a new, NULL terminated string list
      45             : */
      46      181708 : _PUBLIC_ char **str_list_make_single(TALLOC_CTX *mem_ctx, const char *entry)
      47             : {
      48      181708 :         char **ret = NULL;
      49             : 
      50      181708 :         ret = talloc_array(mem_ctx, char *, 2);
      51      181708 :         if (ret == NULL) {
      52           0 :                 return NULL;
      53             :         }
      54             : 
      55      181708 :         ret[0] = talloc_strdup(ret, entry);
      56      181708 :         if (!ret[0]) {
      57           0 :                 talloc_free(ret);
      58           0 :                 return NULL;
      59             :         }
      60      181708 :         ret[1] = NULL;
      61             : 
      62      181708 :         return ret;
      63             : }
      64             : 
      65             : /**
      66             :   build a null terminated list of strings from a input string and a
      67             :   separator list. The separator list must contain characters less than
      68             :   or equal to 0x2f for this to work correctly on multi-byte strings
      69             : */
      70      200915 : _PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
      71             : {
      72      200915 :         int num_elements = 0;
      73      200915 :         char **ret = NULL;
      74             : 
      75      200915 :         if (sep == NULL) {
      76      150250 :                 sep = LIST_SEP;
      77             :         }
      78             : 
      79      200915 :         ret = talloc_array(mem_ctx, char *, 1);
      80      200915 :         if (ret == NULL) {
      81           0 :                 return NULL;
      82             :         }
      83             : 
      84     1339121 :         while (string && *string) {
      85     1138206 :                 size_t len = strcspn(string, sep);
      86       28672 :                 char **ret2;
      87             : 
      88     1138206 :                 if (len == 0) {
      89      468647 :                         string += strspn(string, sep);
      90      468647 :                         continue;
      91             :                 }
      92             : 
      93      669559 :                 ret2 = talloc_realloc(mem_ctx, ret, char *,
      94             :                         num_elements+2);
      95      669559 :                 if (ret2 == NULL) {
      96           0 :                         talloc_free(ret);
      97           0 :                         return NULL;
      98             :                 }
      99      669559 :                 ret = ret2;
     100             : 
     101      669559 :                 ret[num_elements] = talloc_strndup(ret, string, len);
     102      669559 :                 if (ret[num_elements] == NULL) {
     103           0 :                         talloc_free(ret);
     104           0 :                         return NULL;
     105             :                 }
     106             : 
     107      669559 :                 num_elements++;
     108      669559 :                 string += len;
     109             :         }
     110             : 
     111      200915 :         ret[num_elements] = NULL;
     112             : 
     113      200915 :         return ret;
     114             : }
     115             : 
     116             : /**
     117             :  * build a null terminated list of strings from an argv-like input string
     118             :  * Entries are separated by spaces and can be enclosed by quotes.
     119             :  * Does NOT support escaping
     120             :  */
     121         112 : _PUBLIC_ char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
     122             : {
     123         112 :         int num_elements = 0;
     124         112 :         char **ret = NULL;
     125             : 
     126         112 :         ret = talloc_array(mem_ctx, char *, 1);
     127         112 :         if (ret == NULL) {
     128           0 :                 return NULL;
     129             :         }
     130             : 
     131         112 :         if (sep == NULL)
     132         110 :                 sep = " \t\n\r";
     133             : 
     134         447 :         while (string && *string) {
     135         335 :                 size_t len = strcspn(string, sep);
     136          45 :                 char *element;
     137          45 :                 char **ret2;
     138             : 
     139         335 :                 if (len == 0) {
     140         121 :                         string += strspn(string, sep);
     141         121 :                         continue;
     142             :                 }
     143             : 
     144         214 :                 if (*string == '\"') {
     145          11 :                         string++;
     146          11 :                         len = strcspn(string, "\"");
     147          11 :                         element = talloc_strndup(ret, string, len);
     148          11 :                         string += len + 1;
     149             :                 } else {
     150         203 :                         element = talloc_strndup(ret, string, len);
     151         203 :                         string += len;
     152             :                 }
     153             : 
     154         214 :                 if (element == NULL) {
     155           0 :                         talloc_free(ret);
     156           0 :                         return NULL;
     157             :                 }
     158             : 
     159         214 :                 ret2 = talloc_realloc(mem_ctx, ret, char *, num_elements+2);
     160         214 :                 if (ret2 == NULL) {
     161           0 :                         talloc_free(ret);
     162           0 :                         return NULL;
     163             :                 }
     164         214 :                 ret = ret2;
     165             : 
     166         214 :                 ret[num_elements] = element;
     167             : 
     168         214 :                 num_elements++;
     169             :         }
     170             : 
     171         112 :         ret[num_elements] = NULL;
     172             : 
     173         112 :         return ret;
     174             : 
     175             : }
     176             : 
     177             : /**
     178             :  * join a list back to one string
     179             :  */
     180      363178 : _PUBLIC_ char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char separator)
     181             : {
     182      363178 :         char *ret = NULL;
     183       12156 :         int i;
     184             : 
     185      363178 :         if (list[0] == NULL)
     186      181589 :                 return talloc_strdup(mem_ctx, "");
     187             : 
     188      181589 :         ret = talloc_strdup(mem_ctx, list[0]);
     189             : 
     190      181589 :         for (i = 1; list[i]; i++) {
     191           0 :                 talloc_asprintf_addbuf(&ret, "%c%s", separator, list[i]);
     192             :         }
     193             : 
     194      181589 :         return ret;
     195             : }
     196             : 
     197             : /** join a list back to one (shell-like) string; entries
     198             :  * separated by spaces, using quotes where necessary */
     199           8 : _PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep)
     200             : {
     201           8 :         char *ret = NULL;
     202           8 :         int i;
     203             : 
     204           8 :         if (list[0] == NULL)
     205           1 :                 return talloc_strdup(mem_ctx, "");
     206             : 
     207           7 :         if (strchr(list[0], ' ') || strlen(list[0]) == 0)
     208           2 :                 ret = talloc_asprintf(mem_ctx, "\"%s\"", list[0]);
     209             :         else
     210           5 :                 ret = talloc_strdup(mem_ctx, list[0]);
     211             : 
     212          15 :         for (i = 1; list[i]; i++) {
     213           8 :                 if (strchr(list[i], ' ') || strlen(list[i]) == 0) {
     214           4 :                         talloc_asprintf_addbuf(&ret, "%c\"%s\"", sep, list[i]);
     215             :                 } else {
     216           4 :                         talloc_asprintf_addbuf(&ret, "%c%s", sep, list[i]);
     217             :                 }
     218             :         }
     219             : 
     220           7 :         return ret;
     221             : }
     222             : 
     223             : /**
     224             :   return the number of elements in a string list
     225             : */
     226   426521867 : _PUBLIC_ size_t str_list_length(const char * const *list)
     227             : {
     228     8050425 :         size_t ret;
     229 11356966691 :         for (ret=0;list && list[ret];ret++) /* noop */ ;
     230   426521867 :         return ret;
     231             : }
     232             : 
     233             : 
     234             : /**
     235             :   copy a string list
     236             : */
     237    17330452 : _PUBLIC_ char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list)
     238             : {
     239      153993 :         int i;
     240      153993 :         char **ret;
     241             : 
     242    17330452 :         if (list == NULL)
     243    12980037 :                 return NULL;
     244             : 
     245     4313533 :         ret = talloc_array(mem_ctx, char *, str_list_length(list)+1);
     246     4313533 :         if (ret == NULL)
     247           0 :                 return NULL;
     248             : 
     249    25271299 :         for (i=0;list && list[i];i++) {
     250    20957766 :                 ret[i] = talloc_strdup(ret, list[i]);
     251    20957766 :                 if (ret[i] == NULL) {
     252           0 :                         talloc_free(ret);
     253           0 :                         return NULL;
     254             :                 }
     255             :         }
     256     4313533 :         ret[i] = NULL;
     257     4313533 :         return ret;
     258             : }
     259             : 
     260             : /**
     261             :    Return true if all the elements of the list match exactly.
     262             :  */
     263       34805 : _PUBLIC_ bool str_list_equal(const char * const *list1,
     264             :                              const char * const *list2)
     265             : {
     266         971 :         int i;
     267             : 
     268       34805 :         if (list1 == NULL || list2 == NULL) {
     269       28126 :                 return (list1 == list2);
     270             :         }
     271             : 
     272       27082 :         for (i=0;list1[i] && list2[i];i++) {
     273       21299 :                 if (strcmp(list1[i], list2[i]) != 0) {
     274         886 :                         return false;
     275             :                 }
     276             :         }
     277        5783 :         if (list1[i] || list2[i]) {
     278          44 :                 return false;
     279             :         }
     280        5586 :         return true;
     281             : }
     282             : 
     283             : 
     284             : /**
     285             :   add an entry to a string list
     286             : */
     287     5739315 : _PUBLIC_ const char **str_list_add(const char **list, const char *s)
     288             : {
     289     5739315 :         size_t len = str_list_length(list);
     290      129980 :         const char **ret;
     291             : 
     292     5739315 :         ret = talloc_realloc(NULL, list, const char *, len+2);
     293     5739315 :         if (ret == NULL) return NULL;
     294             : 
     295     5739315 :         ret[len] = talloc_strdup(ret, s);
     296     5739315 :         if (ret[len] == NULL) return NULL;
     297             : 
     298     5739315 :         ret[len+1] = NULL;
     299             : 
     300     5739315 :         return ret;
     301             : }
     302             : 
     303             : /**
     304             :  * @brief Extend a talloc'ed string list with a printf'ed string
     305             :  *
     306             :  * str_list_add_printf() does nothing if *plist is NULL and it sets
     307             :  * *plist to NULL on failure. It is designed to avoid intermediate
     308             :  * NULL checks:
     309             :  *
     310             :  *     argv = str_list_make_empty(ctx);
     311             :  *     str_list_add_printf(&argv, "smbstatus");
     312             :  *     str_list_add_printf(&argv, "--configfile=%s", config);
     313             :  *     if (argv == NULL) {
     314             :  *        goto nomem;
     315             :  *     }
     316             :  *
     317             :  * @param[in,out] plist The talloc'ed list to extend
     318             :  * @param[in] fmt The format string
     319             :  */
     320       10280 : void str_list_add_printf(char ***plist, const char *fmt, ...)
     321             : {
     322       10280 :         char **list = *plist;
     323           3 :         size_t len;
     324       10280 :         char **tmp = NULL;
     325           3 :         va_list ap;
     326             : 
     327       10280 :         if (list == NULL) {
     328       10280 :                 return;
     329             :         }
     330       10279 :         len = str_list_length((const char * const *)list);
     331             : 
     332       10279 :         tmp = talloc_realloc(NULL, list, char *, len+2);
     333       10279 :         if (tmp == NULL) {
     334           0 :                 goto fail;
     335             :         }
     336       10279 :         list = tmp;
     337       10279 :         list[len+1] = NULL;
     338             : 
     339       10279 :         va_start(ap, fmt);
     340       10279 :         list[len] = talloc_vasprintf(list, fmt, ap);
     341       10279 :         va_end(ap);
     342             : 
     343       10279 :         if (list[len] == NULL) {
     344           0 :                 goto fail;
     345             :         }
     346       10279 :         *plist = list;
     347             : 
     348       10279 :         return;
     349           0 : fail:
     350           0 :         TALLOC_FREE(list);
     351           0 :         *plist = NULL;
     352             : }
     353             : 
     354             : /**
     355             :   remove an entry from a string list
     356             : */
     357     7967820 : _PUBLIC_ void str_list_remove(const char **list, const char *s)
     358             : {
     359      822601 :         int i;
     360             : 
     361    16982953 :         for (i=0;list[i];i++) {
     362    16963677 :                 if (strcmp(list[i], s) == 0) break;
     363             :         }
     364     7967820 :         if (!list[i]) return;
     365             : 
     366    30807422 :         for (;list[i];i++) {
     367    22858878 :                 list[i] = list[i+1];
     368             :         }
     369             : }
     370             : 
     371             : 
     372             : /**
     373             :   return true if a string is in a list
     374             : */
     375  1899749461 : _PUBLIC_ bool str_list_check(const char **list, const char *s)
     376             : {
     377    24301931 :         int i;
     378             : 
     379 15023806831 :         for (i=0; list != NULL && list[i] != NULL; i++) {
     380 13189136798 :                 if (strcmp(list[i], s) == 0) return true;
     381             :         }
     382  1813159243 :         return false;
     383             : }
     384             : 
     385             : /**
     386             :   return true if a string is in a list, case insensitively
     387             : */
     388     1596902 : _PUBLIC_ bool str_list_check_ci(const char **list, const char *s)
     389             : {
     390       99923 :         int i;
     391             : 
     392    71682260 :         for (i=0; list != NULL && list[i] != NULL; i++) {
     393    71215081 :                 if (strcasecmp(list[i], s) == 0) return true;
     394             :         }
     395      461015 :         return false;
     396             : }
     397             : 
     398             : 
     399             : /**
     400             :   append one list to another - expanding list1
     401             : */
     402           8 : _PUBLIC_ const char **str_list_append(const char **list1,
     403             :         const char * const *list2)
     404             : {
     405           8 :         size_t len1 = str_list_length(list1);
     406           8 :         size_t len2 = str_list_length(list2);
     407           8 :         const char **ret;
     408           8 :         size_t i;
     409             : 
     410           8 :         ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
     411           8 :         if (ret == NULL) return NULL;
     412             : 
     413          74 :         for (i=len1;i<len1+len2;i++) {
     414          66 :                 ret[i] = talloc_strdup(ret, list2[i-len1]);
     415          66 :                 if (ret[i] == NULL) {
     416           0 :                         return NULL;
     417             :                 }
     418             :         }
     419           8 :         ret[i] = NULL;
     420             : 
     421           8 :         return ret;
     422             : }
     423             : 
     424   748219897 : static int list_cmp(const char **el1, const char **el2)
     425             : {
     426   748219897 :         return strcmp(*el1, *el2);
     427             : }
     428             : 
     429             : /*
     430             :   return a list that only contains the unique elements of a list,
     431             :   removing any duplicates
     432             :  */
     433    37935127 : _PUBLIC_ const char **str_list_unique(const char **list)
     434             : {
     435    37935127 :         size_t len = str_list_length(list);
     436      437431 :         const char **list2;
     437      437431 :         size_t i, j;
     438    37935127 :         if (len < 2) {
     439    23832748 :                 return list;
     440             :         }
     441    13818140 :         list2 = (const char **)talloc_memdup(list, list,
     442             :                                              sizeof(list[0])*(len+1));
     443    13818140 :         TYPESAFE_QSORT(list2, len, list_cmp);
     444    13818140 :         list[0] = list2[0];
     445   181452256 :         for (i=j=1;i<len;i++) {
     446   167634116 :                 if (strcmp(list2[i], list[j-1]) != 0) {
     447   133834280 :                         list[j] = list2[i];
     448   133834280 :                         j++;
     449             :                 }
     450             :         }
     451    13818140 :         list[j] = NULL;
     452    13818140 :         list = talloc_realloc(NULL, list, const char *, j + 1);
     453    13818140 :         talloc_free(list2);
     454    13818140 :         return list;
     455             : }
     456             : 
     457             : /*
     458             :   very useful when debugging complex list related code
     459             :  */
     460           0 : _PUBLIC_ void str_list_show(const char **list)
     461             : {
     462           0 :         int i;
     463           0 :         DEBUG(0,("{ "));
     464           0 :         for (i=0;list && list[i];i++) {
     465           0 :                 DEBUG(0,("\"%s\", ", list[i]));
     466             :         }
     467           0 :         DEBUG(0,("}\n"));
     468           0 : }
     469             : 
     470             : 
     471             : 
     472             : /**
     473             :   append one list to another - expanding list1
     474             :   this assumes the elements of list2 are const pointers, so we can re-use them
     475             : */
     476   115491281 : _PUBLIC_ const char **str_list_append_const(const char **list1,
     477             :                                             const char **list2)
     478             : {
     479   115491281 :         size_t len1 = str_list_length(list1);
     480   115491281 :         size_t len2 = str_list_length(list2);
     481     1306270 :         const char **ret;
     482     1306270 :         size_t i;
     483             : 
     484   115491281 :         ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
     485   115491281 :         if (ret == NULL) return NULL;
     486             : 
     487   243248888 :         for (i=len1;i<len1+len2;i++) {
     488   127757607 :                 ret[i] = list2[i-len1];
     489             :         }
     490   115491281 :         ret[i] = NULL;
     491             : 
     492   115491281 :         return ret;
     493             : }
     494             : 
     495             : /**
     496             :  * Add a string to an array of strings.
     497             :  *
     498             :  * num should be a pointer to an integer that holds the current
     499             :  * number of elements in strings. It will be updated by this function.
     500             :  */
     501      606947 : _PUBLIC_ bool add_string_to_array(TALLOC_CTX *mem_ctx,
     502             :                          const char *str, const char ***strings, size_t *num)
     503             : {
     504      606947 :         char *dup_str = talloc_strdup(mem_ctx, str);
     505             : 
     506      606947 :         *strings = talloc_realloc(mem_ctx,
     507             :                                     *strings,
     508             :                                     const char *, ((*num)+1));
     509             : 
     510      606947 :         if ((*strings == NULL) || (dup_str == NULL)) {
     511           0 :                 *num = 0;
     512           0 :                 return false;
     513             :         }
     514             : 
     515      606947 :         (*strings)[*num] = dup_str;
     516      606947 :         *num += 1;
     517             : 
     518      606947 :         return true;
     519             : }
     520             : 
     521             : /**
     522             :   add an entry to a string list
     523             :   this assumes s will not change
     524             : */
     525   102243657 : _PUBLIC_ const char **str_list_add_const(const char **list, const char *s)
     526             : {
     527   102243657 :         size_t len = str_list_length(list);
     528     1177066 :         const char **ret;
     529             : 
     530   102243657 :         ret = talloc_realloc(NULL, list, const char *, len+2);
     531   102243657 :         if (ret == NULL) return NULL;
     532             : 
     533   102243657 :         ret[len] = s;
     534   102243657 :         ret[len+1] = NULL;
     535             : 
     536   102243657 :         return ret;
     537             : }
     538             : 
     539             : /**
     540             :   copy a string list
     541             :   this assumes list will not change
     542             : */
     543    36869172 : _PUBLIC_ const char **str_list_copy_const(TALLOC_CTX *mem_ctx,
     544             :                                           const char **list)
     545             : {
     546      418492 :         int i;
     547      418492 :         const char **ret;
     548             : 
     549    36869172 :         if (list == NULL)
     550    32891138 :                 return NULL;
     551             : 
     552     3605621 :         ret = talloc_array(mem_ctx, const char *, str_list_length(list)+1);
     553     3605621 :         if (ret == NULL)
     554           0 :                 return NULL;
     555             : 
     556    21991907 :         for (i=0;list && list[i];i++) {
     557    18386286 :                 ret[i] = list[i];
     558             :         }
     559     3605621 :         ret[i] = NULL;
     560     3605621 :         return ret;
     561             : }

Generated by: LCOV version 1.14