Coverage Report

Created: 2026-07-25 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/MapServer/src/maphash.c
Line
Count
Source
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  Implement hashTableObj class.
6
 * Author:   Sean Gillies, sgillies@frii.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 1996-2005 Regents of the University of Minnesota.
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a
12
 * copy of this software and associated documentation files (the "Software"),
13
 * to deal in the Software without restriction, including without limitation
14
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
 * and/or sell copies of the Software, and to permit persons to whom the
16
 * Software is furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies of this Software or works derived from this Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
 * DEALINGS IN THE SOFTWARE.
28
 ****************************************************************************/
29
30
#include <ctype.h>
31
32
#include "mapserver.h"
33
#include "maphash.h"
34
35
30.5k
static unsigned hash(const char *key) {
36
30.5k
  unsigned hashval;
37
38
357k
  for (hashval = 0; *key != '\0'; key++)
39
326k
    hashval = tolower(*key) + 31 * hashval;
40
41
30.5k
  return (hashval % MS_HASHSIZE);
42
30.5k
}
43
44
0
hashTableObj *msCreateHashTable() {
45
0
  int i;
46
0
  hashTableObj *table;
47
48
0
  table = (hashTableObj *)msSmallMalloc(sizeof(hashTableObj));
49
0
  table->items =
50
0
      (struct hashObj **)msSmallMalloc(sizeof(struct hashObj *) * MS_HASHSIZE);
51
52
0
  for (i = 0; i < MS_HASHSIZE; i++)
53
0
    table->items[i] = NULL;
54
0
  table->numitems = 0;
55
56
0
  return table;
57
0
}
58
59
8.17k
int initHashTable(hashTableObj *table) {
60
8.17k
  int i;
61
62
8.17k
  table->items =
63
8.17k
      (struct hashObj **)malloc(sizeof(struct hashObj *) * MS_HASHSIZE);
64
8.17k
  MS_CHECK_ALLOC(table->items, sizeof(struct hashObj *) * MS_HASHSIZE,
65
8.17k
                 MS_FAILURE);
66
67
343k
  for (i = 0; i < MS_HASHSIZE; i++)
68
335k
    table->items[i] = NULL;
69
8.17k
  table->numitems = 0;
70
8.17k
  return MS_SUCCESS;
71
8.17k
}
72
73
0
void msFreeHashTable(hashTableObj *table) {
74
0
  if (table != NULL) {
75
0
    msFreeHashItems(table);
76
0
    free(table);
77
0
  }
78
0
}
79
80
0
int msHashIsEmpty(const hashTableObj *table) {
81
0
  if (table->numitems == 0)
82
0
    return MS_TRUE;
83
0
  else
84
0
    return MS_FALSE;
85
0
}
86
87
8.17k
void msFreeHashItems(hashTableObj *table) {
88
8.17k
  int i;
89
8.17k
  struct hashObj *tp = NULL;
90
8.17k
  struct hashObj *prev_tp = NULL;
91
92
8.17k
  if (table) {
93
8.17k
    if (table->items) {
94
343k
      for (i = 0; i < MS_HASHSIZE; i++) {
95
335k
        if (table->items[i] != NULL) {
96
13.1k
          for (tp = table->items[i]; tp != NULL;
97
7.34k
               prev_tp = tp, tp = tp->next, free(prev_tp)) {
98
7.34k
            msFree(tp->key);
99
7.34k
            msFree(tp->data);
100
7.34k
          }
101
5.82k
        }
102
335k
      }
103
8.17k
      free(table->items);
104
8.17k
      table->items = NULL;
105
8.17k
    } else {
106
0
      msSetError(MS_HASHERR, "No items allocated.", "msFreeHashItems()");
107
0
    }
108
8.17k
  } else {
109
0
    msSetError(MS_HASHERR, "Can't free NULL table", "msFreeHashItems()");
110
0
  }
111
8.17k
}
112
113
struct hashObj *msInsertHashTable(hashTableObj *table, const char *key,
114
9.86k
                                  const char *value) {
115
9.86k
  struct hashObj *tp;
116
9.86k
  unsigned hashval;
117
118
9.86k
  if (!table || !key || !value) {
119
0
    msSetError(MS_HASHERR, "Invalid hash table or key", "msInsertHashTable");
120
0
    return NULL;
121
0
  }
122
123
13.5k
  for (tp = table->items[hash(key)]; tp != NULL; tp = tp->next)
124
6.23k
    if (strcasecmp(key, tp->key) == 0)
125
2.52k
      break;
126
127
9.86k
  if (tp == NULL) { /* not found */
128
7.34k
    tp = (struct hashObj *)malloc(sizeof(*tp));
129
7.34k
    MS_CHECK_ALLOC(tp, sizeof(*tp), NULL);
130
7.34k
    tp->key = msStrdup(key);
131
7.34k
    hashval = hash(key);
132
7.34k
    tp->next = table->items[hashval];
133
7.34k
    table->items[hashval] = tp;
134
7.34k
    table->numitems++;
135
7.34k
  } else {
136
2.52k
    free(tp->data);
137
2.52k
  }
138
139
9.86k
  if ((tp->data = msStrdup(value)) == NULL)
140
0
    return NULL;
141
142
9.86k
  return tp;
143
9.86k
}
144
145
6.69k
const char *msLookupHashTable(const hashTableObj *table, const char *key) {
146
6.69k
  struct hashObj *tp;
147
148
6.69k
  if (!table || !key) {
149
0
    return (NULL);
150
0
  }
151
152
8.96k
  for (tp = table->items[hash(key)]; tp != NULL; tp = tp->next)
153
8.96k
    if (strcasecmp(key, tp->key) == 0)
154
6.69k
      return (tp->data);
155
156
0
  return NULL;
157
6.69k
}
158
159
0
int msRemoveHashTable(hashTableObj *table, const char *key) {
160
0
  struct hashObj *tp;
161
0
  struct hashObj *prev_tp = NULL;
162
0
  int status = MS_FAILURE;
163
164
0
  if (!table || !key) {
165
0
    msSetError(MS_HASHERR, "No hash table", "msRemoveHashTable");
166
0
    return MS_FAILURE;
167
0
  }
168
169
0
  tp = table->items[hash(key)];
170
0
  if (!tp) {
171
0
    msSetError(MS_HASHERR, "No such hash entry", "msRemoveHashTable");
172
0
    return MS_FAILURE;
173
0
  }
174
175
0
  prev_tp = NULL;
176
0
  while (tp != NULL) {
177
0
    if (strcasecmp(key, tp->key) == 0) {
178
0
      status = MS_SUCCESS;
179
0
      if (prev_tp) {
180
0
        prev_tp->next = tp->next;
181
0
        msFree(tp->key);
182
0
        msFree(tp->data);
183
0
        free(tp);
184
0
        break;
185
0
      } else {
186
0
        table->items[hash(key)] = tp->next;
187
0
        msFree(tp->key);
188
0
        msFree(tp->data);
189
0
        free(tp);
190
0
        break;
191
0
      }
192
0
    }
193
0
    prev_tp = tp;
194
0
    tp = tp->next;
195
0
  }
196
197
0
  if (status == MS_SUCCESS)
198
0
    table->numitems--;
199
200
0
  return status;
201
0
}
202
203
2.22k
const char *msFirstKeyFromHashTable(const hashTableObj *table) {
204
2.22k
  int hash_index;
205
206
2.22k
  if (!table) {
207
0
    msSetError(MS_HASHERR, "No hash table", "msFirstKeyFromHashTable");
208
0
    return NULL;
209
0
  }
210
211
32.2k
  for (hash_index = 0; hash_index < MS_HASHSIZE; hash_index++) {
212
32.2k
    if (table->items[hash_index] != NULL)
213
2.21k
      return table->items[hash_index]->key;
214
32.2k
  }
215
216
7
  return NULL;
217
2.22k
}
218
219
const char *msNextKeyFromHashTable(const hashTableObj *table,
220
6.69k
                                   const char *lastKey) {
221
6.69k
  int hash_index;
222
6.69k
  struct hashObj *link;
223
224
6.69k
  if (!table) {
225
0
    msSetError(MS_HASHERR, "No hash table", "msNextKeyFromHashTable");
226
0
    return NULL;
227
0
  }
228
229
6.69k
  if (lastKey == NULL)
230
0
    return msFirstKeyFromHashTable(table);
231
232
6.69k
  hash_index = hash(lastKey);
233
6.69k
  for (link = table->items[hash_index];
234
8.96k
       link != NULL && strcasecmp(lastKey, link->key) != 0; link = link->next) {
235
2.26k
  }
236
237
6.69k
  if (link != NULL && link->next != NULL)
238
1.29k
    return link->next->key;
239
240
61.0k
  while (++hash_index < MS_HASHSIZE) {
241
58.8k
    if (table->items[hash_index] != NULL)
242
3.18k
      return table->items[hash_index]->key;
243
58.8k
  }
244
245
2.21k
  return NULL;
246
5.39k
}