示例#1
0
/********************************************************************
 * FUNCTION output_pattern_diff
 * 
 *  Output the differences report for one pattern clause and
 *  any of its sub-clauses, within a leaf, leaf-list, or 
 *  typedef definition
 *
 * INPUTS:
 *    cp == parameter block to use
 *    oldpat == old internal pattern
 *    newpat == new internal pattern
 *    patnum == index number of pattern in the Q [1 .. N]
 *
 *********************************************************************/
static void
    output_pattern_diff (yangdiff_diffparms_t *cp,
                         const typ_pattern_t *oldpat,
                         const typ_pattern_t *newpat,
                         uint32 patnum)
{
    const ncx_errinfo_t *olderr, *newerr;
    const xmlChar       *oldstr, *newstr;
    xmlChar              buff[NCX_MAX_NUMLEN+16], *p;

    oldstr = (oldpat) ? oldpat->pat_str : NULL;
    newstr = (newpat) ? newpat->pat_str : NULL;

    olderr = (oldpat) ? &oldpat->pat_errinfo : NULL;
    newerr = (newpat) ? &newpat->pat_errinfo : NULL;

    p = buff;
    p += xml_strcpy(p, YANG_K_PATTERN);
    *p++ = ' ';
    *p++ = '[';
    p += (uint32)sprintf((char *)p, "%u", patnum);
    *p++ = ']';
    *p = 0;
    
    if (!oldstr && newstr) {
        /* pattern added in new revision */
        output_diff(cp, buff, oldstr, newstr, FALSE);
        indent_in(cp);
        output_errinfo_diff(cp, olderr, newerr);
        indent_out(cp);
    } else if (oldstr && !newstr) {
        /* pattern removed in new revision */
        output_diff(cp, buff, oldstr, newstr, FALSE);
        indent_in(cp);
        output_errinfo_diff(cp, olderr, newerr);
        indent_out(cp);
    } else if (oldstr && newstr) {
        /* check if pattern changed */
        if (xml_strcmp(oldstr, newstr)) {
            output_diff(cp, buff, oldstr, newstr, FALSE);
            indent_in(cp);
            output_errinfo_diff(cp, olderr, newerr);
            indent_out(cp);
        } else if (errinfo_changed(olderr, newerr)) {
            output_mstart_line(cp, buff, oldstr, FALSE);
            indent_in(cp);
            output_errinfo_diff(cp, olderr, newerr);
            indent_out(cp);
        }
    }

} /* output_pattern_diff */
示例#2
0
/********************************************************************
 * FUNCTION output_one_typedef_diff
 * 
 *  Output the differences report for one typedef definition
 *
 * INPUTS:
 *    cp == parameter block to use
 *    oldtyp == old typedef
 *    newtyp == new typedef
 *
 *********************************************************************/
static void
    output_one_typedef_diff (yangdiff_diffparms_t *cp,
                             typ_template_t *oldtyp,
                             typ_template_t *newtyp)
{
    yangdiff_cdb_t  typcdb[5];
    uint32          changecnt, i;
    boolean         isrev, tchanged;

    isrev = (cp->edifftype==YANGDIFF_DT_REVISION) ? TRUE : FALSE;

    tchanged = FALSE;
    changecnt = 0;

    if (type_changed(cp, &oldtyp->typdef, &newtyp->typdef)) {
        tchanged = TRUE;
        changecnt++;
    }

    changecnt += str_field_changed(YANG_K_UNITS,
                                   oldtyp->units, newtyp->units, 
                                   isrev, &typcdb[0]);
    changecnt += str_field_changed(YANG_K_DEFAULT,
                                   oldtyp->defval, newtyp->defval, 
                                   isrev, &typcdb[1]);
    changecnt += status_field_changed(YANG_K_STATUS,
                                      oldtyp->status, newtyp->status, 
                                      isrev, &typcdb[2]);
    changecnt += str_field_changed(YANG_K_DESCRIPTION,
                                   oldtyp->descr, newtyp->descr, 
                                   isrev, &typcdb[3]);
    changecnt += str_field_changed(YANG_K_REFERENCE,
                                   oldtyp->ref, newtyp->ref, 
                                   isrev, &typcdb[4]);
    if (changecnt == 0) {
        return;
    }

    /* generate the diff output, based on the requested format */
    output_mstart_line(cp, YANG_K_TYPEDEF, oldtyp->name, TRUE);

    if (cp->edifftype == YANGDIFF_DT_TERSE) {
        return;
    }

    indent_in(cp);

    for (i=0; i<5; i++) {
        if (typcdb[i].changed) {
            output_cdb_line(cp, &typcdb[i]);
        }
    }

    if (tchanged) {
        output_one_type_diff(cp, &oldtyp->typdef, &newtyp->typdef);
    }

    indent_out(cp);

} /* output_one_typedef_diff */
示例#3
0
/********************************************************************
 * FUNCTION output_range_diff
 * 
 *  Output the differences report for one range or length
 *  clause and any sub-clauses,
 *  within a leaf, leaf-list, or typedef definition
 *
 * Only the top-level typedef is checked, instead of
 * following the type chain looking for the first rangedef.
 * This prevents chain mis-alignment false positives
 *
 * Only the top-level rangedef is relevant for validation,
 * since each refinement must be a valid subset of its parent
 * range definition
 *
 * INPUTS:
 *    cp == parameter block to use
 *    keyword == range or length keyword
 *    oldtypdef == old internal typedef
 *    newtypdef == new internal typedef
 *
 *********************************************************************/
static void
    output_range_diff (yangdiff_diffparms_t *cp,
                       const xmlChar *keyword,
                       typ_def_t *oldtypdef,
                       typ_def_t *newtypdef)
{
    typ_range_t         *oldrange, *newrange;
    const xmlChar       *oldstr, *newstr;
    ncx_errinfo_t       *olderr, *newerr;
    yangdiff_cdb_t       cdb;
    boolean              isrev;

    isrev = (cp->edifftype==YANGDIFF_DT_REVISION) ? TRUE : FALSE;
    oldrange = typ_get_range_con(oldtypdef);
    oldstr = oldrange ? oldrange->rangestr : NULL;
    newrange = typ_get_range_con(newtypdef);
    newstr = newrange ? newrange->rangestr : NULL;
    olderr = typ_get_range_errinfo(oldtypdef);
    newerr = typ_get_range_errinfo(newtypdef);

    if (str_field_changed(keyword, 
                          oldstr, 
                          newstr,
                          isrev, 
                          &cdb)) {
        output_cdb_line(cp, &cdb);
        indent_in(cp);
        output_errinfo_diff(cp, olderr, newerr);
        indent_out(cp);
    }

} /* output_range_diff */
示例#4
0
static char *def_array_type(CTX *ctx, struct ir_array_type *at)
{
    char *m = get_mangle(ctx, at);
    if (m)
        return m;
    assert(ctx->writing_types);
    m = talloc_strdup(ctx, MANGLE_PREFIX "arr_");
    m = talloc_asprintf_append_buffer(m, "%d_", at->dimension);
    mangle_append_sub(&m, def_type(ctx, at->item_type));
    add_mangle(ctx, at, m);
    if (!check_redef(ctx, m)) {
        wf(ctx, "typedef struct %s {", m);
        indent_in(ctx);
        wf(ctx, "%s a[%d];", def_type(ctx, at->item_type), at->dimension);
        indent_out(ctx);
        wf(ctx, "} %s;", m);
    }
    return m;
}
示例#5
0
static void write_struct(CTX *ctx, struct ir_struct_type *st, char *name)
{
    assert(ctx->writing_types);
    wf(ctx, "struct %s;", name);
    wf(ctx, "typedef struct %s %s;", name, name);
    // Make sure all types are written out first.
    for (int n = 0; n < st->members_count; n++) {
        struct ir_struct_member *m = st->members[n];
        def_type(ctx, m->type);
    }
    set_loc(ctx, st->loc);
    wf(ctx, "struct %s {", name);
    indent_in(ctx);
    for (int n = 0; n < st->members_count; n++) {
        struct ir_struct_member *m = st->members[n];
        struct name_temp t;
        char *mname = member_name(m, &t);
        set_loc(ctx, m->loc);
        wf(ctx, "%s %s;", def_type(ctx, m->type), mname);
    }
    indent_out(ctx);
    wf(ctx, "};");
    set_no_loc(ctx);
}
示例#6
0
static void gen_fn(CTX *ctx, struct ir_function *fn, char *name, bool visible)
{
    assert(!ctx->writing_types);

    if (!fn->parent)
        fn_complete_nested_calls(fn);

    for (int n = 0; n < fn->nested_functions_count; n++) {
        struct ir_function *nfn = fn->nested_functions[n];
        ctx->writing_types = true;
        char *nname = def_nested_fn(ctx, nfn);
        ctx->writing_types = false;
        gen_fn(ctx, nfn, nname, false);
    }

    fn_remove_global_ssa(fn);
    fn_verify(fn);
    //dump_fn(stderr, fn);

    for (int b = 0; b < fn->blocks_count; b++) {
        for (struct ir_inst *in = fn->blocks[b]->first; in; in = in->next)
            in->scratch1_i = -1;
    }

    // add all C types and function declarations needed for this function
    ctx->writing_types = true;
    do_fn_types(ctx, fn->type);
    for (int n = 0; n < fn->vars_count; n++)
        def_type(ctx, fn->vars[n]->type);
    for (int b = 0; b < fn->blocks_count; b++) {
        struct ir_bb *bb = fn->blocks[b];
        for (struct ir_inst *in = bb->first; in; in = in->next) {
            def_type(ctx, in->result_type);
            if (in->op == IR_OP_CALL || in->op == IR_OP_FN_PTR) {
                def_fn(ctx, in->fn);
            }
        }
    }
    ctx->writing_types = false;

    set_loc(ctx, fn->loc);
    if (!visible)
        fprintf(ctx->f, "static ");
    write_fn_type(ctx, fn->type, false, name);
    wf(ctx, " {");
    indent_in(ctx);
    for (int n = 0; n < fn->vars_count; n++) {
        struct ir_var *v = fn->vars[n];
        set_loc(ctx, v->loc);
        indent(ctx);
        P(ctx, "%s V%d", type(ctx, v->type), n);
        // void values are never assigned to (to avoid clashes with C's void);
        // since they have only one value, there's no need to. Initialize them
        // to avoid C warnings, though.
        if (type_is_void(v->type))
            P(ctx, " = {0}");
        P(ctx, ";\n");
    }
    indent(ctx);
    P(ctx, "goto B%d;\n", fn->entry->index);
    for (int b = 0; b < fn->blocks_count; b++) {
        struct ir_bb *bb = fn->blocks[b];
        indent(ctx);
        P(ctx, "B%d: {\n", b);
        indent_in(ctx);
        ctx->reg = 0;
        for (struct ir_inst *in = bb->first; in; in = in->next)
            gen_inst(ctx, in);
        indent_out(ctx);
        wf(ctx, "}");
    }
    indent_out(ctx);
    wf(ctx, "}");
}
示例#7
0
// sort in place, i.e. A will be reordered
void merge_sort(int16_t *A, int16_t A_len) {
    indent_in();
    indent();
    Serial.print("Entering merge sort: array addr ");
    Serial.print( (int) A );
    Serial.print(" len ");
    Serial.println( A_len);
    mem_info("");

    assert_free_mem_ok(128, "merge_sort");

    if ( A_len < 2 ) {
        indent_out();
        return;
        }

    if ( A_len == 2 ) {
        if ( A[0] > A[1] ) {
            int temp = A[0];
            A[0] = A[1];
            A[1] = temp;
            }
        indent_out();
        return;
        }

    // split A in half, sort left, sort right, then merge
    // left half is:  A[0], ..., A[split_point-1]
    // right half is: A[split_point], ..., A[A_len-1]

    int split_point = A_len / 2;

    indent();
    Serial.println("Doing left sort");

    merge_sort(A, split_point);

    mem_info("After left sort");

    indent();
    Serial.println("Doing right sort");

    merge_sort(A+split_point, A_len-split_point);

    mem_info("After right sort");

    // don't need the merging arrat S until this point
    int *S = (int *) malloc( A_len * sizeof(int) );

    assert_malloc_ok(S, "Cannot get merge buffer");

    mem_info("Doing merge");

    merge(A, split_point, A+split_point, A_len-split_point, S);

    for (int i=0; i < A_len; i++) {
        A[i] = S[i];
        }

    // now we are done with it
    free(S);

    mem_info("After free");
    indent_out();
    }
示例#8
0
/********************************************************************
 * FUNCTION output_union_diff
 * 
 *  Output the differences report for one union sub-clauses
 *  within a leaf, leaf-list, or typedef definition
 *
 * INPUTS:
 *    cp == parameter block to use
 *    oldtypdef == old internal typedef
 *    newtypdef == new internal typedef
 *********************************************************************/
static void
    output_union_diff (yangdiff_diffparms_t *cp,
                       typ_def_t *oldtypdef,
                       typ_def_t *newtypdef)
{
    typ_unionnode_t     *oldval, *newval, *curnew;
    dlq_hdr_t           *oldQ, *newQ;
    typ_def_t           *olddef, *newdef;
    uint32               oldid, newid;
    char                 oldnum[NCX_MAX_NUMLEN];
    char                 newnum[NCX_MAX_NUMLEN];

    olddef = typ_get_base_typdef(oldtypdef);
    newdef = typ_get_base_typdef(newtypdef);

    oldQ = &olddef->def.simple.unionQ,
    newQ = &newdef->def.simple.unionQ;

    if (!unQ_changed(cp, oldQ, newQ)) {
        return;
    }

    oldid = 0;
    newid = 0;

    /* clear the seen flag to be safe */
    for (newval = (typ_unionnode_t *)dlq_firstEntry(newQ);
         newval != NULL;
         newval = (typ_unionnode_t *)dlq_nextEntry(newval)) {
        newval->seen = FALSE;
    }

    /* start the diff output */
    output_mstart_line(cp, YANG_K_UNION, NULL, FALSE);
    if (cp->edifftype == YANGDIFF_DT_TERSE) {
        return;
    }

    indent_in(cp);

    /* check for matching unionnode entries */
    for (oldval = (typ_unionnode_t *)dlq_firstEntry(oldQ);
         oldval != NULL;
         oldval = (typ_unionnode_t *)dlq_nextEntry(oldval), oldid++) {

        curnew = NULL;
        sprintf(oldnum, "[%u]", oldid);
        olddef = typ_get_unionnode_ptr(oldval);

        /* first try the corresponded entry if available */
        newval = unQ_match_id(oldid, newQ);
        if (newval) {
            curnew = newval;
            newid = oldid;
            sprintf(newnum, "[%u]", newid);
            newdef = typ_get_unionnode_ptr(newval);

            /* if the corresponding entry did not change
             * then this is a match and continue to next type
             */
            if (!type_changed(cp, olddef, newdef)) {
                newval->seen = TRUE;
                continue;
            }
        }
            
        /* did not match the corresponding entry,
         * so see if the typdef moved in the new union
         */
        newval = unQ_match(cp, oldval, newQ, &newid);
        if (newval) {
            newval->seen = TRUE;
            if (oldid != newid) {
                sprintf(newnum, "[%u]", newid);
                /* old union node was moved in new version */
                output_diff(cp, YANG_K_TYPE, 
                            (const xmlChar *)oldnum, 
                            (const xmlChar *)newnum, TRUE);
            }
        } else if (curnew) {
            /* type node was changed in the new union */
            curnew->seen = TRUE;
            newdef = typ_get_unionnode_ptr(curnew);
            sprintf(newnum, "[%u]", oldid);
            output_one_type_diff(cp, olddef, newdef);
        } else {
            /* old union node was removed in new version */
            output_diff(cp, YANG_K_TYPE,
                        (const xmlChar *)oldnum, NULL, TRUE);
        }
    }

    indent_out(cp);

    /* check for new entries */
    newid = 0;
    for (newval = (typ_unionnode_t *)dlq_firstEntry(newQ);
         newval != NULL;
         newval = (typ_unionnode_t *)dlq_nextEntry(newval)) {
        if (!newval->seen) {
            sprintf(newnum, "[%u]", newid);
            output_diff(cp, YANG_K_TYPE, NULL,
                        (const xmlChar *)newnum, TRUE);
        }
        newid++;
    }

} /* output_union_diff */
示例#9
0
/********************************************************************
 * FUNCTION output_eb_type_diff
 * 
 *  Output the differences report for one enum or bits sub-clauses
 *  within a leaf, leaf-list, or typedef definition
 *
 * INPUTS:
 *    cp == parameter block to use
 *    name == type name to use
 *    oldtypdef == old internal typedef
 *    newtypdef == new internal typedef
 *    isbits == TRUE if NCX_BT_BITS
 *              FALSE if NCX_BT_ENUM
 *********************************************************************/
static void
    output_eb_type_diff (yangdiff_diffparms_t *cp,
                         typ_def_t *oldtypdef,
                         typ_def_t *newtypdef,
                         boolean isbits)
{
    typ_enum_t      *oldval, *newval;
    dlq_hdr_t       *oldQ, *newQ;
    typ_def_t       *oldbase, *newbase;
    const xmlChar   *kw;
    xmlChar          oldnum[NCX_MAX_NUMLEN];
    xmlChar          newnum[NCX_MAX_NUMLEN];
    yangdiff_cdb_t   cdb[4];
    boolean          isrev;
    uint32           chcount, i;

    oldbase = typ_get_base_typdef(oldtypdef);
    newbase = typ_get_base_typdef(newtypdef);

    oldQ = &oldbase->def.simple.valQ;
    newQ = &newbase->def.simple.valQ;

    isrev = (cp->edifftype==YANGDIFF_DT_REVISION) ? TRUE : FALSE;
    kw = isbits ? YANG_K_BIT : YANG_K_ENUM;

    /* clear the seen flag to find new enums/bits */
    for (newval = (typ_enum_t *)dlq_firstEntry(newQ);
         newval != NULL;
         newval = (typ_enum_t *)dlq_nextEntry(newval)) {
        newval->flags &= ~TYP_FL_SEEN;
    }

    /* check for matching entries */
    for (oldval = (typ_enum_t *)dlq_firstEntry(oldQ);
         oldval != NULL;
         oldval = (typ_enum_t *)dlq_nextEntry(oldval)) {

        chcount = 0;
        newval = typ_find_enumdef(newQ, oldval->name);
        if (newval) {
            if (isbits) {
                sprintf((char *)oldnum, "%u", oldval->pos);
                sprintf((char *)newnum, "%u", newval->pos);                     
                chcount += str_field_changed(YANG_K_POSITION,
                                             oldnum, newnum,
                                             isrev, &cdb[0]);
            } else {
                sprintf((char *)oldnum, "%d", oldval->val);
                sprintf((char *)newnum, "%d", newval->val);                     
                chcount += str_field_changed(YANG_K_VALUE,
                                             oldnum, newnum,
                                             isrev, &cdb[0]);
            }
            chcount += status_field_changed(YANG_K_STATUS,
                                            oldval->status, newval->status,
                                            isrev, &cdb[1]);
            chcount += str_field_changed(YANG_K_DESCRIPTION,
                                         oldval->descr, newval->descr,
                                         isrev, &cdb[2]);
            chcount += str_field_changed(YANG_K_REFERENCE,
                                         oldval->ref, newval->ref,
                                         isrev, &cdb[3]);
            newval->flags |= TYP_FL_SEEN;
            if (chcount) {
                output_mstart_line(cp, kw, oldval->name, isbits);
                if (cp->edifftype != YANGDIFF_DT_TERSE) {
                    indent_in(cp);
                    for (i=0; i<4; i++) {
                        output_cdb_line(cp, &cdb[i]);
                    }
                    indent_out(cp);
                }
            }
        } else {
            /* removed name in new version */
            output_diff(cp, kw, oldval->name, NULL, isbits);
        }
    }

    /* check for new entries */
    for (newval = (typ_enum_t *)dlq_firstEntry(newQ);
         newval != NULL;
         newval = (typ_enum_t *)dlq_nextEntry(newval)) {
        if ((newval->flags & TYP_FL_SEEN) == 0) {
            output_diff(cp, kw, NULL, newval->name, isbits);
        }
    }

} /* output_eb_type_diff */
示例#10
0
/********************************************************************
 * FUNCTION output_one_type_diff
 * 
 *  Output the differences report for one type section
 *  within a leaf, leaf-list, or typedef definition
 *
 * type_changed should be called first to determine
 * if the type actually changed.  Otherwise a 'M typedef foo'
 * output line will result and be a false positive
 *
 * INPUTS:
 *    cp == parameter block to use
 *    oldtypdef == old internal typedef
 *    newtypdef == new internal typedef
 *
 *********************************************************************/
void
    output_one_type_diff (yangdiff_diffparms_t *cp,
                          typ_def_t *oldtypdef,
                          typ_def_t *newtypdef)
{
    xmlChar            *p, *oldp, *newp;
    const xmlChar      *oldname, *newname;
    const xmlChar      *oldpath, *newpath;
    yangdiff_cdb_t      typcdb[5];
    ncx_btype_t         oldbtyp, newbtyp;
    ncx_tclass_t        oldclass, newclass;
    boolean             isrev;

    isrev = (cp->edifftype==YANGDIFF_DT_REVISION) ? TRUE : FALSE;

    oldclass = oldtypdef->tclass;
    newclass = newtypdef->tclass;

    oldname = typ_get_name(oldtypdef);
    newname = typ_get_name(newtypdef);

    oldbtyp = typ_get_basetype(oldtypdef);
    newbtyp = typ_get_basetype(newtypdef);

    if (oldbtyp == NCX_BT_LEAFREF) {
        oldpath = typ_get_leafref_path(oldtypdef);
    } else {
        oldpath = NULL;
    }
    if (newbtyp==NCX_BT_LEAFREF) {
        newpath = typ_get_leafref_path(newtypdef);
    } else {
        newpath = NULL;
    }

    /* check if there is a module prefix involved
     * in the change.  This may be a false positive
     * if the prefix simply changed
     * create YANG QNames for the type change record
     * use the scratch buffer cp->buff for both strings
     */
    p = cp->buff;
    if (oldtypdef->prefix) {
        oldp = p;
        p += xml_strcpy(p, oldtypdef->prefix);
        *p++ = ':';
        p += xml_strcpy(p, oldname);
        if (oldtypdef->tclass==NCX_CL_NAMED) {
            *p++ = ' ';
            *p++ = '(';
            p += xml_strcpy(p, (const xmlChar *)
                            tk_get_btype_sym(oldbtyp));
            *p++ = ')';
            *p = 0;         
        }
        p++;   /* leave last NULL char in place */
        oldname = oldp;
    }
    if (newtypdef->prefix) {
        newp = p;
        p += xml_strcpy(p, newtypdef->prefix);
        *p++ = ':';
        p += xml_strcpy(p, newname);
        if (newtypdef->tclass==NCX_CL_NAMED) {
            *p++ = ' ';
            *p++ = '(';
            p += xml_strcpy(p, (const xmlChar *)
                            tk_get_btype_sym(newbtyp));
            *p++ = ')';
            *p = 0;
        }
        newname = newp;
    }

    /* Print the type name change set only if it really
     * changed; otherwise force an M line to be printed
     */
    if (str_field_changed(YANG_K_TYPE, oldname, newname, 
                          isrev, &typcdb[0])) {
        output_cdb_line(cp, &typcdb[0]);
    } else {
        output_mstart_line(cp, YANG_K_TYPE, NULL, FALSE);
    }

    /* check invalid change of builtin type */
    if (oldbtyp != newbtyp) {
        /* need to figure out what type changes are really allowed */
        if (!((typ_is_number(oldbtyp) && typ_is_number(newbtyp)) ||
              (typ_is_string(oldbtyp) && typ_is_string(newbtyp)))) {
            /* ses_putstr(cp->scb, (const xmlChar *)" (invalid)"); */
            return;
        }
    }

    /* check if that is all the data requested */
    if (cp->edifftype == YANGDIFF_DT_TERSE) {
        return;
    }

    /* check corner-case, no sub-fields to compare */
    if (oldclass==NCX_CL_BASE && newclass==NCX_CL_BASE) {
        /* type field is a plain builtin like 'int32;' */
        return;
    }

    /* in all modes except 'normal', indent 1 level and
     * show the specific sub-clauses that have changed
     */
    indent_in(cp);

    /* special case -- check leafref here */
    if (oldpath || newpath) {
        output_diff(cp, YANG_K_PATH, oldpath, newpath, FALSE);
    }

    if (typ_is_number(oldbtyp)) {
        output_range_diff(cp, YANG_K_RANGE, oldtypdef, newtypdef);
    } else if (typ_is_string(oldbtyp)) {
        output_range_diff(cp, YANG_K_LENGTH, oldtypdef, newtypdef);
        output_patternQ_diff(cp, oldtypdef, newtypdef);
    } else {
        switch (oldbtyp) {
        case NCX_BT_ENUM:
            output_eb_type_diff(cp, oldtypdef, newtypdef, FALSE);
            break;
        case NCX_BT_BITS:
            output_eb_type_diff(cp, oldtypdef, newtypdef, TRUE);
            break;
        case NCX_BT_UNION:
            output_union_diff(cp, oldtypdef, newtypdef);
            break;
        default:
            ;
        }
    }

    indent_out(cp);

} /* output_one_type_diff */