/* 
 * sim_init.c
 *
 * x-kernel v3.3
 *
 * Copyright (c) 1996,1993,1991,1990  Arizona Board of Regents
 */

#include <ctype.h>
#include <string.h>
#include "sc.h"

#include <sys/types.h>
#include "x_stdio.h"
#include "xkernel.h"
#include "eth.h"
#include "eth_i.h"
#include "ip.h"
#include "ip_i.h"
#include "sim_i.h"
#include "sim_init.h"

#include <stdio.h>

char *CurObjName=NULL;
struct {
  char *varName;
  char *repVarName;
  char *objName;
} ReplaceArray[200];
int ReplaceArrayN=0;
static void CONVERT(void);

#include "sim_init_vals.c"

/* char *xMalloc(unsigned len) */
/* { */
/*   return (char *) xMalloc(len); */
/* } */

static void
ip2eth (IPhost *iph, ETHhost *ethh)
{
  ethh->high = (iph->a << 8) | iph->b;
  ethh->mid  = (iph->c << 8) | iph->d;
  ethh->low  = 0;
}

static int
getTraceValue(char *name)
{
  int 	k;

  for (k=0; traceNameArray[k].name != NULL; k++)
    if (!strcmp(name, traceNameArray[k].name))
      return traceNameArray[k].val;

  return SIM_ERROR;
}

static void *
simGetOtherInitFuncAddr(char *name)
{
  int k;

  for (k=0; simOtherTab[k].name != NULL; k++)
    if (!strcmp(name, simOtherTab[k].name))
      return (void *)simOtherTab[k].initFunc;

  return NULL;
}

static void *
simGetOtherTraceVarAddr(char *name)
{
  int   k;

  for (k=0; simOtherTab[k].name != NULL; k++)
    if (!strcmp(name, simOtherTab[k].name))
      return (void *)simOtherTab[k].traceAddr;

  return NULL;
}

/* int  globalArgc=3; */
/* char **globalArgv, *staticArgv[]={"parse", "-file", "sim.init"}; */

/* main (int argc, char *argv[]) */
/* { */
/*   int 		i, k; */
/*   SIM_PSTATE 	*ps; */
/*  */
/*   for (k=1; k<argc; k++) */
/*     if (!strncmp(argv[k], "-d", 2))  */
/*       sscanf(argv[k]+2, "%d", &debug); */
/*   ps = (SIM_PSTATE *)xMallocZero(sizeof(SIM_PSTATE)); */
/*   globalArgv = staticArgv; */
/*   sim_createNetwork (ps); */
/* } */

#define MAX_OBJ_ARGV 30
static Protl    objArgv[MAX_OBJ_ARGV];
Protl 		protl_tab[MAX_PROTOCOLS];

extern char *dtTraceDir; /* defined in datatrace.c */

void
sim_build_pgraph ()
{
  int k;

#ifdef XMEMTRACK
  TrackId = TrackGetId("sim_init");
#endif
  for (k=1; k<globalArgc; k++)
    if (!strncmp(globalArgv[k], "-traceDir=", 10)) {
      dtTraceDir = globalArgv[k]+10;
    }

  /* --- build protocol SIM */
  if (xsimAddHost("sim") != 0)
    error1("ERROR: `sim' is not first host!\n", NULL);
  xsimSetCurHost(0);
  protl_tab[0] = xCreateProtl(sim_init, "sim", "",
                              (int *)simGetProtlTraceVarAddr("sim"),
                              0, objArgv);
  if ( protl_tab[0] == ERR_PROTL ) {
      Kabort("Could not create sim protocol");
  }
  createNetwork(SimPstate);
}
   

static void
createNetwork (SIM_PSTATE *ps)
{
  char		*cp;
  int		i, k;
  OBJ		*op, dummyObj;
  NET		*net;
  CONNECT	*con;
  static char 	*fname="xsim.data";

  dummyObj.name = "";
  objNames = ScCreate(0, 64);
  varNames = ScCreate(0, 64);
  simNode.name = "sim";
  simNode.instance = "";
  simNode.host = &dummyObj;
  simNode.index = 0;
  simNode.level = 0;
  simNode.flags = FLG_DONE;
  simNode.numParents = simNode.numChildren = 0;
  simNode.parents[0] = simNode.children[0] = NULL;

  for (k=1; k<globalArgc; k++) {
    if (!strcmp(globalArgv[k], "-simfile")) {
      fname = globalArgv[++k];
    }
    else if (!strncmp(globalArgv[k], "-pdbg", 5))
      sscanf(globalArgv[k]+5, "%d", &debug);
    else if (k <= 15) {
      sprintf(Str, "%d", k);
      cp = xerox(Str);
      ScInsert(varNames, cp, (void *)globalArgv[k]);
    }
  }

  if ((fin=fopen(fname, "r")) == NULL) {
    printf("\nERRROR: Could not open initialization file: `%s'\n", fname);
    exit(1);
  }
  parse();
  doLevels();
  fixNames();
  create(ps);

  /* Create addr to key maps! */
  SimPstate->ethAddr2Key = mapCreate(3*SimPstate->numHosts, sizeof(ETHhost));
  for (k=0; k<SimPstate->numHosts; k++) {
    if (mapBind(SimPstate->ethAddr2Key, (char *)&(SimPstate->keyMap[k].ethAddr),
		&(SimPstate->keyMap[k])) == -1)
      Kabort("Could not bind ethAddr to key in sim_init.c!\n");
  }
  SimPstate->ipAddr2Key = mapCreate(3*SimPstate->numHosts, sizeof(IPhost));
  for (k=0; k<SimPstate->numHosts; k++) {
    if (mapBind(SimPstate->ipAddr2Key, (char *)&(SimPstate->keyMap[k].ipAddr),
                &(SimPstate->keyMap[k])) == -1)
      Kabort("Could not bind ipAddr to key in sim_init.c!\n");
  }
  my_build_pgraph();

  if (debug == 0)
    return;

  ScForEach(objNames, cp, op) {
    if (op->type == HOST_TYPE) {
      for (i=0; i<op->topProtocolCnt; i++) {
        printf("\n%s `%s'  top level protocols: `%s'\n", objTypes[op->type],
               cp, op->topProtocol[i]->name);
          showProt(op->topProtocol[i]);
      }
    }
    else
      printf("\n%s %s `%s'\n", objTypes[op->type], op->routerType, cp);

    printf("  args: ");
    for (k=0; k<op->argc; k++)
      printf("%s ", op->argv[k]);
    printf("\n\n");
  } ScNext();

  net = netList;
  while (net != NULL) {
    printf("\nNET type: %s, addr: %s, connections:\n", net->type, 
	   net->netAddr);
    con = net->connections;
    while (con != NULL) {
      if (con->obj->type == HOST_TYPE)
	printf("    host %s, prot %s, addr %s\n", con->obj->name,
	       con->prot->name, con->hostAddr);
      else
	printf("    router %s, addr %s\n", con->obj->name, con->hostAddr);
      con = con->next;
    }
    if (net->argc > 0) {
      printf("  args: ");
      for (k=0; k<net->argc; k++)
	printf("%s ", net->argv[k]);
      printf("\n");
    }
    net = net->next;
  }

  /* --- Free resources: Obj, Pnodes and Scs */
}

static void
my_build_pgraph()
{
  int	i;

  /* --- Quick and dirty way. At some stage the PNODES should be connected
         though an array of levels, then do that way! 
   */
  for (i=1; i<=maxLevel; i++) {
    createProt(&simNode, i);
  }
}

static char *protArgv[2*MAX_ARGS];

void
createProt(PNODE *pn, int level)
{
  int   i, j, k, argc;
  void  (*addr)();

  if (pn->level == level) {
    if ((pn->flags & FLG_DONE))
      return;
    if (debug == 1) 
      printf("\n/* building protocol   %s/%s   */\n", pn->name, pn->instance); 
    if (pn->numChildren > MAX_OBJ_ARGV)
      Kabort("ERROR: Need to increase MAX_OBJ_ARGV!\n");
    for (i=pn->numChildren-1; i>=0; i--) {
      if (debug == 1)
	printf("objArgv[%d] = protl_tab[%d] (%s/%s)\n", i, pn->children[i]->index,
	       pn->children[i]->name, pn->children[i]->instance);
      objArgv[i] = protl_tab[pn->children[i]->index];
    }
    if (debug == 1)
      printf("protl_tab[%d] = xCreateProtl(%s_init, \"%s\", \"%s\", %d, %s)\n",
	     nextIndex, pn->name, pn->name, pn->instance, pn->numChildren, 
	     "argv");
    
    addr = (void (*)()) simGetProtlInitFuncAddr(pn->name);
    if (addr == NULL)
      error2("\nERROR: Unknown protocol: `%s' at line:%d\n", pn->name, 
	     (char *)((int)pn->fileLine));
    argc = pn->host->argc + pn->argc;
    if (argc > 2*MAX_ARGS)
      Kabort("ERROR: Need to increase MAX_ARGS!\n");
    for (k=0; k<pn->host->argc; k++)
      protArgv[k] = pn->host->argv[k];
    for (j=0; j<pn->argc; k++,j++)
      protArgv[k] = pn->argv[j];
    xsimArgc = argc;
    xsimArgv = protArgv;
    xsimSetCurHost(pn->host->id);
    if (nextIndex > MAX_PROTOCOLS)
      Kabort("ERROR: Need to incrase MAX_PROTOCOLS!\n");
    protl_tab[nextIndex] = xCreateProtl(addr, pn->name, pn->instance, 
	                               (int *)simGetProtlTraceVarAddr(pn->name),
				       pn->numChildren, objArgv);
    if (protl_tab[nextIndex] == NULL)
      error1("\nERROR: Could not create %s protocol\n", pn->name);
    pn->index = nextIndex++;
    pn->flags |= FLG_DONE;
  }
  else if (pn->level < level) {
    for (i=0; i<pn->numParents; i++) {
      createProt(pn->parents[i], level);
    }
  }
}

static void
showProt(PNODE *pn)
{
  int   k;

  printf("(%2d) %s -> ", pn->index, pn->name);
  for (k=0; k<pn->numChildren; k++) 
    printf("%s ", pn->children[k]->name);
  printf("\n");
  for (k=0; k<pn->numChildren; k++) 
    showProt(pn->children[k]);
}

static void 
doLevels()
{
  char 	*cp;
  int	i, k;
  OBJ	*op;

  ScForEach(objNames, cp, op) {
    if (op->type == HOST_TYPE) {
      for (k=0; k<op->topProtocolCnt; k++) {
        i = getLevel(op->topProtocol[k]);
        if (i > maxLevel)
	  maxLevel = i;
      }
    }
  } ScNext();
}

static int
getLevel(PNODE *pn)
{
  int 	i, k, max=0;
  PNODE	*np;

  if (pn->level >= 0)
    return pn->level;
  for (k=0; k<pn->numChildren; k++) {
    np = pn->children[k];
    if (np->level >= 0)
      i = np->level + 1;
    else
      i = getLevel(pn->children[k]) + 1;
    if (i > max)
      max = i;
  }
  pn->level = max;
  return max;
}
  
static void 
fixNames()
{
  char 	*cp, *hostName, *protName, str[100];
  int	i, k;
  OBJ	*op;
  PNODE *np;

  ScForEach(objNames, hostName, op) {
    if (op->type == HOST_TYPE) {
      ScForEach(op->protNames, protName, np) {
	strcpy(str, hostName);
	for (cp=np->name; *cp; cp++) 
	  if (*cp == '/') {
	    *cp = '\0';
	    strcat(str, "_");
	    strcat(str, cp+1);
	    break;
	  }
	np->instance = xerox(str);
      } ScNext();
      for (k=0; k<op->topProtocolCnt; k++) {
        i = getLevel(op->topProtocol[k]);
        if (i > maxLevel)
	  maxLevel = i;
      }
    }
  } ScNext();
}

static void 
parse()     
{           
  if (debug)
    printf("\n>parse\n"); 
  get();
  S();      
}           
   
/*          
 * S -> ( HOST | ROUTER | NETWORK | TRACE | SET | CONVERT) S | EPSILON
 */     
static void
S()              
{     
  if (debug)
    printf("\n>S\n");
  skip_blanks();
  while (!done) {
    if (cur == 'h') {
      HOST();
    } else if (cur == 'r') {
      ROUTER();
    } else if (cur == 'n') {
      NETWORK();
    } else if (cur == 't') {
      TRACE();
    } else if (cur == 's') {
      SET();
    } else if (cur == 'c') {
      CONVERT();
    } else {
      syntaxErrorString("'host' or 'router' or 'net'");
    }
    skip_blanks();
  }
}

/*
 * HOST -> "host" <host-name> ; PROTOCOLS [ARGS]
 */
static void
HOST()
{
  OBJ	*op;

  if (debug)
    printf("\n>HOST\n");
  force_string("host");
  op = (OBJ *)xMallocZero(sizeof(OBJ));
  op->next = hostList;
  hostList = op;
  hostCnt++;
  op->type = HOST_TYPE;
  skip_blanks_force();
  CurObjName = op->name = xerox(OBJNAME());
  op->id = xsimAddHost(op->name);
  op->argc = 0;
  op->topProtocolCnt = 0;
  op->protNames = ScCreate(0, 16);
  if (ScLookup(objNames, op->name) != NULL) {
    error1("Host `%s' has already been defined!\n", op->name);
  }
  ScInsert(objNames, op->name, (void *)op);
  skip_blanks();
  force_char(';');
  PROTOCOLS(op);
  skip_blanks();
  while (cur == 'a'  ||  cur == 'p') {
    if (cur == 'a')
      ARGS(op->argv, &op->argc);
    else if (cur == 'p')
      PROT_ARG(op);
    skip_blanks();
  }
  CurObjName = NULL;
}

/*
 * PROTOCOLS -> "protocols" "=" PROTOCOL_LIST
 */
static void 
PROTOCOLS(OBJ *op)
{
  if (debug)
    printf("\n>PROTOCOLS\n");
  skip_blanks();
  force_string("protocols");
  skip_blanks();
  force_char('=');
  PROTOCOL_LIST(op);
}

/*
 * PROTOCOL_LIST -> <prot-name> NAMES PROTOCOL_LIST | ;
 */
static void
PROTOCOL_LIST(OBJ *op)
{
  char  *cp;
  int   fp, fl;
  PNODE *np;
  void  ScPrint(Sc);

  if (debug)
    printf("\n>PROTOCOL_LIST\n");
  skip_blanks();
  fp = filePosition;
  fl = fileLine;
  cp = PROTOCOL();

  np = (PNODE *)xMallocZero(sizeof(PNODE));
  if (op->topProtocolCnt > MAX_TOP_PROTOCOLS)
    Kabort("ERROR: Need to increase MAX_TOP_PROTOCOLS!\n");
  op->topProtocol[op->topProtocolCnt++] = np;
  np->host = op;
  np->filePos = fp;
  np->fileLine = fl;
  np->numChildren = np->numParents = 0;
  np->index = -1;
  np->level = -1;
  np->flags = 0;
  np->name = xerox(cp);
  np->instance = nullName;
  ScInsert(op->protNames, np->name, (void *)np);
  NAMES(op, np);
  skip_blanks();

  while (cur != ';'  &&  !done) {
    if (debug)
      printf("\n>PROTOCOL_LIST\n");
    cp = PROTOCOL();
    if (strstr(cp, "tcp"))
      TcpCntMax++;
    if ((np=(PNODE *)ScLookup(op->protNames, cp)) == NULL) {
/*    ScPrint(op->protNames);
      error1("sim_init: protocol `%s' has not been defined\n", cp);
*/
      np = (PNODE *)xMallocZero(sizeof(PNODE));
      if (op->topProtocolCnt > MAX_TOP_PROTOCOLS)
        Kabort("ERROR: Need to increase MAX_TOP_PROTOCOLS!\n");
      op->topProtocol[op->topProtocolCnt++] = np;
      np->host = op;
      np->filePos = fp;
      np->fileLine = fl;
      np->numChildren = np->numParents = 0;
      np->index = -1;
      np->level = -1;
      np->flags = 0;
      np->name = xerox(cp);
      np->instance = nullName;
      ScInsert(op->protNames, np->name, (void *)np);
    }
    NAMES(op, np);
    skip_blanks();
  }
  force_char(';');
}

/*
 * NAMES -> <lower-protocol-name> NAMES | ,
 */
static void
NAMES(OBJ *op, PNODE *pn)
{
  char  *cp;
  int	fp, fl;
  PNODE *np;

  if (debug)
    printf("\n>NAMES\n");
  skip_blanks();
  while (cur != ','  &&  cur != ';'  &&  !done) {
    fp = filePosition;
    fl = fileLine;
    cp = PROTOCOL();
    if (!strcmp(cp, "sim")) {
      np = &simNode;
      if (np->numParents > MAX_BRANCH_PARENTS)
        Kabort("ERROR: Need to increase MAX_BRANCH_PARENTS!\n");
      np->parents[np->numParents++] = pn;
    }
    else if ((np=(PNODE *)ScLookup(op->protNames, cp)) == NULL) {
      np = (PNODE *)xMalloc(sizeof(PNODE));
      np->name = xerox(cp);
      np->instance = nullName;
      np->host = pn->host;
      np->filePos = fp;
      np->fileLine = fl;
      np->index = -1;
      np->level = -1;
      np->flags = 0;
      np->numParents = 1;
      np->parents[0] = pn;
      np->numChildren = 0;
      ScInsert(op->protNames, np->name, (void *)np);
    }
    else {
      if (np->numParents > MAX_BRANCH_PARENTS)
        Kabort("ERROR: Need to increase MAX_BRANCH_PARENTS!\n");
      np->parents[np->numParents++] = pn;
    }
    if (np->numChildren > MAX_BRANCH_CHILDREN)
      Kabort("ERROR: Need to increase MAX_BRANCH_CHILDREN!\n");
    pn->children[pn->numChildren++] = np;
    skip_blanks();
  }
  if (cur != ';')
    force_char(',');
}

/*
 * PROT_ARG -> "pargs" <protocol-name> "=" ARGLIST
 */
static void
PROT_ARG(OBJ *op)
{
  char  *cp;
  PNODE *np;

  force_string("pargs");
  skip_blanks();
  cp = PROTOCOL();
  if ((np=(PNODE *)ScLookup(op->protNames, cp)) == NULL) {
    ScPrint(op->protNames);
    error1("sim_init: protocol `%s' has not been defined\n", cp);
  }
  skip_blanks();
  force_char('=');
  skip_blanks();
  while (cur != ';'  && !done) {
    if (np->argc > MAX_ARGS)
      Kabort("ERROR: Need to increase MAX_ARGS!\n");
    np->argv[(np->argc)++] = xerox(NONBLANK());
    skip_blanks();
    if (cur == ',') {
      force_char(',');
      skip_blanks();
    }
  }
  force_char(';');
  skip_blanks();
}

/*
 * ARGS -> "args" "=" ARGLIST
 */
static void
ARGS(char *argv[], int *argc)
{
  force_string("args");
  skip_blanks();
  force_char('=');
  skip_blanks();
  while (cur != ';'  && !done) {
    if (*argc > MAX_ARGS)
      Kabort("ERROR: Need to increase MAX_ARGS!\n");
    argv[(*argc)++] = xerox(NONBLANK());
    skip_blanks();
    if (cur == ',') {
      force_char(',');
      skip_blanks();
    }
  }
  force_char(';');
}

/*
 * ROUTER -> "router" <type> <name> ; 
 *           "rtable" = (<for-net> <use-host> ",")+ ; [ARGS]
 */
static void ROUTER()
{
  char *cp;
  OBJ  *op;

  if (debug)
    printf("\n>ROUTER\n");
  force_string("router");
  op = (OBJ *)xMallocZero(sizeof(OBJ));
  op->next = routerList;
  routerList = op;
  routerCnt++;
  op->rtableCnt = 0;
  op->type = ROUTER_TYPE;
  skip_blanks_force();
  op->routerType = xerox(OBJNAME());
  skip_blanks_force();
  CurObjName = op->name = xerox(OBJNAME());
  op->id = xsimAddHost(op->name);
  op->argc = 0;
  op->topProtocolCnt = 0;
  ScInsert(objNames, op->name, (void *)op);
  skip_blanks();
  force_char(';');
  skip_blanks();
  if (cur == 'r') {
    force_string("rtable");
    skip_blanks();
    force_char('=');
    skip_blanks();
    while (cur != ';') {
      cp = IP_ADDRESS();
      if (op->rtableCnt > MAX_ROUTE_TABLE)
        Kabort("ERROR: Need to increase MAX_ROUTE_TABLE!\n");
      str2ipHost(&op->forNet[op->rtableCnt], cp);
      skip_blanks();
      cp = IP_ADDRESS();
      str2ipHost(&op->useHost[op->rtableCnt++], cp);
      skip_blanks();
      if (cur != ';') {
	force_char(',');
	skip_blanks();
      }
    }
    force_char(';');
    skip_blanks();
  }
  if (cur == 'a')
    ARGS(op->argv, &op->argc);
  CurObjName = NULL;
}

/*
 * NETWORK -> "net" <type> net-ip-addr ; CONNECT_LIST [ARGS]
 */
static void NETWORK()
{
  int k;
  NET *net;

  if (debug)
    printf("\n>NETWORK\n");
  force_string("net");
  net = (NET *)xMallocZero(sizeof(NET));
  net->next = netList;
  netList = net;
  skip_blanks_force();
  net->type = xerox(OBJNAME());
  skip_blanks();
/*   if (cur != ';') */
    net->netAddr = xerox(IP_ADDRESS());
/*   else */
/*     net->netAddr = NULL; */
  net->argc = 0;
  net->connectCnt = 0;
  net->connections = NULL;
  skip_blanks();
  force_char(';');
  CONNECT_LIST(net);
  skip_blanks();
  if (cur == 'a')
    ARGS(net->argv, &net->argc);
  if (net->other != NULL) {
    net->other->argc = net->argc;
    for (k=0; k<net->argc; k++)
      net->other->argv[k] = net->argv[k];
  }
}

/*
 * CONNECT_LIST -> "connections" "=" ( (<host> <protocol above sim>) | router )
 *				    ip-host-addr , CONNECT_LIST | ;
 */
static void
CONNECT_LIST(NET *net)
{
  char    *cp;
  int     hostFlag = 0;
  OBJ     *op;
  PNODE   *np=NULL;
  CONNECT *con;
  IPhost  ipn;
  NET     *onet;

  skip_blanks();
  force_string("connections");
  skip_blanks();
  force_char('=');
  skip_blanks();
  str2ipHost(&ipn, net->netAddr);

  while (cur != ';') {
    np = NULL;
    if (net->connectCnt == 1  &&  !strcmp(net->type, "PP")) {
      if (net->other != NULL)
      error1("sim_init: A PP net (%s) cannot have more than 2 attachments\n",
             net->netAddr);
      onet = (NET *)xMallocZero(sizeof(NET));
      onet->next = netList;
      netList = onet;
      onet->type = xerox(net->type);
      onet->netAddr = xerox(net->netAddr);
      onet->argc = 0;
      onet->connectCnt = 0;
      onet->connections = NULL;
      net->other = onet;
      cp = OBJNAME();
      if ((op=(OBJ *)ScLookup(objNames, cp)) == NULL) {
        ScPrint(objNames);
        error1("sim_init: Object `%s' has not been defined\n", cp);
      }
      if (op->type == HOST_TYPE) {
        skip_blanks_force();
        hostFlag = 1;
        cp = PROTOCOL();
        if ((np=(PNODE *)ScLookup(op->protNames, cp)) == NULL) {
	  ScPrint(op->protNames);
	  error2("sim_init: Protocol `%s' hasn't been defined for host `%s'\n",
	         cp, op->name);
        }
      }
      con = (CONNECT *) xMallocZero(sizeof(CONNECT));
      con->next = onet->connections;
      onet->connections = con;
      onet->connectCnt++;
      if (hostFlag) {
        onet->type = net->type = xerox("EPP");
      }
    }
    else {
      cp = OBJNAME();
      if ((op=(OBJ *)ScLookup(objNames, cp)) == NULL) {
        ScPrint(objNames);
        error1("sim_init: Object `%s' has not been defined\n", cp);
      }
      if (op->type == HOST_TYPE) {
        skip_blanks_force();
        hostFlag = 1;
        cp = PROTOCOL();
        if ((np=(PNODE *)ScLookup(op->protNames, cp)) == NULL) {
          ScPrint(op->protNames);
          error2("sim_init: Protocol `%s' hasn't been defined for host `%s'\n",
                 cp, op->name);
        }
      }
      con = (CONNECT *) xMallocZero(sizeof(CONNECT));
      con->next = net->connections;
      net->connections = con;
      net->connectCnt++;
    }
    con->obj = op;
    con->prot = np;
    skip_blanks();
/*  if (cur != ','  &&  cur != ';') { */
      con->hostAddr = xerox(IP_ADDRESS());
/*    str2ipHost(&iph, con->hostAddr);
      iph.a |= ipn.a, iph.b |= ipn.b, iph.c |= ipn.c, iph.d |= ipn.d;
*/
      skip_blanks();
/*     } */
    if (cur != ';') {
      force_char(',');
      skip_blanks();
    }
  }
  force_char(';');
}

/*
 * TRACE -> "trace" <protocol-name> = <trace-level>;
 */
static void
TRACE()
{
  char *cp, str[100];
  int *ip, i;

  if (debug)
    printf("\nTRACE\n");
  force_string("trace");
  skip_blanks_force();
  cp = OBJNAME();
  strcpy(str, cp);
  skip_blanks();
  force_char('=');
  skip_blanks();
  cp = OBJNAME();
  skip_blanks();
  force_char(';');
  ip = (int *)simGetProtlTraceVarAddr(str);
  if (ip == (int *)NULL) {
    if ((ip = (int *)simGetOtherTraceVarAddr(str)) == NULL)
      error1("ERROR: Could not find trace variable for protocol: `%s'\n", str);
  }
  i = getTraceValue(cp);
  if (i == (int)SIM_ERROR)
    error1("ERROR: Could not find value of `%s'\n", cp);
  *ip = i;
}
  
/*
 * SET -> "set" <var-name> = <value>;
 */
static void
SET()
{
  char *cp, *cp1, *cp2, str[400];
  int  i;

  if (debug)
    printf("\nSET\n");
  force_string("set");
  skip_blanks_force();
  cp1 = xerox(OBJNAME());
  skip_blanks();
  force_char('=');
  skip_blanks();
  for (i=0,cp=str; cur!=';'; get()) {
    *cp++ = (char) cur;
    if (++i >= 400)
      error1("ERROR: Value of variable `%s' is too long!\n", cp1);
  }
  *cp = '\0';
  cp2 = xerox(str);
  ScInsert(varNames, cp1, (void *)cp2);
  force_char(';');
}
 
/*
 * CONVERT -> "convert" <var-name> "in" <obj-name> "to" <var-name>;
 */
static void
CONVERT()
{
  char *cp3, *cp1, *cp2;

  if (debug)
    printf("\nCONVERT\n");
  force_string("convert");
  skip_blanks_force();
  cp1 = xerox(OBJNAME());
  skip_blanks_force();
  force_string("in");
  skip_blanks_force();
  cp2 = xerox(OBJNAME());
  skip_blanks_force();
  force_string("to");
  skip_blanks_force();
  cp3 = xerox(OBJNAME());
  ReplaceArray[ReplaceArrayN].varName = cp1;
  ReplaceArray[ReplaceArrayN].objName = cp2;
  ReplaceArray[ReplaceArrayN++].repVarName = cp3;
  skip_blanks();
  force_char(';');
}
static char *
OBJNAME()
{
  int  len=0;
  static char buf[BUF_SIZE];

  if (debug)
    printf("\n>OBJNAME\n");
  while (islower(cur) || isupper(cur) || isdigit(cur) || (cur == '_')) {
    buf[len++] = cur;
    get();
  }
  buf[len] = '\0';
  if (debug)
    printf("<OBJNAME: %s>\n", buf);
  if (len == 0)
    error1("ERROR: Name should be non-empty!\n", NULL);
  return buf;
}
   
static char *
PROTOCOL()
{
  int  len=0, olen;
  static char buf[BUF_SIZE];

  if (debug)
    printf("\n>PROTOCOL\n");
  while (islower(cur) || isupper(cur) || isdigit(cur) || (cur == '_')) {
    buf[len++] = cur;
    get();
  }
  if (len == 0)
    error1("ERROR: Name should be non-empty!\n", NULL);
  if (cur == '/') {
    olen = len;
    buf[len++] = cur;
    get();
    while (islower(cur) || isupper(cur) || isdigit(cur) || (cur == '_')) {
      buf[len++] = cur;
      get();
    }
    if (olen == len)
      error1("ERROR: Instance name should be non-empty!\n", NULL);
  }
  buf[len] = '\0';
  if (debug)
    printf("<PROTOCOL: %s>\n", buf);
  return buf;
}
   
static char *
NONBLANK()
{
  int  len=0;
  static char buf[BUF_SIZE];

  if (debug)
    printf("\n>NONBLANK\n");
  while (cur != ' '  &&  cur != '\t'  &&  cur != '\n'  &&  cur != ';'  &&
	 cur != ',') {
    buf[len++] = cur;
    get();
  }
  buf[len] = '\0';
  return buf;
}
   
static char *
IP_ADDRESS()
{
  int  k, len=0;
  static char buf[BUF_SIZE];

  if (debug)
    printf("\n>IP_ADDRESS\n");
  for (k=0; k<3; k++) {
    while (isdigit(cur)) {
      buf[len++] = cur;
      get();
    }
    force_char('.');
    buf[len++] = '.';
  }
  while (isdigit(cur)) {
    buf[len++] = cur;
    get();
  }
  buf[len] = '\0';  
  if (debug)
    printf("<IP_ADDRESS: %s>\n", buf);
  return buf;
}
   
static void
force_char(char ch)
{
  if (cur == ch) {
    get();
  } else { 
    syntaxErrorChar(ch, cur);
  }
}   
        
static void 
force_string(char *str)
{
  char *temp;
  
  temp = str;
  while (cur == *temp) {
    get();
    temp++;
  } 
  if (*temp != 0) {
    syntaxErrorString(str);
  }
}
    
static void
skip_blanks()
{ 
    while ( (cur == ' ') || (cur == '\t') || (cur == '\n') ) {
        get();
    } 
} 
    
static void
skip_blanks_force()
{   
    if ( (cur == ' ') || (cur == '\t') || (cur == '\n') ) {
        skip_blanks();
    } else {
        syntaxErrorString("white space");
    }
}   
    
#define NEXT_CHAR() (usebuf ? cur=*bufp++, usebuf=*bufp, cur : getc(fin))
static void
get()
{
  char 		str[400], *cp=str;
  int  		k, temp, repFlag = 0;
  static char 	buf[4097], *bufp=buf;
  static int	usebuf=0;

  if (done)
    return;
    
  cur = NEXT_CHAR();
  if ( cur == '#' ) {
      while ( cur != '\n' && cur != EOF ) {
          cur = NEXT_CHAR();
      }
  } 
  else if (cur == '$') {
    cur = NEXT_CHAR();
    filePosition++;
    while (islower(cur) || isupper(cur) || isdigit(cur) || (cur == '_')) {
      *cp++ = cur;
      cur = NEXT_CHAR();
      filePosition++;
    }
    temp = cur;
    *cp = '\0';
    if (CurObjName != NULL) {
      for (k=0; k<ReplaceArrayN; k++)
        if (!strcmp(str, ReplaceArray[k].varName)  &&
            !strcmp(CurObjName, ReplaceArray[k].objName)) {
          if (debug)
            printf("Converting %s to %s in %s\n", ReplaceArray[k].varName,
                   ReplaceArray[k].repVarName, ReplaceArray[k].objName);
          strcpy(str, ReplaceArray[k].repVarName);
          repFlag = 1;
          break;
        }
    }
    if ((cp=(char *)ScLookup(varNames, str)) == NULL) {
      if (repFlag)
         error2("ERROR: Variable `%s' undefined! Replaced from `%s'\n",
                str, ReplaceArray[k].varName);
      else
        error1("ERROR: Variable `%s' undefined!\n", str);
    }
    if (usebuf) 
      error1("ERROR: Found a variable while reading from buffer!\n", NULL);
    else {
      usebuf = 1;
      strcpy(buf, cp);
      cp = buf + strlen(buf);
      *cp++ = temp;
      *cp++ = '\0';
      bufp = buf;
    }
    cur = NEXT_CHAR();
  }    

  if (!usebuf)
    filePosition++;
  if (debug)
    putchar(cur);
  if (cur == EOF) {
    done = 1;
    cur = 0;
  }
  if (cur == '\n'  &&  !usebuf) { 
    filePosition=0;
    fileLine++;
    cur = ' ';
    if (debug)
      putchar(cur);
  }
}   

static char *
join(char *str1, char *str2)
{
  char *temp;
  int len;

  len = strlen(str1) + strlen(str2) + 2;
  temp = (char *) xMalloc(len);
  strcpy(temp, str1);
  strcat(temp, str2);
  return (temp);
}

static char *
xerox(char *str)
{
  char *temp;
  int len;
    
  len = strlen(str) + 2;
  temp = (char *) xMalloc(len);
  strcpy(temp, str);
  return (temp);
} 

static void
syntaxErrorChar(char expected, char got)
{
  fprintf(stderr,
          "sim_init: syntax error: expecting \"%c\" got \"%c\" at line %d, pos %d\n",
          expected, got, fileLine, filePosition);
  Kabort("ABORT");
}
    
static void
syntaxErrorString(char *s) 
{
  fprintf(stderr,
          "sim_init: syntax error: expecting \"%s\" at line %d, pos %d\n",
          s, fileLine, filePosition);
  Kabort("ABORT");
}
  
static void
error1 (char *s, char *arg)
{
  fprintf(stderr, s, arg);
  if (!done)
    fprintf(stderr, "At line %d, pos %d\n", fileLine, filePosition);
  Kabort("ABORT");
}

static void
error2(char *s, char *arg1, char *arg2)
{
  fprintf(stderr, s, arg1, arg2);
  if (!done) 
    fprintf(stderr, "At line %d, pos %d\n", fileLine, filePosition);
  Kabort("ABORT");
}

/* ----- */

static void
addKey(SIM_PSTATE *ps, char *name, char *instance, IPhost *ipAddr, 
       int type, char *obj, int port, int net, int host)
{
  char 		str[100];
  static int	keyCount=0;
  
  strcpy(str, name);
  if (instance != NULL  &&  *instance != '\0') {
    strcat(str, "/");
    strcat(str, instance);
  }
  if (keyCount > MAX_KEYS)
    Kabort("ERROR: Need to increase MAX_KEYS!\n");
  ps->keyMap[keyCount].name = xerox(str);
  ps->keyMap[keyCount].ipAddr = *ipAddr;
  ip2eth(ipAddr, &ps->keyMap[keyCount].ethAddr);
  ps->keyMap[keyCount].objType = type;
  ps->keyMap[keyCount].obj = obj;
  ps->keyMap[keyCount].inPort = port;
  ps->keyMap[keyCount].net = net;
  ps->keyMap[keyCount].host = host;

  xsimAddHostMap(&(ps->keyMap[keyCount++]));
  ps->numHosts++;
}

static char *
getArg(int argc, char *argv[], char *str)
{
  int 	k;

  for (k=0; k<argc; k++)
    if (!strcmp(argv[k], str))
      return argv[k+1];

  return NULL;
}

static char *
getnArg(int argc, char *argv[], char *str, int n)
{
  int   k;

  for (k=0; k<argc; k++)
    if (!strncmp(argv[k], str, n))
      return argv[k]+n;
  return NULL;
}

static void
getIpMask (IPhost *mask, IPhost *addr)
{
  if (addr->a == 0) {
    mask->a = mask->b = mask->c = 0xff;
    mask->d = 0;
  }
  else if ( !(addr->a & 0x80) ) {
    mask->a = 0xff;
    mask->b = mask->c = mask->d = 0;
  }
  else if ( (addr->a &0xc0) == 0x80) {
    mask->a = mask->b = 0xff;
    mask->c = mask->d = 0;
  }
  else {
    mask->a = mask->b = mask->c = 0xff;
    mask->d = 0;
  }
}

#include "sim_init_create.c"

int getHostCnt()
{
  return hostCnt;
}

int getRouterCnt()
{
  return routerCnt;
}

void getHostArray(int max, char *prot, IPhost *ipa)
{
  int         k;
  OBJ *obj;
  PNODE       *np=NULL;

  for (obj=hostList,k=0; obj!=NULL && k<max; obj=obj->next,k++) {
    if ((np=(PNODE *)ScLookup(obj->protNames, prot)) != NULL)
      *ipa++ = obj->ipAddr;
  }
}
