Imported Upstream version 0.4.8
[platform/upstream/libsmi.git] / tools / smilint.c
1 /*
2  * smilint.c --
3  *
4  *      MIB module checker main program.
5  *
6  * Copyright (c) 1999 Frank Strauss, Technical University of Braunschweig.
7  *
8  * See the file "COPYING" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  * @(#) $Id: smilint.c 1867 2004-10-06 13:45:31Z strauss $
12  */
13
14 #include <config.h>
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22 #ifdef HAVE_WIN_H
23 #include "win.h"
24 #endif
25
26 #include "smi.h"
27 #include "shhopt.h"
28
29
30
31 /*
32  * These are functions that are not officially exported by the libsmi.
33  * See the original prototype definitions in lib/error.h.
34  */
35
36 extern int smiGetErrorSeverity(int id);
37 extern char* smiGetErrorTag(int id);
38 extern char* smiGetErrorMsg(int id);
39 extern char* smiGetErrorDescription(int id);
40
41
42 static int mFlag = 0;   /* show the name for error messages */
43 static int sFlag = 0;   /* show the severity for error messages */
44 static int eFlag = 0;   /* print the list of possible error messages */
45 static int flags;
46
47
48 typedef struct Error {
49     int id;
50     int severity;
51     char *tag;
52     char *msg;
53     char *description;
54     int used;
55 } Error;
56
57
58 static Error *errors = NULL;
59
60
61 static void fold(FILE *f, int indent, const char *msg)
62 {
63     const char *p, *s;
64
65     if (! msg) {
66         fprintf(f, "\n");
67         return;
68     }
69
70     for (s = msg; *s; s++) {
71         for (p = s; *p && *p != '\n'; p++) ;
72         if (*p) {
73             fprintf(f, "%.*s\n%*s", p - s, s, indent, "");
74             s = p;
75         } else {
76             fprintf(f, "%.*s\n", p - s, s);
77             break;
78         }
79     }
80 }
81
82
83
84 static int compare(const void *v1, const void *v2)
85 {
86     Error *err1 = (Error *) v1;
87     Error *err2 = (Error *) v2;
88
89     if (err1->severity < err2->severity) {
90         return -1;
91     }
92     if (err1->severity > err2->severity) {
93         return 1;
94     }
95     return strcmp(err1->msg, err2->msg);
96 }
97
98
99
100 static Error* errors_new()
101 {
102     int i, cnt;
103     Error *errors;
104     
105     for (cnt = 0; smiGetErrorSeverity(cnt) >= 0; cnt++) ;
106     
107     errors = malloc((cnt + 1) * sizeof(Error));
108     if (! errors) {
109         fprintf(stderr, "smilint: malloc failed - running out of memory\n");
110         exit(1);
111     }
112     memset(errors, 0, (cnt + 1) * sizeof(Error));
113
114     for (i = 0; i < cnt; i++) {
115         errors[i].id = i;
116         errors[i].severity = smiGetErrorSeverity(i);
117         errors[i].tag = smiGetErrorTag(i);
118         errors[i].msg = smiGetErrorMsg(i);
119         errors[i].description = smiGetErrorDescription(i);
120     }
121
122     qsort(errors, cnt, sizeof(Error), compare);
123
124     return errors;
125 }
126
127
128 static void display_one(FILE *f, Error *error)
129 {
130     const int indent = 12;
131     char *type, *tag;
132
133     type = (error->severity <= 3) ? "Error:" : "Warning:";
134     tag = (error->tag && strlen(error->tag))
135         ? error->tag : "<xxx-missing-xxx>";
136     fprintf(f, "%-*s %s (level %d%s)\n",
137             indent, type, tag, error->severity & 127,
138             error->severity & 128 ? ", ignored" : "");
139     fprintf(f, "%-*s %s\n", indent, "Message:",
140             error->msg ? error->msg : "");
141     if (error->description) {
142         fprintf(f, "%-*s ", indent, "Description:");
143         fold(f, indent + 1, error->description);
144     }
145 }
146
147
148 static void display_all(Error *errors)
149 {
150     int i;
151     
152     for (i = 0; errors[i].msg; i++) {
153         if (i) printf("\n");
154         display_one(stdout, errors + i);
155     }
156 }
157
158
159
160 static void display_used(Error *errors)
161 {
162     int i, n;
163
164     for (i = 0, n = 0; errors[i].msg; i++) {
165         if (errors[i].used && errors[i].description) n++;
166     }
167
168     if (! n) {
169         return;
170     }
171
172     fprintf(stderr,
173             "\nAdditional descriptions of some error/warning messages:\n"); 
174
175     for (i = 0; errors[i].msg; i++) {
176         if (! errors[i].used || !errors[i].description) continue;
177         if (i) fprintf(stderr, "\n");
178         display_one(stderr, errors + i);
179     }
180 }
181
182
183
184 static void usage()
185 {
186     fprintf(stderr,
187             "Usage: smilint [options] [module or path ...]\n"
188             "  -V, --version         show version and license information\n"
189             "  -h, --help            show usage information\n"
190             "  -c, --config=file     load a specific configuration file\n"
191             "  -p, --preload=module  preload <module>\n"
192             "  -e, --error-list      print list of known error messages\n"
193             "  -m, --error-names     print the name of errors in braces\n"
194             "  -s, --severity        print the severity of errors in brackets\n"
195             "  -r, --recursive       print errors also for imported modules\n"
196             "  -l, --level=level     set maximum level of errors and warnings\n"
197             "  -i, --ignore=prefix   ignore errors matching prefix pattern\n"
198             "  -I, --noignore=prefix do not ignore errors matching prefix pattern\n");
199 }
200
201
202
203 static void help() { usage(); exit(0); }
204 static void version() { printf("smilint " SMI_VERSION_STRING "\n"); exit(0); }
205 static void config(char *filename) { smiReadConfig(filename, "smilint"); }
206 static void preload(char *module) { smiLoadModule(module); }
207 static void recursive() { flags |= SMI_FLAG_RECURSIVE; smiSetFlags(flags); }
208 static void level(int lev) { smiSetErrorLevel(lev); }
209 static void ignore(char *ign) { smiSetSeverity(ign, 128); }
210 static void noignore(char *ign) { smiSetSeverity(ign, -1); }
211
212
213
214 static void
215 errorHandler(char *path, int line, int severity, char *msg, char *tag)
216 {
217     int i;
218     
219     if (path) {
220         fprintf(stderr, "%s:%d: ", path, line);
221     }
222     if (sFlag) {
223         fprintf(stderr, "[%d] ", severity);
224     }
225     if (mFlag) {
226         fprintf(stderr, "{%s} ", tag);
227     }
228     switch (severity) {
229     case 4:
230     case 5:
231         fprintf(stderr, "warning: ");
232         break;
233     case 6:     
234         fprintf(stderr, "info: ");
235         break;
236     }
237     fprintf(stderr, "%s\n", msg);
238
239     if (severity <= 0) {
240         exit(1);
241     }
242
243     /* If we are supposed to generate error descriptions, locate this
244      * error in our error list and increment its usage counter. Note
245      * that we assume that error tags are unique (and we should better
246      * check for this somewhere). */
247
248     if (errors) {
249         for (i = 0; errors[i].msg; i++) {
250             if (strcmp(errors[i].tag, tag) == 0) {
251                 errors[i].used++;
252                 break;
253             }
254         }
255     }
256 }
257
258
259
260 int main(int argc, char *argv[])
261 {
262     int i;
263
264     static optStruct opt[] = {
265         /* short long              type        var/func       special       */
266         { 'h', "help",           OPT_FLAG,   help,          OPT_CALLFUNC },
267         { 'V', "version",        OPT_FLAG,   version,       OPT_CALLFUNC },
268         { 'c', "config",         OPT_STRING, config,        OPT_CALLFUNC },
269         { 'p', "preload",        OPT_STRING, preload,       OPT_CALLFUNC },
270         { 'e', "error-list",     OPT_FLAG,   &eFlag,        0 },
271         { 'm', "error-names",    OPT_FLAG,   &mFlag,        0 },
272         { 's', "severity",       OPT_FLAG,   &sFlag,        0 },
273         { 'r', "recursive",      OPT_FLAG,   recursive,     OPT_CALLFUNC },
274         { 'l', "level",          OPT_INT,    level,         OPT_CALLFUNC },
275         { 'i', "ignore",         OPT_STRING, ignore,        OPT_CALLFUNC },
276         { 'I', "noignore",       OPT_STRING, noignore,      OPT_CALLFUNC },
277         { 0, 0, OPT_END, 0, 0 }  /* no more options */
278     };
279     
280     for (i = 1; i < argc; i++)
281         if ((strstr(argv[i], "-c") == argv[i]) ||
282             (strstr(argv[i], "--config") == argv[i])) break;
283     if (i == argc) 
284         smiInit("smilint");
285     else
286         smiInit(NULL);
287
288     flags = smiGetFlags();
289     flags |= SMI_FLAG_ERRORS;
290     flags |= SMI_FLAG_NODESCR;
291     smiSetFlags(flags);
292
293     optParseOptions(&argc, argv, opt, 0);
294
295     if (eFlag) {
296         mFlag = 1;
297         errors = errors_new();
298     }
299
300     if (sFlag || mFlag) {
301         smiSetErrorHandler(errorHandler);
302     }
303
304     if (eFlag && argc == 1) {
305         if (errors) {
306             display_all(errors);
307             free(errors);
308         }
309         smiExit();
310         return 0;
311     }
312     
313     for (i = 1; i < argc; i++) {
314         if (smiLoadModule(argv[i]) == NULL) {
315             fprintf(stderr, "smilint: cannot locate module `%s'\n",
316                     argv[i]);
317             smiExit();
318             exit(1);
319         }
320     }
321
322     if (eFlag) {
323         if (errors) {
324             display_used(errors);
325             free(errors);
326         }
327     }
328
329     smiExit();
330
331     return 0;
332 }