Imported Upstream version 0.4.8
[platform/upstream/libsmi.git] / lib / smi.c
1 /*
2  * smi.c --
3  *
4  *      Interface Implementation of libsmi.
5  *
6  * Copyright (c) 1999 Frank Strauss, Technical University of Braunschweig.
7  *
8  * See the file "COPYING" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  * @(#) $Id: smi.c 8071 2008-04-17 11:14:46Z schoenw $
12  */
13
14 #include <config.h>
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <sys/types.h>
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24 #ifdef HAVE_PWD_H
25 #include <pwd.h>
26 #endif
27
28 #include "smi.h"
29 #include "data.h"
30 #include "error.h"
31 #include "util.h"
32 #include "snprintf.h"
33
34 #ifdef BACKEND_SMI
35 #include "scanner-smi.h"
36 #include "parser-smi.h"
37 #endif
38
39 #ifdef BACKEND_SMING
40 #include "scanner-sming.h"
41 #include "parser-sming.h"
42 #endif
43
44 #ifdef HAVE_DMALLOC_H
45 #include <dmalloc.h>
46 #endif
47
48
49
50 #ifndef MIN
51 #define MIN(a, b)       ((a) < (b) ? (a) : (b))
52 #define MAX(a, b)       ((a) < (b) ? (b) : (a))
53 #endif
54
55
56
57 const char *smi_library_version = SMI_LIBRARY_VERSION;
58 const char *smi_version_string = SMI_VERSION_STRING;
59
60 Handle *smiHandle = NULL;
61
62
63
64 /*
65  * Internal functions.
66  */
67
68 static void getModulenameAndName(const char *arg1, const char *arg2,
69                                  char **module, char **name)
70 {
71     char            *p;
72     int             l;
73
74     if ((!arg1) && (!arg2)) {
75         *module = NULL;
76         *name = NULL;
77     } else if (!arg2) {
78         if (isupper((int)arg1[0])) {
79             if ((p = strstr(arg1, "::"))) {
80                 /* SMIng style module/label separator */
81                 *name = smiStrdup(&p[2]);
82                 l = strcspn(arg1, "::");
83                 *module = smiStrndup(arg1, l);
84             } else if ((p = strchr(arg1, '!'))) {
85                 /* old scotty style module/label separator */
86                 *name = smiStrdup(&p[1]);
87                 l = strcspn(arg1, "!");
88                 *module = smiStrndup(arg1, l);
89             } else if ((p = strchr(arg1, '.'))) {
90                 /* SMIv1/v2 style module/label separator */
91                 *name = smiStrdup(&p[1]);
92                 l = strcspn(arg1, ".");
93                 *module = smiStrndup(arg1, l);
94             } else {
95                 *name = smiStrdup(arg1);
96                 *module = smiStrdup("");
97             }
98         } else {
99             *name = smiStrdup(arg1);
100             *module = smiStrdup("");
101         }
102     } else if (!arg1) {
103         if (isupper((int)arg2[0])) {
104             if ((p = strstr(arg2, "::"))) {
105                 /* SMIng style module/label separator */
106                 *name = smiStrdup(&p[2]);
107                 l = strcspn(arg2, "::");
108                 *module = smiStrndup(arg2, l);
109             } else if ((p = strchr(arg2, '!'))) {
110                 /* old scotty style module/label separator */
111                 *name = smiStrdup(&p[1]);
112                 l = strcspn(arg2, "!");
113                 *module = smiStrndup(arg2, l);
114             } else if ((p = strchr(arg2, '.'))) {
115                 /* SMIv1/v2 style module/label separator */
116                 *name = smiStrdup(&p[1]);
117                 l = strcspn(arg2, ".");
118                 *module = smiStrndup(arg2, l);
119             } else {
120                 *name = smiStrdup(arg2);
121                 *module = smiStrdup("");
122             }
123         } else {
124             *name = smiStrdup(arg2);
125             *module = smiStrdup("");
126         }
127     } else {
128         *module = smiStrdup(arg1);
129         *name = smiStrdup(arg2);
130     }
131 }
132
133
134
135 static Node *getNode(unsigned int oidlen, SmiSubid oid[])
136 {
137     Node *nodePtr, *parentPtr;
138     unsigned int i;
139
140     for(nodePtr = smiHandle->rootNodePtr, i=0; i < oidlen; i++) {
141         parentPtr = nodePtr;
142         nodePtr = findNodeByParentAndSubid(parentPtr, oid[i]);
143         if (!nodePtr) {
144             return parentPtr;
145         }
146     }
147     
148     return nodePtr;
149 }
150
151
152
153 static Object *getNextChildObject(Node *startNodePtr, Module *modulePtr,
154                                   SmiNodekind nodekind)
155 {
156     Node   *nodePtr;
157     Object *objectPtr = NULL;
158
159     if (!startNodePtr || !modulePtr)
160         return NULL;
161
162     for (nodePtr = startNodePtr; nodePtr; nodePtr = nodePtr->nextPtr) {
163         for (objectPtr = nodePtr->firstObjectPtr; objectPtr;
164              objectPtr = objectPtr->nextSameNodePtr) {
165             if (((!modulePtr) || (objectPtr->modulePtr == modulePtr)) &&
166                 ((nodekind == SMI_NODEKIND_ANY) ||
167                  (nodekind & objectPtr->export.nodekind))) {
168                 break;
169             }
170         }
171         if (objectPtr) break;
172         objectPtr = getNextChildObject(nodePtr->firstChildPtr,
173                                        modulePtr, nodekind);
174         if (objectPtr) break;
175     }
176
177     return objectPtr;
178 }
179
180
181
182 /*
183  * Interface Functions.
184  */
185
186 int smiInit(const char *tag)
187 {
188     char *p, *pp, *tag2;
189 #ifdef HAVE_PWD_H
190     struct passwd *pw;
191 #endif
192
193     smiHandle = findHandleByName(tag);
194     if (smiHandle) {
195         return 0;
196     }
197     smiHandle = addHandle(tag);
198     
199     smiDepth = 0;
200
201     smiHandle->errorLevel = DEFAULT_ERRORLEVEL;
202     smiHandle->errorHandler = smiErrorHandler;
203 #if !defined(_MSC_VER)
204     smiHandle->cache = NULL;
205     smiHandle->cacheProg = NULL;
206 #endif
207     
208     if (smiInitData()) {
209         return -1;
210     }
211
212     /*
213      * Setup the SMI MIB module search path:
214      *  1. set to builtin DEFAULT_SMIPATH
215      *  2. read global config file if present (append/prepend/replace)
216      *  3. read user config file if present (append/prepend/replace)
217      *  4. evaluate SMIPATH env-var if set (append/prepend/replace)
218      */
219
220     /* 1. set to builtin DEFAULT_SMIPATH */
221     smiHandle->path = smiStrdup(DEFAULT_SMIPATH);
222
223     tag2 = smiStrdup(tag);
224     if (tag2) tag2 = strtok(tag2, ":");
225     if (tag2) {
226         /* 2. read global config file if present (append/prepend/replace) */
227         smiReadConfig(DEFAULT_GLOBALCONFIG, tag2);
228 #ifdef HAVE_PWD_H
229         pw = getpwuid(getuid());
230         if (pw && pw->pw_dir) {
231             /* 3. read user config file if present (append/prepend/replace) */
232             smiAsprintf(&p, "%s%c%s",
233                         pw->pw_dir, DIR_SEPARATOR, DEFAULT_USERCONFIG);
234             smiReadConfig(p, tag2);
235             smiFree(p);
236         }
237 #endif
238     }
239     smiFree(tag2);
240
241     /* 4. evaluate SMIPATH env-var if set (append/prepend/replace) */
242     p = getenv("SMIPATH");
243     if (p) {
244         if (p[0] == PATH_SEPARATOR) {
245             smiAsprintf(&pp, "%s%s", smiHandle->path, p);
246             smiFree(smiHandle->path);
247             smiHandle->path = pp;
248         } else if (p[strlen(p)-1] == PATH_SEPARATOR) {
249             smiAsprintf(&pp, "%s%s", p, smiHandle->path);
250             smiFree(smiHandle->path);
251             smiHandle->path = pp;
252         } else {
253             smiHandle->path = smiStrdup(p);
254         }
255     }
256     
257     if (!smiHandle->path) {
258         return -1;
259     }
260
261     return 0;
262 }
263
264
265
266 void smiExit()
267 {
268     if (!smiHandle)
269         return;
270
271     smiFreeData();
272
273     smiFree(smiHandle->path);
274 #if !defined(_MSC_VER)
275     smiFree(smiHandle->cache);
276     smiFree(smiHandle->cacheProg);
277 #endif
278     
279     removeHandle(smiHandle);
280     
281     smiHandle = NULL;
282     return;
283 }
284
285
286
287 char *smiGetPath()
288 {
289     if (smiHandle->path) {
290         return smiStrdup(smiHandle->path);
291     } else {
292         return NULL;
293     }
294 }
295
296
297
298 int smiSetPath(const char *s)
299 {
300     char *s2;
301
302     if (!smiHandle) smiInit(NULL);
303
304     if (!s) {
305         smiFree(smiHandle->path);
306         smiHandle->path = NULL;
307         return 0;
308     }
309     
310     s2 = smiStrdup(s);
311     if (s2) {
312         smiFree(smiHandle->path);
313         smiHandle->path = s2;
314         return 0;
315     } else {
316         return -1;
317     }
318     
319 }
320
321
322
323 void smiSetSeverity(char *pattern, int severity)
324 {
325     smiSetErrorSeverity(pattern, severity);
326 }
327
328
329
330 int smiReadConfig(const char *filename, const char *tag)
331 {
332     FILE *file;
333     char buf[201];
334     char *cmd, *arg, *s;
335     
336     file = fopen(filename, "r");
337     if (file) {
338         while (!feof(file)) {
339             if (!fgets(buf, 200, file)) continue;
340             if ((!strlen(buf)) || (buf[0] == '#')) continue;
341             cmd = strtok(buf, " \t\n\r");
342             if (!cmd) continue;
343             if (cmd[0] == '#') continue;
344             if (cmd[strlen(cmd)-1] == ':') {
345                 if (!tag) continue;
346                 cmd[strlen(cmd)-1] = 0;
347                 if (strcmp(cmd, tag)) continue;
348                 cmd = strtok(NULL, " \t\n\r");
349             }
350             arg = strtok(NULL, " \t\n\r");
351             if (!strcmp(cmd, "load")) {
352                 smiLoadModule(arg);
353             } else if (!strcmp(cmd, "path")) {
354                 if (arg) {
355                     if (arg[0] == PATH_SEPARATOR) {
356                         smiAsprintf(&s, "%s%s", smiHandle->path, arg);
357                         smiFree(smiHandle->path);
358                         smiHandle->path = s;
359                     } else if (arg[strlen(arg)-1] == PATH_SEPARATOR) {
360                         smiAsprintf(&s, "%s%s", arg, smiHandle->path);
361                         smiFree(smiHandle->path);
362                         smiHandle->path = s;
363                     } else {
364                         smiHandle->path = smiStrdup(arg);
365                     }
366                 }
367             } else if (!strcmp(cmd, "cache")) {
368 #if !defined(_MSC_VER)
369                 smiFree(smiHandle->cache);
370                 smiFree(smiHandle->cacheProg);
371 #endif
372                 if (arg && strcmp(arg, "off")) {
373 #if !defined(_MSC_VER)
374                     smiHandle->cache = smiStrdup(arg);
375                     arg = strtok(NULL, "\n\r");
376                     smiHandle->cacheProg = smiStrdup(arg);
377 #else
378                     smiPrintError(NULL, ERR_CACHE_CONFIG_NOT_SUPPORTED,
379                                   filename);
380 #endif
381                 }
382             } else if (!strcmp(cmd, "level")) {
383                 smiSetErrorLevel(atoi(arg));
384             } else if (!strcmp(cmd, "hide")) {
385                 smiSetSeverity(arg, 9);
386             } else {
387                 smiPrintError(NULL, ERR_UNKNOWN_CONFIG_CMD, cmd, filename);
388             }
389         }
390         fclose(file);
391         return 0;
392     }
393     return -1;
394 }
395
396
397
398 int smiIsLoaded(const char *module)
399 {
400     if (!module)
401         return 0;
402     
403     return isInView(module);
404 }
405
406
407
408 char *smiLoadModule(const char *module)
409 {
410     Module *modulePtr;
411     
412     if (!smiHandle) smiInit(NULL);
413
414     if (smiIsPath(module)) {
415
416         modulePtr = loadModule(module, NULL);
417
418         if (modulePtr) {
419             if (!isInView(modulePtr->export.name)) {
420                 addView(modulePtr->export.name);
421             }
422             return modulePtr->export.name;
423         } else {
424             return NULL;
425         }
426
427     } else {
428         
429         if ((modulePtr = findModuleByName(module))) {
430             /* already loaded. */
431             if (!isInView(module)) {
432                 addView(module);
433             }
434             return modulePtr->export.name;
435         } else {
436             if ((modulePtr = loadModule(module, NULL))) {
437                 if (!isInView(module)) {
438                     addView(module);
439                 }
440                 return modulePtr->export.name;
441             } else {
442                 return NULL;
443             }
444         }
445     }
446 }
447  
448
449
450 void smiSetErrorLevel(int level)
451 {
452     if (!smiHandle) smiInit(NULL);
453     
454     smiHandle->errorLevel = level;
455 }
456
457
458
459 void smiSetFlags(int userflags)
460 {
461     if (!smiHandle) smiInit(NULL);
462     
463     smiHandle->flags = (smiHandle->flags & ~SMI_FLAG_MASK) | userflags;
464 }
465
466
467
468 int smiGetFlags()
469 {
470     if (!smiHandle) smiInit(NULL);
471     
472     return smiHandle->flags & SMI_FLAG_MASK;
473 }
474
475
476
477 SmiModule *smiGetModule(const char *module)
478 {
479     Module            *modulePtr;
480     
481     if (!module) {
482         return NULL;
483     }
484
485     modulePtr = findModuleByName(module);
486     
487     if (!modulePtr) {
488         modulePtr = loadModule(module, NULL);
489     }
490     
491     return &modulePtr->export;
492 }
493
494
495
496 SmiModule *smiGetFirstModule()
497 {
498     Module            *modulePtr;
499
500     for (modulePtr = smiHandle->firstModulePtr;
501          modulePtr && modulePtr->export.name &&
502              (strlen(modulePtr->export.name) == 0);
503          modulePtr = modulePtr->nextPtr);
504
505     return &modulePtr->export;
506 }
507
508
509
510 SmiModule *smiGetNextModule(SmiModule *smiModulePtr)
511 {
512     Module            *modulePtr;
513     
514     if (!smiModulePtr) {
515         return NULL;
516     }
517
518     
519     for (modulePtr = ((Module *)smiModulePtr)->nextPtr;
520          modulePtr && modulePtr->export.name &&
521              (strlen(modulePtr->export.name) == 0);
522          modulePtr = modulePtr->nextPtr);
523
524     return &modulePtr->export;
525 }
526
527
528
529 SmiImport *smiGetFirstImport(SmiModule *smiModulePtr)
530 {
531     if (!smiModulePtr) {
532         return NULL;
533     }
534     
535     return &((Module *)smiModulePtr)->firstImportPtr->export;
536 }
537
538
539
540 SmiImport *smiGetNextImport(SmiImport *smiImportPtr)
541 {
542     if (!smiImportPtr) {
543         return NULL;
544     }
545
546     return &((Import *)smiImportPtr)->nextPtr->export;
547 }
548
549
550
551 int smiIsImported(SmiModule *smiModulePtr,
552                   SmiModule *importedModulePtr,
553                   char *importedName)
554 {
555     Import         *importPtr;
556     Module         *modulePtr;
557     char           *importedModule;
558     
559     if ((!smiModulePtr) || (!importedName)) {
560         return 0;
561     }
562
563     modulePtr = (Module *)smiModulePtr;
564     
565     if (importedModulePtr) {
566         importedModule = importedModulePtr->name;
567     } else {
568         importedModule = NULL;
569     }
570         
571     for (importPtr = modulePtr->firstImportPtr; importPtr;
572          importPtr = importPtr->nextPtr) {
573         if ((!strcmp(importedName, importPtr->export.name)) &&
574             ((!importedModule) ||
575              (!strcmp(importedModule, importPtr->export.module)))) {
576             return 1;
577         }
578     }
579
580     return 0;
581 }
582
583
584
585 SmiRevision *smiGetFirstRevision(SmiModule *smiModulePtr)
586 {
587     if (!smiModulePtr) {
588         return NULL;
589     }
590     
591     return &((Module *)smiModulePtr)->firstRevisionPtr->export;
592 }
593
594
595
596 SmiRevision *smiGetNextRevision(SmiRevision *smiRevisionPtr)
597 {
598     if (!smiRevisionPtr) {
599         return NULL;
600     }
601
602     return &((Revision *)smiRevisionPtr)->nextPtr->export;
603 }
604
605
606
607 int smiGetRevisionLine(SmiRevision *smiRevisionPtr)
608 {
609     return ((Revision *)smiRevisionPtr)->line;
610 }
611
612
613
614 SmiType *smiGetType(SmiModule *smiModulePtr, char *type)
615 {
616     Type            *typePtr = NULL;
617     Module          *modulePtr = NULL;
618     char            *module2, *type2;
619
620     if (!type) {
621         return NULL;
622     }
623
624     modulePtr = (Module *)smiModulePtr;
625
626     getModulenameAndName(smiModulePtr ? smiModulePtr->name : NULL, type,
627                          &module2, &type2);
628     
629     if (!modulePtr && module2 && strlen(module2)) {
630         if (!(modulePtr = findModuleByName(module2))) {
631             modulePtr = loadModule(module2, NULL);
632         }
633     }
634
635     if (modulePtr) {
636         typePtr = findTypeByModuleAndName(modulePtr, type2);
637     } else {
638         typePtr = findTypeByName(type2);
639     }
640     
641     smiFree(module2);
642     smiFree(type2);
643
644     if (!typePtr ||
645         typePtr->export.basetype == SMI_BASETYPE_UNKNOWN) {
646         return NULL;
647     }
648     
649     return &typePtr->export;
650 }
651
652
653
654 SmiType *smiGetFirstType(SmiModule *smiModulePtr)
655 {
656     Type *typePtr;
657     
658     if (!smiModulePtr) {
659         return NULL;
660     }
661     
662     for (typePtr = ((Module *)smiModulePtr)->firstTypePtr; typePtr;
663          typePtr = typePtr->nextPtr) {
664         /* loop until we found a `real' type */
665         if (typePtr->export.name &&
666             typePtr->export.basetype != SMI_BASETYPE_UNKNOWN) {
667             break;
668         }
669     }
670     
671     return &typePtr->export;
672 }
673
674
675
676 SmiType *smiGetNextType(SmiType *smiTypePtr)
677 {
678     Type *typePtr;
679
680     if (!smiTypePtr) {
681         return NULL;
682     }
683
684     for (typePtr = ((Type *)smiTypePtr)->nextPtr; typePtr;
685          typePtr = typePtr->nextPtr) {
686         /* loop until we found a `real' type */
687         if (typePtr->export.name &&
688             typePtr->export.basetype != SMI_BASETYPE_UNKNOWN) {
689             break;
690         }
691     }
692     
693     return &typePtr->export;
694 }
695
696
697 SmiType *smiGetParentType(SmiType *smiTypePtr)
698 {
699     Type *typePtr;
700
701     if (!smiTypePtr) {
702         return NULL;
703     }
704
705     typePtr = ((Type *)smiTypePtr)->parentPtr;
706     
707     if (!typePtr ||
708         typePtr->export.basetype == SMI_BASETYPE_UNKNOWN) {
709         return NULL;
710     }
711     
712     return &typePtr->export;
713 }
714
715
716
717 SmiModule *smiGetTypeModule(SmiType *smiTypePtr)
718 {
719     return &((Type *)smiTypePtr)->modulePtr->export;
720 }
721
722 int smiGetTypeLine(SmiType *smiTypePtr)
723 {
724     return ((Type *)smiTypePtr)->line;
725 }
726
727
728
729 SmiNamedNumber *smiGetFirstNamedNumber(SmiType *smiTypePtr)
730 {
731     Type    *typePtr;
732
733     typePtr = (Type *)smiTypePtr;
734     
735     if ((!typePtr) || (!typePtr->listPtr) ||
736         ((typePtr->export.basetype != SMI_BASETYPE_ENUM) &&
737          (typePtr->export.basetype != SMI_BASETYPE_BITS) && 
738          (typePtr->export.basetype != SMI_BASETYPE_POINTER))) {
739         return NULL;
740     }
741     
742     return &((NamedNumber *)typePtr->listPtr->ptr)->export;
743 }
744
745
746
747 SmiNamedNumber *smiGetNextNamedNumber(SmiNamedNumber *smiNamedNumberPtr)
748 {
749     Type  *typePtr;
750     List  *listPtr;
751     
752     if (!smiNamedNumberPtr) {
753         return NULL;
754     }
755     
756     typePtr = ((NamedNumber *)smiNamedNumberPtr)->typePtr;
757
758     
759     if ((!typePtr) || (!typePtr->listPtr) ||
760         ((typePtr->export.basetype != SMI_BASETYPE_ENUM) &&
761          (typePtr->export.basetype != SMI_BASETYPE_BITS))) {
762         return NULL;
763     }
764
765     for (listPtr = typePtr->listPtr; listPtr; listPtr = listPtr->nextPtr) {
766         if (((NamedNumber *)(listPtr->ptr))->export.name ==
767                                                        smiNamedNumberPtr->name)
768             break;
769     }
770
771     if ((!listPtr) || (!listPtr->nextPtr)) {
772         return NULL;
773     }
774         
775     return &((NamedNumber *)listPtr->nextPtr->ptr)->export;
776 }
777
778 SmiNamedNumber *smiGetAttributeFirstNamedNumber(SmiAttribute *smiAttributePtr)
779 {
780     Attribute    *attributePtr;
781
782     attributePtr = (Attribute *)smiAttributePtr;
783     
784     if ((!attributePtr) || (!attributePtr->listPtr) ||
785         ((attributePtr->export.basetype != SMI_BASETYPE_ENUM) &&
786          (attributePtr->export.basetype != SMI_BASETYPE_BITS) && 
787          (attributePtr->export.basetype != SMI_BASETYPE_POINTER))) {
788         return NULL;
789     }
790     
791     return &((NamedNumber *)attributePtr->listPtr->ptr)->export;
792 }
793
794
795
796 SmiNamedNumber *smiGetAttributeNextNamedNumber(SmiNamedNumber *smiNamedNumberPtr)
797 {
798     Attribute  *attributePtr;
799     List  *listPtr;
800     
801     if (!smiNamedNumberPtr) {
802         return NULL;
803     }
804     
805     attributePtr = (Attribute*)(((NamedNumber *)smiNamedNumberPtr)->typePtr);
806
807     
808     if ((!attributePtr) || (!attributePtr->listPtr) ||
809         ((attributePtr->export.basetype != SMI_BASETYPE_ENUM) &&
810          (attributePtr->export.basetype != SMI_BASETYPE_BITS))) {
811         return NULL;
812     }
813
814     for (listPtr = attributePtr->listPtr; listPtr; listPtr = listPtr->nextPtr) {
815         if (((NamedNumber *)(listPtr->ptr))->export.name ==
816                                                        smiNamedNumberPtr->name)
817             break;
818     }
819
820     if ((!listPtr) || (!listPtr->nextPtr)) {
821         return NULL;
822     }
823         
824     return &((NamedNumber *)listPtr->nextPtr->ptr)->export;
825 }
826
827 SmiRange *smiGetFirstRange(SmiType *smiTypePtr)
828 {
829     Type    *typePtr;
830
831     typePtr = (Type *)smiTypePtr;
832     
833     if ((!typePtr) || (!typePtr->listPtr) ||
834         (typePtr->export.basetype == SMI_BASETYPE_ENUM) ||
835         (typePtr->export.basetype == SMI_BASETYPE_BITS)) {
836         return NULL;
837     }
838
839     return &((Range *)typePtr->listPtr->ptr)->export;
840 }
841
842
843
844 SmiRange *smiGetNextRange(SmiRange *smiRangePtr)
845 {
846     Type  *typePtr;
847     List  *listPtr;
848
849     if (!smiRangePtr) {
850         return NULL;
851     }
852     
853     typePtr = ((Range *)smiRangePtr)->typePtr;
854
855     if ((!typePtr) || (!typePtr->listPtr) ||
856         (typePtr->export.basetype == SMI_BASETYPE_ENUM) ||
857         (typePtr->export.basetype == SMI_BASETYPE_BITS)) {
858         return NULL;
859     }
860  
861     for (listPtr = typePtr->listPtr; listPtr; listPtr = listPtr->nextPtr) {
862         if (!memcmp(&((Range *)listPtr->ptr)->export.minValue,
863                     &smiRangePtr->minValue, sizeof(struct SmiValue)))
864             break;
865     }
866
867     if ((!listPtr) || (!listPtr->nextPtr)) {
868         return NULL;
869     }
870         
871     return &((Range *)listPtr->nextPtr->ptr)->export;
872 }
873
874 SmiRange *smiGetAttributeFirstRange(SmiAttribute *smiAttributePtr)
875 {
876     Attribute    *attributePtr;
877
878     attributePtr = (Attribute *)smiAttributePtr;
879     
880     if ((!attributePtr) || (!attributePtr->listPtr) ||
881         (attributePtr->export.basetype == SMI_BASETYPE_ENUM) ||
882         (attributePtr->export.basetype == SMI_BASETYPE_BITS)) {
883         return NULL;
884     }
885
886     return &((Range *)attributePtr->listPtr->ptr)->export;
887 }
888
889
890
891 SmiRange *smiGetAttributeNextRange(SmiRange *smiRangePtr)
892 {
893     Attribute  *attributePtr;
894     List  *listPtr;
895
896     if (!smiRangePtr) {
897         return NULL;
898     }
899     
900     attributePtr = (Attribute*)((Range *)smiRangePtr)->typePtr;
901
902     if ((!attributePtr) || (!attributePtr->listPtr) ||
903         (attributePtr->export.basetype == SMI_BASETYPE_ENUM) ||
904         (attributePtr->export.basetype == SMI_BASETYPE_BITS)) {
905         return NULL;
906     }
907  
908     for (listPtr = attributePtr->listPtr; listPtr; listPtr = listPtr->nextPtr) {
909         if (!memcmp(&((Range *)listPtr->ptr)->export.minValue,
910                     &smiRangePtr->minValue, sizeof(struct SmiValue)))
911             break;
912     }
913
914     if ((!listPtr) || (!listPtr->nextPtr)) {
915         return NULL;
916     }
917         
918     return &((Range *)listPtr->nextPtr->ptr)->export;
919 }
920
921
922 SmiIdentity *smiGetFirstIdentity(SmiModule *smiModulePtr)
923 {
924         if (!smiModulePtr) {
925         return NULL;
926     }
927     
928     return ((Module *)smiModulePtr)->firstIdentityPtr ?
929         &((Module *)smiModulePtr)->firstIdentityPtr->export : NULL;
930     
931 }
932
933 SmiIdentity *smiGetNextIdentity(SmiIdentity *smiIdentityPtr)
934 {
935     if (!smiIdentityPtr) {
936         return NULL;
937     }
938
939     return ((Identity *)smiIdentityPtr)->nextPtr ?
940         &((Identity *)smiIdentityPtr)->nextPtr->export : NULL;
941 }
942
943 SmiModule *smiGetIdentityModule(SmiIdentity *smiIdentityPtr)
944 {
945     return &((Identity *)smiIdentityPtr)->modulePtr->export;
946 }
947
948 SmiIdentity *smiGetParentIdentity(SmiIdentity *smiIdentityPtr)
949 {
950     return (SmiIdentity*)(((Identity *)smiIdentityPtr)->parentPtr);
951 }
952
953 SmiIdentity *smiGetIdentity(SmiModule *smiModulePtr, char *identity)
954 {
955         
956         if (!smiModulePtr) {
957         return NULL;
958     }
959     else
960     {
961         SmiIdentity *ide; 
962         
963         for(ide = smiGetFirstIdentity(smiModulePtr); 
964                 ide;
965                 ide = smiGetNextIdentity(ide))
966                         if(!strncmp(ide->name,identity,64))return ide;
967                 
968         return NULL;
969     }
970     
971 }
972
973 int smiGetIdentityLine(SmiIdentity *smiIdentityPtr)
974 {
975     return ((Identity *)smiIdentityPtr)->line;
976 }
977
978         
979 SmiClass *smiGetFirstClass(SmiModule *smiModulePtr)
980 {
981         if (!smiModulePtr) {
982         return NULL;
983     }
984     
985     return ((Module *)smiModulePtr)->firstClassPtr ?
986         &((Module *)smiModulePtr)->firstClassPtr->export : NULL;
987     
988 }
989
990 SmiClass *smiGetNextClass(SmiClass *smiClassPtr)
991 {
992     if (!smiClassPtr) {
993         return NULL;
994     }
995
996     return ((Class *)smiClassPtr)->nextPtr ?
997         &((Class *)smiClassPtr)->nextPtr->export : NULL;
998 }
999
1000 SmiModule *smiGetClassModule(SmiClass *smiClassPtr)
1001 {
1002     return &((Class *)smiClassPtr)->modulePtr->export;
1003 }
1004
1005 SmiClass *smiGetParentClass(SmiClass *smiClassPtr)
1006 {
1007     return (SmiClass*)(((Class *)smiClassPtr)->parentPtr);
1008 }
1009
1010 SmiClass *smiGetClass(SmiModule *smiModulePtr, char *class)
1011 {
1012         
1013         if (!smiModulePtr) {
1014         return NULL;
1015     }
1016     else
1017     {
1018         SmiClass *cl; 
1019         
1020         for(cl = smiGetFirstClass(smiModulePtr); 
1021                 cl;
1022                 cl = smiGetNextClass(cl))
1023                         if(!strncmp(cl->name,class,64))return cl;
1024                 
1025         return NULL;
1026     }
1027     
1028 }
1029
1030 int smiGetClassLine(SmiClass *smiClassPtr)
1031 {
1032     return ((Class *)smiClassPtr)->line;
1033 }
1034
1035 SmiAttribute *smiGetFirstAttribute(SmiClass *smiClassPtr)
1036 {
1037     Attribute *attributePtr;
1038     
1039     if (!smiClassPtr) {
1040         return NULL;
1041     }
1042     
1043         attributePtr = ((Class *)smiClassPtr)->firstAttributePtr;
1044     
1045     return &attributePtr->export;
1046 }
1047
1048  SmiAttribute *smiGetNextAttribute( SmiAttribute *smiTypePtr)
1049 {
1050     Attribute *attributePtr;
1051
1052     if (!smiTypePtr) {
1053         return NULL;
1054     }
1055
1056     attributePtr = ((Attribute *)smiTypePtr)->nextPtr;
1057     
1058     return &attributePtr->export;
1059 }
1060
1061 SmiAttribute *smiGetAttribute(SmiClass *smiClassPtr, char *attribute)
1062 {
1063     Attribute *attributePtr;
1064     
1065     if (! smiClassPtr) {
1066         return NULL;
1067     }
1068     
1069     attributePtr = ((Class *)smiClassPtr)->firstAttributePtr;
1070     
1071     for (attributePtr = ((Class *)smiClassPtr)->firstAttributePtr; 
1072          attributePtr; attributePtr = attributePtr->nextPtr)
1073     {
1074         if (!strncmp(attributePtr->export.name, attribute,64)) {
1075             return &attributePtr->export;
1076         }
1077     }
1078     
1079     /*
1080      * attribute might belong to the parent so check parent if
1081      * attribute not found
1082      */
1083     
1084     smiClassPtr = smiGetParentClass(smiClassPtr);
1085     attributePtr = (Attribute*)smiGetAttribute(smiClassPtr , attribute);
1086                 
1087     return &attributePtr->export;
1088 }
1089
1090 SmiType *smiGetAttributeParentType(SmiAttribute *smiAttributePtr)
1091 {
1092     Type *parentTypePtr;
1093     
1094     if (! smiAttributePtr) {
1095         return NULL;
1096     }
1097     
1098     parentTypePtr = ((Attribute*)smiAttributePtr)->parentTypePtr;
1099     
1100     return (parentTypePtr) ? &parentTypePtr->export : NULL;
1101 }
1102
1103 SmiClass *smiGetAttributeParentClass( SmiAttribute *smiAttributePtr)
1104 {
1105     Class *parentClassPtr;
1106     
1107     if (! smiAttributePtr) {
1108         return NULL;
1109     }
1110     
1111     parentClassPtr = ((Attribute*)smiAttributePtr)->parentClassPtr;
1112
1113     return parentClassPtr ? &parentClassPtr->export : NULL;
1114 }
1115
1116 SmiAttribute *smiGetFirstUniqueAttribute(SmiClass *smiClassPtr)
1117 {
1118     Class *classPtr;
1119     
1120     if (! smiClassPtr) {
1121         return NULL;
1122     }
1123         
1124     classPtr = (Class*)smiClassPtr;
1125         
1126     if (! classPtr->uniqueList) {
1127         return NULL;
1128     }
1129     
1130     if (classPtr->uniqueList->ptr == classPtr) {
1131         return NULL; /* scalar class */
1132     }
1133
1134     return (SmiAttribute*)(classPtr->uniqueList->ptr);
1135 }
1136
1137 SmiAttribute *smiGetNextUniqueAttribute( SmiAttribute *smiTypePtr)
1138 {
1139     Class *classPtr;
1140     List  *listPtr; 
1141     
1142     if (! smiTypePtr) {
1143         return NULL;
1144     }
1145         
1146     classPtr = ((Attribute*)smiTypePtr)->classPtr;
1147     
1148     if (classPtr && classPtr->uniqueList) {
1149         for (listPtr=classPtr->uniqueList;listPtr; listPtr=listPtr->nextPtr) {
1150             if (&((Attribute*)(listPtr->ptr))->export ==  smiTypePtr) { 
1151                 if (listPtr->nextPtr) {
1152                     return &((Attribute*)(listPtr->nextPtr->ptr))->export;
1153                 }
1154             }
1155         }
1156     }
1157     return NULL;
1158 }
1159
1160
1161
1162 int smiGetAttributeLine(SmiAttribute *smiAttributePtr)
1163 {
1164     return ((Attribute *)smiAttributePtr)->line;
1165 }
1166
1167
1168
1169 int smiIsClassScalar(SmiClass *smiClassPtr)
1170 {
1171     Class *classPtr;
1172     
1173     if (! smiClassPtr) {
1174         return 0;
1175     }
1176         
1177     classPtr = (Class*)smiClassPtr;
1178     
1179     if (! classPtr->uniqueList) {
1180         return 0;
1181     }
1182
1183     return (classPtr->uniqueList->ptr == classPtr);
1184 }
1185
1186
1187
1188 SmiEvent *smiGetFirstEvent(SmiClass *smiClassPtr)
1189 {
1190     Event *eventPtr;
1191     
1192     if (! smiClassPtr) {
1193         return NULL;
1194     }
1195     
1196     eventPtr = ((Class *)smiClassPtr)->firstEventPtr;
1197     return &(eventPtr->export);
1198 }
1199
1200
1201
1202 SmiEvent *smiGetNextEvent(SmiEvent *smiEventPtr)
1203 {
1204     Event *eventPtr;
1205
1206     if (! smiEventPtr) {
1207         return NULL;
1208     }
1209
1210     eventPtr = ((Event *)smiEventPtr)->nextPtr;
1211     return &eventPtr->export;
1212 }
1213
1214
1215
1216 int smiGetEventLine(SmiEvent *smiEventPtr)
1217 {
1218     return ((Event *)smiEventPtr)->line;
1219 }
1220
1221         
1222
1223 SmiMacro *smiGetMacro(SmiModule *smiModulePtr, char *macro)
1224 {
1225     Macro           *macroPtr = NULL;
1226     Module          *modulePtr = NULL;
1227     char            *module2, *macro2;
1228     
1229     if (!macro) {
1230         return NULL;
1231     }
1232
1233     modulePtr = (Module *)smiModulePtr;
1234
1235     getModulenameAndName(smiModulePtr ? smiModulePtr->name : NULL, macro,
1236                          &module2, &macro2);
1237     
1238     if (!modulePtr && module2 && strlen(module2)) {
1239         if (!(modulePtr = findModuleByName(module2))) {
1240             modulePtr = loadModule(module2, NULL);
1241         }
1242     }
1243
1244     if (modulePtr) {
1245         macroPtr = findMacroByModuleAndName(modulePtr, macro2);
1246     } else {
1247         macroPtr = findMacroByName(macro2);
1248     }
1249     
1250     smiFree(module2);
1251     smiFree(macro2);
1252     return macroPtr ? &macroPtr->export : NULL;
1253 }
1254
1255
1256
1257 SmiMacro *smiGetFirstMacro(SmiModule *smiModulePtr)
1258 {
1259     if (!smiModulePtr) {
1260         return NULL;
1261     }
1262     
1263     return ((Module *)smiModulePtr)->firstMacroPtr ?
1264         &((Module *)smiModulePtr)->firstMacroPtr->export : NULL;
1265 }
1266
1267
1268
1269 SmiMacro *smiGetNextMacro(SmiMacro *smiMacroPtr)
1270 {
1271     if (!smiMacroPtr) {
1272         return NULL;
1273     }
1274
1275     return ((Macro *)smiMacroPtr)->nextPtr ?
1276         &((Macro *)smiMacroPtr)->nextPtr->export : NULL;
1277 }
1278
1279
1280 SmiModule *smiGetMacroModule(SmiMacro *smiMacroPtr)
1281 {
1282     return &((Macro *)smiMacroPtr)->modulePtr->export;
1283 }
1284
1285
1286 int smiGetMacroLine(SmiMacro *smiMacroPtr)
1287 {
1288     return ((Macro *)smiMacroPtr)->line;
1289 }
1290
1291
1292 SmiNode *smiGetNode(SmiModule *smiModulePtr, const char *node)
1293 {
1294     Object          *objectPtr = NULL;
1295     Module          *modulePtr = NULL;
1296     Node            *nodePtr;
1297     char            *module2, *node2, *p;
1298     unsigned int    oidlen;
1299     SmiSubid        oid[128];
1300     
1301     if (!node) {
1302         return NULL;
1303     }
1304
1305     modulePtr = (Module *)smiModulePtr;
1306
1307     getModulenameAndName(smiModulePtr ? smiModulePtr->name : NULL, node,
1308                          &module2, &node2);
1309     
1310     if (!modulePtr && module2 && strlen(module2)) {
1311         if (!(modulePtr = findModuleByName(module2))) {
1312             modulePtr = loadModule(module2, NULL);
1313         }
1314     }
1315
1316     if (isdigit((int)node2[0])) {
1317         for (oidlen = 0, p = strtok(node2, ". "); p;
1318              oidlen++, p = strtok(NULL, ". ")) {
1319             oid[oidlen] = strtoul(p, NULL, 0);
1320         }
1321         nodePtr = getNode(oidlen, oid);
1322         if (nodePtr) {
1323             if (modulePtr) {
1324                 objectPtr = findObjectByModuleAndNode(modulePtr, nodePtr);
1325             } else {
1326                 objectPtr = findObjectByNode(nodePtr);
1327             }
1328         }
1329     } else {
1330         p = strtok(node2, ". ");
1331         if (modulePtr) {
1332             objectPtr = findObjectByModuleAndName(modulePtr, p);
1333         } else {
1334             objectPtr = findObjectByName(p);
1335         }
1336     }
1337     
1338     smiFree(module2);
1339     smiFree(node2);
1340     return objectPtr ? &objectPtr->export : NULL;
1341 }
1342
1343
1344
1345 SmiNode *smiGetNodeByOID(unsigned int oidlen, SmiSubid oid[])
1346 {
1347     Node            *nodePtr;
1348     Object          *objectPtr;
1349     
1350     if (!oidlen) {
1351         return NULL;
1352     }
1353
1354     nodePtr = getNode(oidlen, oid);
1355
1356     if (!nodePtr) {
1357         return NULL;
1358     }
1359     
1360     objectPtr = findObjectByNode(nodePtr);
1361
1362     return objectPtr ? &objectPtr->export : NULL;
1363 }
1364
1365
1366
1367 SmiNode *smiGetFirstNode(SmiModule *smiModulePtr, SmiNodekind nodekind)
1368 {
1369     Module *modulePtr;
1370     Node   *nodePtr = NULL;
1371     Object *objectPtr;
1372
1373     if (!smiModulePtr) {
1374         return NULL;
1375     }
1376     
1377     modulePtr = (Module *)smiModulePtr;
1378
1379     if (modulePtr && modulePtr->prefixNodePtr) {
1380         /* start at the common oid prefix of this module */
1381         nodePtr = modulePtr->prefixNodePtr;
1382     } else {
1383         nodePtr = smiHandle->rootNodePtr->firstChildPtr;
1384     }
1385
1386     do {
1387         objectPtr = getNextChildObject(nodePtr, modulePtr, nodekind);
1388         
1389         if (objectPtr)
1390             return &objectPtr->export;
1391         
1392         if (nodePtr->firstChildPtr) {
1393             nodePtr = nodePtr->firstChildPtr;
1394         } else if (nodePtr->nextPtr) {
1395             nodePtr = nodePtr->nextPtr;
1396         } else {
1397             for (nodePtr = nodePtr->parentPtr;
1398                  nodePtr && (nodePtr->parentPtr) && (!nodePtr->nextPtr);
1399                  nodePtr = nodePtr->parentPtr);
1400             if (nodePtr) nodePtr = nodePtr->nextPtr;
1401         }
1402     } while (nodePtr);
1403
1404     return NULL;
1405 }
1406
1407
1408
1409 SmiNode *smiGetNextNode(SmiNode *smiNodePtr, SmiNodekind nodekind)
1410 {
1411     Module            *modulePtr;
1412     Object            *objectPtr;
1413     Node              *nodePtr;
1414     int               i;
1415     
1416     if (!smiNodePtr) {
1417         return NULL;
1418     }
1419
1420     objectPtr = (Object *)smiNodePtr;
1421     nodePtr = objectPtr->nodePtr;
1422     modulePtr = objectPtr->modulePtr;
1423
1424     if (!modulePtr) {
1425         return NULL;
1426     }
1427
1428     if (!nodePtr) {
1429         return NULL;
1430     }
1431
1432     do {
1433         if (nodePtr->firstChildPtr) {
1434             nodePtr = nodePtr->firstChildPtr;
1435         } else if (nodePtr->nextPtr) {
1436             nodePtr = nodePtr->nextPtr;
1437         } else {
1438             for (nodePtr = nodePtr->parentPtr;
1439                  (nodePtr->parentPtr) && (!nodePtr->nextPtr);
1440                  nodePtr = nodePtr->parentPtr);
1441             nodePtr = nodePtr->nextPtr;
1442             /* did we move outside the common oid prefix of this module? */
1443             for (i = 0; i < modulePtr->prefixNodePtr->oidlen; i++)
1444                 if ((!nodePtr) || (!nodePtr->oid) ||
1445                     (nodePtr->oid[i] != modulePtr->prefixNodePtr->oid[i]))
1446                     return NULL;
1447         }
1448
1449         objectPtr = getNextChildObject(nodePtr, modulePtr, nodekind);
1450
1451         if (objectPtr)
1452             return &objectPtr->export;
1453         
1454     } while (nodePtr);
1455
1456     return NULL;
1457 }
1458
1459
1460
1461 SmiNode *smiGetParentNode(SmiNode *smiNodePtr)
1462 {
1463     Module            *modulePtr;
1464     Object            *objectPtr;
1465     Import            *importPtr;
1466     Node              *nodePtr;
1467     
1468     if (!smiNodePtr) {
1469         return NULL;
1470     }
1471
1472     objectPtr = (Object *)smiNodePtr;
1473     nodePtr = objectPtr->nodePtr;
1474     modulePtr = objectPtr->modulePtr;
1475
1476     if (!nodePtr) {
1477         return NULL;
1478     }
1479
1480     if (nodePtr == smiHandle->rootNodePtr) {
1481         return NULL;
1482     }
1483
1484     nodePtr = nodePtr->parentPtr;
1485     if (! nodePtr) {
1486         return NULL;
1487     }
1488
1489     /*
1490      * First, try to find a definition in the same module.
1491      */
1492     objectPtr = NULL;
1493     if (modulePtr) {
1494         objectPtr = findObjectByModuleAndNode(modulePtr, nodePtr);
1495     }
1496
1497     /*
1498      * If found, check if it's imported. In case, get the original definition.
1499      */
1500     if (objectPtr) {
1501         importPtr = findImportByName(objectPtr->export.name,
1502                                      objectPtr->modulePtr);
1503         if (importPtr) {
1504             objectPtr = findObjectByModulenameAndNode(importPtr->export.module,
1505                                                       nodePtr);
1506         } else {
1507             objectPtr = NULL;
1508         }
1509     }
1510     
1511     /*
1512      * If not yet found, try to find any definition.
1513      */
1514     if (!objectPtr) {
1515         objectPtr = findObjectByNode(nodePtr);
1516
1517         if ((!objectPtr) && (nodePtr->parentPtr)) {
1518             /* an implicitly created node, e.g. gaga.0 in an object
1519              * definition with oid == gaga.0.1.
1520              */
1521             objectPtr = addObject(SMI_UNKNOWN_LABEL,
1522                                   nodePtr->parentPtr, nodePtr->subid,
1523                                   0, NULL);
1524             objectPtr->nodePtr = nodePtr;
1525             objectPtr->modulePtr = modulePtr;
1526         }
1527     }
1528
1529     return objectPtr ? &objectPtr->export : NULL;
1530 }
1531
1532
1533
1534 SmiNode *smiGetRelatedNode(SmiNode *smiNodePtr)
1535 {
1536     if (!smiNodePtr) {
1537         return NULL;
1538     }
1539
1540     return &((Object *)smiNodePtr)->relatedPtr->export;
1541 }
1542
1543
1544
1545 SmiNode *smiGetFirstChildNode(SmiNode *smiNodePtr)
1546 {
1547     Module            *modulePtr;
1548     Object            *objectPtr;
1549     Node              *nodePtr;
1550
1551     if (!smiNodePtr) {
1552         return NULL;
1553     }
1554
1555     objectPtr = (Object *)smiNodePtr;
1556     nodePtr = objectPtr->nodePtr;
1557     modulePtr = objectPtr->modulePtr;
1558
1559     if (!nodePtr) {
1560         return NULL;
1561     }
1562
1563     nodePtr = nodePtr->firstChildPtr;
1564
1565     if (!nodePtr) {
1566         return NULL;
1567     }
1568
1569     objectPtr = findObjectByModuleAndNode(modulePtr, nodePtr);
1570     if (!objectPtr) objectPtr = findObjectByNode(nodePtr);
1571
1572     return objectPtr ? &objectPtr->export : NULL;
1573 }
1574
1575
1576
1577 SmiNode *smiGetNextChildNode(SmiNode *smiNodePtr)
1578 {
1579     Module            *modulePtr;
1580     Object            *objectPtr;
1581     Node              *nodePtr;
1582     
1583     if (!smiNodePtr) {
1584         return NULL;
1585     }
1586
1587     objectPtr = (Object *)smiNodePtr;
1588     nodePtr = objectPtr->nodePtr;
1589     modulePtr = objectPtr->modulePtr;
1590
1591     if (!nodePtr) {
1592         return NULL;
1593     }
1594
1595     nodePtr = nodePtr->nextPtr;
1596
1597     if (!nodePtr) {
1598         return NULL;
1599     }
1600
1601     objectPtr = findObjectByModuleAndNode(modulePtr, nodePtr);
1602     if (!objectPtr) objectPtr = findObjectByNode(nodePtr);
1603     
1604     return objectPtr ? &objectPtr->export : NULL;
1605 }
1606
1607
1608
1609 SmiNode *smiGetModuleIdentityNode(SmiModule *smiModulePtr)
1610 {
1611     if (!smiModulePtr) {
1612         return NULL;
1613     }
1614
1615     return &((Module *)smiModulePtr)->objectPtr->export;
1616 }
1617
1618
1619
1620 SmiModule *smiGetNodeModule(SmiNode *smiNodePtr)
1621 {
1622     return &((Object *)smiNodePtr)->modulePtr->export;
1623 }
1624
1625
1626
1627 SmiType *smiGetNodeType(SmiNode *smiNodePtr)
1628 {
1629     Type *typePtr;
1630
1631     typePtr = ((Object *)smiNodePtr)->typePtr;
1632     
1633     if (!typePtr ||
1634         typePtr->export.basetype == SMI_BASETYPE_UNKNOWN) {
1635         return NULL;
1636     }
1637     
1638     return &typePtr->export;
1639 }
1640
1641
1642
1643 int smiGetNodeLine(SmiNode *smiNodePtr)
1644 {
1645     return ((Object *)smiNodePtr)->line;
1646 }
1647
1648
1649
1650 SmiElement *smiGetFirstElement(SmiNode *smiNodePtr)
1651 {
1652     List              *listPtr;
1653     
1654     if (!smiNodePtr) {
1655         return NULL;
1656     }
1657
1658     listPtr = ((Object *)smiNodePtr)->listPtr;
1659
1660     return (SmiElement *)listPtr;
1661 }
1662
1663
1664
1665 SmiElement *smiGetNextElement(SmiElement *smiElementPtr)
1666 {
1667     List              *listPtr;
1668     
1669     if (!smiElementPtr) {
1670         return NULL;
1671     }
1672
1673     listPtr = ((List *)smiElementPtr)->nextPtr;
1674     
1675     return (SmiElement *)listPtr;
1676 }
1677
1678
1679
1680 SmiNode *smiGetElementNode(SmiElement *smiElementPtr)
1681 {
1682     if ((Object *)((List *)smiElementPtr)->ptr)
1683         return &((Object *)((List *)smiElementPtr)->ptr)->export;
1684     else
1685         return NULL;
1686 }
1687
1688
1689
1690 SmiOption *smiGetFirstOption(SmiNode *smiComplianceNodePtr)
1691 {
1692     Object            *objectPtr;
1693     
1694     if (!smiComplianceNodePtr) {
1695         return NULL;
1696     }
1697
1698     objectPtr = (Object *)smiComplianceNodePtr;
1699     
1700     if (!objectPtr->optionlistPtr) {
1701         return NULL;
1702     }
1703
1704     if (objectPtr->export.nodekind != SMI_NODEKIND_COMPLIANCE) {
1705         return NULL;
1706     }
1707                                                      
1708     return &((Option *)objectPtr->optionlistPtr->ptr)->export;
1709 }
1710
1711
1712
1713 SmiOption *smiGetNextOption(SmiOption *smiOptionPtr)
1714 {
1715     List              *listPtr;
1716     
1717     if (!smiOptionPtr) {
1718         return NULL;
1719     }
1720                                                      
1721     for (listPtr =
1722             ((Option *)smiOptionPtr)->compliancePtr->optionlistPtr;
1723          listPtr;
1724          listPtr = listPtr->nextPtr) {
1725         if ((Option *)(listPtr->ptr) == (Option *)smiOptionPtr) {
1726             if (listPtr->nextPtr) {
1727                 return &((Option *)listPtr->nextPtr->ptr)->export;
1728             } else {
1729                 return NULL;
1730             }
1731         }
1732     }
1733     
1734     return NULL;
1735 }
1736
1737
1738
1739 SmiNode *smiGetOptionNode(SmiOption *smiOptionPtr)
1740 {
1741     return &((Option *)smiOptionPtr)->objectPtr->export;
1742 }
1743
1744
1745
1746 int smiGetOptionLine(SmiOption *smiOptionPtr)
1747 {
1748     return ((Option *)smiOptionPtr)->line;
1749 }
1750
1751
1752
1753 SmiRefinement *smiGetFirstRefinement(SmiNode *smiComplianceNodePtr)
1754 {
1755     Object            *objectPtr;
1756     
1757     if (!smiComplianceNodePtr) {
1758         return NULL;
1759     }
1760
1761     objectPtr = (Object *)smiComplianceNodePtr;
1762     
1763     if (!objectPtr->refinementlistPtr) {
1764         return NULL;
1765     }
1766
1767     if (objectPtr->export.nodekind != SMI_NODEKIND_COMPLIANCE) {
1768         return NULL;
1769     }
1770                                                      
1771     return &((Refinement *)objectPtr->refinementlistPtr->ptr)->export;
1772 }
1773
1774
1775
1776 SmiRefinement *smiGetNextRefinement(SmiRefinement *smiRefinementPtr)
1777 {
1778     List              *listPtr;
1779     
1780     if (!smiRefinementPtr) {
1781         return NULL;
1782     }
1783                                                      
1784     for (listPtr =
1785             ((Refinement *)smiRefinementPtr)->compliancePtr->refinementlistPtr;
1786          listPtr;
1787          listPtr = listPtr->nextPtr) {
1788         if ((Refinement *)(listPtr->ptr) == (Refinement *)smiRefinementPtr) {
1789             if (listPtr->nextPtr) {
1790                 return &((Refinement *)listPtr->nextPtr->ptr)->export;
1791             } else {
1792                 return NULL;
1793             }
1794         }
1795     }
1796     
1797     return NULL;
1798 }
1799
1800
1801
1802 SmiNode *smiGetRefinementNode(SmiRefinement *smiRefinementPtr)
1803 {
1804     return &((Refinement *)smiRefinementPtr)->objectPtr->export;
1805 }
1806
1807
1808
1809 SmiType *smiGetRefinementType(SmiRefinement *smiRefinementPtr)
1810 {
1811     Type *typePtr;
1812
1813     typePtr = ((Refinement *)smiRefinementPtr)->typePtr;
1814     
1815     if (!typePtr ||
1816         typePtr->export.basetype == SMI_BASETYPE_UNKNOWN) {
1817         return NULL;
1818     }
1819     
1820     return &typePtr->export;
1821 }
1822
1823
1824
1825 SmiType *smiGetRefinementWriteType(SmiRefinement *smiRefinementPtr)
1826 {
1827     Type *typePtr;
1828
1829     typePtr = ((Refinement *)smiRefinementPtr)->writetypePtr;
1830     
1831     if (!typePtr ||
1832         typePtr->export.basetype == SMI_BASETYPE_UNKNOWN) {
1833         return NULL;
1834     }
1835     
1836     return &typePtr->export;
1837 }
1838
1839
1840
1841 int smiGetRefinementLine(SmiRefinement *smiRefinementPtr)
1842 {
1843     return ((Refinement *)smiRefinementPtr)->line;
1844 }
1845
1846
1847
1848 SmiElement *smiGetFirstUniquenessElement(SmiNode *smiNodePtr)
1849 {
1850     List              *listPtr;
1851     
1852     if (!smiNodePtr) {
1853         return NULL;
1854     }
1855
1856     listPtr = ((Object *)smiNodePtr)->uniquenessPtr;
1857
1858     return (SmiElement *)listPtr;
1859 }
1860
1861
1862
1863 char *smiRenderOID(unsigned int oidlen, SmiSubid *oid, int flags)
1864 {
1865     SmiNode *nodePtr = NULL;
1866     SmiModule *modulePtr = NULL;
1867     unsigned int i = 0;
1868     char *ss, *s = NULL;
1869
1870     if (!oid) {
1871         if (flags & SMI_RENDER_UNKNOWN) {
1872             smiAsprintf(&s, SMI_UNKNOWN_LABEL);
1873         } else {
1874             s = NULL;
1875         }
1876         return s;
1877     }
1878     
1879     if (flags & (SMI_RENDER_NAME | SMI_RENDER_QUALIFIED)) {
1880         int len;
1881         for (len = oidlen; len; len--) {
1882             nodePtr = smiGetNodeByOID(len, oid);
1883             if (! nodePtr || nodePtr->name) break;
1884         }
1885         if (nodePtr && nodePtr->name) {
1886             i = nodePtr->oidlen;
1887             if (flags & SMI_RENDER_QUALIFIED) {
1888                 modulePtr = smiGetNodeModule(nodePtr);
1889             }
1890             if (modulePtr) {
1891                 smiAsprintf(&s, "%s::%s",
1892                             modulePtr->name, nodePtr->name);
1893             } else {
1894                 smiAsprintf(&s, "%s", nodePtr->name);
1895             }
1896         }
1897     }
1898
1899     for (; i < oidlen; i++) {
1900         ss = s;
1901         smiAsprintf(&s, "%s%s%u", ss ? ss : "", i ? "." : "", oid[i]);
1902         smiFree(ss);
1903     }
1904
1905     if ((!s) && (flags & SMI_RENDER_UNKNOWN)) {
1906         smiAsprintf(&s, SMI_UNKNOWN_LABEL);
1907     }
1908     
1909     return s;
1910 }
1911
1912
1913
1914 char *smiRenderValue(SmiValue *smiValuePtr, SmiType *smiTypePtr, int flags)
1915 {
1916     unsigned int i, pfx;
1917     int j, k, n, have_pfx;
1918     char *last_fmt, *fmt;
1919     SmiUnsigned64 vv;
1920     int xlen;
1921     SmiNamedNumber *nn;
1922     char *s, *ss;
1923     char f[8];
1924     SmiUnsigned32 v32;
1925     SmiUnsigned64 v64;
1926     
1927     if (!smiValuePtr) {
1928         if (flags & SMI_RENDER_UNKNOWN) {
1929             smiAsprintf(&s, SMI_UNKNOWN_LABEL);
1930         } else {
1931             s = NULL;
1932         }
1933         return s;
1934     }
1935     
1936     switch (smiValuePtr->basetype) {
1937     case SMI_BASETYPE_UNSIGNED32:
1938         if (!(flags & SMI_RENDER_FORMAT) ||
1939             !smiTypePtr || !smiTypePtr->format ||
1940             !strlen(smiTypePtr->format) || smiTypePtr->format[0] == 'd') {
1941             if (smiTypePtr->format && (strlen(smiTypePtr->format) >= 3) &&
1942                 (smiTypePtr->format[1] == '-')) {
1943                 i = atoi(&smiTypePtr->format[2]);
1944                 if (i < 0) i = 0;
1945                 if (i > 20) i = 20;
1946                 smiAsprintf(&s, "%0*lu.",
1947                             1 + i,
1948                             smiValuePtr->value.unsigned32);
1949                 if (s) {
1950                     for (j = strlen(s) - 1; i > 0; i--, j--) {
1951                         s[j] = s[j-1];
1952                     }
1953                     s[j] = '.';
1954                 }
1955             } else {
1956                 smiAsprintf(&s, "%lu", smiValuePtr->value.unsigned32);
1957             }
1958         } else if (smiTypePtr->format[0] == 'x') {
1959             smiAsprintf(&s, "%lx", smiValuePtr->value.unsigned32);
1960         } else if (smiTypePtr->format[0] == 'o') {
1961             smiAsprintf(&s, "%lo", smiValuePtr->value.unsigned32);
1962         } else if (smiTypePtr->format[0] == 'b') {
1963             for (i = 32 - 1;
1964                  i > 0 && !(smiValuePtr->value.unsigned32 & (1 << i)); i--);
1965             s = smiMalloc(i + 1 + 1);
1966             if (s) {
1967                 for (j = 0; i >= 0; i--, j++) {
1968                     s[j] = smiValuePtr->value.unsigned32 & (1<<i) ? '1' : '0';
1969                 }
1970                 s[j] = 0;
1971             }
1972         }
1973         break;
1974     case SMI_BASETYPE_UNSIGNED64:
1975         if (!(flags & SMI_RENDER_FORMAT) ||
1976             !smiTypePtr || !smiTypePtr->format ||
1977             !strlen(smiTypePtr->format) || smiTypePtr->format[0] == 'd') {
1978             if (smiTypePtr->format && (strlen(smiTypePtr->format) >= 3) &&
1979                 (smiTypePtr->format[1] == '-')) {
1980                 i = atoi(&smiTypePtr->format[2]);
1981                 if (i < 0) i = 0;
1982                 if (i > 20) i = 20;
1983                 sprintf(f, "%%0%s.", UINT64_FORMAT);
1984                 f[2] = '*';
1985                 smiAsprintf(&s, f,
1986                             1 + i,
1987                             smiValuePtr->value.unsigned64);
1988                 if (s) {
1989                     for (j = strlen(s) - 1; i > 0; i--, j--) {
1990                         s[j] = s[j-1];
1991                     }
1992                     s[j] = '.';
1993                 }
1994             } else {
1995                 smiAsprintf(&s, UINT64_FORMAT, smiValuePtr->value.unsigned64);
1996             }
1997         } else if (smiTypePtr->format[0] == 'x') {
1998             strcpy(f, UINT64_FORMAT);
1999             f[strlen(f)-1] = 'x';
2000             smiAsprintf(&s, f, smiValuePtr->value.unsigned64);
2001         } else if (smiTypePtr->format[0] == 'o') {
2002             strcpy(f, UINT64_FORMAT);
2003             f[strlen(f)-1] = 'o';
2004             smiAsprintf(&s, f, smiValuePtr->value.unsigned64);
2005         } else if (smiTypePtr->format[0] == 'b') {
2006             for (i = 64 - 1;
2007                  i > 0 && !(smiValuePtr->value.unsigned64 & (1 << i)); i--);
2008             s = smiMalloc(i + 1 + 1);
2009             if (s) {
2010                 for (j = 0; i >= 0; i--, j++) {
2011                     s[j] = smiValuePtr->value.unsigned64 & (1<<i) ? '1' : '0';
2012                 }
2013                 s[j] = 0;
2014             }
2015         }
2016         break;
2017     case SMI_BASETYPE_INTEGER32:
2018         if (!(flags & SMI_RENDER_FORMAT) ||
2019             !smiTypePtr || !smiTypePtr->format ||
2020             !strlen(smiTypePtr->format) || smiTypePtr->format[0] == 'd') {
2021             if (smiTypePtr->format && (strlen(smiTypePtr->format) >= 3) &&
2022                 (smiTypePtr->format[1] == '-')) {
2023                 i = atoi(&smiTypePtr->format[2]);
2024                 if (i < 0) i = 0;
2025                 if (i > 20) i = 20;
2026                 smiAsprintf(&s, "%0*ld.",
2027                             1 + i + (smiValuePtr->value.integer32 < 0 ? 1 : 0),
2028                             smiValuePtr->value.integer32);
2029                 if (s) {
2030                     for (j = strlen(s) - 1; i > 0; i--, j--) {
2031                         s[j] = s[j-1];
2032                     }
2033                     s[j] = '.';
2034                 }
2035             } else {
2036                 smiAsprintf(&s, "%ld", smiValuePtr->value.integer32);
2037             }
2038         } else if (smiTypePtr->format[0] == 'x') {
2039             if (smiValuePtr->value.integer32 >= 0) {
2040                 smiAsprintf(&s, "%lx", smiValuePtr->value.integer32);
2041             } else {
2042                 smiAsprintf(&s, "-%lx", - smiValuePtr->value.integer32);
2043             }
2044         } else if (smiTypePtr->format[0] == 'o') {
2045             if (smiValuePtr->value.integer32 >= 0) {
2046                 smiAsprintf(&s, "%lo", smiValuePtr->value.integer32);
2047             } else {
2048                 smiAsprintf(&s, "-%lo", - smiValuePtr->value.integer32);
2049             }
2050         } else if (smiTypePtr->format[0] == 'b') {
2051             if (smiValuePtr->value.integer32 >= 0) {
2052                 v32 = smiValuePtr->value.integer32;
2053                 j = 0;
2054             } else {
2055                 v32 = - smiValuePtr->value.integer32;
2056                 j = 1;
2057             }
2058             for (i = 32 - 1;
2059                  i > 0 && !(v32 & (1 << i)); i--);
2060             s = smiMalloc(i + j + 1 + 1);
2061             if (s) {
2062                 s[0] = '-';
2063                 for (; i >= 0; i--, j++) {
2064                     s[j] = v32 & (1<<i) ? '1' : '0';
2065                 }
2066                 s[j] = 0;
2067             }
2068         }
2069         break;
2070     case SMI_BASETYPE_INTEGER64:
2071         if (!(flags & SMI_RENDER_FORMAT) ||
2072             !smiTypePtr || !smiTypePtr->format ||
2073             !strlen(smiTypePtr->format) || smiTypePtr->format[0] == 'd') {
2074             if (smiTypePtr->format && (strlen(smiTypePtr->format) >= 3) &&
2075                 (smiTypePtr->format[1] == '-')) {
2076                 i = atoi(&smiTypePtr->format[2]);
2077                 if (i < 0) i = 0;
2078                 if (i > 20) i = 20;
2079                 sprintf(f, "%%0%s.", INT64_FORMAT);
2080                 f[2] = '*';
2081                 smiAsprintf(&s, f,
2082                             1 + i + (smiValuePtr->value.integer64 < 0 ? 1 : 0),
2083                             smiValuePtr->value.integer64);
2084                 if (s) {
2085                     for (j = strlen(s) - 1; i > 0; i--, j--) {
2086                         s[j] = s[j-1];
2087                     }
2088                     s[j] = '.';
2089                 }
2090             } else {
2091                 smiAsprintf(&s, INT64_FORMAT, smiValuePtr->value.integer64);
2092             }
2093         } else if (smiTypePtr->format[0] == 'x') {
2094             if (smiValuePtr->value.integer64 >= 0) {
2095                 strcpy(f, UINT64_FORMAT);
2096                 f[strlen(f)-1] = 'x';
2097                 smiAsprintf(&s, f, smiValuePtr->value.integer64);
2098             } else {
2099                 sprintf(f, "-%s", UINT64_FORMAT);
2100                 f[strlen(f)-1] = 'x';
2101                 smiAsprintf(&s, f, - smiValuePtr->value.integer64);
2102             }
2103         } else if (smiTypePtr->format[0] == 'o') {
2104             if (smiValuePtr->value.integer64 >= 0) {
2105                 strcpy(f, UINT64_FORMAT);
2106                 sprintf(f, "-%s", UINT64_FORMAT);
2107                 f[strlen(f)-1] = 'o';
2108                 smiAsprintf(&s, f, smiValuePtr->value.integer64);
2109             } else {
2110                 smiAsprintf(&s, f, - smiValuePtr->value.integer64);
2111             }
2112         } else if (smiTypePtr->format[0] == 'b') {
2113             if (smiValuePtr->value.integer64 >= 0) {
2114                 v64 = smiValuePtr->value.integer64;
2115                 j = 0;
2116             } else {
2117                 v64 = - smiValuePtr->value.integer64;
2118                 j = 1;
2119             }
2120             for (i = 64 - 1;
2121                  i > 0 && !(v64 & (1 << i)); i--);
2122             s = smiMalloc(i + j + 1 + 1);
2123             if (s) {
2124                 s[0] = '-';
2125                 for (; i >= 0; i--, j++) {
2126                     s[j] = v64 & (1<<i) ? '1' : '0';
2127                 }
2128                 s[j] = 0;
2129             }
2130         }
2131         break;
2132     case SMI_BASETYPE_OBJECTIDENTIFIER:
2133         s = smiRenderOID(smiValuePtr->len, smiValuePtr->value.oid, flags);
2134         break;
2135     case SMI_BASETYPE_OCTETSTRING:
2136         if (!(flags & SMI_RENDER_FORMAT) ||
2137             (!smiTypePtr->format &&
2138              (smiTypePtr->name && strcmp( smiTypePtr->name, "IpAddress")) ) ) {
2139             for (i = 0; i < smiValuePtr->len; i++) {
2140                 if (!isprint((int)smiValuePtr->value.ptr[i])) break;
2141             }
2142             if ((i < smiValuePtr->len) ||
2143                 !(flags & SMI_RENDER_PRINTABLE)) {
2144                 smiAsprintf(&s, "");
2145                 for (i=0; i < smiValuePtr->len; i++) {
2146                     ss = s;
2147                     smiAsprintf(&s, "%s%02x", ss, smiValuePtr->value.ptr[i]);
2148                     smiFree(ss);
2149                 }
2150             } else {
2151                 smiAsprintf(&s, "%s", smiValuePtr->value.ptr);
2152             }
2153         } else {
2154             i = 0;
2155             smiAsprintf(&s, "");
2156             /* SNMPv2-SMI:IpAddress does not have a display hint.
2157                ==> let's use this one: "1d." if we have an IpAddress here */
2158             fmt = (smiTypePtr->name &&
2159                    strcmp( smiTypePtr->name, "IpAddress" ) ) ?
2160                 smiTypePtr->format : "1d.";
2161             while (*fmt && i < smiValuePtr->len) {
2162                 last_fmt = fmt;
2163                 have_pfx = pfx = 0; /* scan prefix: */
2164                 while (*fmt && isdigit((int)*fmt)) {
2165                     pfx = pfx * 10 + *fmt - '0', have_pfx = 1, fmt++;
2166                 }
2167                 if (! have_pfx) {
2168                     pfx = 1;
2169                 }
2170                 switch (*fmt) {
2171                 case 't':
2172                     /* XXX UTF-8 not implemented, fall through to ASCII (a) */
2173                 case 'a':
2174                     n = (pfx < (smiValuePtr->len - i)) ?
2175                         pfx : smiValuePtr->len - i;
2176                     for (k = 0; k < n; k++) {
2177                         if (! isascii((int) smiValuePtr->value.ptr[i+k])) {
2178                             smiFree(s);
2179                             if (flags & SMI_RENDER_UNKNOWN) {
2180                                 smiAsprintf(&s, SMI_UNKNOWN_LABEL);
2181                             } else {
2182                                 s = NULL;
2183                             }
2184                             return s;
2185                         }
2186                         ss = s;
2187                         smiAsprintf(&s, "%s%c", ss, smiValuePtr->value.ptr[i+k]);
2188                         smiFree(ss);
2189                     }
2190                     i += n;
2191                     break;
2192                 case 'b':
2193                 case 'd':
2194                 case 'o':
2195                 case 'x':
2196                     /* XXX: limited to no more than
2197                        sizeof(SmiUnsigned64) octets */
2198                     vv = 0;
2199                     xlen = pfx * 2;
2200                     while (pfx > 0 && i < smiValuePtr->len) {
2201                         vv = vv * 256 +
2202                              ((unsigned char)smiValuePtr->value.ptr[i]);
2203                         i++;
2204                         pfx--;
2205                     }
2206                     switch (*fmt) {
2207                     case 'd':
2208                         ss = s;
2209                         sprintf(f, "%%s%s", UINT64_FORMAT);
2210                         smiAsprintf(&s, f, ss, vv);
2211                         smiFree(ss);
2212                         break;
2213                     case 'o':
2214                         ss = s;
2215                         sprintf(f, "%%s%s", UINT64_FORMAT);
2216                         f[strlen(f)-1] = 'o';
2217                         smiAsprintf(&s, f, ss, vv);
2218                         smiFree(ss);
2219                         break;
2220                     case 'x':
2221                         ss = s;
2222                         sprintf(f, "%%s%%0%s", UINT64_FORMAT);
2223                         f[4] = '*';
2224                         f[strlen(f)-1] = 'x';
2225                         smiAsprintf(&s, f, ss, xlen, vv);
2226                         smiFree(ss);
2227                         break;
2228                     case 'b':
2229                         k = pfx * 8 - 1;
2230                         if (k > sizeof(SmiUnsigned64) * 8 - 1)
2231                             k = sizeof(SmiUnsigned64) * 8 - 1;
2232                         for (j = 0; k >= 0; k--, j++) {
2233                             ss = s;
2234                             smiAsprintf(&s, "%s%c",
2235                                         ss, vv & (1 << k) ? '1' : '0');
2236                             smiFree(ss);
2237                         }
2238                         break;
2239                     }
2240                     break;
2241                 default:
2242                     smiFree(s);
2243                     if (flags & SMI_RENDER_UNKNOWN) {
2244                         smiAsprintf(&s, SMI_UNKNOWN_LABEL);
2245                     } else {
2246                         s = NULL;
2247                     }
2248                     return s;
2249                 }
2250                 fmt++;
2251
2252                 /*
2253                  * Check for a separator and repeat with last format if
2254                  * data is still available.
2255                  */
2256                 if (*fmt && ! isdigit((int) *fmt) && *fmt != '*') {
2257                     if (i < smiValuePtr->len) {
2258                         ss = s;
2259                         smiAsprintf(&s, "%s%c", ss, fmt[0]);
2260                         smiFree(ss);
2261                     }
2262                     fmt++;
2263                 }
2264
2265                 if (! *fmt && (i < smiValuePtr->len)) {
2266                     fmt = last_fmt;
2267                 }
2268             }
2269         }
2270         break;
2271     case SMI_BASETYPE_ENUM:
2272         if ((flags & SMI_RENDER_NAME) && (smiTypePtr)) {
2273             for (nn = smiGetFirstNamedNumber(smiTypePtr); nn;
2274                  nn = smiGetNextNamedNumber(nn)) {
2275                 if (nn->value.value.integer32 == smiValuePtr->value.integer32)
2276                     break;
2277             }
2278             if (nn) {
2279                 if (flags & SMI_RENDER_NUMERIC) {
2280                     smiAsprintf(&s, "%s(%ld)",
2281                                 nn->name, nn->value.value.integer32);
2282                 } else {
2283                     smiAsprintf(&s, "%s", nn->name);
2284                 }
2285             } else {
2286                 smiAsprintf(&s, "%ld", smiValuePtr->value.integer32);
2287             }
2288         } else {
2289             smiAsprintf(&s, "%ld", smiValuePtr->value.integer32);
2290         }
2291         break;
2292     case SMI_BASETYPE_BITS:
2293         smiAsprintf(&s, "");
2294         for (i = 0, nn = NULL; i < smiValuePtr->len * 8; i++) {
2295             if (smiValuePtr->value.ptr[i/8] & (1 << (7-(i%8)))) {
2296                 if ((flags & SMI_RENDER_NAME) && (smiTypePtr)) {
2297                     for (nn = smiGetFirstNamedNumber(smiTypePtr); nn;
2298                          nn = smiGetNextNamedNumber(nn)) {
2299                         if (nn->value.value.unsigned32 == i)
2300                             break;
2301                     }
2302                 }
2303                 ss = s;
2304                 if ((flags & SMI_RENDER_NAME) &&
2305                     (flags & SMI_RENDER_NUMERIC) && nn) {
2306                     smiAsprintf(&s, "%s%s%s(%d)",
2307                                 ss, strlen(ss) ? " " : "", nn->name, i);
2308                 } else if (nn) {
2309                     smiAsprintf(&s, "%s%s%s",
2310                                 ss, strlen(ss) ? " " : "", nn->name);
2311                 } else {
2312                     smiAsprintf(&s, "%s%s%d",
2313                                 ss, strlen(ss) ? " " : "", i);
2314                 }
2315                 smiFree(ss);
2316             }
2317         }
2318         break;
2319     case SMI_BASETYPE_FLOAT32:
2320     case SMI_BASETYPE_FLOAT64:
2321     case SMI_BASETYPE_FLOAT128:
2322     case SMI_BASETYPE_UNKNOWN:
2323     default:
2324         if (flags & SMI_RENDER_UNKNOWN) {
2325             smiAsprintf(&s, SMI_UNKNOWN_LABEL);
2326         } else {
2327             s = NULL;
2328         }
2329         break;
2330     }
2331
2332     return s;
2333 }
2334
2335 char *smiRenderNode(SmiNode *smiNodePtr, int flags)
2336 {
2337     char *s;
2338     SmiModule *modulePtr;
2339     
2340     if ((!smiNodePtr) || (smiNodePtr->name == NULL)) {
2341         if (flags & SMI_RENDER_UNKNOWN) {
2342             smiAsprintf(&s, SMI_UNKNOWN_LABEL);
2343         } else {
2344             s = NULL;
2345         }
2346     } else {
2347         modulePtr = smiGetNodeModule(smiNodePtr);
2348         if ((!(flags & SMI_RENDER_QUALIFIED)) ||
2349             (!modulePtr) ||
2350             (!strlen(modulePtr->name))) {
2351             smiAsprintf(&s, "%s", smiNodePtr->name);
2352         } else {
2353             smiAsprintf(&s, "%s::%s", modulePtr->name, smiNodePtr->name);
2354         }
2355     }
2356     return s;
2357 }
2358
2359
2360
2361 char *smiRenderType(SmiType *smiTypePtr, int flags)
2362 {
2363     char *s;
2364     SmiModule *modulePtr;
2365     
2366     if ((!smiTypePtr) || (smiTypePtr->name == NULL)) {
2367         if (flags & SMI_RENDER_UNKNOWN) {
2368             smiAsprintf(&s, SMI_UNKNOWN_LABEL);
2369         } else {
2370             s = NULL;
2371         }
2372     } else {
2373         modulePtr = smiGetTypeModule(smiTypePtr);
2374         if ((!(flags & SMI_RENDER_QUALIFIED)) ||
2375             (!modulePtr) ||
2376             (!strlen(modulePtr->name))) {
2377             smiAsprintf(&s, "%s", smiTypePtr->name);
2378         } else {
2379             smiAsprintf(&s, "%s::%s", modulePtr->name, smiTypePtr->name);
2380         }
2381     }
2382     return s;
2383 }
2384
2385
2386
2387 unsigned int smiGetMinSize(SmiType *smiType)
2388 {
2389     SmiRange *smiRange;
2390     SmiType  *parentType;
2391     unsigned int min = 65535, size;
2392     
2393     switch (smiType->basetype) {
2394     case SMI_BASETYPE_BITS:
2395         return 0;
2396     case SMI_BASETYPE_OCTETSTRING:
2397     case SMI_BASETYPE_OBJECTIDENTIFIER:
2398         size = 0;
2399         break;
2400     default:
2401         return 0;
2402     }
2403
2404     for (smiRange = smiGetFirstRange(smiType);
2405          smiRange ; smiRange = smiGetNextRange(smiRange)) {
2406         if (smiRange->minValue.value.unsigned32 < min) {
2407             min = smiRange->minValue.value.unsigned32;
2408         }
2409     }
2410     if (min < 65535 && min > size) {
2411         size = min;
2412     }
2413
2414     parentType = smiGetParentType(smiType);
2415     if (parentType) {
2416         unsigned int psize = smiGetMinSize(parentType);
2417         if (psize > size) {
2418             size = psize;
2419         }
2420     }
2421
2422     return size;
2423 }
2424
2425
2426
2427 unsigned int smiGetMaxSize(SmiType *smiType)
2428 {
2429     SmiRange *smiRange;
2430     SmiType  *parentType;
2431     SmiNamedNumber *nn;
2432     unsigned int max = 0, size;
2433     
2434     switch (smiType->basetype) {
2435     case SMI_BASETYPE_BITS:
2436     case SMI_BASETYPE_OCTETSTRING:
2437         size = 65535;
2438         break;
2439     case SMI_BASETYPE_OBJECTIDENTIFIER:
2440         size = 128;
2441         break;
2442     default:
2443         return 0xffffffff;
2444     }
2445
2446     if (smiType->basetype == SMI_BASETYPE_BITS) {
2447         for (nn = smiGetFirstNamedNumber(smiType);
2448              nn;
2449              nn = smiGetNextNamedNumber(nn)) {
2450             if (nn->value.value.unsigned32 > max) {
2451                 max = nn->value.value.unsigned32;
2452             }
2453         }
2454         size = (max / 8) + 1;
2455         return size;
2456     }
2457
2458     for (smiRange = smiGetFirstRange(smiType);
2459          smiRange ; smiRange = smiGetNextRange(smiRange)) {
2460         if (smiRange->maxValue.value.unsigned32 > max) {
2461             max = smiRange->maxValue.value.unsigned32;
2462         }
2463     }
2464     if (max > 0 && max < size) {
2465         size = max;
2466     }
2467
2468     parentType = smiGetParentType(smiType);
2469     if (parentType) {
2470         unsigned int psize = smiGetMaxSize(parentType);
2471         if (psize < size) {
2472             size = psize;
2473         }
2474     }
2475
2476     return size;
2477 }
2478
2479
2480
2481 int smiUnpack(SmiNode *row, SmiSubid *oid, unsigned int oidlen,
2482               SmiValue **vals, int *valslen)
2483 {
2484     SmiNode *indexNode = NULL;
2485     SmiElement *smiElement;
2486     SmiNode *iNode;
2487     SmiType *iType; 
2488     int i, j, last = 0;
2489    
2490     if (!vals || !valslen || !row || !oid) {
2491         return 0;
2492     }
2493
2494     switch (row->indexkind) {
2495     case SMI_INDEX_INDEX:
2496     case SMI_INDEX_REORDER:
2497         indexNode = row;
2498         break;
2499     case SMI_INDEX_EXPAND:      /* TODO: we have to do more work here! */
2500         indexNode = NULL;
2501         break;
2502     case SMI_INDEX_AUGMENT:
2503     case SMI_INDEX_SPARSE:
2504         indexNode = smiGetRelatedNode(row);
2505         break;
2506     case SMI_INDEX_UNKNOWN:
2507         indexNode = NULL;
2508         break;
2509     }
2510
2511     *valslen = 0;
2512     for (smiElement = smiGetFirstElement(indexNode);
2513          smiElement; smiElement = smiGetNextElement(smiElement)) {
2514         iNode = smiGetElementNode(smiElement);
2515         if (iNode) {
2516             iType = smiGetNodeType(iNode);
2517             if (! iType) break;
2518             (*valslen)++;
2519         }
2520     }
2521     if (smiElement) {
2522         return 0;
2523     }
2524
2525     *vals = smiMalloc(*valslen * sizeof(SmiValue));
2526
2527     for (smiElement = smiGetFirstElement(indexNode), i = 0, j = 0;
2528          smiElement; smiElement = smiGetNextElement(smiElement), i++) {
2529         iNode = smiGetElementNode(smiElement);
2530         last = (smiGetNextElement(smiElement) == NULL);
2531         iType = smiGetNodeType(iNode);
2532         fprintf(stderr, "** %s (%s)\n", iNode->name, iType->name);
2533         (*vals)[i].basetype = iType->basetype;
2534         switch (iType->basetype) {
2535         case SMI_BASETYPE_ENUM:
2536         case SMI_BASETYPE_INTEGER32:
2537             (*vals)[i].value.integer32 = oid[j]; j++;
2538             break;
2539         case SMI_BASETYPE_UNSIGNED32:
2540             (*vals)[i].value.unsigned32 = oid[j]; j++;
2541             break;
2542         case SMI_BASETYPE_OCTETSTRING:
2543             /* need to know whether implied/fixed length or not */
2544             break;
2545         case SMI_BASETYPE_OBJECTIDENTIFIER:
2546             /* need to know whether implied/fixed length or not */
2547             break;
2548         default:
2549             return 0;
2550         }
2551     }
2552
2553     return *valslen;
2554 }
2555
2556
2557
2558 int smiAsprintf(char **strp, const char *format, ...)
2559 {
2560     int rc;
2561     va_list ap;
2562
2563     va_start(ap, format);
2564     rc = vasprintf(strp, format, ap);
2565     va_end(ap);
2566     if (! strp) {
2567         smiPrintError(NULL, ERR_OUT_OF_MEMORY);
2568     }
2569     return rc;
2570 }
2571
2572
2573
2574 int smiVasprintf(char **strp, const char *format, va_list ap)
2575 {
2576     int rc;
2577
2578     rc = vasprintf(strp, format, ap);
2579     if (! strp) {
2580         smiPrintError(NULL, ERR_OUT_OF_MEMORY);
2581     }
2582     return rc;
2583 }
2584
2585
2586 int smiGetMinMaxRange(SmiType *smiType, SmiValue *min, SmiValue *max)
2587 {
2588     SmiBasetype    basetype = SMI_BASETYPE_UNKNOWN;
2589     SmiRange       *range;
2590
2591     min->basetype = max->basetype = SMI_BASETYPE_UNKNOWN;
2592     min->len = max->len = 0;
2593
2594     range = smiGetFirstRange(smiType);
2595     if (!range) {
2596         return 0;
2597     }
2598
2599     basetype = range->minValue.basetype;
2600     min->basetype = max->basetype = basetype;
2601
2602     switch (basetype) {
2603     case SMI_BASETYPE_INTEGER32:
2604         min->value.integer32 = SMI_BASETYPE_INTEGER32_MAX;
2605         max->value.integer32 = SMI_BASETYPE_INTEGER32_MIN;
2606         break;
2607     case SMI_BASETYPE_INTEGER64:
2608         min->value.integer64 = SMI_BASETYPE_INTEGER64_MAX;
2609         max->value.integer64 = SMI_BASETYPE_INTEGER64_MIN;
2610         break;
2611     case SMI_BASETYPE_UNSIGNED32:
2612         min->value.unsigned32 = SMI_BASETYPE_UNSIGNED32_MAX;
2613         max->value.unsigned32 = SMI_BASETYPE_UNSIGNED32_MIN;
2614         break;
2615     case SMI_BASETYPE_UNSIGNED64:
2616         min->value.unsigned64 = SMI_BASETYPE_UNSIGNED64_MAX;
2617         max->value.unsigned64 = SMI_BASETYPE_UNSIGNED32_MIN;
2618         break;
2619     default:
2620         fprintf(stderr, "smidump: unexpected basetype %d\n", basetype);
2621         return -1;
2622     }
2623
2624     for (range = smiGetFirstRange(smiType);
2625          range;
2626          range = smiGetNextRange(range)) {
2627         switch (basetype) {
2628         case SMI_BASETYPE_INTEGER32:
2629             if (range->minValue.value.integer32 < min->value.integer32) {
2630                 min->value.integer32 = range->minValue.value.integer32;
2631             }
2632             if (range->maxValue.value.integer32 > max->value.integer32) {
2633                 max->value.integer32 = range->maxValue.value.integer32;
2634             }
2635             break;
2636         case SMI_BASETYPE_INTEGER64:
2637             if (range->minValue.value.integer64 < min->value.integer64) {
2638                 min->value.integer64 = range->minValue.value.integer64;
2639             }
2640             if (range->maxValue.value.integer64 > max->value.integer64) {
2641                 max->value.integer64 = range->maxValue.value.integer64;
2642             }
2643             break;
2644         case SMI_BASETYPE_UNSIGNED32:
2645             if (range->minValue.value.unsigned32 < min->value.unsigned32) {
2646                 min->value.unsigned32 = range->minValue.value.unsigned32;
2647             }
2648             if (range->maxValue.value.unsigned32 > max->value.unsigned32) {
2649                 max->value.unsigned32 = range->maxValue.value.unsigned32;
2650             }
2651             break;
2652         case SMI_BASETYPE_UNSIGNED64:
2653             if (range->minValue.value.unsigned64 < min->value.unsigned64) {
2654                 min->value.unsigned64 = range->minValue.value.unsigned64;
2655             }
2656             if (range->maxValue.value.unsigned64 > max->value.unsigned64) {
2657                 max->value.unsigned64 = range->maxValue.value.unsigned64;
2658             }
2659             break;
2660         default:
2661             fprintf(stderr, "smidump: unexpected basetype %d\n", basetype);
2662             return -1;
2663         }
2664     }
2665
2666     return 0;
2667 }