OpenSolaris_b135/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.
 */

#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 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:
		(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);
	}
}