Imported Upstream version 0.4.8
[platform/upstream/libsmi.git] / tools / smidiff.c
1 /*
2  * smidiff.c --
3  *
4  *      Compute and check differences between MIB modules.
5  *
6  * Copyright (c) 2001 T. Klie, Technical University of Braunschweig.
7  * Copyright (c) 2001 J. Schoenwaelder, Technical University of Braunschweig.
8  * Copyright (c) 2001 F. Strauss, Technical University of Braunschweig.
9  * Copyright (c) 2006 J. Schoenwaelder, International University Bremen.
10  *
11  * See the file "COPYING" for information on usage and redistribution
12  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13  *
14  * @(#) $Id: smidiff.c 8090 2008-04-18 12:56:29Z strauss $ 
15  */
16
17 /*
18  * TODO:
19  *
20  * - replacing an implicit type with a named type should cause a real
21  *   error if the new type is formally not identical (Mike Heard)
22  */
23
24 #include <config.h>
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <ctype.h>
31 #ifdef HAVE_WIN_H
32 #include "win.h"
33 #endif
34
35 #include "smi.h"
36 #include "shhopt.h"
37
38
39 static int errorLevel = 6;      /* smidiff/libsmi error level (inclusive) */
40 static int mFlag = 0;           /* show the name for error messages */
41 static int sFlag = 0;           /* show the severity for error messages */
42 static char *oldCompl = NULL;   /* name of old compliance statement */
43 static char *newCompl = NULL;   /* name of new compliance statement */
44
45 /* the `:' separates the view identifier */
46 static const char *oldTag = "smidiff:old";
47 static const char *newTag = "smidiff:new";
48
49
50 #define CODE_SHOW_PREVIOUS              0x01
51 #define CODE_SHOW_PREVIOUS_IMPLICIT     0x02
52
53
54 typedef struct Error {
55     int level;          /* error level - roughly the same as smilint */
56     int id;             /* error id used in the error() invocation */
57     char *tag;          /* tag for error identification on cmd line */
58     char *fmt;          /* the complete error format string */
59     char *description;  /* description of the error message */
60 } Error;
61
62
63 #define ERR_INTERNAL                            0
64 #define ERR_TYPE_REMOVED                        1
65 #define ERR_TYPE_ADDED                          2
66 #define ERR_NODE_REMOVED                        3
67 #define ERR_NODE_ADDED                          4
68 #define ERR_BASETYPE_CHANGED                    5
69 #define ERR_DECL_CHANGED                        6
70 #define ERR_LEGAL_STATUS_CHANGED                8
71 #define ERR_PREVIOUS_DEFINITION                 9
72 #define ERR_STATUS_CHANGED                      10
73 #define ERR_DESCR_ADDED                         11
74 #define ERR_DESCR_REMOVED                       12
75 #define ERR_DESCR_CHANGED                       13
76 #define ERR_REF_ADDED                           14
77 #define ERR_REF_REMOVED                         15
78 #define ERR_REF_CHANGED                         16
79 #define ERR_FORMAT_ADDED                        17
80 #define ERR_FORMAT_REMOVED                      18
81 #define ERR_FORMAT_CHANGED                      19
82 #define ERR_UNITS_ADDED                         20
83 #define ERR_UNITS_REMOVED                       21
84 #define ERR_UNITS_CHANGED                       22
85 #define ERR_ACCESS_ADDED                        23
86 #define ERR_ACCESS_REMOVED                      24
87 #define ERR_ACCESS_CHANGED                      25
88 #define ERR_NAME_ADDED                          26
89 #define ERR_NAME_REMOVED                        27
90 #define ERR_NAME_CHANGED                        28
91 #define ERR_TO_IMPLICIT                         29
92 #define ERR_FROM_IMPLICIT                       30
93 #define ERR_RANGE_ADDED                         31
94 #define ERR_RANGE_REMOVED                       32
95 #define ERR_RANGE_CHANGED                       33
96 #define ERR_DEFVAL_ADDED                        34
97 #define ERR_DEFVAL_REMOVED                      35
98 #define ERR_DEFVAL_CHANGED                      36
99 #define ERR_ORGA_ADDED                          37
100 #define ERR_ORGA_REMOVED                        38
101 #define ERR_ORGA_CHANGED                        39
102 #define ERR_CONTACT_ADDED                       40
103 #define ERR_CONTACT_REMOVED                     41
104 #define ERR_CONTACT_CHANGED                     42
105 #define ERR_SMIVERSION_CHANGED                  43
106 #define ERR_REVISION_ADDED                      44
107 #define ERR_REVISION_REMOVED                    45
108 #define ERR_REVISION_CHANGED                    46
109 #define ERR_LENGTH_CHANGED                      47
110 #define ERR_LENGTH_OF_TYPE_CHANGED              48
111 #define ERR_LENGTH_ADDED                        49
112 #define ERR_MEMBER_ADDED                        50
113 #define ERR_MEMBER_REMOVED                      51
114 #define ERR_MEMBER_CHANGED                      52
115 #define ERR_OBJECT_ADDED                        53
116 #define ERR_OBJECT_REMOVED                      54
117 #define ERR_OBJECT_CHANGED                      55
118 #define ERR_NAMED_NUMBER_ADDED                  56
119 #define ERR_NAMED_NUMBER_REMOVED                57
120 #define ERR_NAMED_NUMBER_CHANGED                58
121 #define ERR_NAMED_BIT_ADDED_OLD_BYTE            59
122 #define ERR_NODEKIND_CHANGED                    60
123 #define ERR_INDEXKIND_CHANGED                   61
124 #define ERR_INDEX_CHANGED                       62
125 #define ERR_TYPE_IS_AND_WAS                     63
126 #define ERR_RANGE_OF_TYPE_CHANGED               64
127 #define ERR_RANGE_OF_TYPE_ADDED                 65
128 #define ERR_RANGE_OF_TYPE_REMOVED               66
129 #define ERR_TYPE_BASED_ON                       67
130 #define ERR_INDEX_AUGMENT_CHANGED               68
131 #define ERR_NAMED_NUMBER_OF_TYPE_REMOVED        69
132 #define ERR_NAMED_NUMBER_TO_TYPE_ADDED          70
133 #define ERR_NAMED_NUMBER_OF_TYPE_CHANGED        71
134 #define ERR_NAMED_BIT_OF_TYPE_ADDED_OLD_BYTE    72
135 #define ERR_LENGTH_REMOVED                      73
136 #define ERR_PREVIOUS_IMPLICIT_DEFINITION        74
137 #define ERR_STATUS_CHANGED_IMPLICIT             75
138 #define ERR_LEGAL_STATUS_CHANGED_IMPLICIT       76
139 #define ERR_LENGTH_OF_TYPE_ADDED                77
140 #define ERR_LENGTH_OF_TYPE_REMOVED              78
141 #define ERR_STATUS_ADDED                        79
142 #define ERR_STATUS_REMOVED                      80
143 #define ERR_MANDATORY_GROUP_ADDED               81
144 #define ERR_MANDATORY_GROUP_REMOVED             82
145 #define ERR_MANDATORY_EXT_GROUP_ADDED           83
146 #define ERR_MANDATORY_EXT_GROUP_REMOVED         84
147 #define ERR_OPTION_ADDED                        85
148 #define ERR_OPTION_REMOVED                      86
149 #define ERR_EXT_OPTION_ADDED                    87
150 #define ERR_EXT_OPTION_REMOVED                  88
151 #define ERR_REFINEMENT_ADDED                    89
152 #define ERR_REFINEMENT_REMOVED                  90
153 #define ERR_EXT_REFINEMENT_ADDED                91
154 #define ERR_EXT_REFINEMENT_REMOVED              92
155 #define ERR_MANDATORY_REMOVED                   93
156 #define ERR_MANDATORY_ADDED                     94
157 #define ERR_OPTIONAL_REMOVED                    95
158 #define ERR_OPTIONAL_ADDED                      96
159 #define ERR_MANDATORY_EXT_REMOVED               97
160 #define ERR_MANDATORY_EXT_ADDED                 98
161 #define ERR_OPTIONAL_EXT_REMOVED                99
162 #define ERR_OPTIONAL_EXT_ADDED                  100
163
164 static Error errors[] = {
165     { 0, ERR_INTERNAL, "internal", 
166       "internal error!!!", NULL },
167     { 1, ERR_TYPE_REMOVED, "type-removed",
168       "type `%s' has been deleted", NULL },
169     { 5, ERR_TYPE_ADDED, "type-added",
170       "type `%s' has been added", NULL },
171     { 1, ERR_NODE_REMOVED, "node-removed",
172       "%s `%s' has been deleted", NULL },
173     { 5, ERR_NODE_ADDED, "node-added",
174       "%s `%s' has been added", NULL },
175     { 1, ERR_BASETYPE_CHANGED, "basetype-changed",
176       "base type of `%s' changed", NULL },
177     { 5, ERR_DECL_CHANGED, "decl-changed",
178       "declaration changed for `%s'", NULL },
179     { 5, ERR_LEGAL_STATUS_CHANGED, "status-change",
180       "legal status change from `%s' to `%s' for `%s'", NULL },
181     { 6, ERR_PREVIOUS_DEFINITION, "previous-definition",
182       "previous definition of `%s'", NULL },
183     { 2, ERR_STATUS_CHANGED, "status-change",
184       "status change from `%s' to `%s' for `%s'", NULL },
185     { 5, ERR_DESCR_ADDED, "description-added",
186       "description added to `%s'", NULL },
187     { 2, ERR_DESCR_REMOVED, "description-removed",
188       "description removed from `%s'", NULL },
189     { 5, ERR_DESCR_CHANGED, "description-changed",
190       "description of %s `%s' changed", NULL },
191     { 5, ERR_REF_ADDED, "ref-added",
192       "reference added to `%s'", NULL },
193     { 3, ERR_REF_REMOVED, "ref-removed",
194       "reference removed from `%s'", NULL },
195     { 5, ERR_REF_CHANGED, "ref-changed",
196       "reference of `%s' changed", NULL },
197     { 5, ERR_FORMAT_ADDED, "format-added",
198       "format added to `%s'", NULL },
199     { 3, ERR_FORMAT_REMOVED, "format-removed",
200       "format removed from `%s'", NULL },
201     { 5, ERR_FORMAT_CHANGED, "format-changed",
202       "format of `%s' changed", NULL },
203     { 5, ERR_UNITS_ADDED, "units-added",
204       "units added to `%s'", NULL },
205     { 3, ERR_UNITS_REMOVED, "units-removed",
206       "units removed from `%s'", NULL },
207     { 5, ERR_UNITS_CHANGED, "units-changed",
208       "units of `%s' changed", NULL },
209     { 5, ERR_ACCESS_ADDED, "access-added",
210       "access added to `%s'", NULL },
211     { 3, ERR_ACCESS_REMOVED, "access-removed",
212       "access removed from `%s'", NULL },
213     { 5, ERR_ACCESS_CHANGED, "access-changed",
214       "access of `%s' changed from `%s' to `%s'", NULL },
215     { 5, ERR_NAME_ADDED, "name-added",
216       "name added to `%s'", NULL },
217     { 3, ERR_NAME_REMOVED, "name-removed",
218       "name removed from `%s'", NULL },
219     { 5, ERR_NAME_CHANGED, "name-changed",
220       "name changed from `%s' to `%s'", NULL },
221     { 3, ERR_TO_IMPLICIT, "to-implicit",
222       "implicit type for `%s' replaces type `%s'", NULL },
223     { 5, ERR_FROM_IMPLICIT, "from-implicit",
224       "type `%s' replaces implicit type for `%s'", NULL },
225     { 3, ERR_RANGE_ADDED, "range-added",
226       "range `%s' added to type used in `%s'", NULL },
227     { 3, ERR_RANGE_REMOVED, "range-removed",
228       "range `%s' removed from type used in `%s'", NULL },
229     { 3, ERR_RANGE_CHANGED, "range-changed",
230       "range of type used in `%s' changed from `%s' to `%s'", NULL }, 
231     { 3, ERR_DEFVAL_ADDED, "defval-added",
232       "default value added to `%s'", NULL },
233     { 3, ERR_DEFVAL_REMOVED, "defval-removed",
234       "default value removed from `%s'", NULL },
235     { 3, ERR_DEFVAL_CHANGED, "defval-changed",
236       "default value of `%s' changed", NULL },
237     { 5, ERR_ORGA_ADDED, "organization-added",
238       "organization added to `%s'", NULL },
239     { 3, ERR_ORGA_REMOVED, "organization-removed",
240       "organization removed from `%s'", NULL },
241     { 5, ERR_ORGA_CHANGED, "organization-changed",
242       "organization of `%s' changed", NULL },
243     { 5, ERR_CONTACT_ADDED, "contact-added",
244       "contact added to `%s'", NULL },
245     { 3, ERR_CONTACT_REMOVED, "contact-removed",
246       "contact removed from `%s'", NULL },
247     { 5, ERR_CONTACT_CHANGED, "contact-changed",
248       "contact of `%s' changed", NULL },
249     { 3, ERR_SMIVERSION_CHANGED, "smi-version-changed",
250       "SMI version changed", NULL },
251     { 5, ERR_REVISION_ADDED, "revision-added",
252       "revision `%s' added", NULL },
253     { 3, ERR_REVISION_REMOVED, "revision-removed",
254       "revision `%s' removed", NULL },
255     { 5, ERR_REVISION_CHANGED, "revision-changed",
256       "revision `%s' changed", NULL },
257     { 3, ERR_LENGTH_CHANGED, "range-changed",
258       "size of type used in `%s' changed from `%s' to `%s'", NULL },
259     { 3, ERR_LENGTH_OF_TYPE_CHANGED, "range-changed",
260       "size of type `%s' changed from `%s' to `%s'", NULL },
261     { 3, ERR_LENGTH_ADDED, "range-added",
262       "size `%s' added to type used in `%s'", NULL },
263     { 2, ERR_MEMBER_ADDED, "member-added",
264       "member `%s' added to group `%s'", NULL },
265     { 2, ERR_MEMBER_REMOVED, "member-removed",
266       "member `%s' removed from group `%s'", NULL },
267     { 3, ERR_MEMBER_CHANGED, "member-changed",
268       "member `%s' changed in group `%s'", NULL },
269     { 3, ERR_OBJECT_ADDED, "object-added",
270       "object `%s' added", NULL },
271     { 2, ERR_OBJECT_REMOVED, "object-removed",
272       "object `%s' removed", NULL },
273     { 3, ERR_OBJECT_CHANGED, "object-changed",
274       "object `%s' changed", NULL },
275     { 5, ERR_NAMED_NUMBER_ADDED, "named-number-added",
276       "named number `%s' added to type used in `%s'", NULL },
277     { 2, ERR_NAMED_NUMBER_REMOVED, "named-number-removed",
278       "named number `%s' removed from type used in `%s'", NULL },
279     { 5, ERR_NAMED_NUMBER_CHANGED, "named-number-changed",
280       "named number `%s' changed to `%s' at type used in `%s'", NULL },
281     { 3, ERR_NAMED_BIT_ADDED_OLD_BYTE, "named-bit-added-old-byte",
282       "named bit `%s' added without starting in a new byte in type used in `%s'", NULL },
283      { 3, ERR_LENGTH_REMOVED, "range-removed",
284       "size `%s' removed from type used in `%s'", NULL },
285     { 2, ERR_NODEKIND_CHANGED, "nodekind-changed",
286       "node kind of `%s' changed", NULL },
287     { 2, ERR_INDEXKIND_CHANGED, "indexkind-changed",
288       "changed kind of index from `%s' to `%s' in node `%s'", NULL },
289     { 2, ERR_INDEX_CHANGED, "index-changed",
290       "index of `%s' changed from %s to %s", NULL },
291     { 5, ERR_TYPE_IS_AND_WAS, "type-is-and-was",
292       "type changed from %s to %s", NULL },
293     { 3, ERR_RANGE_OF_TYPE_CHANGED, "range-changed",
294       "range of type `%s' changed from `%s' to `%s'", NULL },
295     { 3, ERR_RANGE_OF_TYPE_ADDED, "range-added",
296       "range `%s' added to type `%s'", NULL },
297     { 3, ERR_RANGE_OF_TYPE_REMOVED, "range-removed",
298       "range `%s' removed from type `%s'", NULL },
299     { 6, ERR_TYPE_BASED_ON, "type-based-on",
300       "type `%s' based on `%s'", NULL },
301     { 2, ERR_INDEX_AUGMENT_CHANGED, "index-changed",
302       "index of `%s' changed from augmenting `%s' to augmenting `%s'", NULL },
303     { 2, ERR_NAMED_NUMBER_OF_TYPE_REMOVED, "named-number-removed",
304       "named number `%s' removed from type `%s'", NULL },
305     { 5, ERR_NAMED_NUMBER_TO_TYPE_ADDED, "named-number-added",
306       "named number `%s' added to type `%s'", NULL },
307     { 5, ERR_NAMED_NUMBER_OF_TYPE_CHANGED, "named-number-changed",
308       "named number `%s' changed to `%s' in type `%s'", NULL },
309     { 3, ERR_NAMED_BIT_OF_TYPE_ADDED_OLD_BYTE, "named-bit-added-old-byte",
310       "named bit `%s' added without starting in a new byte in type `%s'", NULL },
311     { 6, ERR_PREVIOUS_IMPLICIT_DEFINITION, "previous-definition",
312       "previous implicit definition", NULL },
313     { 2, ERR_STATUS_CHANGED_IMPLICIT, "status-change",
314       "status change from `%s' to `%s' for implicit type", NULL },
315     { 5, ERR_LEGAL_STATUS_CHANGED_IMPLICIT, "status-change",
316       "legal status change from `%s' to `%s' for implicit type", NULL },
317     { 3, ERR_LENGTH_OF_TYPE_ADDED, "range-added",
318       "size `%s' added to type `%s'", NULL },
319     { 3, ERR_LENGTH_OF_TYPE_REMOVED, "range-removed",
320       "size `%s' removed from type `%s'", NULL },
321     { 5, ERR_STATUS_ADDED, "status-added",
322       "status added to `%s'", NULL },
323     { 3, ERR_STATUS_REMOVED, "status-removed",
324       "status removed from `%s'", NULL },
325     { 2, ERR_MANDATORY_GROUP_ADDED, "mandatory-added",
326       "mandatory group `%s' added to `%s'", NULL },
327     { 2, ERR_MANDATORY_GROUP_REMOVED, "mandatory-removed",
328       "mandatory group `%s' removed from `%s'", NULL },
329     { 2, ERR_MANDATORY_EXT_GROUP_ADDED, "mandatory-added",
330       "mandatory group `%s::%s' added to `%s'", NULL },
331     { 2, ERR_MANDATORY_EXT_GROUP_REMOVED, "mandatory-removed",
332       "mandatory group `%s::%s' removed from `%s'", NULL },
333     { 2, ERR_OPTION_ADDED, "option-added",
334       "optional group `%s' added to `%s'", NULL },
335     { 2, ERR_OPTION_REMOVED, "option-removed",
336       "optional group `%s' removed from `%s'", NULL },
337     { 2, ERR_EXT_OPTION_ADDED, "option-added",
338       "optional group `%s::%s' added to `%s'", NULL },
339     { 2, ERR_EXT_OPTION_REMOVED, "option-removed",
340       "optional group `%s::%s' removed from `%s'", NULL },
341     { 5, ERR_REFINEMENT_ADDED, "refinement-added",
342       "object refinement for `%s' added to `%s'", NULL },
343     { 2, ERR_REFINEMENT_REMOVED, "refinement-removed",
344       "object refinement for `%s' removed from `%s'", NULL },
345     { 5, ERR_EXT_REFINEMENT_ADDED, "refinement-added",
346       "object refinement for `%s::%s' added to `%s'", NULL },
347     { 2, ERR_EXT_REFINEMENT_REMOVED, "refinement-removed",
348       "object refinement for `%s::%s' removed from `%s'", NULL },
349     { 3, ERR_MANDATORY_REMOVED, "mandatory-removed",
350       "%s `%s' is mandatory under `%s' but not mandatory under `%s'", NULL },
351     { 3, ERR_MANDATORY_ADDED, "mandatory-added",
352       "%s `%s' is not mandatory under `%s' but mandatory under `%s'", NULL },
353     { 3, ERR_OPTIONAL_REMOVED, "optional-removed",
354       "%s `%s' is conditionally optional under `%s' but not under `%s'", NULL },
355     { 3, ERR_OPTIONAL_ADDED, "optional-added",
356       "%s `%s' is not conditionally optional under `%s' but under `%s'", NULL },
357     { 3, ERR_MANDATORY_EXT_REMOVED, "mandatory-removed",
358       "%s `%s::%s' is mandatory under `%s' but not mandatory under `%s'", NULL },
359     { 3, ERR_MANDATORY_EXT_ADDED, "mandatory-added",
360       "%s `%s::%s' is not mandatory under `%s' but mandatory under `%s'", NULL },
361     { 3, ERR_OPTIONAL_EXT_REMOVED, "optional-removed",
362       "%s `%s::%s' is conditionally optional under `%s' but not under `%s'", NULL },
363     { 3, ERR_OPTIONAL_EXT_ADDED, "optional-added",
364       "%s `%s::%s' is not conditionally optional under `%s' but under `%s'", NULL },
365     { 0, 0, NULL, NULL }
366 };
367
368
369
370 static char *smiStringDecl(SmiDecl macro)
371 {
372     return
373         (macro == SMI_DECL_UNKNOWN)           ? "unknown construct" :
374         (macro == SMI_DECL_IMPLICIT_TYPE)     ? "implicit construct" :
375         (macro == SMI_DECL_TYPEASSIGNMENT)    ? "type assignment" :
376         (macro == SMI_DECL_IMPL_SEQUENCEOF)   ? "implicit sequence-of construct" :
377         (macro == SMI_DECL_VALUEASSIGNMENT)   ? "value assignment" :
378         (macro == SMI_DECL_OBJECTTYPE)        ? "object definition" :
379         (macro == SMI_DECL_OBJECTIDENTITY)    ? "object identity definition" :
380         (macro == SMI_DECL_MODULEIDENTITY)    ? "module identity definition" :
381         (macro == SMI_DECL_NOTIFICATIONTYPE)  ? "notification definition" :
382         (macro == SMI_DECL_TRAPTYPE)          ? "trap definition" :
383         (macro == SMI_DECL_OBJECTGROUP)       ? "object group definition" :
384         (macro == SMI_DECL_NOTIFICATIONGROUP) ? "notification group definition" :
385         (macro == SMI_DECL_MODULECOMPLIANCE)  ? "module compliance definition" :
386         (macro == SMI_DECL_AGENTCAPABILITIES) ? "agent capabilities definition" :
387         (macro == SMI_DECL_TEXTUALCONVENTION) ? "textual convention definition" :
388         (macro == SMI_DECL_MACRO)             ? "macro definition" :
389         (macro == SMI_DECL_COMPL_GROUP)       ? "optional group" :
390         (macro == SMI_DECL_COMPL_OBJECT)      ? "object refinement" :
391         (macro == SMI_DECL_MODULE)            ? "module" :
392         (macro == SMI_DECL_TYPEDEF)           ? "typedef" :
393         (macro == SMI_DECL_NODE)              ? "node" :
394         (macro == SMI_DECL_SCALAR)            ? "scalar" :
395         (macro == SMI_DECL_TABLE)             ? "table" :
396         (macro == SMI_DECL_ROW)               ? "row" :
397         (macro == SMI_DECL_COLUMN)            ? "column" :
398         (macro == SMI_DECL_NOTIFICATION)      ? "notification" :
399         (macro == SMI_DECL_GROUP)             ? "group" :
400         (macro == SMI_DECL_COMPLIANCE)        ? "compliance" :
401                                                 "<UNDEFINED>";
402 }
403
404
405
406 static void
407 setErrorSeverity(char *pattern, int severity)
408 {
409     int i;
410     
411     for (i = 0; errors[i].fmt; i++) {
412         if (strstr(errors[i].tag, pattern) == errors[i].tag) {
413             errors[i].level = severity;
414         }
415     }
416 }
417
418
419
420 static void
421 printError(SmiModule *smiModule, int id, int line, va_list ap)
422 {
423     int i;
424
425     /*
426      * Search for the tag instead of just using the id as an index so
427      * that we do not run into trouble if the id is bogus.
428      */
429
430     for (i = 0; errors[i].fmt; i++) {
431         if (errors[i].id == id) break;
432     }
433     if (! errors[i].fmt) {
434         i = 0;          /* assumes that 0 is the internal error */
435     }
436     
437     if (errors[i].level <= errorLevel) {
438         fprintf(stdout, "%s", smiModule->path);
439
440         if (line >= 0) {
441             fprintf(stdout, ":%d", line);
442         }
443         fprintf(stdout, " ");
444         if (sFlag) {
445             fprintf(stdout, "[%d] ", errors[i].level);
446         }
447         if (mFlag) {
448             fprintf(stdout, "{%s} ", errors[i].tag);
449         }
450         switch (errors[i].level) {
451         case 4:
452         case 5:
453             fprintf(stdout, "warning: ");
454             break;
455         case 6: 
456             fprintf(stdout, "info: ");
457             break;
458         }
459         vfprintf(stdout, errors[i].fmt, ap);
460         fprintf(stdout, "\n");
461     }
462 }
463
464
465
466 static void
467 printErrorAtLine(SmiModule *smiModule, int id, int line, ...)
468 {
469     va_list ap;
470
471     va_start(ap, line);
472     printError(smiModule, id, line, ap);
473     va_end(ap);
474 }
475
476
477
478 static char*
479 getStringTime(time_t t)
480 {
481     static char   s[27];
482     struct tm     *tm;
483
484     tm = gmtime(&t);
485     sprintf(s, "%04d-%02d-%02d %02d:%02d",
486             tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
487             tm->tm_hour, tm->tm_min);
488     return s;
489 }
490
491
492
493 static char*
494 getStringNodekind(SmiNodekind nodekind)
495 {
496     return
497         (nodekind == SMI_NODEKIND_UNKNOWN)      ? "unknown" :
498         (nodekind == SMI_NODEKIND_NODE)         ? "node" :
499         (nodekind == SMI_NODEKIND_SCALAR)       ? "scalar" :
500         (nodekind == SMI_NODEKIND_TABLE)        ? "table" :
501         (nodekind == SMI_NODEKIND_ROW)          ? "row" :
502         (nodekind == SMI_NODEKIND_COLUMN)       ? "column" :
503         (nodekind == SMI_NODEKIND_NOTIFICATION) ? "notification" :
504         (nodekind == SMI_NODEKIND_GROUP)        ? "group" :
505         (nodekind == SMI_NODEKIND_COMPLIANCE)   ? "compliance" :
506         (nodekind == SMI_NODEKIND_CAPABILITIES) ? "capabilities" :
507                                                   "<unknown>";
508 }
509
510
511
512 static int
513 diffStrings(const char *s1, const char *s2)
514 {
515     int i, j;
516
517     for (i = 0, j = 0; s1[i] && s2[j]; i++, j++) {
518         while (s1[i] && isspace((int) s1[i])) i++;
519         while (s2[j] && isspace((int) s2[j])) j++;
520         if (! s1[i] || ! s2[j]) break;
521         if (s1[i] != s2[j]) {
522             return 1;
523         }
524     }
525     return (s1[i] != s2[j]);
526 }
527
528
529
530 static int
531 checkName(SmiModule *oldModule, int oldLine,
532             SmiModule *newModule, int newLine,
533             char *oldName, char *newName)
534 {
535     int code = 0;
536     
537     if (!oldName && newName) {
538         printErrorAtLine(newModule, ERR_NAME_ADDED,
539                          newLine, newName);
540     }
541
542     if (oldName && !newName) {
543         printErrorAtLine(oldModule, ERR_NAME_REMOVED,
544                          oldLine, oldName);
545     }
546     
547     if (oldName && newName && strcmp(oldName, newName) != 0) {
548         printErrorAtLine(newModule, ERR_NAME_CHANGED,
549                          newLine, oldName, newName);
550         code |= CODE_SHOW_PREVIOUS;
551     }
552
553     return code;
554 }
555
556
557
558 static int
559 checkDecl(SmiModule *oldModule, int oldLine,
560           SmiModule *newModule, int newLine,
561           char *name, SmiDecl oldDecl, SmiDecl newDecl)
562 {
563     int code = 0;
564
565     if (oldDecl != newDecl) {
566         printErrorAtLine(newModule, ERR_DECL_CHANGED,
567                          newLine, name);
568         code |= CODE_SHOW_PREVIOUS;
569     }
570     return code;
571 }
572
573
574
575 static char*
576 getStringStatus(SmiStatus status)
577 {
578     char *statStr;
579     
580     switch( status ) {
581     case SMI_STATUS_CURRENT:
582         statStr = "current";
583         break;
584     case SMI_STATUS_DEPRECATED:
585         statStr = "deprecated";
586         break;
587     case SMI_STATUS_OBSOLETE:
588         statStr = "obsolete";
589         break;
590     case SMI_STATUS_MANDATORY:
591         statStr = "mandatory";
592         break;
593     case SMI_STATUS_OPTIONAL:
594         statStr = "optional";
595         break;
596     case SMI_STATUS_UNKNOWN:
597     default:
598         statStr = "unknown";
599         break;
600     }
601     return statStr;
602 }
603
604
605
606 static int
607 checkStatus(SmiModule *oldModule, int oldLine,
608             SmiModule *newModule, int newLine,
609             char *name, SmiStatus oldStatus, SmiStatus newStatus)
610 {
611     int code = 0;
612
613     if (oldStatus == newStatus) {
614         return code;
615     }
616     
617     if (oldStatus == SMI_STATUS_UNKNOWN) {
618         printErrorAtLine(newModule, ERR_STATUS_ADDED,
619                          newLine, name);
620     } else if (newStatus == SMI_STATUS_UNKNOWN) {
621         printErrorAtLine(newModule, ERR_STATUS_REMOVED,
622                          newLine, name);
623
624     } else if (((oldStatus == SMI_STATUS_CURRENT
625           && (newStatus == SMI_STATUS_DEPRECATED
626               || newStatus == SMI_STATUS_OBSOLETE)))
627         || ((oldStatus == SMI_STATUS_DEPRECATED
628              && newStatus == SMI_STATUS_OBSOLETE))) {
629         if (name) {
630             printErrorAtLine(newModule, ERR_LEGAL_STATUS_CHANGED, newLine,
631                              getStringStatus(oldStatus),
632                              getStringStatus(newStatus),
633                              name);
634             code |= CODE_SHOW_PREVIOUS;
635         } else {
636             printErrorAtLine(newModule, ERR_LEGAL_STATUS_CHANGED_IMPLICIT, newLine,
637                              getStringStatus(oldStatus),
638                              getStringStatus(newStatus));
639             code |= CODE_SHOW_PREVIOUS_IMPLICIT;
640         }
641     } else {
642         if (name) {
643             printErrorAtLine(newModule, ERR_STATUS_CHANGED, newLine,
644                              getStringStatus(oldStatus),
645                              getStringStatus(newStatus),
646                              name);
647             code |= CODE_SHOW_PREVIOUS;
648         } else {
649             printErrorAtLine(newModule, ERR_STATUS_CHANGED_IMPLICIT,
650                              newLine,
651                              getStringStatus(oldStatus),
652                              getStringStatus(newStatus));
653             code |= CODE_SHOW_PREVIOUS_IMPLICIT;
654         }
655     }
656
657     return code;
658 }
659
660
661
662 static char*
663 getStringAccess( SmiAccess smiAccess )
664 {
665     switch( smiAccess ) {
666     case SMI_ACCESS_NOT_IMPLEMENTED: return "not-implemented";
667     case SMI_ACCESS_NOT_ACCESSIBLE : return "not-accessible";
668     case SMI_ACCESS_NOTIFY         : return "notify";
669     case SMI_ACCESS_READ_ONLY      : return "read-only";
670     case SMI_ACCESS_READ_WRITE     : return "read-write";
671     case SMI_ACCESS_UNKNOWN:
672     default: return "unknown";
673     }
674 }
675
676
677
678 static int
679 checkAccess(SmiModule *oldModule, int oldLine,
680             SmiModule *newModule, int newLine,
681             char *name, SmiAccess oldAccess, SmiAccess newAccess)
682 {
683     int code = 0;
684     
685     if (oldAccess == newAccess) {
686         return code;
687     }
688
689     if (oldAccess == SMI_ACCESS_UNKNOWN) {
690         printErrorAtLine(newModule, ERR_ACCESS_ADDED,
691                          newLine, name);
692     } else if (newAccess == SMI_ACCESS_UNKNOWN) {
693         printErrorAtLine(newModule, ERR_ACCESS_REMOVED,
694                          newLine, name);
695     } else {
696         printErrorAtLine(newModule, ERR_ACCESS_CHANGED,
697                          newLine, name,
698                          getStringAccess( oldAccess ),
699                          getStringAccess( newAccess ));
700         code |= CODE_SHOW_PREVIOUS;
701     }
702
703     return code;
704 }
705
706
707
708 static int
709 checkDescription(SmiModule *oldModule, int oldLine,
710                  SmiModule *newModule, int newLine,
711                  char *name, SmiDecl decl, char *oldDescr, char *newDescr)
712 {
713     int code = 0;
714     
715     if (!oldDescr && newDescr) {
716         printErrorAtLine(newModule, ERR_DESCR_ADDED,
717                          newLine, name);
718     }
719
720     if (oldDescr && !newDescr) {
721         printErrorAtLine(newModule, ERR_DESCR_REMOVED,
722                          newLine, name);
723         code |= CODE_SHOW_PREVIOUS;
724     }
725
726     if (oldDescr && newDescr && diffStrings(oldDescr, newDescr)) {
727         printErrorAtLine(newModule, ERR_DESCR_CHANGED,
728                          newLine, smiStringDecl(decl), name);
729         code |= CODE_SHOW_PREVIOUS;
730     }
731
732     return code;
733 }
734
735
736
737 static int
738 checkReference(SmiModule *oldModule, int oldLine,
739                SmiModule *newModule, int newLine,
740                char *name, char *oldRef, char *newRef)
741 {
742     int code = 0;
743     
744     if (!oldRef && newRef) {
745         printErrorAtLine(newModule, ERR_REF_ADDED,
746                          newLine, name);
747     }
748
749     if (oldRef && !newRef) {
750         printErrorAtLine(oldModule, ERR_REF_REMOVED,
751                          oldLine, name);
752     }
753     
754     if (oldRef && newRef && diffStrings(oldRef, newRef) != 0) {
755         printErrorAtLine(newModule, ERR_REF_CHANGED,
756                          newLine, name);
757         code |= CODE_SHOW_PREVIOUS;
758     }
759
760     return code;
761 }
762
763
764
765 static int
766 checkFormat(SmiModule *oldModule, int oldLine,
767             SmiModule *newModule, int newLine,
768             char *name, char *oldFormat, char *newFormat)
769 {
770     int code = 0;
771
772     if (!oldFormat && newFormat) {
773         printErrorAtLine(newModule, ERR_FORMAT_ADDED,
774                          newLine, name);
775     }
776
777     if (oldFormat && !newFormat) {
778         printErrorAtLine(oldModule, ERR_FORMAT_REMOVED,
779                          oldLine, name);
780     }
781     
782     if (oldFormat && newFormat && strcmp(oldFormat, newFormat) != 0) {
783         printErrorAtLine(newModule, ERR_FORMAT_CHANGED,
784                          newLine, name);
785         code |= CODE_SHOW_PREVIOUS;
786     }
787
788     return code;
789 }
790
791
792
793 static int
794 checkUnits(SmiModule *oldModule, int oldLine,
795            SmiModule *newModule, int newLine,
796            char *name, char *oldUnits, char *newUnits)
797 {
798     int code = 0;
799     
800     if (!oldUnits && newUnits) {
801         printErrorAtLine(newModule, ERR_UNITS_ADDED,
802                          newLine, name);
803     }
804
805     if (oldUnits && !newUnits) {
806         printErrorAtLine(oldModule, ERR_UNITS_REMOVED,
807                          oldLine, name);
808     }
809     
810     if (oldUnits && newUnits && strcmp(oldUnits, newUnits) != 0) {
811         printErrorAtLine(newModule, ERR_UNITS_CHANGED,
812                          newLine, name);
813         code |= CODE_SHOW_PREVIOUS;
814     }
815
816     return code;
817 }
818
819
820
821 static SmiType*
822 findTypeWithRange(SmiType *smiType)
823 {
824     SmiType *iterType;
825
826     for (iterType = smiType; iterType; iterType = smiGetParentType(iterType)) {
827         if (smiGetFirstRange(iterType)) {
828             return iterType;
829         }
830     }
831     return NULL;
832 }
833
834
835 /* This function assumes that the compared values have the same basetype.
836  * If the basetype is different, no comparison is done
837  * and '0' will be returned. Same for SMI_BASETYPE_UNKNOWN.
838  */
839 static int 
840 cmpSmiValues( SmiValue a, SmiValue b )
841 {
842     unsigned int i;
843     int changed = 0;
844
845     switch (a.basetype) {
846     case SMI_BASETYPE_INTEGER32:
847     case SMI_BASETYPE_ENUM :
848         changed = (a.value.integer32 != b.value.integer32);
849         break;
850     case SMI_BASETYPE_UNSIGNED32:
851         changed = (a.value.unsigned32 != b.value.unsigned32);
852         break;
853     case SMI_BASETYPE_INTEGER64:
854         changed = (a.value.integer64 != b.value.integer64);
855         break;
856     case SMI_BASETYPE_UNSIGNED64:
857         changed = (a.value.unsigned64 != b.value.unsigned64);
858         break;
859     case SMI_BASETYPE_FLOAT32:
860         changed = (a.value.float32 != b.value.float32);
861         break;
862     case SMI_BASETYPE_FLOAT64:
863         changed = (a.value.float64 != b.value.float64);
864         break;
865     case SMI_BASETYPE_FLOAT128:
866         changed = (a.value.float128 != b.value.float128);
867         break;
868     case SMI_BASETYPE_OCTETSTRING:
869     case SMI_BASETYPE_BITS:
870         changed = (a.len != b.len)
871             || (memcmp(a.value.ptr, b.value.ptr, a.len) != 0);
872         break;
873     case SMI_BASETYPE_OBJECTIDENTIFIER:
874         changed = (a.len != b.len);
875         for (i = 0; !changed && i < a.len; i++) {
876             changed = (a.value.oid[i] - b.value.oid[i]);
877         }
878         break;
879     case SMI_BASETYPE_UNKNOWN:
880     case SMI_BASETYPE_POINTER:
881         /* this should not occur */
882         break;
883     }
884     
885     return changed;
886 }
887
888 #if 0
889 static char*
890 getTypeName(SmiType *smiType, SmiModule *smiModule)
891 {
892     char* name;
893     SmiModule * tm;
894     
895     if( ! smiType ) {
896         return 0;
897     }
898
899     if( smiType->name ) {
900         tm = smiGetTypeModule( smiType );
901         if( smiModule != tm ) {
902             if( smiModule->name ) {
903                 name = (char *)malloc( strlen( smiType->name ) +
904                                        strlen( tm->name ) + 5 );
905                 sprintf( name, "%s::%s",
906                          tm->name, smiType->name );
907             }
908             else {
909                 name = strdup( smiType->name );
910             }
911         }
912         else {
913             name = strdup( smiType->name );
914         }
915     }
916     else {
917         name = NULL;
918     }
919     return name;
920 }
921
922 static void
923 iterateTypeImports(char *typeName,
924                    SmiType *smiType, SmiType *smiTwR,
925                    int line,
926                    SmiModule *smiModule)
927 {
928     SmiType *iterType, *oldIterType;
929     char *iterTypeName, *oldIterTypeName = strdup( typeName );
930
931     iterType =  smiType;
932     while( 1 ) {
933         iterType = smiGetParentType( iterType );
934         iterTypeName = getTypeName( iterType, smiModule );      
935         if( (!iterType) || !iterTypeName ) {
936             return;
937         }
938         printErrorAtLine( smiGetTypeModule( smiType ),
939                           ERR_TYPE_BASED_ON,
940                           line,
941                           oldIterTypeName,
942                           iterTypeName );
943         free( oldIterTypeName );
944         oldIterTypeName = iterTypeName;
945         oldIterType = iterType;
946     }
947 }
948 #endif
949
950 static char *getValueString(SmiValue *valuePtr, SmiType *typePtr)
951 {
952     static char    s[1024];
953     char           ss[9];
954     int            n;
955     unsigned int   i;
956     SmiNamedNumber *nn;
957     SmiNode        *nodePtr;
958     
959     s[0] = 0;
960     
961     switch (valuePtr->basetype) {
962     case SMI_BASETYPE_UNSIGNED32:
963         sprintf(s, "%lu", valuePtr->value.unsigned32);
964         break;
965     case SMI_BASETYPE_INTEGER32:
966         sprintf(s, "%ld", valuePtr->value.integer32);
967         break;
968     case SMI_BASETYPE_UNSIGNED64:
969         sprintf(s, UINT64_FORMAT, valuePtr->value.unsigned64);
970         break;
971     case SMI_BASETYPE_INTEGER64:
972         sprintf(s, INT64_FORMAT, valuePtr->value.integer64);
973         break;
974     case SMI_BASETYPE_FLOAT32:
975     case SMI_BASETYPE_FLOAT64:
976     case SMI_BASETYPE_FLOAT128:
977         break;
978     case SMI_BASETYPE_ENUM:
979         for (nn = smiGetFirstNamedNumber(typePtr); nn;
980              nn = smiGetNextNamedNumber(nn)) {
981             if (nn->value.value.unsigned32 == valuePtr->value.unsigned32)
982                 break;
983         }
984         if (nn) {
985             sprintf(s, "%s", nn->name);
986         } else {
987             sprintf(s, "%ld", valuePtr->value.integer32);
988         }
989         break;
990     case SMI_BASETYPE_OCTETSTRING:
991         for (i = 0; i < valuePtr->len; i++) {
992             if (!isprint((int)valuePtr->value.ptr[i])) break;
993         }
994         if (i == valuePtr->len) {
995             sprintf(s, "\"%s\"", valuePtr->value.ptr);
996         } else {
997             sprintf(s, "'%*s'H", 2 * valuePtr->len, " ");
998             for (i=0; i < valuePtr->len; i++) {
999                 sprintf(ss, "%02x", valuePtr->value.ptr[i]);
1000                 strncpy(&s[1+2*i], ss, 2);
1001             }
1002         }
1003         break;
1004     case SMI_BASETYPE_BITS:
1005         
1006         sprintf(s, "{");
1007         for (i = 0, n = 0; i < valuePtr->len * 8; i++) {
1008             if (valuePtr->value.ptr[i/8] & (1 << (7-(i%8)))) {
1009                 for (nn = smiGetFirstNamedNumber(typePtr); nn;
1010                      nn = smiGetNextNamedNumber(nn)) {
1011                     if (nn->value.value.unsigned32 == i)
1012                         break;
1013                 }
1014                 if (nn) {
1015                     if (n)
1016                         sprintf(&s[strlen(s)], ", ");
1017                     n++;
1018                     sprintf(&s[strlen(s)], "%s", nn->name);
1019                 }
1020             }
1021         }
1022         sprintf(&s[strlen(s)], "}");
1023         break;
1024     case SMI_BASETYPE_UNKNOWN:
1025     case SMI_BASETYPE_POINTER:
1026         break;
1027     case SMI_BASETYPE_OBJECTIDENTIFIER:
1028         nodePtr = smiGetNodeByOID(valuePtr->len, valuePtr->value.oid);
1029         if (nodePtr) {
1030             sprintf(s, "%s", nodePtr->name);
1031         } else {
1032             strcpy(s, "{");
1033             for (i=0; i < valuePtr->len; i++) {
1034                 if (i) strcat(s, " ");
1035                 sprintf(&s[strlen(s)], "%u", valuePtr->value.oid[i]);
1036             }
1037             strcat(s, "}");
1038         }
1039         break;
1040     }
1041
1042     return s;
1043 }
1044
1045 static char*
1046 getStringSubrange(SmiRange *range, SmiType *smiType)
1047 {
1048     char *minStr, *maxStr, *str;
1049     minStr = strdup( getValueString(&range->minValue, smiType) );
1050     maxStr = strdup( getValueString(&range->maxValue, smiType) );
1051     if (memcmp(&range->minValue, &range->maxValue,
1052                sizeof(SmiValue))) {
1053         str = malloc( strlen( minStr ) + strlen( maxStr ) + 3 );
1054         if( !str ) {
1055             return NULL;
1056         }
1057         sprintf(str, "%s..%s", minStr, maxStr);
1058     } else {
1059         str = strdup( minStr );
1060     }
1061     
1062     return str;
1063 }
1064
1065
1066 static char*
1067 getStringRange(SmiType *smiType)
1068 {
1069     SmiRange *range;
1070     int i;
1071     char *str, *subRange;
1072
1073     str = NULL;
1074     for(i = 0, range = smiGetFirstRange(smiType);
1075         range; i++, range = smiGetNextRange(range)) {
1076         
1077         if (i) {
1078             str = realloc( str, strlen( str ) +2 );
1079             if( str ) {
1080                 sprintf(str, "%s|", str);
1081             }
1082             
1083         }
1084         else {
1085             str = strdup("(");
1086         }
1087         
1088         subRange = getStringSubrange( range, smiType );
1089         if( !subRange ) {
1090             return NULL;
1091         }
1092         str = realloc( str, strlen( str ) + strlen( subRange ) + 1 );
1093         if( !str ) {
1094             return NULL;
1095         }
1096         sprintf( str, "%s%s", str, subRange );
1097         
1098     }
1099     str = realloc( str, strlen( str ) + 2 );
1100     if( str ) {
1101         sprintf(str, "%s)", str);
1102     }
1103     return str;
1104 }
1105
1106 static void
1107 printRangeChangeError( SmiType *oldTwR, SmiType *newTwR,
1108                        SmiModule *newModule, char *name )
1109 {
1110     char *strOldRange, *strNewRange;
1111     int error, errorOT;
1112     if( newTwR->basetype == SMI_BASETYPE_OCTETSTRING ) {
1113         error =  ERR_LENGTH_CHANGED;
1114         errorOT = ERR_LENGTH_OF_TYPE_CHANGED;
1115     }
1116     else {
1117         error = ERR_RANGE_CHANGED;
1118         errorOT = ERR_RANGE_OF_TYPE_CHANGED;
1119     }
1120     strOldRange = getStringRange( oldTwR );
1121     strNewRange = getStringRange( newTwR );
1122     if( name ) {
1123         printErrorAtLine(newModule,
1124                          error,
1125                          smiGetTypeLine( newTwR ),
1126                          name, strOldRange, strNewRange );
1127     }
1128     else {
1129         printErrorAtLine(newModule,
1130                          errorOT,
1131                          smiGetTypeLine( newTwR ),
1132                          oldTwR->name, strOldRange, strNewRange );
1133     }
1134     free( strOldRange );
1135     free( strNewRange );
1136 }
1137
1138 static void
1139 checkRanges(SmiModule *oldModule, int oldLine, 
1140             SmiModule *newModule, int newLine,
1141             char *name,
1142             SmiType *oldType, SmiType *newType)
1143 {
1144     SmiType *oldTwR, *newTwR; /* parent types with ranges */
1145    
1146     oldTwR = findTypeWithRange(oldType);
1147     newTwR = findTypeWithRange(newType);
1148     
1149     if (!oldTwR && newTwR) {
1150         char *strRange;
1151         int error, errorOT;
1152
1153         strRange = getStringRange( newTwR );
1154         if( newTwR->basetype == SMI_BASETYPE_OCTETSTRING ) {
1155             error = ERR_LENGTH_ADDED;
1156             errorOT = ERR_LENGTH_OF_TYPE_ADDED;
1157         }
1158         else {
1159             error = ERR_RANGE_ADDED;
1160             errorOT = ERR_RANGE_OF_TYPE_ADDED;
1161         }
1162         if( name ) {
1163             printErrorAtLine(newModule, error,
1164                              newLine, strRange, name);
1165         }
1166         else {
1167             printErrorAtLine( newModule, errorOT,
1168                               newLine, strRange, newTwR->name );
1169         }
1170         
1171         free( strRange );
1172         return;
1173     }
1174     
1175     if (oldTwR && !newTwR) {
1176         char *strRange;
1177         int error, errorOT;
1178         
1179         strRange = getStringRange( oldTwR );
1180         if( oldTwR->basetype == SMI_BASETYPE_OCTETSTRING ) {
1181             error = ERR_LENGTH_REMOVED;
1182             errorOT = ERR_LENGTH_OF_TYPE_REMOVED;
1183         }
1184         else {
1185             error = ERR_RANGE_REMOVED;
1186             errorOT = ERR_RANGE_OF_TYPE_REMOVED;
1187         }
1188         if( name ) {
1189             printErrorAtLine( newModule, error,
1190                               newLine, strRange, name);
1191         }
1192         else {
1193             printErrorAtLine( newModule, errorOT,
1194                               newLine, strRange, oldTwR->name );
1195         }
1196         free( strRange );
1197
1198         if( oldTwR == oldType ) {
1199             
1200             printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
1201                              oldLine, name);
1202         }
1203         else {
1204             SmiModule *modTwR;
1205             int line;
1206             
1207             modTwR = smiGetTypeModule( oldTwR );
1208             line = smiGetTypeLine( oldTwR );
1209             
1210             printErrorAtLine( modTwR, ERR_PREVIOUS_DEFINITION,
1211                               line, name );
1212
1213         }
1214         return;
1215     }
1216     
1217     if (oldTwR && newTwR) {
1218         
1219         SmiRange *oldRange, *newRange;
1220         oldRange = smiGetFirstRange(oldTwR);
1221         newRange = smiGetFirstRange(newTwR);
1222
1223         while( oldRange || newRange ) {
1224
1225             if( oldRange && newRange ) {
1226                 
1227                 if(cmpSmiValues(oldRange->minValue, newRange->minValue) ||
1228                    cmpSmiValues(oldRange->maxValue, newRange->maxValue)) {
1229                     printRangeChangeError( oldTwR, newTwR, newModule, name );
1230                     return;
1231                 }
1232             }
1233             
1234             else if (oldRange){
1235                 printRangeChangeError( oldTwR, newTwR, newModule, name );
1236                 return;
1237             }
1238             
1239             else if( newRange ) {
1240                 printRangeChangeError( oldTwR, newTwR, newModule, name );
1241                 return;
1242             }
1243             
1244             oldRange = smiGetNextRange( oldRange );
1245             newRange = smiGetNextRange( newRange );
1246         }
1247     }
1248 }
1249
1250
1251
1252 static void
1253 checkDefVal(SmiModule *oldModule, int oldLine,
1254             SmiModule *newModule, int newLine,
1255             char *name,
1256             SmiValue oldVal, SmiValue newVal)
1257 {
1258     if ((oldVal.basetype != SMI_BASETYPE_UNKNOWN) && 
1259         (newVal.basetype == SMI_BASETYPE_UNKNOWN)) {
1260         printErrorAtLine(newModule, ERR_DEFVAL_REMOVED, newLine, name);
1261         printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION, oldLine, name);
1262         return;
1263     }
1264
1265     if ((oldVal.basetype == SMI_BASETYPE_UNKNOWN) && 
1266         (newVal.basetype != SMI_BASETYPE_UNKNOWN)) {
1267         printErrorAtLine(newModule, ERR_DEFVAL_ADDED, newLine, name);
1268         return;
1269     }
1270
1271 #if 0 /* changed base type is reported, anyway. */
1272     if (oldVal.basetype != newVal.basetype) {
1273         printErrorAtLine(newModule, ERR_DEFVAL_CHANGED, newLine, name);
1274         printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION, oldLine, name);
1275         return;
1276     }
1277 #endif
1278     
1279     if (cmpSmiValues(oldVal, newVal)) {
1280         printErrorAtLine(newModule, ERR_DEFVAL_CHANGED, newLine,name);
1281         printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION, oldLine, name);
1282     }
1283 }
1284
1285
1286
1287 static void
1288 checkNamedNumbers(SmiModule *oldModule, int oldLine,
1289                   SmiModule *newModule, int newLine,
1290                   char *name, SmiNode *smiNode,
1291                   SmiType *oldType, SmiType *newType)
1292 {
1293     SmiNamedNumber *oldNN, *newNN;
1294
1295     oldNN = smiGetFirstNamedNumber( oldType );
1296     newNN = smiGetFirstNamedNumber( newType );
1297
1298     while( oldNN || newNN ) {
1299         if( oldNN && !newNN ) {
1300             if( smiNode ) {
1301                 printErrorAtLine(newModule, ERR_NAMED_NUMBER_REMOVED, newLine,
1302                                  oldNN->name, smiNode->name);
1303             }
1304             else {
1305                 printErrorAtLine(newModule, ERR_NAMED_NUMBER_OF_TYPE_REMOVED,
1306                                  newLine, oldNN->name, name);
1307             }
1308             oldNN = smiGetNextNamedNumber( oldNN );
1309         }
1310         else if( !oldNN && newNN ) {
1311             /* check if new byte has been started (bits only) */
1312             if( newType->basetype == SMI_BASETYPE_BITS ) {
1313                 SmiNamedNumber *veryOldNN = NULL, *iterNN;
1314
1315                 /* find largest old named number */
1316                 for( iterNN = smiGetFirstNamedNumber( oldType );
1317                      iterNN; iterNN = smiGetNextNamedNumber( iterNN ) ) {
1318                     veryOldNN = iterNN;
1319                 }
1320                 
1321                 if( veryOldNN ) {
1322                     /* we assume that we have bits, and the named numbers
1323                        of bits are stored in NN->value.value.unsigned32 */
1324                     if( newNN->value.value.unsigned32 / 8 <=
1325                         veryOldNN->value.value.unsigned32 / 8 ) {
1326                         if( smiNode ) {
1327                             printErrorAtLine( newModule,
1328                                               ERR_NAMED_BIT_ADDED_OLD_BYTE,
1329                                               newLine, newNN->name,
1330                                               smiNode->name );
1331                         }
1332                         else {
1333                             printErrorAtLine( newModule,
1334                                               ERR_NAMED_BIT_OF_TYPE_ADDED_OLD_BYTE,
1335                                               newLine, newNN->name, name );
1336                         }
1337                     }
1338                     else {
1339                         if( smiNode ){
1340                             printErrorAtLine(newModule, ERR_NAMED_NUMBER_ADDED,
1341                                              newLine, newNN->name,
1342                                              smiNode->name);
1343                         }
1344                         else {
1345                             printErrorAtLine(newModule,
1346                                              ERR_NAMED_NUMBER_TO_TYPE_ADDED,
1347                                              newLine, newNN->name, name);
1348                         }
1349                     }
1350                 }
1351                 else {
1352                     if( smiNode ) {
1353                         printErrorAtLine(newModule, ERR_NAMED_NUMBER_ADDED,
1354                                          newLine, newNN->name, smiNode->name);
1355                     }
1356                     else {
1357                         printErrorAtLine(newModule,
1358                                          ERR_NAMED_NUMBER_TO_TYPE_ADDED,
1359                                          newLine, newNN->name, name);
1360                     }
1361                 }
1362             }
1363             else {
1364                 if( smiNode ) {
1365                     printErrorAtLine(newModule, ERR_NAMED_NUMBER_ADDED,
1366                                      newLine, newNN->name, smiNode->name);
1367                 }
1368                 else {
1369                     printErrorAtLine(newModule, ERR_NAMED_NUMBER_TO_TYPE_ADDED,
1370                                      newLine, newNN->name, name);
1371                 }
1372             }
1373             newNN = smiGetNextNamedNumber( newNN );
1374         }
1375         else if( oldNN && newNN ) {
1376             switch( oldType->basetype ) {
1377             case SMI_BASETYPE_BITS:
1378                 /* we assume that we have bits, and the named numbers
1379                    of bits are stored in NN->value.value.unsigned32 */
1380                 if( oldNN->value.value.unsigned32 <
1381                     newNN->value.value.unsigned32 ) {
1382                     if( smiNode ) {
1383                         printErrorAtLine( newModule, ERR_NAMED_NUMBER_REMOVED,
1384                                           newLine,
1385                                           oldNN->name,
1386                                           smiNode->name );
1387                     }
1388                     else {
1389                         printErrorAtLine( newModule,
1390                                           ERR_NAMED_NUMBER_OF_TYPE_REMOVED,
1391                                           newLine,
1392                                           oldNN->name, name );
1393                     }
1394                     oldNN = smiGetNextNamedNumber( oldNN );
1395                 }
1396                 else if( oldNN->value.value.unsigned32 >
1397                          newNN->value.value.unsigned32 ) {
1398                     if( smiNode ) {
1399                         printErrorAtLine( newModule, ERR_NAMED_NUMBER_ADDED,
1400                                           newLine, newNN->name,
1401                                           smiNode->name );
1402                     }
1403                     else {
1404                         printErrorAtLine( newModule,
1405                                           ERR_NAMED_NUMBER_TO_TYPE_ADDED,
1406                                           newLine, newNN->name, name );
1407                     }
1408                     newNN = smiGetNextNamedNumber( newNN );
1409                 }
1410                 else {
1411                     if( strcmp( oldNN->name, newNN->name ) ) {
1412                         if( smiNode ) {
1413                             printErrorAtLine( newModule,
1414                                               ERR_NAMED_NUMBER_CHANGED,
1415                                               newLine,
1416                                               oldNN->name, newNN->name,
1417                                               smiNode->name );
1418                         }
1419                         else {
1420                             printErrorAtLine( newModule,
1421                                               ERR_NAMED_NUMBER_OF_TYPE_CHANGED,
1422                                               newLine,
1423                                               oldNN->name, newNN->name, name );
1424                         }
1425                     }
1426                     oldNN = smiGetNextNamedNumber( oldNN );
1427                     newNN = smiGetNextNamedNumber( newNN );
1428                 }
1429                 break;
1430             case SMI_BASETYPE_ENUM:
1431                 /* we assume that we have an enumeration, and the named numbers
1432                    of an enumeration are stored in NN->value.value.integer32 */
1433                 if( oldNN->value.value.integer32 <
1434                     newNN->value.value.integer32 ) {
1435                     if( smiNode ) {
1436                         printErrorAtLine( newModule, ERR_NAMED_NUMBER_REMOVED,
1437                                           newLine,oldNN->name,
1438                                           smiNode->name );
1439                     }
1440                     else {
1441                         printErrorAtLine( newModule,
1442                                           ERR_NAMED_NUMBER_OF_TYPE_REMOVED,
1443                                           newLine, oldNN->name, name );
1444                     }
1445                     oldNN = smiGetNextNamedNumber( oldNN );
1446                 }
1447                 else if( oldNN->value.value.integer32 >
1448                          newNN->value.value.integer32 ) {
1449                     if( smiNode ) {
1450                         printErrorAtLine( newModule, ERR_NAMED_NUMBER_ADDED,
1451                                           newLine ,newNN->name,
1452                                           smiNode->name );
1453                     }
1454                     else {
1455                         printErrorAtLine( newModule,
1456                                           ERR_NAMED_NUMBER_TO_TYPE_ADDED,
1457                                           newLine, newNN->name, name );
1458                     }
1459                     newNN = smiGetNextNamedNumber( newNN );
1460                 }
1461                 else {
1462                     if( strcmp( oldNN->name, newNN->name ) ) {
1463                         if( smiNode ) {
1464                             printErrorAtLine( newModule,
1465                                               ERR_NAMED_NUMBER_CHANGED,
1466                                               newLine, oldNN->name,
1467                                               newNN->name, smiNode->name );
1468                         }
1469                         else {
1470                             printErrorAtLine( newModule,
1471                                               ERR_NAMED_NUMBER_OF_TYPE_CHANGED,
1472                                               newLine, oldNN->name,
1473                                               newNN->name, name );
1474                         }
1475                     }
1476                     oldNN = smiGetNextNamedNumber( oldNN );
1477                     newNN = smiGetNextNamedNumber( newNN );
1478                 }
1479                 break;
1480             default:
1481                 break;
1482             }
1483         }
1484     }
1485 }
1486
1487
1488 static void
1489 checkTypeCompatibility(SmiModule *oldModule, SmiNode *oldNode,
1490                        SmiType *oldType,
1491                        SmiModule *newModule, int newLine,
1492                        SmiType *newType)
1493 {
1494     int oldLine;
1495     char *oldName;
1496
1497     if ((!oldType) && (!newType)) return;
1498
1499     if (!oldType) {
1500         if (newType->name) {
1501             printErrorAtLine(newModule, ERR_TYPE_ADDED,
1502                              smiGetTypeLine(newType));
1503         }
1504         return;
1505     }
1506     
1507     if (!newType) {
1508         if (oldType->name) {
1509             printErrorAtLine(oldModule, ERR_TYPE_REMOVED,
1510                              smiGetTypeLine(oldType));
1511         }
1512         return;
1513     }
1514     
1515     if (oldType->basetype != newType->basetype) {
1516         if( newType->name ) {
1517             printErrorAtLine(newModule, ERR_BASETYPE_CHANGED,
1518                              smiGetTypeLine(newType), newType->name);
1519         }
1520         else {
1521             printErrorAtLine(newModule, ERR_BASETYPE_CHANGED,
1522                              smiGetTypeLine(newType), "implicit type");
1523         }
1524         if( oldType->name ) {
1525             printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
1526                              smiGetTypeLine(oldType), oldType->name);
1527         }
1528         else {
1529             printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
1530                              smiGetTypeLine(oldType), "implicit type" );
1531         }
1532     }
1533
1534     oldLine = oldNode ? smiGetNodeLine( oldNode ) : smiGetTypeLine( oldType );
1535     checkNamedNumbers(oldModule,
1536                       oldLine,
1537                       newModule,
1538                       newLine > 0 ? newLine : smiGetTypeLine( newType ),
1539                       oldType->name,
1540                       oldNode,
1541                       oldType,
1542                       newType);
1543
1544     oldName = oldNode ? oldNode->name : NULL;
1545     checkRanges(oldModule,
1546                 oldLine,
1547                 newModule,
1548                 newLine > 0 ? newLine : smiGetTypeLine( newType ),
1549                 oldName,
1550                 oldType,
1551                 newType);
1552 }
1553
1554
1555 static void
1556 checkNodeTypeCompatibility(SmiModule *oldModule, SmiNode *oldNode,
1557                            SmiModule *newModule, SmiNode *newNode)
1558 {
1559     SmiType *oldType, *newType;
1560     
1561     const int oldLine = smiGetNodeLine(oldNode);
1562     const int newLine = smiGetNodeLine(newNode);
1563
1564     oldType = smiGetNodeType(oldNode);
1565     newType = smiGetNodeType(newNode);
1566
1567     if ((!oldType) && (!newType)) return;
1568
1569     if (oldType && newType && oldType->basetype != newType->basetype) {
1570         printErrorAtLine(newModule, ERR_BASETYPE_CHANGED,
1571                          newLine, newNode->name);
1572         printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
1573                          oldLine, oldNode->name);
1574         return;
1575     }
1576
1577     checkNamedNumbers(oldModule,
1578                       oldLine,
1579                       newModule,
1580                       newLine > 0 ? newLine : smiGetTypeLine(newType),
1581                       oldType->name,
1582                       oldNode,
1583                       oldType,
1584                       newType);
1585     checkRanges(oldModule,
1586                 oldLine,
1587                 newModule,
1588                 newLine > 0 ? newLine : smiGetTypeLine(newType),
1589                 oldNode->name,
1590                 oldType,
1591                 newType);
1592 }
1593
1594
1595 static void
1596 checkTypes(SmiModule *oldModule, SmiNode *oldNode, SmiType *oldType,
1597            SmiModule *newModule, SmiNode *newNode, SmiType *newType)
1598 {
1599     int code = 0;
1600     
1601     code |= checkName(oldModule, smiGetTypeLine(oldType),
1602                       newModule, smiGetTypeLine(newType),
1603                       oldType->name, newType->name);
1604
1605     checkTypeCompatibility(oldModule, oldNode, oldType,
1606                            newModule,
1607                            newNode ? smiGetNodeLine(newNode) : smiGetTypeLine(newType),
1608                            newType);
1609     
1610     checkDefVal(oldModule, smiGetTypeLine(oldType),
1611                 newModule, smiGetTypeLine(newType),
1612                 oldType->name, 
1613                 oldType->value, newType->value);
1614
1615     code |= checkDecl(oldModule, smiGetTypeLine(oldType),
1616                       newModule, smiGetTypeLine(newType),
1617                       newType->name,
1618                       oldType->decl, newType->decl);
1619
1620     if (newType->name) {
1621         code |= checkStatus(oldModule, smiGetTypeLine(oldType),
1622                             newModule, smiGetTypeLine(newType),
1623                             newType->name, oldType->status, newType->status);
1624     }
1625
1626     code |= checkFormat(oldModule, smiGetTypeLine(oldType),
1627                         newModule, smiGetTypeLine(newType),
1628                         newType->name,
1629                         oldType->format, newType->format);
1630
1631     code |= checkUnits(oldModule, smiGetTypeLine(oldType),
1632                        newModule, smiGetTypeLine(newType),
1633                        newType->name,
1634                        oldType->units, newType->units);
1635
1636     code |= checkDescription(oldModule, smiGetTypeLine(oldType),
1637                              newModule, smiGetTypeLine(newType),
1638                              newType->name, oldType->decl,
1639                              oldType->description, newType->description);
1640
1641     code |= checkReference(oldModule, smiGetTypeLine(oldType),
1642                            newModule, smiGetTypeLine(newType),
1643                            newType->name,
1644                            oldType->reference, newType->reference);
1645
1646     if (code & CODE_SHOW_PREVIOUS) {
1647         printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
1648                          smiGetTypeLine(oldType), oldType->name);
1649     }
1650     if (code & CODE_SHOW_PREVIOUS_IMPLICIT) {
1651         printErrorAtLine(oldModule, ERR_PREVIOUS_IMPLICIT_DEFINITION,
1652                          smiGetTypeLine(oldType));
1653     }
1654 }
1655
1656
1657
1658 static void
1659 diffTypes(SmiModule *oldModule, const char *oldTag,
1660           SmiModule *newModule, const char *newTag)
1661 {
1662     SmiType *oldType, *newType;
1663
1664     /*
1665      * First check whether the old type definitions still exist and
1666      * whether the updates (if any) are consistent with the SMI rules.
1667      */
1668     
1669     smiInit(oldTag);
1670     for (oldType = smiGetFirstType(oldModule);
1671          oldType;
1672          oldType = smiGetNextType(oldType)) {
1673         
1674         smiInit(newTag);
1675         newType = smiGetType(newModule, oldType->name);
1676         if (newType) {
1677             checkTypes(oldModule, NULL, oldType,
1678                        newModule, NULL, newType);
1679         } else {
1680             printErrorAtLine(oldModule, ERR_TYPE_REMOVED,
1681                              smiGetTypeLine(oldType), oldType->name);
1682         }
1683         smiInit(oldTag);
1684     }
1685
1686     /*
1687      * Let's see if there are any new definitions.
1688      */
1689
1690     smiInit(newTag);
1691     for (newType = smiGetFirstType(newModule);
1692          newType;
1693          newType = smiGetNextType(newType)) {
1694         
1695         smiInit(oldTag);
1696         oldType = smiGetType(oldModule, newType->name);
1697         if (! oldType) {
1698             printErrorAtLine(newModule, ERR_TYPE_ADDED,
1699                              smiGetTypeLine(newType), newType->name);
1700         }
1701         smiInit(newTag);
1702     }
1703 }
1704
1705
1706
1707 static int
1708 checkNodekind(SmiModule *oldModule, SmiNode *oldNode,
1709               SmiModule *newModule, SmiNode *newNode)
1710 {
1711     int code = 0;
1712     
1713     if (oldNode->nodekind != newNode->nodekind) {
1714         printErrorAtLine(newModule, ERR_NODEKIND_CHANGED,
1715                          smiGetNodeLine(newNode), newNode->name);
1716         code |= CODE_SHOW_PREVIOUS;
1717     }
1718
1719     return code;
1720 }
1721
1722
1723
1724 static char*
1725 getStringIndexkind( SmiIndexkind indexkind )
1726 {
1727     switch( indexkind ) {
1728     case SMI_INDEX_INDEX  : return "index";
1729     case SMI_INDEX_AUGMENT: return "augment";
1730     case SMI_INDEX_REORDER: return "reorder";
1731     case SMI_INDEX_SPARSE : return "sparse";
1732     case SMI_INDEX_EXPAND : return "expand";
1733     case SMI_INDEX_UNKNOWN:
1734     default: return "unknown";
1735     }
1736 }
1737
1738 static char*
1739 getStringIndexList( SmiNode *smiNode )
1740 {
1741     SmiNode *indexNode;
1742     SmiElement *smiElement;
1743     char *strIdxLst;
1744
1745     smiElement = smiGetFirstElement( smiNode );
1746     indexNode = smiGetElementNode( smiElement );
1747     strIdxLst = (char *)malloc( strlen( indexNode->name ) + 3);
1748     if( strIdxLst ) {
1749         sprintf( strIdxLst, "`%s'", indexNode->name );
1750     }
1751     smiElement = smiGetNextElement( smiElement );
1752     while ( smiElement ) {
1753         indexNode = smiGetElementNode( smiElement );
1754         strIdxLst = (char *)realloc( strIdxLst,
1755                                      strlen( strIdxLst ) +
1756                                      strlen( indexNode->name ) + 4 );
1757         sprintf( strIdxLst, "%s, `%s'", strIdxLst, indexNode->name );
1758         smiElement = smiGetNextElement( smiElement );
1759     }
1760     return strIdxLst;
1761 }
1762
1763 static void
1764 checkIndex(SmiModule *oldModule, SmiNode *oldNode,
1765            SmiModule *newModule, SmiNode *newNode)
1766 {
1767     if (newNode->indexkind == SMI_INDEX_UNKNOWN
1768         && oldNode->indexkind == SMI_INDEX_UNKNOWN) {
1769         return;
1770     }
1771
1772     if( newNode->indexkind != oldNode->indexkind) {
1773         printf( "%s\n", newModule->name );
1774         printErrorAtLine( newModule, ERR_INDEXKIND_CHANGED, 
1775                           smiGetNodeLine( oldNode ),
1776                           getStringIndexkind( oldNode->indexkind ),
1777                           getStringIndexkind( newNode->indexkind ),
1778                           newNode->name );
1779         printErrorAtLine( oldModule, ERR_PREVIOUS_DEFINITION,
1780                           smiGetNodeLine( newNode ), oldNode->name );
1781         
1782     }
1783
1784     switch (newNode->indexkind) {
1785         SmiElement *oldElement, *newElement;
1786         SmiNode *oldRelNode, *newRelNode;
1787         int i;
1788         
1789     case SMI_INDEX_INDEX:
1790         /* compare OIDs of all index elements */
1791         oldElement = smiGetFirstElement( oldNode );
1792         newElement = smiGetFirstElement( newNode );
1793         while( oldElement && newElement ) {
1794             SmiNode *oldIndexNode, *newIndexNode;
1795             
1796             oldIndexNode = smiGetElementNode( oldElement );
1797             newIndexNode = smiGetElementNode( newElement );
1798
1799             if( oldIndexNode->oidlen != newIndexNode->oidlen ) {
1800                 char *oldIdxLst, *newIdxLst;
1801                 oldIdxLst = getStringIndexList( oldNode );
1802                 newIdxLst = getStringIndexList( newNode );
1803                 printErrorAtLine( newModule, ERR_INDEX_CHANGED,
1804                                   smiGetNodeLine( newNode ), oldNode->name,
1805                                   oldIdxLst, newIdxLst);
1806                 free( oldIdxLst );
1807                 free( newIdxLst );
1808                 printErrorAtLine( oldModule, ERR_PREVIOUS_DEFINITION,
1809                                   smiGetNodeLine( oldNode ), oldNode->name );
1810                 return;
1811             }
1812
1813             for( i = 0; i < oldIndexNode->oidlen; i++ ) {
1814                 if( oldIndexNode->oid[i] != newIndexNode->oid[i] ) {
1815                     char *oldIdxLst, *newIdxLst;
1816                     oldIdxLst = getStringIndexList( oldNode );
1817                     newIdxLst = getStringIndexList( newNode );
1818                     printErrorAtLine( newModule, ERR_INDEX_CHANGED,
1819                                       smiGetNodeLine( newNode ),
1820                                       oldNode->name,
1821                                       oldIdxLst, newIdxLst);
1822                     free( oldIdxLst );
1823                     free( newIdxLst );
1824                     printErrorAtLine( oldModule, ERR_PREVIOUS_DEFINITION,
1825                                       smiGetNodeLine( oldNode ),
1826                                       oldNode->name );
1827                     return;
1828                 }
1829             }
1830             oldElement = smiGetNextElement( oldElement );
1831             newElement = smiGetNextElement( newElement );
1832         }
1833         break;
1834         
1835     case SMI_INDEX_AUGMENT:
1836         /* compare OIDs of related nodes */
1837         oldRelNode = smiGetRelatedNode( oldNode );
1838         newRelNode = smiGetRelatedNode( newNode );
1839
1840         if( !oldRelNode || !newRelNode ) {
1841             /* should not occur */
1842             return;
1843         }
1844         if( oldRelNode->oidlen != newRelNode->oidlen ) {
1845             printErrorAtLine( newModule, ERR_INDEX_AUGMENT_CHANGED,
1846                               smiGetNodeLine( newNode ), oldNode->name,
1847                               oldRelNode->name, newRelNode->name);
1848             printErrorAtLine( oldModule, ERR_PREVIOUS_DEFINITION,
1849                               smiGetNodeLine( oldNode ), oldNode->name );
1850             return;
1851         }
1852         for( i = 0; i < oldRelNode->oidlen; i++ ) {
1853             if( oldRelNode->oid[i] != newRelNode->oid[i] ) {
1854                 printErrorAtLine( newModule, ERR_INDEX_AUGMENT_CHANGED,
1855                                   smiGetNodeLine( newNode ),
1856                                   oldNode->name,
1857                                   oldRelNode->name, newRelNode->name);
1858                 printErrorAtLine( oldModule, ERR_PREVIOUS_DEFINITION,
1859                                   smiGetNodeLine( oldNode ), oldNode->name );
1860             }
1861         }
1862         break;
1863
1864     case SMI_INDEX_UNKNOWN:
1865         return;
1866         
1867     case SMI_INDEX_REORDER:
1868     case SMI_INDEX_SPARSE:
1869     case SMI_INDEX_EXPAND:
1870         /* xxx do things for SMI-NG */
1871         break;
1872     }
1873 }
1874
1875
1876 static void
1877 checkObject(SmiModule *oldModule, SmiNode *oldNode,
1878             SmiModule *newModule, SmiNode *newNode)
1879 {
1880     int code = 0;
1881     SmiType *oldType, *newType;
1882
1883     const int oldLine = smiGetNodeLine(oldNode);
1884     const int newLine = smiGetNodeLine(newNode);
1885
1886     oldType = smiGetNodeType(oldNode);
1887     newType = smiGetNodeType(newNode);
1888     
1889     code |= checkName(oldModule, oldLine, newModule, newLine,
1890                       oldNode->name, newNode->name);
1891     
1892     if (oldType && newType) {
1893         if (oldType->name && !newType->name) {
1894             printErrorAtLine(newModule, ERR_TO_IMPLICIT,
1895                              smiGetNodeLine(newNode),
1896                              newNode->name, oldType->name);
1897             printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
1898                              smiGetNodeLine(oldNode), oldNode->name);
1899         } else if (!oldType->name && newType->name) {
1900             printErrorAtLine(newModule, ERR_FROM_IMPLICIT,
1901                              smiGetNodeLine(newNode),
1902                              newType->name, oldNode->name);
1903             printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
1904                              smiGetNodeLine(oldNode), oldNode->name);
1905         }
1906     }
1907
1908     checkNodeTypeCompatibility(oldModule, oldNode,
1909                                newModule, newNode);
1910
1911     code |= checkDecl(oldModule, oldLine, newModule, newLine,
1912                       newNode->name, oldNode->decl, newNode->decl);
1913
1914     code |= checkStatus(oldModule, oldLine, newModule, newLine,
1915                         newNode->name, oldNode->status, newNode->status);
1916
1917     code |= checkAccess(oldModule, oldLine, newModule, newLine,
1918                         newNode->name, oldNode->access, newNode->access);
1919
1920     code |= checkNodekind(oldModule, oldNode, newModule, newNode);
1921
1922     checkIndex(oldModule, oldNode, newModule, newNode);
1923
1924    
1925     checkDefVal(oldModule, oldLine, newModule, newLine,
1926                 newNode->name, oldNode->value, newNode->value);
1927
1928     code |= checkFormat(oldModule, oldLine, newModule, newLine,
1929                         newNode->name, oldNode->format, newNode->format);
1930     
1931     code |= checkUnits(oldModule, oldLine, newModule, newLine,
1932                        newNode->name, oldNode->units, newNode->units);
1933
1934     code |= checkDescription(oldModule, oldLine, newModule, newLine,
1935                              newNode->name, oldNode->decl,
1936                              oldNode->description, newNode->description);
1937
1938     code |= checkReference(oldModule, oldLine, newModule, newLine,
1939                            newNode->name,
1940                            oldNode->reference, newNode->reference);
1941
1942     if (code & CODE_SHOW_PREVIOUS) {
1943         printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
1944                          smiGetNodeLine(oldNode), oldNode->name);
1945     }
1946     if (code & CODE_SHOW_PREVIOUS_IMPLICIT) {
1947         printErrorAtLine(oldModule, ERR_PREVIOUS_IMPLICIT_DEFINITION,
1948                          smiGetNodeLine(oldNode));
1949     }
1950 }
1951
1952
1953
1954 static void
1955 diffObjects(SmiModule *oldModule, const char *oldTag,
1956             SmiModule *newModule, const char *newTag)
1957 {
1958     SmiNode *oldNode, *newNode;
1959     SmiNodekind nodekinds;
1960
1961     nodekinds =  SMI_NODEKIND_NODE | SMI_NODEKIND_TABLE |
1962         SMI_NODEKIND_ROW | SMI_NODEKIND_COLUMN | SMI_NODEKIND_SCALAR;
1963     
1964     /*
1965      * First check whether the old node definitions still exist and
1966      * whether the updates (if any) are consistent with the SMI rules.
1967      */
1968     
1969     smiInit(oldTag);
1970     for(oldNode = smiGetFirstNode(oldModule, nodekinds);
1971         oldNode;
1972         oldNode = smiGetNextNode(oldNode, nodekinds)) {
1973         
1974         smiInit(newTag);
1975         newNode = smiGetNodeByOID(oldNode->oidlen, oldNode->oid);
1976         if (newNode
1977             && newNode->oidlen == oldNode->oidlen
1978             && smiGetNodeModule(newNode) == newModule) {
1979             checkObject(oldModule, oldNode, newModule, newNode);
1980         } else {
1981             switch (oldNode->nodekind) {
1982             case SMI_NODEKIND_NODE:
1983             case SMI_NODEKIND_TABLE:
1984             case SMI_NODEKIND_ROW:
1985             case SMI_NODEKIND_COLUMN:
1986             case SMI_NODEKIND_SCALAR:
1987                 printErrorAtLine(oldModule, ERR_NODE_REMOVED,
1988                                  smiGetNodeLine(oldNode),
1989                                  getStringNodekind(oldNode->nodekind),
1990                                  oldNode->name);
1991             }
1992         }
1993         smiInit(oldTag);
1994     }
1995
1996     /*
1997      * Let's see if there are any new definitions.
1998      */
1999
2000     smiInit(newTag);
2001     for (newNode = smiGetFirstNode(newModule, nodekinds);
2002          newNode;
2003          newNode = smiGetNextNode(newNode, nodekinds)) {
2004         
2005         smiInit(oldTag);
2006         oldNode = smiGetNodeByOID(newNode->oidlen, newNode->oid);
2007         if (! oldNode
2008             || newNode->oidlen != oldNode->oidlen
2009             || smiGetNodeModule(oldNode) != oldModule) {
2010             printErrorAtLine(newModule, ERR_NODE_ADDED,
2011                              smiGetNodeLine(newNode),
2012                              getStringNodekind(newNode->nodekind),
2013                              newNode->name);
2014         }
2015         smiInit(newTag);
2016     }
2017 }
2018
2019
2020
2021 static int
2022 checkObjects(SmiModule *oldModule, const char *oldTag,
2023              SmiModule *newModule, const char *newTag,
2024              SmiNode *oldNode, SmiNode *newNode)
2025 {
2026     SmiElement *oldElem, *newElem;
2027     SmiNode *oldElemNode, *newElemNode;
2028     int code = 0;
2029
2030     smiInit(oldTag);
2031     for (oldElem = smiGetFirstElement(oldNode);
2032          oldElem; oldElem = smiGetNextElement(oldElem)) {
2033         oldElemNode = smiGetElementNode(oldElem);
2034         smiInit(newTag);
2035         for (newElem = smiGetFirstElement(newNode);
2036              newElem; newElem = smiGetNextElement(newElem)) {
2037             newElemNode = smiGetElementNode(newElem);
2038             if (strcmp(oldElemNode->name, newElemNode->name) == 0) {
2039                 break;
2040             }
2041         }
2042         if (! newElem) {
2043             printErrorAtLine(oldModule, ERR_OBJECT_REMOVED,
2044                              smiGetNodeLine(oldNode), oldNode->name);
2045             code |= CODE_SHOW_PREVIOUS;
2046         }
2047         smiInit(oldTag);
2048     }
2049
2050     smiInit(newTag);
2051     for (newElem = smiGetFirstElement(newNode);
2052          newElem; newElem = smiGetNextElement(newElem)) {
2053         newElemNode = smiGetElementNode(newElem);
2054         smiInit(oldTag);
2055         for (oldElem = smiGetFirstElement(oldNode);
2056              oldElem; oldElem = smiGetNextElement(oldElem)) {
2057             oldElemNode = smiGetElementNode(oldElem);
2058             if (strcmp(oldElemNode->name, newElemNode->name) == 0) {
2059                 break;
2060             }
2061         }
2062         if (! oldElem) {
2063             printErrorAtLine(newModule, ERR_OBJECT_ADDED,
2064                              smiGetNodeLine(newNode), newNode->name);
2065         }
2066         smiInit(newTag);
2067     }
2068
2069     return code;
2070 }
2071
2072
2073
2074 static void
2075 checkNotification(SmiModule *oldModule, const char *oldTag,
2076                   SmiModule *newModule, const char *newTag,
2077                   SmiNode *oldNode, SmiNode *newNode)
2078 {
2079     int code = 0;
2080     
2081     code |= checkDecl(oldModule, smiGetNodeLine(oldNode),
2082                       newModule, smiGetNodeLine(newNode),
2083                       newNode->name, oldNode->decl, newNode->decl);
2084
2085     code |= checkStatus(oldModule, smiGetNodeLine(oldNode),
2086                         newModule, smiGetNodeLine(newNode),
2087                         newNode->name, oldNode->status, newNode->status);
2088
2089     code |= checkObjects(oldModule, oldTag, newModule, newTag,
2090                          oldNode, newNode);
2091
2092     code |= checkDescription(oldModule, smiGetNodeLine(oldNode),
2093                              newModule, smiGetNodeLine(newNode),
2094                              newNode->name, oldNode->decl,
2095                              oldNode->description, newNode->description);
2096
2097     code |= checkReference(oldModule, smiGetNodeLine(oldNode),
2098                            newModule, smiGetNodeLine(newNode),
2099                            newNode->name,
2100                            oldNode->reference, newNode->reference);
2101
2102     if (code & CODE_SHOW_PREVIOUS) {
2103         printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
2104                          smiGetNodeLine(oldNode), oldNode->name);
2105     }
2106     if (code & CODE_SHOW_PREVIOUS_IMPLICIT) {
2107         printErrorAtLine(oldModule, ERR_PREVIOUS_IMPLICIT_DEFINITION,
2108                          smiGetNodeLine(oldNode));
2109     }
2110 }
2111
2112
2113
2114 static void
2115 diffNotifications(SmiModule *oldModule, const char *oldTag,
2116                   SmiModule *newModule, const char *newTag)
2117 {
2118     SmiNode *oldNode, *newNode;
2119
2120     /*
2121      * First check whether the old node definitions still exist and
2122      * whether the updates (if any) are consistent with the SMI rules.
2123      */
2124     
2125     smiInit(oldTag);
2126     for(oldNode = smiGetFirstNode(oldModule, SMI_NODEKIND_NOTIFICATION);
2127         oldNode;
2128         oldNode = smiGetNextNode(oldNode, SMI_NODEKIND_NOTIFICATION)) {
2129         
2130         smiInit(newTag);
2131         newNode = smiGetNodeByOID(oldNode->oidlen, oldNode->oid);
2132         if (newNode
2133             && newNode->oidlen == oldNode->oidlen
2134             && smiGetNodeModule(newNode) == newModule) {
2135             checkNotification(oldModule, oldTag, newModule, newTag,
2136                               oldNode, newNode);
2137         } else {
2138             printErrorAtLine(oldModule, ERR_NODE_REMOVED,
2139                              smiGetNodeLine(oldNode),
2140                              getStringNodekind(oldNode->nodekind),
2141                              oldNode->name);
2142         }
2143         smiInit(oldTag);
2144     }
2145
2146     /*
2147      * Let's see if there are any new definitions.
2148      */
2149
2150     smiInit(newTag);
2151     for (newNode = smiGetFirstNode(newModule, SMI_NODEKIND_NOTIFICATION);
2152          newNode;
2153          newNode = smiGetNextNode(newNode, SMI_NODEKIND_NOTIFICATION)) {
2154         
2155         smiInit(oldTag);
2156         oldNode = smiGetNodeByOID(newNode->oidlen, newNode->oid);
2157         if (! oldNode
2158             || newNode->oidlen != oldNode->oidlen
2159             || smiGetNodeModule(oldNode) != oldModule) {
2160             printErrorAtLine(newModule, ERR_NODE_ADDED,
2161                              smiGetNodeLine(newNode),
2162                              getStringNodekind(newNode->nodekind),
2163                              newNode->name);
2164         }
2165         smiInit(newTag);
2166     }
2167 }
2168
2169
2170
2171 static int
2172 checkOrganization(SmiModule *oldModule, int oldLine,
2173                   SmiModule *newModule, int newLine,
2174                   char *name, char *oldOrga, char *newOrga)
2175 {
2176     int code = 0;
2177     
2178     if (! oldOrga && newOrga) {
2179         printErrorAtLine(newModule, ERR_ORGA_ADDED,
2180                          newLine, name);
2181     }
2182
2183     if (oldOrga && !newOrga) {
2184         printErrorAtLine(oldModule, ERR_ORGA_REMOVED,
2185                          oldLine, name);
2186         code |= CODE_SHOW_PREVIOUS;
2187     }
2188
2189     if (oldOrga && newOrga && diffStrings(oldOrga, newOrga)) {
2190         printErrorAtLine(newModule, ERR_ORGA_CHANGED,
2191                          newLine, name);
2192         code |= CODE_SHOW_PREVIOUS;
2193     }
2194
2195     return code;
2196 }
2197
2198
2199
2200 static int
2201 checkContact(SmiModule *oldModule, int oldLine,
2202              SmiModule *newModule, int newLine,
2203              char *name, char *oldContact, char *newContact)
2204 {
2205     int code = 0;
2206     
2207     if (! oldContact && newContact) {
2208         printErrorAtLine(newModule, ERR_CONTACT_ADDED,
2209                          newLine, name);
2210     }
2211
2212     if (oldContact && !newContact) {
2213         printErrorAtLine(oldModule, ERR_CONTACT_REMOVED,
2214                          oldLine, name);
2215         code |= CODE_SHOW_PREVIOUS;
2216     }
2217
2218     if (oldContact && newContact && diffStrings(oldContact, newContact)) {
2219         printErrorAtLine(newModule, ERR_CONTACT_CHANGED,
2220                          newLine, name);
2221         code |= CODE_SHOW_PREVIOUS;
2222     }
2223
2224     return code;
2225 }
2226
2227
2228
2229 static void
2230 diffModules(SmiModule *oldModule, const char *oldTag,
2231             SmiModule *newModule, const char *newTag)
2232 {
2233     SmiNode *oldIdentityNode, *newIdentityNode;
2234     SmiRevision *oldRev, *newRev;
2235     int oldLine = -1, newLine = -1;
2236     int code = 0;
2237     
2238     if (oldModule->language != newModule->language) {
2239         printErrorAtLine(newModule, ERR_SMIVERSION_CHANGED, -1);
2240     }
2241
2242     oldIdentityNode = smiGetModuleIdentityNode(oldModule);
2243     if (oldIdentityNode) {
2244         oldLine = smiGetNodeLine(oldIdentityNode);
2245     }
2246     newIdentityNode = smiGetModuleIdentityNode(newModule);
2247     if (newIdentityNode) {
2248         newLine = smiGetNodeLine(newIdentityNode);
2249     }
2250
2251     code |= checkOrganization(oldModule, oldLine,
2252                               newModule, newLine,
2253                               newModule->name,
2254                               oldModule->organization, newModule->organization);
2255
2256     code |= checkContact(oldModule, oldLine, newModule, newLine,
2257                          newModule->name,
2258                          oldModule->contactinfo, newModule->contactinfo);
2259
2260     code |= checkDescription(oldModule, oldLine,
2261                              newModule, newLine,
2262                              newModule->name, SMI_DECL_MODULEIDENTITY,
2263                              oldModule->description, newModule->description);
2264
2265     code |= checkReference(oldModule, oldLine, newModule, newLine, newModule->name,
2266                            oldModule->reference, newModule->reference);
2267
2268     /*
2269      * First check whether the old revisions still exist and
2270      * whether there are any updates.
2271      */
2272
2273     smiInit(oldTag);
2274     for (oldRev = smiGetFirstRevision(oldModule);
2275          oldRev; oldRev = smiGetNextRevision(oldRev)) {
2276         smiInit(newTag);
2277         for (newRev = smiGetFirstRevision(newModule);
2278              newRev; newRev = smiGetNextRevision(newRev)) {
2279             if (oldRev->date == newRev->date) {
2280                 break;
2281             }
2282         }
2283         if (newRev) {
2284             if ((diffStrings(oldRev->description, newRev->description)) &&
2285                 diffStrings(
2286                     "[Revision added by libsmi due to a LAST-UPDATED clause.]",
2287                     oldRev->description)) {
2288                 printErrorAtLine(newModule, ERR_REVISION_CHANGED,
2289                                  smiGetRevisionLine(newRev),
2290                                  getStringTime(newRev->date));
2291                 printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
2292                                  smiGetRevisionLine(oldRev),
2293                                  getStringTime(oldRev->date));
2294             }
2295         } else {
2296             printErrorAtLine(oldModule, ERR_REVISION_REMOVED,
2297                              smiGetRevisionLine(oldRev),
2298                              getStringTime(oldRev->date));
2299         }
2300         smiInit(oldTag);
2301     }
2302
2303     /*
2304      * Let's see if there are any new revisions.
2305      */
2306
2307     smiInit(newTag);
2308     for (newRev = smiGetFirstRevision(newModule);
2309          newRev; newRev = smiGetNextRevision(newRev)) {
2310         smiInit(oldTag);
2311         for (oldRev = smiGetFirstRevision(oldModule);
2312              oldRev; oldRev = smiGetNextRevision(oldRev)) {
2313             if (oldRev->date == newRev->date) {
2314                 break;
2315             }
2316         }
2317         if (!oldRev) {
2318             printErrorAtLine(newModule, ERR_REVISION_ADDED,
2319                              smiGetRevisionLine(newRev),
2320                              getStringTime(newRev->date));
2321         }
2322         smiInit(newTag);
2323     }
2324
2325     if (code & CODE_SHOW_PREVIOUS && oldLine >= 0) {
2326         printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
2327                          oldLine, oldModule->name);
2328     }
2329     if (code & CODE_SHOW_PREVIOUS_IMPLICIT) {
2330         printErrorAtLine(oldModule, ERR_PREVIOUS_IMPLICIT_DEFINITION,
2331                          oldLine);
2332     }
2333 }
2334
2335
2336
2337 static void
2338 checkMember(SmiModule *oldModule, const char *oldTag,
2339             SmiModule *newModule, const char *newTag,
2340             SmiNode *oldNode, SmiNode *newNode)
2341 {
2342     SmiElement *oldElem, *newElem;
2343     SmiNode *oldElemNode, *newElemNode;
2344
2345     smiInit(oldTag);
2346     for (oldElem = smiGetFirstElement(oldNode);
2347          oldElem; oldElem = smiGetNextElement(oldElem)) {
2348         oldElemNode = smiGetElementNode(oldElem);
2349         smiInit(newTag);
2350         for (newElem = smiGetFirstElement(newNode);
2351              newElem; newElem = smiGetNextElement(newElem)) {
2352             newElemNode = smiGetElementNode(newElem);
2353             if (strcmp(oldElemNode->name, newElemNode->name) == 0) {
2354                 break;
2355             }
2356         }
2357         if (! newElem) {
2358             printErrorAtLine(oldModule, ERR_MEMBER_REMOVED,
2359                              smiGetNodeLine(oldNode),
2360                              oldElemNode->name, oldNode->name);
2361         }
2362         smiInit(oldTag);
2363     }
2364
2365     smiInit(newTag);
2366     for (newElem = smiGetFirstElement(newNode);
2367          newElem; newElem = smiGetNextElement(newElem)) {
2368         newElemNode = smiGetElementNode(newElem);
2369         smiInit(oldTag);
2370         for (oldElem = smiGetFirstElement(oldNode);
2371              oldElem; oldElem = smiGetNextElement(oldElem)) {
2372             oldElemNode = smiGetElementNode(oldElem);
2373             if (strcmp(oldElemNode->name, newElemNode->name) == 0) {
2374                 break;
2375             }
2376         }
2377         if (! oldElem) {
2378             printErrorAtLine(newModule, ERR_MEMBER_ADDED,
2379                              smiGetNodeLine(newNode),
2380                              newElemNode->name, newNode->name);
2381         }
2382         smiInit(newTag);
2383     }
2384 }
2385
2386
2387
2388 static void
2389 checkGroup(SmiModule *oldModule, const char *oldTag,
2390            SmiModule *newModule, const char *newTag,
2391            SmiNode *oldNode, SmiNode *newNode)
2392 {
2393     int code = 0;
2394     
2395     code = checkName(oldModule, smiGetNodeLine(oldNode),
2396                      newModule, smiGetNodeLine(newNode),
2397                      oldNode->name, newNode->name);
2398     
2399     code |= checkDecl(oldModule, smiGetNodeLine(oldNode),
2400                       newModule, smiGetNodeLine(newNode),
2401                       newNode->name, oldNode->decl, newNode->decl);
2402     
2403     code |= checkStatus(oldModule, smiGetNodeLine(oldNode),
2404                         newModule, smiGetNodeLine(newNode),
2405                         newNode->name, oldNode->status, newNode->status);
2406
2407     code |= checkDescription(oldModule, smiGetNodeLine(oldNode),
2408                              newModule, smiGetNodeLine(newNode),
2409                              newNode->name, oldNode->decl,
2410                              oldNode->description, newNode->description);
2411
2412     code |= checkReference(oldModule, smiGetNodeLine(oldNode),
2413                            newModule, smiGetNodeLine(newNode),
2414                            newNode->name,
2415                            oldNode->reference, newNode->reference);
2416
2417     checkMember(oldModule, oldTag, newModule, newTag, oldNode, newNode);
2418
2419     if (code & CODE_SHOW_PREVIOUS) {
2420         printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
2421                          smiGetNodeLine(oldNode), oldNode->name);
2422     }
2423     if (code & CODE_SHOW_PREVIOUS_IMPLICIT) {
2424         printErrorAtLine(oldModule, ERR_PREVIOUS_IMPLICIT_DEFINITION,
2425                          smiGetNodeLine(oldNode));
2426     }
2427 }
2428
2429
2430
2431 static void
2432 diffGroups(SmiModule *oldModule, const char *oldTag,
2433            SmiModule *newModule, const char *newTag)
2434 {
2435     SmiNode *oldNode, *newNode;
2436     
2437     /*
2438      * First check whether the old node definitions still exist and
2439      * whether the updates (if any) are consistent with the SMI rules.
2440      */
2441     
2442     smiInit(oldTag);
2443     for(oldNode = smiGetFirstNode(oldModule, SMI_NODEKIND_GROUP);
2444         oldNode;
2445         oldNode = smiGetNextNode(oldNode, SMI_NODEKIND_GROUP)) {
2446         smiInit(newTag);
2447         newNode = smiGetNodeByOID(oldNode->oidlen, oldNode->oid);
2448         if (newNode
2449             && newNode->oidlen == oldNode->oidlen
2450             && smiGetNodeModule(newNode) == newModule) {
2451             checkGroup(oldModule, oldTag, newModule, newTag, oldNode, newNode);
2452         } else {
2453             printErrorAtLine(oldModule, ERR_NODE_REMOVED,
2454                              smiGetNodeLine(oldNode),
2455                              getStringNodekind(oldNode->nodekind),
2456                              oldNode->name);
2457         }
2458         smiInit(oldTag);
2459     }
2460
2461     /*
2462      * Let's see if there are any new definitions.
2463      */
2464
2465     smiInit(newTag);
2466     for (newNode = smiGetFirstNode(newModule, SMI_NODEKIND_GROUP);
2467          newNode;
2468          newNode = smiGetNextNode(newNode, SMI_NODEKIND_GROUP)) {
2469         
2470         smiInit(oldTag);
2471         oldNode = smiGetNodeByOID(newNode->oidlen, newNode->oid);
2472         if (! oldNode
2473             || newNode->oidlen != oldNode->oidlen
2474             || smiGetNodeModule(oldNode) != oldModule) {
2475             printErrorAtLine(newModule, ERR_NODE_ADDED,
2476                              smiGetNodeLine(newNode),
2477                              getStringNodekind(newNode->nodekind),
2478                              newNode->name);
2479         }
2480         smiInit(newTag);
2481     }
2482 }
2483
2484
2485
2486 static void
2487 checkComplMandatory(SmiModule *oldModule, const char *oldTag,
2488                     SmiModule *newModule, const char *newTag,
2489                     SmiNode *oldNode, SmiNode *newNode)
2490 {
2491     SmiElement *oldElem, *newElem;
2492     SmiNode *oldElemNode, *newElemNode;
2493
2494     smiInit(oldTag);
2495     for (oldElem = smiGetFirstElement(oldNode);
2496          oldElem; oldElem = smiGetNextElement(oldElem)) {
2497         oldElemNode = smiGetElementNode(oldElem);
2498         smiInit(newTag);
2499         for (newElem = smiGetFirstElement(newNode);
2500              newElem; newElem = smiGetNextElement(newElem)) {
2501             newElemNode = smiGetElementNode(newElem);
2502             if (strcmp(oldElemNode->name, newElemNode->name) == 0) {
2503                 break;
2504             }
2505         }
2506         if (! newElem) {
2507             if (strcmp(smiGetNodeModule(oldElemNode)->name, oldModule->name)) {
2508                 printErrorAtLine(oldModule, ERR_MANDATORY_EXT_GROUP_REMOVED,
2509                                  smiGetNodeLine(oldNode),
2510                                  oldModule->name, oldElemNode->name,
2511                                  oldNode->name);
2512             } else {
2513                 printErrorAtLine(oldModule, ERR_MANDATORY_GROUP_REMOVED,
2514                                  smiGetNodeLine(oldNode),
2515                                  oldElemNode->name,
2516                                  oldNode->name);
2517             }
2518         }
2519         smiInit(oldTag);
2520     }
2521
2522     smiInit(newTag);
2523     for (newElem = smiGetFirstElement(newNode);
2524          newElem; newElem = smiGetNextElement(newElem)) {
2525         newElemNode = smiGetElementNode(newElem);
2526         smiInit(oldTag);
2527         for (oldElem = smiGetFirstElement(oldNode);
2528              oldElem; oldElem = smiGetNextElement(oldElem)) {
2529             oldElemNode = smiGetElementNode(oldElem);
2530             if (strcmp(oldElemNode->name, newElemNode->name) == 0) {
2531                 break;
2532             }
2533         }
2534         if (! oldElem) {
2535             if (strcmp(smiGetNodeModule(newElemNode)->name, newModule->name)) {
2536                 printErrorAtLine(newModule, ERR_MANDATORY_EXT_GROUP_ADDED,
2537                                  smiGetNodeLine(newNode),
2538                                  newModule->name, newElemNode->name,
2539                                  newNode->name);
2540             } else {
2541                 printErrorAtLine(newModule, ERR_MANDATORY_GROUP_ADDED,
2542                                  smiGetNodeLine(newNode),
2543                                  newElemNode->name, newNode->name);
2544             }
2545         }
2546         smiInit(newTag);
2547     }
2548 }
2549
2550
2551
2552 static void
2553 checkComplOptions(SmiModule *oldModule, const char *oldTag,
2554                   SmiModule *newModule, const char *newTag,
2555                   SmiNode *oldNode, SmiNode *newNode)
2556 {
2557     int code;
2558     SmiOption *oldOption, *newOption;
2559     SmiNode *oldOptionNode, *newOptionNode;
2560
2561     smiInit(oldTag);
2562     for (oldOption = smiGetFirstOption(oldNode);
2563          oldOption; oldOption = smiGetNextOption(oldOption)) {
2564         oldOptionNode = smiGetOptionNode(oldOption);
2565         smiInit(newTag);
2566         for (newOption = smiGetFirstOption(newNode);
2567              newOption; newOption = smiGetNextOption(newOption)) {
2568             newOptionNode = smiGetOptionNode(newOption);
2569             if (strcmp(oldOptionNode->name, newOptionNode->name) == 0) {
2570                 break;
2571             }
2572         }
2573         if (! newOption) {
2574             if (strcmp(smiGetNodeModule(oldOptionNode)->name,
2575                        oldModule->name)) {
2576                 printErrorAtLine(oldModule, ERR_EXT_OPTION_REMOVED,
2577                                  smiGetOptionLine(oldOption),
2578                                  oldModule->name, oldOptionNode->name,
2579                                  oldNode->name);
2580             } else {
2581                 printErrorAtLine(oldModule, ERR_OPTION_REMOVED,
2582                                  smiGetOptionLine(oldOption),
2583                                  oldOptionNode->name,
2584                                  oldNode->name);
2585             }
2586         } else {
2587             code = 0;
2588             code |= checkDescription(oldModule, smiGetOptionLine(oldOption),
2589                                      newModule, smiGetOptionLine(newOption),
2590                                      newOptionNode->name, SMI_DECL_COMPL_GROUP,
2591                                      oldOption->description,
2592                                      newOption->description);
2593             if (code & CODE_SHOW_PREVIOUS) {
2594                 printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
2595                                  smiGetOptionLine(oldOption),
2596                                  oldOptionNode->name);
2597             }
2598         }
2599         smiInit(oldTag);
2600     }
2601
2602     smiInit(newTag);
2603     for (newOption = smiGetFirstOption(newNode);
2604          newOption; newOption = smiGetNextOption(newOption)) {
2605         newOptionNode = smiGetOptionNode(newOption);
2606         smiInit(oldTag);
2607         for (oldOption = smiGetFirstOption(oldNode);
2608              oldOption; oldOption = smiGetNextOption(oldOption)) {
2609             oldOptionNode = smiGetOptionNode(oldOption);
2610             if (strcmp(oldOptionNode->name, newOptionNode->name) == 0) {
2611                 break;
2612             }
2613         }
2614         if (! oldOption) {
2615             if (strcmp(smiGetNodeModule(newOptionNode)->name,
2616                        newModule->name)) {
2617                 printErrorAtLine(newModule, ERR_EXT_OPTION_ADDED,
2618                                  smiGetOptionLine(newOption),
2619                                  newModule->name, newOptionNode->name,
2620                                  newNode->name);
2621             } else {
2622                 printErrorAtLine(newModule, ERR_OPTION_ADDED,
2623                                  smiGetOptionLine(newOption),
2624                                  newOptionNode->name,
2625                                  newNode->name);
2626             }
2627         }
2628         smiInit(newTag);
2629     }
2630 }
2631
2632
2633
2634 static void
2635 checkComplRefinements(SmiModule *oldModule, const char *oldTag,
2636                   SmiModule *newModule, const char *newTag,
2637                   SmiNode *oldNode, SmiNode *newNode)
2638 {
2639     int code;
2640     SmiRefinement *oldRefinement, *newRefinement;
2641     SmiNode *oldRefinementNode, *newRefinementNode;
2642
2643     smiInit(oldTag);
2644     for (oldRefinement = smiGetFirstRefinement(oldNode);
2645          oldRefinement; oldRefinement = smiGetNextRefinement(oldRefinement)) {
2646         oldRefinementNode = smiGetRefinementNode(oldRefinement);
2647         smiInit(newTag);
2648         for (newRefinement = smiGetFirstRefinement(newNode);
2649              newRefinement; newRefinement = smiGetNextRefinement(newRefinement)) {
2650             newRefinementNode = smiGetRefinementNode(newRefinement);
2651             if (strcmp(oldRefinementNode->name, newRefinementNode->name) == 0) {
2652                 break;
2653             }
2654         }
2655         if (! newRefinement) {
2656             if (strcmp(smiGetNodeModule(oldRefinementNode)->name,
2657                        oldModule->name)) {
2658                 printErrorAtLine(oldModule, ERR_EXT_REFINEMENT_REMOVED,
2659                                  smiGetRefinementLine(oldRefinement),
2660                                  oldModule->name, oldRefinementNode->name,
2661                                  oldNode->name);
2662             } else {
2663                 printErrorAtLine(oldModule, ERR_REFINEMENT_REMOVED,
2664                                  smiGetRefinementLine(oldRefinement),
2665                                  oldRefinementNode->name,
2666                                  oldNode->name);
2667             }
2668         } else {
2669             code = 0;
2670             code |= checkDescription(oldModule, smiGetRefinementLine(oldRefinement),
2671                                      newModule, smiGetRefinementLine(newRefinement),
2672                                      newRefinementNode->name,
2673                                      SMI_DECL_COMPL_OBJECT,
2674                                      oldRefinement->description,
2675                                      newRefinement->description);
2676
2677             code |= checkAccess(oldModule,
2678                                 smiGetRefinementLine(oldRefinement),
2679                                 newModule,
2680                                 smiGetRefinementLine(newRefinement),
2681                                 newRefinementNode->name,
2682                                 oldRefinement->access, newRefinement->access);
2683
2684             checkTypeCompatibility(oldModule, oldRefinementNode,
2685                                    smiGetRefinementType(oldRefinement),
2686                                    newModule, smiGetRefinementLine(newRefinement),
2687                                    smiGetRefinementType(newRefinement));
2688             
2689             checkTypeCompatibility(oldModule, oldRefinementNode,
2690                                    smiGetRefinementWriteType(oldRefinement),
2691                                    newModule, smiGetRefinementLine(newRefinement),
2692                                    smiGetRefinementWriteType(newRefinement));
2693             
2694             if (code & CODE_SHOW_PREVIOUS) {
2695                 printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
2696                                  smiGetRefinementLine(oldRefinement),
2697                                  oldRefinementNode->name);
2698             }
2699         }
2700         smiInit(oldTag);
2701     }
2702
2703     smiInit(newTag);
2704     for (newRefinement = smiGetFirstRefinement(newNode);
2705          newRefinement; newRefinement = smiGetNextRefinement(newRefinement)) {
2706         newRefinementNode = smiGetRefinementNode(newRefinement);
2707         smiInit(oldTag);
2708         for (oldRefinement = smiGetFirstRefinement(oldNode);
2709              oldRefinement; oldRefinement = smiGetNextRefinement(oldRefinement)) {
2710             oldRefinementNode = smiGetRefinementNode(oldRefinement);
2711             if (strcmp(oldRefinementNode->name, newRefinementNode->name) == 0) {
2712                 break;
2713             }
2714         }
2715         if (! oldRefinement) {
2716             if (strcmp(smiGetNodeModule(newRefinementNode)->name,
2717                        newModule->name)) {
2718                 printErrorAtLine(newModule, ERR_EXT_REFINEMENT_ADDED,
2719                                  smiGetRefinementLine(newRefinement),
2720                                  newModule->name, newRefinementNode->name,
2721                                  newNode->name);
2722             } else {
2723                 printErrorAtLine(newModule, ERR_REFINEMENT_ADDED,
2724                                  smiGetRefinementLine(newRefinement),
2725                                  newRefinementNode->name,
2726                                  newNode->name);
2727             }
2728         }
2729         smiInit(newTag);
2730     }
2731 }
2732
2733
2734
2735 static void
2736 checkCompliance(SmiModule *oldModule, const char *oldTag,
2737                 SmiModule *newModule, const char *newTag,
2738                 SmiNode *oldNode, SmiNode *newNode)
2739 {
2740     int code = 0;
2741     
2742     code = checkName(oldModule, smiGetNodeLine(oldNode),
2743                      newModule, smiGetNodeLine(newNode),
2744                      oldNode->name, newNode->name);
2745     
2746     code |= checkDecl(oldModule, smiGetNodeLine(oldNode),
2747                       newModule, smiGetNodeLine(newNode),
2748                       newNode->name, oldNode->decl, newNode->decl);
2749     
2750     code |= checkStatus(oldModule, smiGetNodeLine(oldNode),
2751                         newModule, smiGetNodeLine(newNode),
2752                         newNode->name, oldNode->status, newNode->status);
2753
2754     code |= checkDescription(oldModule, smiGetNodeLine(oldNode),
2755                              newModule, smiGetNodeLine(newNode),
2756                              newNode->name, oldNode->decl,
2757                              oldNode->description, newNode->description);
2758
2759     code |= checkReference(oldModule, smiGetNodeLine(oldNode),
2760                            newModule, smiGetNodeLine(newNode),
2761                            newNode->name,
2762                            oldNode->reference, newNode->reference);
2763
2764     if (code & CODE_SHOW_PREVIOUS) {
2765         printErrorAtLine(oldModule, ERR_PREVIOUS_DEFINITION,
2766                          smiGetNodeLine(oldNode), oldNode->name);
2767     }
2768     if (code & CODE_SHOW_PREVIOUS_IMPLICIT) {
2769         printErrorAtLine(oldModule, ERR_PREVIOUS_IMPLICIT_DEFINITION,
2770                          smiGetNodeLine(oldNode));
2771     }
2772
2773     checkComplMandatory(oldModule, oldTag, newModule, newTag,
2774                         oldNode, newNode);
2775
2776     checkComplOptions(oldModule, oldTag, newModule, newTag,
2777                       oldNode, newNode);
2778
2779     checkComplRefinements(oldModule, oldTag, newModule, newTag,
2780                           oldNode, newNode);
2781 }
2782
2783
2784
2785 static void
2786 diffCompliances(SmiModule *oldModule, const char *oldTag,
2787                 SmiModule *newModule, const char *newTag)
2788 {
2789     SmiNode *oldNode, *newNode;
2790     
2791     /*
2792      * First check whether the old node definitions still exist and
2793      * whether the updates (if any) are consistent with the SMI rules.
2794      */
2795     
2796     smiInit(oldTag);
2797     for(oldNode = smiGetFirstNode(oldModule, SMI_NODEKIND_COMPLIANCE);
2798         oldNode;
2799         oldNode = smiGetNextNode(oldNode, SMI_NODEKIND_COMPLIANCE)) {
2800         smiInit(newTag);
2801         newNode = smiGetNodeByOID(oldNode->oidlen, oldNode->oid);
2802         if (newNode
2803             && newNode->oidlen == oldNode->oidlen
2804             && smiGetNodeModule(newNode) == newModule) {
2805             checkCompliance(oldModule, oldTag, newModule, newTag,
2806                             oldNode, newNode);
2807         } else {
2808             printErrorAtLine(oldModule, ERR_NODE_REMOVED,
2809                              smiGetNodeLine(oldNode),
2810                              getStringNodekind(oldNode->nodekind),
2811                              oldNode->name);
2812         }
2813         smiInit(oldTag);
2814     }
2815
2816     /*
2817      * Let's see if there are any new definitions.
2818      */
2819
2820     smiInit(newTag);
2821     for (newNode = smiGetFirstNode(newModule, SMI_NODEKIND_COMPLIANCE);
2822          newNode;
2823          newNode = smiGetNextNode(newNode, SMI_NODEKIND_COMPLIANCE)) {
2824         
2825         smiInit(oldTag);
2826         oldNode = smiGetNodeByOID(newNode->oidlen, newNode->oid);
2827         if (! oldNode
2828             || newNode->oidlen != oldNode->oidlen
2829             || smiGetNodeModule(oldNode) != oldModule) {
2830             printErrorAtLine(newModule, ERR_NODE_ADDED,
2831                              smiGetNodeLine(newNode),
2832                              getStringNodekind(newNode->nodekind),
2833                              newNode->name);
2834         }
2835         smiInit(newTag);
2836     }
2837 }
2838
2839
2840
2841 static SmiNode*
2842 findGroupElement(SmiNode *groupNode, const char *name)
2843 {
2844     SmiElement *smiElement = NULL;
2845     SmiNode *smiNode = NULL;
2846     
2847     for (smiElement = smiGetFirstElement(groupNode);
2848          smiElement;
2849          smiElement = smiGetNextElement(smiElement)) {
2850         smiNode = smiGetElementNode(smiElement);
2851         if (strcmp(smiNode->name, name) == 0) {
2852             return smiNode;
2853         }
2854     }
2855     return NULL;
2856 }
2857
2858
2859 static SmiNode*
2860 findGroupsElement(SmiNode *groupNode, const char *name)
2861 {
2862     SmiElement *smiElement = NULL;
2863     SmiNode *smiNode = NULL, *foundNode;
2864     
2865     for (smiElement = smiGetFirstElement(groupNode);
2866          smiElement;
2867          smiElement = smiGetNextElement(smiElement)) {
2868         smiNode = smiGetElementNode(smiElement);
2869         foundNode = findGroupElement(smiNode, name);
2870         if (foundNode) {
2871             return foundNode;
2872         }
2873     }
2874     return NULL;
2875 }
2876
2877
2878
2879 static void
2880 diffOldNewComplianceMandatory(SmiModule *oldModule, const char *oldTag,
2881                               SmiModule *newModule, const char *newTag,
2882                               SmiNode *oldComplNode, SmiNode *newComplNode)
2883 {
2884     SmiElement *oldGroupElement, *newGroupElement, *oldElement, *newElement;
2885     SmiNode *oldGroupNode, *newGroupNode, *oldNode, *newNode;
2886
2887     smiInit(oldTag);
2888     for (oldGroupElement = smiGetFirstElement(oldComplNode);
2889          oldGroupElement;
2890          oldGroupElement = smiGetNextElement(oldGroupElement)) {
2891         oldGroupNode = smiGetElementNode(oldGroupElement);
2892         for (oldElement = smiGetFirstElement(oldGroupNode);
2893              oldElement;
2894              oldElement = smiGetNextElement(oldElement)) {
2895             oldNode = smiGetElementNode(oldElement);
2896             smiInit(newTag);
2897             newNode = findGroupsElement(newComplNode, oldNode->name);
2898             if (! newNode) {
2899                 if (strcmp(smiGetNodeModule(oldNode)->name, oldModule->name)) {
2900                     printErrorAtLine(oldModule, ERR_MANDATORY_EXT_REMOVED,
2901                                      smiGetNodeLine(oldNode),
2902                                      getStringNodekind(oldNode->nodekind),
2903                                      oldModule->name, oldNode->name,
2904                                      oldComplNode->name,
2905                                      newComplNode->name);
2906                 } else {
2907                     printErrorAtLine(oldModule, ERR_MANDATORY_REMOVED,
2908                                      smiGetNodeLine(oldNode),
2909                                      getStringNodekind(oldNode->nodekind),
2910                                      oldNode->name,
2911                                      oldComplNode->name,
2912                                      newComplNode->name);
2913                 }
2914             }
2915             smiInit(oldTag);
2916         }
2917     }
2918
2919     smiInit(newTag);
2920     for (newGroupElement = smiGetFirstElement(newComplNode);
2921          newGroupElement;
2922          newGroupElement = smiGetNextElement(newGroupElement)) {
2923         newGroupNode = smiGetElementNode(newGroupElement);
2924         for (newElement = smiGetFirstElement(newGroupNode);
2925              newElement;
2926              newElement = smiGetNextElement(newElement)) {
2927             newNode = smiGetElementNode(newElement);
2928             smiInit(oldTag);
2929             oldNode = findGroupsElement(oldComplNode, newNode->name);
2930             if (! oldNode) {
2931                 if (strcmp(smiGetNodeModule(newNode)->name, newModule->name)) {
2932                     printErrorAtLine(newModule, ERR_MANDATORY_EXT_ADDED,
2933                                      smiGetNodeLine(newNode),
2934                                      getStringNodekind(newNode->nodekind),
2935                                      newModule->name, newNode->name,
2936                                      oldComplNode->name,
2937                                      newComplNode->name);
2938                 } else {
2939                     printErrorAtLine(newModule, ERR_MANDATORY_ADDED,
2940                                      smiGetNodeLine(newNode),
2941                                      getStringNodekind(newNode->nodekind),
2942                                      newNode->name,
2943                                      oldComplNode->name,
2944                                      newComplNode->name);
2945                 }
2946             }
2947             smiInit(newTag);
2948         }
2949     }
2950 }
2951
2952
2953
2954 static void
2955 diffOldNewComplianceOptional(SmiModule *oldModule, const char *oldTag,
2956                              SmiModule *newModule, const char *newTag,
2957                              SmiNode *oldComplNode, SmiNode *newComplNode)
2958 {
2959     SmiElement *oldElement, *newElement;
2960     SmiOption *oldOption, *newOption;
2961     SmiNode *oldGroupNode, *newGroupNode, *oldNode, *newNode;
2962
2963     smiInit(oldTag);
2964     for (oldOption = smiGetFirstOption(oldComplNode);
2965          oldOption;
2966          oldOption = smiGetNextOption(oldOption)) {
2967         oldGroupNode = smiGetOptionNode(oldOption);
2968         for (oldElement = smiGetFirstElement(oldGroupNode);
2969              oldElement;
2970              oldElement = smiGetNextElement(oldElement)) {
2971             oldNode = smiGetElementNode(oldElement);
2972             smiInit(newTag);
2973             newNode = findGroupsElement(newComplNode, oldNode->name);
2974             if (! newNode) {
2975                 if (strcmp(smiGetNodeModule(oldNode)->name, oldModule->name)) {
2976                     printErrorAtLine(oldModule, ERR_OPTIONAL_EXT_REMOVED,
2977                                      smiGetNodeLine(oldNode),
2978                                      getStringNodekind(oldNode->nodekind),
2979                                      oldModule->name, oldNode->name,
2980                                      oldComplNode->name,
2981                                      newComplNode->name);
2982                 } else {
2983                     printErrorAtLine(oldModule, ERR_OPTIONAL_REMOVED,
2984                                      smiGetNodeLine(oldNode),
2985                                      getStringNodekind(oldNode->nodekind),
2986                                      oldNode->name,
2987                                      oldComplNode->name,
2988                                      newComplNode->name);
2989                 }
2990             } else {
2991                 /* xxx compare group condition description here? xxx */
2992             }
2993             smiInit(oldTag);
2994         }
2995     }
2996
2997     smiInit(newTag);
2998     for (newOption = smiGetFirstOption(newComplNode);
2999          newOption;
3000          newOption = smiGetNextOption(newOption)) {
3001         newGroupNode = smiGetOptionNode(newOption);
3002         for (newElement = smiGetFirstElement(newGroupNode);
3003              newElement;
3004              newElement = smiGetNextElement(newElement)) {
3005             newNode = smiGetElementNode(newElement);
3006             smiInit(oldTag);
3007             oldNode = findGroupsElement(oldComplNode, newNode->name);
3008             if (! oldNode) {
3009                 if (strcmp(smiGetNodeModule(newNode)->name, newModule->name)) {
3010                     printErrorAtLine(newModule, ERR_OPTIONAL_EXT_ADDED,
3011                                      smiGetNodeLine(newNode),
3012                                      getStringNodekind(newNode->nodekind),
3013                                      newModule->name, newNode->name,
3014                                      oldComplNode->name,
3015                                      newComplNode->name);
3016                 } else {
3017                     printErrorAtLine(newModule, ERR_OPTIONAL_ADDED,
3018                                      smiGetNodeLine(newNode),
3019                                      getStringNodekind(newNode->nodekind),
3020                                      newNode->name,
3021                                      oldComplNode->name,
3022                                      newComplNode->name);
3023                 }
3024             }
3025             smiInit(newTag);
3026         }
3027     }
3028 }
3029
3030
3031
3032 static void
3033 diffOldNewCompliance(SmiModule *oldModule, const char *oldTag,
3034                      SmiModule *newModule, const char *newTag,
3035                      const char *oldCompl, const char *newCompl)
3036 {
3037     SmiNode *smiNode;
3038     SmiNode *oldComplNode = NULL, *newComplNode = NULL;
3039
3040     for (smiNode = smiGetFirstNode(oldModule, SMI_NODEKIND_COMPLIANCE);
3041          smiNode;
3042          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_COMPLIANCE)) {
3043         if (strcmp(smiNode->name, oldCompl) == 0) {
3044             oldComplNode = smiNode;
3045         }
3046     }
3047
3048     if (! oldComplNode) {
3049             fprintf(stderr, "smidiff: unable to find old compliance `%s'\n",
3050                 oldCompl);
3051     }
3052
3053     for (smiNode = smiGetFirstNode(newModule, SMI_NODEKIND_COMPLIANCE);
3054          smiNode;
3055          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_COMPLIANCE)) {
3056         if (strcmp(smiNode->name, newCompl) == 0) {
3057             newComplNode = smiNode;
3058         }
3059     }
3060
3061     if (! newComplNode) {
3062         fprintf(stderr, "smidiff: unable to find new compliance `%s'\n",
3063                 newCompl);
3064     }
3065
3066     if (!oldComplNode || !newComplNode) {
3067         return;
3068     }
3069
3070     diffOldNewComplianceMandatory(oldModule, oldTag,
3071                                   newModule, newTag,
3072                                   oldComplNode, newComplNode);
3073     diffOldNewComplianceOptional(oldModule, oldTag,
3074                                  newModule, newTag,
3075                                  oldComplNode, newComplNode);
3076 }
3077
3078
3079
3080 static void
3081 usage()
3082 {
3083     fprintf(stderr,
3084             "Usage: smidiff [options] oldmodule newmodule\n"
3085             "  -V, --version             show version and license information\n"
3086             "  -c, --config=file         load a specific configuration file\n"
3087             "  -h, --help                show usage information\n"
3088             "  -i, --ignore=prefix       ignore errors matching prefix pattern\n"
3089             "  -l, --level=level         set maximum level of errors and warnings\n"
3090             "  -m, --error-names         print the name of errors in braces\n"
3091             "  -p, --preload=module      preload <module>\n"
3092             "  -s, --severity            print the severity of errors in brackets\n"
3093             "      --old-compliance=name name of the old compliance statement\n"
3094             "      --new-compliance=name name of the new compliance statement\n");
3095 }
3096
3097
3098
3099 static void help() { usage(); exit(0); }
3100 static void version() { printf("smidiff " SMI_VERSION_STRING "\n"); exit(0); }
3101 static void config(char *filename) { smiReadConfig(filename, "smidiff"); }
3102 static void level(int lev) { errorLevel = lev; }
3103 static void ignore(char *ign)
3104 {
3105     smiSetSeverity(ign, 9999);          /* libsmi  error messages */
3106     setErrorSeverity(ign, 9999);        /* smidiff error messages */
3107 }
3108
3109 static void preload(char *module) {
3110     smiInit(oldTag);
3111     smiLoadModule(module);
3112     smiInit(newTag);
3113     smiLoadModule(module);
3114 }
3115
3116
3117 int
3118 main(int argc, char *argv[])
3119 {
3120     SmiModule *oldModule, *newModule;
3121     int flags;
3122
3123     static optStruct opt[] = {
3124         /* short long              type        var/func       special       */
3125         { 'h', "help",           OPT_FLAG,   help,          OPT_CALLFUNC },
3126         { 'V', "version",        OPT_FLAG,   version,       OPT_CALLFUNC },
3127         { 'c', "config",         OPT_STRING, config,        OPT_CALLFUNC },
3128         { 'l', "level",          OPT_INT,    level,         OPT_CALLFUNC },
3129         { 'p', "preload",        OPT_STRING, preload,       OPT_CALLFUNC },
3130         { 'm', "error-names",    OPT_FLAG,   &mFlag,        0 },
3131         { 's', "severity",       OPT_FLAG,   &sFlag,        0 },
3132         { 'i', "ignore",         OPT_STRING, ignore,        OPT_CALLFUNC },
3133         {   0, "old-compliance", OPT_STRING, &oldCompl,     0 },
3134         {   0, "new-compliance", OPT_STRING, &newCompl,     0 },
3135         { 0, 0, OPT_END, 0, 0 }  /* no more options */
3136     };
3137     
3138     smiInit(oldTag);
3139     flags = smiGetFlags();
3140     flags |= SMI_FLAG_ERRORS;
3141     smiSetFlags(flags);
3142     smiSetErrorLevel(errorLevel);
3143
3144     smiInit(newTag);
3145     flags = smiGetFlags();
3146     flags |= SMI_FLAG_ERRORS;
3147     smiSetFlags(flags);
3148     smiSetErrorLevel(errorLevel);
3149
3150     optParseOptions(&argc, argv, opt, 0);
3151
3152     if (argc != 3) {
3153         usage();
3154         return 1;
3155     }
3156
3157     if (oldCompl && !newCompl) {
3158         fprintf(stderr, "smidiff: missing new compliance statement name\n");
3159         return 1;
3160     }
3161
3162     if (!oldCompl && newCompl) {
3163         fprintf(stderr, "smidiff: missing old compliance statement name\n");
3164         return 1;
3165     }
3166
3167     smiInit(oldTag);
3168     smiSetErrorLevel(errorLevel);
3169     oldModule = smiGetModule(smiLoadModule(argv[1]));
3170     if (! oldModule) {
3171         fprintf(stderr, "smidiff: cannot locate module `%s'\n", argv[1]);
3172         smiExit();
3173         exit(1);
3174     }
3175
3176     smiInit(newTag);
3177     smiSetErrorLevel(errorLevel);
3178     newModule = smiGetModule(smiLoadModule(argv[2]));
3179     if (! newModule) {
3180         fprintf(stderr, "smidiff: cannot locate module `%s'\n", argv[2]);
3181         smiExit();
3182         smiInit(oldTag);
3183         smiExit();
3184         exit(2);
3185     }
3186
3187     if (oldCompl && newCompl) {
3188         diffOldNewCompliance(oldModule, oldTag, newModule, newTag,
3189                              oldCompl, newCompl);
3190     } else {
3191         diffModules(oldModule, oldTag, newModule, newTag);
3192         diffTypes(oldModule, oldTag, newModule, newTag);
3193         diffObjects(oldModule, oldTag, newModule, newTag);
3194         diffNotifications(oldModule, oldTag, newModule, newTag);
3195         diffGroups(oldModule, oldTag, newModule, newTag);
3196         diffCompliances(oldModule, oldTag, newModule, newTag);
3197     }
3198
3199     smiInit(oldTag);
3200     smiExit();
3201
3202     smiInit(newTag);
3203     smiExit();
3204
3205     if (fflush(stdout) || ferror(stdout)) {
3206         perror("smidiff: write error");
3207         exit(1);
3208     }
3209
3210     return 0;
3211 }