#!/usr/bin/awk -f # # MIB to HTML file converter # Copyright (C) 1996 by Equivalance # # # # This script will convert most MIB definition files into a tree of # HTML files that can be used by MibMaster. It requires the "awk" # program, and is invoked as follows: # # awk -f mib_to_html mib.txt # # where: mib.txt is the input ASN file # # While running, it will print the names of all files it creates. The # last file generated will contain hyperlinks to all of the top level # files for the MIBs. It will have the same name as the MIB definition. # # This script will correctly interpret tables, and will automatically # detect and fill in enumerated types. It extracts the MIB descriptions # and inserts them as online help automatically. In fact, it's pretty damn # good, and will take every MIB file I can throw at it!! # # # Parse error codes # 100 expected IDENTIFIER # 101 expected IDENTIFIER # 102 type does not exist # 104 expected { or OF # 105 expected ACCESS type # 106 expected object attribute # 107 symbol used but not defined # 108 expected object identifer # 109 Attempt to define with empty name # 110 Attempt to redefine symbol # 111 Expected LITERAL ################################################################### ## ## general functions ## # # parse_error # display a parse error # function parse_error(num, str) { print "parse error " num " near line " NR " : " str; } # # generate_error # display a code generation error # function gen_error(num, str) { print "codegen error " num " : " str; } # # generate_warning # display a code generation warning # function gen_warning(num, str) { print "codegen warning " num " : " str; } # # sort # sort an array of strings and return the sorted indexes in _sort # function sort(array, f, i, len, t) { len = 0 for (i in array) { _sort[len] = i; len++; } f = 1; while (f != 0) { f = 0; for (i = 0; i < len-1; i++) { if (array[_sort[i]] > array[_sort[i+1]]) { t = _sort[i]; _sort[i] = _sort[i+1] _sort[i+1] = t; f = 1; } } } return len; } function sortobj(array, len) { len = 0 for (i in array) { _sort[len] = i; len++; } quicksort_obj(array, 0, len-1); return len; } function quicksort_obj(array, l, r, v, t, i, j, c) { if (r > l) { v = array[_sort[r]]; i = l - 1; j = r; do { do { i = i + 1; c = compare_oid(array[_sort[i]], v) } while (c < 0) do { j = j - 1; c = compare_oid(array[_sort[j]], v) } while (c > 0) t = _sort[i]; _sort[i] = _sort[j]; _sort[j] = t } while (j > i); _sort[j] = _sort[i]; _sort[i] = _sort[r]; _sort[r] = t quicksort_obj(array, l, i-1) quicksort_obj(array, i+1, r) } } # # make_filename # given a basename, make a legal filename. Also check it # for uniqueness against all other filenames created so far, # and also hack it for 8.3 compliance if required # function make_filename(fn, nfn, i) { if (_force8dot3) nfn = substr(tolower(fn), 1, 8) else nfn = tolower(fn) fn = nfn nfn = fn _fileext if (_force8dot3) nfn = substr(tolower(fn), 1, 6) else nfn = tolower(fn) fn = nfn; i = 0; nfn = fn _fileext while (nfn in _filenames) { i++; nfn = fn i _fileext } _filenames[nfn] = 1; return nfn; } # # compare_oid # compare two oids in terms of their numeric order # function compare_oid(oid1, oid2, l1, l2, c, j) { l1 = split(oid1, a1, ".") l2 = split(oid2, a2, ".") c = 0; j = 1; while ((c == 0) && (j <= l1) && (j <= l2)) { c = (a1[j] + 0) - (a2[j] + 0) j++ } if (c == 0) c = l1 - l2; return c; } # # relate_oid # compare the relationship between two oids. # if oid1 is a child of oid2, return -1 # if oid1 is identical to oid1, return 0 # if oid1 is a parent of oid2, return 1 # if the Lowest Common Parent of oid1 and oid2 isn't oid1 or oid, return 2 # # function relate_oid(oid1, oid2, l1, l2, c, j) { l1 = split(oid1, a1, ".") l2 = split(oid2, a2, ".") c = 0; j = 1; while ((c == 0) && (j <= l1) && (j <= l2)) { c = a1[j] - a2[j] j++ } if (c == 0) { if (l1 == l2) return 0; else if (l1 < l2) return 1; else return -1; } return 2; } # # return the parent of an oid by removing the last integer # function get_parent_oid(oid, n, array, i, poid) { # calculate the parent oid n = split(oid, array, ".") for (i = 1; i < n; i++) { if (i == 1) poid = array[i] else poid = poid "." array[i] } return poid; } function print_indent(indent) { for (i = 0; i < indent; i++) printf " "; } ################################################################### ## ## lexical analyser functions ## function get_new_line( stat, line) { do { stat = getline line; if (stat <= 0) return EOF; gsub(/^[ \t]*/, "", line); gsub(/[ \t]$/, "", line); } while (line == "") return line; } function get_raw_token( n, s, t, u, z) { gsub(/^[ \t]*/, "", _text); gsub(/[ \t]$/, "", line); while (1) { if (_text == "") _text = get_new_line() if (_text == EOF) return EOF; if (_text !~ /^\-\-/) break; _text = get_new_line(); if (_text == EOF) return EOF; } if (_text ~ /^\"[^\"]*/) { gsub(/^\"/, "", _text); sval = ""; while (1) { gsub(/^[ \t]*/, "", _text); gsub(/[ \t]*$/, "", _text); if (_text ~ /\"[ \t]*$/) break; if (sval == "") sval = _text "\n" else sval = sval " " _text "\n" stat = getline _text; if (stat <= 0) break; if (_text ~ /^[ \t]*$/) _text = "
\n" } gsub(/\"$/, "\n", _text); sval = sval _text _text = ""; return LITERAL; } if (match(_text, /^[a-zA-Z][a-zA-Z0-9\-_]+/) == 1) { sval = substr(_text, 1, RLENGTH); u = substr(_text, RLENGTH+1); _text = u; return IDENTIFIER; } if (match(_text, /[0-9]+/) == 1) { sval = substr(_text, 1, RLENGTH); u = substr(_text, RLENGTH+1); _text = u; return INTEGER; } if (match(_text, /^\:\:\=/) == 1) { sval = substr(_text, 1, RLENGTH); u = substr(_text, RLENGTH+1); _text = u; return ASSIGNMENT; } t = substr(_text, 1, 1); sval = t; _text = substr(_text, 2); return t; } function ignore_line() { _text = ""; } function get_token( t) { if (_unget_sp > 0) { t = _unget_token_stack [_unget_sp]; sval = _unget_lexeme_stack[_unget_sp]; _unget_sp--; return t; } t = get_raw_token(); if (t == EOF) return t; if (t != IDENTIFIER) return t; if (sval in _token) return _token[sval]; return t; } function unget_token(t, s) { _unget_sp++; _unget_token_stack [_unget_sp] = t; _unget_lexeme_stack[_unget_sp] = s; } function expect_identifier(id, t) { t = get_token(); if (t != IDENTIFIER || sval != id) { print "error 1 (" NR ") : expected " id ", found " s; exit; } } function expect_token(t, u) { u = get_token(); if (t != u) { print "error 2 (" NR ") : expected token " t " found " u; exit; } } function expect_literal() { if (get_token() != LITERAL) parse_error(111, "Expected LITERAL, found \"" sval "\""); } function get_integer( t) { t = get_token(); if (t != INTEGER) { print "error 3 (" NR ") : expected integer, found " sval; exit; } return sval; } function get_identifier( t) { t = get_token(); if (t != IDENTIFIER) { print "error 4 (" NR ") : expected identifier " s ", found " t; exit; } return sval; } ################################################################### ## ## ASN type functions ## function make_type(name, typeinfo, outputType) { if (!(name in _type)) { _type[name] = typeinfo _typeOutput[name] = outputType } ## else ## parse_error(103, "type " name " already exists"); } function resolve_type(name, t) { while (1) { t = _type[name] if (t == "") return name if (t !~ /^__/) return t name = t } } function dump_types( i) { print "types:" for (i in _type) print i } function dump_objects( i, len, oid) { print "objects:" len = sortobj(_symbolToOid) for (i = 0; i < len; i++) { oid = _symbolToOid[_sort[i]]; if (_oidToAccess[oid] != "na") { print oid " : " _sort[i] " " _oidToAccess[oid] } } } function make_object(oid, name, desc, access, syntax, size, type, idx) { if (oid in _oidToSymbol && _oidToSymbol[oid] != name) { _symbolToOid[name] = oid; return; } if (name == "") { parse_error(109, "Attempt to define " oid " with empty name") return; } if (name in _symbolToOid && oid != _symbolToOid[name]) { parse_error(110, "Attempt to redefine symbol " name); return; } _symbolToOid[name] = oid _oidToSymbol[oid] = name _oidToDesc[oid] = desc _oidToAccess[oid] = access _oidToSyntax[oid] = syntax _oidToType[oid] = type _oidToParent[oid] = get_parent_oid(oid) _oidToIndex[oid] = idx _oidToSize[oid] = size } ################################################################### ## ## parser functions ## function parse_enumeratedtype( text, t, pos, num, s) { text = ""; pos = 1; while (1) { t = get_token(); if (t == "}") return text else if (t == ",") ; else if (t == IDENTIFIER) { s = sval; expect_token("(") num = get_integer() expect_token(")") while (pos < num) { text = text "ILLEGAL " pos++; } text = text s " " pos++; } } } function parse_textual_convention( t, syntax, size) { while (syntax == "") { t = get_token(); if (t == STATUS) { if (get_token() != IDENTIFIER) ; } else if (t == DISPLAY_HINT) expect_literal(); else if (t == DESCRIPTION) expect_literal() else if (t == REFERENCE) expect_literal() else if (t == SYNTAX) { syntax = parse_type() size = _size } else parse_error(112, "expected TEXTUAL CONVENTION attribute, found \"" sval "\"") } return syntax; } function parse_type( s1, t2, t, size) { # get the first token of the type t = get_token(); def = ""; _size = 0 # INTEGER type if (t == INTEGERt) { t = get_token(); # check to see if it is an enumerated integer # if it is, create an internal type and return that as the type if (t == "{") { t = "__enum" _internalType; _internalType++; make_type(t, "E " parse_enumeratedtype(), ""); return t; } # check to see if it is has a min/max value if (t == "(") ignore_line(); # otherwise end of type else unget_token(t, sval); return "INTEGER"; } # SEQUENCE type if (t == SEQUENCE) { t = get_token(); # check if sequence of another type if (sval == "OF") { t = "__sequence" _internalType; _internalType++; make_type(t, "O " get_identifier(), ""); return t; } else if (t == "{") { s = ""; while (1) { t = get_token(); while (t == ",") t = get_token() if (t == "}" || t == EOF) break; if (s == "") s = sval else s = s " " sval parse_type() } t = "__sequence" _internalType; _internalType++; make_type(t, "S " s, ""); return t; } parse_error(104, "expected { or OF, found " _lexeme[t]); return ""; } if (t == OBJECT_TYPE) { return "OBJECT TYPE"; } if (t == TRAP_TYPE) { return "TRAP TYPE"; } if (t == OBJECT) { s1 = sval; t2 = get_token(); if (t2 == IDENTIFIERt) return "OBJECT ID"; unget_token(t2, sval); unget_token(t, s1); } if (t == OCTET) { s1 = sval; t2 = get_token(); if (t2 == STRING) { t = get_token(); if (t == "(") { expect_identifier("SIZE") expect_token("(") t = get_token() ##% while ((t != ")") && (t != EOF)) { if (t == INTEGER) _size = sval+0; t = get_token() ##% } expect_token(")") } else unget_token(t, sval) return "OCTET_STRING" } unget_token(t2, sval); unget_token(t, s1); } if (t == IDENTIFIER && (sval in _type)) { s1 = sval t = get_token(); if (t == "(") ignore_line(); else unget_token(t, sval); return s1; } if (t == TEXTUAL_CONVENTION) return parse_textual_convention(); return sval; } function parse_imports( t) { while (t != ";") t = get_token(); } function parse_block( t) { expect_token("{") t = get_token(); while (t != "}") { # print sval t = get_token(); } } function parse_index( t, str) { expect_token("{") while (1) { t = get_token(); if (t == EOF || t == "}") break; if (t != ",") str = str sval " " } return str } function parse_variables( s) { s = "" expect_token("{") while (1) { t = get_token() while (t == ",") t = get_token(); if (t == "}") break; if (s == "") s = sval else s = s " " sval } return s } # # parse_object_def # parse an object definition. This will result in the creation of an # entry in the OID tree # function parse_object_def(name, oid, type, access, syntax, desc, t, t2, s, i, y, z, str, fn, array, idx, size) { type = parse_type() access = "na" syntax = ""; desc = ""; while (1) { t = get_token(); if (t == ASSIGNMENT) break; if (t == SYNTAX) { syntax = parse_type() size = _size } else if (t == ACCESS) { t = get_token(); if (tolower(sval) == "read-only") access = "ro" else if (tolower(sval) == "read-write") access = "rw" else if (tolower(sval) == "not-accessible") access = "na" else parse_error(105, "expected ACCESS type, found \"" sval "\"") } else if (t == ENTERPRISE) { ignore_line(); } else if (t == STATUS) { if (get_token() != IDENTIFIER) ; } else if (t == DEFVAL) { ignore_line(); } else if (t == INDEX) { idx = parse_index(); } else if (t == REFERENCE) { expect_literal() } else if (t == VARIABLES) { variables[n] = parse_variables() } else if (t == DESCRIPTION) { expect_literal() desc = sval } else parse_error(106, "expected object attribute, found \"" sval "\"") } t = get_token() if (t == INTEGER) oid = sval+0; else if (t == "{") { oid = ""; while (1) { t = get_token() if (t == "}") break; if (t == INTEGER) { if (oid == "") oid = sval + 0; else oid = oid "." sval+0; } else if (t == IDENTIFIER) { s1 = sval t2 = get_token() if (t2 == "(") { z = get_integer(); expect_token(")") if (oid == "") oid = z else oid = oid "." z make_object(oid, s1, "", "na", "", 0, "", "") } else { unget_token(t2, sval) if (s1 in _symbolToOid) z = _symbolToOid[s1] else { parse_error(107, "symbol " s1 " used but not defined") z = 0; } if (oid == "") oid = z else oid = oid "." z } } else break; } } else { parse_error(108, "expected object identifer, found \"" sval "\"") return; } make_object(oid, name, desc, access, syntax, size, type, idx) return; } # # parse a type assignment of the form # newtype ::= oldtype # function parse_type_assign(newtype, oldtype) { oldtype = parse_type() # make sure the "old" type actually exists if (!(oldtype in _type)) { parse_error(102, "type " oldtype " does not exist") return; } # assign the information from the old type to the new type make_type(newtype, _type[oldtype], _typeOutput[oldtype]); } # # parse a DEFINITION block # function parse_definition( t, t2, t3, s) { t = get_token(); if (t == EOF) return EOF; if (t != IDENTIFIER) { parse_error(100, "expected IDENTIFIER, found " _lexeme[t] " \"" sval "\"") return EOF; } _defname = sval; expect_token(DEFINITIONS); expect_token(ASSIGNMENT); expect_token(BEGINt); fileList = FILELIST; print "Parsing " _defname "..."; t = get_token(); while (t != ENDt) { if (t == IMPORTS) parse_imports(); else if (t == IDENTIFIER) { s = sval; t2 = get_token(); if (t2 == ASSIGNMENT) parse_type_assign(s); else { unget_token(t2, sval); parse_object_def(s); } } else { parse_error(101, "expected IDENTIFIER, found \"" sval "\"") ignore_line(); } t = get_token(); } return 1; } ################################################################### ## ## initialisation functions ## function init_globals( i, symbol, t) { # globals _force8dot3 = 0; _text = ""; _unget_sp = 0; _internalType = 1; if (_force8dot3) _fileext = ".htm" else _fileext = ".html"; # token definitions EOF = -1; i = 256; IDENTIFIER = i++; LITERAL = i++; ASSIGNMENT = i++; INTEGER = i++; IMPORTS = i++; _token["IMPORTS"] = IMPORTS; ENDt = i++; _token["END"] = ENDt; BEGINt = i++; _token["BEGIN"] = BEGINt; OBJECT = i++; _token["OBJECT"] = OBJECT; IDENTIFIERt = i++; _token["IDENTIFIER"] = IDENTIFIERt; OBJECT_TYPE = i++; _token["OBJECT-TYPE"] = OBJECT_TYPE SEQUENCE = i++; _token["SEQUENCE"] = SEQUENCE; SYNTAX = i++; _token["SYNTAX"] = SYNTAX; ACCESS = i++; _token["ACCESS"] = ACCESS; _token["MAX-ACCESS"] = ACCESS; STATUS = i++; _token["STATUS"] = STATUS; DEFVAL = i++; _token["DEFVAL"] = DEFVAL DESCRIPTION = i++; _token["DESCRIPTION"] = DESCRIPTION; VARIABLES = i++; _token["VARIABLES"] = VARIABLES; INDEX = i++; _token["INDEX"] = INDEX; INTEGERt = i++; _token["INTEGER"] = INTEGERt; OCTET = i++; _token["OCTET"] = OCTET; STRING = i++; _token["STRING"] = STRING; REFERENCE = i++; _token["REFERENCE"] = REFERENCE; TRAP_TYPE = i++; _token["TRAP-TYPE"] = TRAP_TYPE; ENTERPRISE = i++; _token["ENTERPRISE"] = ENTERPRISE; DEFINITIONS = i++; _token["DEFINITIONS"] = DEFINITIONS; TEXTUAL_CONVENTION = i++; _token["TEXTUAL-CONVENTION"] = TEXTUAL_CONVENTION; DISPLAY_HINT = i++; _token["DISPLAY_HINT"] = DISPLAY_HINT; OCTECTSTRING = i++; OBJECTID = i++; # lexeme lookup table for (i in _token) _lexeme[_token[i]] = i; _lexeme[IDENTIFIER] = "IDENTIFIER"; _lexeme[LITERAL] = "LITERAL"; _lexeme[ASSIGNMENT] = "ASSIGNMENT"; _lexeme[INTEGER] = "INTEGER"; # RFC 1155 symbols _symbolToOid["iso"] = "1"; _symbolToOid["org"] = "1.3"; _symbolToOid["dod"] = "1.3.6"; _symbolToOid["internet"] = "1.3.6.1"; _symbolToOid["directory"] = _symbolToOid["internet"] ".1"; _symbolToOid["mgmt"] = _symbolToOid["internet"] ".2"; _symbolToOid["experimental"] = _symbolToOid["internet"] ".3"; _symbolToOid["private"] = _symbolToOid["internet"] ".4"; _symbolToOid["mib"] = _symbolToOid["mgmt"] ".1" _symbolToOid["mib-2"] = _symbolToOid["mgmt"] ".1" _symbolToOid["system"] = _symbolToOid["mib-2"] ".1" _symbolToOid["interfaces"] = _symbolToOid["mib-2"] ".2" _symbolToOid["at"] = _symbolToOid["mib-2"] ".3" _symbolToOid["ip"] = _symbolToOid["mib-2"] ".4" _symbolToOid["icmp"] = _symbolToOid["mib-2"] ".5" _symbolToOid["tcp"] = _symbolToOid["mib-2"] ".6" _symbolToOid["udp"] = _symbolToOid["mib-2"] ".7" _symbolToOid["egp"] = _symbolToOid["mib-2"] ".8" _symbolToOid["cmot"] = _symbolToOid["mib-2"] ".9" _symbolToOid["transmission"] = _symbolToOid["mib-2"] ".10" _symbolToOid["snmp"] = _symbolToOid["mib-2"] ".11" _symbolToOid["enterprises"] = _symbolToOid["private"] ".1" for (symbol in _symbolToOid) { _oidToSymbol[_symbolToOid[symbol]] = symbol _oidToAccess[_symbolToOid[symbol]] = "na"; } # types make_type("TRAP TYPE", "", ""); make_type("INTEGER", "", ""); make_type("OCTET_STRING", "", ""); make_type("DisplayString", "", ""); make_type("Counter", "", ""); make_type("TimeTicks", "", ""); make_type("Gauge", "", ""); make_type("PhysAddress", "", "hex"); make_type("IpAddress", "", ""); make_type("NetworkAddress", "", ""); make_type("DateAndTime", "", "dateandtime"); make_type("OBJECT ID", "", ""); # index lengths _typeToIndexLen["INTEGER"] = 1; _typeToIndexLen["IpAddress"] = 4; _typeToIndexLen["NetworkAddress"] = 4; } ################################################################### ## ## Code generation routines ## function get_change_page(oid, value, len, array, ofile, type, fn, i, text, typecode) { type = _oidToSyntax[oid] if (type in _typeToChangePage) return _typeToChangePage[type] if ((type !~ /^__enum/) && (type !~ /DateAndTime/)) return "/change.html" if (type ~ /^__enum/) { text = "
| " array[i] " | "
}
typecode = ""
} else {
text = "\">"
typecode = "date"
}
ofile = _dir "change" type ".html"
_typeToChangePage[type] = "../" ofile
print "Change MIB Entry" >> ofile print " |
|---|
| OID | Name | Type" s >> _outfile } function output_page_table_hdr(n, root) { output_hdr(n, "") print "" >> _outfile print " | Row " >> _outfile print "" >> _outfile print " |
|---|
" >> _outfile print "
| Name" >> _outfile; for (i = 0; i < len; i++) { suffix_i = suffixes[i] oid = root "." suffix_i name = _oidToSymbol[oid] print " | " name >> _outfile desc = desc make_description(_oidToSymbol[oid], _oidToDesc[oid]) } print " |
|---|---|
| Type" >> _outfile; for (i = 0; i < len; i++) { suffix_i = suffixes[i] oid = root "." suffix_i s = get_printable_type(oid) print " | " s >> _outfile } print " |
| Row " >> _outfile for (i = 0; i < len; i++) { suffix_i = suffixes[i] oid = root "." suffix_i t = _oidToType[oid] s = _oidToSyntax[oid] if (t == "OBJECT ID") { gen_error(102, "found nested table whilst expanding table") } else { if (t == "OBJECT TYPE") { t2 = resolve_type(s) if (s ~ /^__sequence/) gen_error(102, "found nested table whilst expanding table") else if (t2 ~ /^E /) { gsub(/^E /, "", t2) output_enum(3, prefix, oid, suffix_i, t2) } else { t = _typeOutput[s] if (t == "") _output_entry(3, prefix, oid, suffix_i, "smartvalue") else _output_entry(3, prefix, oid, suffix_i, t) } } } } print " |