Imported Upstream version 0.4.8
[platform/upstream/libsmi.git] / tools / dump-metrics.c
1 /*
2  * dump-metrics.c --
3  *
4  *      Operations to compute and dump some MIB metrics.
5  *
6  * Copyright (c) 2000 Frank Strauss, Technical University of Braunschweig.
7  * Copyright (c) 2000 J. Schoenwaelder, Technical University of Braunschweig.
8  * Copyright (c) 2002 J. Schoenwaelder, University of Osnabrueck.
9  * Copyright (c) 2004 J. Schoenwaelder, International University Bremen.
10  *
11  * See the file "COPYING" for information on usage and redistribution
12  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13  *
14  * @(#) $Id: dump-metrics.c 8090 2008-04-18 12:56:29Z strauss $
15  */
16
17 /*
18   # revisions
19   # imports
20   # row creations:
21   # count node references in notification definitions
22  */
23
24 #include <config.h>
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "smi.h"
30 #include "smidump.h"
31
32
33 static int raw = 0;
34
35 static int silent = 0;
36
37
38 typedef struct BasetypeCounter {
39     unsigned long total;
40     unsigned long unknown;
41     unsigned long integer32;
42     unsigned long octetstring;
43     unsigned long objectidentifier;
44     unsigned long unsigned32;
45     unsigned long integer64;
46     unsigned long unsigned64;
47     unsigned long float32;
48     unsigned long float64;
49     unsigned long float128;
50     unsigned long enums;
51     unsigned long bits;
52     unsigned long pointer;
53 } BasetypeCounter;
54
55
56 typedef struct StatusCounter {
57     unsigned long total;
58     unsigned long current;
59     unsigned long deprecated;
60     unsigned long obsolete;
61 } StatusCounter;
62
63
64
65 typedef struct AccessCounter {
66     unsigned long total;
67     unsigned long noaccess;
68     unsigned long notify;
69     unsigned long readonly;
70     unsigned long readwrite;
71 } AccessCounter;
72
73
74
75 typedef struct IndexCounter {
76     unsigned long total;
77     unsigned long index;
78     unsigned long augment;
79     unsigned long reorder;
80     unsigned long sparse;
81     unsigned long expand;
82 } IndexCounter;
83
84
85
86 typedef struct IndexLenCounter {
87     unsigned long total;
88     unsigned long length[11];
89 } IndexLenCounter;
90
91
92
93 typedef struct TableLenCounter {
94     unsigned long total;
95     unsigned long length[81];
96 } TableLenCounter;
97
98
99
100 typedef struct ScalarLenCounter {
101     unsigned long total;
102     unsigned long length[81];
103 } ScalarLenCounter;
104
105
106
107 typedef struct IndexComplexityCounter {
108     unsigned long total;
109     unsigned long complexity[100];
110 } IndexComplexityCounter;
111
112
113
114 typedef struct LengthCounter {
115     unsigned long total;
116     unsigned long descr;
117     unsigned long descr_len;
118     unsigned long reference;
119     unsigned long reference_len;
120     unsigned long units;
121     unsigned long units_len;
122     unsigned long format;
123     unsigned long format_len;
124 } LengthCounter;
125
126
127
128 typedef struct RowStatusCounter {
129     unsigned long basetables;
130     unsigned long rowstatus;
131     unsigned long storagetype;
132 } RowStatusCounter;
133
134
135
136 typedef struct Metrics {
137     BasetypeCounter basetypesColumns;
138     BasetypeCounter basetypesScalars;
139     BasetypeCounter basetypesAll;
140     StatusCounter   statusTypes;
141     StatusCounter   statusTables;
142     StatusCounter   statusColumns;
143     StatusCounter   statusScalars;
144     StatusCounter   statusNotifications;
145     StatusCounter   statusGroups;
146     StatusCounter   statusCompliances;
147     StatusCounter   statusAll;
148     AccessCounter   accessColumns;
149     AccessCounter   accessScalars;
150     AccessCounter   accessAll;
151     IndexCounter    indexTables;
152     IndexLenCounter indexLenTables;
153     IndexComplexityCounter indexComplexity;
154     TableLenCounter tableLength;
155     ScalarLenCounter scalarLength;
156     LengthCounter   lengthTypes;
157     LengthCounter   lengthTables;
158     LengthCounter   lengthRows;
159     LengthCounter   lengthColumns;
160     LengthCounter   lengthScalars;
161     LengthCounter   lengthNotifications;
162     LengthCounter   lengthAll;
163 } Metrics;
164
165
166
167 typedef struct UsageCounter {
168     char     *module;
169     char     *name;
170     unsigned count;
171     struct UsageCounter *nextPtr;
172 } UsageCounter;
173
174
175 static UsageCounter *typeList = NULL;
176 static UsageCounter *extTypeList = NULL;
177 static UsageCounter *extNodeList = NULL;
178 static UsageCounter *extModuleList = NULL;
179 static UsageCounter *indexComplexityList = NULL;
180
181 #define INCR_NODE 0x01
182 #define INCR_TYPE 0x02
183
184
185 static char*
186 getDateString(time_t t)
187 {
188     static char   *s = NULL;
189     struct tm     *tm;
190
191     if (s) xfree(s);
192     
193     tm = gmtime(&t);
194     smiAsprintf(&s, "%04d-%02d-%02d",
195                 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
196     return s;
197 }
198
199
200
201 static char*
202 language(SmiLanguage language)
203 {
204     return
205         (language == SMI_LANGUAGE_UNKNOWN)    ? "-" :
206         (language == SMI_LANGUAGE_SMIV1)      ? "SMIv1" :
207         (language == SMI_LANGUAGE_SMIV2)      ? "SMIv2" :
208         (language == SMI_LANGUAGE_SMING)      ? "SMIng" :
209                                                 "-";
210 }
211
212
213
214 static int
215 calcSize(SmiModule *smiModule)
216 {
217     SmiNode *smiNode;
218     SmiType *smiType;
219     int size = 0;
220     
221     for (smiType = smiGetFirstType(smiModule);
222          smiType;
223          smiType = smiGetNextType(smiType)) {
224         if (smiType->name) {
225             size++;
226         }
227     }
228     
229     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
230          smiNode;
231          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
232
233         switch (smiNode->nodekind) {
234         case SMI_NODEKIND_SCALAR:
235         case SMI_NODEKIND_COLUMN:
236         case SMI_NODEKIND_NOTIFICATION:
237             size++;
238             break;
239         default:
240             break;
241         }
242     }
243
244     return size;
245 }
246
247
248
249 typedef void    (*ForEachIndexFunc)     (FILE *f, SmiNode *groupNode, SmiNode *smiNode, void *data);
250
251 static void
252 foreachIndexDo(FILE *f, SmiNode *smiNode, ForEachIndexFunc func, void *data)
253 {
254     SmiNode *indexNode = NULL, *iNode;
255     SmiElement *smiElement;
256     
257     switch (smiNode->indexkind) {
258     case SMI_INDEX_INDEX:
259     case SMI_INDEX_REORDER:
260         indexNode = smiNode;
261         break;
262     case SMI_INDEX_EXPAND:      /* TODO: we have to do more work here! */
263         break;
264     case SMI_INDEX_AUGMENT:
265     case SMI_INDEX_SPARSE:
266         indexNode = smiGetRelatedNode(smiNode);
267         break;
268     case SMI_INDEX_UNKNOWN:
269         break;
270     }
271     if (indexNode) {
272         for (smiElement = smiGetFirstElement(indexNode);
273              smiElement; smiElement = smiGetNextElement(smiElement)) {
274             iNode = smiGetElementNode(smiElement);
275             if (iNode) {
276                 (func) (f, smiNode, iNode, data);
277             }
278         }
279     }
280 }
281
282
283
284 static UsageCounter*
285 incrUsageCounter(UsageCounter *uCntList, char *module, char *name, int incr)
286 {
287     UsageCounter *uCnt;
288
289     for (uCnt = uCntList; uCnt; uCnt = uCnt->nextPtr) {
290         if (strcmp(uCnt->module, module) == 0
291             && (! name || strcmp(uCnt->name, name) == 0)) {
292             break;
293         }
294     }
295
296     if (! uCnt) {
297         uCnt = (UsageCounter *) xmalloc(sizeof(UsageCounter));
298         uCnt->module = xstrdup(module);
299         uCnt->name = name ? xstrdup(name) : NULL;
300         uCnt->count = 0;
301         uCnt->nextPtr = uCntList;
302         uCntList = uCnt;
303     }
304
305     uCnt->count += incr;
306     return uCntList;
307 }
308
309
310
311 static void
312 incrTypeAndNodeUsageCounter(SmiModule *smiModule, SmiNode *smiNode, int flags)
313 {
314     SmiType *smiType;
315     char *extModule;
316
317     /*
318      * First check whether the node is external. If yes, increment the
319      * external node counter and we are done.
320      */
321
322     extModule = smiGetNodeModule(smiNode)->name;
323     if (extModule
324         && strcmp(extModule, smiModule->name) != 0) {
325         if (flags & INCR_NODE) {
326             extNodeList = incrUsageCounter(extNodeList,
327                                            extModule, smiNode->name, 1);
328             extModuleList = incrUsageCounter(extModuleList, extModule, NULL, 1);
329         }
330         return;
331     }
332     
333     /*
334      * Next, check whether the type of the node is external. If yes,
335      * increment the external type counter and we are done. Do not
336      * count base types (that is types that have no parent type).
337      */
338
339     smiType = smiGetNodeType(smiNode);
340     if (! smiType) {
341         return;
342     }
343
344     if (smiType->name && smiGetParentType(smiType)) {
345         char *extModule = smiGetTypeModule(smiType)->name;
346         if (extModule /* && *extModule */
347             && strcmp(extModule, smiModule->name) != 0) {
348             if (flags & INCR_TYPE) {
349                 extTypeList = incrUsageCounter(extTypeList,
350                                                extModule, smiType->name, 1);
351                 extModuleList = incrUsageCounter(extModuleList, extModule, NULL, 1);
352             }
353         }
354     }
355
356     /*
357      * Finally, count the type name (whether external or not does not
358      * matter here nor does it matter whether it is a base type or
359      * not).
360      */
361
362     if (! smiType->name && smiGetParentType(smiType)) {
363         smiType = smiGetParentType(smiType);
364     }
365     typeList = incrUsageCounter(typeList, smiGetTypeModule(smiType)->name,
366                                 smiType->name, 1);
367 }
368
369
370
371 static void
372 incrIndexComplexityCounter(SmiModule *smiModule, SmiNode *smiNode, int complexity)
373 {
374     indexComplexityList = incrUsageCounter(indexComplexityList,
375                                            smiModule->name, smiNode->name, complexity);
376 }
377
378
379
380 static int
381 cmp(const void *va, const void *vb)
382 {
383     UsageCounter **a = (UsageCounter **) va;
384     UsageCounter **b = (UsageCounter **) vb;
385
386     if ((*a)->count > (*b)->count) return -1;
387     if ((*a)->count < (*b)->count) return 1;
388
389     if ((*a)->module && (*b)->module) {
390         int x = strcmp((*a)->module,  (*b)->module);
391         if (x) return x;
392     }
393
394     if ((*a)->name && (*b)->name) {
395         int x = strcmp((*a)->name,  (*b)->name);
396         if (x) return x;
397     }
398
399     return 0;
400 }
401
402
403
404 static int
405 fprintRevisions(FILE *f, int modLen, SmiRevision *smiRevision,
406                 SmiModule *smiModule, int size)
407 {
408     int n = 0;
409     
410     if (smiRevision) {
411         n = fprintRevisions(f, modLen,
412                             smiGetNextRevision(smiRevision), smiModule, -1);
413         fprintf(f, "%-*s %7s  ", modLen, smiModule->name,
414                 (size >= 0) ? language(smiModule->language) : "-");
415         if (size >= 0) {
416             fprintf(f, "%4d", size);
417         } else {
418             fprintf(f, "   -");
419         }
420         fprintf(f, "   %3d    %s\n", n, getDateString(smiRevision->date));
421         n++;
422     }
423
424     if (!smiRevision && size >= 0) {
425         fprintf(f, "%-*s %7s  ", modLen, smiModule->name,
426                 language(smiModule->language));
427         fprintf(f, "%4d", size);
428         fprintf(f, "     -    ----------\n");
429     }
430     
431     return n;
432 }
433
434
435
436 static void
437 fprintRevision(FILE *f, int modc, SmiModule **modv)
438 {
439     int i;
440     int modLen = 8;
441
442     for (i = 0; i < modc; i++) {
443         if (modLen < strlen(modv[i]->name)) {
444             modLen = strlen(modv[i]->name);
445         }
446     }
447
448     fprintf(f, "%-*s LANGUAGE SIZE REVISION DATE\n", modLen, "MODULE");
449
450     for (i = 0; i < modc; i++) {
451         fprintRevisions(f, modLen, smiGetFirstRevision(modv[i]),
452                         modv[i], calcSize(modv[i]));
453     }
454     fprintf(f, "\n");
455  
456 }
457
458
459
460 static void
461 fprintTypeUsage(FILE *f, UsageCounter *typeUsageList)
462 {
463     UsageCounter *uCnt;
464     int modLen = 8, nameLen = 8;
465     unsigned total = 0;
466     int i, cnt = 0;
467     UsageCounter **sortCnt;
468
469     /* should be sorted */
470
471     for (uCnt = typeUsageList, cnt = 0; uCnt; uCnt = uCnt->nextPtr, cnt++) {
472         if (modLen < strlen(uCnt->module)) {
473             modLen = strlen(uCnt->module);
474         }
475         if (nameLen < strlen(uCnt->name)) {
476             nameLen = strlen(uCnt->name);
477         }
478         total += uCnt->count;
479     }
480
481     if (cnt == 0) {
482         return;
483     }
484
485     /* create an array for a quick qsort */
486
487     sortCnt = (UsageCounter **) xmalloc(cnt * sizeof(UsageCounter *));
488     memset(sortCnt, 0, cnt * sizeof(UsageCounter *));
489     for (uCnt = typeUsageList, i = 0; uCnt; uCnt = uCnt->nextPtr, i++) {
490         sortCnt[i] = uCnt;
491     }
492     qsort(sortCnt, cnt, sizeof(UsageCounter *), cmp);
493     
494     if (! silent) {
495         fputs(
496 "# The following table shows the distribution of the number of references\n"
497 "# to defined types (including base types) in the set of loaded MIB\n"
498 "# modules.\n"
499 "\n", f);
500     }
501     fprintf(f, "%-*s %-*s   USAGE\n", modLen, "MODULE", nameLen, "TYPE");
502
503     for (i = 0; i < cnt; i++) {
504         fprintf(f, "%-*s %-*s ",
505                 modLen, sortCnt[i]->module, nameLen, sortCnt[i]->name);
506         if (raw) {
507             fprintf(f, "%8u\n", sortCnt[i]->count);
508         } else {
509             fprintf(f, "%6.1f%%\n", (double) sortCnt[i]->count * 100 / total);
510         }
511     }
512
513     xfree(sortCnt);
514 }
515
516
517
518 static void
519 fprintExtTypeUsage(FILE *f, UsageCounter *typeUsageList)
520 {
521     UsageCounter *uCnt;
522     int modLen = 8, nameLen = 8;
523     unsigned total = 0;
524     int i, cnt = 0;
525     UsageCounter **sortCnt;
526
527     /* should be sorted */
528
529     for (uCnt = typeUsageList, cnt = 0; uCnt; uCnt = uCnt->nextPtr, cnt++) {
530         if (modLen < strlen(uCnt->module)) {
531             modLen = strlen(uCnt->module);
532         }
533         if (nameLen < strlen(uCnt->name)) {
534             nameLen = strlen(uCnt->name);
535         }
536         total += uCnt->count;
537     }
538
539     if (cnt == 0) {
540         return;
541     }
542
543     /* create an array for a quick qsort */
544
545     sortCnt = (UsageCounter **) xmalloc(cnt * sizeof(UsageCounter *));
546     memset(sortCnt, 0, cnt * sizeof(UsageCounter *));
547     for (uCnt = typeUsageList, i = 0; uCnt; uCnt = uCnt->nextPtr, i++) {
548         sortCnt[i] = uCnt;
549     }
550     qsort(sortCnt, cnt, sizeof(UsageCounter *), cmp);
551     
552     if (! silent) {
553         fputs(
554 "# The following table shows the distribution of the number of references\n"
555 "# to externally defined types (excluding base types) in the set of loaded\n"
556 "# MIB modules.\n"
557 "\n", f);
558     }
559     fprintf(f, "%-*s %-*s EXT-USAGE\n", modLen, "MODULE", nameLen, "TYPE");
560
561     for (i = 0; i < cnt; i++) {
562         fprintf(f, "%-*s %-*s ",
563                 modLen, sortCnt[i]->module, nameLen, sortCnt[i]->name);
564         if (raw) {
565             fprintf(f, "%8u\n", sortCnt[i]->count);
566         } else {
567             fprintf(f, "%6.1f%%\n", (double) sortCnt[i]->count * 100 / total);
568         }
569     }
570
571     xfree(sortCnt);
572 }
573
574
575
576 static void
577 fprintExtNodeUsage(FILE *f, UsageCounter *typeUsageList)
578 {
579     UsageCounter *uCnt;
580     int modLen = 8, nameLen = 8;
581     unsigned total = 0;
582     int i, cnt = 0;
583     UsageCounter **sortCnt;
584
585     /* should be sorted */
586
587     for (uCnt = typeUsageList, cnt = 0; uCnt; uCnt = uCnt->nextPtr, cnt++) {
588         if (modLen < strlen(uCnt->module)) {
589             modLen = strlen(uCnt->module);
590         }
591         if (nameLen < strlen(uCnt->name)) {
592             nameLen = strlen(uCnt->name);
593         }
594         total += uCnt->count;
595     }
596
597     if (cnt == 0) {
598         return;
599     }
600
601     /* create an array for a quick qsort */
602
603     sortCnt = (UsageCounter **) xmalloc(cnt * sizeof(UsageCounter *));
604     memset(sortCnt, 0, cnt * sizeof(UsageCounter *));
605     for (uCnt = typeUsageList, i = 0; uCnt; uCnt = uCnt->nextPtr, i++) {
606         sortCnt[i] = uCnt;
607     }
608     qsort(sortCnt, cnt, sizeof(UsageCounter *), cmp);
609     
610     if (! silent) {
611         fputs(
612 "# The following table shows the distribution of the number of references\n"
613 "# to externally defined nodes in the set of loaded MIB modules.\n"
614 "\n", f);
615     }
616     fprintf(f, "%-*s %-*s EXT-USAGE\n", modLen, "MODULE", nameLen, "NODE");
617
618     for (i = 0; i < cnt; i++) {
619         fprintf(f, "%-*s %-*s ",
620                 modLen, sortCnt[i]->module, nameLen, sortCnt[i]->name);
621         if (raw) {
622             fprintf(f, "%8u\n", sortCnt[i]->count);
623         } else {
624             fprintf(f, "%6.1f%%\n", (double) sortCnt[i]->count * 100 / total);
625         }
626     }
627
628     xfree(sortCnt);
629 }
630
631
632
633 static void
634 fprintModuleUsage(FILE *f, UsageCounter *modUsageList)
635 {
636     UsageCounter *uCnt;
637     int modLen = 8;
638     unsigned total = 0;
639     int i, cnt = 0;
640     UsageCounter **sortCnt;
641
642     /* should be sorted */
643
644     for (uCnt = modUsageList, cnt = 0; uCnt; uCnt = uCnt->nextPtr, cnt++) {
645         if (modLen < strlen(uCnt->module)) {
646             modLen = strlen(uCnt->module);
647         }
648         total += uCnt->count;
649     }
650
651     if (cnt == 0) {
652         return;
653     }
654
655     /* create an array for a quick qsort */
656
657     sortCnt = (UsageCounter **) xmalloc(cnt * sizeof(UsageCounter *));
658     memset(sortCnt, 0, cnt * sizeof(UsageCounter *));
659     for (uCnt = modUsageList, i = 0; uCnt; uCnt = uCnt->nextPtr, i++) {
660         sortCnt[i] = uCnt;
661     }
662     qsort(sortCnt, cnt, sizeof(UsageCounter *), cmp);
663
664     if (! silent) {
665         fputs(
666 "# The following table shows the distribution of the number of references\n"
667 "# to externally defined items (such as types or objects) accumulated by\n"
668 "# the defining MIB module in the set of loaded MIB modules.\n"
669 "\n", f);
670     }
671     fprintf(f, "%-*s EXT-USAGE\n", modLen, "MODULE");
672
673     for (i = 0; i < cnt; i++) {
674         fprintf(f, "%-*s ", modLen, sortCnt[i]->module);
675         if (raw) {
676             fprintf(f, "%8u\n", sortCnt[i]->count);
677         } else {
678             fprintf(f, "%6.1f%%\n", (double) sortCnt[i]->count * 100 / total);
679         }
680     }
681
682     xfree(sortCnt);
683 }
684
685
686
687 static void
688 fprintIndexComplexity(FILE *f, UsageCounter *modUsageList)
689 {
690     UsageCounter *uCnt;
691     int modLen = 8;
692     int nameLen = 8;
693     unsigned total = 0;
694     int i, cnt = 0;
695     UsageCounter **sortCnt;
696
697     /* should be sorted */
698
699     for (uCnt = modUsageList, cnt = 0; uCnt; uCnt = uCnt->nextPtr, cnt++) {
700         if (modLen < strlen(uCnt->module)) {
701             modLen = strlen(uCnt->module);
702         }
703         if (nameLen < strlen(uCnt->name)) {
704             nameLen = strlen(uCnt->name);
705         }
706         total += uCnt->count;
707     }
708
709     if (cnt == 0) {
710         return;
711     }
712
713     /* create an array for a quick qsort */
714
715     sortCnt = (UsageCounter **) xmalloc(cnt * sizeof(UsageCounter *));
716     memset(sortCnt, 0, cnt * sizeof(UsageCounter *));
717     for (uCnt = modUsageList, i = 0; uCnt; uCnt = uCnt->nextPtr, i++) {
718         sortCnt[i] = uCnt;
719     }
720     qsort(sortCnt, cnt, sizeof(UsageCounter *), cmp);
721
722     if (! silent) {
723         fputs(
724 "# The following table shows the distribution of the index complexity\n"
725 "# in the set of loaded MIB modules.\n"
726 "\n", f);
727     }
728     fprintf(f, "%-*s %-*s COMPLEXITY\n", modLen, "MODULE", nameLen, "TABLE");
729
730     for (i = 0; i < cnt; i++) {
731         fprintf(f, "%-*s %-*s ", modLen, sortCnt[i]->module, nameLen, sortCnt[i]->name);
732         if (raw) {
733             fprintf(f, "%8u\n", sortCnt[i]->count);
734         } else {
735             fprintf(f, "%6.1f%%\n", (double) sortCnt[i]->count);
736         }
737     }
738
739     xfree(sortCnt);
740 }
741
742
743
744 static void
745 freeUsageCounter(UsageCounter *usageCounterList)
746 {
747     UsageCounter *uCnt, *p;
748     
749     for (uCnt = usageCounterList; uCnt; ) {
750         p = uCnt, uCnt = uCnt->nextPtr;
751         xfree(p->module);
752         xfree(p->name);
753         xfree(p);
754     }
755 }
756
757
758
759 static void
760 incrBasetypeCounter(BasetypeCounter *basetypeCounter, SmiNode *smiNode)
761 {
762     SmiType *smiType;
763
764     smiType = smiGetNodeType(smiNode);
765     if (smiType) {
766         basetypeCounter->total++;
767         switch (smiType->basetype) {
768         case SMI_BASETYPE_UNKNOWN:
769             basetypeCounter->unknown++;
770             break;
771         case SMI_BASETYPE_INTEGER32:
772             basetypeCounter->integer32++;
773             break;
774         case SMI_BASETYPE_OCTETSTRING:
775             basetypeCounter->octetstring++;
776             break;
777         case SMI_BASETYPE_OBJECTIDENTIFIER:
778             basetypeCounter->objectidentifier++;
779             break;
780         case SMI_BASETYPE_UNSIGNED32:
781             basetypeCounter->unsigned32++;
782             break;
783         case SMI_BASETYPE_INTEGER64:
784             basetypeCounter->integer64++;
785             break;
786         case SMI_BASETYPE_UNSIGNED64:
787             basetypeCounter->unsigned64++;
788             break;
789         case SMI_BASETYPE_FLOAT32:
790             basetypeCounter->float32++;
791             break;
792         case SMI_BASETYPE_FLOAT64:
793             basetypeCounter->float64++;
794             break;
795         case SMI_BASETYPE_FLOAT128:
796             basetypeCounter->float128++;
797             break;
798         case SMI_BASETYPE_ENUM:
799             basetypeCounter->enums++;
800             break;
801         case SMI_BASETYPE_BITS:
802             basetypeCounter->bits++;
803             break;
804         case SMI_BASETYPE_POINTER:
805             basetypeCounter->pointer++;
806             break;
807         }
808     }
809 }
810
811
812
813 static void
814 incrStatusCounter(StatusCounter *cnt, SmiStatus smiStatus)
815 {
816     cnt->total++;
817     switch (smiStatus) {
818     case SMI_STATUS_CURRENT:
819     case SMI_STATUS_MANDATORY:
820     case SMI_STATUS_OPTIONAL:
821         cnt->current++;
822         break;
823     case SMI_STATUS_DEPRECATED:
824         cnt->deprecated++;
825         break;
826     case SMI_STATUS_OBSOLETE:
827         cnt->obsolete++;
828         break;
829     case SMI_STATUS_UNKNOWN:
830         break;
831     }
832 }
833
834
835
836 static void
837 incrAccessCounter(AccessCounter *cnt, SmiAccess smiAccess)
838 {
839     cnt->total++;
840     switch (smiAccess) {
841     case SMI_ACCESS_NOT_ACCESSIBLE:
842         cnt->noaccess++;
843         break;
844     case SMI_ACCESS_NOTIFY:
845         cnt->notify++;
846         break;
847     case SMI_ACCESS_READ_ONLY:
848         cnt->readonly++;
849         break;
850     case SMI_ACCESS_READ_WRITE:
851         cnt->readwrite++;
852         break;
853     case SMI_ACCESS_INSTALL:
854     case SMI_ACCESS_INSTALL_NOTIFY:
855     case SMI_ACCESS_REPORT_ONLY:
856     case SMI_ACCESS_UNKNOWN:
857     case SMI_ACCESS_NOT_IMPLEMENTED:
858     case SMI_ACCESS_EVENT_ONLY:
859         break;
860     }
861 }
862
863
864
865 static void
866 incrIndexCounter(IndexCounter *cnt, SmiIndexkind indexkind)
867 {
868     cnt->total++;
869     switch (indexkind) {
870     case SMI_INDEX_INDEX:
871         cnt->index++;
872         break;
873     case SMI_INDEX_AUGMENT:
874         cnt->augment++;
875         break;
876     case SMI_INDEX_REORDER:
877         cnt->reorder++;
878         break;
879     case SMI_INDEX_SPARSE:
880         cnt->sparse++;
881         break;
882     case SMI_INDEX_EXPAND:
883         cnt->expand++;
884         break;
885     case SMI_INDEX_UNKNOWN:
886         break;
887     }
888 }
889
890
891
892 static void
893 incrIndexLenCounter(IndexLenCounter *cnt, int len)
894 {
895     cnt->total++;
896     if (len < sizeof(cnt->length)/sizeof(cnt->length[0])) {
897         cnt->length[len]++;
898     } else {
899         fprintf(stderr, "smidump: index len overflow: %d\n", len);
900     }
901 }
902
903
904
905 static void
906 incrTableLenCounter(TableLenCounter *cnt, int len)
907 {
908     cnt->total++;
909     if (len < sizeof(cnt->length)/sizeof(cnt->length[0])) {
910         cnt->length[len]++;
911     } else {
912         fprintf(stderr, "smidump: table len overflow: %d\n", len);
913     }
914 }
915
916
917
918 static void
919 incrIndexComplexityMetric(IndexComplexityCounter *cnt, int cmplx)
920 {
921     cnt->total++;
922     if (cmplx < sizeof(cnt->complexity)/sizeof(cnt->complexity[0])) {
923         cnt->complexity[cmplx]++;
924     } else {
925         fprintf(stderr, "smidump: index complexity overflow: %d\n", cmplx);
926     }
927 }
928
929
930
931 static void
932 incrLengthCounter(LengthCounter *cnt, char *description, char *reference,
933                   char *units, char *format)
934 {
935     cnt->total++;
936     if (description) {
937         cnt->descr++;
938         cnt->descr_len += strlen(description);
939     }
940
941     if (reference) {
942         cnt->reference++;
943         cnt->reference_len += strlen(reference);
944     }
945     if (units) {
946         cnt->units++;
947         cnt->units_len += strlen(units);
948     }
949     if (format) {
950         cnt->format++;
951         cnt->format_len += strlen(format);
952     }
953 }
954
955
956
957 static void
958 incrRowStatusCounter(SmiNode *rowNode)
959 {
960     SmiNode *smiNode;
961     SmiType *smiType;
962     SmiModule *smiModule;
963
964     for (smiNode = smiGetFirstChildNode(rowNode);
965          smiNode;
966          smiNode = smiGetNextChildNode(smiNode)) {
967         smiType = smiGetNodeType(smiNode);
968         if (smiType && smiType->name) {
969             smiModule = smiGetTypeModule(smiType);
970             if (smiModule && smiModule->name
971                 && strcmp(smiType->name, "RowStatus") == 0
972                 && strcmp(smiModule->name, "SNMPv2-TC") == 0) {
973                 break;
974             }
975         }
976     }
977
978     if (smiNode) {
979 #if 0
980         fprintf(stderr, "** %s\t%s\t%s\n", rowNode->name,
981                 smiNode->name, smiType->name);
982         /* xxx count rows indexed by ifIndex, InterfaceIndex, InterfaceIndexOrZero, ... */
983 #endif
984     }
985 }
986
987
988
989 static void
990 count(FILE *f, SmiNode *row, SmiNode *col, void *data)
991 {
992     int *cnt = (int *) data;
993
994     (*cnt)++;
995 }
996
997
998
999 static void
1000 complexity(FILE *f, SmiNode *row, SmiNode *col, void *data)
1001 {
1002     int *cmplx = (int *) data;
1003     SmiType *smiType;
1004     unsigned long min, max;
1005
1006     smiType = smiGetNodeType(col);
1007     if (! smiType) {
1008         return;
1009     }
1010
1011     switch (smiType->basetype) {
1012     case SMI_BASETYPE_INTEGER32:
1013     case SMI_BASETYPE_UNSIGNED32:
1014     case SMI_BASETYPE_ENUM:
1015         *cmplx += 1;
1016         break;
1017     case SMI_BASETYPE_OCTETSTRING:
1018     case SMI_BASETYPE_OBJECTIDENTIFIER:
1019     case SMI_BASETYPE_BITS:
1020         *cmplx += 2;
1021         min = smiGetMinSize(smiType);
1022         max = smiGetMaxSize(smiType);
1023         if (min != max) {
1024             *cmplx += 1;
1025         }
1026         break;
1027     default:                            /* ignore everything else */
1028         break;
1029     }
1030 }
1031
1032
1033
1034 static void
1035 yadayada(FILE *f, SmiNode *row, SmiNode *col, void *data)
1036 {
1037     SmiModule *smiModule = (SmiModule *) data;
1038     int flags = 0;
1039
1040     if (col->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1041         flags |= INCR_TYPE;
1042     }
1043     flags |= INCR_NODE;
1044
1045     incrTypeAndNodeUsageCounter(smiModule, col, flags);
1046 }
1047
1048
1049
1050 static void
1051 addMetrics(Metrics *metrics, SmiModule *smiModule)
1052 {
1053     SmiNode *smiNode;
1054     SmiType *smiType;
1055     size_t len;
1056
1057     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
1058          smiNode;
1059          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
1060         len = smiNode->description ? strlen(smiNode->description) : 0;
1061         switch (smiNode->nodekind) {
1062         case SMI_NODEKIND_TABLE:
1063             incrStatusCounter(&metrics->statusTables, smiNode->status);
1064             incrStatusCounter(&metrics->statusAll, smiNode->status);
1065             incrLengthCounter(&metrics->lengthTables,
1066                               smiNode->description, smiNode->reference,
1067                               smiNode->units, smiNode->format);
1068             incrLengthCounter(&metrics->lengthAll,
1069                               smiNode->description, smiNode->reference,
1070                               smiNode->units, smiNode->format);
1071             break;
1072         case SMI_NODEKIND_ROW:
1073             incrIndexCounter(&metrics->indexTables, smiNode->indexkind);
1074             incrLengthCounter(&metrics->lengthRows,
1075                               smiNode->description, smiNode->reference,
1076                               smiNode->units, smiNode->format);
1077             incrLengthCounter(&metrics->lengthAll,
1078                               smiNode->description, smiNode->reference,
1079                               smiNode->units, smiNode->format);
1080             incrRowStatusCounter(smiNode);
1081             {
1082                 int cnt = 0;
1083                 foreachIndexDo(NULL, smiNode, count, &cnt);
1084                 incrIndexLenCounter(&metrics->indexLenTables, cnt);
1085                 foreachIndexDo(NULL, smiNode, yadayada, smiModule);
1086             }
1087             {
1088                 int cmplx = 0;
1089                 foreachIndexDo(NULL, smiNode, complexity, &cmplx);
1090                 incrIndexComplexityCounter(smiModule, smiNode, cmplx);
1091                 incrIndexComplexityMetric(&metrics->indexComplexity, cmplx);
1092             }
1093             /* count the childs ... */
1094             {
1095                     SmiModule *smiModule = smiGetModule("SNMPv2-TC");
1096                     SmiNode *childNode;
1097                     SmiType *rowStatus = smiGetType(smiModule, "RowStatus");
1098                     SmiType *storageType = smiGetType(smiModule, "StorageType");
1099                     /* include index elements not in table */
1100                     int n = 0;
1101                     for (childNode = smiGetFirstChildNode(smiNode);
1102                          childNode;
1103                          childNode = smiGetNextChildNode(childNode)) {
1104                             n++;
1105                             if (rowStatus == smiGetNodeType(childNode)) {
1106                                     fprintf(stderr, "**** GEEEEEE - ROWSTATUS\n");
1107                             }
1108                             if (storageType == smiGetNodeType(childNode)) {
1109                                     fprintf(stderr, "**** GEEEEEE - STORAGETYPE\n");
1110                             }
1111                     }
1112                     incrTableLenCounter(&metrics->tableLength, n);
1113             }
1114             break;
1115         case SMI_NODEKIND_COLUMN:
1116             incrBasetypeCounter(&metrics->basetypesColumns, smiNode);
1117             incrBasetypeCounter(&metrics->basetypesAll, smiNode);
1118             incrStatusCounter(&metrics->statusColumns, smiNode->status);
1119             incrStatusCounter(&metrics->statusAll, smiNode->status);
1120             incrAccessCounter(&metrics->accessColumns, smiNode->access);
1121             incrAccessCounter(&metrics->accessAll, smiNode->access);
1122             incrLengthCounter(&metrics->lengthColumns,
1123                               smiNode->description, smiNode->reference,
1124                               smiNode->units, smiNode->format);
1125             incrLengthCounter(&metrics->lengthAll,
1126                               smiNode->description, smiNode->reference,
1127                               smiNode->units, smiNode->format);
1128             incrTypeAndNodeUsageCounter(smiModule, smiNode, INCR_TYPE);
1129             break;
1130         case SMI_NODEKIND_SCALAR:
1131             incrBasetypeCounter(&metrics->basetypesScalars, smiNode);
1132             incrBasetypeCounter(&metrics->basetypesAll, smiNode);
1133             incrStatusCounter(&metrics->statusScalars, smiNode->status);
1134             incrStatusCounter(&metrics->statusAll, smiNode->status);
1135             incrAccessCounter(&metrics->accessScalars, smiNode->access);
1136             incrAccessCounter(&metrics->accessAll, smiNode->access);
1137             incrLengthCounter(&metrics->lengthScalars,
1138                               smiNode->description, smiNode->reference,
1139                               smiNode->units, smiNode->format);
1140             incrLengthCounter(&metrics->lengthAll,
1141                               smiNode->description, smiNode->reference,
1142                               smiNode->units, smiNode->format);
1143             incrTypeAndNodeUsageCounter(smiModule, smiNode, INCR_TYPE);
1144             break;
1145         case SMI_NODEKIND_NOTIFICATION:
1146             incrStatusCounter(&metrics->statusNotifications, smiNode->status);
1147             incrStatusCounter(&metrics->statusAll, smiNode->status);
1148             incrLengthCounter(&metrics->lengthNotifications,
1149                               smiNode->description, smiNode->reference,
1150                               smiNode->units, smiNode->format);
1151             incrLengthCounter(&metrics->lengthAll,
1152                               smiNode->description, smiNode->reference,
1153                               smiNode->units, smiNode->format);
1154             break;
1155         case SMI_NODEKIND_GROUP:
1156             incrStatusCounter(&metrics->statusGroups, smiNode->status);
1157             incrStatusCounter(&metrics->statusAll, smiNode->status);
1158             break;
1159         case SMI_NODEKIND_COMPLIANCE:
1160             incrStatusCounter(&metrics->statusCompliances, smiNode->status);
1161             incrStatusCounter(&metrics->statusAll, smiNode->status);
1162             break;
1163         }
1164     }
1165
1166     for (smiType = smiGetFirstType(smiModule);
1167          smiType;
1168          smiType = smiGetNextType(smiType)) {
1169
1170         /*
1171          * Ignore all types with empty descriptions coming from the
1172          * "SNMPv2-SMI" module since they are not really defined
1173          * types but part of the language itself.
1174          */
1175
1176         if (! smiType->description) {
1177             SmiModule *m = smiGetTypeModule(smiType);
1178             if (m && strcmp(m->name, "SNMPv2-SMI") == 0) {
1179                 continue;
1180             }
1181         }
1182     
1183         incrStatusCounter(&metrics->statusTypes, smiType->status);
1184         incrStatusCounter(&metrics->statusAll, smiType->status);
1185         incrLengthCounter(&metrics->lengthTypes,
1186                           smiType->description, smiType->reference,
1187                           smiType->units, smiType->format);
1188         incrLengthCounter(&metrics->lengthAll,
1189                           smiType->description, smiType->reference,
1190                           smiType->units, smiType->format);
1191     }
1192 }
1193
1194
1195
1196 static void
1197 fprintBasetypeCounter(FILE *f, BasetypeCounter *cnt, const char *s)
1198 {
1199     if (!s && ! cnt) {
1200         if (! silent) {
1201             fputs(
1202 "# The following table shows the basetype usage distribution in the\n"
1203 "# set of loaded MIB modules.\n"
1204 "\n", f);
1205         }
1206         fprintf(f, "%-10s Int32 Uns32 Int64 Uns64 OctSt ObjId Enums  Bits Flo32 Flo64 Flo128\n",
1207                 "CATEGORY");
1208         return;
1209     }
1210
1211     if (raw) {
1212         fprintf(f, "%-10s %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n", s,
1213                 cnt->integer32, cnt->unsigned32,
1214                 cnt->integer64, cnt->unsigned64,
1215                 cnt->octetstring, cnt->objectidentifier,
1216                 cnt->enums, cnt->bits,
1217                 cnt->float32, cnt->float64, cnt->float128);
1218     } else {
1219         fprintf(f, "%-10s %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%%\n", s,
1220                 cnt->total ? (double) cnt->integer32 * 100 / cnt->total : 0,
1221                 cnt->total ? (double) cnt->unsigned32 * 100 / cnt->total : 0,
1222                 cnt->total ? (double) cnt->integer64 * 100 / cnt->total : 0,
1223                 cnt->total ? (double) cnt->unsigned64 * 100 / cnt->total : 0,
1224                 cnt->total ? (double) cnt->octetstring * 100 / cnt->total : 0,
1225                 cnt->total ? (double) cnt->objectidentifier * 100 / cnt->total : 0,
1226                 cnt->total ? (double) cnt->enums * 100 / cnt->total : 0,
1227                 cnt->total ? (double) cnt->bits * 100 / cnt->total : 0,
1228                 cnt->total ? (double) cnt->float32 * 100 / cnt->total : 0,
1229                 cnt->total ? (double) cnt->float64 * 100 / cnt->total : 0,
1230                 cnt->total ? (double) cnt->float128 * 100 / cnt->total : 0);
1231     }
1232 }
1233
1234
1235
1236
1237 static void
1238 fprintStatusCounter(FILE *f, StatusCounter *cnt, char *s)
1239 {
1240     if (!s || !cnt) {
1241         if (! silent) {
1242             fputs(
1243 "# The following table shows the status distribution of various\n"
1244 "# definitions contained in the set of loaded MIB modules.\n"
1245 "\n", f);
1246         }
1247         fprintf(f, "%-14s %8s %8s %11s %9s\n", "CATEGORY",
1248                 "TOTAL", "CURRENT", "DEPRECATED", "OBSOLETE");
1249         return;
1250     }
1251
1252     if (raw) {
1253         fprintf(f, "%-14s %8lu %8lu %11lu %9lu\n", s,
1254                 cnt->total, cnt->current, cnt->deprecated, cnt->obsolete);
1255     } else {
1256         fprintf(f, "%-14s %8lu %7.1f%% %10.1f%% %8.1f%%\n", s,
1257                 cnt->total,
1258                 cnt->total ? (double) cnt->current * 100 / cnt->total : 0,
1259                 cnt->total ? (double) cnt->deprecated * 100 / cnt->total : 0,
1260                 cnt->total ? (double) cnt->obsolete * 100 / cnt->total : 0);
1261     }
1262 }
1263
1264
1265
1266 static void
1267 fprintAccessCounter(FILE *f, AccessCounter *cnt, char *s)
1268 {
1269     if (!s || !cnt) {
1270         if (! silent) {
1271             fputs(
1272 "# The following table shows the access mode distribution of all scalar\n"
1273 "# or column definitions contained in the set of loaded MIB modules.\n"
1274 "\n", f);
1275         }
1276         fprintf(f, "%-14s %8s %10s %9s %7s %8s\n", "CATEGORY",
1277                 "TOTAL", "READWRITE", "READONLY", "NOTIFY", "NOACCES");
1278         return;
1279     }
1280
1281     if (raw) {
1282         fprintf(f, "%-14s %8lu %10lu %9lu %7lu %8lu\n", s,
1283                 cnt->total, cnt->readwrite, cnt->readonly,
1284                 cnt->notify, cnt->noaccess);
1285     } else {
1286         fprintf(f, "%-14s %8lu %9.1f%% %8.1f%% %6.1f%% %7.1f%%\n", s,
1287                 cnt->total,
1288                 cnt->total ? (double) cnt->readwrite * 100 / cnt->total : 0,
1289                 cnt->total ? (double) cnt->readonly * 100 / cnt->total : 0,
1290                 cnt->total ? (double) cnt->notify * 100 / cnt->total : 0,
1291                 cnt->total ? (double) cnt->noaccess * 100 / cnt->total : 0);
1292     }
1293 }
1294
1295
1296
1297 static void
1298 fprintIndexCounter(FILE *f, IndexCounter *cnt, char *s)
1299 {
1300     if (! s || ! cnt) {
1301         if (! silent) {
1302             fputs(
1303 "# The following table shows the table index kind distribution of\n"
1304 "# table definitions contained in the set of loaded MIB modules.\n"
1305 "\n", f);
1306         fprintf(f, "%-14s %8s %8s %8s %8s %8s %8s\n", "CATEGORY",
1307                 "TOTAL", "INDEX", "AUGMENT", "REORDER", "SPARSE", "EXPAND");
1308         }
1309         return;
1310     }
1311     
1312     if (raw) {
1313         fprintf(f, "%-14s %8lu %8lu %8lu %8lu %8lu %8lu\n", s,
1314                 cnt->total, cnt->index, cnt->augment,
1315                 cnt->reorder, cnt->sparse, cnt->expand);
1316     } else {
1317         fprintf(f, "%-14s %8lu %7.1f%% %7.1f%% %7.1f%% %7.1f%% %7.1f%%\n", s,
1318                 cnt->total,
1319                 cnt->total ? (double) cnt->index * 100 / cnt->total : 0,
1320                 cnt->total ? (double) cnt->augment * 100 / cnt->total : 0,
1321                 cnt->total ? (double) cnt->reorder * 100 / cnt->total : 0,
1322                 cnt->total ? (double) cnt->sparse * 100 / cnt->total : 0,
1323                 cnt->total ? (double) cnt->expand * 100 / cnt->total : 0);
1324     }
1325 }
1326
1327
1328
1329 static void
1330 fprintIndexLenCounter(FILE *f, IndexLenCounter *cnt, char *s)
1331 {
1332     int i;
1333     int n = sizeof(cnt->length)/sizeof(cnt->length[0]);
1334     char buf[42];
1335     
1336     if (! s || ! cnt) {
1337         if (! silent) {
1338             fputs(
1339 "# The following table shows the table index length distribution of\n"
1340 "# table definitions contained in the set of loaded MIB modules.\n"
1341 "\n", f);
1342         }
1343         fprintf(f, "%-10s %6s ", "CATEGORY", "TOTAL");
1344         for (i = 1; i < n; i++) {
1345             sprintf(buf, "[%d]", i);
1346             fprintf(f, " %5s", buf);
1347         }
1348         fprintf(f, "\n");
1349         return;
1350     }
1351
1352     fprintf(f, "%-10s %6lu ", s, cnt->total);
1353     if (raw) {
1354         for (i = 1; i < n; i++) {
1355             fprintf(f, " %5lu", cnt->length[i]);
1356         }
1357     } else {
1358         for (i = 1; i < n; i++) {
1359             fprintf(f, " %4.1f%%", (double) cnt->length[i] * 100 / cnt->total);
1360         }
1361     }
1362     
1363     fprintf(f, "\n");
1364 }
1365
1366
1367
1368 static void
1369 fprintTableLenCounter(FILE *f, TableLenCounter *cnt, char *s)
1370 {
1371     int i;
1372     int n = sizeof(cnt->length)/sizeof(cnt->length[0]);
1373     char buf[42];
1374     
1375     if (! s || ! cnt) {
1376         if (! silent) {
1377             fputs(
1378 "# The following table shows the table length distribution of\n"
1379 "# table definitions contained in the set of loaded MIB modules.\n"
1380 "\n", f);
1381         }
1382         fprintf(f, "%-10s %6s ", "CATEGORY", "TOTAL");
1383         for (i = 1; i < n; i++) {
1384             sprintf(buf, "[%d]", i);
1385             fprintf(f, " %5s", buf);
1386         }
1387         fprintf(f, "\n");
1388         return;
1389     }
1390
1391     fprintf(f, "%-10s %6lu ", s, cnt->total);
1392     if (raw) {
1393         for (i = 1; i < n; i++) {
1394             fprintf(f, " %5lu", cnt->length[i]);
1395         }
1396     } else {
1397         for (i = 1; i < n; i++) {
1398             fprintf(f, " %4.1f%%", (double) cnt->length[i] * 100 / cnt->total);
1399         }
1400     }
1401     
1402     fprintf(f, "\n");
1403 }
1404
1405
1406
1407 static void
1408 fprintLengthCounter(FILE *f, LengthCounter *cnt, char *s)
1409 {
1410     if (! s) {
1411         if (! silent) {
1412             fputs(
1413 "# The following table shows the text clause usage distribution of all\n"
1414 "# definitions contained in the set of loaded MIB modules.\n"
1415 "\n", f);
1416         }
1417         fprintf(f, "%-14s %8s %12s %10s %8s %8s\n", "CATEGORY",
1418                 "TOTAL", "DESCRIPTION", "REFERENCE", "UNIT", "FORMAT");
1419         return;
1420     }
1421     
1422     if (raw) {
1423         fprintf(f, "%-14s %8lu %12lu %10lu %8lu %8lu\n", s,
1424                 cnt->total, cnt->descr, cnt->reference,
1425                 cnt->units, cnt->format);
1426     } else {
1427         fprintf(f, "%-14s %8lu %11.1f%% %9.1f%% %7.1f%% %7.1f%%\n", s,
1428                 cnt->total,
1429                 cnt->total ? (double) cnt->descr * 100 / cnt->total : 0,
1430                 cnt->total ? (double) cnt->reference * 100 / cnt->total : 0,
1431                 cnt->total ? (double) cnt->units * 100 / cnt->total : 0,
1432                 cnt->total ? (double) cnt->format * 100 / cnt->total : 0);
1433     }
1434 }
1435
1436
1437
1438 static void
1439 fprintLengthCounter2(FILE *f, LengthCounter *cnt, char *s)
1440 {
1441     if (! s) {
1442         if (! silent) {
1443             fprintf(f,
1444 "# The following table shows the %s text length distribution (in\n"
1445 "# bytes) of all definitions contained in the set of loaded MIB modules.\n"
1446 "\n", raw ? "total" : "average");
1447         }
1448         fprintf(f, "%-14s %8s %12s %10s %8s %8s\n", "CATEGORY",
1449                 "TOTAL", "DESCRIPTION", "REFERENCE", "UNIT", "FORMAT");
1450         return;
1451     }
1452     
1453     if (raw) {
1454         fprintf(f, "%-14s %8lu %12lu %10lu %8lu %8lu\n", s,
1455                 cnt->total, cnt->descr_len, cnt->reference_len,
1456                 cnt->units_len, cnt->format_len);
1457     } else {
1458         fprintf(f, "%-14s %8lu %12.1f %10.1f %8.1f %8.1f\n", s,
1459                 cnt->total,
1460                 cnt->descr ? (double) cnt->descr_len / cnt->descr : 0,
1461                 cnt->reference ? (double) cnt->reference_len / cnt->reference : 0,
1462                 cnt->units ? (double) cnt->units_len / cnt->units : 0,
1463                 cnt->format ? (double) cnt->format_len / cnt->format : 0);
1464     }
1465 }
1466
1467
1468
1469 static void
1470 fprintfComplexity(FILE *f, Metrics *metrics)
1471 {
1472     unsigned long cmplx = 0, fctrs = 0;
1473     unsigned long total_cmplx = 0, total_fctrs = 0;
1474
1475     if (! silent) {
1476         fputs(
1477 "# The following table shows the complexity metrics of the set of loaded\n"
1478 "# MIB modules.\n"
1479 "\n", f);
1480     }
1481     fprintf(f, "%-14s %8s %8s %8s %8s\n", "CATEGORY", "TOTAL",
1482             "RAW", "WEIGHT", "COMPLEXITY");
1483     
1484     cmplx = metrics->accessScalars.readonly  * 1;
1485     fctrs = metrics->accessScalars.readonly;
1486     fprintf(f, "%-14s %8lu %8lu\n", "Scalars (ro):", fctrs, cmplx);
1487     total_cmplx += cmplx;
1488     total_fctrs += fctrs;
1489             
1490     cmplx = metrics->accessScalars.readwrite * 2;
1491     fctrs = metrics->accessScalars.readwrite;
1492     fprintf(f, "%-14s %8lu %8lu\n", "Scalars (rw):", fctrs, cmplx);
1493     total_cmplx += cmplx;
1494     total_fctrs += fctrs;
1495
1496     cmplx = metrics->accessColumns.readonly * 2;
1497     fctrs = metrics->accessColumns.readonly;
1498     fprintf(f, "%-14s %8lu %8lu\n", "Columns (ro):", fctrs, cmplx);
1499     total_cmplx += cmplx;
1500     total_fctrs += fctrs;
1501
1502     cmplx = metrics->accessColumns.readwrite * 3;
1503     fctrs = metrics->accessColumns.readwrite;
1504     fprintf(f, "%-14s %8lu %8lu\n", "Columns (rw):", fctrs, cmplx);
1505     total_cmplx += cmplx;
1506     total_fctrs += fctrs;
1507
1508     /* readcreate tables ? */
1509
1510     /* table index complexity ? */
1511
1512     {
1513         int i;
1514         cmplx = 0;
1515         for (i = 0; i < 100; i++) {
1516             cmplx += 3 * i * metrics->indexComplexity.complexity[i];
1517         }
1518         fprintf(f, "%-14s %8lu %8lu\n", "Indexes:", metrics->indexComplexity.total, cmplx);
1519     }
1520
1521     fprintf(f, "%-14s %8lu %8lu\n", "Summary:", total_fctrs, total_cmplx);
1522 }
1523
1524
1525
1526 static void
1527 fprintMetrics(FILE *f, Metrics *metrics)
1528 {
1529     fprintStatusCounter(f, NULL, NULL);
1530     fprintStatusCounter(f, &metrics->statusTypes, "Types:");
1531     fprintStatusCounter(f, &metrics->statusTables, "Tables:");
1532     fprintStatusCounter(f, &metrics->statusColumns, "Columns:");
1533     fprintStatusCounter(f, &metrics->statusScalars, "Scalars:");
1534     fprintStatusCounter(f, &metrics->statusNotifications, "Notifications:");
1535     fprintStatusCounter(f, &metrics->statusGroups, "Groups:");
1536     fprintStatusCounter(f, &metrics->statusCompliances, "Compliances:");
1537     fprintStatusCounter(f, &metrics->statusAll, "Summary:");
1538     fprintf(f, "\n");
1539     fprintAccessCounter(f, NULL, NULL);
1540     fprintAccessCounter(f, &metrics->accessColumns, "Columns:");
1541     fprintAccessCounter(f, &metrics->accessScalars, "Scalars:");
1542     fprintAccessCounter(f, &metrics->accessAll, "Summary:");
1543     fprintf(f, "\n");
1544     fprintIndexCounter(f, NULL, NULL);
1545     fprintIndexCounter(f, &metrics->indexTables, "Tables:");
1546     fprintf(f, "\n");
1547     fprintIndexLenCounter(f, NULL, NULL);
1548     fprintIndexLenCounter(f, &metrics->indexLenTables, "Tables:");
1549     fprintf(f, "\n");
1550     fprintTableLenCounter(f, NULL, NULL);
1551     fprintTableLenCounter(f, &metrics->tableLength, "Tables:");
1552     fprintf(f, "\n");
1553     fprintLengthCounter(f, NULL, NULL);
1554     fprintLengthCounter(f, &metrics->lengthTypes, "Types:");
1555     fprintLengthCounter(f, &metrics->lengthTables, "Tables:");
1556     fprintLengthCounter(f, &metrics->lengthColumns, "Columns:");
1557     fprintLengthCounter(f, &metrics->lengthScalars, "Scalars:");
1558     fprintLengthCounter(f, &metrics->lengthNotifications, "Notifications:");
1559     fprintLengthCounter(f, &metrics->lengthAll, "Summary:");
1560     fprintf(f, "\n");
1561     fprintLengthCounter2(f, NULL, NULL);
1562     fprintLengthCounter2(f, &metrics->lengthTypes, "Types:");
1563     fprintLengthCounter2(f, &metrics->lengthTables, "Tables:");
1564     fprintLengthCounter2(f, &metrics->lengthColumns, "Columns:");
1565     fprintLengthCounter2(f, &metrics->lengthScalars, "Scalars:");
1566     fprintLengthCounter2(f, &metrics->lengthNotifications, "Notifications:");
1567     fprintLengthCounter2(f, &metrics->lengthAll, "Summary:");
1568     fprintf(f, "\n");
1569     fprintBasetypeCounter(f, NULL, NULL);
1570     fprintBasetypeCounter(f, &metrics->basetypesColumns, "Columns:");
1571     fprintBasetypeCounter(f, &metrics->basetypesScalars, "Scalars:");
1572     fprintBasetypeCounter(f, &metrics->basetypesAll, "Summary:");
1573     fprintf(f, "\n");
1574     fprintfComplexity(f, metrics);
1575     fprintf(f, "\n");
1576     fprintTypeUsage(f, typeList);
1577     freeUsageCounter(typeList), typeList = NULL;
1578     fprintf(f, "\n");
1579     fprintExtTypeUsage(f, extTypeList);
1580     freeUsageCounter(extTypeList), extTypeList = NULL;
1581     fprintf(f, "\n");
1582     fprintExtNodeUsage(f, extNodeList);
1583     freeUsageCounter(extNodeList), extNodeList = NULL;
1584     fprintf(f, "\n");
1585     fprintModuleUsage(f, extModuleList);
1586     freeUsageCounter(extModuleList), extModuleList = NULL;
1587     fprintf(f, "\n");
1588     fprintIndexComplexity(f, indexComplexityList);
1589     freeUsageCounter(indexComplexityList), indexComplexityList = NULL;
1590     fprintf(f, "\n");
1591 }
1592
1593
1594
1595 static void
1596 dumpMetrics(int modc, SmiModule **modv, int flags, char *output)
1597 {
1598     Metrics   metrics;
1599     int       i;
1600     FILE      *f = stdout;
1601
1602     silent = (flags & SMIDUMP_FLAG_SILENT);
1603
1604     if (output) {
1605         f = fopen(output, "w");
1606         if (!f) {
1607             fprintf(stderr, "smidump: cannot open %s for writing: ", output);
1608             perror(NULL);
1609             exit(1);
1610         }
1611     }
1612
1613     if (flags & SMIDUMP_FLAG_UNITE) {
1614         if (! silent) {
1615             int pos = 8888;
1616             fprintf(f, "# united module metrics [%d modules] "
1617                     "(generated by smidump " SMI_VERSION_STRING ")\n", modc);
1618             fprintf(f, "#\n# smidump -u -f metrics");
1619             if (raw) fprintf(f, " --metrics-raw");
1620             for (i = 0; i < modc; i++) {
1621                 int len = strlen(modv[i]->name);
1622                 if (pos + len > 70) {
1623                     fprintf(f, " \\\n#\t"), pos = 8;
1624                 }
1625                 fprintf(f, "%s ", modv[i]->name);
1626                 pos += len + 1;
1627             }
1628             fprintf(f, "%s\n", (pos == 8) ? "" : "\n");
1629         }
1630
1631         fprintRevision(f, modc, modv);
1632             
1633         for (i = 0; i < modc; i++) {
1634             memset(&metrics, 0, sizeof(Metrics));
1635         }
1636         for (i = 0; i < modc; i++) {
1637             addMetrics(&metrics, modv[i]);
1638         }
1639         fprintMetrics(f, &metrics);
1640     } else {
1641         for (i = 0; i < modc; i++) {
1642             if (! silent) {
1643                 fprintf(f, "# %s module metrics (generated by smidump "
1644                         SMI_VERSION_STRING ")\n\n", modv[i]->name);
1645             }
1646
1647             fprintRevision(f, 1, modv+i);
1648     
1649             memset(&metrics, 0, sizeof(Metrics));
1650             addMetrics(&metrics, modv[i]);
1651             fprintMetrics(f, &metrics);
1652         }
1653     }
1654
1655     if (fflush(f) || ferror(f)) {
1656         perror("smidump: write error");
1657         exit(1);
1658     }
1659
1660     if (output) {
1661         fclose(f);
1662     }
1663 }
1664
1665
1666
1667 void
1668 initMetrics()
1669 {
1670     static SmidumpDriverOption opt[] = {
1671         { "raw", OPT_FLAG, &raw, 0,
1672           "generate raw statistics (no percentages)"},
1673         { 0, OPT_END, 0, 0 }
1674     };
1675
1676     static SmidumpDriver driver = {
1677         "metrics",
1678         dumpMetrics,
1679         0,
1680         0,
1681         "metrics characterizing MIB modules",
1682         opt,
1683         NULL
1684     };
1685     
1686     smidumpRegisterDriver(&driver);
1687 }