1/* 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1988, 1989 by Adam de Boor 5 * Copyright (c) 1989 by Berkeley Softworks 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Adam de Boor. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)hash.c 8.1 (Berkeley) 6/6/93 40 */ 41 42#include <sys/cdefs.h>
| 1/* 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1988, 1989 by Adam de Boor 5 * Copyright (c) 1989 by Berkeley Softworks 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Adam de Boor. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)hash.c 8.1 (Berkeley) 6/6/93 40 */ 41 42#include <sys/cdefs.h>
|
43__FBSDID("$FreeBSD: head/usr.bin/make/hash.c 138434 2004-12-06 08:52:02Z harti $");
| 43__FBSDID("$FreeBSD: head/usr.bin/make/hash.c 138435 2004-12-06 08:56:30Z harti $");
|
44 45/* hash.c -- 46 * 47 * This module contains routines to manipulate a hash table. 48 * See hash.h for a definition of the structure of the hash 49 * table. Hash tables grow automatically as the amount of 50 * information increases. 51 */ 52#include <unistd.h> 53#include "sprite.h" 54#include "make.h" 55#include "hash.h" 56 57/* 58 * Forward references to local procedures that are used before they're 59 * defined: 60 */ 61static void RebuildTable(Hash_Table *); 62 63/* 64 * The following defines the ratio of # entries to # buckets 65 * at which we rebuild the table to make it larger. 66 */ 67 68#define rebuildLimit 8 69 70/* 71 *--------------------------------------------------------- 72 * 73 * Hash_InitTable -- 74 * 75 * Set up the hash table t with a given number of buckets, or a 76 * reasonable default if the number requested is less than or 77 * equal to zero. Hash tables will grow in size as needed. 78 * 79 * 80 * Results: 81 * None. 82 * 83 * Side Effects: 84 * Memory is allocated for the initial bucket area. 85 * 86 *--------------------------------------------------------- 87 */ 88void 89Hash_InitTable(Hash_Table *t, int numBuckets) 90{ 91 int i; 92 struct Hash_Entry **hp; 93 94 /* 95 * Round up the size to a power of two. 96 */ 97 if (numBuckets <= 0) 98 i = 16; 99 else { 100 for (i = 2; i < numBuckets; i <<= 1) 101 continue; 102 } 103 t->numEntries = 0; 104 t->size = i; 105 t->mask = i - 1; 106 t->bucketPtr = hp = emalloc(sizeof(*hp) * i); 107 while (--i >= 0) 108 *hp++ = NULL; 109} 110 111/* 112 *--------------------------------------------------------- 113 * 114 * Hash_DeleteTable -- 115 * 116 * This routine removes everything from a hash table 117 * and frees up the memory space it occupied (except for 118 * the space in the Hash_Table structure). 119 * 120 * Results: 121 * None. 122 * 123 * Side Effects: 124 * Lots of memory is freed up. 125 * 126 *--------------------------------------------------------- 127 */ 128void 129Hash_DeleteTable(Hash_Table *t) 130{ 131 struct Hash_Entry **hp, *h, *nexth = NULL; 132 int i; 133 134 for (hp = t->bucketPtr, i = t->size; --i >= 0;) { 135 for (h = *hp++; h != NULL; h = nexth) { 136 nexth = h->next; 137 free(h); 138 } 139 } 140 free(t->bucketPtr); 141 142 /* 143 * Set up the hash table to cause memory faults on any future access 144 * attempts until re-initialization. 145 */ 146 t->bucketPtr = NULL; 147} 148 149/* 150 *--------------------------------------------------------- 151 * 152 * Hash_FindEntry -- 153 * 154 * Searches a hash table for an entry corresponding to key. 155 * 156 * Results: 157 * The return value is a pointer to the entry for key, 158 * if key was present in the table. If key was not 159 * present, NULL is returned. 160 * 161 * Side Effects: 162 * None. 163 * 164 *--------------------------------------------------------- 165 */ 166Hash_Entry *
| 44 45/* hash.c -- 46 * 47 * This module contains routines to manipulate a hash table. 48 * See hash.h for a definition of the structure of the hash 49 * table. Hash tables grow automatically as the amount of 50 * information increases. 51 */ 52#include <unistd.h> 53#include "sprite.h" 54#include "make.h" 55#include "hash.h" 56 57/* 58 * Forward references to local procedures that are used before they're 59 * defined: 60 */ 61static void RebuildTable(Hash_Table *); 62 63/* 64 * The following defines the ratio of # entries to # buckets 65 * at which we rebuild the table to make it larger. 66 */ 67 68#define rebuildLimit 8 69 70/* 71 *--------------------------------------------------------- 72 * 73 * Hash_InitTable -- 74 * 75 * Set up the hash table t with a given number of buckets, or a 76 * reasonable default if the number requested is less than or 77 * equal to zero. Hash tables will grow in size as needed. 78 * 79 * 80 * Results: 81 * None. 82 * 83 * Side Effects: 84 * Memory is allocated for the initial bucket area. 85 * 86 *--------------------------------------------------------- 87 */ 88void 89Hash_InitTable(Hash_Table *t, int numBuckets) 90{ 91 int i; 92 struct Hash_Entry **hp; 93 94 /* 95 * Round up the size to a power of two. 96 */ 97 if (numBuckets <= 0) 98 i = 16; 99 else { 100 for (i = 2; i < numBuckets; i <<= 1) 101 continue; 102 } 103 t->numEntries = 0; 104 t->size = i; 105 t->mask = i - 1; 106 t->bucketPtr = hp = emalloc(sizeof(*hp) * i); 107 while (--i >= 0) 108 *hp++ = NULL; 109} 110 111/* 112 *--------------------------------------------------------- 113 * 114 * Hash_DeleteTable -- 115 * 116 * This routine removes everything from a hash table 117 * and frees up the memory space it occupied (except for 118 * the space in the Hash_Table structure). 119 * 120 * Results: 121 * None. 122 * 123 * Side Effects: 124 * Lots of memory is freed up. 125 * 126 *--------------------------------------------------------- 127 */ 128void 129Hash_DeleteTable(Hash_Table *t) 130{ 131 struct Hash_Entry **hp, *h, *nexth = NULL; 132 int i; 133 134 for (hp = t->bucketPtr, i = t->size; --i >= 0;) { 135 for (h = *hp++; h != NULL; h = nexth) { 136 nexth = h->next; 137 free(h); 138 } 139 } 140 free(t->bucketPtr); 141 142 /* 143 * Set up the hash table to cause memory faults on any future access 144 * attempts until re-initialization. 145 */ 146 t->bucketPtr = NULL; 147} 148 149/* 150 *--------------------------------------------------------- 151 * 152 * Hash_FindEntry -- 153 * 154 * Searches a hash table for an entry corresponding to key. 155 * 156 * Results: 157 * The return value is a pointer to the entry for key, 158 * if key was present in the table. If key was not 159 * present, NULL is returned. 160 * 161 * Side Effects: 162 * None. 163 * 164 *--------------------------------------------------------- 165 */ 166Hash_Entry *
|
167Hash_FindEntry(Hash_Table *t, char *key)
| 167Hash_FindEntry(const Hash_Table *t, const char *key)
|
168{ 169 Hash_Entry *e; 170 unsigned h;
| 168{ 169 Hash_Entry *e; 170 unsigned h;
|
171 char *p;
| 171 const char *p;
|
172 173 for (h = 0, p = key; *p;) 174 h = (h << 5) - h + *p++; 175 p = key; 176 for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) 177 if (e->namehash == h && strcmp(e->name, p) == 0) 178 return (e); 179 return (NULL); 180} 181 182/* 183 *--------------------------------------------------------- 184 * 185 * Hash_CreateEntry -- 186 * 187 * Searches a hash table for an entry corresponding to 188 * key. If no entry is found, then one is created. 189 * 190 * Results: 191 * The return value is a pointer to the entry. If *newPtr 192 * isn't NULL, then *newPtr is filled in with TRUE if a 193 * new entry was created, and FALSE if an entry already existed 194 * with the given key. 195 * 196 * Side Effects: 197 * Memory may be allocated, and the hash buckets may be modified. 198 *--------------------------------------------------------- 199 */ 200Hash_Entry *
| 172 173 for (h = 0, p = key; *p;) 174 h = (h << 5) - h + *p++; 175 p = key; 176 for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) 177 if (e->namehash == h && strcmp(e->name, p) == 0) 178 return (e); 179 return (NULL); 180} 181 182/* 183 *--------------------------------------------------------- 184 * 185 * Hash_CreateEntry -- 186 * 187 * Searches a hash table for an entry corresponding to 188 * key. If no entry is found, then one is created. 189 * 190 * Results: 191 * The return value is a pointer to the entry. If *newPtr 192 * isn't NULL, then *newPtr is filled in with TRUE if a 193 * new entry was created, and FALSE if an entry already existed 194 * with the given key. 195 * 196 * Side Effects: 197 * Memory may be allocated, and the hash buckets may be modified. 198 *--------------------------------------------------------- 199 */ 200Hash_Entry *
|
201Hash_CreateEntry(Hash_Table *t, char *key, Boolean *newPtr)
| 201Hash_CreateEntry(Hash_Table *t, const char *key, Boolean *newPtr)
|
202{ 203 Hash_Entry *e; 204 unsigned int h;
| 202{ 203 Hash_Entry *e; 204 unsigned int h;
|
205 char *p;
| 205 const char *p;
|
206 int keylen; 207 struct Hash_Entry **hp; 208 209 /* 210 * Hash the key. As a side effect, save the length (strlen) of the 211 * key in case we need to create the entry. 212 */ 213 for (h = 0, p = key; *p;) 214 h = (h << 5) - h + *p++; 215 keylen = p - key; 216 p = key; 217 for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) { 218 if (e->namehash == h && strcmp(e->name, p) == 0) { 219 if (newPtr != NULL) 220 *newPtr = FALSE; 221 return (e); 222 } 223 } 224 225 /* 226 * The desired entry isn't there. Before allocating a new entry, 227 * expand the table if necessary (and this changes the resulting 228 * bucket chain). 229 */ 230 if (t->numEntries >= rebuildLimit * t->size) 231 RebuildTable(t); 232 e = emalloc(sizeof(*e) + keylen); 233 hp = &t->bucketPtr[h & t->mask]; 234 e->next = *hp; 235 *hp = e; 236 e->clientData = NULL; 237 e->namehash = h; 238 strcpy(e->name, p); 239 t->numEntries++; 240 241 if (newPtr != NULL) 242 *newPtr = TRUE; 243 return (e); 244} 245 246/* 247 *--------------------------------------------------------- 248 * 249 * Hash_DeleteEntry -- 250 * 251 * Delete the given hash table entry and free memory associated with 252 * it. 253 * 254 * Results: 255 * None. 256 * 257 * Side Effects: 258 * Hash chain that entry lives in is modified and memory is freed. 259 * 260 *--------------------------------------------------------- 261 */ 262void 263Hash_DeleteEntry(Hash_Table *t, Hash_Entry *e) 264{ 265 Hash_Entry **hp, *p; 266 267 if (e == NULL) 268 return; 269 for (hp = &t->bucketPtr[e->namehash & t->mask]; 270 (p = *hp) != NULL; hp = &p->next) { 271 if (p == e) { 272 *hp = p->next; 273 free(p); 274 t->numEntries--; 275 return; 276 } 277 } 278 write(STDERR_FILENO, "bad call to Hash_DeleteEntry\n", 29); 279 abort(); 280} 281 282/* 283 *--------------------------------------------------------- 284 * 285 * Hash_EnumFirst -- 286 * This procedure sets things up for a complete search 287 * of all entries recorded in the hash table. 288 * 289 * Results: 290 * The return value is the address of the first entry in 291 * the hash table, or NULL if the table is empty. 292 * 293 * Side Effects: 294 * The information in searchPtr is initialized so that successive 295 * calls to Hash_Next will return successive HashEntry's 296 * from the table. 297 * 298 *--------------------------------------------------------- 299 */ 300Hash_Entry * 301Hash_EnumFirst(Hash_Table *t, Hash_Search *searchPtr) 302{ 303 304 searchPtr->tablePtr = t; 305 searchPtr->nextIndex = 0; 306 searchPtr->hashEntryPtr = NULL; 307 return (Hash_EnumNext(searchPtr)); 308} 309 310/* 311 *--------------------------------------------------------- 312 * 313 * Hash_EnumNext -- 314 * This procedure returns successive entries in the hash table. 315 * 316 * Results: 317 * The return value is a pointer to the next HashEntry 318 * in the table, or NULL when the end of the table is 319 * reached. 320 * 321 * Side Effects: 322 * The information in searchPtr is modified to advance to the 323 * next entry. 324 * 325 *--------------------------------------------------------- 326 */ 327Hash_Entry * 328Hash_EnumNext(Hash_Search *searchPtr) 329{ 330 Hash_Entry *e; 331 Hash_Table *t = searchPtr->tablePtr; 332 333 /* 334 * The hashEntryPtr field points to the most recently returned 335 * entry, or is NULL if we are starting up. If not NULL, we have 336 * to start at the next one in the chain. 337 */ 338 e = searchPtr->hashEntryPtr; 339 if (e != NULL) 340 e = e->next; 341 /* 342 * If the chain ran out, or if we are starting up, we need to 343 * find the next nonempty chain. 344 */ 345 while (e == NULL) { 346 if (searchPtr->nextIndex >= t->size) 347 return (NULL); 348 e = t->bucketPtr[searchPtr->nextIndex++]; 349 } 350 searchPtr->hashEntryPtr = e; 351 return (e); 352} 353 354/* 355 *--------------------------------------------------------- 356 * 357 * RebuildTable -- 358 * This local routine makes a new hash table that 359 * is larger than the old one. 360 * 361 * Results: 362 * None. 363 * 364 * Side Effects: 365 * The entire hash table is moved, so any bucket numbers 366 * from the old table are invalid. 367 * 368 *--------------------------------------------------------- 369 */ 370static void 371RebuildTable(Hash_Table *t) 372{ 373 Hash_Entry *e, *next = NULL, **hp, **xp; 374 int i, mask; 375 Hash_Entry **oldhp; 376 int oldsize; 377 378 oldhp = t->bucketPtr; 379 oldsize = i = t->size; 380 i <<= 1; 381 t->size = i; 382 t->mask = mask = i - 1; 383 t->bucketPtr = hp = emalloc(sizeof(*hp) * i); 384 while (--i >= 0) 385 *hp++ = NULL; 386 for (hp = oldhp, i = oldsize; --i >= 0;) { 387 for (e = *hp++; e != NULL; e = next) { 388 next = e->next; 389 xp = &t->bucketPtr[e->namehash & mask]; 390 e->next = *xp; 391 *xp = e; 392 } 393 } 394 free(oldhp); 395}
| 206 int keylen; 207 struct Hash_Entry **hp; 208 209 /* 210 * Hash the key. As a side effect, save the length (strlen) of the 211 * key in case we need to create the entry. 212 */ 213 for (h = 0, p = key; *p;) 214 h = (h << 5) - h + *p++; 215 keylen = p - key; 216 p = key; 217 for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) { 218 if (e->namehash == h && strcmp(e->name, p) == 0) { 219 if (newPtr != NULL) 220 *newPtr = FALSE; 221 return (e); 222 } 223 } 224 225 /* 226 * The desired entry isn't there. Before allocating a new entry, 227 * expand the table if necessary (and this changes the resulting 228 * bucket chain). 229 */ 230 if (t->numEntries >= rebuildLimit * t->size) 231 RebuildTable(t); 232 e = emalloc(sizeof(*e) + keylen); 233 hp = &t->bucketPtr[h & t->mask]; 234 e->next = *hp; 235 *hp = e; 236 e->clientData = NULL; 237 e->namehash = h; 238 strcpy(e->name, p); 239 t->numEntries++; 240 241 if (newPtr != NULL) 242 *newPtr = TRUE; 243 return (e); 244} 245 246/* 247 *--------------------------------------------------------- 248 * 249 * Hash_DeleteEntry -- 250 * 251 * Delete the given hash table entry and free memory associated with 252 * it. 253 * 254 * Results: 255 * None. 256 * 257 * Side Effects: 258 * Hash chain that entry lives in is modified and memory is freed. 259 * 260 *--------------------------------------------------------- 261 */ 262void 263Hash_DeleteEntry(Hash_Table *t, Hash_Entry *e) 264{ 265 Hash_Entry **hp, *p; 266 267 if (e == NULL) 268 return; 269 for (hp = &t->bucketPtr[e->namehash & t->mask]; 270 (p = *hp) != NULL; hp = &p->next) { 271 if (p == e) { 272 *hp = p->next; 273 free(p); 274 t->numEntries--; 275 return; 276 } 277 } 278 write(STDERR_FILENO, "bad call to Hash_DeleteEntry\n", 29); 279 abort(); 280} 281 282/* 283 *--------------------------------------------------------- 284 * 285 * Hash_EnumFirst -- 286 * This procedure sets things up for a complete search 287 * of all entries recorded in the hash table. 288 * 289 * Results: 290 * The return value is the address of the first entry in 291 * the hash table, or NULL if the table is empty. 292 * 293 * Side Effects: 294 * The information in searchPtr is initialized so that successive 295 * calls to Hash_Next will return successive HashEntry's 296 * from the table. 297 * 298 *--------------------------------------------------------- 299 */ 300Hash_Entry * 301Hash_EnumFirst(Hash_Table *t, Hash_Search *searchPtr) 302{ 303 304 searchPtr->tablePtr = t; 305 searchPtr->nextIndex = 0; 306 searchPtr->hashEntryPtr = NULL; 307 return (Hash_EnumNext(searchPtr)); 308} 309 310/* 311 *--------------------------------------------------------- 312 * 313 * Hash_EnumNext -- 314 * This procedure returns successive entries in the hash table. 315 * 316 * Results: 317 * The return value is a pointer to the next HashEntry 318 * in the table, or NULL when the end of the table is 319 * reached. 320 * 321 * Side Effects: 322 * The information in searchPtr is modified to advance to the 323 * next entry. 324 * 325 *--------------------------------------------------------- 326 */ 327Hash_Entry * 328Hash_EnumNext(Hash_Search *searchPtr) 329{ 330 Hash_Entry *e; 331 Hash_Table *t = searchPtr->tablePtr; 332 333 /* 334 * The hashEntryPtr field points to the most recently returned 335 * entry, or is NULL if we are starting up. If not NULL, we have 336 * to start at the next one in the chain. 337 */ 338 e = searchPtr->hashEntryPtr; 339 if (e != NULL) 340 e = e->next; 341 /* 342 * If the chain ran out, or if we are starting up, we need to 343 * find the next nonempty chain. 344 */ 345 while (e == NULL) { 346 if (searchPtr->nextIndex >= t->size) 347 return (NULL); 348 e = t->bucketPtr[searchPtr->nextIndex++]; 349 } 350 searchPtr->hashEntryPtr = e; 351 return (e); 352} 353 354/* 355 *--------------------------------------------------------- 356 * 357 * RebuildTable -- 358 * This local routine makes a new hash table that 359 * is larger than the old one. 360 * 361 * Results: 362 * None. 363 * 364 * Side Effects: 365 * The entire hash table is moved, so any bucket numbers 366 * from the old table are invalid. 367 * 368 *--------------------------------------------------------- 369 */ 370static void 371RebuildTable(Hash_Table *t) 372{ 373 Hash_Entry *e, *next = NULL, **hp, **xp; 374 int i, mask; 375 Hash_Entry **oldhp; 376 int oldsize; 377 378 oldhp = t->bucketPtr; 379 oldsize = i = t->size; 380 i <<= 1; 381 t->size = i; 382 t->mask = mask = i - 1; 383 t->bucketPtr = hp = emalloc(sizeof(*hp) * i); 384 while (--i >= 0) 385 *hp++ = NULL; 386 for (hp = oldhp, i = oldsize; --i >= 0;) { 387 for (e = *hp++; e != NULL; e = next) { 388 next = e->next; 389 xp = &t->bucketPtr[e->namehash & mask]; 390 e->next = *xp; 391 *xp = e; 392 } 393 } 394 free(oldhp); 395}
|