parse_capabilities(FILE * fp, char *name)
{
    int             type;
    char            token[MAXTOKEN];
    char            quoted_string_buffer[MAXQUOTESTR];
    struct node    *np;

    np = alloc_node(current_module);
    if (np == NULL)
        return (NULL);
    type = get_token(fp, token, MAXTOKEN);
    if (type != PRODREL) {
        print_error("Expected PRODUCT-RELEASE", token, type);
        goto skip;
    }
    type = get_token(fp, token, MAXTOKEN);
    if (type != QUOTESTRING) {
        print_error("Expected STRING after PRODUCT-RELEASE", token, type);
        goto skip;
    }
    type = get_token(fp, token, MAXTOKEN);
    if (type != STATUS) {
        print_error("Expected STATUS", token, type);
        goto skip;
    }
    type = get_token(fp, token, MAXTOKEN);
    if (type != CURRENT && type != OBSOLETE) {
        print_error("STATUS should be current or obsolete", token, type);
        goto skip;
    }
    type = get_token(fp, token, MAXTOKEN);
    if (type != DESCRIPTION) {
        print_error("Expected DESCRIPTION", token, type);
        goto skip;
    }
    type = get_token(fp, quoted_string_buffer, MAXTOKEN);
    if (type != QUOTESTRING) {
        print_error("Bad DESCRIPTION", quoted_string_buffer, type);
        goto skip;
    }
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
			       NETSNMP_DS_LIB_SAVE_MIB_DESCRS)) {
        np->description = strdup(quoted_string_buffer);
    }
    type = get_token(fp, token, MAXTOKEN);
    if (type == REFERENCE) {
        type = get_token(fp, quoted_string_buffer, MAXTOKEN);
        if (type != QUOTESTRING) {
            print_error("Bad REFERENCE", quoted_string_buffer, type);
            goto skip;
        }
        np->reference = strdup(quoted_string_buffer);
        type = get_token(fp, token, type);
    }
    while (type == SUPPORTS) {
        int             modid;
        struct tree    *tp;

        type = get_token(fp, token, MAXTOKEN);
        if (type != LABEL) {
            print_error("Bad module name", token, type);
            goto skip;
        }
        modid = read_module_internal(token);
        if (modid != MODULE_LOADED_OK && modid != MODULE_ALREADY_LOADED) {
            print_error("Module not found", token, type);
            goto skip;
        }
        modid = which_module(token);
        type = get_token(fp, token, MAXTOKEN);
        if (type != INCLUDES) {
            print_error("Expected INCLUDES", token, type);
            goto skip;
        }
        type = get_token(fp, token, MAXTOKEN);
        if (type != LEFTBRACKET) {
            print_error("Expected \"{\"", token, type);
            goto skip;
        }
        do {
            type = get_token(fp, token, MAXTOKEN);
            if (type != LABEL) {
                print_error("Expected group name", token, type);
                goto skip;
            }
            tp = find_tree_node(token, modid);
            if (!tp)
                print_error("Group not found in module", token, type);
            type = get_token(fp, token, MAXTOKEN);
        } while (type == COMMA);
        if (type != RIGHTBRACKET) {
            print_error("Expected \"}\" after group list", token, type);
            goto skip;
        }
        type = get_token(fp, token, MAXTOKEN);
        while (type == VARIATION) {
            type = get_token(fp, token, MAXTOKEN);
            if (type != LABEL) {
                print_error("Bad object name", token, type);
                goto skip;
            }
            tp = find_tree_node(token, modid);
            if (!tp)
                print_error("Object not found in module", token, type);
            type = get_token(fp, token, MAXTOKEN);
            if (type == SYNTAX) {
                type = eat_syntax(fp, token, MAXTOKEN);
            }
            if (type == WRSYNTAX) {
                type = eat_syntax(fp, token, MAXTOKEN);
            }
            if (type == ACCESS) {
                type = get_token(fp, token, MAXTOKEN);
                if (type != ACCNOTIFY && type != READONLY
                    && type != READWRITE && type != READCREATE
                    && type != WRITEONLY && type != NOTIMPL) {
                    print_error("Bad ACCESS", token, type);
                    goto skip;
                }
                type = get_token(fp, token, MAXTOKEN);
            }
            if (type == CREATEREQ) {
                type = get_token(fp, token, MAXTOKEN);
                if (type != LEFTBRACKET) {
                    print_error("Expected \"{\"", token, type);
                    goto skip;
                }
                do {
                    type = get_token(fp, token, MAXTOKEN);
                    if (type != LABEL) {
                        print_error("Bad object name in list", token,
                                    type);
                        goto skip;
                    }
                    type = get_token(fp, token, MAXTOKEN);
                } while (type == COMMA);
                if (type != RIGHTBRACKET) {
                    print_error("Expected \"}\" after list", token, type);
                    goto skip;
                }
                type = get_token(fp, token, MAXTOKEN);
            }
            if (type == DEFVAL) {
                int             level = 1;
                type = get_token(fp, token, MAXTOKEN);
                if (type != LEFTBRACKET) {
                    print_error("Expected \"{\" after DEFVAL", token,
                                type);
                    goto skip;
                }
                do {
                    type = get_token(fp, token, MAXTOKEN);
                    if (type == LEFTBRACKET)
                        level++;
                    else if (type == RIGHTBRACKET)
                        level--;
                } while ((type != RIGHTBRACKET || level != 0)
                         && type != ENDOFFILE);
                if (type != RIGHTBRACKET) {
                    print_error("Missing \"}\" after DEFVAL", token, type);
                    goto skip;
                }
                type = get_token(fp, token, MAXTOKEN);
            }
            if (type != DESCRIPTION) {
                print_error("Expected DESCRIPTION", token, type);
                goto skip;
            }
            type = get_token(fp, quoted_string_buffer, MAXTOKEN);
            if (type != QUOTESTRING) {
                print_error("Bad DESCRIPTION", quoted_string_buffer, type);
                goto skip;
            }
            type = get_token(fp, token, MAXTOKEN);
        }
    }
    if (type != EQUALS)
        print_error("Expected \"::=\"", token, type);
  skip:
    while (type != EQUALS && type != ENDOFFILE) {
        type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
    }
    return merge_parse_objectid(np, fp, name);
}