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

/*
 * rpc←clntout.c, Client-stub outputter for the RPC protocol compiler
 * Copyright (C) 1987, Sun Microsytsems, Inc.
 */
#include <stdio.h>
#include <strings.h>
#include "rpc←parse.h"
#include "rpc←util.h"

void
write←stubs(svcName)
     char *svcName;
{
    list *l;
    definition *def;
    
    for (l = CurrentContext->defined; l != NULL; l = l->next) {
	def = (definition *) l->val;
	if (def->def←kind == DEF←PROGRAM) {
	    write←program(svcName, def);
	}
    }
}

static
EmitProcSignature(vp, proc, pvName, defStruct, o, res, recoverySuffix)
     version←list *vp;
     proc←list *proc;
     char *pvName;
     definition *defStruct;
     char *o, *res;
     char *recoverySuffix;
{
    decl←list *dl;

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

static
write←program(svcName, def)
     char *svcName;
     definition *def;
{
    version←list *vp;
    proc←list *proc;
    char pvName[256];
    int inArg, outArg;
    char *srcMethod;
    definition *defStruct;
    decl←list *dl;
    int expandFlag;
    extern definition *FindStructDefn();
    char *o, *res;
    char rpcHandle[256];
    char *recoverySuffix = "";
    char *mName;
    char *sp;

    CurrentProgNameFlag++;
    
    for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
	strcpy(pvName, def->def←name);
	strcat(pvName, vp->vers←num);
	
	if (PCedar) {
	    f←print(fout,
		    "\nImportByName%s: PUBLIC PROC[name: ROPE]\n",
		    pvName);
	    f←print(fout, "\t\tRETURNS [h: %s.%s] = {\n",
		    svcName, pvName);
	    f←print(fout, "  };\n\n");

	    if (PCedarUDP) {
		f←print(fout,
			"Import%s: PUBLIC PROC[b: %s.Address ← %s.nullAddress]\n",
			pvName, SunRPC, SunRPC);
	    }
	    else {		/* PCedarTCP */
		f←print(fout,
			"ImportStream%s: PUBLIC PROC[b: %s.Address ← %s.nullAddress]\n",
			pvName, SunRPC, SunRPC);
	    }

	    f←print(fout, "\t\tRETURNS [h: %s.%s] = {\n",
		    svcName, pvName);
	    f←print(fout, "  rh: %s.Handle;\n", SunRPC);
	    f←print(fout,
		    "  rhPM: SunRPC.Handle ← SunRPC.Create[b, Basics.HFromCard16[SunPMap.udpPort]];\n");
	    f←print(fout,
		    "  c: SunRPCAuth.Conversation ← SunRPCAuth.Initiate[];\n");
	    f←print(fout,
		    "  port: CARDINAL ← SunPMapClient.GetPort[rhPM, c,\n");
	    if (PCedarUDP) {
		f←print(fout,
			"\t\t%s.%s, %s, SunPMap.ipProtocolUDP];\n\n",
			svcName, def->def←name, vp->vers←num);
	    }
	    else {		/* PCedarTCP */
		f←print(fout,
			"\t\t%s.%s, %s, SunPMap.ipProtocolTCP];\n\n",
			svcName, def->def←name, vp->vers←num);
		f←print(fout,
			"remoteAddress: ROPE ← Rope.Cat[Convert.RopeFromArpaAddress[b], \":\", Convert.RopeFromCard[port]];\n");
	    }
	    f←print(fout, "  IF port = 0 THEN ERROR;\n");

	    if (PCedarUDP) {
		f←print(fout, "  rh ← %s.SetRemote[rhPM, b, Basics.HFromCard16[Basics.LowHalf[port]]];\n",
			SunRPC);
	    }
	    else {		/* PCedarTCP */
		f←print(fout,
			"  rh ← %s.Create[$ARPA, remoteAddress];\n",
			SunRPC, SunRPC);
	    }
	    f←print(fout, "  h ← NEW[%s.%sObject];\n",
		    svcName, pvName);
	    f←print(fout, "  h.rpcHandle ← rh;\n");
	    f←print(fout, "  h.rpcConversation ← c;\n");
	    for (proc = vp->procs; proc != NULL; proc = proc->next) {
		f←print(fout, "  h.%s ← %s%s;\n",
			locase(proc->proc←name),
			locase(proc->proc←name), vp->vers←num);
	    }
	    f←print(fout, "  };\n\n");
	}
	else {
	    if (BadProgNameFlag[CurrentProgNameFlag]) {
	        f←print(fout,
		    "Make%s%sClient: PUBLIC PROC [h: %s.Handle,\n",
		    svcName, pvName, SunRPC);
	        f←print(fout,
		    "\tc: SunRPCAuth.Conversation] RETURNS [%s.%s%s] ~ {\n",
		    svcName, svcName, pvName);
	        f←print(fout,
		    "  RETURN [NEW[%s.%s%sObject ← [\n",
		    svcName, svcName, pvName);
	    }
	    else {
	        f←print(fout,
		    "Make%sClient: PUBLIC PROC [h: %s.Handle,\n",
		    pvName, SunRPC);
    	        f←print(fout,
		    "\tc: SunRPCAuth.Conversation] RETURNS [%s.%s] ~ {\n",
		    svcName, pvName);
	        f←print(fout,
		    "  RETURN [NEW[%s.%sObject ← [\n",
		    svcName, pvName);
	    }
	    for (proc = vp->procs; proc != NULL; proc = proc->next) {
		f←print(fout, "\t%s%s",
			locase(proc->proc←name), vp->vers←num);
		f←print(fout, ",\n");
	    }
	    f←print(fout, "\th, c, NIL]]];\n");
	    f←print(fout, "  };\n\n");
	}
	
	for (proc = vp->procs; proc != NULL; proc = proc->next) {
	    expandFlag = FALSE;
	    o  = "o";
	    res = "res";
	    if (ExpandProcArgs) {
		defStruct = FindStructDefn(proc->arg←type);
		if (defStruct != NULL) {
		    o = FindUniqueName("o", defStruct->def.st.decls);
		    sprintf(rpcHandle, "%s.rpcHandle", o);
		    res = FindUniqueName("res", defStruct->def.st.decls);
		}
	    }
	    if (ExpandProcArgs && defStruct != NULL &&
		defStruct->def←kind == DEF←STRUCT) {
		inArg = TRUE;
		expandFlag = TRUE;
	    }
	    else {
		if (!streq(proc->arg←type, "void"))
		    inArg = TRUE;
		else
		    inArg = FALSE;
	    }
	    if (!streq(proc->res←type, "void")) {
		outArg = TRUE;
	    }
	    else {
		outArg = FALSE;
	    }

	    EmitProcSignature(vp, proc, pvName, defStruct, o, res, "");

	    f←print(fout, "    %s.StartCall[%s.rpcHandle, %s.rpcConversation,\n",
		    SunRPC, o, o);
	    if (BadProgNameFlag[CurrentProgNameFlag]) {
	        f←print(fout, "                   %s.%sPrognum, %s, %s];\n",
		    svcName, svcName, vp->vers←num,
		    proc->proc←num);
	    }
	    else {
	        f←print(fout, "                   %s.%s, %s, %s];\n",
		    svcName, def->def←name, vp->vers←num,
		    proc->proc←num);
	    }
	    if (inArg) {
		if (expandFlag) {
		    for (dl = defStruct->def.st.decls;
			 dl != NULL;
			 dl = dl->next) {
			emit←put←stat(&(dl->decl), "", "", FALSE, rpcHandle);
		    }
		}
		else {
		    srcMethod = rpcgenBaseType(proc->arg←type);
		    if (srcMethod != NULL)
			f←print(fout,
				"    %s.Put%s[%s.rpcHandle,in];\n",
				SunRPC, srcMethod, o);
		    else {
			mName = ModuleName(proc->arg←type);
			f←print(fout,
				"    %sGetPut.Put%s[%s.rpcHandle, in];\n",
				mName, StripPrefix(mName, proc->arg←type), o);
		    }
		}
	    }
	    if (PCedarTCP) {
		f←print(fout,
			"    [] ← %s.SendCallAndReceiveReply[%s.rpcHandle];\n",
			SunRPC, o);
	    }
	    else {		/* Either PCedarUDP or Cedar10 case. */
		f←print(fout,
			"    [] ← %s.SendCallAndReceiveReply[%s.rpcHandle, defaultTimeout, defaultRetries];\n",
			SunRPC, o);
	    }
	    if (outArg) {
		srcMethod = rpcgenBaseType(proc->res←type);
		if (srcMethod != NULL)
		    f←print(fout,
			    "    %s ← %s.Get%s[%s.rpcHandle];\n",
			    res, SunRPC, srcMethod, o);
		else {
		    mName = ModuleName(proc->res←type);
		    if (streq(mName, svcName))
		        sp = proc->res←type;
		    else
		        sp = StripPrefix(mName, proc->res←type);
		    f←print(fout,
			    "    %s ← %sGetPut.Get%s[%s.rpcHandle];\n",
			    res, mName, sp, o);
		}
	    }
	    f←print(fout, "    %s.ReleaseReply[%s.rpcHandle];\n", SunRPC, o);
	    f←print(fout, "  };\n");
	}
    }
}