root/usr/src/tools/ndrgen/ndr_print.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
 */

#include "ndrgen.h"
#include "y.tab.h"


static void print_declaration(ndr_node_t *);
static void print_advice_list(ndr_node_t *);
static void print_node_list(ndr_node_t *);


void
tdata_dump(void)
{
        print_node_list(construct_list);
}

void
print_node(ndr_node_t *np)
{
        char            *nm;

        if (!np) {
                (void) printf("<null>");
                return;
        }

        switch (np->label) {
        case ALIGN_KW:          nm = "align";           break;
        case FAKE_KW:           nm = "fake";            break;
        case STRUCT_KW:         nm = "struct";          break;
        case UNION_KW:          nm = "union";           break;
        case TYPEDEF_KW:        nm = "typedef";         break;
        case INTERFACE_KW:      nm = "interface";       break;
        case IN_KW:             nm = "in";              break;
        case OUT_KW:            nm = "out";             break;
        case SIZE_IS_KW:        nm = "size_is";         break;
        case LENGTH_IS_KW:      nm = "length_is";       break;
        case STRING_KW:         nm = "string";          break;
        case TRANSMIT_AS_KW:    nm = "transmit_as";     break;
        case OPERATION_KW:      nm = "operation";       break;
        case UUID_KW:           nm = "uuid";            break;
        case _NO_REORDER_KW:    nm = "_no_reorder";     break;
        case EXTERN_KW:         nm = "extern";          break;
        case ARG_IS_KW:         nm = "arg_is";          break;
        case CASE_KW:           nm = "case";            break;
        case DEFAULT_KW:        nm = "default";         break;
        case BASIC_TYPE:        nm = "<btype>";         break;
        case TYPENAME:          nm = "<tname>";         break;
        case IDENTIFIER:        nm = "<ident>";         break;
        case INTEGER:           nm = "<intg>";          break;
        case STRING:            nm = "<string>";        break;
        case STAR:              nm = "<*>";             break;
        case LB:                nm = "<[>";             break;
        case LP:                nm = "<(>";             break;
        case L_MEMBER:          nm = "<member>";        break;
        default:
                (void) printf("<<lab=%d>>", np->label);
                return;
        }

        switch (np->label) {
        case STRUCT_KW:
        case UNION_KW:
        case TYPEDEF_KW:
                (void) printf("\n");
                if (np->n_c_advice) {
                        print_advice_list(np->n_c_advice);
                        (void) printf("\n");
                }
                (void) printf("%s ", nm);
                print_node(np->n_c_typename);
                (void) printf(" {\n");
                print_node_list(np->n_c_members);
                (void) printf("};\n");
                break;

        case IN_KW:
        case OUT_KW:
        case STRING_KW:
        case DEFAULT_KW:
        case _NO_REORDER_KW:
        case EXTERN_KW:
        case FAKE_KW:
                (void) printf("%s", nm);
                break;

        case ALIGN_KW:
                /*
                 * Don't output anything for default alignment.
                 */
                if ((np->n_a_arg == NULL) || (np->n_a_arg->n_int == 0))
                        break;
                (void) printf("%s(", nm);
                print_node(np->n_a_arg);
                (void) printf(")");
                break;

        case SIZE_IS_KW:
        case LENGTH_IS_KW:
                (void) printf("%s(", nm);
                print_field_attr(np);
                (void) printf(")");
                break;

        case INTERFACE_KW:
        case TRANSMIT_AS_KW:
        case ARG_IS_KW:
        case CASE_KW:
        case OPERATION_KW:
        case UUID_KW:
                (void) printf("%s(", nm);
                print_node(np->n_a_arg);
                (void) printf(")");
                break;

        case BASIC_TYPE:
        case TYPENAME:
        case IDENTIFIER:
                (void) printf("%s", np->n_sym->name);
                break;

        case INTEGER:
                (void) printf("%ld", np->n_int);
                break;

        case STRING:
                (void) printf("\"%s\"", np->n_str);
                break;

        case STAR:
                (void) printf("*");
                print_node(np->n_d_descend);
                break;

        case LB:
                print_node(np->n_d_descend);
                (void) printf("[");
                if (np->n_d_dim)
                        print_node(np->n_d_dim);
                (void) printf("]");
                break;

        case LP:
                (void) printf("(");
                print_node(np->n_d_descend);
                (void) printf(")");
                break;

        case L_MEMBER:
                if (np->n_m_advice) {
                        (void) printf("    ");
                        print_advice_list(np->n_m_advice);
                        (void) printf("\n");
                }
                (void) printf("\t");
                print_declaration(np);
                (void) printf(";\n");
                break;

        default:
                return;
        }
}

/*
 * Field attributes are used to specify the size of an array, or the portion
 * of the array, that contains valid data, which is done by associating
 * another parameter with the array that contains the sizing information.
 *
 * Supports formats such as size_is(x) or size_is(x / 2).  The supported
 * operators are:
 *
 *      * / % + - & | ^
 */
void
print_field_attr(ndr_node_t *np)
{
        static char     *valid = "*/%+-&|^";
        ndr_node_t      *arg;
        char            *name;
        char            *operator;
        long            value;

        arg = np->n_a_arg;
        if (arg->label != IDENTIFIER)
                fatal_error("invalid label %d", arg->label);
        if ((name = arg->n_sym->name) == NULL)
                fatal_error("missing symbol name");

        arg = np->n_a_arg1;
        operator = NULL;
        if (arg->label == IDENTIFIER) {
                operator = arg->n_sym->name;

                if (operator != NULL) {
                        /*
                         * The lexer sets the name and operator to
                         * the same value if there is no operator.
                         */
                        if (strcmp(name, operator) == 0)
                                operator = NULL;
                        else if (strchr(valid, *operator) == NULL)
                                compile_error("invalid operator: %s", operator);
                }
        }

        arg = np->n_a_arg2;
        if (arg->label == INTEGER) {
                value = arg->n_int;

                if ((value == 0) && strcmp(operator, "/") == 0)
                        compile_error("divide by zero");
        }

        if (operator)
                (void) printf("%s %s %ldUL", name, operator, value);
        else
                (void) printf("%s", name);
}

static void
print_declaration(ndr_node_t *np)
{
        ndr_node_t      *dnp = np->n_m_decl;
        char            buf[NDLBUFSZ];
        char            *p = buf;

        if (np->n_m_type &&
            (np->n_m_type->label == IDENTIFIER ||
            np->n_m_type->label == TYPENAME)) {
                (void) snprintf(buf, NDLBUFSZ, "%s", np->n_m_type->n_sym->name);

                while (*p)
                        p++;

                if (dnp && dnp->label == STAR) {
                        *p++ = ' ';
                        while (dnp && dnp->label == STAR) {
                                *p++ = '*';
                                dnp = dnp->n_d_descend;
                        }
                }
                *p = 0;
                (void) printf("%-23s ", buf);
        } else {
                print_node(np->n_m_type);
                (void) printf(" ");
        }

        print_node(dnp);
}

static void
print_advice_list(ndr_node_t *np)
{
        if (!np)
                return;

        (void) printf("[");
        for (; np; np = np->n_next) {
                print_node(np);
                if (np->n_next)
                        (void) printf(" ");
        }
        (void) printf("]");
}

static void
print_node_list(ndr_node_t *np)
{
        for (; np; np = np->n_next) {
                print_node(np);
        }
}