1 /***************************************************************
2 Copyright (C) 2006-2013 Hewlett-Packard Development Company, L.P.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 version 2 as published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
17 ***************************************************************/
18
19 /* Equivalent to core nomos v1.10 */
20
21 /**
22 * \file
23 * \brief list manipulation functions and str/val Compare functions
24 *
25 * list.c supplies all of the functions needed to manipulate the list and
26 * listitem structures defined in nomos.h. It also supplies the
27 * str*Compare* and valCompare* functions.
28 *
29 * @version "$Id: list.c 3676 2010-11-15 23:10:52Z bobgo $"
30 *
31 */
32
33 #include "nomos.h"
34 #include "list.h"
35 #include "util.h"
36
37 #define DFL_STARTSIZE 100
38
39 static int strCompare(item_t *, item_t *);
40 static int strIcaseCompare(item_t *, item_t *);
41 static int strCompareBasename(item_t *, item_t *);
42 static int valCompareDsc(item_t *, item_t *);
43 static int valCompareAsc(item_t *, item_t *);
44 static int bufCompare(item_t *, item_t *);
45 static void listDoubleSize(list_t *);
46 static void listValidate(list_t *, int);
47
48 #if defined(PROC_TRACE) || defined(LIST_DEBUG)
49 static void listDebugDetails();
50 #endif /* PROC_TRACE || LIST_DEBUG */
51
52 /**
53 * \brief intialize a list, if the list is not empty, empty it (initialize it to
54 * zero's).
55 *
56 * sets:\n
57 * l->name to label\n
58 * l->size to DFL_STARTSIZE\n
59 * l->used = 0\n
60 * l->ix = -1\n
61 * l->sorted = UNSORTED\n
62 * \param l List to initialize
63 * \param label Name of the list
64 * \note label can't be longer than l->name (64)
65 *
66 */
listInit(list_t * l,int size,char * label)67 void listInit(list_t *l, int size, char *label) {
68
69 #ifdef PROC_TRACE
70 traceFunc("== listInit(%p, %d, \"%s\")\n", l, size, label);
71 #endif /* PROC_TRACE */
72
73 if (l == NULL_LIST) {
74 LOG_FATAL("listInit: List @ %p is NULL", l)
75 Bail(-__LINE__);
76 }
77 if (label == NULL_STR) {
78 LOG_FATAL("no name for list @ %p", l)
79 Bail(-__LINE__);
80 }
81 if (strlen(label) > sizeof(l->name)) {
82 LOG_FATAL("List name \"%s\" too long", label)
83 Bail(-__LINE__);
84 }
85 if (l->name != label) (void) strcpy(l->name, label);
86 if (size == 0) {
87 #ifdef LIST_DEBUG
88 printf("LIST: (%p) initialize %s to %d elements\n", l,
89 l->name, DFL_STARTSIZE);
90 #endif /* LIST_DEBUG */
91 l->size = DFL_STARTSIZE; /* default start */
92 l->items = (item_t *)memAlloc(l->size*(int)sizeof(item_t),
93 l->name);
94 }
95 #ifdef QA_CHECKS
96 else if (size != l->size) {
97 Assert(NO, "%s: specified reset size %d != list size %d",
98 l->name, size, l->size);
99 }
100 #endif /* QA_CHECKS */
101 else {
102 #ifdef LIST_DEBUG
103 printf("LIST: reset %d elements in \"%s\" (%d bytes)\n",
104 l->size, l->name, l->size*sizeof(item_t));
105 #endif /* LIST_DEBUG */
106 memset(l->items, 0, l->size*sizeof(item_t));
107 }
108 l->used = 0;
109 l->ix = -1;
110 l->sorted = UNSORTED;
111 return;
112 }
113
114 /**
115 * \brief Destroy list_t
116 * \param l List to destroy
117 * \param deallocFlag Set to also free list memory
118 */
listClear(list_t * l,int deallocFlag)119 void listClear(list_t *l, int deallocFlag) {
120 item_t *p;
121 int i;
122
123 #if defined(PROC_TRACE) /* || defined(UNPACK_DEBUG) */
124 traceFunc("== listClear(%p, %s)\n", l,
125 deallocFlag ? "DEALLOC" : "NOTOUCH");
126 listDebugDetails(l);
127 #endif /* PROC_TRACE || UNPACK_DEBUG */
128
129 if (l == NULL_LIST) {
130 #ifdef LIST_DEBUG
131 printf("%% clear NULL list\n");
132 #endif /* LIST_DEBUG */
133 return;
134 }
135
136 if (l->size == 0) {
137 #ifdef LIST_DEBUG
138 printf("%% clear empty list \"%s\"\n", l->name);
139 #endif /* LIST_DEBUG */
140 return;
141 }
142 #ifdef LIST_DEBUG
143 listDump(l, YES);
144 #endif /* LIST_DEBUG */
145
146 #ifdef GLOBAL_DEBUG
147 if (gl.MEM_DEEBUG) {
148 printf("... used %d size %d ix %d sorted %d items %p\n",
149 l->used, l->size, l->ix, l->sorted, l->items);
150 }
151 #endif /* GLOBAL_DEBUG */
152 if (l->used) {
153 if (l->items == NULL_ITEM) {
154 Assert(NO, "%s: used/size %d/%d with null data",
155 l->name, l->used, l->size);
156 }
157 #ifdef LIST_DEBUG
158 printf("LIST: clearing %s, used entries == %d\n", l->name,
159 l->used);
160 #endif /* LIST_DEBUG */
161 #ifdef GLOBAL_DEBUG
162 if (gl.MEM_DEEBUG) {
163 printf("LIST: clearing %s, used entries == %d\n",
164 l->name, l->used);
165 }
166 #endif /* GLOBAL_DEBUG */
167 for (p = l->items, i = 0; i < l->used; i++, p++) {
168 if (p->str != NULL_STR) {
169 #ifdef GLOBAL_DEBUG
170 if (gl.MEM_DEEBUG) {
171 printf("FREE %p items[%d].str %p\n",
172 l, i, p->str);
173 }
174 #endif /* GLOBAL_DEBUG */
175 memFree((void *) p->str, MTAG_LISTKEY);
176 p->str = NULL_STR;
177 }
178 if (p->buf != NULL_STR) {
179 #ifdef GLOBAL_DEBUG
180 if (gl.MEM_DEEBUG) {
181 printf("... FREE %p items[%d].buf %p\n",
182 l, i, p->buf);
183 }
184 #endif /* GLOBAL_DEBUG */
185 memFree((void *) p->buf, MTAG_LISTBUF);
186 p->buf = NULL_STR;
187 }
188 p->buf = NULL_STR;
189 p->val = p->val2 = p->val3 = 0;
190 }
191 #ifdef GLOBAL_DEBUG
192 if (gl.MEM_DEEBUG) {
193 printf("INIT %s...\n", l->name);
194 }
195 #endif /* GLOBAL_DEBUG */
196 listInit(l, l->size, l->name);
197 }
198 #ifdef GLOBAL_DEBUG
199 if (gl.MEM_DEEBUG) {
200 printf("... dealloc %p \"items\" %p\n", l, l->items);
201 }
202 #endif /* GLOBAL_DEBUG */
203 if (deallocFlag && l->size) {
204 memFree(l->items, "list items");
205 l->size = 0;
206 }
207 #ifdef GLOBAL_DEBUG
208 if (gl.MEM_DEEBUG) {
209 printf("LIST: %s is cleared!\n", l->name);
210 }
211 #endif /* GLOBAL_DEBUG */
212 return;
213 }
214
215 /**
216 * \brief Validate list
217 * \param l List to validate
218 * \param appendFlag If set and list is completely used, double its size
219 */
listValidate(list_t * l,int appendFlag)220 void listValidate(list_t *l, int appendFlag) {
221 if (l == NULL_LIST) {
222 LOG_FATAL("listValidate: null list!")
223 Bail(-__LINE__);
224 }
225 /**
226 * \note Question: do we want to initialize the list here, instead of aborting?
227 * It would mean we don't have to initialize EVERY list EVERYWHERE -- we
228 * could just set the size to zero and start adding/inserting.
229 */
230 if (l->size == 0) {
231 LOG_FATAL("List (%s) @ %p not initialized", l->name, l)
232 Bail(-__LINE__);
233 }
234 if (l->items == NULL_ITEM) {
235 Assert(NO, "List (%s) @ %p has no data", l->name, l);
236 }
237 if (appendFlag) {
238 if (l->size == l->used) {
239 listDoubleSize(l);
240 }
241 }
242 return;
243 }
244
245
246 /**
247 * \brief get an item from the itemlist. If the item is not in the itemlist,
248 * then add it to the itemlist.
249 *
250 * This function searches the str member in the listitem structure, if found,
251 * a pointer to that item is returned. If not found, the item is added to the
252 * list of items 'in the middle' of the list.
253 *
254 * @param list_t *list the list to search/update
255 * @param *s pointer to the string to search for.
256 *
257 * @return pointer to the item
258 */
listGetItem(list_t * l,char * s)259 item_t *listGetItem(list_t *l, char *s) {
260 item_t *p;
261 int i;
262 int x;
263
264 #ifdef PROC_TRACE
265 traceFunc("== listGetItem(%p, \"%s\")\n", l, s);
266 listDebugDetails(l);
267 #endif /* PROC_TRACE */
268
269 listValidate(l, YES); /* assume/setup for an 'add' */
270 if (s == NULL_STR) {
271 Assert(NO, "listGetItem: Null string to insert!");
272 }
273 if (l->sorted && l->sorted != SORT_BY_NAME) {
274 LOG_FATAL("%s is sorted other than by-name (%d)", l->name, l->sorted)
275 Bail(-__LINE__);
276 }
277 else if (l->used == 0) {
278 l->sorted = SORT_BY_NAME;
279 }
280 /*
281 * Now we KNOW we have at least one opening in the list; see if the
282 * requested string already exists in the list
283 */
284 /**
285 \todo CDB -- Change so that there is only one loop variable in the
286 for loop
287 */
288 for (p = l->items, i = 0; i < l->used; i++, p++) {
289 #ifdef LIST_DEBUG
290 printf("%p: check i = %d, used = %d, size = %d\n", l, i, l->used,
291 l->size);
292 #endif /* LIST_DEBUG */
293 if ((x = strcmp(s, p->str)) == 0) {
294 return (p);
295 }
296 else if (x < 0) { /* e.g., not in list */
297 break; /* add new list entry */
298 }
299 } /* for */
300 #ifdef LIST_DEBUG
301 printf("listGetItem: new entry @%d (size %d, max %d)\n", i,
302 l->used, l->size);
303 #endif /* LIST_DEBUG */
304 if (i != l->used) { /* make room in 'middle' of list */
305 (void) memmove(l->items+i+1, l->items+i, (l->used-i)*sizeof(*p));
306 }
307 (l->used)++;
308 p->str = copyString(s, MTAG_SORTKEY);
309 p->buf = NULL_STR;
310 p->val = 0;
311 p->val2 = 0;
312 p->val3 = 0;
313 #ifdef LIST_DEBUG
314 printf("ADDING: insert %s @%d, \"used\" now == %d, Cache (listDump):\n",
315 p->str, i, l->used);
316 listDump(l, NO);
317 #endif /* LIST_DEBUG */
318 return (p);
319 }
320
321 /**
322 * \brief Utility list that isn't sorted - faster for unpacking archives and
323 * maintaining lists of files (we only need to sort that list at the
324 * end of the unpacking process - this just appends an entry at the
325 * bottom/end of the list.
326 */
listAppend(list_t * l,char * s)327 item_t *listAppend(list_t *l, char *s) {
328 item_t *p; /* computed return value */
329
330 #ifdef PROC_TRACE
331 traceFunc("== listAppend(%p, \"%s\")\n", l, s);
332 listDebugDetails(l);
333 #endif /* PROC_TRACE */
334
335 listValidate(l, YES);
336 if (s == NULL_STR) {
337 Assert(NO, "listAppend: Null string to insert!");
338 }
339 /*
340 * Now we know we have a valid list with enough room to add one more
341 * element; simply insert it at the end, increment the 'used' counter
342 * and get outta Dodge.
343 */
344 p = &l->items[l->used++];
345 p->str = copyString(s, MTAG_UNSORTKEY);
346 p->buf = NULL_STR;
347 p->val = p->val2 = p->val3 = 0;
348 return (p);
349 }
350
351 #ifdef notdef
352 /**
353 * \brief Look up an element in a list based on it's name (str) value and
354 * return NULL if not found.
355 * \note the list MUST be of sort-type SORT_BY_NAME for this to be valid.
356 * This is a specific-purpose routine, necessitated by needing to change
357 * the name of a DOS-format package on-the-fly. This function should
358 * probably be used sparingly -- as little as needed, actually. :(
359 */
360 /*
361 CDB -- From comment above, we could probably get rid of this. #ifdef'd
362 out for now.
363 */
listLookupName(list_t * l,char * s)364 item_t *listLookupName(list_t *l, char *s)
365 {
366 item_t *p; /* computed return value */
367 int i;
368 int match;
369
370 #if defined(PROC_TRACE)
371 #ifdef PROC_TRACE_SWITCH
372 if (gl.ptswitch) {
373 #endif /* PROC_TRACE_SWITCH */
374 printf("== listLookupName(%p, \"%s\")\n", l, s);
375 listDebugDetails(l);
376 #ifdef PROC_TRACE_SWITCH
377 }
378 #endif /* PROC_TRACE_SWITCH */
379 #endif /* PROC_TRACE */
380
381 #if defined(QA_CHECKS) || defined(LIST_DEBUG)
382 listValidate(l, NO);
383 if (s == NULL_STR) {
384 Assert(NO, "lookupName: Null key for lookup!");
385 return(NULL_ITEM);
386 }
387 #endif /* QA_CHECKS || LIST_DEBUG */
388 /*
389 * Now we know we have a valid list with enough room to add one more
390 * element; simply insert it at the end, increment the 'used' counter
391 * and get outta Dodge.
392 */
393 if (l->sorted != SORT_BY_NAME && l->sorted != 0) {
394 LOG_FATAL("Improper sort-type %d for %s name-lookup", l->sorted, l->name)
395 Bail(-__LINE__);
396 }
397 /*
398 * Walk through the sorted-by-name list and exit when we're done.
399 * This function could be called during a loop (while(listIterate(&list)))
400 * and we DON'T want to mess up the 'ix' field for this list!
401 */
402 for (i = 0; i < l->used; i++) {
403 if (l->items[i].str == NULL_STR) {
404 Assert(NO, "%s[%d] is NULL!", l->name, i);
405 continue;
406 }
407 match = strcmp(s, l->items[i].str);
408 if (match == 0) {
409 return(&(l->items[i]));
410 }
411 else if (match < 0) { /* e.g., cannnot be in list */
412 break;
413 }
414 }
415 return(NULL_ITEM);
416 }
417 #endif /* notdef */
418
419 #ifdef notdef
420 /*
421 * Look up an element in a list based on it's alias (buf) value and
422 * return NULL if not found.
423 *****
424 * NOTE: the list MUST be of sort-type SORT_BY_ALIAS for this to be valid.
425 *****
426 * This is a general-purpose utility; often it's required to look up a
427 * specific value based on an item's alias.
428 */
listLookupAlias(list_t * l,char * s)429 item_t *listLookupAlias(list_t *l, char *s)
430 {
431 item_t *p; /* computed return value */
432 int i;
433 int x;
434
435 #if defined(PROC_TRACE)
436 #ifdef PROC_TRACE_SWITCH
437 if (gl.ptswitch) {
438 #endif /* PROC_TRACE_SWITCH */
439 printf("== listLookupAlias(%p, \"%s\")\n", l, s);
440 listDebugDetails(l);
441 #ifdef PROC_TRACE_SWITCH
442 }
443 #endif /* PROC_TRACE_SWITCH */
444 #endif /* PROC_TRACE */
445 #if defined(QA_CHECKS) || defined(LIST_DEBUG)
446 listValidate(l, NO);
447 if (s == NULL_STR) {
448 Assert(NO, "lookupAlias: Null key for lookup!");
449 }
450 #endif /* QA_CHECKS || LIST_DEBUG */
451 /*
452 * Now we know we have a valid list with enough room to add one more
453 * element; simply insert it at the end, increment the 'used' counter
454 * and get outta Dodge.
455 */
456 if (l->sorted != SORT_BY_ALIAS) {
457 LOG_FATAL("Improper sort-type %d for %s alias-lookup", l->sorted, l->name)
458 Bail(-__LINE__);
459 }
460 /*
461 * Walk through the sorted-by-alias list and exit when we're done.
462 * Do NOT use listIterate() or we could mess up the 'ix' field!
463 */
464 for (i = 0, p = l->items; i < l->used; i++, p++) {
465 if (p->buf == NULL_STR) {
466 Assert(NO, "%s[%d] is NULL!", l->name, i);
467 continue;
468 }
469 if ((x = strcmp(s, p->buf)) == 0) {
470 return(p);
471 }
472 else if (x < 0) { /* e.g., not in list */
473 break;
474 }
475 }
476 return(NULL_ITEM);
477 }
478 #endif /* notdef */
479
480 /**
481 * \brief return a pointer to listitem, returns a NULL_ITEM when no more items
482 * to return.
483 *
484 * @param l list a point to a list
485 *
486 * \note This routine increments the ix member! (bad boy)
487 *
488 * \todo remove/fix the fact that this routine increments ix.
489 */
listIterate(list_t * l)490 item_t *listIterate(list_t *l) {
491
492 item_t *p;
493
494 #ifdef LIST_DEBUG /* was PROC_TRACE */
495 traceFunc("== listIterate(%p) -- %s (ix %d, used %d)\n", l, l->name,
496 l->ix, l->used);
497 listDebugDetails(l);
498 #endif /* LIST_DEBUG, oh-so-formerly-PROC_TRACE */
499
500 #if defined(QA_CHECKS) || defined(LIST_DEBUG)
501 listValidate(l, NO);
502 if (l->used == 0) { /* empty list? */
503 return(NULL_ITEM);
504 }
505 #endif /* QA_CHECKS || LIST_DEBUG */
506 l->ix++;
507
508 if (l->ix == l->used) {
509 #ifdef LIST_DEBUG
510 Assert(NO, "End-of-list: %s", l->name);
511 #endif /* LIST_DEBUG */
512 l->ix = -1;
513 return (NULL_ITEM);
514 } else if ((l->ix > l->used) || (l->ix < 0)) {
515 LOG_FATAL("Index %d out of bounds (%d) on %s", l->ix, l->used, l->name)
516 Bail(-__LINE__);
517 }
518 p = l->items+(l->ix);
519 return (p);
520 }
521
522 /**
523 * \brief Rest list ix to -1
524 * \param l List to reset
525 */
listIterationReset(list_t * l)526 void listIterationReset(list_t *l) {
527
528 #ifdef LIST_DEBUG /* was PROC_TRACE */
529 traceFunc("== listIterationReset(%p) -- %s (ix %d, used %d)\n", l, l->name,
530 l->ix, l->used);
531 listDebugDetails(l);
532 #endif /* LIST_DEBUG, oh-so-formerly-PROC_TRACE */
533
534 #if defined(QA_CHECKS) || defined(LIST_DEBUG)
535 listValidate(l, NO);
536 #endif /* QA_CHECKS || LIST_DEBUG */
537
538 l->ix = -1; /* reset index for listIterate() */
539 return;
540 }
541
542 /**
543 * \brief Delete an item from list
544 *
545 * The function also rearrange list after deletion.
546 * \param l List to delete from
547 * \param p Item to delete
548 * \return 0 on error, 1 on success
549 */
listDelete(list_t * l,item_t * p)550 int listDelete(list_t *l, item_t *p) {
551 int index;
552 item_t *base;
553
554 #if defined(PROC_TRACE)
555 traceFunc("== listDelete(%p, %p)\n", l, p);
556 listDebugDetails(l);
557 #endif /* PROC_TRACE */
558
559 #if defined(QA_CHECKS) || defined(LIST_DEBUG)
560 listValidate(l, NO);
561 #endif /* QA_CHECKS || LIST_DEBUG */
562 if ((base = l->items) == NULL_ITEM) {
563 Assert(NO, "%s: empty list", l->name);
564 return (0);
565 }
566 if ((index = p-base) >= l->used) {
567 Assert(NO, "%s[%d] is out of range", l->name, p-(l->items));
568 return (0);
569 }
570 #ifdef LIST_DEBUG
571 printf("DEBUG: listDelete: delete index %d (used %d, size %d)\n",
572 index, l->used, l->size);
573 #endif /* LIST_DEBUG */
574 /*
575 * If anything was allocated, delete it.
576 */
577 if (p->str != NULL_STR) {
578 memFree(p->str, MTAG_LISTKEY);
579 }
580 if (p->buf != NULL_STR) {
581 memFree(p->buf, MTAG_LISTBUF);
582 }
583 /*
584 * move everything up (e.g., from index+1 to index, index+2 to index+1)
585 */
586 if (index+1 < l->used) {
587 (void) memmove(l->items+index, l->items+index+1, (size_t)((l->used
588 -index)*sizeof(item_t)));
589 }
590 l->used--; /* ... then just ignore it now */
591 return (1);
592 }
593
594 /**
595 * \brief Double the size of list
596 *
597 * Creates a new pointer with double the size of current list, copy old list
598 * items, free the old list->items and assign new pointer to list->items
599 * \param l List to be doubled
600 */
listDoubleSize(list_t * l)601 static void listDoubleSize(list_t *l) {
602 int sz;
603 item_t *newptr;
604
605 #if defined(PROC_TRACE)
606 traceFunc("== listDoubleSize(%p) -- %s\n", l, l->name);
607 listDebugDetails(l);
608 #endif /* PROC_TRACE */
609
610 sz = (size_t) (l->used * (int)sizeof(item_t));
611 #ifdef LIST_DEBUG
612 printf("LIST: %s FULL (%d) @ addr %p! -- %d -> %d\n", l->name,
613 l->used, l, sz, sz * 2);
614 #endif /* LIST_DEBUG */
615 #ifdef MEMSTATS
616 printf("... DOUBLE \"%s\" (%d -> %d) => %d slots\n", l->name, sz, sz * 2,
617 (sz * 2)/sizeof(item_t));
618 #endif /* MEMSTATS */
619
620 newptr = (item_t *)memAlloc(sz * 2, MTAG_DOUBLED);
621 memcpy((void *) newptr, (void *) l->items, sz);
622 if (l->items != newptr) {
623 #ifdef LIST_DEBUG
624 printf("LIST: old %p new %p\n", l->items, newptr);
625 #endif /* LIST_DEBUG */
626 memFree(l->items, MTAG_TOOSMALL);
627 l->items = newptr;
628 }
629 l->size *= 2;
630
631 return;
632 }
633
634 /**
635 * \brief Sort the list as per the sortType passed
636 * \param[in,out] l List to sort
637 * \param sortType \parblock
638 * Which type of sorting to use.
639 *
640 * It can of `UNSORTED|SORT_BY_NAME_ICASE|SORT_BY_NAME|SORT_BY_COUNT_DSC|
641 * SORT_BY_COUNT_ASC|SORT_BY_ALIAS|SORT_BY_BASENAME`
642 * \endparblock
643 */
listSort(list_t * l,int sortType)644 void listSort(list_t *l, int sortType) {
645
646 int (*f)() = 0;
647
648 #ifdef PROC_TRACE
649 char *fName;
650 #ifdef PROC_TRACE_SWITCH
651 if (gl.ptswitch) {
652 #endif /* PROC_TRACE_SWITCH */
653 printf("== listSort(%p, %d", l, sortType);
654 switch (sortType) {
655 case SORT_BY_NAME:
656 printf("(NAME)");
657 break;
658 case SORT_BY_COUNT_DSC:
659 printf("(COUNT_DSC)");
660 break;
661 case SORT_BY_COUNT_ASC:
662 printf("(COUNT_ASC)");
663 break;
664 case SORT_BY_ALIAS:
665 printf("(ALIAS)");
666 break;
667 case SORT_BY_BASENAME:
668 printf("(BASENAME)");
669 break;
670 default:
671 printf("(***)");
672 break;
673 }
674 printf(")\n");
675 listDebugDetails(l);
676 #ifdef PROC_TRACE_SWITCH
677 }
678 #endif /* PROC_TRACE_SWITCH */
679 #endif /* PROC_TRACE */
680
681 if (sortType == SORT_BY_BASENAME) { /* special case */
682 l->sorted = SORT_BY_NAME;
683 } else {
684 l->sorted = sortType;
685 }
686
687 if (l->used == 0) {
688 #ifdef LIST_DEBUG
689 LOG_WARNING("\"%s\" is empty", l->name);
690 #endif /* LIST_DEBUG */
691 return;
692 }
693
694 switch (sortType) {
695 #ifdef QA_CHECKS
696 case UNSORTED:
697 LOG_FATAL("Sort-spec == UNSORTED")
698 Bail(-__LINE__);
699 break;
700 #endif /* QA_CHECKS */
701 case SORT_BY_NAME_ICASE:
702 f = strIcaseCompare;
703 #ifdef PROC_TRACE
704 fName = "strIcaseCompare";
705 #endif /* PROC_TRACE */
706 break;
707 case SORT_BY_NAME:
708 f = strCompare;
709 #ifdef PROC_TRACE
710 fName = "strCompare";
711 #endif /* PROC_TRACE */
712 break;
713 case SORT_BY_COUNT_DSC:
714 f = valCompareDsc;
715 #ifdef PROC_TRACE
716 fName = "valCompareDsc";
717 #endif /* PROC_TRACE */
718 break;
719 case SORT_BY_COUNT_ASC:
720 f = valCompareAsc;
721 #ifdef PROC_TRACE
722 fName = "valCompareAsc";
723 #endif /* PROC_TRACE */
724 break;
725 case SORT_BY_ALIAS:
726 #ifdef PROC_TRACE
727 fName = "bufCompare";
728 #endif /* PROC_TRACE */
729 f = bufCompare;
730 break;
731 case SORT_BY_BASENAME:
732 #ifdef PROC_TRACE
733 fName = "strCompareBasename";
734 #endif /* PROC_TRACE */
735 f = strCompareBasename;
736 sortType = SORT_BY_NAME;
737 break;
738 default:
739 LOG_FATAL("Invalid sort-spec %d", sortType)
740 Bail(-__LINE__);
741 }
742
743 #ifdef PROC_TRACE
744 traceFunc("=> invoking qsort(): callback is %s()\n", fName);
745 #endif /* PROC_TRACE */
746
747 qsort(l->items, (size_t) l->used, sizeof(item_t), f);
748 return;
749 }
750
751 /**
752 * qsort utility-function to create an alphabetically sorted (ASCENDING)
753 * [case-insensitive] list based on the string value in the item_t 'str' field
754 */
strIcaseCompare(item_t * p1,item_t * p2)755 static int strIcaseCompare(item_t *p1, item_t *p2) {
756 int ret;
757
758 ret = strcasecmp(p1->str, p2->str);
759 return (ret ? ret : valCompareDsc(p1, p2));
760 }
761
762 /**
763 * qsort utility-function to create an alphabetically sorted (ASCENDING)
764 * list based on the string value in the item_t 'str' field
765 */
strCompare(item_t * p1,item_t * p2)766 static int strCompare(item_t *p1, item_t *p2) {
767 int ret;
768
769 ret = strcmp(p1->str, p2->str);
770 return (ret ? ret : valCompareDsc(p1, p2));
771 }
772
773 /**
774 * qsort utility-function to create an alphabetically sorted (ASCENDING)
775 * list based on the path-basename of string value in the item_t 'str' field
776 */
strCompareBasename(item_t * p1,item_t * p2)777 static int strCompareBasename(item_t *p1, item_t *p2) {
778 int ret;
779
780 ret = strcmp(pathBasename(p1->str), pathBasename(p2->str));
781 return (ret ? ret : strCompare(p1, p2));
782 }
783
784 /**
785 * qsort utility-function to create a numerically sorted (ASCENDING)
786 * list based on the integer value in the item_t 'val' field
787 */
valCompareAsc(item_t * p1,item_t * p2)788 static int valCompareAsc(item_t *p1, item_t *p2) {
789 return (p1->val - p2->val);
790 }
791
792 /**
793 * qsort utility-function to create a numerically sorted (DESCENDING)
794 * list based on the integer value in the item_t 'val' field
795 */
valCompareDsc(item_t * p1,item_t * p2)796 static int valCompareDsc(item_t *p1, item_t *p2) {
797 return (p2->val - p1->val);
798 }
799
800 /**
801 * qsort utility-function to create an alphabetically sorted (ASCENDING)
802 * list based on the string value in the item_t 'buf' field
803 */
bufCompare(item_t * p1,item_t * p2)804 static int bufCompare(item_t *p1, item_t *p2) {
805 int ret = strcmp(p1->buf, p2->buf);
806 return (ret ? ret : valCompareDsc(p1, p2));
807 }
808
809 /**
810 * Be careful about calling this function; some lists use the 'val'
811 * field as a flag, others use it as a count!
812 */
listCount(list_t * l)813 int listCount(list_t *l) {
814 int i;
815 int total;
816
817 #ifdef PROC_TRACE
818 traceFunc("== listCount(%p)\n", l);
819 listDebugDetails(l);
820 #endif /* PROC_TRACE */
821
822 #if defined(QA_CHECKS) || defined(LIST_DEBUG)
823 listValidate(l, NO);
824 #endif /* QA_CHECKS || LIST_DEBUG */
825 total = 0;
826 for (i = 0; i < l->used; i++) {
827 if (l->items[i].val > 0) {
828 total += l->items[i].val; /* sum POSITIVE 'val' values */
829 }
830 }
831 return (total);
832 }
833
834 /**
835 * \brief print the passed in list
836 *
837 * @param *l the list to dump
838 * @param verbose flag, print more
839 *
840 * \callgraph
841 */
listDump(list_t * l,int verbose)842 void listDump(list_t *l, int verbose) {
843 item_t *p;
844 int i;
845 int max = (verbose ? l->size : l->used);
846
847 #ifdef PROC_TRACE
848 traceFunc("== listDump(%p, %d)\n", l, verbose);
849 listDebugDetails(l);
850 #endif /* PROC_TRACE */
851
852 /*MD: why should an empty list be fatal? Just return....? */
853 if (l == NULL_LIST) {
854 LOG_FATAL("NULL list passed to listDump()")
855 Bail(-__LINE__);
856 }
857 if (l->used == 0) {
858 #if defined(LIST_DEBUG) || defined(UNPACK_DEBUG) || defined(REPORT_DEBUG)
859 LOG_WARNING("%s is empty", l->name);
860 #endif /* LIST_DEBUG || UNPACK_DEBUG || REPORT_DEBUG */
861 return;
862 }
863 if (verbose < 0) {
864 printf("** %s (size %d, used %d, ix %d, sort %d desc %d) == %lu\n",
865 l->name, l->size, l->used, l->ix, l->sorted, l->desc,
866 (unsigned long)sizeof(item_t));
867 return;
868 }
869 if (verbose || max) {
870 printf("Contents of %s:\n", l->name);
871 printf(" ... @%p (size %d, used %d, ix %d, sort %d desc %d)\n", l,
872 l->size, l->used, l->ix, l->sorted, l->desc);
873 }
874 /*
875 * Brute-force a walk through the list contents. This function could
876 * be called during a loop (while(listIterate(&list))) and we CANNOT
877 * mess with the 'ix' field for this list as listIterate() does!
878 */
879 for (i = 0; i < l->used; i++) {
880 p = &(l->items[i]);
881 if (verbose) {
882 printf("[%c] ", (i < l->used ? 'x' : ' '));
883 }
884 printf("#%03d: str %p buf %p (val %d, val2 %d val3 %d)\n", i, p->str,
885 p->buf, p->val, p->val2, p->val3);
886 if (i < l->used) {
887 printf(" str: \"%s\"\n", p->str);
888 if (p->buf != NULL_STR) {
889 printf(" ... buf: \"%s\"\n", (char *)p->buf);
890 }
891 }
892 }
893 return;
894 } /* listDump */
895
896 #if defined(PROC_TRACE) || defined(LIST_DEBUG)
listDebugDetails(list_t * l)897 void listDebugDetails(list_t *l)
898 {
899 if (l != NULL_LIST && l->size) {
900 printf("... %p is %s\n", l, l->name ? l->name : "No-name");
901 }
902 return;
903 }
904 #endif /* PROC_TRACE || LIST_DEBUG */
905