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