Imported Upstream version 0.4.8
[platform/upstream/libsmi.git] / tools / dump-scli.c
1 /*
2  * dump-scli.c --
3  *
4  *      Operations to generate MIB module stubs for the scli package.
5  *
6  * Copyright (c) 2001 J. Schoenwaelder, Technical University of Braunschweig.
7  * Copyright (c) 2002 J. Schoenwaelder, University of Osnabrueck.
8  * Copyright (c) 2004 J. Schoenwaelder, International University Bremen.
9  *
10  * See the file "COPYING" for information on usage and redistribution
11  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12  *
13  * @(#) $Id: dump-scli.c 8090 2008-04-18 12:56:29Z strauss $
14  */
15
16 /*
17  * TODO:
18  *        - range checks for 64 bit numbers
19  */
20
21 #include <config.h>
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <ctype.h>
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #ifdef HAVE_WIN_H
31 #include "win.h"
32 #endif
33
34 #include "smi.h"
35 #include "smidump.h"
36
37
38 #include <sys/types.h>
39
40 #ifdef HAVE_REGEX_H
41 #include <regex.h>
42 #else
43 #define regex_t int
44 #define regcomp(a, b, c)        1
45 #define regexec(a, b, c, d, e)  0
46 #define regerror(a,b,c,d)       strncpy(c, "regex not supported", d)
47 #define regfree(a)
48 #endif
49
50 static char *prefix = NULL;
51 static char *include = NULL;
52 static char *exclude = NULL;
53 static int  sflag = 0;
54 static int  cflag = 0;
55 static int  dflag = 0;
56 static regex_t _incl_regex, *incl_regex = NULL;
57 static regex_t _excl_regex, *excl_regex = NULL;
58
59 static char *keywords_c99[] = {
60     "auto",        "enum",        "restrict",    "unsigned",
61     "break",       "extern",      "return",      "void",
62     "case",        "float",       "short",       "volatile",
63     "char",        "for",         "signed",      "while",
64     "const",       "goto",        "sizeof",      "_Bool",
65     "continue",    "if",          "static",      "_Complex",
66     "default",     "inline",      "struct",      "_Imaginary",
67     "do",          "int",         "switch",
68     "double",      "long",        "typedef",
69     "else",        "register",    "union",
70     NULL
71 };
72
73
74
75 static int
76 isKeyword(char *m)
77 {
78     int i;
79     
80     for (i = 0; keywords_c99[i]; i++) {
81         if (strcmp(m, keywords_c99[i]) == 0) {
82             return 1;
83         }
84     }
85     return 0;
86 }
87
88
89
90 static char *
91 getStringTime(time_t t)
92 {
93     static char   s[27];
94     struct tm     *tm;
95
96     tm = gmtime(&t);
97     sprintf(s, "%04d-%02d-%02d %02d:%02d",
98             tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
99             tm->tm_hour, tm->tm_min);
100     return s;
101 }
102
103
104
105 static void
106 fprintCommentString(FILE *f, char *s)
107 {
108     int i, len;
109
110     if (s) {
111         fprintf(f, " *   ");
112         len = strlen(s);
113         for (i = 0; i < len; i++) {
114             fputc(s[i], f);
115             if (s[i] == '\n') {
116                 fprintf(f, " *   ");
117             }
118         }
119         fputc('\n', f);
120     }
121 }
122
123
124
125 static void
126 fprintTopComment(FILE *f, SmiModule *smiModule)
127 {
128     SmiRevision *smiRevision;
129     char *date;
130
131     fprintf(f,
132             "/* \t\t\t\t\t\t-- DO NOT EDIT --\n"
133             " * Generated by smidump version " SMI_VERSION_STRING ":\n");
134
135     fprintf(f, " *   smidump -f scli");
136     if (sflag) {
137         fprintf(f, " --scli-set");
138     }
139     if (cflag) {
140         fprintf(f, " --scli-create");
141     }
142     if (dflag) {
143         fprintf(f, " --scli-delete");
144     }
145     if (prefix) {
146         fprintf(f, " \\\n *     --scli-prefix='%s'", prefix);
147     }
148     if (include) {
149         fprintf(f, " \\\n *     --scli-include='%s'", include);
150     }
151     if (exclude) {
152         fprintf(f, " \\\n *     --scli-exclude='%s'", exclude);
153     }
154     fprintf(f, " %s\n *\n", smiModule->name);
155
156     fprintf(f,
157             " * Derived from %s:\n", smiModule->name);
158     fprintCommentString(f, smiModule->description);
159
160     for (smiRevision = smiGetFirstRevision(smiModule);
161          smiRevision;
162          smiRevision = smiGetNextRevision(smiRevision)) {
163         date = getStringTime(smiRevision->date);
164         fprintf(f,
165                 " *\n"
166                 " * Revision %s:\n", date);
167         fprintCommentString(f, smiRevision->description);
168     }
169
170 #if 0
171     if (smiModule->organization || smiModule->contactinfo) {
172         fprintf(f, " *\n * Contact:\n");
173         printCommentString(f, smiModule->organization);
174         fprintf(f, " *\n");
175         printCommentString(f, smiModule->contactinfo);
176     }
177 #endif
178
179     fprintf(f,
180             " *\n * $I" "d$\n"
181             " */\n"
182             "\n");
183 }
184
185
186
187 static char*
188 translate(char *m)
189 {
190     char *s;
191     int i;
192
193     s = xstrdup(m);
194     for (i = 0; s[i]; i++) {
195         if (s[i] == '-') s[i] = '_';
196     }
197   
198     while (isKeyword(s)) {
199         s = xrealloc(s, strlen(s) + 2);
200         strcat(s, "_");
201     }
202     
203     return s;
204 }
205
206
207
208 static char*
209 translateUpper(char *m)
210 {
211     char *s;
212     int i;
213
214     s = xstrdup(m);
215     for (i = 0; s[i]; i++) {
216         if (s[i] == '-') s[i] = '_';
217         if (islower((int) s[i])) {
218             s[i] = toupper(s[i]);
219         }
220     }
221   
222     while (isKeyword(s)) {
223         s = xrealloc(s, strlen(s) + 2);
224         strcat(s, "_");
225     }
226     
227     return s;
228 }
229
230
231
232 static char*
233 translateLower(char *m)
234 {
235     char *s;
236     int i;
237
238     s = xstrdup(m);
239     for (i = 0; s[i]; i++) {
240         if (s[i] == '-') s[i] = '_';
241         if (isupper((int) s[i])) {
242             s[i] = tolower(s[i]);
243         }
244     }
245   
246     while (isKeyword(s)) {
247         s = xrealloc(s, strlen(s) + 2);
248         strcat(s, "_");
249     }
250     
251     return s;
252 }
253
254
255
256 static char*
257 translateFileName(char *m)
258 {
259     char *s;
260     int i;
261
262     s = xstrdup(m);
263     for (i = 0; s[i]; i++) {
264         if (s[i] == '_') s[i] = '-';
265         if (isupper((int) s[i])) {
266             s[i] = tolower(s[i]);
267         }
268     }
269   
270     return s;
271 }
272
273
274
275 static FILE *
276 createFile(char *name, char *suffix)
277 {
278     char *fullname;
279     FILE *f;
280
281     fullname = xmalloc(strlen(name) + (suffix ? strlen(suffix) : 0) + 2);
282     strcpy(fullname, name);
283     if (suffix) {
284         strcat(fullname, suffix);
285     }
286     if (!access(fullname, R_OK)) {
287         fprintf(stderr, "smidump: %s already exists\n", fullname);
288         xfree(fullname);
289         return NULL;
290     }
291     f = fopen(fullname, "w");
292     if (!f) {
293         fprintf(stderr, "smidump: cannot open %s for writing: ", fullname);
294         perror(NULL);
295         xfree(fullname);
296         exit(1);
297     }
298     xfree(fullname);
299     return f;
300 }
301
302
303
304 static int
305 isGroup(SmiNode *smiNode, SmiNodekind memberkind)
306 {
307     SmiNode *childNode;
308     int status;
309
310     if (incl_regex) {
311         if (! smiNode->name) {
312             return 0;
313         }
314         status = regexec(incl_regex, smiNode->name, (size_t) 0, NULL, 0);
315         if (status != 0) {
316             return 0;
317         }
318     }
319
320     if (excl_regex) {
321         if (! smiNode->name) {
322             return 0;
323         }
324         status = regexec(excl_regex, smiNode->name, (size_t) 0, NULL, 0);
325         if (status == 0) {
326             return 0;
327         }
328     }
329     
330     for (childNode = smiGetFirstChildNode(smiNode);
331          childNode;
332          childNode = smiGetNextChildNode(childNode)) {
333         if (childNode->nodekind & memberkind) {
334             return 1;
335         }
336     }
337
338     return 0;
339 }
340
341
342
343 static int
344 isAccessible(SmiNode *groupNode)
345 {
346     SmiNode *smiNode;
347     int num = 0;
348     
349     for (smiNode = smiGetFirstChildNode(groupNode);
350          smiNode;
351          smiNode = smiGetNextChildNode(smiNode)) {
352         if ((smiNode->nodekind == SMI_NODEKIND_SCALAR
353              || smiNode->nodekind == SMI_NODEKIND_COLUMN)
354             && (smiNode->access == SMI_ACCESS_READ_ONLY
355                 || smiNode->access == SMI_ACCESS_READ_WRITE)) {
356             num++;
357         }
358     }
359
360     return num;
361 }
362
363
364
365 static int
366 isIndex(SmiNode *groupNode, SmiNode *smiNode)
367 {
368     SmiElement *smiElement;
369     
370     /*
371      * Perhaps this test needs to be more sophisticated if you have
372      * really creative cross-table indexing constructions...
373      */
374
375     for (smiElement = smiGetFirstElement(groupNode);
376          smiElement; smiElement = smiGetNextElement(smiElement)) {
377         if (smiNode == smiGetElementNode(smiElement)) {
378             return 1;
379         }
380     }
381
382     return 0;
383 }
384
385
386
387 static int
388 isWritable(SmiNode *treeNode, SmiNodekind nodekind)
389 {
390     SmiNode *smiNode;
391     
392     for (smiNode = smiGetFirstChildNode(treeNode);
393          smiNode;
394          smiNode = smiGetNextChildNode(smiNode)) {
395         if (smiNode->nodekind & (nodekind)
396             && (smiNode->access >= SMI_ACCESS_READ_WRITE)) {
397             break;
398         }
399     }
400
401     return (smiNode != NULL);
402 }
403
404
405
406 static char*
407 getSnmpType(SmiType *smiType)
408 {
409     struct {
410         char *module;
411         char *name;
412         char *tag;
413     } typemap[] = {
414         { "RFC1155-SMI","Counter",      "GNET_SNMP_VARBIND_TYPE_COUNTER32" },
415         { "SNMPv2-SMI", "Counter32",    "GNET_SNMP_VARBIND_TYPE_COUNTER32" },
416         { "RFC1155-SMI","TimeTicks",    "GNET_SNMP_VARBIND_TYPE_TIMETICKS" },
417         { "SNMPv2-SMI", "TimeTicks",    "GNET_SNMP_VARBIND_TYPE_TIMETICKS" },
418         { "RFC1155-SMI","Opaque",       "GNET_SNMP_VARBIND_TYPE_OPAQUE" },
419         { "SNMPv2-SMI", "Opaque",       "GNET_SNMP_VARBIND_TYPE_OPAQUE" },
420         { "RFC1155-SMI","IpAddress",    "GNET_SNMP_VARBIND_TYPE_IPADDRESS" },
421         { "SNMPv2-SMI", "IpAddress",    "GNET_SNMP_VARBIND_TYPE_IPADDRESS" },
422         { NULL, NULL, NULL }
423     };
424
425     SmiBasetype basetype = smiType->basetype;
426     
427     do {
428         int i;
429         for (i = 0; typemap[i].name; i++) {
430             if (smiType->name
431                 && (strcmp(smiType->name, typemap[i].name) == 0)) {
432                 return typemap[i].tag;
433             }
434         }
435     } while ((smiType = smiGetParentType(smiType)));
436
437     switch (basetype) {
438     case SMI_BASETYPE_INTEGER32:
439     case SMI_BASETYPE_ENUM:
440         return "GNET_SNMP_VARBIND_TYPE_INTEGER32";
441     case SMI_BASETYPE_UNSIGNED32:
442         return "GNET_SNMP_VARBIND_TYPE_UNSIGNED32";
443     case SMI_BASETYPE_INTEGER64:
444         return NULL;
445     case SMI_BASETYPE_UNSIGNED64:
446         return "GNET_SNMP_VARBIND_TYPE_COUNTER64";
447     case SMI_BASETYPE_OCTETSTRING:
448         return "GNET_SNMP_VARBIND_TYPE_OCTETSTRING";
449     case SMI_BASETYPE_BITS:
450         return "GNET_SNMP_VARBIND_TYPE_OCTETSTRING";
451     case SMI_BASETYPE_OBJECTIDENTIFIER:
452         return "GNET_SNMP_VARBIND_TYPE_OBJECTID";
453     case SMI_BASETYPE_FLOAT32:
454     case SMI_BASETYPE_FLOAT64:
455     case SMI_BASETYPE_FLOAT128:
456         return NULL;
457     case SMI_BASETYPE_UNKNOWN:
458         return NULL;
459     case SMI_BASETYPE_POINTER:
460         return NULL;
461     }
462     return NULL;
463 }
464
465
466
467 typedef void    (*ForEachIndexFunc)     (FILE *f, SmiNode *groupNode, SmiNode *smiNode, int flags, int maxlen, char *name);
468
469
470 /*
471  * Check whether we have duplicate nodes in the INDEX.  If yes,
472  * generate a unique name.
473  */
474
475 static char*
476 getIndexName(SmiNode *indexNode, SmiNode *iNode, SmiElement *smiElement)
477 {
478     SmiElement *se;
479     SmiNode *sn;
480     int n = 0, m = 0, tail = 0;
481     char *name;
482     
483     for (se = smiGetFirstElement(indexNode);
484          se; se = smiGetNextElement(se)) {
485         sn = smiGetElementNode(se);
486         if (strcmp(sn->name, iNode->name) == 0) {
487             n++;
488             if (! tail) m++;
489         }
490         if (se == smiElement) tail = 1;
491     }
492     if (n > 1) {
493         smiAsprintf(&name, "%s%d", iNode->name, m);
494     } else {
495         name = xstrdup(iNode->name);
496     }
497     return name;
498 }
499
500
501 static void
502 foreachIndexDo(FILE *f, SmiNode *smiNode, ForEachIndexFunc func,
503                int flags, int maxlen)
504 {
505     SmiNode *indexNode = NULL, *iNode;
506     SmiElement *smiElement;
507     
508     switch (smiNode->indexkind) {
509     case SMI_INDEX_INDEX:
510     case SMI_INDEX_REORDER:
511         indexNode = smiNode;
512         break;
513     case SMI_INDEX_EXPAND:      /* TODO: we have to do more work here! */
514         break;
515     case SMI_INDEX_AUGMENT:
516     case SMI_INDEX_SPARSE:
517         indexNode = smiGetRelatedNode(smiNode);
518         break;
519     case SMI_INDEX_UNKNOWN:
520         break;
521     }
522     if (indexNode) {
523         for (smiElement = smiGetFirstElement(indexNode);
524              smiElement; smiElement = smiGetNextElement(smiElement)) {
525             iNode = smiGetElementNode(smiElement);
526             if (iNode) {
527                 char *name = getIndexName(indexNode, iNode, smiElement);
528                 (func) (f, smiNode, iNode, flags, maxlen, name);
529                 if (name) xfree(name);
530             }
531         }
532     }
533 }
534
535
536
537 static void
538 printIndexParamsFunc(FILE *f, SmiNode *smiNode, SmiNode *iNode,
539                      int flags, int maxlen, char *name)
540 {
541     SmiType *iType;
542     char *cName;
543     unsigned minSize, maxSize;
544
545     iType = smiGetNodeType(iNode);
546     if (! iType) {
547         return;
548     }
549
550     cName = translate(name ? name : iNode->name);
551     switch (iType->basetype) {
552     case SMI_BASETYPE_OBJECTIDENTIFIER:
553         maxSize = smiGetMaxSize(iType);
554         minSize = smiGetMinSize(iType);
555         fprintf(f, ", %s%s", flags ? "guint32 *" : "", cName);
556         if (minSize != maxSize) {
557             fprintf(f, ", %s_%sLength",
558                     flags ? "guint16 " : "", cName);
559         }
560         break;
561     case SMI_BASETYPE_OCTETSTRING:
562     case SMI_BASETYPE_BITS:
563         maxSize = smiGetMaxSize(iType);
564         minSize = smiGetMinSize(iType);
565         fprintf(f, ", %s%s", flags ? "guchar *" : "", cName);
566         if (minSize != maxSize) {
567             fprintf(f, ", %s_%sLength",
568                     flags ? "guint16 " : "", cName);
569         }
570         break;
571     case SMI_BASETYPE_ENUM:
572     case SMI_BASETYPE_INTEGER32:
573         fprintf(f, ", %s%s", flags ? "gint32 " : "", cName);
574         break;
575     case SMI_BASETYPE_UNSIGNED32:
576         fprintf(f, ", %s%s", flags ? "guint32 " : "", cName);
577         break;
578     default:
579         fprintf(f, "/* ?? %s */", cName);
580         break;
581     }
582     xfree(cName);
583 }
584
585
586
587 static void
588 printIndexParamsPassFunc(FILE *f, SmiNode *smiNode, SmiNode *iNode,
589                          int flags, int maxlen, char *name)
590 {
591     SmiType *iType;
592     char *cName, *gName;
593     unsigned minSize, maxSize;
594
595     iType = smiGetNodeType(iNode);
596     if (! iType) {
597         return;
598     }
599
600     gName = translate(smiNode->name);
601     cName = translate(iNode->name);
602     fprintf(f, ", %s->%s", gName, cName);
603     switch (iType->basetype) {
604     case SMI_BASETYPE_BITS:
605     case SMI_BASETYPE_OCTETSTRING:
606     case SMI_BASETYPE_OBJECTIDENTIFIER:
607         maxSize = smiGetMaxSize(iType);
608         minSize = smiGetMinSize(iType);
609         if (minSize != maxSize) {
610             fprintf(f, ", %s->_%sLength", gName, cName);
611         }
612         break;
613     default:
614         break;
615     }
616     xfree(cName);
617     xfree(gName);
618 }
619
620
621
622 static void
623 printIndexAssignmentFunc(FILE *f, SmiNode *smiNode, SmiNode *iNode,
624                          int flags, int maxlen, char *name)
625 {
626     SmiType *iType;
627     char *cName, *gName, *dName, *dModuleName;
628     unsigned minSize, maxSize;
629
630     iType = smiGetNodeType(iNode);
631     if (! iType) {
632         return;
633     }
634
635     gName = translate(smiNode->name);
636     cName = translate(iNode->name);
637     dName = translateUpper(iNode->name);
638     dModuleName = translateUpper(smiGetNodeModule(iNode)->name);
639     switch (iType->basetype) {
640     case SMI_BASETYPE_OBJECTIDENTIFIER:
641         fprintf(f, "    memcpy(%s->%s, %s, _%sLength * sizeof(guint32));\n",
642             gName, cName, cName, cName);
643         break;
644     case SMI_BASETYPE_OCTETSTRING:
645     case SMI_BASETYPE_BITS:
646         maxSize = smiGetMaxSize(iType);
647         minSize = smiGetMinSize(iType);
648         if (minSize != maxSize) {
649             fprintf(f, "    memcpy(%s->%s, %s, _%sLength);\n",
650                     gName, cName, cName, cName);
651         } else {
652             fprintf(f, "    memcpy(%s->%s, %s, %s_%sLENGTH);\n",
653                     gName, cName, cName, dModuleName, dName);
654         }
655         break;
656     case SMI_BASETYPE_ENUM:
657     case SMI_BASETYPE_INTEGER32:
658     case SMI_BASETYPE_UNSIGNED32:
659         fprintf(f, "    %s->%s = %s;\n",
660                 gName, cName, cName);
661         break;
662     default:
663         fprintf(f, "    /* ?? %s */\n", cName);
664         break;
665     }
666     xfree(dModuleName);
667     xfree(dName);
668     xfree(cName);
669     xfree(gName);
670 }
671
672
673
674 static void
675 printHeaderEnumeration(FILE *f, SmiModule *smiModule,
676                        SmiNode * smiNode, SmiType *smiType)
677 {
678     SmiNamedNumber *nn;
679     char *cName, *cPrefix;
680     char *dName, *dModuleName;
681     char *name;
682     int len;
683
684     if (smiType && smiType->name) {
685         name = smiType->name;
686     } else if (smiNode && smiNode->name) {
687         name = smiNode->name;
688     } else {
689         return;
690     }
691
692     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
693     dModuleName = translateUpper(smiModule->name);
694     cName = translate(name);
695     dName = translateUpper(name);
696     
697     for (len = 0, nn = smiGetFirstNamedNumber(smiType); nn;
698          nn = smiGetNextNamedNumber(nn)) {
699         if (len < strlen(nn->name)) {
700             len = strlen(nn->name);
701         }
702     }
703     for (nn = smiGetFirstNamedNumber(smiType); nn;
704                  nn = smiGetNextNamedNumber(nn)) {
705         char *dEnum = translateUpper(nn->name);
706         fprintf(f, "#define %s_%s_%-*s %d\n",
707                 dModuleName, dName, len, dEnum,
708                 (int) nn->value.value.integer32);
709         xfree(dEnum);
710     }
711     fprintf(f, "\nextern GNetSnmpEnum const %s_enums_%s[];\n\n",
712             cPrefix, cName);
713     
714     xfree(dName);
715     xfree(cName);
716     xfree(dModuleName);
717     xfree(cPrefix);
718 }
719
720
721
722 static void
723 printHeaderEnumerations(FILE *f, SmiModule *smiModule)
724 {
725     SmiNode  *smiNode, *parentNode;
726     SmiType  *smiType;
727     int      cnt = 0;
728     const unsigned int groupkind = SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN;
729
730     const char *header =
731         "/*\n"
732         " * Tables to map enumerations to strings and vice versa.\n"
733         " */\n"
734         "\n";
735
736     for (smiNode = smiGetFirstNode(smiModule, groupkind);
737          smiNode;
738          smiNode = smiGetNextNode(smiNode, groupkind)) {
739         parentNode = smiGetParentNode(smiNode);
740         if (! parentNode || ! isGroup(parentNode, groupkind)) {
741             continue;
742         }
743         smiType = smiGetNodeType(smiNode);
744         if (smiType && !smiType->name
745             && smiType->basetype == SMI_BASETYPE_ENUM
746             && smiGetTypeModule(smiType) == smiModule) {
747             if (! cnt) {
748                 fputs(header, f);
749             }
750             cnt++;
751             printHeaderEnumeration(f, smiModule, smiNode, smiType);
752         }
753     }
754
755     for (smiType = smiGetFirstType(smiModule);
756          smiType;
757          smiType = smiGetNextType(smiType)) {
758         if (smiType->basetype == SMI_BASETYPE_ENUM
759             && smiGetTypeModule(smiType) == smiModule) {
760             if (! cnt) {
761                 fputs(header, f);
762             }
763             cnt++;
764             printHeaderEnumeration(f, smiModule, NULL, smiType);
765         }
766     }
767     
768     if (cnt) {
769         fprintf(f, "\n");
770     }
771 }
772
773
774
775 static void
776 printHeaderIdentities(FILE *f, SmiModule *smiModule)
777 {
778     SmiNode      *smiNode, *moduleIdentityNode, *parentNode;
779     int          cnt = 0;
780     unsigned int i;
781     char         *dName, *dModuleName;
782     char         *cModuleName;
783
784     moduleIdentityNode = smiGetModuleIdentityNode(smiModule);
785     
786     dModuleName = translateUpper(smiModule->name);
787
788     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_NODE);
789          smiNode;
790          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_NODE)) {
791         parentNode = smiGetParentNode(smiNode);
792         if (! parentNode || ! isGroup(parentNode, SMI_NODEKIND_NODE)) {
793             continue;
794         }
795         if (smiNode->status == SMI_STATUS_UNKNOWN) {
796             continue;
797         }
798         if (smiNode == moduleIdentityNode) {
799             continue;
800         }
801         if (! cnt) {
802             fprintf(f,
803                     "/*\n"
804                     " * Tables to map identities to strings and vice versa.\n"
805                     " */\n"
806                     "\n");
807         }
808         cnt++;
809         dName = translateUpper(smiNode->name);
810         fprintf(f, "#define %s_%s\t", dModuleName, dName);
811         for (i = 0; i < smiNode->oidlen; i++) {
812             fprintf(f, "%s%u", i ? "," : "", smiNode->oid[i]);
813         }
814         fprintf(f, "\n");
815         xfree(dName);
816     }
817     
818     if (cnt) {
819         cModuleName = translateLower(smiModule->name);
820         fprintf(f,
821                 "\n"
822                 "extern GNetSnmpIdentity const %s_identities[];\n"
823                 "\n",
824                 cModuleName);
825         xfree(cModuleName);
826     }
827
828     xfree(dModuleName);
829 }
830
831
832
833 static void
834 printHeaderNotifications(FILE *f, SmiModule *smiModule)
835 {
836     SmiNode      *smiNode;
837     int          cnt = 0;
838     unsigned int i;
839     char         *dName, *dModuleName;
840     char         *cModuleName;
841
842     dModuleName = translateUpper(smiModule->name);
843
844     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_NOTIFICATION);
845          smiNode;
846          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_NOTIFICATION)) {
847         if (smiNode->status == SMI_STATUS_UNKNOWN) {
848             continue;
849         }
850         if (! cnt) {
851             fprintf(f,
852                     "/*\n"
853                     " * Tables to map notifications to strings and vice versa.\n"
854                     " */\n"
855                     "\n");
856         }
857         cnt++;
858         dName = translateUpper(smiNode->name);
859         fprintf(f, "#define %s_%s\t", dModuleName, dName);
860         for (i = 0; i < smiNode->oidlen; i++) {
861             fprintf(f, "%s%u", i ? "," : "", smiNode->oid[i]);
862         }
863         fprintf(f, "\n");
864         xfree(dName);
865     }
866     
867     if (cnt) {
868         cModuleName = translateLower(smiModule->name);
869         fprintf(f,
870                 "\n"
871                 "extern GNetSnmpIdentity const %s_notifications[];\n"
872                 "\n",
873                 cModuleName);
874         xfree(cModuleName);
875     }
876
877     xfree(dModuleName);
878 }
879
880
881
882 static void
883 printParam(FILE *f, SmiNode *smiNode)
884 {
885     char *cName, *dNodeName, *dModuleName;
886     unsigned minSize, maxSize;
887     SmiType *smiType;
888     SmiModule *smiModule;
889
890     smiModule = smiGetNodeModule(smiNode);
891     smiType = smiGetNodeType(smiNode);
892     if (! smiType) {
893         return;
894     }
895
896     cName = translate(smiNode->name);
897     dNodeName = translateUpper(smiNode->name);
898     dModuleName = translateUpper(smiModule ? smiModule->name : "");
899     switch (smiType->basetype) {
900     case SMI_BASETYPE_OBJECTIDENTIFIER:
901         maxSize = smiGetMaxSize(smiType);
902         minSize = smiGetMinSize(smiType);
903         fprintf(f,
904                 ", guint32 *%s", cName);
905         if (maxSize != minSize) {
906             fprintf(f,
907                     ", guint16 _%sLength", cName);
908         }
909         break;
910     case SMI_BASETYPE_OCTETSTRING:
911     case SMI_BASETYPE_BITS:
912         maxSize = smiGetMaxSize(smiType);
913         minSize = smiGetMinSize(smiType);
914         fprintf(f,
915                 ", guchar *%s", cName);
916         if (maxSize != minSize) {
917             fprintf(f,
918                     ", guint16 _%sLength", cName);
919         }
920         break;
921     case SMI_BASETYPE_ENUM:
922     case SMI_BASETYPE_INTEGER32:
923         fprintf(f,
924                 ", gint32 %s", cName);
925         break;
926     case SMI_BASETYPE_UNSIGNED32:
927         fprintf(f,
928                 ", guint32 %s", cName);
929         break;
930     case SMI_BASETYPE_INTEGER64:
931         fprintf(f,
932                 ", gint64 %s", cName);
933         break;
934     case SMI_BASETYPE_UNSIGNED64:
935         fprintf(f,
936                 ", guint64 %s", cName);
937         break;
938     default:
939         fprintf(f,
940                 " /* ?? */ _%s", cName);
941         break;
942     }
943     xfree(cName);
944 }
945
946
947
948 static void
949 printCreateMethodPrototype(FILE *f, SmiNode *groupNode)
950 {
951     SmiModule *smiModule;
952     char *cPrefix, *cNodeName;
953
954     smiModule = smiGetNodeModule(groupNode);
955     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
956     cNodeName = translate(groupNode->name);
957     
958     fprintf(f,
959             "extern void\n"
960             "%s_create_%s(GNetSnmp *s", cPrefix, cNodeName);
961     foreachIndexDo(f, groupNode, printIndexParamsFunc, 1, 0);
962     fprintf(f, ");\n\n");
963
964     xfree(cNodeName);
965     xfree(cPrefix);
966 }
967
968
969
970 static void
971 printDeleteMethodPrototype(FILE *f, SmiNode *groupNode)
972 {
973     SmiModule *smiModule;
974     char *cPrefix, *cNodeName;
975
976     smiModule = smiGetNodeModule(groupNode);
977     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
978     cNodeName = translate(groupNode->name);
979     
980     fprintf(f,
981             "extern void\n"
982             "%s_delete_%s(GNetSnmp *s", cPrefix, cNodeName);
983     
984     foreachIndexDo(f, groupNode, printIndexParamsFunc, 1, 0);
985     
986     fprintf(f, ");\n\n");
987
988     xfree(cNodeName);
989     xfree(cPrefix);
990 }
991
992
993
994 static void
995 printSetMethodPrototype(FILE *f, SmiNode *groupNode, SmiNode *smiNode)
996 {
997     SmiModule *smiModule;
998     char *cPrefix, *cNodeName;
999
1000     smiModule = smiGetNodeModule(smiNode);
1001     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
1002     cNodeName = translate(smiNode->name);
1003     
1004     fprintf(f,
1005             "extern void\n"
1006             "%s_set_%s(GNetSnmp *s",
1007             cPrefix, cNodeName);
1008
1009     foreachIndexDo(f, groupNode, printIndexParamsFunc, 1, 0);
1010     printParam(f, smiNode);
1011     
1012     fprintf(f, ");\n\n");
1013
1014     xfree(cNodeName);
1015     xfree(cPrefix);
1016 }
1017
1018
1019
1020 static void
1021 printMethodPrototypes(FILE *f, SmiNode *groupNode)
1022 {
1023     SmiNode *smiNode;
1024     SmiType *smiType;
1025
1026     for (smiNode = smiGetFirstChildNode(groupNode);
1027          smiNode;
1028          smiNode = smiGetNextChildNode(smiNode)) {
1029         if (smiNode->nodekind & (SMI_NODEKIND_COLUMN | SMI_NODEKIND_SCALAR)
1030             && (smiNode->access >= SMI_ACCESS_READ_ONLY)) {
1031             if (smiNode->access == SMI_ACCESS_READ_WRITE) {
1032                 smiType = smiGetNodeType(smiNode);
1033                 if (smiType && smiType->name
1034                     && strcmp(smiType->name, "RowStatus") == 0) {
1035                     if (cflag) printCreateMethodPrototype(f, groupNode);
1036                     if (dflag) printDeleteMethodPrototype(f, groupNode);
1037                 } else {
1038                     if (! isIndex(groupNode, smiNode)) {
1039                         if (sflag) printSetMethodPrototype(f, groupNode, smiNode);
1040                     }
1041                 }
1042             }
1043         }           
1044     }
1045 }
1046
1047
1048
1049 static void
1050 printHeaderTypedefMemberComment(FILE *f, SmiNode *smiNode, SmiType *smiType)
1051 {
1052     char *s = NULL;
1053
1054     switch (smiNode->access) {
1055     case SMI_ACCESS_READ_WRITE:
1056         s = "rw";
1057         break;
1058     case SMI_ACCESS_READ_ONLY:
1059         s = "ro";
1060         break;
1061     case SMI_ACCESS_NOT_ACCESSIBLE:
1062         s = "na";
1063         break;
1064     case SMI_ACCESS_NOTIFY:
1065         s = "no";
1066         break;
1067     default:
1068         break;
1069     }
1070     if (s) fprintf(f, "%s", s);
1071     s = smiRenderType(smiType, SMI_RENDER_NAME | SMI_RENDER_QUALIFIED);
1072     if (s) {
1073         fprintf(f, " %s", s);
1074         free(s);
1075     }
1076     if (smiNode->units) {
1077         fprintf(f, " [%s]", smiNode->units);
1078     } else if (smiType->units) {
1079         fprintf(f, " [%s]", smiNode->units);
1080     }
1081 }
1082
1083
1084
1085 static void
1086 printHeaderTypedefMember(FILE *f, SmiNode *smiNode,
1087                          SmiType *smiType, int isIndex, int maxlen, char *name)
1088 {
1089     char *cName, *dNodeName, *dModuleName;
1090     unsigned minSize, maxSize;
1091     SmiModule *smiModule;
1092
1093     smiModule = smiGetNodeModule(smiNode);
1094
1095     cName = translate(name ? name : smiNode->name);
1096     dNodeName = translateUpper(name ? name : smiNode->name);
1097     dModuleName = translateUpper(smiModule ? smiModule->name : "");
1098     switch (smiType->basetype) {
1099     case SMI_BASETYPE_OBJECTIDENTIFIER:
1100         maxSize = smiGetMaxSize(smiType);
1101         minSize = smiGetMinSize(smiType);
1102         if (isIndex && maxSize > 128 - smiNode->oidlen) {
1103             maxSize = 128 - smiNode->oidlen;
1104         }
1105         if (isIndex) {
1106             fprintf(f, "    guint32  %s[%u];", cName, maxSize);
1107             fprintf(f, "%*s/* ", maxlen-strlen(cName)+2, "");
1108             printHeaderTypedefMemberComment(f, smiNode, smiType);
1109             fprintf(f, " */\n");
1110         } else {
1111             fprintf(f, "    guint32  *%s;", cName);
1112             fprintf(f, "%*s/* ", maxlen-strlen(cName)+5, "");
1113             printHeaderTypedefMemberComment(f, smiNode, smiType);
1114             fprintf(f, " */\n");
1115         }
1116         if (maxSize == minSize) {
1117             fprintf(f,
1118                     "#define %s_%sLENGTH %u\n",
1119                     dModuleName, dNodeName, maxSize);
1120         } else {
1121             fprintf(f,
1122                     "#define %s_%sMINLENGTH %u\n",
1123                     dModuleName, dNodeName, minSize);
1124             fprintf(f,
1125                     "#define %s_%sMAXLENGTH %u\n",
1126                     dModuleName, dNodeName, maxSize);
1127             fprintf(f,
1128                     "    guint16  _%sLength;\n", cName);
1129         }
1130         break;
1131     case SMI_BASETYPE_OCTETSTRING:
1132     case SMI_BASETYPE_BITS:
1133         maxSize = smiGetMaxSize(smiType);
1134         minSize = smiGetMinSize(smiType);
1135         if (isIndex && maxSize > 128 - smiNode->oidlen) {
1136             maxSize = 128 - smiNode->oidlen;
1137         }
1138         if (isIndex) {
1139             fprintf(f, "    guchar   %s[%u];", cName, maxSize);
1140             fprintf(f, "%*s/* ", maxlen-strlen(cName)+2, "");
1141             printHeaderTypedefMemberComment(f, smiNode, smiType);
1142             fprintf(f, " */\n");
1143         } else {
1144             fprintf(f, "    guchar   *%s;", cName);
1145             fprintf(f, "%*s/* ", maxlen-strlen(cName)+5, "");
1146             printHeaderTypedefMemberComment(f, smiNode, smiType);
1147             fprintf(f, " */\n");
1148         }
1149         if (maxSize == minSize) {
1150             fprintf(f,
1151                     "#define %s_%sLENGTH %u\n",
1152                     dModuleName, dNodeName, maxSize);
1153         } else {
1154             fprintf(f,
1155                     "#define %s_%sMINLENGTH %u\n",
1156                     dModuleName, dNodeName, minSize);
1157             fprintf(f,
1158                     "#define %s_%sMAXLENGTH %u\n",
1159                     dModuleName, dNodeName, maxSize);
1160             fprintf(f,
1161                     "    guint16  _%sLength;\n", cName);
1162         }
1163         break;
1164     case SMI_BASETYPE_ENUM:
1165     case SMI_BASETYPE_INTEGER32:
1166         fprintf(f, "    gint32   %s%s;", isIndex ? "" : "*", cName);
1167         fprintf(f, "%*s/* ", maxlen-strlen(cName)+5+isIndex, "");
1168         printHeaderTypedefMemberComment(f, smiNode, smiType);
1169         fprintf(f, " */\n");
1170         break;
1171     case SMI_BASETYPE_UNSIGNED32:
1172         fprintf(f, "    guint32  %s%s;", isIndex ? "" : "*", cName);
1173         fprintf(f, "%*s/* ", maxlen-strlen(cName)+5+isIndex, "");
1174         printHeaderTypedefMemberComment(f, smiNode, smiType);
1175         fprintf(f, " */\n");
1176         break;
1177     case SMI_BASETYPE_INTEGER64:
1178         fprintf(f, "    gint64   *%s;", cName);
1179         fprintf(f, "%*s/* ", maxlen-strlen(cName)+5, "");
1180         printHeaderTypedefMemberComment(f, smiNode, smiType);
1181         fprintf(f, " */\n");
1182         break;
1183     case SMI_BASETYPE_UNSIGNED64:
1184         fprintf(f, "    guint64  *%s;", cName);
1185         fprintf(f, "%*s/* ", maxlen-strlen(cName)+5, "");
1186         printHeaderTypedefMemberComment(f, smiNode, smiType);
1187         fprintf(f, " */\n");
1188         break;
1189     default:
1190         fprintf(f,
1191                 "    /* ?? */  _%s; \n", cName);
1192         break;
1193     }
1194     xfree(dModuleName);
1195     xfree(dNodeName);
1196     xfree(cName);
1197 }
1198
1199
1200
1201 static void
1202 printHeaderTypedefMemberIndex(FILE *f, SmiNode *smiNode, SmiNode *iNode,
1203                               int flags, int maxlen, char *name)
1204 {
1205     SmiType *iType;
1206
1207     iType = smiGetNodeType(iNode);
1208     if (! iType) {
1209         return;
1210     }
1211     
1212     printHeaderTypedefMember(f, iNode, iType, 1, maxlen, name);
1213 }
1214
1215
1216
1217 static void
1218 printHeaderTypedef(FILE *f, SmiModule *smiModule, SmiNode *groupNode)
1219 {
1220     SmiNode *smiNode;
1221     SmiType *smiType;
1222     char    *cPrefix, *dModuleName, *cGroupName, *dGroupName, *dNodeName;
1223     int     writable = 0, count = 0, len = 0;
1224
1225     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
1226     dModuleName = translateUpper(smiModule->name);
1227     cGroupName = translate(groupNode->name);
1228     dGroupName = translateUpper(groupNode->name);
1229
1230     fprintf(f,
1231             "/*\n"
1232             " * C type definitions for %s::%s.\n"
1233             " */\n\n",
1234             smiModule->name, groupNode->name);
1235     
1236     for (smiNode = smiGetFirstChildNode(groupNode);
1237          smiNode;
1238          smiNode = smiGetNextChildNode(smiNode)) {
1239         if (smiNode->nodekind & (SMI_NODEKIND_COLUMN | SMI_NODEKIND_SCALAR)
1240             && (smiNode->access >= SMI_ACCESS_READ_ONLY)) {
1241             if (len < strlen(smiNode->name)) {
1242                 len = strlen(smiNode->name);
1243             }
1244         }
1245     }
1246     
1247     for (smiNode = smiGetFirstChildNode(groupNode);
1248          smiNode;
1249          smiNode = smiGetNextChildNode(smiNode)) {
1250         if (smiNode->nodekind & (SMI_NODEKIND_COLUMN | SMI_NODEKIND_SCALAR)
1251             && (smiNode->access >= SMI_ACCESS_READ_ONLY)) {
1252             dNodeName = translateUpper(smiNode->name);
1253             fprintf(f, "#define %s_%-*s (1 << %d) \n", dModuleName, len, dNodeName, count);
1254             xfree(dNodeName);
1255             count++;
1256         }           
1257     }
1258
1259     if (count) {
1260         fprintf(f, "\n");
1261     }
1262
1263     fprintf(f, "typedef struct {\n");
1264
1265     foreachIndexDo(f, groupNode, printHeaderTypedefMemberIndex, 0, len);
1266             
1267     for (smiNode = smiGetFirstChildNode(groupNode);
1268          smiNode;
1269          smiNode = smiGetNextChildNode(smiNode)) {
1270         if (smiNode->nodekind & (SMI_NODEKIND_COLUMN | SMI_NODEKIND_SCALAR)
1271             && (smiNode->access >= SMI_ACCESS_READ_ONLY)) {
1272             if (isIndex(groupNode, smiNode)) {
1273                 continue;
1274             }
1275             if (smiNode->access == SMI_ACCESS_READ_WRITE) {
1276                 writable++;
1277             }
1278             smiType = smiGetNodeType(smiNode);
1279             if (! smiType) {
1280                 continue;
1281             }
1282             printHeaderTypedefMember(f, smiNode, smiType, 0, len, 0);
1283         }           
1284     }
1285
1286     fprintf(f, "} %s_%s_t;\n\n", cPrefix, cGroupName);
1287
1288     if (groupNode->nodekind == SMI_NODEKIND_ROW) {
1289         char *cTableName;
1290         SmiNode *tableNode;
1291
1292         tableNode = smiGetParentNode(groupNode);
1293         if (tableNode) {
1294             cTableName = translate(tableNode->name);
1295             fprintf(f, "extern void\n"
1296                     "%s_get_%s(GNetSnmp *s, %s_%s_t ***%s, gint64 mask);\n\n",
1297                     cPrefix, cTableName,
1298                     cPrefix, cGroupName, cGroupName);
1299             fprintf(f, "extern void\n"
1300                     "%s_free_%s(%s_%s_t **%s);\n\n",
1301                     cPrefix, cTableName,
1302                     cPrefix, cGroupName, cGroupName);
1303             xfree(cTableName);
1304         }
1305     }
1306     fprintf(f, "extern %s_%s_t *\n"
1307             "%s_new_%s(void);\n\n",
1308             cPrefix, cGroupName, cPrefix, cGroupName);
1309     fprintf(f, "extern void\n"
1310             "%s_get_%s(GNetSnmp *s, %s_%s_t **%s",
1311             cPrefix, cGroupName,
1312             cPrefix, cGroupName,
1313             cGroupName);
1314     if (groupNode->nodekind == SMI_NODEKIND_ROW) {
1315         foreachIndexDo(f, groupNode, printIndexParamsFunc, 1, 0);
1316     }
1317     fprintf(f, ", gint64 mask);\n\n");
1318     if (writable) {
1319         fprintf(f, "extern void\n"
1320                 "%s_set_%s(GNetSnmp *s, %s_%s_t *%s, gint64 mask);\n\n",
1321                 cPrefix, cGroupName,
1322                 cPrefix, cGroupName, cGroupName);
1323     }
1324     fprintf(f, "extern void\n"
1325             "%s_free_%s(%s_%s_t *%s);\n\n",
1326             cPrefix, cGroupName,
1327             cPrefix, cGroupName, cGroupName);
1328
1329     printMethodPrototypes(f, groupNode);
1330             
1331     xfree(dGroupName);
1332     xfree(cGroupName);
1333     xfree(dModuleName);
1334     xfree(cPrefix);
1335 }
1336
1337
1338
1339 static void
1340 printHeaderTypedefs(FILE *f, SmiModule *smiModule)
1341 {
1342     SmiNode   *smiNode;
1343     int       cnt = 0;
1344     const unsigned int groupkind = SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN;
1345     
1346     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
1347          smiNode;
1348          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
1349         if (isGroup(smiNode, groupkind) && isAccessible(smiNode)) {
1350             cnt++;
1351             printHeaderTypedef(f, smiModule, smiNode);
1352         }
1353     }
1354     
1355     if (cnt) {
1356         fprintf(f, "\n");
1357     }
1358 }
1359
1360
1361
1362 static void
1363 dumpHeader(SmiModule *smiModule, char *baseName)
1364 {
1365     char *pModuleName;
1366     FILE *f;
1367     
1368     pModuleName = translateUpper(smiModule->name);
1369
1370     f = createFile(baseName, ".h");
1371     if (! f) {
1372         return;
1373     }
1374
1375     fprintTopComment(f, smiModule);
1376     
1377     fprintf(f,
1378             "#ifndef _%s_H_\n"
1379             "#define _%s_H_\n"
1380             "\n"
1381             "#include \"gsnmp.h\"\n"
1382             "\n"
1383             "G_BEGIN_DECLS\n"
1384             "\n",
1385             pModuleName, pModuleName);
1386
1387     printHeaderEnumerations(f, smiModule);
1388     printHeaderIdentities(f, smiModule);
1389     printHeaderNotifications(f, smiModule);
1390     printHeaderTypedefs(f, smiModule);
1391
1392     fprintf(f,
1393             "G_END_DECLS\n"
1394             "\n"
1395             "#endif /* _%s_H_ */\n",
1396             pModuleName);
1397
1398     if (fflush(f) || ferror(f)) {
1399         perror("smidump: write error");
1400         exit(1);
1401     }
1402
1403     fclose(f);
1404     xfree(pModuleName);
1405 }
1406
1407
1408
1409 static void
1410 printStubEnumeration(FILE *f, SmiModule *smiModule,
1411                      SmiNode *smiNode, SmiType *smiType)
1412 {
1413     SmiNamedNumber *nn;
1414     char *cName, *cPrefix;
1415     char *dName, *dModuleName;
1416     char *name;
1417     int len;
1418
1419     if (smiType && smiType->name) {
1420         name = smiType->name;
1421     } else if (smiNode && smiNode->name) {
1422         name = smiNode->name;
1423     } else {
1424         return;
1425     }
1426     
1427     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
1428     dModuleName = translateUpper(smiModule->name);
1429     cName = translate(name);
1430     dName = translateUpper(name);
1431     
1432     fprintf(f, "GNetSnmpEnum const %s_enums_%s[] = {\n",
1433             cPrefix, cName);
1434     for (len = 0, nn = smiGetFirstNamedNumber(smiType); nn;
1435          nn = smiGetNextNamedNumber(nn)) {
1436         if (len < strlen(nn->name)) {
1437             len = strlen(nn->name);
1438         }
1439     }
1440     for (nn = smiGetFirstNamedNumber(smiType); nn;
1441          nn = smiGetNextNamedNumber(nn)) {
1442         char *dEnum = translateUpper(nn->name);
1443         fprintf(f, "    { %s_%s_%s,%*s \"%s\" },\n",
1444                 dModuleName, dName, dEnum,
1445                 len - strlen(dEnum), "", nn->name);
1446         xfree(dEnum);
1447     }
1448     fprintf(f,
1449             "    { 0, NULL }\n"
1450             "};\n"
1451             "\n");
1452     
1453     xfree(dName);
1454     xfree(cName);
1455     xfree(dModuleName);
1456     xfree(cPrefix);
1457 }
1458
1459
1460
1461 static void
1462 printStubEnumerations(FILE *f, SmiModule *smiModule)
1463 {
1464     SmiNode   *smiNode, *parentNode;
1465     SmiType   *smiType;
1466     int       cnt = 0;
1467     const unsigned int groupkind = SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN;
1468     
1469     for (smiNode = smiGetFirstNode(smiModule, groupkind);
1470          smiNode;
1471          smiNode = smiGetNextNode(smiNode, groupkind)) {
1472         parentNode = smiGetParentNode(smiNode);
1473         if (! parentNode || ! isGroup(parentNode, groupkind)) {
1474             continue;
1475         }
1476         smiType = smiGetNodeType(smiNode);
1477         if (smiType && !smiType->name
1478             && smiType->basetype == SMI_BASETYPE_ENUM
1479             && smiGetTypeModule(smiType) == smiModule) {
1480             cnt++;
1481             printStubEnumeration(f, smiModule, smiNode, smiType);
1482         }
1483     }
1484     
1485     for (smiType = smiGetFirstType(smiModule);
1486          smiType;
1487          smiType = smiGetNextType(smiType)) {
1488         if (smiType->basetype == SMI_BASETYPE_ENUM
1489             && smiGetTypeModule(smiType) == smiModule) {
1490             cnt++;
1491             printStubEnumeration(f, smiModule, NULL, smiType);
1492         }
1493     }
1494     
1495     if (cnt) {
1496         fprintf(f, "\n");
1497     }
1498 }
1499
1500
1501
1502 static void
1503 printStubIdentities(FILE *f, SmiModule *smiModule)
1504 {
1505     SmiNode   *smiNode, *moduleIdentityNode, *parentNode;
1506     char      *cName, *cModuleName;
1507     char      *dName, *dModuleName;
1508     int       cnt = 0;
1509     
1510     moduleIdentityNode = smiGetModuleIdentityNode(smiModule);
1511     
1512     cModuleName = translateLower(smiModule->name);
1513     dModuleName = translateUpper(smiModule->name);
1514     
1515     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_NODE);
1516          smiNode;
1517          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_NODE)) {
1518         parentNode = smiGetParentNode(smiNode);
1519         if (! parentNode || ! isGroup(parentNode, SMI_NODEKIND_NODE)) {
1520             continue;
1521         }
1522         if (smiNode->status == SMI_STATUS_UNKNOWN) {
1523             continue;
1524         }
1525         if (smiNode == moduleIdentityNode) {
1526             continue;
1527         }
1528         cnt++;
1529         cName = translate(smiNode->name);
1530         dName = translateUpper(smiNode->name);
1531         fprintf(f,
1532                 "static guint32 const %s[]\n\t= { %s_%s };\n",
1533                 cName, dModuleName, dName);
1534         xfree(dName);
1535         xfree(cName);
1536     }
1537
1538     if (cnt) {
1539         fprintf(f,
1540                 "\n"
1541                 "GNetSnmpIdentity const %s_identities[] = {\n",
1542                 cModuleName);
1543     
1544         for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_NODE);
1545              smiNode;
1546              smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_NODE)) {
1547             if (smiNode->status == SMI_STATUS_UNKNOWN) {
1548                 continue;
1549             }
1550             if (smiNode == moduleIdentityNode) {
1551                 continue;
1552             }
1553             cName = translate(smiNode->name);
1554             fprintf(f, "    { %s,\n"
1555                     "      G_N_ELEMENTS(%s),\n"
1556                     "      \"%s\" },\n",
1557                     cName, cName, smiNode->name);
1558             xfree(cName);
1559         }
1560         
1561         fprintf(f,
1562                 "    { 0, 0, NULL }\n"
1563                 "};\n"
1564                 "\n"
1565                 "\n");
1566     }
1567
1568     xfree(dModuleName);
1569     xfree(cModuleName);
1570 }
1571
1572
1573
1574 static void
1575 printStubNotifications(FILE *f, SmiModule *smiModule)
1576 {
1577     SmiNode   *smiNode;
1578     char      *cName, *cModuleName;
1579     char      *dName, *dModuleName;
1580     int       cnt = 0;
1581     
1582     cModuleName = translateLower(smiModule->name);
1583     dModuleName = translateUpper(smiModule->name);
1584     
1585     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_NOTIFICATION);
1586          smiNode;
1587          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_NOTIFICATION)) {
1588         if (smiNode->status == SMI_STATUS_UNKNOWN) {
1589             continue;
1590         }
1591         cnt++;
1592         cName = translate(smiNode->name);
1593         dName = translateUpper(smiNode->name);
1594         fprintf(f,
1595                 "static guint32 const %s[]\n\t= { %s_%s };\n",
1596                 cName, dModuleName, dName);
1597         xfree(dName);
1598         xfree(cName);
1599     }
1600
1601     if (cnt) {
1602         fprintf(f,
1603                 "\n"
1604                 "GNetSnmpIdentity const %s_notifications[] = {\n",
1605                 cModuleName);
1606     
1607         for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_NOTIFICATION);
1608              smiNode;
1609              smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_NOTIFICATION)) {
1610             if (smiNode->status == SMI_STATUS_UNKNOWN) {
1611                 continue;
1612             }
1613             cName = translate(smiNode->name);
1614             fprintf(f, "    { %s,\n"
1615                     "      G_N_ELEMENTS(%s),\n"
1616                     "      \"%s\" },\n",
1617                     cName, cName, smiNode->name);
1618             xfree(cName);
1619         }
1620         
1621         fprintf(f,
1622                 "    { 0, 0, NULL }\n"
1623                 "};\n"
1624                 "\n"
1625                 "\n");
1626     }
1627
1628     xfree(dModuleName);
1629     xfree(cModuleName);
1630 }
1631
1632
1633
1634 static int
1635 printSizeConstraints(FILE *f, SmiNode *smiNode, SmiType *smiType)
1636 {
1637     SmiRange *smiRange;
1638     unsigned int minSize, maxSize;
1639     int cnt;
1640     char *cName;
1641
1642     cName = translate(smiNode->name);
1643
1644     for (cnt = 0; !cnt && smiType; smiType = smiGetParentType(smiType)) {
1645         for (smiRange = smiGetFirstRange(smiType);
1646              smiRange ; smiRange = smiGetNextRange(smiRange)) {
1647             minSize = smiRange->minValue.value.unsigned32;
1648             maxSize = smiRange->maxValue.value.unsigned32;
1649             if (minSize == 0 && maxSize >= 65535) continue;
1650             if (f) {
1651                 if (cnt) {
1652                     fprintf(f, ", %u, %u", minSize, maxSize);
1653                 } else {
1654                     fprintf(f, "static guint16 %s_constraints[] = {%uU, %uU",
1655                             cName, minSize, maxSize);
1656                 }
1657             }
1658             cnt++;
1659         }
1660     }
1661
1662     xfree(cName);
1663     if (f && cnt) fprintf(f, ", 0, 0};\n");
1664     return (cnt > 0);
1665 }
1666
1667
1668
1669 static int
1670 printInteger32RangeConstraints(FILE *f, SmiNode *smiNode, SmiType *smiType)
1671 {
1672     SmiRange *smiRange;
1673     long minSize, maxSize;
1674     int cnt;
1675     char *cName;
1676
1677     cName = translate(smiNode->name);
1678
1679     for (cnt = 0; !cnt && smiType; smiType = smiGetParentType(smiType)) {
1680         for (smiRange = smiGetFirstRange(smiType);
1681              smiRange ; smiRange = smiGetNextRange(smiRange)) {
1682             minSize = smiRange->minValue.value.integer32;
1683             maxSize = smiRange->maxValue.value.integer32;
1684             if (minSize < -2147483647 && maxSize > 2147483646) continue;
1685             if (f) {
1686                 if (cnt) {
1687                     fprintf(f, ", %ldL, %ldL", minSize, maxSize);
1688                 } else {
1689                     fprintf(f, "static gint32 %s_constraints[] = {%ldL, %ldL",
1690                             cName, minSize, maxSize);
1691                 }
1692             }
1693             cnt++;
1694         }
1695     }
1696
1697     xfree(cName);
1698     if (f && cnt) fprintf(f, ", 0, 0};\n");
1699     return (cnt > 0);
1700 }
1701
1702
1703
1704 static int
1705 printUnsigned32RangeConstraints(FILE *f, SmiNode *smiNode, SmiType *smiType)
1706 {
1707     SmiRange *smiRange;
1708     unsigned long minSize, maxSize;
1709     int cnt;
1710     char *cName;
1711
1712     cName = translate(smiNode->name);
1713
1714     for (cnt = 0; !cnt && smiType; smiType = smiGetParentType(smiType)) {
1715         for (smiRange = smiGetFirstRange(smiType);
1716              smiRange ; smiRange = smiGetNextRange(smiRange)) {
1717             minSize = smiRange->minValue.value.unsigned32;
1718             maxSize = smiRange->maxValue.value.unsigned32;
1719             if (minSize == 0 && maxSize >= 4294967295UL) continue;
1720             if (f) {
1721                 if (cnt) {
1722                     fprintf(f, ", %luUL, %luUL", minSize, maxSize);
1723                 } else {
1724                     fprintf(f, "static guint32 %s_constraints[] = {%luUL, %luUL",
1725                         cName, minSize, maxSize);
1726                 }
1727             }
1728             cnt++;
1729         }
1730     }
1731
1732     xfree(cName);
1733     if (f && cnt) fprintf(f, ", 0, 0};\n");
1734     return (cnt > 0);
1735 }
1736
1737
1738
1739 static int
1740 printConstraints(FILE *f, SmiNode *smiNode, SmiNode *groupNode, int flags)
1741 {
1742     SmiType *smiType;
1743     int cnt;
1744
1745     smiType = smiGetNodeType(smiNode);
1746     if (! smiType) {
1747         return 0;
1748     }
1749
1750     /*
1751      * Generally suppress all INDEX objects (treat them as if they
1752      * were not-accessible). This is a cheap optimization for SMIv1
1753      * MIBs where these objects were generally read-only.
1754      */
1755
1756     if (flags && isIndex(groupNode, smiNode)) {
1757         return 0;
1758     }
1759
1760     if (smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE
1761         || smiNode->access == SMI_ACCESS_NOTIFY) {
1762         return 0;
1763     }
1764
1765     switch (smiType->basetype) {
1766     case SMI_BASETYPE_OCTETSTRING:
1767         cnt = printSizeConstraints(f, smiNode, smiType);
1768         break;
1769     case SMI_BASETYPE_INTEGER32:
1770         cnt = printInteger32RangeConstraints(f, smiNode, smiType);
1771         break;
1772     case SMI_BASETYPE_UNSIGNED32:
1773         cnt = printUnsigned32RangeConstraints(f, smiNode, smiType);
1774         break;
1775     default:
1776         cnt = 0;
1777         break;
1778     }
1779
1780     return cnt;
1781 }
1782
1783
1784
1785 static int
1786 printScalarsAttributesContraints(FILE *f, SmiNode *groupNode)
1787 {
1788     SmiNode *smiNode;
1789     int      n = 0;
1790     
1791     for (smiNode = smiGetFirstChildNode(groupNode);
1792          smiNode;
1793          smiNode = smiGetNextChildNode(smiNode)) {
1794         n += printConstraints(f, smiNode, groupNode, 0);
1795     }
1796     return n;
1797 }
1798
1799
1800
1801 static int
1802 printTableAttributesConstraints(FILE *f, SmiNode *rowNode)
1803 {
1804     SmiNode *smiNode;
1805     int     idx, cnt, n = 0;
1806     
1807     for (smiNode = smiGetFirstChildNode(rowNode), idx = 0, cnt = 0;
1808          smiNode;
1809          smiNode = smiGetNextChildNode(smiNode)) {
1810         if (isIndex(rowNode, smiNode)) idx++;
1811         cnt++;
1812     }
1813
1814     for (smiNode = smiGetFirstChildNode(rowNode);
1815          smiNode;
1816          smiNode = smiGetNextChildNode(smiNode)) {
1817         n += printConstraints(f, smiNode, rowNode, cnt > idx);
1818     }
1819     return n;
1820 }
1821
1822
1823
1824 static void
1825 printStubContraints(FILE *f, SmiModule *smiModule)
1826 {
1827     SmiNode *smiNode;
1828     int cnt = 0;
1829     const unsigned int groupkind = SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN;
1830     
1831     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
1832          smiNode;
1833          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
1834         if (isGroup(smiNode, groupkind) && isAccessible(smiNode)) {
1835             if (smiNode->nodekind == SMI_NODEKIND_ROW) {
1836                 cnt += printTableAttributesConstraints(f, smiNode);
1837             } else {
1838                 cnt += printScalarsAttributesContraints(f, smiNode);
1839             }
1840         }
1841     }
1842     
1843     if (cnt) {
1844         fprintf(f, "\n\n");
1845     }
1846 }
1847
1848
1849
1850 static void
1851 printAttribute(FILE *f, SmiNode *smiNode, SmiNode *groupNode, int flags)
1852 {
1853     SmiType *smiType;
1854     char *snmpType;
1855     char *dModuleName, *dNodeName;
1856     char *cPrefix, *cGroupName, *cNodeName;
1857     unsigned maxSize = 0, minSize = 0;
1858     int cnt;
1859
1860     smiType = smiGetNodeType(smiNode);
1861     if (!smiType) {
1862         return;
1863     }
1864
1865     snmpType = getSnmpType(smiType);
1866     if (!snmpType) {
1867         return;
1868     }
1869
1870     /*
1871      * Generally suppress all INDEX objects (treat them as if they
1872      * were not-accessible). This is a cheap optimization for SMIv1
1873      * MIBs where these objects were generally read-only.
1874      */
1875
1876     if (flags && isIndex(groupNode, smiNode)) {
1877         return;
1878     }
1879
1880     if (smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE
1881         || smiNode->access == SMI_ACCESS_NOTIFY) {
1882         return;
1883     }
1884
1885     dModuleName = translateUpper(smiGetNodeModule(smiNode)->name);
1886     dNodeName = translateUpper(smiNode->name);
1887     cNodeName = translate(smiNode->name);
1888     cGroupName = translate(groupNode->name);
1889     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiGetNodeModule(smiNode)->name);
1890
1891     fprintf(f,
1892             "    { %u, %s,\n"
1893             "      %s_%s, \"%s\",\n",
1894             smiNode->oid[smiNode->oidlen-1], snmpType,
1895             dModuleName, dNodeName, smiNode->name);
1896
1897     switch (smiType->basetype) {
1898     case SMI_BASETYPE_OCTETSTRING:
1899         cnt = printSizeConstraints(NULL, smiNode, smiType);
1900         break;
1901     case SMI_BASETYPE_INTEGER32:
1902         cnt = printInteger32RangeConstraints(NULL, smiNode, smiType);
1903         break;
1904     case SMI_BASETYPE_UNSIGNED32:
1905         cnt = printUnsigned32RangeConstraints(NULL, smiNode, smiType);
1906         break;
1907     default:
1908         cnt = 0;
1909         break;
1910     }
1911     if (cnt) {
1912         fprintf(f, "       %s_constraints,\n", cNodeName);
1913     } else {
1914         fprintf(f, "       NULL,\n");
1915     }
1916
1917     if (! flags && isIndex(groupNode, smiNode)) {
1918         fprintf(f, "      -1,\n");
1919     } else {
1920         fprintf(f,
1921                 "      G_STRUCT_OFFSET(%s_%s_t, %s),\n",
1922                 cPrefix, cGroupName, cNodeName);
1923     }
1924
1925     switch (smiType->basetype) {
1926     case SMI_BASETYPE_OCTETSTRING:
1927     case SMI_BASETYPE_BITS:
1928     case SMI_BASETYPE_OBJECTIDENTIFIER:
1929         maxSize = smiGetMaxSize(smiType);
1930         minSize = smiGetMinSize(smiType);
1931         break;
1932     default:
1933         break;
1934     }
1935     if (minSize != maxSize) {
1936         fprintf(f,
1937                 "      G_STRUCT_OFFSET(%s_%s_t, _%sLength)",
1938                 cPrefix, cGroupName, cNodeName);
1939     } else {
1940         fprintf(f,
1941                 "      0");
1942     }
1943
1944     fprintf(f,
1945             ",\n"
1946             "      %s },\n",
1947             (smiNode->access > SMI_ACCESS_READ_ONLY) ? "GSNMP_ATTR_FLAG_WRITABLE" : "0");
1948
1949     xfree(cPrefix);
1950     xfree(cGroupName);
1951     xfree(cNodeName);
1952     xfree(dNodeName);
1953     xfree(dModuleName);
1954 }
1955
1956
1957
1958 static void
1959 printScalarsAttributes(FILE *f, SmiModule *smiModule, SmiNode *groupNode)
1960 {
1961     SmiNode *smiNode;
1962     
1963     for (smiNode = smiGetFirstChildNode(groupNode);
1964          smiNode;
1965          smiNode = smiGetNextChildNode(smiNode)) {
1966         printAttribute(f, smiNode, groupNode, 0);
1967     }
1968 }
1969
1970
1971
1972 static void
1973 printTableAttributes(FILE *f, SmiModule *smiModule, SmiNode *rowNode)
1974 {
1975     SmiNode *smiNode;
1976     int     idx, cnt;
1977     
1978     for (smiNode = smiGetFirstChildNode(rowNode), idx = 0, cnt = 0;
1979          smiNode;
1980          smiNode = smiGetNextChildNode(smiNode)) {
1981         if (isIndex(rowNode, smiNode)) idx++;
1982         cnt++;
1983     }
1984
1985     for (smiNode = smiGetFirstChildNode(rowNode);
1986          smiNode;
1987          smiNode = smiGetNextChildNode(smiNode)) {
1988         printAttribute(f, smiNode, rowNode, cnt > idx);
1989     }
1990 }
1991
1992
1993
1994 static void
1995 printStubAttributes(FILE *f, SmiModule *smiModule)
1996 {
1997     SmiNode      *smiNode;
1998     char         *cName;
1999     int          cnt = 0;
2000     unsigned int i;
2001     const unsigned int groupkind = SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN;
2002         
2003     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
2004          smiNode;
2005          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
2006         if (isGroup(smiNode, groupkind) && isAccessible(smiNode)) {
2007             cnt++;
2008             cName = translate(smiNode->name);
2009
2010             fprintf(f, "static guint32 const %s_oid[] = {", cName);
2011             for (i = 0; i < smiNode->oidlen; i++) {
2012                 fprintf(f, "%s%u", i ? ", " : "", smiNode->oid[i]);
2013             }
2014             fprintf(f, "};\n\n");
2015             
2016             fprintf(f,
2017                     "static GNetSnmpAttribute %s_attr[] = {\n",
2018                     cName);
2019             if (smiNode->nodekind == SMI_NODEKIND_ROW) {
2020                 printTableAttributes(f, smiModule, smiNode);
2021             } else {
2022                 printScalarsAttributes(f, smiModule, smiNode);
2023             }
2024             fprintf(f,
2025                     "    { 0, 0, 0, NULL }\n"
2026                     "};\n"
2027                     "\n");
2028             xfree(cName);
2029         }
2030     }
2031     
2032     if (cnt) {
2033         fprintf(f, "\n");
2034     }
2035 }
2036
2037
2038
2039 static void
2040 printInteger32RangeChecks(FILE *f, char *cGroupName, char *cName,
2041                           SmiType *smiType)
2042 {
2043     SmiRange *smiRange;
2044     long int minSize, maxSize;
2045     int c;
2046
2047     for (c = 0; smiType; smiType = smiGetParentType(smiType)) {
2048         for (smiRange = smiGetFirstRange(smiType);
2049              smiRange ; smiRange = smiGetNextRange(smiRange)) {
2050             minSize = smiRange->minValue.value.integer32;
2051             maxSize = smiRange->maxValue.value.integer32;
2052             if (! c) {
2053                 fprintf(f, "    if (");
2054             } else {
2055                 fprintf(f, "\n        && ");
2056             }
2057             if (minSize == -2147483647 - 1) {
2058                 fprintf(f, "(%s->%s > %ld)", cGroupName, cName, maxSize);
2059             } else if (maxSize == 2147483647) {
2060                 fprintf(f, "(%s->%s < %ld)", cGroupName, cName, minSize);
2061             } else if (minSize == maxSize) {
2062                 fprintf(f, "(%s->%s != %ld)", cGroupName, cName, maxSize);
2063             } else {
2064                 fprintf(f, "(%s->%s < %ld || %s->%s > %ld)",
2065                         cGroupName, cName, minSize,
2066                         cGroupName, cName, maxSize);
2067             }
2068             c++;
2069         }
2070     }
2071
2072     if (c) {
2073         fprintf(f, ") {\n"
2074                 "         return -1;\n"
2075                 "    }\n");
2076     }
2077 }
2078
2079
2080
2081 static void
2082 printUnsigned32RangeChecks(FILE *f, char *cGroupName, char *cName,
2083                            SmiType *smiType)
2084 {
2085     SmiRange *smiRange;
2086     unsigned long minSize, maxSize;
2087     int c;
2088
2089     for (c = 0; smiType; smiType = smiGetParentType(smiType)) {
2090         for (smiRange = smiGetFirstRange(smiType);
2091              smiRange ; smiRange = smiGetNextRange(smiRange)) {
2092             minSize = smiRange->minValue.value.unsigned32;
2093             maxSize = smiRange->maxValue.value.unsigned32;
2094             if (minSize == 0 && maxSize == 4294967295U) {
2095                 continue;
2096             }
2097             if (! c) {
2098                 fprintf(f, "     if (");
2099             } else {
2100                 fprintf(f, "\n         && ");
2101             }
2102             if (minSize == 0) {
2103                 fprintf(f, "(%s->%s > %lu)", cGroupName, cName, maxSize);
2104             } else if (maxSize == 4294967295U) {
2105                 fprintf(f, "(%s->%s < %lu)", cGroupName, cName, minSize);
2106             } else if (minSize == maxSize) {
2107                 fprintf(f, "(%s->%s != %lu)", cGroupName, cName, maxSize);
2108             } else {
2109                 fprintf(f, "(%s->%s < %lu || %s->%s > %lu)",
2110                         cGroupName, cName, minSize,
2111                         cGroupName, cName, maxSize);
2112             }
2113             c++;
2114         }
2115     }
2116     if (c) {
2117         fprintf(f, ") {\n"
2118                 "         return -1;\n"
2119                 "    }\n");
2120     }
2121 }
2122
2123
2124
2125 static void
2126 printUnpackMethod(FILE *f, SmiModule *smiModule, SmiNode *groupNode)
2127 {
2128     SmiElement *smiElement;
2129     SmiNode *indexNode = NULL;
2130     SmiNode *iNode;
2131     SmiType *iType;
2132     char    *cPrefix, *cGroupName, *cName, *name;
2133     unsigned maxSize, minSize;
2134     int last = 0;
2135
2136     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
2137     cGroupName = translate(groupNode->name);
2138
2139     switch (groupNode->indexkind) {
2140     case SMI_INDEX_INDEX:
2141     case SMI_INDEX_REORDER:
2142         indexNode = groupNode;
2143         break;
2144     case SMI_INDEX_EXPAND:      /* TODO: we have to do more work here! */
2145         indexNode = NULL;
2146         break;
2147     case SMI_INDEX_AUGMENT:
2148     case SMI_INDEX_SPARSE:
2149         indexNode = smiGetRelatedNode(groupNode);
2150         break;
2151     case SMI_INDEX_UNKNOWN:
2152         indexNode = NULL;
2153         break;
2154     }
2155
2156     /*
2157      * First check if there are OID or string types so that we
2158      * know whether we need some additional variables.
2159      */
2160     
2161     for (smiElement = smiGetFirstElement(indexNode);
2162          smiElement; smiElement = smiGetNextElement(smiElement)) {
2163         iNode = smiGetElementNode(smiElement);
2164         if (iNode) {
2165             iType = smiGetNodeType(iNode);
2166             if (iType
2167                 && (iType->basetype == SMI_BASETYPE_OCTETSTRING
2168                     || iType->basetype == SMI_BASETYPE_OBJECTIDENTIFIER)) {
2169                 break;
2170             }
2171         }
2172     }
2173
2174     fprintf(f,
2175             "static inline int\n"
2176             "unpack_%s(GNetSnmpVarBind *vb, %s_%s_t *%s)\n"
2177             "{\n"
2178             "    guint8 idx = %u;\n"
2179             "%s"
2180             "\n",
2181             cGroupName, cPrefix, cGroupName, cGroupName,
2182             groupNode->oidlen + 1,
2183             smiElement ? "    guint16 i, len;\n" : "");
2184
2185     for (smiElement = smiGetFirstElement(indexNode);
2186          smiElement; smiElement = smiGetNextElement(smiElement)) {
2187         iNode = smiGetElementNode(smiElement);
2188         last = (smiGetNextElement(smiElement) == NULL);
2189         if (iNode) {
2190             iType = smiGetNodeType(iNode);
2191             if (! iType) {
2192                 continue;
2193             }
2194             name = getIndexName(indexNode, iNode, smiElement);
2195             cName = translate(name ? name : iNode->name);
2196             switch (iType->basetype) {
2197             case SMI_BASETYPE_ENUM:
2198             case SMI_BASETYPE_INTEGER32:
2199                 fprintf(f,
2200                         "    if (vb->oid_len < idx) return -1;\n"
2201                         "    %s->%s = vb->oid[idx++];\n",
2202                         cGroupName, cName);
2203                 printInteger32RangeChecks(f, cGroupName, cName, iType);
2204                 break;
2205             case SMI_BASETYPE_UNSIGNED32:
2206                 fprintf(f,
2207                         "    if (vb->oid_len < idx) return -1;\n"
2208                         "    %s->%s = vb->oid[idx++];\n",
2209                         cGroupName, cName);
2210                 printUnsigned32RangeChecks(f, cGroupName, cName, iType);
2211                 break;
2212             case SMI_BASETYPE_OCTETSTRING:
2213                 maxSize = smiGetMaxSize(iType);
2214                 minSize = smiGetMinSize(iType);
2215                 if (maxSize > 128 - iNode->oidlen) {
2216                     maxSize = 128 - iNode->oidlen;
2217                 }
2218                 if (minSize == maxSize) {
2219                     fprintf(f,
2220                             "    len = %u;\n",
2221                             minSize);
2222                 } else if (last && indexNode->implied) {
2223                     fprintf(f,
2224                             "    if (vb->oid_len < idx) return -1;\n"
2225                             "    len = vb->oid_len - idx;\n");
2226                 } else {
2227                     fprintf(f,
2228                             "    if (vb->oid_len < idx) return -1;\n"
2229                             "    len = vb->oid[idx++];\n");
2230                 }
2231                 if (minSize != maxSize) {
2232                     if (minSize > 0 && maxSize < 65535) {
2233                         fprintf(f,
2234                                 "    if (len < %u || len > %u) return -1;\n",
2235                                 minSize, maxSize);
2236                     } else if (minSize > 0 && maxSize == 65535) {
2237                         fprintf(f,
2238                                 "    if (len < %u) return -1;\n", minSize);
2239                     } else if (minSize == 0 && maxSize < 65535) {
2240                         fprintf(f,
2241                                 "    if (len > %u) return -1;\n", maxSize);
2242                     }
2243                 }
2244                 fprintf(f,
2245                         "    if (vb->oid_len < idx + len) return -1;\n"
2246                         "    for (i = 0; i < len; i++) {\n"
2247                         "        %s->%s[i] = vb->oid[idx++];\n"
2248                         "    }\n",
2249                         cGroupName, cName);
2250                 if (minSize != maxSize) {
2251                     fprintf(f, 
2252                             "    %s->_%sLength = len;\n", cGroupName, cName);
2253                 }
2254                 break;
2255             case SMI_BASETYPE_OBJECTIDENTIFIER:
2256                 maxSize = smiGetMaxSize(iType);
2257                 minSize = smiGetMinSize(iType);
2258                 if (maxSize > 128 - iNode->oidlen) {
2259                     maxSize = 128 - iNode->oidlen;
2260                 }
2261                 if (minSize == maxSize) {
2262                     fprintf(f,
2263                             "    len = %u;\n"
2264                             "    if (vb->oid_len < idx + len) return -1;\n",
2265                             minSize);
2266                 } else if (last && indexNode->implied) {
2267                     fprintf(f,
2268                             "    if (vb->oid_len < idx) return -1;\n"
2269                             "    len = vb->oid_len - idx;\n");
2270                 } else {
2271                     fprintf(f,
2272                             "    if (vb->oid_len < idx) return -1;\n"
2273                             "    len = vb->oid[idx++];\n"
2274                             "    if (vb->oid_len < idx + len) return -1;\n");
2275                 }
2276                 if (minSize != maxSize) {
2277                     if (minSize > 0 && maxSize < 65535) {
2278                         fprintf(f,
2279                                 "    if (len < %u || len > %u) return -1;\n",
2280                                 minSize, maxSize);
2281                     } else if (minSize > 0 && maxSize == 65535) {
2282                         fprintf(f,
2283                                 "    if (len < %u) return -1;\n", minSize);
2284                     } else if (minSize == 0 && maxSize < 65535) {
2285                         fprintf(f,
2286                                 "    if (len > %u) return -1;\n", maxSize);
2287                     }
2288                 }
2289                 fprintf(f,
2290                         "    for (i = 0; i < len; i++) {\n"
2291                         "        %s->%s[i] = vb->oid[idx++];\n"
2292                         "    }\n",
2293                         cGroupName, cName);
2294                 if (minSize != maxSize) {
2295                     fprintf(f,
2296                             "    %s->_%sLength = len;\n", cGroupName, cName);
2297                 }
2298                 break;
2299             default:
2300                 fprintf(f,
2301                         "    /* XXX how to unpack %s->%s ? */\n",
2302                         cGroupName, cName);
2303                 break;
2304             }
2305             xfree(cName);
2306             if (name) xfree(name);
2307         }
2308     }
2309
2310     fprintf(f,
2311             "    if (vb->oid_len > idx) return -1;\n"
2312             "    return 0;\n"
2313             "}\n\n");
2314
2315     xfree(cGroupName);
2316     xfree(cPrefix);
2317 }
2318
2319
2320
2321 static void
2322 printPackMethod(FILE *f, SmiModule *smiModule, SmiNode *groupNode)
2323 {
2324     SmiElement *smiElement;
2325     SmiNode *indexNode = NULL;
2326     SmiNode *iNode;
2327     SmiType *iType;
2328     char    *cGroupName, *cName, *name;
2329     unsigned maxSize, minSize;
2330     int last = 0;
2331
2332     cGroupName = translate(groupNode->name);
2333
2334     switch (groupNode->indexkind) {
2335     case SMI_INDEX_INDEX:
2336     case SMI_INDEX_REORDER:
2337         indexNode = groupNode;
2338         break;
2339     case SMI_INDEX_EXPAND:      /* TODO: we have to do more work here! */
2340         indexNode = NULL;
2341         break;
2342     case SMI_INDEX_AUGMENT:
2343     case SMI_INDEX_SPARSE:
2344         indexNode = smiGetRelatedNode(groupNode);
2345         break;
2346     case SMI_INDEX_UNKNOWN:
2347         indexNode = NULL;
2348         break;
2349     }
2350
2351     /*
2352      * First check if there are OID or string types so that we
2353      * know whether we need some additional variables.
2354      */
2355     
2356     for (smiElement = smiGetFirstElement(indexNode);
2357          smiElement; smiElement = smiGetNextElement(smiElement)) {
2358         iNode = smiGetElementNode(smiElement);
2359         if (iNode) {
2360             iType = smiGetNodeType(iNode);
2361             if (iType
2362                 && (iType->basetype == SMI_BASETYPE_OCTETSTRING
2363                     || iType->basetype == SMI_BASETYPE_OBJECTIDENTIFIER)) {
2364                 break;
2365             }
2366         }
2367     }
2368
2369     fprintf(f,
2370             "static inline gint8\n"
2371             "pack_%s(guint32 *base",
2372             cGroupName);
2373     foreachIndexDo(f, groupNode, printIndexParamsFunc, 1, 0);
2374     fprintf(f,
2375             ")\n"
2376             "{\n"
2377             "    guint8 idx = %u;\n"
2378             "%s"
2379             "\n",
2380             groupNode->oidlen + 1,
2381             smiElement ? "    guint16 i, len;\n" : "");
2382
2383     for (smiElement = smiGetFirstElement(indexNode);
2384          smiElement; smiElement = smiGetNextElement(smiElement)) {
2385         iNode = smiGetElementNode(smiElement);
2386         last = (smiGetNextElement(smiElement) == NULL);
2387         if (iNode) {
2388             iType = smiGetNodeType(iNode);
2389             if (! iType) {
2390                 continue;
2391             }
2392             name = getIndexName(indexNode, iNode, smiElement);
2393             cName = translate(name ? name : iNode->name);
2394             switch (iType->basetype) {
2395             case SMI_BASETYPE_ENUM:
2396             case SMI_BASETYPE_INTEGER32:
2397                 fprintf(f,
2398                         "    base[idx++] = %s;\n",
2399                         cName);
2400                 break;
2401             case SMI_BASETYPE_UNSIGNED32:
2402                 fprintf(f,
2403                         "    base[idx++] = %s;\n",
2404                         cName);
2405                 break;
2406             case SMI_BASETYPE_OCTETSTRING:
2407                 maxSize = smiGetMaxSize(iType);
2408                 minSize = smiGetMinSize(iType);
2409                 if (maxSize > 128 - iNode->oidlen) {
2410                     maxSize = 128 - iNode->oidlen;
2411                 }
2412                 if (minSize == maxSize) {
2413                     fprintf(f,
2414                             "    len = %u;\n",
2415                             minSize);
2416                 } else if (last && indexNode->implied) {
2417                     fprintf(f,
2418                             "    len = _%sLength;\n",
2419                             cName);
2420                 } else {
2421                     fprintf(f,
2422                             "    len = _%sLength;\n"
2423                             "    base[idx++] = len;\n",
2424                             cName);
2425                 }
2426                 if (minSize == maxSize) {
2427                     fprintf(f,
2428                             "    if (len != %u) return -1;\n",
2429                             minSize);
2430                 } else {
2431                     if (minSize > 0 && maxSize < 65535) {
2432                         fprintf(f,
2433                                 "    if (len < %u || len > %u) return -1;\n",
2434                                 minSize, maxSize);
2435                     } else if (minSize > 0 && maxSize == 65535) {
2436                         fprintf(f,
2437                                 "    if (len < %u) return -1;\n", minSize);
2438                     } else if (minSize == 0 && maxSize < 65535) {
2439                         fprintf(f,
2440                                 "    if (len > %u) return -1;\n", maxSize);
2441                     }
2442                 }
2443                 fprintf(f,
2444                         "    for (i = 0; i < len; i++) {\n"
2445                         "        base[idx++] = %s[i];\n"
2446                         "        if (idx >= 128) return -1;\n"
2447                         "    }\n",
2448                         cName);
2449                 break;
2450             case SMI_BASETYPE_OBJECTIDENTIFIER:
2451                 maxSize = smiGetMaxSize(iType);
2452                 minSize = smiGetMinSize(iType);
2453                 if (maxSize > 128 - iNode->oidlen) {
2454                     maxSize = 128 - iNode->oidlen;
2455                 }
2456                 if (minSize == maxSize) {
2457                     fprintf(f,
2458                             "    len = %u;\n",
2459                             minSize);
2460                 } else if (last && indexNode->implied) {
2461                     fprintf(f,
2462                             "    len = _%sLength;\n",
2463                             cName);
2464                 } else {
2465                     fprintf(f,
2466                             "    len = _%sLength;\n"
2467                             "    base[idx++] = len;\n",
2468                             cName);
2469                 }
2470                 if (minSize == maxSize) {
2471                     fprintf(f,
2472                             "    if (len != %u) return -1;\n",
2473                             minSize);
2474                 } else {
2475                     if (minSize > 0 && maxSize < 65535) {
2476                         fprintf(f,
2477                                 "    if (len < %u || len > %u) return -1;\n",
2478                                 minSize, maxSize);
2479                     } else if (minSize > 0 && maxSize == 65535) {
2480                         fprintf(f,
2481                                 "    if (len < %u) return -1;\n", minSize);
2482                     } else if (minSize == 0 && maxSize < 65535) {
2483                         fprintf(f,
2484                                 "    if (len > %u) return -1;\n", maxSize);
2485                     }
2486                 }
2487                 fprintf(f,
2488                         "    for (i = 0; i < len; i++) {\n"
2489                         "        base[idx++] = %s[i];\n"
2490                         "        if (idx >= 128) return -1;\n"
2491                         "    }\n",
2492                         cName);
2493                 break;
2494             default:
2495                 fprintf(f,
2496                         "    /* XXX how to pack %s ? */\n", cGroupName);
2497                 break;
2498             }
2499             xfree(cName);
2500             if (name) xfree(name);
2501         }
2502     }
2503
2504     fprintf(f,
2505             "    return idx;\n"
2506             "}\n\n");
2507
2508     xfree(cGroupName);
2509 }
2510
2511
2512
2513 static void
2514 printAssignMethod(FILE *f, SmiModule *smiModule, SmiNode *groupNode)
2515 {
2516     char *cPrefix, *cGroupName;
2517
2518     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
2519     cGroupName = translate(groupNode->name);
2520
2521     if (groupNode->nodekind == SMI_NODEKIND_ROW) {
2522         printUnpackMethod(f, smiModule, groupNode);
2523         printPackMethod(f, smiModule, groupNode);
2524     }
2525     
2526     fprintf(f,
2527             "static inline %s_%s_t *\n"
2528             "assign_%s(GList *vbl)\n"
2529             "{\n"
2530             "    %s_%s_t *%s;\n"
2531             "    char *p;\n"
2532             "\n",
2533             cPrefix, cGroupName, cGroupName,
2534             cPrefix, cGroupName, cGroupName);
2535
2536     fprintf(f,
2537             "    %s = %s_new_%s();\n"
2538             "    p = (char *) %s + sizeof(%s_%s_t);\n"
2539             "    * (GList **) p = vbl;\n"
2540             "\n",
2541             cGroupName, cPrefix, cGroupName,
2542             cGroupName, cPrefix, cGroupName);
2543
2544     if (groupNode->nodekind == SMI_NODEKIND_ROW) {
2545         fprintf(f,
2546                 "    if (unpack_%s((GNetSnmpVarBind *) vbl->data, %s) < 0) {\n"
2547                 "        g_warning(\"%%s: invalid instance identifier\", \"%s\");\n"
2548                 "        g_free(%s);\n"
2549                 "        return NULL;\n"
2550                 "    }\n\n",
2551                 cGroupName, cGroupName, cGroupName, cGroupName);
2552     }
2553
2554     fprintf(f,
2555             "    gnet_snmp_attr_assign(vbl, %s_oid, G_N_ELEMENTS(%s_oid),\n"
2556             "                      %s_attr, %s);\n"
2557             "\n"
2558             "    return %s;\n"
2559             "}\n"
2560             "\n", cGroupName, cGroupName, cGroupName, cGroupName, cGroupName);
2561             
2562     xfree(cGroupName);
2563     xfree(cPrefix);
2564 }
2565  
2566
2567
2568
2569 static void
2570 printGetTableMethod(FILE *f, SmiModule *smiModule, SmiNode *rowNode)
2571 {
2572     SmiNode      *tableNode;
2573     char         *cPrefix, *cModuleName, *cRowName, *cTableName;
2574     unsigned int i;
2575
2576     tableNode = smiGetParentNode(rowNode);
2577     if (! tableNode) {
2578         return;
2579     }
2580
2581     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
2582     cModuleName = translateLower(smiModule->name);
2583     cRowName = translate(rowNode->name);
2584     cTableName = translate(tableNode->name);
2585
2586     fprintf(f,
2587             "void\n"
2588             "%s_get_%s(GNetSnmp *s, %s_%s_t ***%s, gint64 mask)\n"
2589             "{\n"
2590             "    GList *in = NULL, *out = NULL;\n",
2591             cPrefix, cTableName, cPrefix, cRowName, cRowName);
2592
2593     fprintf(f,
2594             "    GList *row;\n"
2595             "    int i;\n");
2596
2597     fprintf(f, "    static guint32 const _base[] = {");
2598     for (i = 0; i < rowNode->oidlen; i++) {
2599         fprintf(f, "%u, ", rowNode->oid[i]);
2600     }
2601     fprintf(f, "0};\n");
2602     fprintf(f, "    guint32 base[128];\n");
2603
2604     fprintf(f,
2605             "\n"
2606             "    *%s = NULL;\n"
2607             "    memcpy(base, _base, sizeof(_base));\n"
2608             "\n",
2609             cRowName);
2610
2611     fprintf(f,
2612             "    gnet_snmp_attr_get(s, &in, base, %u, %u, %s_attr, mask);\n",
2613             rowNode->oidlen+1, rowNode->oidlen, cRowName);
2614
2615     fprintf(f,
2616             "\n"
2617             "    out = gnet_snmp_sync_table(s, in);\n"
2618             "    /* gnet_snmp_varbind_list_free(in); */\n"
2619             "\n");
2620     fprintf(f,
2621             "    if (out) {\n"
2622             "        *%s = (%s_%s_t **) g_malloc0((g_list_length(out) + 1) * sizeof(%s_%s_t *));\n"
2623             "        for (row = out, i = 0; row; row = g_list_next(row), i++) {\n"
2624             "            (*%s)[i] = assign_%s(row->data);\n"
2625             "        }\n"
2626             "    }\n"
2627             "}\n"
2628             "\n",
2629             cRowName, cPrefix, cRowName,
2630             cPrefix, cRowName,
2631             cRowName, cRowName);
2632     
2633     xfree(cTableName);
2634     xfree(cRowName);
2635     xfree(cModuleName);
2636     xfree(cPrefix);
2637 }
2638
2639
2640
2641 static void
2642 printGetRowMethod(FILE *f, SmiModule *smiModule, SmiNode *rowNode)
2643 {
2644     char       *cPrefix, *cRowName;
2645
2646     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
2647     cRowName = translate(rowNode->name);
2648
2649     fprintf(f,
2650             "void\n"
2651             "%s_get_%s(GNetSnmp *s, %s_%s_t **%s",
2652             cPrefix, cRowName, cPrefix, cRowName, cRowName);
2653     foreachIndexDo(f, rowNode, printIndexParamsFunc, 1, 0);
2654     fprintf(f,
2655             ", gint64 mask)\n"
2656             "{\n"
2657             "    GList *in = NULL, *out = NULL;\n");
2658
2659     fprintf(f,
2660             "    guint32 base[128];\n"
2661             "    gint8 len;\n"
2662             "\n"
2663             "    memcpy(base, %s_oid, sizeof(%s_oid));\n",
2664             cRowName, cRowName);
2665
2666     fprintf(f,
2667             "    len = pack_%s(base",
2668             cRowName);
2669
2670     foreachIndexDo(f, rowNode, printIndexParamsFunc, 0, 0);
2671
2672     fprintf(f,
2673             ");\n"
2674             "    if (len < 0) {\n"
2675             "        g_warning(\"%%s: invalid index values\", \"%s\");\n"
2676             "        s->error_status = GNET_SNMP_PDU_ERR_INTERNAL;\n"
2677             "        return;\n"
2678             "    }\n",
2679             cRowName);
2680
2681     fprintf(f,
2682             "\n"
2683             "    *%s = NULL;\n"
2684             "\n",
2685             cRowName);
2686
2687     fprintf(f,
2688             "    gnet_snmp_attr_get(s, &in, base, len, %u, %s_attr, mask);\n",
2689             rowNode->oidlen, cRowName);
2690
2691     fprintf(f,
2692             "\n"
2693             "    out = gnet_snmp_sync_get(s, in);\n"
2694             "    g_list_foreach(in, (GFunc) gnet_snmp_varbind_delete, NULL);\n"
2695             "    g_list_free(in);\n"
2696             "    if (out) {\n"
2697             "        if (s->error_status != GNET_SNMP_PDU_ERR_NOERROR) {\n"
2698             "            g_list_foreach(out, (GFunc) gnet_snmp_varbind_delete, NULL);\n"
2699             "            g_list_free(out);\n"
2700             "            return;\n"
2701             "        }\n"
2702             "        *%s = assign_%s(out);\n"
2703             "    }\n"
2704             "}\n"
2705             "\n", cRowName, cRowName);
2706     
2707     xfree(cRowName);
2708     xfree(cPrefix);
2709 }
2710
2711
2712
2713 static void
2714 printSetRowMethod(FILE *f, SmiModule *smiModule, SmiNode *rowNode)
2715 {
2716     char         *cPrefix, *cRowName, *cTableName;
2717     SmiNode      *tableNode;
2718
2719     tableNode = smiGetParentNode(rowNode);
2720     if (! tableNode) {
2721         return;
2722     }
2723
2724     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
2725     cRowName = translate(rowNode->name);
2726     cTableName = translate(tableNode->name);
2727
2728     fprintf(f,
2729             "void\n"
2730             "%s_set_%s(GNetSnmp *s, %s_%s_t *%s, gint64 mask)\n"
2731             "{\n"
2732             "    GList *in = NULL, *out = NULL;\n",
2733             cPrefix, cRowName, cPrefix, cRowName, cRowName);
2734
2735     fprintf(f,
2736             "    guint32 base[128];\n"
2737             "    gint8 len;\n"
2738             "\n"
2739             "    memcpy(base, %s_oid, sizeof(%s_oid));\n",
2740             cRowName, cRowName);
2741
2742     fprintf(f,
2743             "    len = pack_%s(base", cRowName);
2744
2745     foreachIndexDo(f, rowNode, printIndexParamsPassFunc, 0, 0);
2746
2747     fprintf(f,
2748             ");\n"
2749             "    if (len < 0) {\n"
2750             "        g_warning(\"%%s: invalid index values\", \"%s\");\n"
2751             "        s->error_status = GNET_SNMP_PDU_ERR_INTERNAL;\n"
2752             "        return;\n"
2753             "    }\n"
2754             "\n",
2755             cRowName);
2756
2757     fprintf(f,
2758             "    gnet_snmp_attr_set(s, &in, base, len, %u, %s_attr, mask, %s);\n",
2759             rowNode->oidlen, cRowName, cRowName);
2760
2761     fprintf(f,
2762             "\n"
2763             "    out = gnet_snmp_sync_set(s, in);\n"
2764             "    g_list_foreach(in, (GFunc) gnet_snmp_varbind_delete, NULL);\n"
2765             "    g_list_free(in);\n"
2766             "    if (out) {\n"
2767             "        g_list_foreach(out, (GFunc) gnet_snmp_varbind_delete, NULL);\n"
2768             "        g_list_free(out);\n"
2769             "    }\n"
2770             "}\n"
2771             "\n");
2772
2773     xfree(cTableName);
2774     xfree(cRowName);
2775     xfree(cPrefix);
2776 }
2777
2778
2779
2780 static void
2781 printCreateMethod(FILE *f, SmiNode *groupNode, SmiNode *smiNode)
2782 {
2783     char        *cPrefix, *cNodeName, *cGroupName;
2784     char        *dModuleName, *dNodeName;
2785     SmiModule   *smiModule;
2786
2787     smiModule = smiGetNodeModule(smiNode);
2788
2789     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
2790     dModuleName = translateUpper(smiModule->name);
2791     cGroupName = translate(groupNode->name);
2792     cNodeName = translate(smiNode->name);
2793     dNodeName = translateUpper(smiNode->name);
2794
2795     fprintf(f,
2796             "void\n"
2797             "%s_create_%s(GNetSnmp *s",
2798             cPrefix, cGroupName);
2799
2800     foreachIndexDo(f, groupNode, printIndexParamsFunc, 1, 0);
2801     
2802     fprintf(f,
2803             ")\n"
2804             "{\n"
2805             "    %s_%s_t *%s;\n"
2806             "    gint32 create = 4; /* SNMPv2-TC::RowStatus createAndGo */\n"
2807             "\n",
2808             cPrefix, cGroupName, cGroupName);
2809
2810     fprintf(f,
2811             "    %s = %s_new_%s();\n",
2812             cGroupName, cPrefix, cGroupName);
2813
2814     foreachIndexDo(f, groupNode, printIndexAssignmentFunc, 0, 0);
2815
2816     fprintf(f, "    %s->%s = &create;\n",
2817             cGroupName, cNodeName);
2818
2819     fprintf(f,
2820             "    %s_set_%s(s, %s, %s_%s);\n"
2821             "    %s_free_%s(%s);\n",
2822             cPrefix, cGroupName, cGroupName,
2823             dModuleName, dNodeName,
2824             cPrefix, cGroupName, cGroupName);
2825
2826     fprintf(f,
2827             "}\n"
2828             "\n");
2829
2830     xfree(dNodeName);
2831     xfree(cNodeName);
2832     xfree(cGroupName);
2833     xfree(dModuleName);
2834     xfree(cPrefix);
2835 }
2836
2837
2838
2839 static void
2840 printDeleteMethod(FILE *f, SmiNode *groupNode, SmiNode *smiNode)
2841 {
2842     char        *cPrefix, *cNodeName, *cGroupName;
2843     char        *dModuleName, *dNodeName;
2844     SmiModule   *smiModule;
2845
2846     smiModule = smiGetNodeModule(smiNode);
2847
2848     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
2849     dModuleName = translateUpper(smiModule->name);
2850     cGroupName = translate(groupNode->name);
2851     cNodeName = translate(smiNode->name);
2852     dNodeName = translateUpper(smiNode->name);
2853
2854     fprintf(f,
2855             "void\n"
2856             "%s_delete_%s(GNetSnmp *s",
2857             cPrefix, cGroupName);
2858
2859     foreachIndexDo(f, groupNode, printIndexParamsFunc, 1, 0);
2860     
2861     fprintf(f,
2862             ")\n"
2863             "{\n"
2864             "    %s_%s_t *%s;\n"
2865             "    gint32 destroy = 6; /* SNMPv2-TC::RowStatus destroy */\n"
2866             "\n",
2867             cPrefix, cGroupName, cGroupName);
2868
2869     fprintf(f,
2870             "    %s_get_%s(s, &%s",
2871             cPrefix, cGroupName, cGroupName);
2872
2873     foreachIndexDo(f, groupNode, printIndexParamsFunc, 0, 0);
2874     
2875     fprintf(f,
2876             ", %s_%s);\n"
2877             "    if (s->error_status || !%s) return;\n",
2878             dModuleName, dNodeName,
2879             cGroupName);
2880
2881     fprintf(f, "    %s->%s = &destroy;\n",
2882             cGroupName, cNodeName);
2883
2884     fprintf(f,
2885             "    %s_set_%s(s, %s, %s_%s);\n"
2886             "    %s_free_%s(%s);\n",
2887             cPrefix, cGroupName, cGroupName,
2888             dModuleName, dNodeName,
2889             cPrefix, cGroupName, cGroupName);
2890
2891     fprintf(f,
2892             "}\n"
2893             "\n");
2894
2895     xfree(dNodeName);
2896     xfree(cNodeName);
2897     xfree(cGroupName);
2898     xfree(dModuleName);
2899     xfree(cPrefix);
2900 }
2901
2902
2903
2904 static void
2905 printSetMethod(FILE *f, SmiNode *groupNode, SmiNode *smiNode)
2906 {
2907     char        *cPrefix, *cNodeName, *cGroupName;
2908     char        *dModuleName, *dNodeName;
2909     SmiType     *smiType;
2910     SmiModule   *smiModule;
2911     unsigned    minSize, maxSize;
2912
2913     smiModule = smiGetNodeModule(smiNode);
2914     smiType = smiGetNodeType(smiNode);
2915     if (! smiType) {
2916         return;
2917     }
2918
2919     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
2920     dModuleName = translateUpper(smiModule->name);
2921     cGroupName = translate(groupNode->name);
2922     cNodeName = translate(smiNode->name);
2923     dNodeName = translateUpper(smiNode->name);
2924
2925     fprintf(f,
2926             "void\n"
2927             "%s_set_%s(GNetSnmp *s",
2928             cPrefix, cNodeName);
2929
2930     foreachIndexDo(f, groupNode, printIndexParamsFunc, 1, 0);
2931     printParam(f, smiNode);
2932     
2933     fprintf(f,
2934             ")\n"
2935             "{\n"
2936             "    %s_%s_t *%s;\n"
2937             "\n", cPrefix, cGroupName, cGroupName);
2938
2939     fprintf(f,
2940             "    %s_get_%s(s, &%s",
2941             cPrefix, cGroupName, cGroupName);
2942
2943     foreachIndexDo(f, groupNode, printIndexParamsFunc, 0, 0);
2944     
2945     fprintf(f,
2946             ", %s_%s);\n"
2947             "    if (s->error_status || !%s) return;\n",
2948             dModuleName, dNodeName,
2949             cGroupName);
2950
2951     switch (smiType->basetype) {
2952     case SMI_BASETYPE_OBJECTIDENTIFIER:
2953     case SMI_BASETYPE_OCTETSTRING:
2954         maxSize = smiGetMaxSize(smiType);
2955         minSize = smiGetMinSize(smiType);
2956         fprintf(f, "    %s->%s = %s;\n",
2957                 cGroupName, cNodeName, cNodeName);
2958         if (minSize != maxSize) {
2959             fprintf(f, "    %s->_%sLength = _%sLength;\n",
2960                     cGroupName, cNodeName, cNodeName);
2961         }
2962         break;
2963     case SMI_BASETYPE_UNSIGNED32:
2964     case SMI_BASETYPE_ENUM:
2965     case SMI_BASETYPE_INTEGER32:
2966         fprintf(f, "    %s->%s = &%s;\n",
2967                 cGroupName, cNodeName, cNodeName);
2968         break;
2969     default:
2970         fprintf(f, "    /* ?? */\n");
2971         break;
2972     }
2973
2974     fprintf(f,
2975             "    %s_set_%s(s, %s, %s_%s);\n"
2976             "    %s_free_%s(%s);\n",
2977             cPrefix, cGroupName, cGroupName,
2978             dModuleName, dNodeName,
2979             cPrefix, cGroupName, cGroupName);
2980
2981     fprintf(f,
2982             "}\n"
2983             "\n");
2984
2985     xfree(dNodeName);
2986     xfree(cNodeName);
2987     xfree(cGroupName);
2988     xfree(dModuleName);
2989     xfree(cPrefix);
2990 }
2991
2992
2993
2994 static void
2995 printGetScalarsMethod(FILE *f, SmiModule *smiModule, SmiNode *groupNode)
2996 {
2997     char         *cPrefix, *cGroupName;
2998     unsigned int i;
2999
3000     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
3001     cGroupName = translate(groupNode->name);
3002
3003     fprintf(f,
3004             "void\n"
3005             "%s_get_%s(GNetSnmp *s, %s_%s_t **%s, gint64 mask)\n"
3006             "{\n"
3007             "    GList *in = NULL, *out = NULL;\n",
3008             cPrefix, cGroupName, cPrefix, cGroupName, cGroupName);
3009
3010     fprintf(f, "    static const guint32 _base[] = {");
3011     for (i = 0; i < groupNode->oidlen; i++) {
3012         fprintf(f, "%u, ", groupNode->oid[i]);
3013     }
3014     fprintf(f, "0};\n");
3015     fprintf(f, "    guint32 base[128];\n");
3016
3017     fprintf(f,
3018             "\n"
3019             "    *%s = NULL;\n"
3020             "    memcpy(base, _base, sizeof(_base));\n"
3021             "\n",
3022             cGroupName);
3023
3024     fprintf(f,
3025             "    gnet_snmp_attr_get(s, &in, base, %u, %u, %s_attr, mask);\n",
3026             groupNode->oidlen + 1, groupNode->oidlen, cGroupName);
3027
3028     fprintf(f,
3029             "\n"
3030             "    out = gnet_snmp_sync_getnext(s, in);\n"
3031             "    g_list_foreach(in, (GFunc) gnet_snmp_varbind_delete, NULL);\n"
3032             "    g_list_free(in);\n"
3033             "    if (out) {\n"
3034             "        if (s->error_status != GNET_SNMP_PDU_ERR_NOERROR) {\n"
3035             "            g_list_foreach(out, (GFunc) gnet_snmp_varbind_delete, NULL);\n"
3036             "            g_list_free(out);\n"
3037             "            return;\n"
3038             "        }\n"
3039             "        *%s = assign_%s(out);\n"
3040             "    }\n"
3041             "}\n"
3042             "\n", cGroupName, cGroupName);
3043     
3044     xfree(cGroupName);
3045     xfree(cPrefix);
3046 }
3047
3048
3049
3050 static void
3051 printSetScalarsMethod(FILE *f, SmiModule *smiModule, SmiNode *groupNode)
3052 {
3053     char         *cPrefix, *cGroupName;
3054     unsigned int i;
3055
3056     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
3057     cGroupName = translate(groupNode->name);
3058
3059     fprintf(f,
3060             "void\n"
3061             "%s_set_%s(GNetSnmp *s, %s_%s_t *%s, gint64 mask)\n"
3062             "{\n"
3063             "    GList *in = NULL, *out = NULL;\n",
3064             cPrefix, cGroupName, cPrefix, cGroupName, cGroupName);
3065
3066     fprintf(f, "    static guint32 base[] = {");
3067     for (i = 0; i < groupNode->oidlen; i++) {
3068         fprintf(f, "%u, ", groupNode->oid[i]);
3069     }
3070     fprintf(f, "0, 0};\n\n");
3071
3072     fprintf(f,
3073             "    gnet_snmp_attr_set(s, &in, base, %u, %u, %s_attr, mask, %s);\n",
3074             groupNode->oidlen + 2, groupNode->oidlen, cGroupName, cGroupName);
3075
3076     fprintf(f,
3077             "\n"
3078             "    out = gnet_snmp_sync_set(s, in);\n"
3079             "    g_list_foreach(in, (GFunc) gnet_snmp_varbind_delete, NULL);\n"
3080             "    g_list_free(in);\n"
3081             "    if (out) {\n"
3082             "        g_list_foreach(out, (GFunc) gnet_snmp_varbind_delete, NULL);\n"
3083             "        g_list_free(out);\n"
3084             "    }\n"
3085             "}\n"
3086             "\n");
3087
3088     xfree(cGroupName);
3089     xfree(cPrefix);
3090 }
3091
3092
3093
3094 static void
3095 printNewMethod(FILE *f, SmiModule *smiModule, SmiNode *groupNode)
3096 {
3097     char *cPrefix, *cGroupName;
3098
3099     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
3100     cGroupName = translate(groupNode->name);
3101
3102     fprintf(f,
3103             "%s_%s_t *\n"
3104             "%s_new_%s()\n"
3105             "{\n"
3106             "    %s_%s_t *%s;\n"
3107             "\n",
3108             cPrefix, cGroupName,
3109             cPrefix, cGroupName,
3110             cPrefix, cGroupName, cGroupName);
3111
3112     fprintf(f,
3113             "    %s = (%s_%s_t *) g_malloc0(sizeof(%s_%s_t) + sizeof(gpointer));\n"
3114             "    return %s;\n"
3115             "}\n"
3116             "\n",
3117             cGroupName, cPrefix, cGroupName,
3118             cPrefix, cGroupName, cGroupName);
3119
3120     xfree(cGroupName);
3121     xfree(cPrefix);
3122 }
3123
3124
3125
3126 static void
3127 printFreeTableMethod(FILE *f, SmiModule *smiModule, SmiNode *groupNode)
3128 {
3129     SmiNode *tableNode;
3130     char *cPrefix, *cGroupName, *cTableName;
3131
3132     tableNode = smiGetParentNode(groupNode);
3133     if (! tableNode) {
3134         return;
3135     }
3136
3137     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
3138     cGroupName = translate(groupNode->name);
3139     cTableName = translate(tableNode->name);
3140
3141     fprintf(f,
3142             "void\n"
3143             "%s_free_%s(%s_%s_t **%s)\n"
3144             "{\n"
3145             "    int i;\n"
3146             "\n",
3147             cPrefix, cTableName, cPrefix, cGroupName, cGroupName);
3148
3149     fprintf(f,      
3150             "    if (%s) {\n"
3151             "        for (i = 0; %s[i]; i++) {\n"
3152             "            %s_free_%s(%s[i]);\n"
3153             "        }\n"
3154             "        g_free(%s);\n"
3155             "    }\n"
3156             "}\n"
3157             "\n",
3158             cGroupName, cGroupName, cPrefix,
3159             cGroupName, cGroupName, cGroupName);
3160
3161     xfree(cTableName);
3162     xfree(cGroupName);
3163     xfree(cPrefix);
3164 }
3165  
3166
3167
3168
3169 static void
3170 printFreeMethod(FILE *f, SmiModule *smiModule, SmiNode *groupNode)
3171 {
3172     char *cPrefix, *cGroupName;
3173
3174     cPrefix = prefix ? xstrdup(prefix) : translateLower(smiModule->name);
3175     cGroupName = translate(groupNode->name);
3176
3177     fprintf(f,
3178             "void\n"
3179             "%s_free_%s(%s_%s_t *%s)\n"
3180             "{\n"
3181             "    GList *vbl;\n"
3182             "    char *p;\n"
3183             "\n",
3184             cPrefix, cGroupName, cPrefix, cGroupName, cGroupName);
3185
3186     fprintf(f,      
3187             "    if (%s) {\n"
3188             "        p = (char *) %s + sizeof(%s_%s_t);\n"
3189             "        vbl = * (GList **) p;\n"
3190             "        g_list_foreach(vbl, (GFunc) gnet_snmp_varbind_delete, NULL);\n"
3191             "        g_list_free(vbl);\n"
3192             "        g_free(%s);\n"
3193             "    }\n"
3194             "}\n"
3195             "\n",
3196             cGroupName, cGroupName, cPrefix, cGroupName, cGroupName);
3197
3198     xfree(cGroupName);
3199     xfree(cPrefix);
3200 }
3201  
3202
3203
3204
3205 static void
3206 printStubMethod2(FILE *f, SmiNode *groupNode)
3207 {
3208     SmiNode *smiNode;
3209     SmiType *smiType;
3210
3211     for (smiNode = smiGetFirstChildNode(groupNode);
3212          smiNode;
3213          smiNode = smiGetNextChildNode(smiNode)) {
3214         if (smiNode->nodekind & (SMI_NODEKIND_COLUMN | SMI_NODEKIND_SCALAR)
3215             && (smiNode->access >= SMI_ACCESS_READ_ONLY)) {
3216             if (smiNode->access == SMI_ACCESS_READ_WRITE) {
3217                 smiType = smiGetNodeType(smiNode);
3218                 if (smiType && smiType->name
3219                     && strcmp(smiType->name, "RowStatus") == 0) {
3220                     if (cflag) printCreateMethod(f, groupNode, smiNode);
3221                     if (dflag) printDeleteMethod(f, groupNode, smiNode);
3222                 } else {
3223                     if (! isIndex(groupNode, smiNode)) {
3224                         if (sflag) printSetMethod(f, groupNode, smiNode);
3225                     }
3226                 }
3227             }
3228         }           
3229     }
3230 }
3231
3232
3233
3234 static void
3235 printStubMethods(FILE *f, SmiModule *smiModule)
3236 {
3237     SmiNode   *smiNode;
3238     int       cnt = 0;
3239     const unsigned int groupkind = SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN;
3240     
3241     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
3242          smiNode;
3243          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
3244         if (isGroup(smiNode, groupkind) && isAccessible(smiNode)) {
3245             cnt++;
3246             printNewMethod(f, smiModule, smiNode);
3247             printAssignMethod(f, smiModule, smiNode);
3248             if (smiNode->nodekind == SMI_NODEKIND_ROW) {
3249                 printGetTableMethod(f, smiModule, smiNode);
3250                 printGetRowMethod(f, smiModule, smiNode);
3251                 if (isWritable(smiNode, SMI_NODEKIND_COLUMN)) {
3252                     printSetRowMethod(f, smiModule, smiNode);
3253                 }
3254             } else {
3255                 printGetScalarsMethod(f, smiModule, smiNode);
3256                 if (isWritable(smiNode, SMI_NODEKIND_SCALAR)) {
3257                     printSetScalarsMethod(f, smiModule, smiNode);
3258                 }
3259             }
3260             printFreeMethod(f, smiModule, smiNode);
3261             if (smiNode->nodekind == SMI_NODEKIND_ROW) {
3262                 printFreeTableMethod(f, smiModule, smiNode);
3263             }
3264             printStubMethod2(f, smiNode);
3265         }
3266     }
3267     
3268     if (cnt) {
3269         fprintf(f, "\n");
3270     }
3271 }
3272
3273
3274
3275 static void
3276 dumpStubs(SmiModule *smiModule, char *baseName)
3277 {
3278     FILE *f;
3279
3280     f = createFile(baseName, ".c");
3281     if (! f) {
3282         return;
3283     }
3284
3285     fprintTopComment(f, smiModule);
3286
3287     fprintf(f,
3288             "#include \"%s.h\"\n"
3289             "\n",
3290             baseName);
3291
3292     printStubEnumerations(f, smiModule);
3293     printStubIdentities(f, smiModule);
3294     printStubNotifications(f, smiModule);
3295
3296     printStubContraints(f, smiModule);
3297     printStubAttributes(f, smiModule);
3298     printStubMethods(f, smiModule);
3299     
3300     if (fflush(f) || ferror(f)) {
3301         perror("smidump: write error");
3302         exit(1);
3303     }
3304
3305     fclose(f);
3306 }
3307
3308
3309
3310 static void
3311 dumpScli(int modc, SmiModule **modv, int flags, char *output)
3312 {
3313     char        *baseName;
3314     int         i, code;
3315
3316     if (include) {
3317         incl_regex = &_incl_regex;
3318         code = regcomp(incl_regex, include, REG_EXTENDED|REG_NOSUB);
3319         if (code != 0) {
3320             char buffer[256];
3321             regerror(code, incl_regex, buffer, sizeof(buffer));
3322             fprintf(stderr, "smidump: regular expression error: %s\n", buffer);
3323             exit(1);
3324         }
3325     }
3326
3327     if (exclude) {
3328         excl_regex = &_excl_regex;
3329         code = regcomp(excl_regex, exclude, REG_EXTENDED|REG_NOSUB);
3330         if (code != 0) {
3331             char buffer[256];
3332             regerror(code, excl_regex, buffer, sizeof(buffer));
3333             fprintf(stderr, "smidump: regular expression error: %s\n", buffer);
3334             if (incl_regex) {
3335                 regfree(incl_regex);
3336             }
3337             exit(1);
3338         }
3339     }
3340
3341     if (flags & SMIDUMP_FLAG_UNITE) {
3342         /* not implemented yet */
3343     } else {
3344         for (i = 0; i < modc; i++) {
3345             baseName = output ? output : translateFileName(modv[i]->name);
3346             dumpHeader(modv[i], baseName);
3347             dumpStubs(modv[i], baseName);
3348             if (! output) xfree(baseName);
3349         }
3350     }
3351
3352     if (incl_regex) {
3353         regfree(incl_regex);
3354         incl_regex = NULL;
3355     }
3356     if (excl_regex) {
3357         regfree(excl_regex);
3358         excl_regex = NULL;
3359     }
3360 }
3361
3362
3363
3364 void initScli()
3365 {
3366     static SmidumpDriverOption opt[] = {
3367         { "prefix", OPT_STRING, &prefix, 0,
3368           "use prefix instead of module name in stubs"},
3369         { "include", OPT_STRING, &include, 0,
3370           "include stubs for groups matching a regex"},
3371         { "exclude", OPT_STRING, &exclude, 0,
3372           "exclude stubs for groups matching a regex"},
3373         { "set", OPT_FLAG, &sflag, 0,
3374           "generate set stubs for writable objects"},
3375         { "create", OPT_FLAG, &cflag, 0,
3376           "generate create stubs for tables using RowStatus"},
3377         { "delete", OPT_FLAG, &dflag, 0,
3378           "generate delete stubs for tables using RowStatus"},
3379         { 0, OPT_END, 0, 0 }
3380     };
3381
3382     static SmidumpDriver driver = {
3383         "scli",
3384         dumpScli,
3385         0,
3386         SMIDUMP_DRIVER_CANT_UNITE,
3387         "ANSI C manager stubs for the gsnmp package",
3388         opt,
3389         NULL
3390     };
3391
3392     smidumpRegisterDriver(&driver);
3393 }