#ifndef lint
static char sccsid[] = "@(#)rpc←hout.c 1.1 90/10/29 (C) 1987 SMI";
#endif

/*
 * rpc←hout.c, Header file outputter for the RPC protocol compiler 
 * Copyright (C) 1987, Sun Microsystems, Inc. 
 */
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include "rpc←util.h"
#include "rpc←parse.h"

list *pstructdef();
list *puniondef();
list *ptypedef();
list *pdeclaration();
char *CreateSeqType();


void
print←datadef(def)
	definition *def;
{
        list *sequenceDefns = NULL;
	list *seqDefn;

	switch (def->def←kind) {
	case DEF←STRUCT:
		sequenceDefns = pstructdef(def);
		break;
	case DEF←UNION:
		sequenceDefns = puniondef(def);
		break;
	case DEF←ENUM:
		penumdef(def);
		break;
	case DEF←TYPEDEF:
		sequenceDefns = ptypedef(def);
		break;
	case DEF←PROGRAM:
		pprogramdef(def);
		break;
	case DEF←CONST:
		pconstdef(def);
		break;
	}

	for (seqDefn = sequenceDefns; seqDefn != NULL; seqDefn = seqDefn->next)
	    f←print(fout, "\n%s", seqDefn->val);
}

static
pconstdef(def)
	definition *def;
{
	if (def->def.co[0] == '"')
	    f←print(fout, "%s: ROPE = %s;\n", def->def←name, def->def.co);
	else
	    f←print(fout, "%s: INT32 = %s;\n", def->def←name, def->def.co);
}

static
list *pstructdef(def)
	definition *def;
{
	decl←list *l;
	char *name = def->def←name;
	list *sequenceDefns = NULL;
	list *seqDefn;

	f←print(fout, "\n%s: TYPE = RECORD [\n", name);
	for (l = def->def.st.decls; l != NULL; l = l->next) {
	    seqDefn = pdeclaration(name, &l->decl, 1, TRUE);
	    if (seqDefn != NULL) {
		seqDefn->next = sequenceDefns;
		sequenceDefns = seqDefn;
	    }
	    if (l->next != NULL) f←print(fout, ",\n");
	    else f←print(fout, "\n");
	}
	f←print(fout, "\t];\n");

	return (sequenceDefns);
}

static
list *puniondef(def)
	definition *def;
{
	case←list *l;
	char *name = def->def←name;
	declaration *decl;
	char *defaultPrefix = "";
	list *sequenceDefns = NULL;
	list *seqDefn;
	int numericFlag;
	char *defaultEnumElements;
	int endFlag = TRUE;
	char *namesArray[128];

	f←print(fout, "\n%s: TYPE = REF %sObject;\n", name, name);
	f←print(fout, "%sObject: TYPE = RECORD [\n", name);
	decl = &def->def.un.enum←decl;
	if (NumericEnumType(decl->type))
	    numericFlag = TRUE;
	else
	    numericFlag = FALSE;
	if (PFlag && !numericFlag) {
	    f←print(fout, "\tunion: SELECT %s: %s FROM\n",
		    decl->name, MapToCedarType(decl->type, TRUE));
	}
	else {
	    if (streq(decl->type, "bool")) {
		f←print(fout, "\t%s: BOOLEAN,\n", decl->name);
	    } else {
		f←print(fout, "\t%s: %s,\n",
			decl->name, MapToCedarType(decl->type, TRUE));
	    }
	    f←print(fout, "\tunion: SELECT uTag: * FROM\n");
	}
	for (l = def->def.un.cases; l != NULL; l = l->next) {
	    if (PFlag) {
		if (numericFlag)
		    f←print(fout, "\t  v%s => [", l->case←name);
		else
		    f←print(fout, "\t  %s => [", l->case←name);
	    }
	    else {
		f←print(fout, "\t  %s%s => [", name, l->case←name);
	    }
	    if (!streq(l->case←decl.type, "void")) {
		seqDefn = pdeclaration(name, &l->case←decl, 0, TRUE);
		if (seqDefn != NULL) {
		    seqDefn->next = sequenceDefns;
		    sequenceDefns = seqDefn;
		}
	    }
	    f←print(fout, "],\n");
	    if (streq(l->case←name, "default")) {
		defaultPrefix = "0";
	    }
	}
	decl = def->def.un.default←decl;
	if (PFlag) {
	    if (numericFlag)
		f←print(fout, "\t  default => [");
	    else {
		defaultEnumElements = DefaultEnumTypes(def, namesArray);
		if (streq(defaultEnumElements, ""))
		    endFlag = FALSE;
		else
		    f←print(fout, "\t  %s => [", defaultEnumElements);
	    }
	}
	else {
	    f←print(fout, "\t  %s%sDefault => [", name, defaultPrefix);
	}
	if (decl && !streq(decl->type, "void")) {
	    seqDefn = pdeclaration(name, decl, 0, TRUE);
	    if (seqDefn != NULL) {
		seqDefn->next = sequenceDefns;
		sequenceDefns = seqDefn;
	    }
	}
	if (endFlag) f←print(fout, "],\n");
	f←print(fout, "\t  ENDCASE];\n");

	return (sequenceDefns);
}

static
pprogramdef(def)
	definition *def;
{
    char progName[256];
    char progNum[64];
    char progNumName[256];
    version←list *vers;
    proc←list *proc;
    definition *defStruct;
    decl←list *dl;
    int expandFlag;
    char *o = "o";
    extern definition *FindStructDefn();

    BadProgNameFlag[++CurrentProgNameFlag] = FALSE;

    strcpy(progNum, def->def.pr.prog←num);
    strcpy(progNumName, def->def←name);
    if (PFlag && ((progNumName[0] == '\0') || isdigit(progNumName[0]))) {
        BadProgNameFlag[CurrentProgNameFlag] = TRUE;
        sprintf(progNumName, "%sPrognum", svcName);
    }
    if ((progNum[0] == '0') && (progNum[1] == 'x'))
	f←print(fout, "\n%s: CARDINAL = %sH;\n", progNumName, &(progNum[2]));
    else
	f←print(fout, "\n%s: CARDINAL = %s;\n", progNumName, progNum);
    for (vers = def->def.pr.versions; vers != NULL; vers = vers->next) {
	f←print(fout, "\n%s: CARDINAL = %s;\n\n", vers->vers←name, vers->vers←num);
	if (BadProgNameFlag[CurrentProgNameFlag])
	    sprintf(progName, "%s%s", svcName, vers->vers←num);
	else
	    sprintf(progName, "%s%s", def->def←name, vers->vers←num);

	for (proc = vers->procs; proc != NULL; proc = proc->next) {
	    if (ExpandProcArgs) {
		defStruct = FindStructDefn(proc->arg←type);
	    }
	    if (ExpandProcArgs && defStruct != NULL &&
		defStruct->def←kind == DEF←STRUCT) {
		o = FindUniqueName("o", defStruct->def.st.decls);
		f←print(fout, "%sProc: TYPE = PROC[%s: %s,\n",
		        locase(proc->proc←name), o, progName);
		for (dl = defStruct->def.st.decls;
		     dl != NULL;
		     dl = dl->next) {
		    pdeclaration(defStruct->def←name, &(dl->decl), 16, TRUE);
		    if (dl->next == NULL)
			f←print(fout, "]");
		    else
			f←print(fout, ",\n");
		}
	    }
	    else {
	        f←print(fout, "%sProc: TYPE = PROC[o: %s",
		        locase(proc->proc←name), progName);
		if (!streq(proc->arg←type, "void"))
		    f←print(fout, ", in: %s]", MapToCedarType(proc->arg←type,
							      TRUE));
		else
		    f←print(fout, "]");
	    }
	    if (!streq(proc->res←type, "void"))
		f←print(fout, "\n\t\tRETURNS [res: %s]",
			MapToCedarType(proc->res←type, TRUE));
	    f←print(fout, ";\n");
	}
	f←print(fout, "\n");

	f←print(fout,
		"%s: TYPE =  REF %sObject;\n", progName, progName);
	f←print(fout, "%sObject: TYPE = RECORD [\n", progName);
	for (proc = vers->procs; proc != NULL; proc = proc->next) {
	    f←print(fout, "  %s: %sProc",
		    locase(proc->proc←name), locase(proc->proc←name));
	    f←print(fout, ",\n");
	}
	f←print(fout, "  rpcHandle: %s.Handle ← NIL,\n", SunRPC);
	f←print(fout, "  rpcConversation: SunRPCAuth.Conversation ← NIL,\n");
	f←print(fout, "  data: REF ANY ← NIL\n");
	f←print(fout, "  ];\n\n");

	if (PCedar) {
	    f←print(fout,
		    "ImportByName%s: PROC[name: ROPE]\n\t\tRETURNS [h: %s];\n",
		    progName, progName);
	    if (PCedarUDP) {
		f←print(fout,
			"Import%s: PROC[b: %s.Address ← %s.nullAddress]\n\t\tRETURNS [h: %s];\n\n",
			progName, SunRPC, SunRPC, progName);
		f←print(fout,
			"Export%s: PROC[p: %s];\n\n", progName, progName);
	    }
	    else {		/* PCedarTCP */
		f←print(fout,
			"ImportStream%s: PROC[b: %s.Address ← %s.nullAddress]\n\t\tRETURNS [h: %s];\n\n",
			progName, SunRPC, SunRPC, progName);
		f←print(fout,
			"ExportStream%s: PROC[p: %s];\n\n", progName, progName);
	    }
	}
	else {
	    f←print(fout, "Make%sClient: PROC[h: %s.Handle,\n",
		    progName, SunRPC);
	    f←print(fout, "\tc: SunRPCAuth.Conversation] RETURNS [%s];\n",
		    progName);
	    f←print(fout, "Make%sServer: PROC[\n", progName);
	    f←print(fout, "  data: REF,\n");
	    for (proc = vers->procs; proc != NULL; proc = proc->next) {
		f←print(fout, "  %s: %sProc",
			locase(proc->proc←name), locase(proc->proc←name));
		if (proc->next != NULL) f←print(fout, ",\n");
		else f←print(fout, "\n");
	    }
	    f←print(fout, "  ] RETURNS [%s.Server];\n\n", SunRPC);
	}
    }
}

static
penumdef(def)
	definition *def;
{
	char *name = def->def←name;
	enumval←list *l = def->def.en.vals;
	int contigFlag;
	StringHashElement elem;
	int inserted;
	list *enumElementNames = NULL;
	list *enumElement;
	
	contigFlag = FillEnumAssignments(def->def.en.vals);

	elem = StringHashFind(EnumTypes, name, insert, &inserted);

	f←print(fout, "\n%s: TYPE = MACHINE DEPENDENT {\n", name);
	for (l = def->def.en.vals; l != NULL; l = l->next) {
	    f←print(fout, "\t%s(%s)", l->name, l->assignment);
	    if (l->next != NULL) f←print(fout, ",\n");
	    else f←print(fout, "\n");
	    enumElement = (list *) malloc(sizeof(list));
	    enumElement->val = strdup(l->name);
	    enumElement->next = enumElementNames;
	    enumElementNames = enumElement;
	    elem->userData = (char *) enumElementNames;
	}
	f←print(fout, "\t};\n");
	
	if (!contigFlag) return;

	f←print(fout, "\n%sNames: READONLY ARRAY %s OF ROPE;\n",
	    name, name);
}

static
list *ptypedef(def)
	definition *def;
{
	char *name = def->def←name;
	char *old = def->def.ty.old←type;
	relation rel = def->def.ty.rel;
	char buf[256];
	list *sequenceDefns = NULL;
	list *seqDefn;
	int opaqueFlag = FALSE;
	StringHashElement elem;
	int inserted;

	f←print(fout, "\n");
	if (!streq(name, old)) {
		if (streq(old, "string")) {
			old = "ROPE";
			rel = REL←ALIAS;
		} else if (streq(old, "opaque")) {
			old = "BYTE";
			opaqueFlag = TRUE;
		} else if (streq(old, "bool")) {
			old = "BOOLEAN";
		}
		else {
		        old = MapToCedarType(old, TRUE);
		}
		switch (rel) {
		  case REL←ARRAY:
		    if (opaqueFlag) {
			f←print(fout, "%s: TYPE = REF TEXT;\n", name);
		    }
		    else {
			elem = StringHashFind(SeqTypes,
					      def->def.ty.old←type,
					      insert, &inserted);
			if (inserted) {
			    sprintf(buf, "SeqType%d", SeqTypeId);
			    SeqTypeId++;
			    elem->userData = strdup(buf);
			}
			else {
			    sprintf(buf, "%s", elem->userData);
			}
			f←print(fout, "%s: TYPE = %s;\n", name, buf);
			seqDefn = (list *) malloc(sizeof(list));
			seqDefn->val = CreateSeqType(buf, old);
			seqDefn->next = sequenceDefns;
			sequenceDefns = seqDefn;
		    }
		    break;
		  case REL←POINTER:
		    f←print(fout, "%s: TYPE = REF %s;\n", name, old);
		    break;
		  case REL←VECTOR:
		    f←print(fout, "%s: TYPE = PACKED ARRAY [0..%s) OF %s;\n",
			    name,
			    ArrayMax(def->def.ty.array←max, FALSE),
			    old);
		    break;
		  case REL←ALIAS:
		    f←print(fout, "%s: TYPE = %s;\n", name, old);
		    break;
		}
	}

	return (sequenceDefns);
}

list *pdeclaration(name, dec, blank, defaultFlag)
     char *name;
     declaration *dec;
     int blank;
     int defaultFlag;
{
    char *type;
    int n;
    char buf[256];
    list *sequenceDefns = NULL;
    list *seqDefn;
    StringHashElement elem;
    int inserted;
    char buf1[256];
    
    if (streq(dec->type, "void")) {
	return (NULL);
    }
    while (blank--) {
	(void) fputc(' ', fout);
    }
    if (streq(dec->type, "string")) {
	f←print(fout, "%s: ROPE", dec->name);
    } else {
	if (streq(dec->type, "opaque")) {
	    type = "char";
	} else {
	    type = dec->type;
	}
	type = MapToCedarType(type, defaultFlag);
	switch (dec->rel) {
	  case REL←ALIAS:
	    f←print(fout, "%s: %s",
		    dec->name, type);
	    break;
	  case REL←VECTOR:
	    f←print(fout, "%s: PACKED ARRAY [0..%s) OF %s",
		    dec->name, ArrayMax(dec->array←max, FALSE),
		    type);
	    break;
	  case REL←POINTER:
	    f←print(fout, "%s: REF %s",
		    dec->name, type);
	    break;
	  case REL←ARRAY:
	    if (streq(dec->type, "opaque")) {
		f←print(fout, "%s: REF TEXT", dec->name);
	    }
	    else {
		sprintf(buf, "%s.%s", name, dec->name);
		elem = StringHashFind(SeqTypes, buf,
				      insert, &inserted);
		if (inserted) {
		    sprintf(buf, "SeqType%d", SeqTypeId);
		    SeqTypeId++;
		    elem->userData = strdup(buf);
		}
		else {
		    sprintf(buf, "%s", elem->userData);
		}
		if (defaultFlag || index(buf, '.') != NULL)
		    strcpy(buf1, buf);
		else
		    sprintf(buf1, "%s.%s", svcName, buf);
		f←print(fout, "%s: %s", dec->name, buf1);
		seqDefn = (list *) malloc(sizeof(list));
		seqDefn->val = CreateSeqType(buf, type);
		seqDefn->next = sequenceDefns;
		sequenceDefns = seqDefn;
	    }
	    break;
	}
    }
    
    return (sequenceDefns);
}

static
char *CreateSeqType(name, type)
     char *name;
     char *type;
{
    char buf[512], buf1[256];

    sprintf(buf, "%s: TYPE = REF %sObject;\n", name, name);
    sprintf(buf1,
	    "%sObject: TYPE = RECORD [SEQUENCE size: [0..LAST[INT32]) OF %s];\n",
	    name, type);
    strcat(buf, buf1);
    return (strdup(buf));
}