LCOV - code coverage report
Current view: top level - lib/util - util_strlist.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 170 229 74.2 %
Date: 2024-06-13 04:01:37 Functions: 19 22 86.4 %

          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    21676086 : _PUBLIC_ char **str_list_make_empty(TALLOC_CTX *mem_ctx)
      38             : {
      39    21676086 :         char **ret = talloc_zero_array(mem_ctx, char *, 1);
      40    21676086 :         return ret;
      41             : }
      42             : 
      43             : /**
      44             :   place the only element 'entry' into a new, NULL terminated string list
      45             : */
      46      108131 : _PUBLIC_ char **str_list_make_single(TALLOC_CTX *mem_ctx, const char *entry)
      47             : {
      48      108131 :         char **ret = NULL;
      49             : 
      50      108131 :         ret = talloc_array(mem_ctx, char *, 2);
      51      108131 :         if (ret == NULL) {
      52           0 :                 return NULL;
      53             :         }
      54             : 
      55      108131 :         ret[0] = talloc_strdup(ret, entry);
      56      108131 :         if (!ret[0]) {
      57           0 :                 talloc_free(ret);
      58           0 :                 return NULL;
      59             :         }
      60      108131 :         ret[1] = NULL;
      61             : 
      62      108131 :         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      128422 : _PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
      71             : {
      72      128422 :         int num_elements = 0;
      73      128422 :         char **ret = NULL;
      74             : 
      75      128422 :         if (sep == NULL) {
      76       91968 :                 sep = LIST_SEP;
      77             :         }
      78             : 
      79      128422 :         ret = talloc_array(mem_ctx, char *, 1);
      80      128422 :         if (ret == NULL) {
      81           0 :                 return NULL;
      82             :         }
      83             : 
      84      941128 :         while (string && *string) {
      85      708846 :                 size_t len = strcspn(string, sep);
      86             :                 char **ret2;
      87             :                 
      88      708846 :                 if (len == 0) {
      89      290212 :                         string += strspn(string, sep);
      90      290212 :                         continue;
      91             :                 }
      92             : 
      93      418634 :                 ret2 = talloc_realloc(mem_ctx, ret, char *,
      94             :                         num_elements+2);
      95      418634 :                 if (ret2 == NULL) {
      96           0 :                         talloc_free(ret);
      97           0 :                         return NULL;
      98             :                 }
      99      418634 :                 ret = ret2;
     100             : 
     101      418634 :                 ret[num_elements] = talloc_strndup(ret, string, len);
     102      418634 :                 if (ret[num_elements] == NULL) {
     103           0 :                         talloc_free(ret);
     104           0 :                         return NULL;
     105             :                 }
     106             : 
     107      418634 :                 num_elements++;
     108      418634 :                 string += len;
     109             :         }
     110             : 
     111      128422 :         ret[num_elements] = NULL;
     112             : 
     113      128422 :         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         116 : _PUBLIC_ char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
     122             : {
     123         116 :         int num_elements = 0;
     124         116 :         char **ret = NULL;
     125             : 
     126         116 :         ret = talloc_array(mem_ctx, char *, 1);
     127         116 :         if (ret == NULL) {
     128           0 :                 return NULL;
     129             :         }
     130             : 
     131         116 :         if (sep == NULL)
     132         116 :                 sep = " \t\n\r";
     133             : 
     134         495 :         while (string && *string) {
     135         310 :                 size_t len = strcspn(string, sep);
     136             :                 char *element;
     137             :                 char **ret2;
     138             :                 
     139         310 :                 if (len == 0) {
     140         106 :                         string += strspn(string, sep);
     141         106 :                         continue;
     142             :                 }
     143             : 
     144         204 :                 if (*string == '\"') {
     145           0 :                         string++;
     146           0 :                         len = strcspn(string, "\"");
     147           0 :                         element = talloc_strndup(ret, string, len);
     148           0 :                         string += len + 1;
     149             :                 } else {
     150         204 :                         element = talloc_strndup(ret, string, len);
     151         204 :                         string += len;
     152             :                 }
     153             : 
     154         204 :                 if (element == NULL) {
     155           0 :                         talloc_free(ret);
     156           0 :                         return NULL;
     157             :                 }
     158             : 
     159         204 :                 ret2 = talloc_realloc(mem_ctx, ret, char *, num_elements+2);
     160         204 :                 if (ret2 == NULL) {
     161           0 :                         talloc_free(ret);
     162           0 :                         return NULL;
     163             :                 }
     164         204 :                 ret = ret2;
     165             : 
     166         204 :                 ret[num_elements] = element;    
     167             : 
     168         204 :                 num_elements++;
     169             :         }
     170             : 
     171         116 :         ret[num_elements] = NULL;
     172             : 
     173         116 :         return ret;
     174             : 
     175             : }
     176             : 
     177             : /**
     178             :  * join a list back to one string 
     179             :  */
     180      216026 : _PUBLIC_ char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char separator)
     181             : {
     182      216026 :         char *ret = NULL;
     183             :         int i;
     184             :         
     185      216026 :         if (list[0] == NULL)
     186      108013 :                 return talloc_strdup(mem_ctx, "");
     187             : 
     188      108013 :         ret = talloc_strdup(mem_ctx, list[0]);
     189             : 
     190      108013 :         for (i = 1; list[i]; i++) {
     191           0 :                 ret = talloc_asprintf_append_buffer(ret, "%c%s", separator, list[i]);
     192             :         }
     193             : 
     194      108013 :         return ret;
     195             : }
     196             : 
     197             : /** join a list back to one (shell-like) string; entries 
     198             :  * separated by spaces, using quotes where necessary */
     199           0 : _PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep)
     200             : {
     201           0 :         char *ret = NULL;
     202             :         int i;
     203             :         
     204           0 :         if (list[0] == NULL)
     205           0 :                 return talloc_strdup(mem_ctx, "");
     206             : 
     207           0 :         if (strchr(list[0], ' ') || strlen(list[0]) == 0) 
     208           0 :                 ret = talloc_asprintf(mem_ctx, "\"%s\"", list[0]);
     209             :         else 
     210           0 :                 ret = talloc_strdup(mem_ctx, list[0]);
     211             : 
     212           0 :         for (i = 1; list[i]; i++) {
     213           0 :                 if (strchr(list[i], ' ') || strlen(list[i]) == 0) 
     214           0 :                         ret = talloc_asprintf_append_buffer(ret, "%c\"%s\"", sep, list[i]);
     215             :                 else 
     216           0 :                         ret = talloc_asprintf_append_buffer(ret, "%c%s", sep, list[i]);
     217             :         }
     218             : 
     219           0 :         return ret;
     220             : }
     221             : 
     222             : /**
     223             :   return the number of elements in a string list
     224             : */
     225   287875440 : _PUBLIC_ size_t str_list_length(const char * const *list)
     226             : {
     227             :         size_t ret;
     228  2155584734 :         for (ret=0;list && list[ret];ret++) /* noop */ ;
     229   287875440 :         return ret;
     230             : }
     231             : 
     232             : 
     233             : /**
     234             :   copy a string list
     235             : */
     236     2967639 : _PUBLIC_ char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list)
     237             : {
     238             :         int i;
     239             :         char **ret;
     240             : 
     241     2967639 :         if (list == NULL)
     242     1784878 :                 return NULL;
     243             :         
     244     1182761 :         ret = talloc_array(mem_ctx, char *, str_list_length(list)+1);
     245     1182761 :         if (ret == NULL) 
     246           0 :                 return NULL;
     247             : 
     248     7780942 :         for (i=0;list && list[i];i++) {
     249     6598181 :                 ret[i] = talloc_strdup(ret, list[i]);
     250     6598181 :                 if (ret[i] == NULL) {
     251           0 :                         talloc_free(ret);
     252           0 :                         return NULL;
     253             :                 }
     254             :         }
     255     1182761 :         ret[i] = NULL;
     256     1182761 :         return ret;
     257             : }
     258             : 
     259             : /**
     260             :    Return true if all the elements of the list match exactly.
     261             :  */
     262       22833 : _PUBLIC_ bool str_list_equal(const char * const *list1,
     263             :                              const char * const *list2)
     264             : {
     265             :         int i;
     266             :         
     267       22833 :         if (list1 == NULL || list2 == NULL) {
     268       18079 :                 return (list1 == list2); 
     269             :         }
     270             :         
     271       19071 :         for (i=0;list1[i] && list2[i];i++) {
     272       14949 :                 if (strcmp(list1[i], list2[i]) != 0) {
     273         632 :                         return false;
     274             :                 }
     275             :         }
     276        4122 :         if (list1[i] || list2[i]) {
     277           0 :                 return false;
     278             :         }
     279        4122 :         return true;
     280             : }
     281             : 
     282             : 
     283             : /**
     284             :   add an entry to a string list
     285             : */
     286     3543488 : _PUBLIC_ const char **str_list_add(const char **list, const char *s)
     287             : {
     288     3543488 :         size_t len = str_list_length(list);
     289             :         const char **ret;
     290             : 
     291     3543488 :         ret = talloc_realloc(NULL, list, const char *, len+2);
     292     3543488 :         if (ret == NULL) return NULL;
     293             : 
     294     3543488 :         ret[len] = talloc_strdup(ret, s);
     295     3543488 :         if (ret[len] == NULL) return NULL;
     296             : 
     297     3543488 :         ret[len+1] = NULL;
     298             : 
     299     3543488 :         return ret;
     300             : }
     301             : 
     302             : /**
     303             :  * @brief Extend a talloc'ed string list with a printf'ed string
     304             :  *
     305             :  * str_list_add_printf() does nothing if *plist is NULL and it sets
     306             :  * *plist to NULL on failure. It is designed to avoid intermediate
     307             :  * NULL checks:
     308             :  *
     309             :  *     argv = str_list_make_empty(ctx);
     310             :  *     str_list_add_printf(&argv, "smbstatus");
     311             :  *     str_list_add_printf(&argv, "--configfile=%s", config);
     312             :  *     if (argv == NULL) {
     313             :  *        goto nomem;
     314             :  *     }
     315             :  *
     316             :  * @param[in,out] plist The talloc'ed list to extend
     317             :  * @param[in] fmt The format string
     318             :  */
     319        1775 : void str_list_add_printf(char ***plist, const char *fmt, ...)
     320             : {
     321        1775 :         char **list = *plist;
     322             :         size_t len;
     323        1775 :         char **tmp = NULL;
     324             :         va_list ap;
     325             : 
     326        1775 :         if (list == NULL) {
     327        1775 :                 return;
     328             :         }
     329        1775 :         len = str_list_length((const char * const *)list);
     330             : 
     331        1775 :         tmp = talloc_realloc(NULL, list, char *, len+2);
     332        1775 :         if (tmp == NULL) {
     333           0 :                 goto fail;
     334             :         }
     335        1775 :         list = tmp;
     336        1775 :         list[len+1] = NULL;
     337             : 
     338        1775 :         va_start(ap, fmt);
     339        1775 :         list[len] = talloc_vasprintf(list, fmt, ap);
     340        1775 :         va_end(ap);
     341             : 
     342        1775 :         if (list[len] == NULL) {
     343           0 :                 goto fail;
     344             :         }
     345        1775 :         *plist = list;
     346             : 
     347        1775 :         return;
     348           0 : fail:
     349           0 :         TALLOC_FREE(list);
     350           0 :         *plist = NULL;
     351             : }
     352             : 
     353             : /**
     354             :   remove an entry from a string list
     355             : */
     356     5077810 : _PUBLIC_ void str_list_remove(const char **list, const char *s)
     357             : {
     358             :         int i;
     359             : 
     360    10743663 :         for (i=0;list[i];i++) {
     361    10733712 :                 if (strcmp(list[i], s) == 0) break;
     362             :         }
     363     5077810 :         if (!list[i]) return;
     364             : 
     365    19709644 :         for (;list[i];i++) {
     366    14641785 :                 list[i] = list[i+1];
     367             :         }
     368             : }
     369             : 
     370             : 
     371             : /**
     372             :   return true if a string is in a list
     373             : */
     374  1270641908 : _PUBLIC_ bool str_list_check(const char **list, const char *s)
     375             : {
     376             :         int i;
     377             : 
     378  9832275469 :         for (i=0; list != NULL && list[i] != NULL; i++) {
     379  8604072387 :                 if (strcmp(list[i], s) == 0) return true;
     380             :         }
     381  1228203082 :         return false;
     382             : }
     383             : 
     384             : /**
     385             :   return true if a string is in a list, case insensitively
     386             : */
     387     1012177 : _PUBLIC_ bool str_list_check_ci(const char **list, const char *s)
     388             : {
     389             :         int i;
     390             : 
     391    46385866 :         for (i=0; list != NULL && list[i] != NULL; i++) {
     392    46082382 :                 if (strcasecmp(list[i], s) == 0) return true;
     393             :         }
     394      303484 :         return false;
     395             : }
     396             : 
     397             : 
     398             : /**
     399             :   append one list to another - expanding list1
     400             : */
     401           0 : _PUBLIC_ const char **str_list_append(const char **list1,
     402             :         const char * const *list2)
     403             : {
     404           0 :         size_t len1 = str_list_length(list1);
     405           0 :         size_t len2 = str_list_length(list2);
     406             :         const char **ret;
     407             :         size_t i;
     408             : 
     409           0 :         ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
     410           0 :         if (ret == NULL) return NULL;
     411             : 
     412           0 :         for (i=len1;i<len1+len2;i++) {
     413           0 :                 ret[i] = talloc_strdup(ret, list2[i-len1]);
     414           0 :                 if (ret[i] == NULL) {
     415           0 :                         return NULL;
     416             :                 }
     417             :         }
     418           0 :         ret[i] = NULL;
     419             : 
     420           0 :         return ret;
     421             : }
     422             : 
     423   500045981 : static int list_cmp(const char **el1, const char **el2)
     424             : {
     425   500045981 :         return strcmp(*el1, *el2);
     426             : }
     427             : 
     428             : /*
     429             :   return a list that only contains the unique elements of a list,
     430             :   removing any duplicates
     431             :  */
     432    25997163 : _PUBLIC_ const char **str_list_unique(const char **list)
     433             : {
     434    25997163 :         size_t len = str_list_length(list);
     435             :         const char **list2;
     436             :         size_t i, j;
     437    25997163 :         if (len < 2) {
     438    16458528 :                 return list;
     439             :         }
     440     9538635 :         list2 = (const char **)talloc_memdup(list, list,
     441             :                                              sizeof(list[0])*(len+1));
     442     9538635 :         TYPESAFE_QSORT(list2, len, list_cmp);
     443     9538635 :         list[0] = list2[0];
     444   122257948 :         for (i=j=1;i<len;i++) {
     445   112719313 :                 if (strcmp(list2[i], list[j-1]) != 0) {
     446    89743027 :                         list[j] = list2[i];
     447    89743027 :                         j++;
     448             :                 }
     449             :         }
     450     9538635 :         list[j] = NULL;
     451     9538635 :         list = talloc_realloc(NULL, list, const char *, j + 1);
     452     9538635 :         talloc_free(list2);
     453     9538635 :         return list;
     454             : }
     455             : 
     456             : /*
     457             :   very useful when debugging complex list related code
     458             :  */
     459           0 : _PUBLIC_ void str_list_show(const char **list)
     460             : {
     461             :         int i;
     462           0 :         DEBUG(0,("{ "));
     463           0 :         for (i=0;list && list[i];i++) {
     464           0 :                 DEBUG(0,("\"%s\", ", list[i]));
     465             :         }
     466           0 :         DEBUG(0,("}\n"));
     467           0 : }
     468             : 
     469             : 
     470             : 
     471             : /**
     472             :   append one list to another - expanding list1
     473             :   this assumes the elements of list2 are const pointers, so we can re-use them
     474             : */
     475    79414500 : _PUBLIC_ const char **str_list_append_const(const char **list1,
     476             :                                             const char **list2)
     477             : {
     478    79414500 :         size_t len1 = str_list_length(list1);
     479    79414500 :         size_t len2 = str_list_length(list2);
     480             :         const char **ret;
     481             :         size_t i;
     482             : 
     483    79414500 :         ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
     484    79414500 :         if (ret == NULL) return NULL;
     485             : 
     486   165039336 :         for (i=len1;i<len1+len2;i++) {
     487    85624836 :                 ret[i] = list2[i-len1];
     488             :         }
     489    79414500 :         ret[i] = NULL;
     490             : 
     491    79414500 :         return ret;
     492             : }
     493             : 
     494             : /**
     495             :  * Add a string to an array of strings.
     496             :  *
     497             :  * num should be a pointer to an integer that holds the current
     498             :  * number of elements in strings. It will be updated by this function.
     499             :  */
     500      513774 : _PUBLIC_ bool add_string_to_array(TALLOC_CTX *mem_ctx,
     501             :                          const char *str, const char ***strings, size_t *num)
     502             : {
     503      513774 :         char *dup_str = talloc_strdup(mem_ctx, str);
     504             : 
     505      513774 :         *strings = talloc_realloc(mem_ctx,
     506             :                                     *strings,
     507             :                                     const char *, ((*num)+1));
     508             : 
     509      513774 :         if ((*strings == NULL) || (dup_str == NULL)) {
     510           0 :                 *num = 0;
     511           0 :                 return false;
     512             :         }
     513             : 
     514      513774 :         (*strings)[*num] = dup_str;
     515      513774 :         *num += 1;
     516             : 
     517      513774 :         return true;
     518             : }
     519             : 
     520             : /**
     521             :   add an entry to a string list
     522             :   this assumes s will not change
     523             : */
     524    68689431 : _PUBLIC_ const char **str_list_add_const(const char **list, const char *s)
     525             : {
     526    68689431 :         size_t len = str_list_length(list);
     527             :         const char **ret;
     528             : 
     529    68689431 :         ret = talloc_realloc(NULL, list, const char *, len+2);
     530    68689431 :         if (ret == NULL) return NULL;
     531             : 
     532    68689431 :         ret[len] = s;
     533    68689431 :         ret[len+1] = NULL;
     534             : 
     535    68689431 :         return ret;
     536             : }
     537             : 
     538             : /**
     539             :   copy a string list
     540             :   this assumes list will not change
     541             : */
     542    25595123 : _PUBLIC_ const char **str_list_copy_const(TALLOC_CTX *mem_ctx,
     543             :                                           const char **list)
     544             : {
     545             :         int i;
     546             :         const char **ret;
     547             : 
     548    25595123 :         if (list == NULL)
     549    23108699 :                 return NULL;
     550             :         
     551     2486424 :         ret = talloc_array(mem_ctx, const char *, str_list_length(list)+1);
     552     2486424 :         if (ret == NULL) 
     553           0 :                 return NULL;
     554             : 
     555    15012390 :         for (i=0;list && list[i];i++) {
     556    12525966 :                 ret[i] = list[i];
     557             :         }
     558     2486424 :         ret[i] = NULL;
     559     2486424 :         return ret;
     560             : }

Generated by: LCOV version 1.13