1*a6826fbcSWolfgang Denk /* 2*a6826fbcSWolfgang Denk * This implementation is based on code from uClibc-0.9.30.3 but was 3*a6826fbcSWolfgang Denk * modified and extended for use within U-Boot. 4*a6826fbcSWolfgang Denk * 5*a6826fbcSWolfgang Denk * Copyright (C) 2010 Wolfgang Denk <wd@denx.de> 6*a6826fbcSWolfgang Denk * 7*a6826fbcSWolfgang Denk * Original license header: 8*a6826fbcSWolfgang Denk * 9*a6826fbcSWolfgang Denk * Copyright (C) 1993, 1995, 1996, 1997, 2002 Free Software Foundation, Inc. 10*a6826fbcSWolfgang Denk * This file is part of the GNU C Library. 11*a6826fbcSWolfgang Denk * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1993. 12*a6826fbcSWolfgang Denk * 13*a6826fbcSWolfgang Denk * The GNU C Library is free software; you can redistribute it and/or 14*a6826fbcSWolfgang Denk * modify it under the terms of the GNU Lesser General Public 15*a6826fbcSWolfgang Denk * License as published by the Free Software Foundation; either 16*a6826fbcSWolfgang Denk * version 2.1 of the License, or (at your option) any later version. 17*a6826fbcSWolfgang Denk * 18*a6826fbcSWolfgang Denk * The GNU C Library is distributed in the hope that it will be useful, 19*a6826fbcSWolfgang Denk * but WITHOUT ANY WARRANTY; without even the implied warranty of 20*a6826fbcSWolfgang Denk * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21*a6826fbcSWolfgang Denk * Lesser General Public License for more details. 22*a6826fbcSWolfgang Denk * 23*a6826fbcSWolfgang Denk * You should have received a copy of the GNU Lesser General Public 24*a6826fbcSWolfgang Denk * License along with the GNU C Library; if not, write to the Free 25*a6826fbcSWolfgang Denk * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 26*a6826fbcSWolfgang Denk * 02111-1307 USA. 27*a6826fbcSWolfgang Denk */ 28*a6826fbcSWolfgang Denk 29*a6826fbcSWolfgang Denk #include <errno.h> 30*a6826fbcSWolfgang Denk #include <malloc.h> 31*a6826fbcSWolfgang Denk 32*a6826fbcSWolfgang Denk #ifdef USE_HOSTCC /* HOST build */ 33*a6826fbcSWolfgang Denk # include <string.h> 34*a6826fbcSWolfgang Denk # include <assert.h> 35*a6826fbcSWolfgang Denk 36*a6826fbcSWolfgang Denk # ifndef debug 37*a6826fbcSWolfgang Denk # ifdef DEBUG 38*a6826fbcSWolfgang Denk # define debug(fmt,args...) printf(fmt ,##args) 39*a6826fbcSWolfgang Denk # else 40*a6826fbcSWolfgang Denk # define debug(fmt,args...) 41*a6826fbcSWolfgang Denk # endif 42*a6826fbcSWolfgang Denk # endif 43*a6826fbcSWolfgang Denk #else /* U-Boot build */ 44*a6826fbcSWolfgang Denk # include <common.h> 45*a6826fbcSWolfgang Denk # include <linux/string.h> 46*a6826fbcSWolfgang Denk #endif 47*a6826fbcSWolfgang Denk 48*a6826fbcSWolfgang Denk #include "search.h" 49*a6826fbcSWolfgang Denk 50*a6826fbcSWolfgang Denk /* 51*a6826fbcSWolfgang Denk * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 52*a6826fbcSWolfgang Denk * [Knuth] The Art of Computer Programming, part 3 (6.4) 53*a6826fbcSWolfgang Denk */ 54*a6826fbcSWolfgang Denk 55*a6826fbcSWolfgang Denk /* 56*a6826fbcSWolfgang Denk * The non-reentrant version use a global space for storing the hash table. 57*a6826fbcSWolfgang Denk */ 58*a6826fbcSWolfgang Denk static struct hsearch_data htab; 59*a6826fbcSWolfgang Denk 60*a6826fbcSWolfgang Denk /* 61*a6826fbcSWolfgang Denk * The reentrant version has no static variables to maintain the state. 62*a6826fbcSWolfgang Denk * Instead the interface of all functions is extended to take an argument 63*a6826fbcSWolfgang Denk * which describes the current status. 64*a6826fbcSWolfgang Denk */ 65*a6826fbcSWolfgang Denk typedef struct _ENTRY { 66*a6826fbcSWolfgang Denk unsigned int used; 67*a6826fbcSWolfgang Denk ENTRY entry; 68*a6826fbcSWolfgang Denk } _ENTRY; 69*a6826fbcSWolfgang Denk 70*a6826fbcSWolfgang Denk 71*a6826fbcSWolfgang Denk /* 72*a6826fbcSWolfgang Denk * hcreate() 73*a6826fbcSWolfgang Denk */ 74*a6826fbcSWolfgang Denk 75*a6826fbcSWolfgang Denk /* 76*a6826fbcSWolfgang Denk * For the used double hash method the table size has to be a prime. To 77*a6826fbcSWolfgang Denk * correct the user given table size we need a prime test. This trivial 78*a6826fbcSWolfgang Denk * algorithm is adequate because 79*a6826fbcSWolfgang Denk * a) the code is (most probably) called a few times per program run and 80*a6826fbcSWolfgang Denk * b) the number is small because the table must fit in the core 81*a6826fbcSWolfgang Denk * */ 82*a6826fbcSWolfgang Denk static int isprime(unsigned int number) 83*a6826fbcSWolfgang Denk { 84*a6826fbcSWolfgang Denk /* no even number will be passed */ 85*a6826fbcSWolfgang Denk unsigned int div = 3; 86*a6826fbcSWolfgang Denk 87*a6826fbcSWolfgang Denk while (div * div < number && number % div != 0) 88*a6826fbcSWolfgang Denk div += 2; 89*a6826fbcSWolfgang Denk 90*a6826fbcSWolfgang Denk return number % div != 0; 91*a6826fbcSWolfgang Denk } 92*a6826fbcSWolfgang Denk 93*a6826fbcSWolfgang Denk int hcreate(size_t nel) 94*a6826fbcSWolfgang Denk { 95*a6826fbcSWolfgang Denk return hcreate_r(nel, &htab); 96*a6826fbcSWolfgang Denk } 97*a6826fbcSWolfgang Denk 98*a6826fbcSWolfgang Denk /* 99*a6826fbcSWolfgang Denk * Before using the hash table we must allocate memory for it. 100*a6826fbcSWolfgang Denk * Test for an existing table are done. We allocate one element 101*a6826fbcSWolfgang Denk * more as the found prime number says. This is done for more effective 102*a6826fbcSWolfgang Denk * indexing as explained in the comment for the hsearch function. 103*a6826fbcSWolfgang Denk * The contents of the table is zeroed, especially the field used 104*a6826fbcSWolfgang Denk * becomes zero. 105*a6826fbcSWolfgang Denk */ 106*a6826fbcSWolfgang Denk int hcreate_r(size_t nel, struct hsearch_data *htab) 107*a6826fbcSWolfgang Denk { 108*a6826fbcSWolfgang Denk /* Test for correct arguments. */ 109*a6826fbcSWolfgang Denk if (htab == NULL) { 110*a6826fbcSWolfgang Denk __set_errno(EINVAL); 111*a6826fbcSWolfgang Denk return 0; 112*a6826fbcSWolfgang Denk } 113*a6826fbcSWolfgang Denk 114*a6826fbcSWolfgang Denk /* There is still another table active. Return with error. */ 115*a6826fbcSWolfgang Denk if (htab->table != NULL) 116*a6826fbcSWolfgang Denk return 0; 117*a6826fbcSWolfgang Denk 118*a6826fbcSWolfgang Denk /* Change nel to the first prime number not smaller as nel. */ 119*a6826fbcSWolfgang Denk nel |= 1; /* make odd */ 120*a6826fbcSWolfgang Denk while (!isprime(nel)) 121*a6826fbcSWolfgang Denk nel += 2; 122*a6826fbcSWolfgang Denk 123*a6826fbcSWolfgang Denk htab->size = nel; 124*a6826fbcSWolfgang Denk htab->filled = 0; 125*a6826fbcSWolfgang Denk 126*a6826fbcSWolfgang Denk /* allocate memory and zero out */ 127*a6826fbcSWolfgang Denk htab->table = (_ENTRY *) calloc(htab->size + 1, sizeof(_ENTRY)); 128*a6826fbcSWolfgang Denk if (htab->table == NULL) 129*a6826fbcSWolfgang Denk return 0; 130*a6826fbcSWolfgang Denk 131*a6826fbcSWolfgang Denk /* everything went alright */ 132*a6826fbcSWolfgang Denk return 1; 133*a6826fbcSWolfgang Denk } 134*a6826fbcSWolfgang Denk 135*a6826fbcSWolfgang Denk 136*a6826fbcSWolfgang Denk /* 137*a6826fbcSWolfgang Denk * hdestroy() 138*a6826fbcSWolfgang Denk */ 139*a6826fbcSWolfgang Denk void hdestroy(void) 140*a6826fbcSWolfgang Denk { 141*a6826fbcSWolfgang Denk hdestroy_r(&htab); 142*a6826fbcSWolfgang Denk } 143*a6826fbcSWolfgang Denk 144*a6826fbcSWolfgang Denk /* 145*a6826fbcSWolfgang Denk * After using the hash table it has to be destroyed. The used memory can 146*a6826fbcSWolfgang Denk * be freed and the local static variable can be marked as not used. 147*a6826fbcSWolfgang Denk */ 148*a6826fbcSWolfgang Denk void hdestroy_r(struct hsearch_data *htab) 149*a6826fbcSWolfgang Denk { 150*a6826fbcSWolfgang Denk int i; 151*a6826fbcSWolfgang Denk 152*a6826fbcSWolfgang Denk /* Test for correct arguments. */ 153*a6826fbcSWolfgang Denk if (htab == NULL) { 154*a6826fbcSWolfgang Denk __set_errno(EINVAL); 155*a6826fbcSWolfgang Denk return; 156*a6826fbcSWolfgang Denk } 157*a6826fbcSWolfgang Denk 158*a6826fbcSWolfgang Denk /* free used memory */ 159*a6826fbcSWolfgang Denk for (i = 1; i <= htab->size; ++i) { 160*a6826fbcSWolfgang Denk if (htab->table[i].used) { 161*a6826fbcSWolfgang Denk ENTRY *ep = &htab->table[i].entry; 162*a6826fbcSWolfgang Denk 163*a6826fbcSWolfgang Denk free(ep->key); 164*a6826fbcSWolfgang Denk free(ep->data); 165*a6826fbcSWolfgang Denk } 166*a6826fbcSWolfgang Denk } 167*a6826fbcSWolfgang Denk free(htab->table); 168*a6826fbcSWolfgang Denk 169*a6826fbcSWolfgang Denk /* the sign for an existing table is an value != NULL in htable */ 170*a6826fbcSWolfgang Denk htab->table = NULL; 171*a6826fbcSWolfgang Denk } 172*a6826fbcSWolfgang Denk 173*a6826fbcSWolfgang Denk /* 174*a6826fbcSWolfgang Denk * hsearch() 175*a6826fbcSWolfgang Denk */ 176*a6826fbcSWolfgang Denk 177*a6826fbcSWolfgang Denk /* 178*a6826fbcSWolfgang Denk * This is the search function. It uses double hashing with open addressing. 179*a6826fbcSWolfgang Denk * The argument item.key has to be a pointer to an zero terminated, most 180*a6826fbcSWolfgang Denk * probably strings of chars. The function for generating a number of the 181*a6826fbcSWolfgang Denk * strings is simple but fast. It can be replaced by a more complex function 182*a6826fbcSWolfgang Denk * like ajw (see [Aho,Sethi,Ullman]) if the needs are shown. 183*a6826fbcSWolfgang Denk * 184*a6826fbcSWolfgang Denk * We use an trick to speed up the lookup. The table is created by hcreate 185*a6826fbcSWolfgang Denk * with one more element available. This enables us to use the index zero 186*a6826fbcSWolfgang Denk * special. This index will never be used because we store the first hash 187*a6826fbcSWolfgang Denk * index in the field used where zero means not used. Every other value 188*a6826fbcSWolfgang Denk * means used. The used field can be used as a first fast comparison for 189*a6826fbcSWolfgang Denk * equality of the stored and the parameter value. This helps to prevent 190*a6826fbcSWolfgang Denk * unnecessary expensive calls of strcmp. 191*a6826fbcSWolfgang Denk * 192*a6826fbcSWolfgang Denk * This implementation differs from the standard library version of 193*a6826fbcSWolfgang Denk * this function in a number of ways: 194*a6826fbcSWolfgang Denk * 195*a6826fbcSWolfgang Denk * - While the standard version does not make any assumptions about 196*a6826fbcSWolfgang Denk * the type of the stored data objects at all, this implementation 197*a6826fbcSWolfgang Denk * works with NUL terminated strings only. 198*a6826fbcSWolfgang Denk * - Instead of storing just pointers to the original objects, we 199*a6826fbcSWolfgang Denk * create local copies so the caller does not need to care about the 200*a6826fbcSWolfgang Denk * data any more. 201*a6826fbcSWolfgang Denk * - The standard implementation does not provide a way to update an 202*a6826fbcSWolfgang Denk * existing entry. This version will create a new entry or update an 203*a6826fbcSWolfgang Denk * existing one when both "action == ENTER" and "item.data != NULL". 204*a6826fbcSWolfgang Denk * - Instead of returning 1 on success, we return the index into the 205*a6826fbcSWolfgang Denk * internal hash table, which is also guaranteed to be positive. 206*a6826fbcSWolfgang Denk * This allows us direct access to the found hash table slot for 207*a6826fbcSWolfgang Denk * example for functions like hdelete(). 208*a6826fbcSWolfgang Denk */ 209*a6826fbcSWolfgang Denk 210*a6826fbcSWolfgang Denk ENTRY *hsearch(ENTRY item, ACTION action) 211*a6826fbcSWolfgang Denk { 212*a6826fbcSWolfgang Denk ENTRY *result; 213*a6826fbcSWolfgang Denk 214*a6826fbcSWolfgang Denk (void) hsearch_r(item, action, &result, &htab); 215*a6826fbcSWolfgang Denk 216*a6826fbcSWolfgang Denk return result; 217*a6826fbcSWolfgang Denk } 218*a6826fbcSWolfgang Denk 219*a6826fbcSWolfgang Denk int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, 220*a6826fbcSWolfgang Denk struct hsearch_data *htab) 221*a6826fbcSWolfgang Denk { 222*a6826fbcSWolfgang Denk unsigned int hval; 223*a6826fbcSWolfgang Denk unsigned int count; 224*a6826fbcSWolfgang Denk unsigned int len = strlen(item.key); 225*a6826fbcSWolfgang Denk unsigned int idx; 226*a6826fbcSWolfgang Denk 227*a6826fbcSWolfgang Denk /* Compute an value for the given string. Perhaps use a better method. */ 228*a6826fbcSWolfgang Denk hval = len; 229*a6826fbcSWolfgang Denk count = len; 230*a6826fbcSWolfgang Denk while (count-- > 0) { 231*a6826fbcSWolfgang Denk hval <<= 4; 232*a6826fbcSWolfgang Denk hval += item.key[count]; 233*a6826fbcSWolfgang Denk } 234*a6826fbcSWolfgang Denk 235*a6826fbcSWolfgang Denk /* 236*a6826fbcSWolfgang Denk * First hash function: 237*a6826fbcSWolfgang Denk * simply take the modul but prevent zero. 238*a6826fbcSWolfgang Denk */ 239*a6826fbcSWolfgang Denk hval %= htab->size; 240*a6826fbcSWolfgang Denk if (hval == 0) 241*a6826fbcSWolfgang Denk ++hval; 242*a6826fbcSWolfgang Denk 243*a6826fbcSWolfgang Denk /* The first index tried. */ 244*a6826fbcSWolfgang Denk idx = hval; 245*a6826fbcSWolfgang Denk 246*a6826fbcSWolfgang Denk if (htab->table[idx].used) { 247*a6826fbcSWolfgang Denk /* 248*a6826fbcSWolfgang Denk * Further action might be required according to the 249*a6826fbcSWolfgang Denk * action value. 250*a6826fbcSWolfgang Denk */ 251*a6826fbcSWolfgang Denk unsigned hval2; 252*a6826fbcSWolfgang Denk 253*a6826fbcSWolfgang Denk if (htab->table[idx].used == hval 254*a6826fbcSWolfgang Denk && strcmp(item.key, htab->table[idx].entry.key) == 0) { 255*a6826fbcSWolfgang Denk /* Overwrite existing value? */ 256*a6826fbcSWolfgang Denk if ((action == ENTER) && (item.data != NULL)) { 257*a6826fbcSWolfgang Denk free(htab->table[idx].entry.data); 258*a6826fbcSWolfgang Denk htab->table[idx].entry.data = 259*a6826fbcSWolfgang Denk strdup(item.data); 260*a6826fbcSWolfgang Denk if (!htab->table[idx].entry.data) { 261*a6826fbcSWolfgang Denk __set_errno(ENOMEM); 262*a6826fbcSWolfgang Denk *retval = NULL; 263*a6826fbcSWolfgang Denk return 0; 264*a6826fbcSWolfgang Denk } 265*a6826fbcSWolfgang Denk } 266*a6826fbcSWolfgang Denk /* return found entry */ 267*a6826fbcSWolfgang Denk *retval = &htab->table[idx].entry; 268*a6826fbcSWolfgang Denk return idx; 269*a6826fbcSWolfgang Denk } 270*a6826fbcSWolfgang Denk 271*a6826fbcSWolfgang Denk /* 272*a6826fbcSWolfgang Denk * Second hash function: 273*a6826fbcSWolfgang Denk * as suggested in [Knuth] 274*a6826fbcSWolfgang Denk */ 275*a6826fbcSWolfgang Denk hval2 = 1 + hval % (htab->size - 2); 276*a6826fbcSWolfgang Denk 277*a6826fbcSWolfgang Denk do { 278*a6826fbcSWolfgang Denk /* 279*a6826fbcSWolfgang Denk * Because SIZE is prime this guarantees to 280*a6826fbcSWolfgang Denk * step through all available indices. 281*a6826fbcSWolfgang Denk */ 282*a6826fbcSWolfgang Denk if (idx <= hval2) 283*a6826fbcSWolfgang Denk idx = htab->size + idx - hval2; 284*a6826fbcSWolfgang Denk else 285*a6826fbcSWolfgang Denk idx -= hval2; 286*a6826fbcSWolfgang Denk 287*a6826fbcSWolfgang Denk /* 288*a6826fbcSWolfgang Denk * If we visited all entries leave the loop 289*a6826fbcSWolfgang Denk * unsuccessfully. 290*a6826fbcSWolfgang Denk */ 291*a6826fbcSWolfgang Denk if (idx == hval) 292*a6826fbcSWolfgang Denk break; 293*a6826fbcSWolfgang Denk 294*a6826fbcSWolfgang Denk /* If entry is found use it. */ 295*a6826fbcSWolfgang Denk if ((htab->table[idx].used == hval) 296*a6826fbcSWolfgang Denk && strcmp(item.key, htab->table[idx].entry.key) == 0) { 297*a6826fbcSWolfgang Denk /* Overwrite existing value? */ 298*a6826fbcSWolfgang Denk if ((action == ENTER) && (item.data != NULL)) { 299*a6826fbcSWolfgang Denk free(htab->table[idx].entry.data); 300*a6826fbcSWolfgang Denk htab->table[idx].entry.data = 301*a6826fbcSWolfgang Denk strdup(item.data); 302*a6826fbcSWolfgang Denk if (!htab->table[idx].entry.data) { 303*a6826fbcSWolfgang Denk __set_errno(ENOMEM); 304*a6826fbcSWolfgang Denk *retval = NULL; 305*a6826fbcSWolfgang Denk return 0; 306*a6826fbcSWolfgang Denk } 307*a6826fbcSWolfgang Denk } 308*a6826fbcSWolfgang Denk /* return found entry */ 309*a6826fbcSWolfgang Denk *retval = &htab->table[idx].entry; 310*a6826fbcSWolfgang Denk return idx; 311*a6826fbcSWolfgang Denk } 312*a6826fbcSWolfgang Denk } 313*a6826fbcSWolfgang Denk while (htab->table[idx].used); 314*a6826fbcSWolfgang Denk } 315*a6826fbcSWolfgang Denk 316*a6826fbcSWolfgang Denk /* An empty bucket has been found. */ 317*a6826fbcSWolfgang Denk if (action == ENTER) { 318*a6826fbcSWolfgang Denk /* 319*a6826fbcSWolfgang Denk * If table is full and another entry should be 320*a6826fbcSWolfgang Denk * entered return with error. 321*a6826fbcSWolfgang Denk */ 322*a6826fbcSWolfgang Denk if (htab->filled == htab->size) { 323*a6826fbcSWolfgang Denk __set_errno(ENOMEM); 324*a6826fbcSWolfgang Denk *retval = NULL; 325*a6826fbcSWolfgang Denk return 0; 326*a6826fbcSWolfgang Denk } 327*a6826fbcSWolfgang Denk 328*a6826fbcSWolfgang Denk /* 329*a6826fbcSWolfgang Denk * Create new entry; 330*a6826fbcSWolfgang Denk * create copies of item.key and item.data 331*a6826fbcSWolfgang Denk */ 332*a6826fbcSWolfgang Denk htab->table[idx].used = hval; 333*a6826fbcSWolfgang Denk htab->table[idx].entry.key = strdup(item.key); 334*a6826fbcSWolfgang Denk htab->table[idx].entry.data = strdup(item.data); 335*a6826fbcSWolfgang Denk if (!htab->table[idx].entry.key || 336*a6826fbcSWolfgang Denk !htab->table[idx].entry.data) { 337*a6826fbcSWolfgang Denk __set_errno(ENOMEM); 338*a6826fbcSWolfgang Denk *retval = NULL; 339*a6826fbcSWolfgang Denk return 0; 340*a6826fbcSWolfgang Denk } 341*a6826fbcSWolfgang Denk 342*a6826fbcSWolfgang Denk ++htab->filled; 343*a6826fbcSWolfgang Denk 344*a6826fbcSWolfgang Denk /* return new entry */ 345*a6826fbcSWolfgang Denk *retval = &htab->table[idx].entry; 346*a6826fbcSWolfgang Denk return 1; 347*a6826fbcSWolfgang Denk } 348*a6826fbcSWolfgang Denk 349*a6826fbcSWolfgang Denk __set_errno(ESRCH); 350*a6826fbcSWolfgang Denk *retval = NULL; 351*a6826fbcSWolfgang Denk return 0; 352*a6826fbcSWolfgang Denk } 353*a6826fbcSWolfgang Denk 354*a6826fbcSWolfgang Denk 355*a6826fbcSWolfgang Denk /* 356*a6826fbcSWolfgang Denk * hdelete() 357*a6826fbcSWolfgang Denk */ 358*a6826fbcSWolfgang Denk 359*a6826fbcSWolfgang Denk /* 360*a6826fbcSWolfgang Denk * The standard implementation of hsearch(3) does not provide any way 361*a6826fbcSWolfgang Denk * to delete any entries from the hash table. We extend the code to 362*a6826fbcSWolfgang Denk * do that. 363*a6826fbcSWolfgang Denk */ 364*a6826fbcSWolfgang Denk 365*a6826fbcSWolfgang Denk int hdelete(const char *key) 366*a6826fbcSWolfgang Denk { 367*a6826fbcSWolfgang Denk return hdelete_r(key, &htab); 368*a6826fbcSWolfgang Denk } 369*a6826fbcSWolfgang Denk 370*a6826fbcSWolfgang Denk int hdelete_r(const char *key, struct hsearch_data *htab) 371*a6826fbcSWolfgang Denk { 372*a6826fbcSWolfgang Denk ENTRY e, *ep; 373*a6826fbcSWolfgang Denk int idx; 374*a6826fbcSWolfgang Denk 375*a6826fbcSWolfgang Denk debug("hdelete: DELETE key \"%s\"\n", key); 376*a6826fbcSWolfgang Denk 377*a6826fbcSWolfgang Denk e.key = (char *)key; 378*a6826fbcSWolfgang Denk 379*a6826fbcSWolfgang Denk if ((idx = hsearch_r(e, FIND, &ep, htab)) == 0) { 380*a6826fbcSWolfgang Denk __set_errno(ESRCH); 381*a6826fbcSWolfgang Denk return 0; /* not found */ 382*a6826fbcSWolfgang Denk } 383*a6826fbcSWolfgang Denk 384*a6826fbcSWolfgang Denk /* free used ENTRY */ 385*a6826fbcSWolfgang Denk debug("hdelete: DELETING key \"%s\"\n", key); 386*a6826fbcSWolfgang Denk 387*a6826fbcSWolfgang Denk free(ep->key); 388*a6826fbcSWolfgang Denk free(ep->data); 389*a6826fbcSWolfgang Denk htab->table[idx].used = 0; 390*a6826fbcSWolfgang Denk 391*a6826fbcSWolfgang Denk --htab->filled; 392*a6826fbcSWolfgang Denk 393*a6826fbcSWolfgang Denk return 1; 394*a6826fbcSWolfgang Denk } 395*a6826fbcSWolfgang Denk 396*a6826fbcSWolfgang Denk /* 397*a6826fbcSWolfgang Denk * hexport() 398*a6826fbcSWolfgang Denk */ 399*a6826fbcSWolfgang Denk 400*a6826fbcSWolfgang Denk /* 401*a6826fbcSWolfgang Denk * Export the data stored in the hash table in linearized form. 402*a6826fbcSWolfgang Denk * 403*a6826fbcSWolfgang Denk * Entries are exported as "name=value" strings, separated by an 404*a6826fbcSWolfgang Denk * arbitrary (non-NUL, of course) separator character. This allows to 405*a6826fbcSWolfgang Denk * use this function both when formatting the U-Boot environment for 406*a6826fbcSWolfgang Denk * external storage (using '\0' as separator), but also when using it 407*a6826fbcSWolfgang Denk * for the "printenv" command to print all variables, simply by using 408*a6826fbcSWolfgang Denk * as '\n" as separator. This can also be used for new features like 409*a6826fbcSWolfgang Denk * exporting the environment data as text file, including the option 410*a6826fbcSWolfgang Denk * for later re-import. 411*a6826fbcSWolfgang Denk * 412*a6826fbcSWolfgang Denk * The entries in the result list will be sorted by ascending key 413*a6826fbcSWolfgang Denk * values. 414*a6826fbcSWolfgang Denk * 415*a6826fbcSWolfgang Denk * If the separator character is different from NUL, then any 416*a6826fbcSWolfgang Denk * separator characters and backslash characters in the values will 417*a6826fbcSWolfgang Denk * be escaped by a preceeding backslash in output. This is needed for 418*a6826fbcSWolfgang Denk * example to enable multi-line values, especially when the output 419*a6826fbcSWolfgang Denk * shall later be parsed (for example, for re-import). 420*a6826fbcSWolfgang Denk * 421*a6826fbcSWolfgang Denk * There are several options how the result buffer is handled: 422*a6826fbcSWolfgang Denk * 423*a6826fbcSWolfgang Denk * *resp size 424*a6826fbcSWolfgang Denk * ----------- 425*a6826fbcSWolfgang Denk * NULL 0 A string of sufficient length will be allocated. 426*a6826fbcSWolfgang Denk * NULL >0 A string of the size given will be 427*a6826fbcSWolfgang Denk * allocated. An error will be returned if the size is 428*a6826fbcSWolfgang Denk * not sufficient. Any unused bytes in the string will 429*a6826fbcSWolfgang Denk * be '\0'-padded. 430*a6826fbcSWolfgang Denk * !NULL 0 The user-supplied buffer will be used. No length 431*a6826fbcSWolfgang Denk * checking will be performed, i. e. it is assumed that 432*a6826fbcSWolfgang Denk * the buffer size will always be big enough. DANGEROUS. 433*a6826fbcSWolfgang Denk * !NULL >0 The user-supplied buffer will be used. An error will 434*a6826fbcSWolfgang Denk * be returned if the size is not sufficient. Any unused 435*a6826fbcSWolfgang Denk * bytes in the string will be '\0'-padded. 436*a6826fbcSWolfgang Denk */ 437*a6826fbcSWolfgang Denk 438*a6826fbcSWolfgang Denk ssize_t hexport(const char sep, char **resp, size_t size) 439*a6826fbcSWolfgang Denk { 440*a6826fbcSWolfgang Denk return hexport_r(&htab, sep, resp, size); 441*a6826fbcSWolfgang Denk } 442*a6826fbcSWolfgang Denk 443*a6826fbcSWolfgang Denk static int cmpkey(const void *p1, const void *p2) 444*a6826fbcSWolfgang Denk { 445*a6826fbcSWolfgang Denk ENTRY *e1 = *(ENTRY **) p1; 446*a6826fbcSWolfgang Denk ENTRY *e2 = *(ENTRY **) p2; 447*a6826fbcSWolfgang Denk 448*a6826fbcSWolfgang Denk return (strcmp(e1->key, e2->key)); 449*a6826fbcSWolfgang Denk } 450*a6826fbcSWolfgang Denk 451*a6826fbcSWolfgang Denk ssize_t hexport_r(struct hsearch_data *htab, const char sep, 452*a6826fbcSWolfgang Denk char **resp, size_t size) 453*a6826fbcSWolfgang Denk { 454*a6826fbcSWolfgang Denk ENTRY *list[htab->size]; 455*a6826fbcSWolfgang Denk char *res, *p; 456*a6826fbcSWolfgang Denk size_t totlen; 457*a6826fbcSWolfgang Denk int i, n; 458*a6826fbcSWolfgang Denk 459*a6826fbcSWolfgang Denk /* Test for correct arguments. */ 460*a6826fbcSWolfgang Denk if ((resp == NULL) || (htab == NULL)) { 461*a6826fbcSWolfgang Denk __set_errno(EINVAL); 462*a6826fbcSWolfgang Denk return (-1); 463*a6826fbcSWolfgang Denk } 464*a6826fbcSWolfgang Denk 465*a6826fbcSWolfgang Denk debug("EXPORT table = %p, htab.size = %d, htab.filled = %d, size = %d\n", 466*a6826fbcSWolfgang Denk htab, htab->size, htab->filled, size); 467*a6826fbcSWolfgang Denk /* 468*a6826fbcSWolfgang Denk * Pass 1: 469*a6826fbcSWolfgang Denk * search used entries, 470*a6826fbcSWolfgang Denk * save addresses and compute total length 471*a6826fbcSWolfgang Denk */ 472*a6826fbcSWolfgang Denk for (i = 1, n = 0, totlen = 0; i <= htab->size; ++i) { 473*a6826fbcSWolfgang Denk 474*a6826fbcSWolfgang Denk if (htab->table[i].used) { 475*a6826fbcSWolfgang Denk ENTRY *ep = &htab->table[i].entry; 476*a6826fbcSWolfgang Denk 477*a6826fbcSWolfgang Denk list[n++] = ep; 478*a6826fbcSWolfgang Denk 479*a6826fbcSWolfgang Denk totlen += strlen(ep->key) + 2; 480*a6826fbcSWolfgang Denk 481*a6826fbcSWolfgang Denk if (sep == '\0') { 482*a6826fbcSWolfgang Denk totlen += strlen(ep->data); 483*a6826fbcSWolfgang Denk } else { /* check if escapes are needed */ 484*a6826fbcSWolfgang Denk char *s = ep->data; 485*a6826fbcSWolfgang Denk 486*a6826fbcSWolfgang Denk while (*s) { 487*a6826fbcSWolfgang Denk ++totlen; 488*a6826fbcSWolfgang Denk /* add room for needed escape chars */ 489*a6826fbcSWolfgang Denk if ((*s == sep) || (*s == '\\')) 490*a6826fbcSWolfgang Denk ++totlen; 491*a6826fbcSWolfgang Denk ++s; 492*a6826fbcSWolfgang Denk } 493*a6826fbcSWolfgang Denk } 494*a6826fbcSWolfgang Denk totlen += 2; /* for '=' and 'sep' char */ 495*a6826fbcSWolfgang Denk } 496*a6826fbcSWolfgang Denk } 497*a6826fbcSWolfgang Denk 498*a6826fbcSWolfgang Denk #ifdef DEBUG 499*a6826fbcSWolfgang Denk /* Pass 1a: print unsorted list */ 500*a6826fbcSWolfgang Denk printf("Unsorted: n=%d\n", n); 501*a6826fbcSWolfgang Denk for (i = 0; i < n; ++i) { 502*a6826fbcSWolfgang Denk printf("\t%3d: %p ==> %-10s => %s\n", 503*a6826fbcSWolfgang Denk i, list[i], list[i]->key, list[i]->data); 504*a6826fbcSWolfgang Denk } 505*a6826fbcSWolfgang Denk #endif 506*a6826fbcSWolfgang Denk 507*a6826fbcSWolfgang Denk /* Sort list by keys */ 508*a6826fbcSWolfgang Denk qsort(list, n, sizeof(ENTRY *), cmpkey); 509*a6826fbcSWolfgang Denk 510*a6826fbcSWolfgang Denk /* Check if the user supplied buffer size is sufficient */ 511*a6826fbcSWolfgang Denk if (size) { 512*a6826fbcSWolfgang Denk if (size < totlen + 1) { /* provided buffer too small */ 513*a6826fbcSWolfgang Denk debug("### buffer too small: %d, but need %d\n", 514*a6826fbcSWolfgang Denk size, totlen + 1); 515*a6826fbcSWolfgang Denk __set_errno(ENOMEM); 516*a6826fbcSWolfgang Denk return (-1); 517*a6826fbcSWolfgang Denk } 518*a6826fbcSWolfgang Denk } else { 519*a6826fbcSWolfgang Denk size = totlen + 1; 520*a6826fbcSWolfgang Denk } 521*a6826fbcSWolfgang Denk 522*a6826fbcSWolfgang Denk /* Check if the user provided a buffer */ 523*a6826fbcSWolfgang Denk if (*resp) { 524*a6826fbcSWolfgang Denk /* yes; clear it */ 525*a6826fbcSWolfgang Denk res = *resp; 526*a6826fbcSWolfgang Denk memset(res, '\0', size); 527*a6826fbcSWolfgang Denk } else { 528*a6826fbcSWolfgang Denk /* no, allocate and clear one */ 529*a6826fbcSWolfgang Denk *resp = res = calloc(1, size); 530*a6826fbcSWolfgang Denk if (res == NULL) { 531*a6826fbcSWolfgang Denk __set_errno(ENOMEM); 532*a6826fbcSWolfgang Denk return (-1); 533*a6826fbcSWolfgang Denk } 534*a6826fbcSWolfgang Denk } 535*a6826fbcSWolfgang Denk /* 536*a6826fbcSWolfgang Denk * Pass 2: 537*a6826fbcSWolfgang Denk * export sorted list of result data 538*a6826fbcSWolfgang Denk */ 539*a6826fbcSWolfgang Denk for (i = 0, p = res; i < n; ++i) { 540*a6826fbcSWolfgang Denk char *s; 541*a6826fbcSWolfgang Denk 542*a6826fbcSWolfgang Denk s = list[i]->key; 543*a6826fbcSWolfgang Denk while (*s) 544*a6826fbcSWolfgang Denk *p++ = *s++; 545*a6826fbcSWolfgang Denk *p++ = '='; 546*a6826fbcSWolfgang Denk 547*a6826fbcSWolfgang Denk s = list[i]->data; 548*a6826fbcSWolfgang Denk 549*a6826fbcSWolfgang Denk while (*s) { 550*a6826fbcSWolfgang Denk if ((*s == sep) || (*s == '\\')) 551*a6826fbcSWolfgang Denk *p++ = '\\'; /* escape */ 552*a6826fbcSWolfgang Denk *p++ = *s++; 553*a6826fbcSWolfgang Denk } 554*a6826fbcSWolfgang Denk *p++ = sep; 555*a6826fbcSWolfgang Denk } 556*a6826fbcSWolfgang Denk *p = '\0'; /* terminate result */ 557*a6826fbcSWolfgang Denk 558*a6826fbcSWolfgang Denk return size; 559*a6826fbcSWolfgang Denk } 560*a6826fbcSWolfgang Denk 561*a6826fbcSWolfgang Denk 562*a6826fbcSWolfgang Denk /* 563*a6826fbcSWolfgang Denk * himport() 564*a6826fbcSWolfgang Denk */ 565*a6826fbcSWolfgang Denk 566*a6826fbcSWolfgang Denk /* 567*a6826fbcSWolfgang Denk * Import linearized data into hash table. 568*a6826fbcSWolfgang Denk * 569*a6826fbcSWolfgang Denk * This is the inverse function to hexport(): it takes a linear list 570*a6826fbcSWolfgang Denk * of "name=value" pairs and creates hash table entries from it. 571*a6826fbcSWolfgang Denk * 572*a6826fbcSWolfgang Denk * Entries without "value", i. e. consisting of only "name" or 573*a6826fbcSWolfgang Denk * "name=", will cause this entry to be deleted from the hash table. 574*a6826fbcSWolfgang Denk * 575*a6826fbcSWolfgang Denk * The "flag" argument can be used to control the behaviour: when the 576*a6826fbcSWolfgang Denk * H_NOCLEAR bit is set, then an existing hash table will kept, i. e. 577*a6826fbcSWolfgang Denk * new data will be added to an existing hash table; otherwise, old 578*a6826fbcSWolfgang Denk * data will be discarded and a new hash table will be created. 579*a6826fbcSWolfgang Denk * 580*a6826fbcSWolfgang Denk * The separator character for the "name=value" pairs can be selected, 581*a6826fbcSWolfgang Denk * so we both support importing from externally stored environment 582*a6826fbcSWolfgang Denk * data (separated by NUL characters) and from plain text files 583*a6826fbcSWolfgang Denk * (entries separated by newline characters). 584*a6826fbcSWolfgang Denk * 585*a6826fbcSWolfgang Denk * To allow for nicely formatted text input, leading white space 586*a6826fbcSWolfgang Denk * (sequences of SPACE and TAB chars) is ignored, and entries starting 587*a6826fbcSWolfgang Denk * (after removal of any leading white space) with a '#' character are 588*a6826fbcSWolfgang Denk * considered comments and ignored. 589*a6826fbcSWolfgang Denk * 590*a6826fbcSWolfgang Denk * [NOTE: this means that a variable name cannot start with a '#' 591*a6826fbcSWolfgang Denk * character.] 592*a6826fbcSWolfgang Denk * 593*a6826fbcSWolfgang Denk * When using a non-NUL separator character, backslash is used as 594*a6826fbcSWolfgang Denk * escape character in the value part, allowing for example for 595*a6826fbcSWolfgang Denk * multi-line values. 596*a6826fbcSWolfgang Denk * 597*a6826fbcSWolfgang Denk * In theory, arbitrary separator characters can be used, but only 598*a6826fbcSWolfgang Denk * '\0' and '\n' have really been tested. 599*a6826fbcSWolfgang Denk */ 600*a6826fbcSWolfgang Denk 601*a6826fbcSWolfgang Denk int himport(const char *env, size_t size, const char sep, int flag) 602*a6826fbcSWolfgang Denk { 603*a6826fbcSWolfgang Denk return himport_r(&htab, env, size, sep, flag); 604*a6826fbcSWolfgang Denk } 605*a6826fbcSWolfgang Denk 606*a6826fbcSWolfgang Denk int himport_r(struct hsearch_data *htab, 607*a6826fbcSWolfgang Denk const char *env, size_t size, const char sep, int flag) 608*a6826fbcSWolfgang Denk { 609*a6826fbcSWolfgang Denk char *data, *sp, *dp, *name, *value; 610*a6826fbcSWolfgang Denk 611*a6826fbcSWolfgang Denk /* Test for correct arguments. */ 612*a6826fbcSWolfgang Denk if (htab == NULL) { 613*a6826fbcSWolfgang Denk __set_errno(EINVAL); 614*a6826fbcSWolfgang Denk return 0; 615*a6826fbcSWolfgang Denk } 616*a6826fbcSWolfgang Denk 617*a6826fbcSWolfgang Denk /* we allocate new space to make sure we can write to the array */ 618*a6826fbcSWolfgang Denk if ((data = malloc(size)) == NULL) { 619*a6826fbcSWolfgang Denk debug("himport_r: can't malloc %d bytes\n", size); 620*a6826fbcSWolfgang Denk __set_errno(ENOMEM); 621*a6826fbcSWolfgang Denk return 0; 622*a6826fbcSWolfgang Denk } 623*a6826fbcSWolfgang Denk memcpy(data, env, size); 624*a6826fbcSWolfgang Denk dp = data; 625*a6826fbcSWolfgang Denk 626*a6826fbcSWolfgang Denk if ((flag & H_NOCLEAR) == 0) { 627*a6826fbcSWolfgang Denk /* Destroy old hash table if one exists */ 628*a6826fbcSWolfgang Denk debug("Destroy Hash Table: %p table = %p\n", htab, 629*a6826fbcSWolfgang Denk htab->table); 630*a6826fbcSWolfgang Denk if (htab->table) 631*a6826fbcSWolfgang Denk hdestroy_r(htab); 632*a6826fbcSWolfgang Denk } 633*a6826fbcSWolfgang Denk 634*a6826fbcSWolfgang Denk /* 635*a6826fbcSWolfgang Denk * Create new hash table (if needed). The computation of the hash 636*a6826fbcSWolfgang Denk * table size is based on heuristics: in a sample of some 70+ 637*a6826fbcSWolfgang Denk * existing systems we found an average size of 39+ bytes per entry 638*a6826fbcSWolfgang Denk * in the environment (for the whole key=value pair). Assuming a 639*a6826fbcSWolfgang Denk * size of 7 per entry (= safety factor of >5) should provide enough 640*a6826fbcSWolfgang Denk * safety margin for any existing environment definitons and still 641*a6826fbcSWolfgang Denk * allow for more than enough dynamic additions. Note that the 642*a6826fbcSWolfgang Denk * "size" argument is supposed to give the maximum enviroment size 643*a6826fbcSWolfgang Denk * (CONFIG_ENV_SIZE). 644*a6826fbcSWolfgang Denk */ 645*a6826fbcSWolfgang Denk 646*a6826fbcSWolfgang Denk if (!htab->table) { 647*a6826fbcSWolfgang Denk int nent = size / 7; 648*a6826fbcSWolfgang Denk 649*a6826fbcSWolfgang Denk debug("Create Hash Table: N=%d\n", nent); 650*a6826fbcSWolfgang Denk 651*a6826fbcSWolfgang Denk if (hcreate_r(nent, htab) == 0) { 652*a6826fbcSWolfgang Denk free(data); 653*a6826fbcSWolfgang Denk return 0; 654*a6826fbcSWolfgang Denk } 655*a6826fbcSWolfgang Denk } 656*a6826fbcSWolfgang Denk 657*a6826fbcSWolfgang Denk /* Parse environment; allow for '\0' and 'sep' as separators */ 658*a6826fbcSWolfgang Denk do { 659*a6826fbcSWolfgang Denk ENTRY e, *rv; 660*a6826fbcSWolfgang Denk 661*a6826fbcSWolfgang Denk /* skip leading white space */ 662*a6826fbcSWolfgang Denk while ((*dp == ' ') || (*dp == '\t')) 663*a6826fbcSWolfgang Denk ++dp; 664*a6826fbcSWolfgang Denk 665*a6826fbcSWolfgang Denk /* skip comment lines */ 666*a6826fbcSWolfgang Denk if (*dp == '#') { 667*a6826fbcSWolfgang Denk while (*dp && (*dp != sep)) 668*a6826fbcSWolfgang Denk ++dp; 669*a6826fbcSWolfgang Denk ++dp; 670*a6826fbcSWolfgang Denk continue; 671*a6826fbcSWolfgang Denk } 672*a6826fbcSWolfgang Denk 673*a6826fbcSWolfgang Denk /* parse name */ 674*a6826fbcSWolfgang Denk for (name = dp; *dp != '=' && *dp && *dp != sep; ++dp) 675*a6826fbcSWolfgang Denk ; 676*a6826fbcSWolfgang Denk 677*a6826fbcSWolfgang Denk /* deal with "name" and "name=" entries (delete var) */ 678*a6826fbcSWolfgang Denk if (*dp == '\0' || *(dp + 1) == '\0' || 679*a6826fbcSWolfgang Denk *dp == sep || *(dp + 1) == sep) { 680*a6826fbcSWolfgang Denk if (*dp == '=') 681*a6826fbcSWolfgang Denk *dp++ = '\0'; 682*a6826fbcSWolfgang Denk *dp++ = '\0'; /* terminate name */ 683*a6826fbcSWolfgang Denk 684*a6826fbcSWolfgang Denk debug("DELETE CANDIDATE: \"%s\"\n", name); 685*a6826fbcSWolfgang Denk 686*a6826fbcSWolfgang Denk if (hdelete_r(name, htab) == 0) 687*a6826fbcSWolfgang Denk debug("DELETE ERROR ##############################\n"); 688*a6826fbcSWolfgang Denk 689*a6826fbcSWolfgang Denk continue; 690*a6826fbcSWolfgang Denk } 691*a6826fbcSWolfgang Denk *dp++ = '\0'; /* terminate name */ 692*a6826fbcSWolfgang Denk 693*a6826fbcSWolfgang Denk /* parse value; deal with escapes */ 694*a6826fbcSWolfgang Denk for (value = sp = dp; *dp && (*dp != sep); ++dp) { 695*a6826fbcSWolfgang Denk if ((*dp == '\\') && *(dp + 1)) 696*a6826fbcSWolfgang Denk ++dp; 697*a6826fbcSWolfgang Denk *sp++ = *dp; 698*a6826fbcSWolfgang Denk } 699*a6826fbcSWolfgang Denk *sp++ = '\0'; /* terminate value */ 700*a6826fbcSWolfgang Denk ++dp; 701*a6826fbcSWolfgang Denk 702*a6826fbcSWolfgang Denk /* enter into hash table */ 703*a6826fbcSWolfgang Denk e.key = name; 704*a6826fbcSWolfgang Denk e.data = value; 705*a6826fbcSWolfgang Denk 706*a6826fbcSWolfgang Denk hsearch_r(e, ENTER, &rv, htab); 707*a6826fbcSWolfgang Denk if (rv == NULL) { 708*a6826fbcSWolfgang Denk printf("himport_r: can't insert \"%s=%s\" into hash table\n", name, value); 709*a6826fbcSWolfgang Denk return 0; 710*a6826fbcSWolfgang Denk } 711*a6826fbcSWolfgang Denk 712*a6826fbcSWolfgang Denk debug("INSERT: %p ==> name=\"%s\" value=\"%s\"\n", rv, name, 713*a6826fbcSWolfgang Denk value); 714*a6826fbcSWolfgang Denk debug(" table = %p, size = %d, filled = %d\n", htab, 715*a6826fbcSWolfgang Denk htab->size, htab->filled); 716*a6826fbcSWolfgang Denk } while ((dp < data + size) && *dp); /* size check needed for text */ 717*a6826fbcSWolfgang Denk /* without '\0' termination */ 718*a6826fbcSWolfgang Denk free(data); 719*a6826fbcSWolfgang Denk 720*a6826fbcSWolfgang Denk return 1; /* everything OK */ 721*a6826fbcSWolfgang Denk } 722