doc: Add top-level description about U-Boot documentation
[oweals/u-boot.git] / lib / hashtable.c
index 6050dd0829f9ac3ce3bc399d1cc7e9428af3afa0..0d288d12d991128a6f3d5690e49215d863c3b0dd 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: LGPL-2.1+
 /*
  * This implementation is based on code from uClibc-0.9.30.3 but was
  * modified and extended for use within U-Boot.
@@ -9,21 +10,6 @@
  * Copyright (C) 1993, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
  * This file is part of the GNU C Library.
  * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1993.
- *
- * The GNU C Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * The GNU C Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with the GNU C Library; if not, write to the Free
- * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307 USA.
  */
 
 #include <errno.h>
@@ -54,6 +40,9 @@
 #define        CONFIG_ENV_MAX_ENTRIES 512
 #endif
 
+#define USED_FREE 0
+#define USED_DELETED -1
+
 #include <env_callback.h>
 #include <env_flags.h>
 #include <search.h>
@@ -317,7 +306,7 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
                 */
                unsigned hval2;
 
-               if (htab->table[idx].used == -1
+               if (htab->table[idx].used == USED_DELETED
                    && !first_deleted)
                        first_deleted = idx;
 
@@ -349,13 +338,17 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
                        if (idx == hval)
                                break;
 
+                       if (htab->table[idx].used == USED_DELETED
+                           && !first_deleted)
+                               first_deleted = idx;
+
                        /* If entry is found use it. */
                        ret = _compare_and_overwrite_entry(item, action, retval,
                                htab, flag, hval, idx);
                        if (ret != -1)
                                return ret;
                }
-               while (htab->table[idx].used);
+               while (htab->table[idx].used != USED_FREE);
        }
 
        /* An empty bucket has been found. */
@@ -447,7 +440,7 @@ static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
        free(ep->data);
        ep->callback = NULL;
        ep->flags = 0;
-       htab->table[idx].used = -1;
+       htab->table[idx].used = USED_DELETED;
 
        --htab->filled;
 }
@@ -490,11 +483,11 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
        return 1;
 }
 
+#if !(defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_SAVEENV))
 /*
  * hexport()
  */
 
-#ifndef CONFIG_SPL_BUILD
 /*
  * Export the data stored in the hash table in linearized form.
  *
@@ -512,7 +505,7 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
  *
  * If the separator character is different from NUL, then any
  * separator characters and backslash characters in the values will
- * be escaped by a preceeding backslash in output. This is needed for
+ * be escaped by a preceding backslash in output. This is needed for
  * example to enable multi-line values, especially when the output
  * shall later be parsed (for example, for re-import).
  *
@@ -556,9 +549,8 @@ static int match_string(int flag, const char *str, const char *pat, void *priv)
        case H_MATCH_REGEX:
                {
                        struct slre *slrep = (struct slre *)priv;
-                       struct cap caps[slrep->num_caps + 2];
 
-                       if (slre_match(slrep, str, strlen(str), caps))
+                       if (slre_match(slrep, str, strlen(str), NULL))
                                return 1;
                }
                break;
@@ -577,7 +569,7 @@ static int match_entry(ENTRY *ep, int flag,
        int arg;
        void *priv = NULL;
 
-       for (arg = 1; arg < argc; ++arg) {
+       for (arg = 0; arg < argc; ++arg) {
 #ifdef CONFIG_REGEX
                struct slre slre;
 
@@ -615,8 +607,8 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,
                return (-1);
        }
 
-       debug("EXPORT  table = %p, htab.size = %d, htab.filled = %d, "
-               "size = %zu\n", htab, htab->size, htab->filled, size);
+       debug("EXPORT  table = %p, htab.size = %d, htab.filled = %d, size = %lu\n",
+             htab, htab->size, htab->filled, (ulong)size);
        /*
         * Pass 1:
         * search used entries,
@@ -636,7 +628,7 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,
 
                        list[n++] = ep;
 
-                       totlen += strlen(ep->key) + 2;
+                       totlen += strlen(ep->key);
 
                        if (sep == '\0') {
                                totlen += strlen(ep->data);
@@ -670,8 +662,8 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,
        /* Check if the user supplied buffer size is sufficient */
        if (size) {
                if (size < totlen + 1) {        /* provided buffer too small */
-                       printf("Env export buffer too small: %zu, "
-                               "but need %zu\n", size, totlen + 1);
+                       printf("Env export buffer too small: %lu, but need %lu\n",
+                              (ulong)size, (ulong)totlen + 1);
                        __set_errno(ENOMEM);
                        return (-1);
                }
@@ -763,8 +755,11 @@ static int drop_var_from_set(const char *name, int nvars, char * vars[])
  *
  * The "flag" argument can be used to control the behaviour: when the
  * H_NOCLEAR bit is set, then an existing hash table will kept, i. e.
- * new data will be added to an existing hash table; otherwise, old
- * data will be discarded and a new hash table will be created.
+ * new data will be added to an existing hash table; otherwise, if no
+ * vars are passed, old data will be discarded and a new hash table
+ * will be created. If vars are passed, passed vars that are not in
+ * the linear list of "name=value" pairs will be removed from the
+ * current hash table.
  *
  * The separator character for the "name=value" pairs can be selected,
  * so we both support importing from externally stored environment
@@ -789,7 +784,7 @@ static int drop_var_from_set(const char *name, int nvars, char * vars[])
 
 int himport_r(struct hsearch_data *htab,
                const char *env, size_t size, const char sep, int flag,
-               int nvars, char * const vars[])
+               int crlf_is_lf, int nvars, char * const vars[])
 {
        char *data, *sp, *dp, *name, *value;
        char *localvars[nvars];
@@ -802,19 +797,20 @@ int himport_r(struct hsearch_data *htab,
        }
 
        /* we allocate new space to make sure we can write to the array */
-       if ((data = malloc(size)) == NULL) {
-               debug("himport_r: can't malloc %zu bytes\n", size);
+       if ((data = malloc(size + 1)) == NULL) {
+               debug("himport_r: can't malloc %lu bytes\n", (ulong)size + 1);
                __set_errno(ENOMEM);
                return 0;
        }
        memcpy(data, env, size);
+       data[size] = '\0';
        dp = data;
 
        /* make a local copy of the list of variables */
        if (nvars)
                memcpy(localvars, vars, sizeof(vars[0]) * nvars);
 
-       if ((flag & H_NOCLEAR) == 0) {
+       if ((flag & H_NOCLEAR) == 0 && !nvars) {
                /* Destroy old hash table if one exists */
                debug("Destroy Hash Table: %p table = %p\n", htab,
                       htab->table);
@@ -830,11 +826,11 @@ int himport_r(struct hsearch_data *htab,
         * size of 8 per entry (= safety factor of ~5) should provide enough
         * safety margin for any existing environment definitions and still
         * allow for more than enough dynamic additions. Note that the
-        * "size" argument is supposed to give the maximum enviroment size
+        * "size" argument is supposed to give the maximum environment size
         * (CONFIG_ENV_SIZE).  This heuristics will result in
         * unreasonably large numbers (and thus memory footprint) for
         * big flash environments (>8,000 entries for 64 KB
-        * envrionment size), so we clip it to a reasonable value.
+        * environment size), so we clip it to a reasonable value.
         * On the other hand we need to add some more entries for free
         * space when importing very small buffers. Both boundaries can
         * be overwritten in the board config file if needed.
@@ -854,6 +850,23 @@ int himport_r(struct hsearch_data *htab,
                }
        }
 
+       if (!size) {
+               free(data);
+               return 1;               /* everything OK */
+       }
+       if(crlf_is_lf) {
+               /* Remove Carriage Returns in front of Line Feeds */
+               unsigned ignored_crs = 0;
+               for(;dp < data + size && *dp; ++dp) {
+                       if(*dp == '\r' &&
+                          dp < data + size - 1 && *(dp+1) == '\n')
+                               ++ignored_crs;
+                       else
+                               *(dp-ignored_crs) = *dp;
+               }
+               size -= ignored_crs;
+               dp = data;
+       }
        /* Parse environment; allow for '\0' and 'sep' as separators */
        do {
                ENTRY e, *rv;
@@ -901,6 +914,13 @@ int himport_r(struct hsearch_data *htab,
                *sp++ = '\0';   /* terminate value */
                ++dp;
 
+               if (*name == 0) {
+                       debug("INSERT: unable to use an empty key\n");
+                       __set_errno(EINVAL);
+                       free(data);
+                       return 0;
+               }
+
                /* Skip variables which are not supposed to be processed */
                if (!drop_var_from_set(name, nvars, localvars))
                        continue;
@@ -922,6 +942,9 @@ int himport_r(struct hsearch_data *htab,
        debug("INSERT: free(data = %p)\n", data);
        free(data);
 
+       if (flag & H_NOCLEAR)
+               goto end;
+
        /* process variables which were not considered */
        for (i = 0; i < nvars; i++) {
                if (localvars[i] == NULL)
@@ -940,6 +963,7 @@ int himport_r(struct hsearch_data *htab,
                        printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]);
        }
 
+end:
        debug("INSERT: done\n");
        return 1;               /* everything OK */
 }