00001 /* 00002 * Copyright 2004 PathScale, Inc. All Rights Reserved. 00003 */ 00004 00005 /* 00006 00007 Copyright (C) 2000, 2001 Silicon Graphics, Inc. All Rights Reserved. 00008 00009 This program is free software; you can redistribute it and/or modify it 00010 under the terms of version 2 of the GNU General Public License as 00011 published by the Free Software Foundation. 00012 00013 This program is distributed in the hope that it would be useful, but 00014 WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00016 00017 Further, this software is distributed without any warranty that it is 00018 free of the rightful claim of any third person regarding infringement 00019 or the like. Any license provided herein, whether implied or 00020 otherwise, applies only to this software file. Patent licenses, if 00021 any, provided herein do not apply to combinations of this program with 00022 other software, or any other product whatsoever. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with this program; if not, write the Free Software Foundation, Inc., 59 00026 Temple Place - Suite 330, Boston MA 02111-1307, USA. 00027 00028 Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pky, 00029 Mountain View, CA 94043, or: 00030 00031 http://www.sgi.com 00032 00033 For further information regarding this notice, see: 00034 00035 http://oss.sgi.com/projects/GenInfo/NoticeExplan 00036 00037 */ 00038 00039 00040 00041 #include "defs.h" 00042 00043 #include "erglob.h" 00044 #include "tracing.h" 00045 #define NO_VARARGS_PROTOTYPES 00046 #include "linklist.h" 00047 #undef NO_VARARGS_PROTOTYPES 00048 00049 char *_ary_lst_bounds_msg = "ARY LST index = %d, out of bounds: 0..%d"; 00050 00051 /* 00052 * Define these macros in case we ever decide to put an additional 00053 * filter on memory for linked lists data. We never call 'malloc()' 00054 * or 'free()' directly in this file -- we always go through these 00055 * macros. 00056 */ 00057 #define lnk_lst_malloc(x) ((MEM_PTR)malloc(x)) 00058 #define lnk_lst_free(x) free((MEM_PTR) (x)) 00059 00060 /* 00061 * This data structure links together blocks of list items that have 00062 * been allocated. We have to save pointers to each allocated block 00063 * so we can free all the list items at the end of a program unit. 00064 */ 00065 typedef struct block_list_items { 00066 MEM_PTR block; /* ptr to block of memory alloced */ 00067 struct block_list_items *next; /* ptr to next block header */ 00068 } BLK_LST_ITMS; 00069 00070 #define BLK_block(blk) ((blk)->block) 00071 #define BLK_next(blk) ((blk)->next) 00072 00073 LST_ITM * _lst_itm; /* Definition added for ANSI C 4/19/92 (jfw) */ 00074 00075 static BLK_LST_ITMS *block_item_hdr = NULL; 00076 00077 /* 00078 * Allocate N_LIST_BLOCK linked list data items per block. 00079 * We make this number just under some nice power of two, because we 00080 * assume that blocks with a size that is a power of 2 (or just under 00081 * a power of 2) are allocated fairly efficiently. We don't make the 00082 * block exactly a power of 2, because we must allocate an extra few 00083 * bytes of overhead to keep a linked list of the blocks of memory 00084 * allocated -- thus allowing us to free things up eventually (see the 00085 * BLK_LST_ITMS data structure, above). 00086 */ 00087 #define N_LIST_BLOCK (2048 - 5) 00088 00089 /* 00090 * Memory Blocks Size: the total number of bytes of memory allocated 00091 * by every call to 'list_malloc()', see below. 00092 * This should be a power of 2 (or slightly less than a power of 2). 00093 */ 00094 #define M_BLOCK_SIZE \ 00095 ((sizeof(LST_ITM)*N_LIST_BLOCK)+sizeof(BLK_LST_ITMS)) 00096 00097 static LST_ITM *list_items = NULL; 00098 static LST_ITM *_list_tmp; 00099 00100 static LST_ITM *list_malloc(void); 00101 00102 /* ==================================================================== 00103 * 00104 * LST_ITM *item_alloc() (macro) 00105 * 00106 * This macro removes a list item from the free list and returns a 00107 * pointer to the removed item. If the free list is empty, it 00108 * allocates a block of items, links that block together onto the 00109 * free list, and returns one of the newly allocated items. 00110 * 00111 * NOTE: THIS IS THE ONLY WAY THAT A LIST ITEM SHOULD BE ALLOCATED. 00112 * 00113 * ==================================================================== 00114 */ 00115 #define item_alloc() ( list_items ? \ 00116 ( (_list_tmp = list_items), \ 00117 (list_items = LST_next(list_items)), \ 00118 (LST_next(_list_tmp) = NULL), _list_tmp ) \ 00119 : list_malloc() ) 00120 00121 /* ==================================================================== 00122 * 00123 * item_free() (macro) 00124 * 00125 * This macro places a list item onto the free list. 00126 * 00127 * NOTE: THIS IS THE ONLY WAY THAT A LIST ITEM SHOULD BE FREED. 00128 * 00129 * ==================================================================== 00130 */ 00131 #ifdef LNK_LST_CHECK 00132 # define item_free(itm) ( (LST_next(itm)=list_items), \ 00133 (list_items=(itm)), (LST_val(itm)=0) ) 00134 #else /* LNK_LST_CHECK not defined */ 00135 # define item_free(itm) ((LST_next(itm)=list_items), (list_items=(itm))) 00136 #endif /* LNK_LST_CHECK not defined */ 00137 00138 #ifndef MONGOOSE_BE 00139 /* ==================================================================== 00140 * 00141 * static LST_ITM *list_malloc() 00142 * 00143 * Allocate a block of memory for N_LIST_BLOCK linked list items and 00144 * for a BLK_LST_ITMS element. Link this block up with any previously 00145 * allocated blocks. Also, link all but one of of the N_LIST_BLOCK 00146 * elements together and put them on the free list. 00147 * 00148 * Return a pointer to the one item that was not put on the free list 00149 * (and NULL out the 'LST_next()' field of the returned item). 00150 * 00151 * NOTE: THIS ROUTINE ASSUMES THE FREE LIST IS EMPTY. THE ONLY CALLS 00152 * TO THIS ROUTINE SHOULD BE FROM THE MACRO 'item_alloc()' WHEN 00153 * THERE ARE NO FREE ELEMENTS REMAINING. 00154 * ==================================================================== 00155 */ 00156 00157 static LST_ITM * 00158 list_malloc ( void ) 00159 { 00160 MEM_PTR mem_block; 00161 BLK_LST_ITMS *blk; 00162 register LST_ITM *itm; 00163 register INT32 i; 00164 00165 /* 00166 * The free list had better be empty. 00167 */ 00168 Is_True (list_items == NULL, ("list_malloc: free list is not empty")); 00169 00170 if ( (mem_block = lnk_lst_malloc(M_BLOCK_SIZE)) == NULL ) 00171 ErrMsg ( EC_No_Mem, "list_malloc" ); 00172 00173 /* 00174 * Link this block up with any previously allocated blocks of 00175 * list items. 00176 */ 00177 blk = (BLK_LST_ITMS *) mem_block; 00178 BLK_block(blk) = mem_block; /* it points to itself! */ 00179 BLK_next(blk) = block_item_hdr; 00180 block_item_hdr = blk; 00181 00182 /* 00183 * Link (N_LIST_BLOCK-1) elements together and place them on the free 00184 * list, making sure the last one on the free list points to NULL. 00185 * Take the one remaining item, NULL out its pointer, and return it. 00186 */ 00187 list_items = (LST_ITM *) ++blk; 00188 for (itm=list_items, i=0; i<(N_LIST_BLOCK-2); ++i, ++itm) { 00189 LST_val(itm) = -1; 00190 LST_next(itm) = itm+1; 00191 } 00192 LST_next(itm) = NULL; /* "ground" the end of the free list */ 00193 00194 ++itm; /* 'itm' now points to the one remaining item */ 00195 LST_next(itm) = NULL; 00196 00197 return itm; 00198 } 00199 #endif /* MONGOOSE_BE */ 00200 00201 #ifdef Is_True_On 00202 /* ==================================================================== 00203 * 00204 * check_linked_list_free 00205 * 00206 * This routine is called only for compile-time checking. At the point 00207 * of call, we are about to free all the memory ever allocated for 00208 * linked list elements. Here, we walk through the entire free list, 00209 * counting number of elements we have, and make sure that we have 00210 * exactly the number that were allocated in total. If they are the 00211 * same, we just return TRUE. If they differ, we print a diagnostic 00212 * and return FALSE. 00213 * 00214 * NOTE: this routine will not be called in a production compiler. 00215 * If it finds we have not freed all the items it means we have a 00216 * memory leak somewhere. This is bad, but it is not a valid reason 00217 * to abort a user's compilation. 00218 * 00219 * ==================================================================== 00220 */ 00221 00222 static void 00223 check_linked_list_free ( void ) 00224 { 00225 INT32 n_total = 0; 00226 INT32 n_in_free = 0; 00227 INT32 n_blocks = 0; 00228 BLK_LST_ITMS *blk; 00229 LST_ITM *item = list_items; 00230 00231 for (blk=block_item_hdr; blk!=NULL; blk=BLK_next(blk), ++n_blocks) 00232 n_total += N_LIST_BLOCK; 00233 00234 for (item=list_items; item!=NULL; item=LST_next(item), ++n_in_free) 00235 /* NULL statement list -- just counting items */ ; 00236 00237 if ( n_total != n_in_free ) { 00238 DevWarn("WARNING: %d linked list items allocated in %d" 00239 " blocks, but %d in free list", 00240 n_total, n_blocks, n_in_free); 00241 ErrMsg ( EC_Mem_Leak, "Free_All_List_Items" ); /* Warning */ 00242 } 00243 } 00244 #endif /* Is_True_On */ 00245 00246 /* ==================================================================== 00247 * 00248 * void Free_All_List_Items() 00249 * 00250 * Step through the blocks of memory that were allocated for all the 00251 * list items and free them up. 00252 * 00253 * This function should be called once for each program unit, after all 00254 * linked list manipulation is complete. 00255 * 00256 * ==================================================================== 00257 */ 00258 00259 void 00260 Free_All_List_Items ( void ) 00261 { 00262 BLK_LST_ITMS *blk, *nblk; 00263 00264 /* We've had more than a year to decide we cared enough about this to 00265 * track it down and we haven't. There's a bug filed. I'm sick of 00266 * the stupid/cute message. Enable the check if you plan to do 00267 * something about it and not until! -- Rutt 00268 */ 00269 00270 #if 0 00271 # ifdef Is_True_On 00272 check_linked_list_free(); 00273 # endif 00274 # endif 00275 00276 for (blk=block_item_hdr; blk!=NULL; blk=nblk) { 00277 nblk = BLK_next(blk); 00278 (void) lnk_lst_free(blk); 00279 } 00280 00281 list_items = NULL; 00282 block_item_hdr = NULL; 00283 } 00284 00285 #ifndef MONGOOSE_BE 00286 /* ==================================================================== 00287 * 00288 * void ARY_Init_List(LNK_LST_ARY *ary, INT32 n_elems) 00289 * 00290 * Allocate an array of 'n_elems' linked list headers for the array of 00291 * lists 'ary'. Initialize each list. 00292 * 00293 * ==================================================================== 00294 */ 00295 00296 void 00297 ARY_Init_List ( LNK_LST_ARY *ary, INT32 n_elems ) 00298 { 00299 register INT32 i; 00300 register LNK_LST *lst; 00301 00302 Is_True (n_elems >= 1, 00303 ("ARY_Init_List: attempt to allocate array of size %d", n_elems) ); 00304 00305 if ((lst=(LNK_LST *)lnk_lst_malloc(sizeof(LNK_LST)*n_elems)) == NULL) 00306 ErrMsg ( EC_No_Mem, "ARY_Init_List" ); 00307 00308 LST_lists(ary) = lst; 00309 ARY_LST_n_elems(ary) = n_elems; 00310 00311 for (i=0; i<n_elems; ++i, ++lst) 00312 Init_List( lst ); 00313 } 00314 /* ==================================================================== 00315 * 00316 * void Free_List(LNK_LST *lst) 00317 * 00318 * Free all the items in the linked list 'lst' (i.e., put the items on 00319 * the free list). Set the length of the list to 0. 00320 * 00321 * ==================================================================== 00322 */ 00323 00324 void 00325 Free_List ( LNK_LST *lst ) 00326 { 00327 register LST_ITM *p1, *p2; 00328 00329 for (p1=LST_first(lst); p1!=NULL; p1=p2) { 00330 p2 = LST_next(p1); 00331 item_free(p1); 00332 } 00333 00334 Init_List(lst); 00335 } 00336 00337 /* ==================================================================== 00338 * 00339 * void ARY_Free_List(LNK_LST_ARY *ary) 00340 * 00341 * Free each list in the array of linked lists 'ary'. Also, free up 00342 * the linked list headers. 00343 * 00344 * ==================================================================== 00345 */ 00346 00347 void 00348 ARY_Free_List ( LNK_LST_ARY *ary ) 00349 { 00350 INT32 n_elems = ARY_LST_n_elems(ary); 00351 INT32 i; 00352 00353 for (i=0; i<n_elems; ++i) 00354 Free_List ( ARY_LST_Elem(ary,i) ); 00355 00356 (void) lnk_lst_free(LST_lists(ary)); /* free the headers */ 00357 } 00358 00359 /* ==================================================================== 00360 * 00361 * Validate_List 00362 * 00363 * Validate a list, i.e. verify that it contains no cycles and that its 00364 * stored length matches its actual length. 00365 * 00366 * ==================================================================== 00367 */ 00368 00369 BOOL 00370 Validate_List ( LNK_LST *lst ) 00371 { 00372 INT32 count = LST_Len(lst); 00373 LST_ITM *p; 00374 00375 for ( p=LST_first(lst); p!=NULL; p=LST_next(p) ) { 00376 if ( --count < 0 ) break; 00377 } 00378 if ( count != 0 ) { 00379 DevWarn("##### Validate_List: Invalid count #####" ); 00380 count = 10*LST_Len(lst); 00381 for ( p=LST_first(lst); p!=NULL; p=LST_next(p) ) { 00382 if ( --count < 0 ) break; 00383 DevWarn(" %p: %d", p, LST_val(p) ); 00384 } 00385 FmtAssert ( FALSE, 00386 ( "Validate_List: invalid count %d", LST_Len(lst) ) ); 00387 return FALSE; 00388 } 00389 return TRUE; 00390 } 00391 #endif /* MONGOOSE_BE */ 00392 00393 #ifndef STORE_LIST_LEN 00394 /* ==================================================================== 00395 * 00396 * INT32 LST_Len(LNK_LST *lst) 00397 * 00398 * Count the number of elements in the list and return that value. 00399 * 00400 * Note that this is implemented as a routine only if the length is 00401 * not stored directly in the list data structures. If the length 00402 * is stored there, this operation is implemented as a macro. See 00403 * the discussion in "linklist.h" regarding STORE_LST_LEN. 00404 * 00405 * ==================================================================== 00406 */ 00407 00408 INT32 00409 LST_Len ( LNK_LST *lst ) 00410 { 00411 register INT32 count = 0; 00412 register LST_ITM *p; 00413 00414 for (p=LST_first(lst); p!=NULL; p=LST_next(p)) 00415 ++count; 00416 00417 return count; 00418 } 00419 #endif /* STORE_LIST_LEN not defined */ 00420 00421 #ifndef MONGOOSE_BE 00422 /* ==================================================================== 00423 * 00424 * BOOL Add_Item(LNK_LST *lst, tlst_val val) 00425 * 00426 * Add the item 'val' to the linked list 'lst'. If the item is already 00427 * in the list, do not add it again. 00428 * Update the number of items in the list. 00429 * 00430 * Return TRUE if the item was added, FALSE if not. 00431 * 00432 * ==================================================================== 00433 */ 00434 00435 BOOL 00436 Add_Item ( LNK_LST *lst, tlst_val val) 00437 { 00438 register LST_ITM *p, *last; 00439 00440 if (LST_Empty(lst)) { 00441 LST_first(lst) = p = item_alloc(); 00442 LST_val(p) = val; 00443 incr_LST_len(lst); 00444 return TRUE; 00445 } 00446 00447 last = NULL; /* unnecessary except to eliminate warning msg */ 00448 for (p=LST_first(lst); p!=NULL; p=LST_next(p)) { 00449 if (LST_val(p) == val) 00450 return FALSE; /* already in the list => return FALSE */ 00451 last = p; 00452 } 00453 00454 /* 00455 * If we get to here, we went through the list without finding a 00456 * matching item. Append a new item to the end of the list. 00457 */ 00458 LST_next(last) = p = item_alloc(); 00459 LST_val(p) = val; 00460 incr_LST_len(lst); 00461 00462 /* 00463 * If the pointer to the next item in the list is NULL, i.e. when 00464 * stepping through the list the end was reached, then make the next 00465 * item be this new item. 00466 */ 00467 if (LST_nxt(lst) == NULL) 00468 LST_nxt(lst) = p; 00469 00470 return TRUE; 00471 } 00472 00473 /* ==================================================================== 00474 * 00475 * Add_Item_Validate 00476 * 00477 * Identical to Add_Item, plus verification of the list afterwards. 00478 * 00479 * ==================================================================== 00480 */ 00481 00482 BOOL 00483 Add_Item_Validate ( LNK_LST *lst, tlst_val val) 00484 { 00485 BOOL added = Add_Item ( lst, val ); 00486 00487 (void) Validate_List ( lst ); 00488 return added; 00489 } 00490 00491 /* ==================================================================== 00492 * 00493 * void Add_Item_Dup(LNK_LST *lst, tlst_val val) 00494 * 00495 * Add the item 'val' to the linked list 'lst', even if the item is 00496 * already in the list. 00497 * Update the number of items in the list. 00498 * 00499 * ==================================================================== 00500 */ 00501 00502 void 00503 Add_Item_Dup ( LNK_LST *lst, tlst_val val ) 00504 { 00505 LST_ITM *p; 00506 LST_ITM *last; 00507 00508 00509 if (LST_Empty(lst)) { 00510 LST_first(lst) = p = item_alloc(); 00511 LST_val(p) = val; 00512 incr_LST_len(lst); 00513 return; 00514 } 00515 00516 /* 00517 * Find the end of the list. 00518 */ 00519 last = NULL; /* unnecessary except to eliminate warning msg */ 00520 for (p=LST_first(lst); p!=NULL; p=LST_next(p)) 00521 last = p; 00522 00523 /* 00524 * Append a new item to the end of the list. 00525 */ 00526 LST_next(last) = p = item_alloc(); 00527 LST_val(p) = val; 00528 incr_LST_len(lst); 00529 00530 /* 00531 * If the pointer to the next item in the list is NULL, i.e. when 00532 * stepping through the list the end was reached, then make the next 00533 * item be this new item. 00534 */ 00535 if (LST_nxt(lst) == NULL) 00536 LST_nxt(lst) = p; 00537 00538 #ifdef BB_VALIDATE_LIST 00539 Validate_List ( lst ); 00540 #endif 00541 00542 return; 00543 } 00544 00545 /* ==================================================================== 00546 * 00547 * void Add_First_Item(LNK_LST *lst, tlst_val val) 00548 * 00549 * Add the item 'val' to the beginning of linked list 'lst'. 00550 * Update the number of items in the list. 00551 * 00552 * NOTE: The item is added even if it is already in the list. 00553 * 00554 * ==================================================================== 00555 */ 00556 00557 void 00558 Add_First_Item ( LNK_LST *lst, tlst_val val ) 00559 { 00560 register LST_ITM *p; 00561 00562 p = item_alloc(); 00563 LST_val(p) = val; 00564 LST_next(p) = LST_first(lst); 00565 LST_first(lst) = p; 00566 incr_LST_len(lst); 00567 } 00568 00569 /* ==================================================================== 00570 * 00571 * BOOL Add_Ordered_Item(LNK_LST *lst, tlst_val val) 00572 * 00573 * Add the item 'val' to the ordered linked list 'lst'. If the item is 00574 * already in the list, do not add it again. 00575 * Update the number of items in the list. 00576 * 00577 * Note: The list *must* be ordered and may not contain any duplicates 00578 * for this routine to work properly. 00579 * 00580 * Return TRUE if the item was added, FALSE if not. 00581 * 00582 * ==================================================================== 00583 */ 00584 00585 BOOL 00586 Add_Ordered_Item ( LNK_LST *lst, tlst_val val ) 00587 { 00588 register LST_ITM *p, *last; 00589 register tlst_val this_val; 00590 00591 if (LST_Empty(lst)) { 00592 LST_first(lst) = p = item_alloc(); 00593 LST_val(p) = val; 00594 incr_LST_len(lst); 00595 return TRUE; 00596 } 00597 00598 p = LST_first(lst); 00599 if ( (this_val = LST_val(p)) == val ) { 00600 return FALSE; /* already in the list => return FALSE */ 00601 00602 } else if ( val < this_val ) { /* insert at beginning of the list */ 00603 register LST_ITM *new = item_alloc(); 00604 LST_next(new) = p; 00605 LST_first(lst) = new; 00606 LST_val(new) = val; 00607 incr_LST_len(lst); 00608 return TRUE; 00609 } 00610 00611 last = p; 00612 for ( p=LST_next(p); p!=NULL; p=LST_next(p)) { 00613 #ifdef LNK_LST_CHECK 00614 Is_True ( this_val < LST_val(p), 00615 ("ordered list not sorted: elems %d and %d",this_val,LST_val(p))); 00616 #endif /* LNK_LST_CHECK */ 00617 if ( (this_val = LST_val(p)) == val ) { 00618 return FALSE; /* already in the list => return FALSE */ 00619 00620 } else if ( val < this_val ) { /* insert here */ 00621 register LST_ITM *new = item_alloc(); 00622 LST_next(new) = p; 00623 LST_next(last) = new; 00624 LST_val(new) = val; 00625 incr_LST_len(lst); 00626 return TRUE; 00627 } 00628 last = p; 00629 } 00630 00631 /* 00632 * If we get to here, we went through the list without finding a 00633 * matching item, and all items in the list have values less than 00634 * the new value. Append a new item to the end of the list. 00635 */ 00636 LST_next(last) = p = item_alloc(); 00637 LST_val(p) = val; 00638 incr_LST_len(lst); 00639 00640 /* 00641 * If the pointer to the next item in the list is NULL, i.e. when 00642 * stepping through the list the end was reached, then make the next 00643 * item be this new item. 00644 */ 00645 if (LST_nxt(lst) == NULL) 00646 LST_nxt(lst) = p; 00647 00648 return TRUE; 00649 } 00650 00651 /* ==================================================================== 00652 * 00653 * void Add_Ordered_Item_Dupl(LNK_LST *lst, tlst_val val) 00654 * 00655 * Add the item 'val' to the ordered linked list 'lst'. If the item is 00656 * already in the list, add a duplicate. 00657 * Update the number of items in the list. 00658 * 00659 * Note: The list *must* already be ordered for this routine to 00660 * work properly. 00661 * 00662 * ==================================================================== 00663 */ 00664 00665 void 00666 Add_Ordered_Item_Dupl ( LNK_LST *lst, tlst_val val ) 00667 { 00668 register LST_ITM *p, *last; 00669 register tlst_val this_val; 00670 00671 if (LST_Empty(lst)) { 00672 LST_first(lst) = p = item_alloc(); 00673 LST_val(p) = val; 00674 incr_LST_len(lst); 00675 return; 00676 } 00677 00678 p = LST_first(lst); 00679 this_val = LST_val(p); 00680 00681 if ( val <= this_val ) { /* insert at beginning of the list */ 00682 register LST_ITM *new = item_alloc(); 00683 LST_next(new) = p; 00684 LST_first(lst) = new; 00685 LST_val(new) = val; 00686 incr_LST_len(lst); 00687 return; 00688 } 00689 00690 last = p; 00691 for ( p=LST_next(p); p!=NULL; p=LST_next(p)) { 00692 #ifdef LNK_LST_CHECK 00693 Is_True ( this_val <= LST_val(p), 00694 ("ordered list not sorted: elems %d and %d",this_val,LST_val(p))); 00695 #endif /* LNK_LST_CHECK */ 00696 00697 this_val = LST_val(p); 00698 if ( val <= this_val ) { /* insert here */ 00699 register LST_ITM *new = item_alloc(); 00700 LST_next(new) = p; 00701 LST_next(last) = new; 00702 LST_val(new) = val; 00703 incr_LST_len(lst); 00704 return; 00705 } 00706 last = p; 00707 } 00708 00709 /* 00710 * If we get to here, we went through the list without finding a 00711 * matching item, and all items in the list have values less than 00712 * the new value. Append a new item to the end of the list. 00713 */ 00714 LST_next(last) = p = item_alloc(); 00715 LST_val(p) = val; 00716 incr_LST_len(lst); 00717 00718 /* 00719 * If the pointer to the next item in the list is NULL, i.e. when 00720 * stepping through the list the end was reached, then make the next 00721 * item be this new item. 00722 */ 00723 if (LST_nxt(lst) == NULL) 00724 LST_nxt(lst) = p; 00725 } 00726 00727 /* ==================================================================== 00728 * 00729 * BOOL Del_Item(LNK_LST *lst, tlst_val val) 00730 * 00731 * Delete the item 'val' from the linked list 'lst' (and free the 00732 * deleted item). 00733 * Update the number of items in the list. 00734 * 00735 * Return TRUE if the item was deleted, FALSE if not (ie it wasn't 00736 * there). 00737 * 00738 * NOTE: 00739 * If the item being deleted is the 'next' item in the list 00740 * then make the 'next' item in the list the one AFTER the 00741 * item being deleted. 00742 * 00743 * ==================================================================== 00744 */ 00745 00746 BOOL 00747 Del_Item ( LNK_LST *lst, tlst_val val ) 00748 { 00749 register LST_ITM *p, *last; 00750 00751 if (LST_Empty(lst)) 00752 return FALSE; /* not in the list => nothing to delete */ 00753 00754 last = NULL; 00755 for (p=LST_first(lst); p!=NULL; p=LST_next(p)) { 00756 00757 if (LST_val(p) == val) { 00758 00759 if (LST_nxt(lst) == p) /* item being deleted is 'next' item */ 00760 LST_nxt(lst) = LST_next(p); 00761 00762 if (last == NULL) /* it was the first item in the list */ 00763 LST_first(lst) = LST_next(p); 00764 else /* it was not the first item in the list */ 00765 LST_next(last) = LST_next(p); 00766 00767 item_free(p); /* put deleted item into the free list */ 00768 decr_LST_len(lst); 00769 return TRUE; /* it was deleted from the list => return TRUE */ 00770 00771 } 00772 00773 last = p; 00774 } 00775 00776 /* 00777 * If we get to here, we went through the list searching for the item 00778 * but could not find it. Just return FALSE. 00779 */ 00780 return FALSE; 00781 } 00782 00783 /* ==================================================================== 00784 * 00785 * BOOL Del_Cur_Item(LNK_LST *lst) 00786 * 00787 * Delete the "current" item from the linked list 'lst' (and free the 00788 * deleted item). Note that the current item is, by definition, the 00789 * item whose LST_next(item) field the same as the LST_nxt(lst) field 00790 * of the list-header. Therefore, this routine can only be called 00791 * when the LST_nxt(lst) field is valid -- i.e., only when stepping 00792 * through the list. 00793 * 00794 * Update the number of items in the list. 00795 * 00796 * Return TRUE if there was an item that was deleted, FALSE if not 00797 * (i.e., FALSE when the list was empty on input). 00798 * 00799 * ==================================================================== 00800 */ 00801 00802 BOOL 00803 Del_Cur_Item ( LNK_LST *lst ) 00804 { 00805 LST_ITM *p, *last; 00806 LST_ITM *next_item = LST_nxt(lst); 00807 00808 if ( LST_Empty(lst) ) 00809 return FALSE; /* not in the list => nothing to delete */ 00810 00811 last = NULL; 00812 for ( p=LST_first(lst); p!=NULL; p=LST_next(p) ) { 00813 00814 if ( LST_next(p) == next_item ) { 00815 00816 if ( last == NULL ) /* it was the first item in the list */ 00817 LST_first(lst) = LST_next(p); 00818 else /* it was not the first item in the list */ 00819 LST_next(last) = LST_next(p); 00820 00821 item_free ( p ); /* put deleted item into the free list */ 00822 decr_LST_len(lst); 00823 return TRUE; /* it was deleted from the list => return TRUE */ 00824 00825 } 00826 00827 last = p; 00828 } 00829 00830 /* If we get to here, we went through the list, but we did not find 00831 * an item with an LST_next field matching the next item of the list. 00832 */ 00833 return FALSE; 00834 } 00835 00836 /* ==================================================================== 00837 * 00838 * BOOL Item_In_List(LNK_LST *lst, tlst_val val) 00839 * 00840 * Check to see if the item 'val' is in the linked list 'lst'. 00841 * 00842 * Return TRUE if the item is in the list, FALSE if not. 00843 * 00844 * ==================================================================== 00845 */ 00846 00847 BOOL 00848 Item_In_List ( LNK_LST *lst, tlst_val val ) 00849 { 00850 register LST_ITM *p; 00851 00852 if (LST_Empty(lst)) 00853 return FALSE; /* empty list => not in the list */ 00854 00855 for (p=LST_first(lst); p!=NULL; p=LST_next(p)) 00856 if (LST_val(p) == val) 00857 return TRUE; /* found it */ 00858 00859 /* 00860 * If we get to here, we went through the list searching for the item 00861 * but could not find it. Just return FALSE. 00862 */ 00863 return FALSE; 00864 } 00865 00866 /* ==================================================================== 00867 * 00868 * BOOL ARY_Item_In_List(LNK_LST_ARY *ary, INT32 i, tlst_val val) 00869 * 00870 * Check to see if the item 'val' is in the linked list 'ary[i]' ('ary' 00871 * is an array of linked lists). 00872 * 00873 * Return TRUE if the item is in the list, FALSE if not. 00874 * 00875 * ==================================================================== 00876 */ 00877 00878 BOOL 00879 ARY_Item_In_List ( LNK_LST_ARY *ary, INT32 i, tlst_val val ) 00880 { 00881 register LNK_LST *lst = ARY_LST_Elem(ary,i); 00882 register LST_ITM *p; 00883 00884 if (LST_Empty(lst)) 00885 return FALSE; /* empty list => not in the list */ 00886 00887 for (p=LST_first(lst); p!=NULL; p=LST_next(p)) 00888 if (LST_val(p) == val) 00889 return TRUE; /* found it */ 00890 00891 /* 00892 * If we get to here, we went through the list searching for the item 00893 * but could not find it. Just return FALSE. 00894 */ 00895 return FALSE; 00896 } 00897 /* ==================================================================== 00898 * 00899 * List_Print 00900 * 00901 * Print the message 'msg' along with any arguments. Then print each 00902 * item in the linked list 'lst' (print the items in decimal form). 00903 * 00904 * NOTE: All output is written to the "trace file" whose file 00905 * pointer is in the externally defined variable, 'TFile'. 00906 * 00907 * ==================================================================== 00908 */ 00909 00910 void 00911 List_Print ( lst, msg, arg1, arg2, arg3 ) 00912 LNK_LST *lst; 00913 char *msg; 00914 INT32 arg1, arg2, arg3; 00915 { 00916 tlst_val data; 00917 00918 fprintf ( TFile, msg, arg1, arg2, arg3 ); 00919 fprintf ( TFile,"\n" ); 00920 00921 /* 00922 * Loop over all the items, printing the data value. 00923 */ 00924 data = First_Item(lst); 00925 for (data=First_Item(lst); Valid_Item(data); data=Next_Item(lst)) 00926 fprintf ( TFile," %d", data ); 00927 00928 fprintf(TFile,"\n"); 00929 } 00930 00931 /* ==================================================================== 00932 * 00933 * ARY_List_Print 00934 * 00935 * Print the message 'msg' along with any arguments. Then print each 00936 * linked list in the array of linked lists 'ary' (print the items in 00937 * decimal form). 00938 * 00939 * NOTE: All output is written to the "trace file" whose file 00940 * pointer is in the externally defined variable, 'TFile'. 00941 * 00942 * ==================================================================== 00943 */ 00944 00945 void 00946 ARY_List_Print ( ary, msg, arg1, arg2, arg3 ) 00947 LNK_LST_ARY *ary; 00948 char *msg; 00949 INT32 arg1, arg2, arg3; 00950 { 00951 INT32 n_elems = ARY_LST_n_elems(ary); 00952 INT32 i; 00953 tlst_val data; 00954 LNK_LST *lst; 00955 00956 fprintf(TFile,msg,arg1,arg2,arg3); 00957 fprintf(TFile,"\n"); 00958 00959 /* 00960 * Loop over all the lists in the array of linked lists. 00961 */ 00962 for (i=0; i<n_elems; ++i) { 00963 /* 00964 * Loop over all the items, printing the data value. 00965 */ 00966 lst = ARY_LST_Elem(ary,i); 00967 data=First_Item(lst); 00968 if (Invalid_Item(data)) 00969 continue; 00970 fprintf(TFile,"%3d: ", i); 00971 for (; Valid_Item(data); data=Next_Item(lst)) 00972 fprintf ( TFile," %d", data ); 00973 00974 fprintf(TFile,"\n"); 00975 } 00976 } 00977 #endif /* MONGOOSE_BE */
1.5.6