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

/*
 * rpc←svcout.c, Server-skeleton 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"

static char RQSTP[] = "rqstp";
static char TRANSP[] = "transp";
static char ARG[] = "argument";
static char RESULT[] = "result";
static char ROUTINE[] = "local";

char ←errbuf[256];	/* For all messages */


/*
 * Write the objects and procedures for a particular version of a particular
 * program.
 */
void
write←server←prog(svcName, progName, vers)
     char *svcName;
     char *progName;
     version←list *vers;
{
    char pvName[256];
    proc←list *proc;
    char *firstFlag = "|";
    char *srcMethod;
    char *inParm, *outParm;
    definition *defStruct;
    decl←list *dl;
    int expandFlag;
    extern definition *FindStructDefn();
    char *h, *c, *o, *out;
    char buf[128];
    char *mName;
    char *sp;

    CurrentProgNameFlag++;

    sprintf(pvName, "%s%s", progName, vers->vers←num);

    if (PCedar) {
	if (PCedarUDP) {
	    f←print(fout, "Export%s: PUBLIC PROC[p: %s.%s] = {\n",
		    pvName, svcName, pvName);
	    f←print(fout, "  o: %s.%s ← NEW[%s.%sObject];\n",
		    svcName, pvName, svcName, pvName);
	    f←print(fout, "  %sServer: %s.Server ← %s.CreateServer[\n",
		    pvName, SunRPC, SunRPC);
	    f←print(fout, "\t\t%s.%s, %s, %sHandler, \n",
		    svcName, progName, vers->vers←num, pvName);
	    f←print(fout, "\t\t%s.nullPort, 3, o];\n", SunRPC);
	    f←print(fout, "  [] ← SunPMapLocal.UnsetLocal[%s.%s, %s];\n",
		    svcName, progName, vers->vers←num);
	    f←print(fout,
		    "  [] ← SunPMapLocal.SetLocal[%s.%s, %s, SunPMap.ipProtocolUDP,\n",
		    svcName, progName, vers->vers←num);
	    f←print(fout, "\t\tBasics.Card16FromH[%s.GetServerPort[%sServer]]];\n",
		    SunRPC, pvName);
	    for (proc = vers->procs; proc != NULL; proc = proc->next) {
		f←print(fout, "	 o.%s ← p.%s;\n",
			locase(proc->proc←name), locase(proc->proc←name));
	    }
	    f←print(fout, "  };\n\n");
	}
	else {			/* PCedarTCP */
	    f←print(fout, "ExportStream%s: PUBLIC PROC[p: %s.%s] = {\n",
		    pvName, svcName, pvName);
	    f←print(fout, "  o: %s.%s ← NEW[%s.%sObject];\n",
		    svcName, pvName, svcName, pvName);
	    f←print(fout, "  %sServer: %s.Server ← %s.CreateServer[\n",
		    pvName, SunRPC, SunRPC);
	    f←print(fout, "\t\t%s.%s, %s, %sHandler, \n",
		    svcName, progName, vers->vers←num, pvName);
	    f←print(fout, "\t\t$ARPA, NIL, o];\n");
	    f←print(fout, "  local: ROPE;\n");
	    f←print(fout, "  port: CARD32;\n");
	    f←print(fout, "  [] ← SunPMapLocal.UnsetLocal[%s.%s, %s];\n",
		    svcName, progName, vers->vers←num);
	    f←print(fout, "  [,local] ← %s.GetServerInfo[%sServer];\n",
		    SunRPC, pvName);
	    f←print(fout, "  port ← Convert.CardFromRope[Rope.Substr[local, Rope.FindBackward[local, \":\"]+1]];\n");
	    f←print(fout,
		    "  [] ← SunPMapLocal.SetLocal[%s.%s, %s, SunPMap.ipProtocolTCP, port];\n",
		    svcName, progName, vers->vers←num);
	    for (proc = vers->procs; proc != NULL; proc = proc->next) {
		f←print(fout, "	 o.%s ← p.%s;\n",
			locase(proc->proc←name), locase(proc->proc←name));
	    }
	    f←print(fout, "  };\n\n");
	}
    }
    else {
	if (BadProgNameFlag[CurrentProgNameFlag]) {
	    f←print(fout, "Make%s%sServer: PUBLIC PROC[\n", svcName, pvName);
	}
	else {
	    f←print(fout, "Make%sServer: PUBLIC PROC[\n", pvName);
	}
	f←print(fout, "  data: REF,\n");
	for (proc = vers->procs; proc != NULL; proc = proc->next) {
	    f←print(fout, "  %s: %s.%sProc",
		    locase(proc->proc←name), svcName, 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);
	if (BadProgNameFlag[CurrentProgNameFlag]) {
	    f←print(fout, "  pseudoClient: %s.%s%s ~\n",
		    svcName, svcName, pvName);
	    f←print(fout, "\tNEW[%s.%s%sObject ← [\n",
		    svcName, svcName, pvName);
        }
        else {
	    f←print(fout, "  pseudoClient: %s.%s ~\n",
		    svcName, pvName);
	    f←print(fout, "\tNEW[%s.%sObject ← [\n",
		    svcName, pvName);
	}
	f←print(fout, "\t\trpcHandle ~ NIL, rpcConversation ~ NIL, data ~ data,\n");
	for (proc = vers->procs; proc != NULL; proc = proc->next) {
	    f←print(fout, "\t\t%s ~ %s",
		    locase(proc->proc←name), locase(proc->proc←name));
	    if (proc->next != NULL) f←print(fout, ",\n");
	    else f←print(fout, "\n");
	}
	f←print(fout, "\t]];\n\n");
	f←print(fout, "unbound: %s.Server ~ NEW[SunRPC.ServerObject ← [\n",
		SunRPC);
	if (BadProgNameFlag[CurrentProgNameFlag]) {
	    f←print(fout, "\tpgm ~ %s.%sPrognum,\n", svcName, svcName);
	}
	else {
	    f←print(fout, "\tpgm ~ %s.%s,\n", svcName, progName);
	}
	f←print(fout, "\tversion ~ %s.%s,\n", svcName, vers->vers←name);
	f←print(fout, "\tclientData ~ pseudoClient,\n");
	if (BadProgNameFlag[CurrentProgNameFlag]) {
	    f←print(fout, "\tserverProc ~ %s%sHandler\n", svcName, pvName);
	}
	else {
	    f←print(fout, "\tserverProc ~ %sHandler\n", pvName);
	}
	f←print(fout, "\t]];\n\n");
	f←print(fout, "RETURN [unbound];\n");
	f←print(fout, "  };\n\n");
    }

    if (BadProgNameFlag[CurrentProgNameFlag]) {
        f←print(fout,
	    "%s%sHandler: %s.ServerProc -- [h: Handle, c: Conversation, proc: CARD, clientData: REFANY\n",
	    svcName, pvName, SunRPC);
    }
    else {
        f←print(fout,
	    "%sHandler: %s.ServerProc -- [h: Handle, c: Conversation, proc: CARD, clientData: REFANY\n",
	    pvName, SunRPC);
    }
    if (PCedarTCP) {
	f←print(fout, "\t\t-- RETURNS [doReply: BOOLEAN] -- = {\n");
    }
    else {			/* PCedarUDP or Cedar10 */
	f←print(fout, "\t\t-- RETURNS [doReply: BOOLEAN, replyTimeToLive: CARDINAL] -- = {\n");
    }
    if (BadProgNameFlag[CurrentProgNameFlag]) {
        f←print(fout, "  o: %s.%s%s ← NARROW[clientData];\n",
	        svcName, svcName, pvName);
    }
    else {
        f←print(fout, "  o: %s.%s ← NARROW[clientData];\n",
	        svcName, pvName);
    }
    f←print(fout, "  doReply ← TRUE;\n");
    if (!PCedarTCP)		/* PCedarUDP or Cedar10 */
	f←print(fout, "  replyTimeToLive ← defaultReplyTTL;\n");
    f←print(fout, "  SELECT proc FROM\n");
    for (proc = vers->procs; proc != NULL; proc = proc->next) {
	f←print(fout, "    %s => %s%s[h, c, o];\n",
		proc->proc←num,	locase(proc->proc←name), vers->vers←num);
    }
    f←print(fout, "    ENDCASE => ERROR %s.Error[$wrongProc];\n", SunRPC);
    f←print(fout, "  };\n\n");

    for (proc = vers->procs; proc != NULL; proc = proc->next) {
	expandFlag = FALSE;
	h = "h";
	c = "c";
	o = "o";
	out = "out";
	if (ExpandProcArgs) {
	    defStruct = FindStructDefn(proc->arg←type);
	    if (defStruct != NULL) {
		h = FindUniqueName("h", defStruct->def.st.decls);
		c = FindUniqueName("c", defStruct->def.st.decls);
		o = FindUniqueName("o", defStruct->def.st.decls);
		out = FindUniqueName("out", defStruct->def.st.decls);
	    }
	}
	if (BadProgNameFlag[CurrentProgNameFlag]) {
	    f←print(fout,
		    "%s%s: PROC[%s: Handle, %s: Conversation, %s: %s.%s%s] = {\n",
		    locase(proc->proc←name), vers->vers←num, h, c, o,
		    svcName, svcName, pvName);
	}
	else {
	    f←print(fout,
		    "%s%s: PROC[%s: Handle, %s: Conversation, %s: %s.%s] = {\n",
		    locase(proc->proc←name), vers->vers←num, h, c, o,
		    svcName, pvName);
	}
	if (ExpandProcArgs && defStruct != NULL &&
	    defStruct->def←kind == DEF←STRUCT) {
	    expandFlag = TRUE;
	    for (dl = defStruct->def.st.decls;
		 dl != NULL;
		 dl = dl->next) {
		pdeclaration(defStruct->def←name, &(dl->decl), 4, FALSE);
		f←print(fout, ";\n");
	    }
	}
	else if (!streq(proc->arg←type, "void")) {
	    f←print(fout, "    in: %s;\n",
		    MapToCedarType(proc->arg←type, FALSE));
	}
	if (!streq(proc->res←type, "void"))
	    f←print(fout, "    %s: %s;\n", out,
		    MapToCedarType(proc->res←type, FALSE));
	if (expandFlag) {
	    for (dl = defStruct->def.st.decls;
		 dl != NULL;
		 dl = dl->next) {
		emit←get←stat(&(dl->decl), "", "", FALSE, h,
			      defStruct->def←name);
	    }
	}
	else {
	    if (!streq(proc->arg←type, "void")) {
		srcMethod = rpcgenBaseType(proc->arg←type);
		if (srcMethod != NULL)
		    f←print(fout, "    in ← %s.Get%s[%s];\n",
			    SunRPC, srcMethod, h);
		else {
		    mName = ModuleName(proc->arg←type);
		    f←print(fout, "    in ← %sGetPut.Get%s[%s];\n",
			    mName, StripPrefix(mName, proc->arg←type), h);
		}
		inParm = ", in";
	    }
	    else
		inParm = "";
	}
	if (streq(proc->res←type, "void"))
	    outParm = "";
	else {
	    sprintf(buf, "%s ← ", out);
	    outParm = buf;
	}
	if (expandFlag) {
	    f←print(fout, "    %so.%s[%s,\n",
		    outParm, locase(proc->proc←name), o);
	    for (dl = defStruct->def.st.decls;
		 dl != NULL;
		 dl = dl->next) {
		f←print(fout, "\t\t\t%s", dl->decl.name);
		if (dl->next != NULL) f←print(fout, ",\n");
		else f←print(fout, "];\n");
	    }
	}
	else {
	    f←print(fout, "    %so.%s[%s%s];\n",
		    outParm, locase(proc->proc←name), o, inParm);
	}
	f←print(fout, "    %s.StartReply[%s];\n", SunRPC, h);
	if (!streq(proc->res←type, "void")) {
	    srcMethod = rpcgenBaseType(proc->res←type);
	    if (srcMethod != NULL)
		f←print(fout, "    %s.Put%s[%s, %s];\n",
			SunRPC, srcMethod, h, out);
	    else {
		mName = ModuleName(proc->res←type);
		if (streq(mName, svcName))
		    sp = proc->res←type;
		else
		    sp = StripPrefix(mName, proc->res←type);
		f←print(fout, "    %sGetPut.Put%s[%s, %s];\n",
			mName, sp, h, out);
	    }
	}
	f←print(fout, "};\n\n");
    }
    f←print(fout, "\n");
}