Reorganized directory structure
authorRobert Brunner <rbrunner@uiuc.edu>
Mon, 5 Jun 1995 19:01:24 +0000 (19:01 +0000)
committerRobert Brunner <rbrunner@uiuc.edu>
Mon, 5 Jun 1995 19:01:24 +0000 (19:01 +0000)
src/arch/net/conv-host.c [new file with mode: 0644]
src/arch/net/machine.c [new file with mode: 0644]
src/arch/net/spantree.c [new file with mode: 0644]
src/arch/tcp/conv-host.c [new file with mode: 0644]
src/arch/tcp/machine.c [new file with mode: 0644]
src/arch/tcp/spantree.c [new file with mode: 0644]
src/xlat++/xp-extn.h [new file with mode: 0644]
src/xlat++/xp-process.c [new file with mode: 0644]
src/xlat++/xp-table.c [new file with mode: 0644]

diff --git a/src/arch/net/conv-host.c b/src/arch/net/conv-host.c
new file mode 100644 (file)
index 0000000..bb33c84
--- /dev/null
@@ -0,0 +1,2065 @@
+
+#include "conv-mach.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <setjmp.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <varargs.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <strings.h>
+#include <varargs.h>
+
+#ifdef CMK_HAVE_WAITFLAGS_H
+#include <waitflags.h>
+#endif
+#ifdef CMK_HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef CMK_NEED_DECLARATION_FOR_STRING_FNS
+char *strchr(), *strrchr(), *strdup();
+#endif
+
+#ifdef CMK_STRERROR_USE_SYS_ERRLIST
+extern char *sys_errlist[];
+#define strerror(i) (sys_errlist[i])
+#endif
+
+#ifdef CMK_RSH_IS_A_COMMAND
+#define RSH_CMD "rsh"
+#endif
+
+#ifdef CMK_RSH_USE_REMSH
+#define RSH_CMD "remsh"
+#endif
+
+/****************************************************************************
+ *
+ * Death-notification
+ *
+ ****************************************************************************/
+
+int *notify_ip;
+int *notify_port;
+int  notify_count;
+int  notify_max;
+
+void notify_die(int ip, int port)
+{
+  if (notify_count==notify_max) {
+    notify_max  = (notify_max*2)+100;
+    if (notify_ip  ==0) notify_ip   = (int *)malloc(sizeof(int));
+    if (notify_port==0) notify_port = (int *)malloc(sizeof(int));
+    notify_ip   = (int *)realloc(notify_ip,   notify_max*sizeof(int));
+    notify_port = (int *)realloc(notify_port, notify_max*sizeof(int));
+  }
+  notify_ip[notify_count] = ip;
+  notify_port[notify_count] = port;
+  notify_count++;
+}
+
+void notify_die_doit(char *msg)
+{
+  int skt_connect();
+  char buffer[1024];
+  int i, fd;
+  sprintf(buffer,"die %s\n",msg);
+  for (i=0; i<notify_count; i++) {
+    int ip = notify_ip[i];
+    int port = notify_port[i];
+    fd = skt_connect(ip, port);
+    if (fd>=0) { write(fd, buffer, strlen(buffer)); close(fd); }
+  }
+  fprintf(stderr,"aborting: %s\n",msg);
+  exit(1);
+}
+
+void notify_abort()
+{
+  notify_die_doit("");
+}
+
+void notify_die_segv()
+{
+  notify_die_doit("host: seg fault.");
+}
+
+void notify_die_intr()
+{
+  notify_die_doit("host: interrupted.");
+}
+
+void notify_die_init()
+{
+  signal(SIGSEGV, notify_die_segv);
+  signal(SIGBUS,  notify_die_segv);
+  signal(SIGILL,  notify_die_segv);
+  signal(SIGABRT, notify_die_segv);
+  signal(SIGFPE,  notify_die_segv);
+
+#ifdef SIGSYS
+  signal(SIGSYS,  notify_die_segv);
+#endif
+  
+  signal(SIGPIPE, notify_die_segv);
+  signal(SIGURG,  notify_die_segv);
+
+  signal(SIGTERM, notify_die_intr);
+  signal(SIGQUIT, notify_die_intr);
+  signal(SIGINT,  notify_die_intr);
+}
+
+/**************************************************************************
+ *
+ * SKT - socket routines
+ *
+ * Uses Module: SCHED  [implicitly TIMEVAL, QUEUE, THREAD]
+ *
+ *
+ * unsigned int skt_ip()
+ *
+ *   - returns the IP address of the current machine.
+ *
+ * void skt_server(unsigned int *pip, unsigned int *ppo, unsigned int *pfd)
+ *
+ *   - create a tcp server socket.  Performs the whole socket/bind/listen
+ *     procedure.  Returns the IP address of the socket (eg, the IP of the
+ *     current machine), the port of the socket, and the file descriptor.
+ *
+ * void skt_accept(int src,
+ *                 unsigned int *pip, unsigned int *ppo, unsigned int *pfd)
+ *
+ *   - accepts a connection to the specified socket.  Returns the
+ *     IP of the caller, the port number of the caller, and the file
+ *     descriptor to talk to the caller.
+ *
+ * int skt_connect(unsigned int ip, int port)
+ *
+ *   - Opens a connection to the specified server.  Returns a socket for
+ *     communication.
+ *
+ *
+ **************************************************************************/
+
+unsigned int skt_ip()
+{
+  static unsigned int ip = 0;
+  struct hostent *hostent;
+  char hostname[100];
+  if (ip==0) {
+    if (gethostname(hostname, 99)<0) ip=0x7f000001;
+    hostent = gethostbyname(hostname);
+    if (hostent == 0) return 0x7f000001;
+    ip = htonl(*((int *)(hostent->h_addr_list[0])));
+  }
+  return ip;
+}
+
+void skt_server(unsigned int *pip, unsigned int *ppo, unsigned int *pfd)
+{
+  int fd= -1;
+  int ok, len;
+  struct sockaddr_in addr;
+  
+  fd = socket(PF_INET, SOCK_STREAM, 0);
+  if (fd < 0) { perror("socket"); exit(1); }
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  ok = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+  if (ok < 0) { perror("bind"); exit(1); }
+  ok = listen(fd,5);
+  if (ok < 0) { perror("listen"); exit(1); }
+  len = sizeof(addr);
+  ok = getsockname(fd, (struct sockaddr *)&addr, &len);
+  if (ok < 0) { perror("getsockname"); exit(1); }
+
+  *pfd = fd;
+  *pip = skt_ip();
+  *ppo = ntohs(addr.sin_port);
+}
+
+void skt_accept(int src,
+               unsigned int *pip, unsigned int *ppo, unsigned int *pfd)
+{
+  int i, fd, ok;
+  struct sockaddr_in remote;
+  i = sizeof(remote);
+ acc:
+  fd = accept(src, (struct sockaddr *)&remote, &i);
+  if ((fd<0)&&(errno==EINTR)) goto acc;
+  if ((fd<0)&&(errno==EMFILE)) goto acc;
+  if (fd<0) { perror("accept"); notify_abort(); }
+  *pip=htonl(remote.sin_addr.s_addr);
+  *ppo=htons(remote.sin_port);
+  *pfd=fd;
+}
+
+int skt_connect(unsigned int ip, int port)
+{
+  struct sockaddr_in remote; short sport=port;
+  int fd, ok, len;
+    
+  /* create an address structure for the server */
+  memset(&remote, 0, sizeof(remote));
+  remote.sin_family = AF_INET;
+  remote.sin_port = htons(sport);
+  remote.sin_addr.s_addr = htonl(ip);
+    
+ sock:
+  fd = socket(AF_INET, SOCK_STREAM, 0);
+  if ((fd<0)&&(errno=EMFILE)) goto sock;
+  if (fd < 0) return -1;
+  
+ conn:
+  ok = connect(fd, (struct sockaddr *)&(remote), sizeof(remote));
+  if (ok<0) {
+    switch (errno) {
+    case EADDRINUSE: close(fd); goto sock;
+    default: return -1;
+    }
+  }
+  return fd;
+}
+
+/****************************************************************************
+ *
+ * Miscellaneous minor routines.
+ *
+ ****************************************************************************/
+
+zap_newline(char *s)
+{
+  char *p;
+  p = s + strlen(s)-1;
+  if (*p == '\n') *p = '\0';
+}
+
+char *substr(char *lo, char *hi)
+{
+  int len = hi-lo;
+  char *res = (char *)malloc(1+len);
+  memcpy(res, lo, len);
+  res[len]=0;
+  return res;
+}
+
+/* advance pointer over blank characters */
+char *skipblanks(char *p)
+{
+  while ((*p==' ')||(*p=='\t')) p++;
+  return p;
+}
+
+/* advance pointer over nonblank characters */
+char *skipstuff(char *p)
+{
+  while ((*p)&&(*p!=' ')&&(*p!='\t')) p++;
+  return p;
+}
+
+char *text_ip(unsigned int ip)
+{
+  static char buffer[100];
+  sprintf(buffer,"%d.%d.%d.%d",
+         (ip>>24)&0xFF,
+         (ip>>16)&0xFF,
+         (ip>>8)&0xFF,
+         (ip>>0)&0xFF);
+  return buffer;
+}
+
+int readhex(FILE *f, int len)
+{
+  char buffer[100];
+  char *p;
+  int res;
+  if (fread(buffer, len, 1, f)!=1) return -1;
+  buffer[len]=0;
+  res=strtol(buffer, &p, 16);
+  if (p!=buffer+len) return -1;
+  return res;
+}
+
+char *getenv_display()
+{
+  static char result[100];
+  char *e, *p;
+  
+  e = getenv("DISPLAY");
+  if (e==0) return 0;
+  p = strrchr(e, ':');
+  if (p==0) return 0;
+  if ((e[0]==':')||(strncmp(e,"unix:",5)==0)) {
+    sprintf(result,"%s:%s",text_ip(skt_ip()),p+1);
+  }
+  else strcpy(result, e);
+  return result;
+}
+
+char *mylogin()
+{
+  struct passwd *self;
+  self = getpwuid(getuid());
+  if (self==0) { perror("getpwuid"); exit(1); }
+  return self->pw_name;
+} 
+
+unsigned int lookup_ip(char *name)
+{
+  struct hostent *h;
+  unsigned int ip1,ip2,ip3,ip4; int nread;
+  nread = sscanf(name,"%d.%d.%d.%d",&ip1,&ip2,&ip3,&ip4);
+  if (nread==4) return (ip1<<24)|(ip2<<16)|(ip3<<8)|ip4;
+  h = gethostbyname(name);
+  if (h==0) return 0;
+  return htonl(*((int *)(h->h_addr_list[0])));
+}
+
+/*****************************************************************************
+ *                                                                           *
+ * PPARAM - obtaining "program parameters" from the user.                    *
+ *                                                                           *
+ *****************************************************************************/
+
+typedef struct ppdef
+{
+  union
+    {
+      double r;
+      int i;
+      char *s;
+      int f;
+    } value;
+  char *lname;
+  char *doc;
+  char  type;
+  struct ppdef *next;
+}
+*ppdef;
+
+static ppdef ppdefs;
+
+static int     pparam_pos;
+static char  **pparam_argv;
+static char    pparam_optc='-';
+char           pparam_error[100];
+
+static ppdef pparam_find(char *lname)
+{
+  ppdef def;
+  for (def=ppdefs; def; def=def->next)
+    if (strcmp(def->lname, lname)==0)
+      return def;
+  return 0;
+}
+
+static ppdef pparam_cell(char *lname)
+{
+  ppdef def = pparam_find(lname);
+  if (def) return def;
+  def = (ppdef)malloc(sizeof(struct ppdef));
+  def->lname = lname;
+  def->type  = 's';
+  def->doc   = "(undocumented)";
+  def->next  = ppdefs;
+  ppdefs = def;
+  return def;
+}
+
+void pparam_doc(char *lname, char *doc)
+{
+  ppdef def = pparam_cell(lname);
+  def->doc = doc;
+}
+
+void pparam_defint(char *lname, int value)
+{
+  ppdef def = pparam_cell(lname);
+  def->type  = 'i';
+  def->value.i = value;
+}
+
+void pparam_defreal(char *lname, double value)
+{
+  ppdef def = pparam_cell(lname);
+  def->type  = 'r';
+  def->value.r = value;
+}
+
+void pparam_defstr(char *lname, char *value)
+{
+  ppdef def = pparam_cell(lname);
+  def->type  = 's';
+  def->value.s = value;
+}
+
+void pparam_defflag(char *lname)
+{
+  ppdef def = pparam_cell(lname);
+  def->type  = 'f';
+  def->value.f = 0;
+}
+
+static ppdef pparam_hfind(char *lname)
+{
+  ppdef def = pparam_find(lname);
+  if (def) return def;
+  printf("No such program parameter %s\n",lname);
+  exit(1);
+}
+
+int pparam_getint(char *lname)
+{
+  ppdef def = pparam_hfind(lname);
+  if (def->type != 'i') return 0;
+  return def->value.i;
+}
+
+double pparam_getreal(char *lname)
+{
+  ppdef def = pparam_hfind(lname);
+  if (def->type != 'r') return 0.0;
+  return def->value.r;
+}
+
+char *pparam_getstr(char *lname)
+{
+  ppdef def = pparam_hfind(lname);
+  if (def->type != 's') return 0;
+  return def->value.s;
+}
+
+int pparam_getflag(char *lname)
+{
+  ppdef def = pparam_hfind(lname);
+  if (def->type != 'f') return 0;
+  return def->value.f;
+}
+
+static int pparam_setdef(ppdef def, char *value)
+{
+  char *p;
+  switch(def->type)
+    {
+    case 'i' :
+      def->value.i = strtol(value, &p, 10);
+      if (*p) return -1;
+      return 0;
+    case 'r' :
+      def->value.r = strtod(value, &p);
+      if (*p) return -1;
+      return 0;
+    case 's' :
+      def->value.s = value;
+      return 0;
+    case 'f' :
+      def->value.i = strtol(value, &p, 10);
+      if (*p) return -1;
+      return 0;
+    }
+}
+
+int pparam_set(char *lname, char *value)
+{
+  ppdef def = pparam_cell(lname);
+  return pparam_setdef(def, value);
+}
+
+char *pparam_getdef(ppdef def)
+{
+  static char result[100];
+  switch(def->type)
+    {
+    case 'i': sprintf(result,"%d", def->value.i); return result;
+    case 'r': sprintf(result,"%lf",def->value.r); return result;
+    case 's': return def->value.s;
+    case 'f': sprintf(result,"%d", def->value.f); return result;
+    }
+}
+
+void pparam_printdocs()
+{
+  ppdef def; int i, len, maxname, maxdoc;
+  maxname = 0;
+  maxdoc = 0;
+  for (def=ppdefs; def; def=def->next)
+    {
+      len = strlen(def->lname);
+      if (len>maxname) maxname=len;
+      len = strlen(def->doc);
+      if (len>maxdoc) maxdoc=len;
+    }
+  printf("\n");
+  printf("parameters recognized are:\n");
+  printf("\n");
+  for (def=ppdefs; def; def=def->next)
+    {
+      len = strlen(def->lname);
+      printf("  %c%c%s ",pparam_optc,pparam_optc,def->lname);
+      for(i=0; i<maxname-len; i++) printf(" ");
+      len = strlen(def->doc);
+      printf("  %s ",def->doc);
+      for(i=0; i<maxdoc-len; i++) printf(" ");
+      printf("[%s]\n",pparam_getdef(def));
+    }
+  printf("\n");
+}
+
+void pparam_delarg(int i)
+{
+  int j;
+  for (j=i; pparam_argv[j]; j++)
+    pparam_argv[j]=pparam_argv[j+1];
+}
+
+int pparam_countargs(char **argv)
+{
+  int argc;
+  for (argc=0; argv[argc]; argc++);
+  return argc;
+}
+
+int pparam_parseopt()
+{
+  int ok; ppdef def;
+  char *opt = pparam_argv[pparam_pos];
+  /* handle ++ by skipping to end */
+  if ((opt[1]=='+')&&(opt[2]==0))
+    {
+      pparam_delarg(pparam_pos);
+      while (pparam_argv[pparam_pos]) pparam_pos++;
+      return 0;
+    }
+  /* handle + by itself - an error */
+  if (opt[1]==0) 
+    {
+      sprintf(pparam_error,"Illegal option +\n");
+      return -1;
+    }
+  /* look up option definition */
+  if (opt[1]=='+') def = pparam_find(opt+2);
+  else
+    {
+      char name[2];
+      name[0]=opt[1];
+      name[1]=0;
+      def = pparam_find(name);
+    }
+  if (def==0)
+    {
+      pparam_pos++;
+      return 0;
+/*
+   sprintf(pparam_error,"Option %s not recognized.",opt);
+   return -1;
+*/
+    }
+  /* handle flag-options */
+  if ((def->type=='f')&&(opt[1]!='+')&&(opt[2]))
+    {
+      sprintf(pparam_error,"Option %s should not include a value",opt);
+      return -1;
+    }
+  if (def->type=='f')
+    {
+      def->value.f = 1;
+      pparam_delarg(pparam_pos);
+      return 0;
+    }
+  /* handle non-flag options */
+  if ((opt[1]=='+')||(opt[2]==0))
+    {
+      pparam_delarg(pparam_pos);
+      opt = pparam_argv[pparam_pos];
+    }
+  else opt+=2;
+  if ((opt == 0)||(opt[0] == 0))
+    {
+      sprintf(pparam_error,"%s must be followed by a value.",opt);
+      return -1;
+    }
+  ok = pparam_setdef(def, opt);
+  pparam_delarg(pparam_pos);
+  if (ok<0)
+    {
+      sprintf(pparam_error,"Illegal value for %s",opt);
+      return -1;
+    }
+  return 0;
+}
+
+int pparam_parsecmd(char optchr, char **argv)
+{
+  pparam_error[0]=0;
+  pparam_argv = argv;
+  pparam_optc = optchr;
+  pparam_pos  = 0;
+  while(1)
+    {
+      char *opt = pparam_argv[pparam_pos];
+      if (opt==0) break;
+      if (opt[0]!=optchr) pparam_pos++;
+      else if (pparam_parseopt()<0) return -1;
+    }
+  return 0;
+}
+
+/****************************************************************************
+ *                                                                           
+ * PATH                                                                      
+ *                                                                           
+ * path_simplify(P)                                                          
+ *                                                                           
+ *  - P is a pointer to a buffer containing a path.  All ".." and "."        
+ *    components of the path are expanded out.                               
+ *                                                                           
+ * path_concat(P, rel)                                                       
+ *                                                                           
+ *  - P is a pointer to a buffer containing a path, rel is another path      
+ *    relative to P.  The logical concatenation of the two paths are         
+ *    stored in the buffer.                                                  
+ *                                                                           
+ * path_absolute(P)                                                          
+ *                                                                           
+ *  - If P is a relative path, it is assumed to be relative to the current   
+ *    directory, and it is thereby converted into an absolute path.          
+ *                                                                           
+ * path_search(name, searchpath)                                             
+ *                                                                           
+ *  - name is a pointer to a buffer containing a program name or program     
+ *    path, and searchpath is a string containing a list of directories      
+ *   (as might be returned by getenv("PATH")).  The program's executable     
+ *    is located and its absolute, readlinked path is stored in the name     
+ *    buffer.                                                                
+ *                                                                           
+ * int path_isprefix(path1, path2)
+ * 
+ *  -  Routine to check whether path1 is a prefix of path2.  Returns 0 if
+ *     not a prefix, or number of chars to chop off 'ipath' if it is a
+ *     prefix.  path1 must be a path without a trailing slash.
+ *
+ *****************************************************************************/
+
+static char *path_segs[100];
+static int   path_nsegs;
+
+static void path_segs_free()
+{
+  while (path_nsegs) free(path_segs[--path_nsegs]);
+}
+
+static void path_dissect(char *path)
+{
+  char buf[1000];
+  int len=0;
+  while (1)
+    {
+      if ((*path=='/')||(*path==0))
+       {
+         buf[len]=0;
+         path_segs[path_nsegs++] = strdup(buf);
+         len=0;
+       }
+      else buf[len++] = *path;
+      if (*path==0) break;
+      path++;
+    }
+}
+
+static void path_reduce()
+{
+  int src, dst;
+  src = 0; dst = 0;
+  for (src=0; src<path_nsegs; src++)
+    {
+      char *t;
+      if ((strcmp(path_segs[src],"")==0)&&(src!=0)) continue;
+      if (strcmp(path_segs[src],".")==0) continue;
+      if (strcmp(path_segs[src],"..")==0) { if (dst) dst--; continue; }
+      t = path_segs[dst]; path_segs[dst]=path_segs[src]; path_segs[src]=t;
+      dst ++;
+    }
+  while (src>dst) free(path_segs[--src]);
+  path_nsegs = dst;
+}
+
+static void path_reconstitute(char *buff)
+{
+  int i;
+  for (i=0; i<path_nsegs; i++)
+    {
+      strcpy(buff, path_segs[i]);
+      buff+=strlen(buff);
+      *buff++ = '/';
+    }
+  *(--buff)=0;
+}
+
+void path_simplify(char *path)
+{
+  path_nsegs = 0;
+  path_dissect(path);
+  path_reduce();
+  path_reconstitute(path);
+  path_segs_free();
+}
+
+void path_concat(char *base, char *rel)
+{
+  path_nsegs = 0;
+  if (rel[0]!='/') path_dissect(base);
+  path_dissect(rel);
+  path_reduce();
+  path_reconstitute(base);
+  path_segs_free();
+}
+
+void path_absolute(char *path)
+{
+  char buff[1024];
+  if (path[0]=='/') return;
+  getcwd(buff, 1023);
+  path_concat(buff, path);
+  strcpy(path, buff);
+}
+
+int path_exists(char *path)
+{
+  struct stat s;
+  int ok = stat(path, &s);
+  if (ok>=0) return 1;
+  return 0;
+}
+
+int path_executable(char *path)
+{
+  struct stat s;
+  int ok = stat(path, &s);
+  if (ok<0) return 0;
+  if (!S_ISREG(s.st_mode)) return 0;
+  if((s.st_mode&S_IXOTH)&&(s.st_mode&S_IROTH)) return 1;
+  if((s.st_mode&S_IXGRP)&&(s.st_mode&S_IRGRP)&&(s.st_gid==getgid()))return 1;
+  if((s.st_mode&S_IXUSR)&&(s.st_mode&S_IRUSR)&&(s.st_uid==getuid()))return 1;
+  return 0;
+}
+
+int path_nonzero(char *path)
+{
+  struct stat s;
+  int ok = stat(path, &s);
+  if (ok<0) return 0;
+  if (!S_ISREG(s.st_mode)) return 0;
+  if (s.st_size==0) return 0;
+  return 1;
+}
+
+int path_search(char *prog, char *path)
+{
+  char *end;
+  if (strchr(prog,'/'))
+    {
+      path_absolute(prog);
+      if (path_exists(prog)) return 0;
+      prog[0]=0; return -1;
+    }
+  if ((path)&&(*path)) while (1)
+    {
+      char buff[1024];
+      int len;
+      end = strchr(path, ':');
+      if (end==0) { end=path+strlen(path); }
+      len = (end - path);
+      memcpy(buff, path, len);
+      buff[len]=0;
+      path_concat(buff, prog);
+      path_absolute(buff);
+      if (path_executable(buff)) { strcpy(prog, buff); return 0; }
+      if (*end==0) break;
+      path=end+1;
+    }
+  prog[0]=0; errno=ENOENT; return -1;
+}
+
+int path_isprefix(char *ipre, char *ipath)
+{
+  char pre[MAXPATHLEN];
+  char path[MAXPATHLEN];
+  struct stat preinfo;
+  struct stat pathinfo;
+  int ok, prelen; char *p;
+  strcpy(pre, ipre);
+  strcpy(path, ipath);
+  prelen = strlen(pre);
+  if (prelen==0) return 0;
+  if (pre[prelen-1]=='/') return 0;
+  if (strncmp(pre, path, prelen)==0) return prelen;
+  ok = stat(pre, &preinfo);
+  if (ok<0) return 0;
+  p=path;
+  while (1) {
+    int ch = *p;
+    if ((ch=='/')||(ch==0)) {
+      *p = 0;
+      ok = stat(path, &pathinfo);
+      if (ok<0) return 0;
+      if ((pathinfo.st_ino == preinfo.st_ino)&&
+          (pathinfo.st_dev == preinfo.st_dev)) return p-path;
+      *p = ch;
+    }
+    if (ch==0) break;
+    p++;
+  }
+  return 0;
+}
+
+/****************************************************************************
+ *                                                                           
+ * xstr                                                                      
+ *                                                                           
+ *  extendable (and otherwise dynamically-changing) strings.                 
+ *                                                                           
+ *  These are handy for implementing character buffers of all types.         
+ *                                                                           
+ *  This module tries to guarantee reasonable speed efficiency for all       
+ *  operations.                                                              
+ *                                                                           
+ *  Each xstr takes around 3*len bytes (where 'len' is the length of the     
+ *  string being stored), so it isn't very space efficient.  This is done    
+ *  to improve the efficiency of updates.                                    
+ *                                                                           
+ *  xstr_alloc()                                                             
+ *                                                                           
+ *      - allocates an empty buffer.                                         
+ *                                                                           
+ *  xstr_free(str)                                                           
+ *                                                                           
+ *      - frees an allocated buffer.                                         
+ *                                                                           
+ *  xstr_lptr(s)                                                             
+ *                                                                           
+ *      - returns a pointer to leftmost char in buffer.                      
+ *                                                                           
+ *  xstr_rptr(s)                                                             
+ *                                                                           
+ *      - returns a pointer beyond rightmost char in buffer.                 
+ *                                                                           
+ *  xstr_rexpand(str, nbytes)                                                
+ *                                                                           
+ *     - add uninitialized bytes to the right end of the string.             
+ *                                                                           
+ *  xstr_lexpand(str, nbytes)                                                
+ *                                                                           
+ *     - add uninitialized bytes to the left end of the string.              
+ *                                                                           
+ *  xstr_rshrink(str, nbytes)                                                
+ *                                                                           
+ *     - remove bytes from the right end of the string.                      
+ *                                                                           
+ *  xstr_lshrink(str, nbytes)                                                
+ *                                                                           
+ *     - remove bytes from the left end of the string.                       
+ *                                                                           
+ *  xstr_write(str, bytes, nbytes)                                           
+ *                                                                           
+ *     - append the specified bytes to the right end of the xstr.            
+ *                                                                           
+ *  xstr_printf(str, ...)                                                    
+ *                                                                           
+ *     - print the specified message onto the end of the xstr.               
+ *                                                                           
+ *****************************************************************************/
+
+typedef struct xstr
+    {
+    char *lptr;
+    char *rptr;
+    char *lend;
+    char *rend;
+    }
+    *xstr;
+
+char *xstr_lptr(l) xstr l; { return l->lptr; }
+char *xstr_rptr(l) xstr l; { return l->rptr; }
+
+int xstr_len(xstr l)
+{
+  return l->rptr - l->lptr;
+}
+
+xstr xstr_alloc()
+{
+  xstr res = (xstr)malloc(sizeof(struct xstr));
+  res->lend = (char *)malloc(257);
+  res->lptr = res->lend + 128;
+  res->rptr = res->lend + 128;
+  res->rend = res->lend + 256;
+  return res;
+}
+
+void xstr_free(xstr s)
+{
+  free(s->lend);
+  free(s);
+}
+
+void xstr_rexpand(xstr l, int nbytes)
+{
+  int lspace, rspace, uspace, needed; char *nbuf;
+  if (l->rend - l->rptr>=nbytes) { l->rptr += nbytes; return; }
+  uspace = (l->rptr - l->lptr);
+  needed = uspace + nbytes;
+  if (needed<64) needed=64;
+  nbuf = (char *)malloc(1+(needed*3));
+  memcpy(nbuf+needed, l->lptr, uspace);
+  free(l->lend);
+  l->lend = nbuf;
+  l->lptr = nbuf + needed;
+  l->rptr = nbuf + needed + uspace + nbytes;
+  l->rend = nbuf + needed + needed + needed;
+}
+
+void xstr_lexpand(xstr l, int nbytes)
+{
+  int lspace, rspace, uspace, needed; char *nbuf;
+  if (l->rend - l->rptr>=nbytes) { l->rptr += nbytes; return; }
+  uspace = (l->rptr - l->lptr);
+  needed = uspace + nbytes;
+  if (needed<64) needed=64;
+  nbuf = (char *)malloc(1+(needed*3));
+  memcpy(nbuf+needed+nbytes, l->lptr, uspace);
+  free(l->lend);
+  l->lend = nbuf;
+  l->lptr = nbuf + needed;
+  l->rptr = nbuf + needed + uspace + nbytes;
+  l->rend = nbuf + needed + needed + needed;
+}
+
+void xstr_rshrink(xstr l, int nbytes)
+{
+  if (l->rptr - l->lptr < nbytes) { l->rptr=l->lptr; return; }
+  l->rptr -= nbytes;
+}
+
+void xstr_lshrink(xstr l, int nbytes)
+{
+  if (l->rptr - l->lptr < nbytes) { l->lptr=l->rptr; return; }
+  l->lptr += nbytes;
+}
+
+void xstr_write(xstr l, char *bytes, int nbytes)
+{
+  xstr_rexpand(l, nbytes);
+  memcpy(xstr_lptr(l)+xstr_len(l)-nbytes, bytes, nbytes);
+}
+
+void xstr_printf(va_alist) va_dcl
+{
+  char buffer[10000];
+  xstr l; char *fmt;
+  va_list p;
+  va_start(p);
+  l = va_arg(p, xstr);
+  fmt = va_arg(p, char *);
+  vsprintf(buffer, fmt, p);
+  xstr_write(l, buffer, strlen(buffer));
+}
+
+char *xstr_gets(char *buff, int size, xstr s)
+{
+  char *p; int len;
+  xstr_rptr(s)[0]=0;
+  p = strchr(xstr_lptr(s),'\n');
+  if (p==0) return 0;
+  *p = 0;
+  len = p - xstr_lptr(s);
+  if (len > size) len=size;
+  memcpy(buff, xstr_lptr(s), len);
+  buff[len] = 0;
+  xstr_lshrink(s, len+1);
+  return buff;
+}
+
+/****************************************************************************
+ *
+ * PROG - much like 'popen', but better.
+ *
+ *
+ * typedef prog
+ *
+ *  - represents an opened, running program.
+ *
+ * prog prog_start(char *prog, char **argv, use_err)
+ *
+ *  - starts a program in the background (with the same args as execv).
+ *    The prog returned can be used to read the standard input and standard
+ *    output of the resulting program.  'use_err' is a flag, if zero, then
+ *    the program's standard error is merged with its standard output,
+ *    otherwise it is kept separate.
+ *
+ *    The program P has three file descriptors (P->ifd, P->ofd, P->efd)
+ *    which can be used to access its standard input, output, and error.
+ *    In addition, it has three xstr buffers (P->ibuf, P->obuf, P->ebuf)
+ *    which are used for buffered IO on those descriptors.
+ *
+ * int prog_flush(prog p)
+ *
+ *  - flushes the contents of P->ibuf into P->ifd.
+ *
+ * void prog_iclose(prog p)
+ * 
+ *  - close the input-side of the specified program.  You may not write to
+ *    the standard input of the program after prog_iclose.
+ *
+ * void prog_close(prog p)
+ *
+ *  - close the standard inputs and outputs of the specified program,
+ *    and free all resources used by the handle.  The program may continue
+ *    to exist in the background if it is capable of doing so without a
+ *    standard input and output.
+ *
+ ****************************************************************************/
+
+typedef struct prog
+{
+  int ifd; xstr ibuf;
+  int ofd; xstr obuf;
+  int efd; xstr ebuf;
+  int pid;
+}
+*prog;
+
+int prog_flush(prog c)
+{
+  xstr ibuf = c->ibuf;
+  int ifd = c->ifd;
+  
+  if (ibuf==0) return;
+  while (xstr_lptr(ibuf)!=xstr_rptr(ibuf))
+    {
+      int nwrote = write(ifd, xstr_lptr(ibuf), xstr_len(ibuf));
+      if (nwrote < 0) return -1;
+      if (nwrote==0)
+       { fprintf(stderr,"error: write returned 0???\n"); exit(1); }
+      xstr_lshrink(ibuf, nwrote);
+    }
+  return 0;
+}
+
+void prog_iclose(prog c)
+{
+  prog_flush(c);
+  if (c->ibuf) { xstr_free(c->ibuf); close(c->ifd); }
+  c->ibuf = 0;
+}
+
+void prog_close(prog c)
+{
+  prog_flush(c);
+  if (c->ibuf) { xstr_free(c->ibuf); close(c->ifd); }
+  if (c->obuf) { xstr_free(c->obuf); close(c->ofd); }
+  if (c->ebuf) { xstr_free(c->ebuf); close(c->efd); }
+  free(c);
+}
+
+prog prog_make(int ifd, int ofd, int efd, int pid)
+{
+  prog res = (prog)malloc(sizeof(struct prog));
+  res->ifd = ifd;
+  res->ofd = ofd;
+  res->efd = efd;
+  res->ibuf = (ifd >= 0) ? xstr_alloc() : NULL;
+  res->obuf = (ofd >= 0) ? xstr_alloc() : NULL;
+  res->ebuf = (efd >= 0) ? xstr_alloc() : NULL;
+  res->pid = pid;
+  return res;
+}
+
+prog prog_start(char *p, char **argv, int useerr)
+{
+  int p_stdin[2];
+  int p_stdout[2];
+  int p_stderr[2];
+  int pid;
+  p_stdin[0]= -1; p_stdout[0]= -1; p_stderr[0]= -1;
+  p_stdin[1]= -1; p_stdout[1]= -1; p_stderr[1]= -1;
+  if (pipe(p_stdin )<0) goto abort;
+  if (pipe(p_stdout)<0) goto abort;
+  if (pipe(p_stderr)<0) goto abort;
+  pid = 0;
+  pid = fork();
+  if (pid < 0) goto abort;
+  if (pid == 0)
+    {
+      int i;
+      dup2(p_stdin[0],0);
+      dup2(p_stdout[1],1);
+      dup2(useerr?p_stderr[1]:p_stdout[1],2);
+      for(i=3; i<128; i++) close(i);
+      execv(p, argv);
+      exit(1);
+    }
+  close(p_stdin[0]);
+  close(p_stdout[1]);
+  close(p_stderr[1]);
+  return prog_make(p_stdin[1], p_stdout[0], p_stderr[0], pid);
+ abort:
+  if (p_stdin[0]!= -1) close(p_stdin[0]);
+  if (p_stdin[1]!= -1) close(p_stdin[1]);
+  if (p_stdout[0]!= -1) close(p_stdout[0]);
+  if (p_stdout[1]!= -1) close(p_stdout[1]);
+  if (p_stderr[0]!= -1) close(p_stderr[0]);
+  if (p_stderr[1]!= -1) close(p_stderr[1]);
+  return 0;
+}
+
+/****************************************************************************
+ * 
+ * ARG
+ *
+ * The following module computes a whole bunch of miscellaneous values, which
+ * are all constant throughout the program.  Naturally, this includes the
+ * value of the command-line arguments.
+ *
+ *****************************************************************************/
+
+
+#define MAX_NODES 100
+#define MAX_LINE_LENGTH 1000
+
+char **arg_argv;
+int    arg_argc;
+
+int   arg_requested_pes;
+int   arg_debug;
+int   arg_debug_no_pause;
+int   arg_in_xterm;
+int   arg_maxrsh;
+char *arg_nodesfile;
+char *arg_display;
+char *arg_nodeprog_a;
+char *arg_nodeprog_r;
+char *arg_rshprog;
+char *arg_currdir_a;
+char *arg_currdir_r;
+char *arg_mylogin;
+
+arg_init(int argc, char **argv)
+{
+  static char buf[1024]; int len, i;
+  
+  pparam_defint ("p"             , -1);
+  pparam_defflag("debug"             );
+  pparam_defflag("debug-no-pause"    );
+  pparam_defflag("in-xterm"          );
+  pparam_defint ("maxrsh"        ,  5);
+  pparam_defstr ("nodesfile"     ,  0);
+  
+  pparam_doc("p",             "number of processes to create");
+  pparam_doc("in-xterm",      "Run each node in an xterm window");
+  pparam_doc("debug",         "Run each node under gdb in an xterm window");
+  pparam_doc("debug-no-pause","Like debug, except doesn't pause at beginning");
+  pparam_doc("maxrsh",        "Maximum number of rsh's to run at a time");
+  pparam_doc("nodesfile",     "file containing list of nodes");
+
+  if (pparam_parsecmd('+', argv) < 0) {
+    fprintf(stderr,"syntax: %s\n",pparam_error);
+    pparam_printdocs();
+    exit(1);
+  }
+  arg_argv = argv+2;
+  arg_argc = pparam_countargs(argv+2);
+
+  arg_requested_pes  = pparam_getint("p");
+  arg_in_xterm       = pparam_getflag("in-xterm");
+  arg_debug          = pparam_getflag("debug");
+  arg_debug_no_pause = pparam_getflag("debug-no-pause");
+  arg_maxrsh         = pparam_getint("maxrsh");
+  arg_nodesfile      = pparam_getstr("nodesfile");
+
+  /* Find the current value of the DISPLAY variable */
+  arg_display = getenv_display();
+  if ((arg_debug || arg_debug_no_pause || arg_in_xterm) && (arg_display==0)) {
+    fprintf(stderr,"DISPLAY must be set to use debugging mode\n");
+    exit(1);
+  }
+
+  /* find the node-program, absolute version */
+  if (argc<2) {
+    fprintf(stderr,"You must specify a node-program.\n");
+    exit(1);
+  }
+  strcpy(buf, argv[1]);
+  path_search(buf, getenv("PATH"));
+  if (buf[0]==0)
+    { fprintf(stderr,"No such program %s\n",argv[1]); exit(1); }
+  arg_nodeprog_a = strdup(buf);
+  
+  /* find the node-program, relative version */
+  sprintf(buf,"%s",getenv("HOME"));
+  if ((len=path_isprefix(buf,arg_nodeprog_a))!=0) {
+    sprintf(buf,"$HOME/%s",arg_nodeprog_a+len);
+    arg_nodeprog_r = strdup(buf);
+  }
+  else arg_nodeprog_r = arg_nodeprog_a;
+
+  strcpy(buf, RSH_CMD);
+  path_search(buf, getenv("PATH"));
+  if (buf[0]==0)
+    { fprintf(stderr,"Cannot find '%s' in path.\n", RSH_CMD); exit(1); }
+  arg_rshprog = strdup(buf);
+
+  /* find the current directory, absolute version */
+  getcwd(buf, 1023);
+  arg_currdir_a = strdup(buf);
+  
+  /* find the current directory, relative version */
+  sprintf(buf,"%s",getenv("HOME"));
+  if ((len=path_isprefix(buf, arg_currdir_a))!=0) {
+    sprintf(buf,"$HOME/%s",arg_currdir_a+len);
+    arg_currdir_r = strdup(buf);
+  }
+  else arg_currdir_r = arg_currdir_a;
+
+  arg_mylogin = mylogin();
+}
+
+/****************************************************************************
+ *                                                                           
+ * NODE:  The nodes file and nodes table.
+ *
+ * void nodetab_init()
+ *
+ *  - initialize the nodes table.
+ *    
+ *
+ * int nodetab_size;
+ *
+ *  - number of nodes in the nodes table.
+ *
+ * char *nodetab_name(int i)
+ *
+ *  - returns the name of node i.
+ *
+ * char *nodetab_login(int i)
+ *
+ *  - returns the login name for node i.
+ *
+ * char *nodetab_passwd(int i)
+ *
+ *  - returns the password for node I.
+ *
+ * char *nodetab_setup(int i)
+ *
+ *  - returns the setup command for node I.
+ *
+ * unsigned int nodetab_ip(int i)
+ *
+ *  - returns the IP address of node I.
+ *
+ * The routines described above retrieve their information from the nodesfile.
+ * This module looks in several places for the nodes file, in the following
+ * order:                                                   
+ *                                                                           
+ *      a file specified by ++nodesfile                                      
+ *      a file whose name is getenv("NODES")                                 
+ *      a file called "nodes" in the current directory.                      
+ *      a file called ".nodes" in the user's home directory.                 
+ *                                                                           
+ ****************************************************************************/
+
+typedef struct nodetab_info {
+   char *name;
+   char *login;
+   char *passwd;
+   char *setup;
+   unsigned int ip;
+} *nodetab_info;
+
+nodetab_info nodetab_table;
+int          nodetab_size;
+
+char *nodetab_file_find()
+{
+  /* Find a nodes-file as specified by ++nodesfile */
+  if (arg_nodesfile)
+    {
+      char *path = arg_nodesfile;
+      if (path_nonzero(path)) return strdup(path);
+      fprintf(stderr,"No such nodes file %s\n",path);
+      exit(1);
+    }
+  /* Find a nodes-file as specified by getenv("NODES") */
+  if (getenv("NODES"))
+    {
+      char *path = getenv("NODES");        
+      if (path && path_nonzero(path)) return strdup(path);
+      fprintf(stderr,"Cannot find NODES file %s\n",path);
+      exit(1);
+    }
+  /* Find a nodes-file by looking under 'nodes' in the current directory */
+  if (path_nonzero("./nodes")) return strdup("./nodes");
+  if (getenv("HOME"))
+    {
+      char buffer[MAXPATHLEN];
+      strcpy(buffer,getenv("HOME"));
+      path_concat(buffer,".nodes");
+      if (path_nonzero(buffer)) return strdup(buffer);
+    }
+  fprintf(stderr,"Cannot find a nodes file.\n");
+  exit(1);
+}
+
+
+void nodetab_init()
+{
+  FILE *f,*fopen();
+  char *nodesfile;
+  char *tok_ptr;
+  char input_line[MAX_LINE_LENGTH];
+  int i;
+  
+  /* Open the NODES_FILE. */
+  nodesfile = nodetab_file_find();
+  if (!(f = fopen(nodesfile,"r"))) {
+    fprintf(stderr,"Cannot read %s: %s\n",nodesfile,strerror(errno));
+    exit(1);
+  }
+  
+  nodetab_table= (nodetab_info)malloc(MAX_NODES * sizeof(struct nodetab_info));
+
+  /* Read in the machine definitions */
+  nodetab_size=0;
+  while(fgets(input_line,sizeof(input_line)-1,f)!=0) {
+    char *b,*e;
+    nodetab_info node = nodetab_table+nodetab_size;
+    if (input_line[0]=='#') continue;
+    zap_newline(input_line);
+    b=skipblanks(input_line);
+    if (*b==0) continue;
+    if (nodetab_size == MAX_NODES) {
+      fprintf(stderr,"Too many nodes, truncating nodesfile.\n");
+      break;
+    }
+    e=skipstuff(b);
+    node->name=substr(b,e);
+    /* put default information */
+    node->login="*";
+    node->passwd="*";
+    node->setup="";
+    b=skipblanks(e);
+    if (*b==0) goto endnode;
+    e=skipstuff(b);
+    node->login=substr(b,e);
+    b=skipblanks(e);
+    if (*b==0) goto endnode;
+    e=skipstuff(b);
+    node->passwd=substr(b,e);
+    b=skipblanks(e);
+    if (*b==0) goto endnode;
+    e=b+strlen(b);
+    node->setup=substr(b,e);
+  endnode:;
+    if (strcmp(node->login,"*")==0)
+      node->login = arg_mylogin;
+    node->ip = lookup_ip(node->name);
+    if (node->ip==0) {
+      fprintf(stderr,"cannot get IP of %s\n",node->name);
+      exit(1);
+    }
+    nodetab_size++;
+    if (nodetab_size == arg_requested_pes) break;
+  }
+  if ((arg_requested_pes > 0)&&(nodetab_size != arg_requested_pes)) {
+    fprintf(stderr,"Cannot read %d nodes from nodesfile %s\n",
+           arg_requested_pes, nodesfile);
+    exit(1);
+  }
+  fclose(f);
+}
+
+nodetab_info nodetab_getinfo(int i) {
+  if (nodetab_table==0) {
+    fprintf(stderr,"Node table not initialized.\n");
+    exit(1);
+  }
+  if ((i<0)||(i>=nodetab_size)) {
+    fprintf(stderr,"No such node %d\n",i);
+    exit(1);
+  }
+  return nodetab_table+i;
+}
+
+char        *nodetab_name(int i)   { return nodetab_getinfo(i)->name; }
+char        *nodetab_login(int i)  { return nodetab_getinfo(i)->login; }
+char        *nodetab_passwd(int i) { return nodetab_getinfo(i)->passwd; }
+char        *nodetab_setup(int i)  { return nodetab_getinfo(i)->setup; }
+unsigned int nodetab_ip(int i)     { return nodetab_getinfo(i)->ip; }
+/****************************************************************************
+ *
+ * ARVAR - array variables
+ *
+ * This host can store arrays for its clients.
+ *
+ * arvar_set(char *var, int index, char *val)
+ *
+ *  - set the specified position in the specified array to the specified
+ *    value.  If the named array does not exist, it is created.  If the
+ *    specified index does not exist, it is created.
+ *
+ * arvar_get(char *var, int lo, int hi)
+ *
+ *  - retrieve the specified subrange of the array.  If the entire subrange
+ *    has not been assigned, NULL is returned. Values are separated by
+ *    spaces.
+ *
+ ****************************************************************************/
+
+typedef struct arvar
+{
+  char *name;
+  int lo;
+  int hi;
+  int tot;
+  char **data;
+  struct arvar *next;
+}
+*arvar;
+
+arvar arvar_list;
+
+arvar arvar_find(char *var)
+{
+  arvar v = arvar_list;
+  while (v && (strcmp(v->name, var))) v=v->next;
+  return v;
+}
+
+arvar arvar_obtain(char *var)
+{
+  arvar v = arvar_find(var);
+  if (v==0) { 
+    v = (arvar)malloc(sizeof(struct arvar));
+    v->name = strdup(var);
+    v->lo = 0;
+    v->hi = -1;
+    v->data = 0;
+    v->next = arvar_list;
+    arvar_list = v;
+  }
+  return v;
+}
+
+void arvar_set(char *var, int index, char *val)
+{
+  char *old;
+  int i, lo, hi;
+  char **data;
+  arvar v = arvar_obtain(var);
+  data = v->data; lo = v->lo; hi = v->hi;
+  if ((index<lo)||(index>=hi)) {
+    if (lo>hi) lo=hi=index;
+    if (index<lo) lo=index;
+    if (index>=hi) hi=index+1;
+    data = (char **)calloc(1, (hi-lo)*sizeof(char *));
+    if (v->data) {
+      memcpy(data+((v->lo)-lo), v->data, (v->hi - v->lo)*sizeof(char *));
+      free(v->data);
+    }
+    v->data = data; v->lo = lo; v->hi = hi;
+  }
+  old = v->data[index-(v->lo)];
+  if (old) free(old);
+  else v->tot++;
+  v->data[index-(v->lo)] = strdup(val);
+}
+
+char *arvar_get(char *var, int lo, int hi)
+{
+  int len=0; int i;
+  arvar v = arvar_find(var);
+  char **data, *res;
+  if (v==0) return 0;
+  data = v->data;
+  if (lo<v->lo) return 0;
+  if (hi>v->hi) return 0;
+  for (i=lo; i<hi; i++) {
+    char *val = data[i-(v->lo)];
+    if (val==0) return 0;
+    len += strlen(val)+1;
+  }
+  res = (char *)malloc(len);
+  len=0;
+  for (i=lo; i<hi; i++) {
+    char *val = data[i-(v->lo)];
+    strcpy(res+len, val);
+    len+=strlen(val);
+    res[len++] = ' ';
+  }
+  res[--len] = 0;
+  return res;
+}
+
+/****************************************************************************
+ *
+ * input handling
+ *
+ * You can use this module to read the standard input.  It supports
+ * one odd function, input_scanf_chars, which is what makes it useful.
+ * if you use this module, you may not read stdin yourself.
+ *
+ * void input_init(void)
+ * char *input_gets(void)
+ * char *input_scanf_chars(char *fmt)
+ *
+ ****************************************************************************/
+
+char *input_buffer;
+
+void input_extend(void)
+{
+  char line[1024];
+  int len = input_buffer?strlen(input_buffer):0;
+  fflush(stdout);
+  if (fgets(line, 1023, stdin)==0) { notify_die_doit("end-of-file on stdin"); }
+  input_buffer = realloc(input_buffer, len + strlen(line) + 1);
+  strcpy(input_buffer+len, line);
+}
+
+void input_init(void)
+{
+  input_buffer = strdup("");
+}
+
+char *input_extract(int nchars)
+{
+  char *res = substr(input_buffer, input_buffer+nchars);
+  char *tmp = substr(input_buffer+nchars, input_buffer+strlen(input_buffer));
+  free(input_buffer);
+  input_buffer = tmp;
+  return res;
+}
+
+char *input_gets(void)
+{
+  char *p, *res; int len;
+  while(1) {
+    p = strchr(input_buffer,'\n');
+    if (p) break;
+    input_extend();
+  }
+  len = p-input_buffer;
+  res = input_extract(len+1);
+  res[len]=0;
+  return res;
+}
+
+char *input_scanf_chars(char *fmt)
+{
+  char buf[8192]; int len, pos;
+  static int fd; static FILE *file;
+  fflush(stdout);
+  if (file==0) {
+    unlink("/tmp/fnord");
+    fd = open("/tmp/fnord",O_RDWR | O_CREAT | O_TRUNC);
+    if (fd<0) { notify_die_doit("cannot open temp file /tmp/fnord"); }
+    file = fdopen(fd, "r+");
+    unlink("/tmp/fnord");
+  }
+  while (1) {
+    len = strlen(input_buffer);
+    rewind(file);
+    fwrite(input_buffer, len, 1, file);
+    fflush(file);
+    rewind(file);
+    ftruncate(fd, len);
+    fscanf(file, fmt, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf);
+    pos = ftell(file);
+    if (pos<len) break;
+    input_extend();
+  }
+  return input_extract(pos);
+}
+
+/****************************************************************************
+ *
+ * REQUEST SERVICER
+ *
+ * The request servicer accepts connections on a TCP port.  The client
+ * sends a sequence of commands (each is one line).  It then closes the
+ * connection.  The server must then contact the client, sending replies.
+ *
+ ****************************************************************************/
+
+typedef struct req_node
+{
+  struct req_node *next;
+  char request[1];
+}
+*req_node;
+
+unsigned int req_fd;
+unsigned int req_ip;
+unsigned int req_port;
+req_node     req_saved;
+
+#define REQ_OK 0
+#define REQ_POSTPONE -1
+#define REQ_FAILED -2
+
+int req_handle_aset(char *line)
+{
+  char cmd[100], var[100], val[1000]; int index, ok;
+  ok = sscanf(line,"%s %s %d %s",cmd,var,&index,val);
+  if (ok!=4) return REQ_FAILED;
+  arvar_set(var,index,val);
+  return REQ_OK;
+}
+
+int req_reply(int ip, int port, char *pre, char *ans)
+{
+  int fd = skt_connect(ip, port);
+  if (fd<=0) return REQ_FAILED;
+  write(fd, pre, strlen(pre));
+  write(fd, " ", 1);
+  write(fd, ans, strlen(ans));
+  write(fd, "\n", 1);
+  close(fd);
+  return REQ_OK;
+}
+
+int req_handle_aget(char *line)
+{
+  char cmd[100], host[1000], pre[1000], var[100]; int ip, port, lo, hi, ok;
+  char *res;
+  ok = sscanf(line,"%s %s %d %s %d %d",cmd,host,&port,var,&lo,&hi);
+  if (ok!=6) return REQ_FAILED;
+  ip = lookup_ip(host);
+  if (ip==0) return REQ_FAILED;
+  res = arvar_get(var,lo,hi+1);
+  if (res==0) return REQ_POSTPONE;
+  sprintf(pre, "aval %s %d %d", var, lo, hi);
+  ok = req_reply(ip,port,pre,res);
+  free(res);
+  return ok;
+}
+
+int req_handle_print(char *line)
+{
+  printf("%s\n",line+6);
+  return REQ_OK;
+}
+
+int req_handle_princ(char *line)
+{
+  printf("%s",line+6);
+  return REQ_OK;
+}
+
+int req_handle_printerr(char *line)
+{
+  fprintf(stderr,"%s\n",line+9);
+  return REQ_OK;
+}
+
+int req_handle_princerr(char *line)
+{
+  fprintf(stderr,"%s",line+9);
+  return REQ_OK;
+}
+
+int req_handle_notify_die(char *line)
+{
+  char cmd[100], host[100]; int ip, port, nread;
+  nread = sscanf(line,"%s%s%d",cmd,host,&port);
+  if (nread != 3) return REQ_FAILED;
+  ip = lookup_ip(host);
+  if (ip==0) return REQ_FAILED;
+  notify_die(ip, port);
+  return REQ_OK;
+}
+
+int req_handle_die(char *line)
+{
+  notify_die_doit(line+4);
+}
+
+int ending_count=0;
+
+int req_handle_ending(char *line)
+{
+  ending_count++;
+  if (ending_count == nodetab_size) exit(0);
+  return REQ_OK;
+}
+
+int req_handle_scanf(char *line)
+{
+  char cmd[100], host[100]; int ip, port, ok;
+  char *fmt, *res, *p;
+  ok = sscanf(line,"%s %s %d",cmd,host,&port);
+  if (ok!=3) return REQ_FAILED;
+  ip = lookup_ip(host);
+  if (ip==0) return REQ_FAILED;
+  fmt = line;
+  fmt = skipblanks(fmt); fmt = skipstuff(fmt);
+  fmt = skipblanks(fmt); fmt = skipstuff(fmt);
+  fmt = skipblanks(fmt); fmt = skipstuff(fmt);
+  fmt = fmt+1;
+  res = input_scanf_chars(fmt);
+  p = res; while (*p) { if (*p=='\n') *p=' '; p++; }
+  req_reply(ip, port, "scanf-data ", res);
+  free(res);
+  return REQ_OK;
+}
+
+int req_handle(char *line)
+{
+  char cmd[100];
+  sscanf(line,"%s",cmd);
+  if      (strcmp(cmd,"aset")==0)       return req_handle_aset(line);
+  else if (strcmp(cmd,"aget")==0)       return req_handle_aget(line);
+  else if (strcmp(cmd,"scanf")==0)      return req_handle_scanf(line);
+  else if (strcmp(cmd,"print")==0)      return req_handle_print(line);
+  else if (strcmp(cmd,"princ")==0)      return req_handle_princ(line);
+  else if (strcmp(cmd,"printerr")==0)   return req_handle_printerr(line);
+  else if (strcmp(cmd,"princerr")==0)   return req_handle_princerr(line);
+  else if (strcmp(cmd,"ending")==0)     return req_handle_ending(line);
+  else if (strcmp(cmd,"notify-die")==0) return req_handle_notify_die(line);
+  else if (strcmp(cmd,"die")==0)        return req_handle_die(line);
+  else return REQ_FAILED;
+}
+
+void req_run_saved()
+{
+  int ok;
+  req_node saved = req_saved;
+  req_saved = 0;
+  while (saved) {
+    req_node t = saved;
+    saved = saved->next;
+    ok = req_handle(t->request);
+    if (ok==REQ_POSTPONE) {
+      t->next = req_saved;
+      req_saved = t;
+    } else if (ok==REQ_FAILED) {
+      fprintf(stderr,"bad request: %s\n",t->request);
+      free(t);
+    } else free(t);
+  }
+}
+
+req_serve_client(FILE *f)
+{
+  char line[1000]; int status;
+  while (1) {
+    line[0]=0;
+    if (fgets(line, 999, f)==0) break;
+    zap_newline(line);
+    status = req_handle(line);
+    if (status==REQ_OK) req_run_saved();
+    else if (status==REQ_POSTPONE) {
+      req_node n = (req_node)malloc(sizeof(struct req_node)+strlen(line));
+      strcpy(n->request, line);
+      n->next = req_saved;
+      req_saved = n;
+    }
+    else fprintf(stderr,"bad request: %s\n",line);
+    line[0]=0;
+  }
+}
+
+req_serve()
+{
+  int client_ip, client_port, client_fd;
+  while (1) {
+    FILE *f;
+    skt_accept(req_fd, &client_ip, &client_port, &client_fd);
+    if (client_fd==0) {
+      perror("accept");
+      notify_abort();
+    }
+    f = fdopen(client_fd, "r+");
+    req_serve_client(f);
+    fclose(f);
+    close(client_fd);
+  }
+}
+
+req_init()
+{
+  skt_server(&req_ip, &req_port, &req_fd);
+  req_saved = 0;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* start_nodes                                                              */
+/*                                                                          */
+/* this starts all the node programs.  It executes fully in the background. */
+/*                                                                          */
+/****************************************************************************/
+
+prog rsh_start(int nodeno)
+{
+  char *rshargv[6];
+  prog rsh;
+  
+  rshargv[0]=RSH_CMD;
+  rshargv[1]=nodetab_name(nodeno);
+  rshargv[2]="-l";
+  rshargv[3]=nodetab_login(nodeno);
+  rshargv[4]="exec /bin/csh -f";
+  rshargv[5]=0;
+  rsh = prog_start(arg_rshprog, rshargv, 0);
+  if ((rsh==0)&&(errno!=EMFILE)) { perror("starting rsh"); exit(1); }
+  if (rsh==0)
+    {
+      fprintf(stderr,"caution: cannot start specified number of rsh's\n");
+      fprintf(stderr,"(not enough file descriptors available).\n");
+    }
+  if (rsh && (arg_debug || arg_debug_no_pause))
+    fprintf(stderr,"node %d: rsh initiated...\n",nodeno);
+  return rsh;
+}
+
+int rsh_pump(prog p, int nodeno, char **argv)
+{
+  xstr ibuf = p->ibuf;
+  int randno = rand();
+  
+  xstr_printf(ibuf,"echo 'remote responding...'\n");
+
+  if (arg_display)
+    xstr_printf(ibuf,"setenv DISPLAY %s\n",arg_display);
+  xstr_printf(ibuf,"setenv NETSTART '%d %d %d %d %d'\n",
+    nodeno, nodetab_size, nodetab_ip(nodeno), req_ip, req_port);
+  prog_flush(p);
+
+  if (arg_debug || arg_debug_no_pause || arg_in_xterm) {
+    xstr_printf(ibuf,"foreach dir ($path)\n");
+    xstr_printf(ibuf,"  if (-e $dir/xterm) setenv F_XTERM $dir/xterm\n");
+    xstr_printf(ibuf,"  if (-e $dir/xdpyinfo) setenv F_XDPYINFO $dir/xdpyinfo\n");
+    xstr_printf(ibuf,"end\n");
+    xstr_printf(ibuf,"if ($?F_XTERM == 0) then\n");
+    xstr_printf(ibuf,"   echo 'xterm not in path --- set your path in your cshrc.'\n");
+    xstr_printf(ibuf,"   kill -9 $$\n");
+    xstr_printf(ibuf,"endif\n");
+    xstr_printf(ibuf,"if ($?F_XDPYINFO == 0) then\n");
+    xstr_printf(ibuf,"   echo 'xdpyinfo not in path - set your path in your cshrc.'\n");
+    xstr_printf(ibuf,"   kill -9 $$\n");
+    xstr_printf(ibuf,"endif\n");
+    prog_flush(p);
+  }
+
+  if (arg_debug || arg_debug_no_pause) {
+    xstr_printf(ibuf,"foreach dir ($path)\n");
+    xstr_printf(ibuf,"  if (-e $dir/gdb) setenv F_GDB $dir/gdb\n");
+    xstr_printf(ibuf,"end\n");
+    xstr_printf(ibuf,"if ($?F_GDB == 0) then\n");
+    xstr_printf(ibuf,"   echo 'gdb not in path - set your path in your cshrc.'\n");
+    xstr_printf(ibuf,"   kill -9 $$\n");
+    xstr_printf(ibuf,"endif\n");
+    prog_flush(p);
+  }
+
+  if (arg_debug || arg_debug_no_pause || arg_in_xterm) {
+    xstr_printf(ibuf,"xdpyinfo > /dev/null\n");
+    xstr_printf(ibuf,"if ($status != 0) then\n");
+    xstr_printf(ibuf,"   echo 'Run xhost to enable display.'\n");
+    xstr_printf(ibuf,"   echo '(See manual for xhost for security issues)'\n");
+    xstr_printf(ibuf,"   kill -9 $$\n");
+    xstr_printf(ibuf,"endif\n");
+    prog_flush(p);
+  }
+  
+  xstr_printf(ibuf,"if (! -x %s) then\n",arg_nodeprog_r);
+  xstr_printf(ibuf,"  echo 'Cannot execute this node-program:'\n");
+  xstr_printf(ibuf,"  echo '%s'\n",arg_nodeprog_r);
+  xstr_printf(ibuf,"  kill -9 $$\n");
+  xstr_printf(ibuf,"endif\n");
+  
+  xstr_printf(ibuf,"cd %s\n",arg_currdir_r);
+  xstr_printf(ibuf,"if ($status == 1) then\n");
+  xstr_printf(ibuf,"  echo 'Cannot propagate this current directory:'\n"); 
+  xstr_printf(ibuf,"  echo '%s'\n",arg_currdir_r);
+  xstr_printf(ibuf,"  kill -9 $$\n");
+  xstr_printf(ibuf,"endif\n");
+  
+  if (nodetab_setup(nodeno)) {
+    xstr_printf(ibuf,"cd .\n");
+    xstr_printf(ibuf,"%s\n",nodetab_setup(nodeno));
+    xstr_printf(ibuf,"if ($status == 1) then\n");
+    xstr_printf(ibuf,"  echo 'this initialization command failed:'\n");
+    xstr_printf(ibuf,"  echo '\"%s\"'\n",nodetab_setup(nodeno));
+    xstr_printf(ibuf,"  echo 'edit your nodes file to fix it.'\n");
+    xstr_printf(ibuf,"  kill -9 $$\n");
+    xstr_printf(ibuf,"endif\n");
+  }
+  
+  if (arg_debug || arg_debug_no_pause) {
+    xstr_printf(ibuf,"cat > /tmp/gdb%08x << END_OF_SCRIPT\n",randno);
+    xstr_printf(ibuf,"shell rm -f /tmp/gdb%08x\n",randno);
+    xstr_printf(ibuf,"set args");
+    while (*argv) { xstr_printf(ibuf," %s",*argv); argv++; }
+    xstr_printf(ibuf,"\n");
+    if (arg_debug_no_pause) xstr_printf(ibuf,"run\n");
+    xstr_printf(ibuf,"END_OF_SCRIPT\n");
+  }
+  
+  if (arg_debug || arg_debug_no_pause) {
+    xstr_printf(ibuf,"$F_XTERM");
+    xstr_printf(ibuf," -T 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
+    xstr_printf(ibuf," -n 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
+    xstr_printf(ibuf," -e $F_GDB %s -x /tmp/gdb%08x",arg_nodeprog_r,randno);
+    xstr_printf(ibuf," < /dev/null >& /dev/null &");
+    xstr_printf(ibuf,"\n");
+  } else if (arg_in_xterm) {
+    xstr_printf(ibuf,"$F_XTERM");
+    xstr_printf(ibuf," -T 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
+    xstr_printf(ibuf," -n 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
+    xstr_printf(ibuf," -e %s", arg_nodeprog_r);
+    while (*argv) { xstr_printf(ibuf," %s",*argv); argv++; }
+    xstr_printf(ibuf," < /dev/null >& /dev/null &");
+    xstr_printf(ibuf,"\n");
+  } else {
+    xstr_printf(ibuf,"%s",arg_nodeprog_r);
+    while (*argv) { xstr_printf(ibuf," %s",*argv); argv++; }
+    xstr_printf(ibuf," < /dev/null >& /dev/null &");
+    xstr_printf(ibuf,"\n");
+  }
+  
+  xstr_printf(ibuf,"echo 'rsh phase successful.'\n");
+  xstr_printf(ibuf,"kill -9 $$\n");
+  
+  prog_flush(p);
+  prog_iclose(p);
+}
+
+
+int start_nodes()
+{
+  prog        rsh_prog[200];
+  int         rsh_node[200];
+  int         rsh_nstarted;
+  int         rsh_nfinished;
+  int         rsh_freeslot;
+  int         rsh_maxsim;
+  fd_set rfds; int i;
+  
+  /* Return immediately.  That way, the nodes which are starting */
+  /* Will be able to establish communication with the host */
+  /* if (fork()) return; */
+  
+  /* Obtain the values from the command line options */
+  rsh_maxsim = arg_maxrsh;
+  if (rsh_maxsim < 1) rsh_maxsim=1;
+  if (rsh_maxsim > nodetab_size) rsh_maxsim=nodetab_size;
+  if (rsh_maxsim > 200) rsh_maxsim=200;
+  
+  /* start initial group of rsh's */
+  for (i=0; i<rsh_maxsim; i++) {
+    prog p = rsh_start(i);
+    if (p==0) { rsh_maxsim=i; break; }
+    rsh_pump(p, i, arg_argv);
+    rsh_prog[i] = p;
+    rsh_node[i] = i;
+  }
+  if (rsh_maxsim==0) { perror("starting rsh"); exit(1); }
+  rsh_nstarted = rsh_maxsim;
+  rsh_nfinished = 0;
+  
+  while (rsh_nfinished < nodetab_size) {
+    int maxfd=0; int ok;
+    FD_ZERO(&rfds);
+    for (i=0; i<rsh_maxsim; i++) {
+      prog p = rsh_prog[i];
+      if (p==0) continue;
+      FD_SET(p->ofd, &rfds);
+      if (p->ofd > maxfd) maxfd = p->ofd;
+    }
+    do ok = select(maxfd+1, &rfds, NULL, NULL, NULL);
+    while ((ok<0)&&(errno==EINTR));
+    if (ok<0) { perror("select"); exit(1); }
+    do ok = waitpid((pid_t)(-1), NULL, WNOHANG);
+    while (ok>=0);
+    for (i=0; i<rsh_maxsim; i++) {
+      char *line = 0;
+      char buffer[1000];
+      int nread, done = 0;
+      prog p = rsh_prog[i];
+      if (p==0) continue;
+      if (!FD_ISSET(p->ofd, &rfds)) continue;
+      do nread = read(p->ofd, buffer, 1000);
+      while ((nread<0)&&(errno==EINTR));
+      if (nread<0) { perror("read"); exit(1); }
+      if (nread==0) {
+       fprintf(stderr,"node %d: rsh phase failed.\n",rsh_node[i]);
+       exit(1);
+      }
+      xstr_write(p->obuf, buffer, nread);
+      while (1) {
+       line = xstr_gets(buffer, 999, p->obuf);
+       if (line==0) break;
+       if (strncmp(line,"[1] ",4)==0) continue;
+       if (arg_debug || arg_debug_no_pause ||
+           (strcmp(line,"rsh phase successful.")
+            &&strcmp(line,"remote responding...")))
+         fprintf(stderr,"node %d: %s\n",rsh_node[i],line);
+       if (strcmp(line,"rsh phase successful.")==0) { done=1; break; }
+      }
+      if (!done) continue;
+      rsh_nfinished++;
+      prog_close(p);
+      rsh_prog[i] = 0;
+      if (rsh_nstarted==nodetab_size) break;
+      p = rsh_start(rsh_nstarted);
+      if (p==0) { perror("starting rsh"); exit(1); }
+      rsh_pump(p, rsh_nstarted, arg_argv);
+      rsh_prog[i] = p;
+      rsh_node[i] = rsh_nstarted;
+      rsh_nstarted++;
+    }
+  }
+}
+
+/****************************************************************************
+ *
+ *  The Main Program
+ *
+ ****************************************************************************/
+
+main(int argc, char **argv) {
+  srand(time(0));
+  /* Compute the values of all constants */
+  arg_init(argc, argv);
+  /* Initialize the node-table by reading nodesfile */
+  nodetab_init();
+  /* Initialize the request-server */
+  req_init();
+  /* Initialize the kill-handler */
+  notify_die_init();
+  /* Initialize the IO module */
+  input_init();
+  /* start the node processes */
+  start_nodes();
+  /* enter request-service mode */
+  req_serve();
+}
+
diff --git a/src/arch/net/machine.c b/src/arch/net/machine.c
new file mode 100644 (file)
index 0000000..f8f4f4d
--- /dev/null
@@ -0,0 +1,1956 @@
+/*****************************************************************************
+ *
+ * Machine-Specific Definitions
+ *
+ ****************************************************************************/
+
+#include "converse.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <setjmp.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <varargs.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <strings.h>
+#include <varargs.h>
+
+#ifdef CMK_NEED_DECLARATION_FOR_STRING_FNS
+char *strdup();
+char *strchr();
+#endif
+
+#ifdef CMK_RSH_IS_A_COMMAND
+#define RSH_CMD "rsh"
+#endif
+#ifdef CMK_RSH_USE_REMSH
+#define RSH_CMD "remsh"
+#endif
+
+#ifdef CMK_STRERROR_USE_SYS_ERRLIST
+extern char *sys_errlist[];
+#define strerror(i) (sys_errlist[i])
+#endif
+
+#ifdef CMK_SIGHOLD_USE_SIGMASK
+int sighold(sig) int sig;
+{ if (sigblock(sigmask(sig)) < 0) return -1;
+  else return 0; }
+int sigrelse(sig) int sig;
+{ if (sigsetmask(sigblock(0)&(~sigmask(sig))) < 0) return -1;
+  else return 0; }
+#endif
+
+static void KillEveryone();
+static void KillEveryoneCode();
+
+#ifdef DEBUG
+#define TRACE(p) p
+#else
+#define TRACE(p)
+#endif
+
+
+/*****************************************************************************
+ *
+ * CmiAlloc, CmiSize, and CmiFree
+ *
+ *****************************************************************************/
+
+static int CmiInsideMem = 1;
+
+void *CmiAlloc(size)
+int size;
+{
+char *res;
+res =(char *)malloc(size+8);
+if (res==0) KillEveryone("Memory allocation failed.");
+((int *)res)[0]=size;
+return (void *)(res+8);
+}
+
+int CmiSize(blk)
+char *blk;
+{
+return ((int *)(blk-8))[0];
+}
+
+void CmiFree(blk)
+char *blk;
+{
+free(blk-8);
+}
+
+/*****************************************************************************
+ *
+ *     Utility routines for network machine interface.
+ *
+ *
+ * Bcopy(char *s1, char *s2, int size)
+ *
+ *    - Temporary bcopy routine.  There seems to be a problem with the
+ *      usual one
+ *
+ * zap_newline(char *s)
+ *
+ *   - Remove the '\n' from the end of a string.
+ *
+ * char *substr(char *lo, char *hi)
+ *
+ *   - return an allocated copy of a string subsequence
+ *
+ * char *skipblanks(char *s)
+ *
+ *   - advance pointer over blank characters
+ *
+ * char *skipstuff(char *s)
+ *
+ *   - advance pointer over nonblank characters
+ *
+ * char *strdupl(char *s)
+ *
+ *   - return a freshly-allocated duplicate of a string
+ *
+ * int my_sendto
+ *     (int s, char *msg, int len, int flags, struct sockaddr *to, int tolen)
+ * 
+ *   - performs a "sendto", automatically retrying on trivial errors.
+ *
+ *****************************************************************************/
+
+
+static void Bcopy (s1,s2,size) char *s1,*s2; int size;
+{
+  int i;
+  for (i=0;i<size;i++) s2[i]=s1[i];
+}
+
+static void zap_newline(s) char *s;
+{
+  char *p;
+  p = s + strlen(s)-1;
+  if (*p == '\n') *p = '\0';
+}
+
+static char *substr(lo, hi) char *lo; char *hi;
+{
+  int len = hi-lo;
+  char *res = (char *)CmiAlloc(1+len);
+  memcpy(res, lo, len);
+  res[len]=0;
+  return res;
+}
+
+static char *skipblanks(p) char *p;
+{
+  while ((*p==' ')||(*p=='\t')||(*p=='\n')) p++;
+  return p;
+}
+
+static char *skipstuff(p) char *p;
+{
+  while ((*p)&&(*p!=' ')&&(*p!='\t')) p++;
+  return p;
+}
+
+static char *readint(p, value) char *p; int *value;
+{
+  int val = 0;
+  while (((*p)==' ')||((*p)=='.')) p++;
+  if (((*p)<'0')||((*p)>'9')) KillEveryone("badly-formed number");
+  while ((*p>='0')&&(*p<='9')) { val*=10; val+=(*p)-'0'; p++; }
+  *value = val;
+  return p;
+}
+
+static char *strdupl(s) char *s;
+{
+  int len = strlen(s);
+  char *res = (char *)CmiAlloc(len+1);
+  strcpy(res, s);
+  return res;
+}
+
+static int my_sendto(s, msg, len, flags, to, tolen)
+int s; char *msg; int len; int flags; struct sockaddr *to; int tolen;
+{
+  int ok;
+  while (1) {
+    ok = sendto(s, msg, len, flags, to, tolen);
+    if (ok>=0) break;
+  }
+  return ok;
+}
+
+static int wait_readable(fd, sec) int fd; int sec;
+{
+  fd_set rfds;
+  struct timeval tmo;
+  int begin, nreadable;
+  
+  begin = time(0);
+  FD_ZERO(&rfds);
+  FD_SET(fd, &rfds);
+ retry:
+  tmo.tv_sec = (time(0) - begin) + sec;
+  tmo.tv_usec = 0;
+  nreadable = select(FD_SETSIZE, &rfds, NULL, NULL, &tmo);
+  if ((nreadable<0)&&(errno==EINTR)) goto retry;
+  if (nreadable == 0) { errno=ETIMEDOUT; return -1; }
+  return 0;
+}
+
+/*****************************************************************************
+ *
+ * Logging Module
+ *
+ *****************************************************************************/
+
+static FILE *outlog_file;
+
+static void outlog_init(outputfile, index) char *outputfile; int index;
+{
+  char fn[MAXPATHLEN];
+  if (outputfile) {
+    sprintf(fn,outputfile,index);
+    outlog_file = fopen(fn,"w");
+  }
+  else outlog_file = 0;
+}
+
+static void outlog_done()
+{
+  fclose(outlog_file);
+}
+
+static void outlog_output(buf) char *buf;
+{
+  if (outlog_file) {
+    fprintf(outlog_file,"%s",buf);
+    fflush(outlog_file);
+  }
+}
+
+/**************************************************************************
+ *
+ * enable_async (enables signal-driven IO on a single descriptor)
+ *
+ **************************************************************************/
+
+#ifdef CMK_ASYNC_USE_SIOCGPGRP_AND_FIOASYNC
+static void enable_async(fd)
+int fd;
+{
+  int pid = getpid();
+  int async = 1;
+  if ( ioctl(fd, SIOCGPGRP, &pid) < 0  ) {
+    CmiError("getting socket owner") ;
+    KillEveryoneCode(65788) ;
+  }
+  if ( ioctl(fd, FIOASYNC, &async) < 0 ) {
+    CmiError("setting socket async") ;
+    KillEveryoneCode(94458) ;
+  }
+}
+#endif
+
+#ifdef CMK_ASYNC_USE_SETOWN_AND_SETFL
+static void enable_async(fd)
+int fd;
+{
+  if ( fcntl(fd, F_SETOWN, getpid()) < 0 ) {
+    CmiError("setting socket owner") ;
+    KillEveryoneCode(8789) ;
+  }
+  if ( fcntl(fd, F_SETFL, FASYNC) < 0 ) {
+    CmiError("setting socket async") ;
+    KillEveryoneCode(28379) ;
+  }
+}
+#endif
+
+#ifdef CMK_SIGNAL_USE_SIGACTION
+static void jsignal(sig, handler)
+int sig;
+void (*handler)();
+{
+  struct sigaction in, out ;
+  in.sa_handler = handler;
+  sigaction(sig, &in, &out);
+}
+#endif
+
+#ifdef CMK_SIGNAL_USE_SIGACTION_AND_SIGEMPTYSET
+static void jsignal(sig, handler)
+int sig;
+void (*handler)();
+{
+  struct sigaction in, out ;
+  in.sa_handler = handler ;
+  sigemptyset(&in.sa_mask);
+  in.sa_flags = SA_RESTART;
+  if(sigaction(sig, &in, &out) == -1)
+      KillEveryone("sigaction failed.");
+}
+#endif
+
+#ifdef CMK_SIGNAL_IS_A_BUILTIN
+static void jsignal(sig, handler)
+int sig;
+void (*handler)();
+{
+  signal(sig, handler) ;
+}
+#endif
+
+/**************************************************************************
+ *
+ * SKT - socket routines
+ *
+ *
+ * void skt_server(unsigned int *ppo, unsigned int *pfd)
+ *
+ *   - create a tcp server socket.  Performs the whole socket/bind/listen
+ *     procedure.  Returns the IP address of the socket (eg, the IP of the
+ *     current machine), the port of the socket, and the file descriptor.
+ *
+ * void skt_datagram(unsigned int *ppo, unsigned int *pfd)
+ *
+ *   - creates a UDP datagram socket.  Performs the whole socket/bind/
+ *     getsockname procedure.  Returns the IP address of the socket (eg,
+ *     the IP address of the current machine), the port of the socket, and
+ *     the file descriptor.
+ *
+ * void skt_accept(int src,
+ *                 unsigned int *pip, unsigned int *ppo, unsigned int *pfd)
+ *
+ *   - accepts a connection to the specified socket.  Returns the
+ *     IP of the caller, the port number of the caller, and the file
+ *     descriptor to talk to the caller.
+ *
+ * int skt_connect(unsigned int ip, int port, int timeout)
+ *
+ *   - Opens a connection to the specified server.  Returns a socket for
+ *     communication.
+ *
+ *
+ **************************************************************************/
+
+static void skt_server(ppo, pfd)
+unsigned int *ppo;
+unsigned int *pfd;
+{
+  int fd= -1;
+  int ok, len;
+  struct sockaddr_in addr;
+  
+  retry: fd = socket(PF_INET, SOCK_STREAM, 0);
+  if ((fd<0)&&(errno==EINTR)) goto retry;
+  if (fd < 0) { perror("socket"); KillEveryoneCode(93483); }
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  ok = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+  if (ok < 0) { perror("bind"); KillEveryoneCode(22933); }
+  ok = listen(fd,5);
+  if (ok < 0) { perror("listen"); KillEveryoneCode(3948); }
+  len = sizeof(addr);
+  ok = getsockname(fd, (struct sockaddr *)&addr, &len);
+  if (ok < 0) { perror("getsockname"); KillEveryoneCode(93583); }
+
+  *pfd = fd;
+  *ppo = ntohs(addr.sin_port);
+}
+
+static void skt_datagram(ppo, pfd)
+unsigned int *ppo;
+unsigned int *pfd;
+{
+  struct sockaddr_in name;
+  int length, ok, skt;
+
+  /* Create data socket */
+  retry: skt = socket(AF_INET,SOCK_DGRAM,0);
+  if ((skt<0)&&(errno==EINTR)) goto retry;
+  if (skt < 0)
+    { perror("socket"); KillEveryoneCode(8934); }
+  name.sin_family = AF_INET;
+  name.sin_port = 0;
+  name.sin_addr.s_addr = htonl(INADDR_ANY);
+  if (bind(skt, (struct sockaddr *)&name, sizeof(name)) == -1)
+    { perror("binding data socket"); KillEveryoneCode(2983); }
+  length = sizeof(name);
+  if (getsockname(skt, (struct sockaddr *)&name , &length))
+    { perror("getting socket name"); KillEveryoneCode(39483); }
+  *pfd = skt;
+  *ppo = htons(name.sin_port);
+}
+
+static void skt_accept(src, pip, ppo, pfd)
+int src;
+unsigned int *pip;
+unsigned int *ppo;
+unsigned int *pfd;
+{
+  int i, fd, ok;
+  struct sockaddr_in remote;
+  i = sizeof(remote);
+ acc:
+  fd = accept(src, (struct sockaddr *)&remote, &i);
+  if ((fd<0)&&(errno==EINTR)) goto acc;
+  if (fd<0) { perror("accept"); KillEveryoneCode(39489); }
+  *pip=htonl(remote.sin_addr.s_addr);
+  *ppo=htons(remote.sin_port);
+  *pfd=fd;
+}
+
+static int skt_connect(ip, port, seconds)
+unsigned int ip; int port; int seconds;
+{
+  struct sockaddr_in remote; short sport=port;
+  int fd, ok, len, retry, begin;
+    
+  /* create an address structure for the server */
+  memset(&remote, 0, sizeof(remote));
+  remote.sin_family = AF_INET;
+  remote.sin_port = htons(sport);
+  remote.sin_addr.s_addr = htonl(ip);
+    
+  begin = time(0);
+  while (time(0)-begin < seconds) {
+  sock:
+    fd = socket(AF_INET, SOCK_STREAM, 0);
+    if ((fd<0)&&(errno==EINTR)) goto sock;
+    if (fd < 0) { perror("socket"); exit(1); }
+    
+  conn:
+    ok = connect(fd, (struct sockaddr *)&(remote), sizeof(remote));
+    if ((ok<0)&&(errno==EINTR)) { close(fd); goto sock; }
+    if ((ok<0)&&(errno==EADDRINUSE)) { close(fd); goto sock; }
+    if (ok>=0) break;
+    if (errno!=ECONNREFUSED) break;
+    
+    sleep(1);
+  }
+  if (ok<0) {
+    perror("connect"); exit(1);
+  }
+  return fd;
+}
+
+/******************************************************************************
+ *
+ * CmiTimer
+ *
+ *****************************************************************************/
+
+#ifdef CMK_TIMER_USE_TIMES
+
+static struct tms inittime;
+
+static void CmiTimerInit()
+{
+  times(&inittime);
+}
+
+double CmiTimer()
+{
+  double currenttime;
+  int clk_tck;
+    struct tms temp;
+
+    times(&temp);
+    clk_tck=sysconf(_SC_CLK_TCK);
+    currenttime = 
+     (((temp.tms_utime - inittime.tms_utime)+
+       (temp.tms_stime - inittime.tms_stime))*1.0)/clk_tck;
+    return (currenttime);
+}
+
+#endif
+
+#ifdef CMK_TIMER_USE_GETRUSAGE
+
+static struct rusage inittime;
+
+static void CmiTimerInit()
+{
+  getrusage(0, &inittime); 
+}
+
+double CmiTimer() {
+  double currenttime;
+
+  struct rusage temp;
+  getrusage(0, &temp);
+  currenttime =
+    (temp.ru_utime.tv_usec - inittime.ru_utime.tv_usec) * 0.000001+
+      (temp.ru_utime.tv_sec - inittime.ru_utime.tv_sec) +
+       (temp.ru_stime.tv_usec - inittime.ru_stime.tv_usec) * 0.000001+
+         (temp.ru_stime.tv_sec - inittime.ru_stime.tv_sec) ; 
+  
+  return (currenttime);
+}
+
+#endif
+
+/*****************************************************************************
+ *
+ * Readonly Data
+ *
+ * Note that the default resend-wait and resend-fail are 10 and 600000
+ * milliseconds, respectively. Both are set very high, to
+ * ameliorate a known bug in the machine version.  If an entry-point is
+ * executing a CmiScanf, then it won't acknowledge messages.  To everyone
+ * else, it appears dead.  Therefore, the default_resend_fail is set very
+ * high to keep things going during long CmiScanfs.  (You have 10 minutes to
+ * respond).
+ *
+ *****************************************************************************/
+
+static int    resend_wait;        /* millisecs to wait before re-sending. */
+static int    resend_fail;        /* millisecs to wait before giving up. */
+static int    Cmi_enableinterrupts;
+static char   Topology;
+static char  *outputfile;
+
+int    Cmi_mype;
+int    Cmi_numpe;
+
+static int    host_IP;
+static char   host_IP_str[16];
+static int    host_port;
+static int    self_IP;
+static char   self_IP_str[16];
+static int    ctrl_port, ctrl_skt;
+static int    data_port, data_skt;
+
+#define MAX_NODES 100
+
+typedef struct {
+   int IP;
+   int dataport;
+   int ctrlport;
+} node_info;
+
+/* Information table about host and other nodes. */
+static node_info node_table[MAX_NODES];
+static int       node_table_fill;
+
+
+static void ParseNetstart()
+{
+  char *ns;
+  int nread;
+  ns = getenv("NETSTART");
+  if (ns==0) goto abort;
+  nread = sscanf(ns, "%d%d%d%d%d",
+                &Cmi_mype,&Cmi_numpe,&self_IP,&host_IP,&host_port);
+  if (nread!=5) goto abort;
+  return;
+ abort:
+  fprintf(stderr,"program not started using NETSTART utility. aborting.\n");
+  exit(1);
+}
+
+static char *DeleteArg(argv)
+char **argv;
+{
+  char *res = argv[0];
+  if (res==0) KillEveryone("Illegal Arglist");
+  while (*argv) { argv[0]=argv[1]; argv++; }
+  return res;
+}
+
+static void ExtractArgs(argv)
+char **argv;
+{
+  resend_wait = 10;
+  resend_fail = 600000;
+  Cmi_enableinterrupts = 1;
+  Topology = 'F';
+  outputfile = NULL;
+
+  while (*argv) {
+    if (strcmp(*argv,"++resend-wait")==0) {
+      DeleteArg(argv); resend_wait = atoi(DeleteArg(argv));
+    } else
+    if (strcmp(*argv,"++resend-fail")==0) {
+      DeleteArg(argv); resend_fail = atoi(DeleteArg(argv));
+    } else
+    if (strcmp(*argv,"++no-interrupts")==0) {
+      DeleteArg(argv); Cmi_enableinterrupts=0;
+    } else
+    if (strcmp(*argv,"++topology")==0) {
+      DeleteArg(argv); Topology=DeleteArg(argv)[0];
+    } else
+    if (strcmp(*argv,"++outputfile")==0) {
+      DeleteArg(argv); outputfile=DeleteArg(argv);
+    } else
+    argv++;
+  }
+}
+
+static void InitializePorts()
+{
+  skt_datagram(&data_port, &data_skt);
+  skt_server(&ctrl_port, &ctrl_skt);
+  
+  sprintf(self_IP_str,"%d.%d.%d.%d",
+         (self_IP>>24)&0xFF,(self_IP>>16)&0xFF,
+         (self_IP>>8)&0xFF,self_IP&0xFF);
+  sprintf(host_IP_str,"%d.%d.%d.%d",
+         (host_IP>>24)&0xFF,(host_IP>>16)&0xFF,
+         (host_IP>>8)&0xFF,host_IP&0xFF);
+}
+
+/****************************************************************************
+ *                                                                          
+ * Fast shutdown                                                            
+ *                                                                          
+ ****************************************************************************/
+
+static int KillIndividual(cmd, ip, port, sec)
+char *cmd; unsigned int ip; unsigned int port; int sec;
+{
+  int fd;
+  fd = skt_connect(ip, port, sec);
+  if (fd<0) return -1;
+  write(fd, cmd, strlen(cmd));
+  close(fd);
+  return 0;  
+}
+
+static void KillEveryone(msg)
+char *msg;
+{
+  char buffer[1024]; int i;
+  sprintf(buffer,"die %s",msg);
+  KillIndividual(buffer, host_IP, host_port, 30);
+  for (i=0; i<Cmi_numpe; i++)
+    KillIndividual(buffer, node_table[i].IP, node_table[i].ctrlport, 3);
+  exit(1);
+}
+
+static void KillEveryoneCode(n)
+int n;
+{
+  char buffer[1024];
+  sprintf(buffer,"Internal error #%d (node %d)\n(Contact CHARM developers)\n", n,Cmi_mype);
+  KillEveryone(buffer);
+}
+
+static void KillOnSegv()
+{
+  char buffer[1024];
+  sprintf(buffer, "Node %d: Segmentation fault.\n",Cmi_mype);
+  KillEveryone(buffer);
+}
+
+static void KillOnIntr()
+{
+  char buffer[1000];
+  sprintf(buffer, "Node %d: Interrupted.\n",Cmi_mype);
+  KillEveryone(buffer);
+}
+
+static void KillInit()
+{
+  signal(SIGSEGV, KillOnSegv);
+  signal(SIGBUS,  KillOnSegv);
+  signal(SIGILL,  KillOnSegv);
+  signal(SIGABRT, KillOnSegv);
+  signal(SIGFPE,  KillOnSegv);
+
+#ifdef SIGSYS
+  signal(SIGSYS,  KillOnSegv);
+#endif
+
+  signal(SIGPIPE, KillOnSegv);
+  signal(SIGURG,  KillOnSegv);
+
+  signal(SIGTERM, KillOnIntr);
+  signal(SIGQUIT, KillOnIntr);
+  signal(SIGINT,  KillOnIntr);
+}
+
+/****************************************************************************
+ *
+ * ctrl_getone
+ *
+ * Receive a command (on the control socket) from the host or another node,
+ * and process it.  This is just a dispatcher, none of the actual processing
+ * is done here.
+ *
+ ****************************************************************************/
+
+static void ctrl_sendone(va_alist) va_dcl
+{
+  char buffer[1024];
+  char *f; int fd, delay;
+  va_list p;
+  va_start(p);
+  delay = va_arg(p, int);
+  f = va_arg(p, char *);
+  vsprintf(buffer, f, p);
+  fd = skt_connect(host_IP, host_port, delay);
+  if (fd<0) KillEveryone("cannot contact host");
+  write(fd, buffer, strlen(buffer));
+  shutdown(fd, 1);
+  while (read(fd, buffer, 1023)>0);
+  close(fd);
+}
+
+static char *scanf_data;
+static int all_done = 0;
+static void node_addresses_store();
+
+static void ctrl_getone()
+{
+  char line[10000];
+  int ok, ip, port, fd;  FILE *f;
+  skt_accept(ctrl_skt, &ip, &port, &fd);
+  f = fdopen(fd,"r");
+  while (fgets(line, 9999, f)) {
+    if      (strncmp(line,"aval addr ",10)==0) node_addresses_store(line);
+    else if (strncmp(line,"aval done ",10)==0) all_done = 1;
+    else if (strncmp(line,"scanf-data ",11)==0) scanf_data=strdup(line+11);
+    else if (strncmp(line,"die ",4)==0) {
+      fprintf(stderr,"aborting: %s\n",line+4);
+      exit(0);
+    }
+    else KillEveryoneCode(2932);
+  }
+  fclose(f);
+  close(fd);
+}
+
+/*****************************************************************************
+ *
+ * node_addresses
+ *
+ *  These two functions fill the node-table.
+ *
+ *
+ *   This node, like all others, first sends its own address to the host
+ *   using this command:
+ *
+ *     aset addr <my-nodeno> <my-ip-addr>.<my-ctrlport>.<my-dataport>
+ *
+ *   Then requests all addresses from the host using this command:
+ *
+ *     aget <my-ip-addr> <my-ctrlport> addr 0 <numnodes>
+ *
+ *   when the host has all the addresses, he sends a table to me:
+ *
+ *     aval addr <ip-addr-0>.<ctrlport-0>.<dataport-0> ...
+ *
+ *****************************************************************************/
+
+static void node_addresses_receive()
+{
+  ctrl_sendone(120, "aset addr %d %s.%d.%d\n",
+              Cmi_mype, self_IP_str, ctrl_port, data_port);
+  ctrl_sendone(120, "aget %s %d addr 0 %d\n",
+    self_IP_str,ctrl_port,Cmi_numpe-1);
+  while (node_table_fill != Cmi_numpe) {
+    if (wait_readable(ctrl_skt, 300)<0)
+      { perror("waiting for data"); KillEveryoneCode(21323); }
+    ctrl_getone();
+  }
+}
+
+static void node_addresses_store(addrs) char *addrs;
+{
+  char *p, *e; int i, lo, hi;
+  if (strncmp(addrs,"aval addr ",10)!=0) KillEveryoneCode(83473);
+  p = skipblanks(addrs+10);
+  p = readint(p,&lo);
+  p = readint(p,&hi);
+  if ((lo!=0)||(hi!=Cmi_numpe-1)) KillEveryoneCode(824793);
+  for (i=0; i<Cmi_numpe; i++) {
+    unsigned int ip0,ip1,ip2,ip3,cport,dport;
+    p = readint(p,&ip0);
+    p = readint(p,&ip1);
+    p = readint(p,&ip2);
+    p = readint(p,&ip3);
+    p = readint(p,&cport);
+    p = readint(p,&dport);
+    node_table[i].IP = (ip0<<24)+(ip1<<16)+(ip2<<8)+ip3;
+    node_table[i].ctrlport = cport;
+    node_table[i].dataport = dport;
+  }
+  p = skipblanks(p);
+  if (*p!=0) KillEveryoneCode(82283);
+  node_table_fill = Cmi_numpe;
+}
+
+/*****************************************************************************
+ *
+ * CmiPrintf, CmiError, CmiScanf
+ *
+ *****************************************************************************/
+
+static void InternalPrintf(buf) char *buf; 
+{
+  char *p;
+  outlog_output(buf);
+  while (*buf) {
+    p = strchr(buf, '\n');
+    if (p) {
+      *p=0; ctrl_sendone(120, "print %s\n", buf);
+      *p='\n'; buf=p+1;
+    } else {
+      ctrl_sendone(120, "princ %s\n", buf); 
+      break;
+    }
+  }
+}
+
+static void InternalError(buf) char *buf;
+{
+  char *p;
+  outlog_output(buf);
+  while (*buf) {
+    p = strchr(buf, '\n');
+    if (p) {
+      *p=0; ctrl_sendone(120, "printerr %s\n", buf);
+      *p='\n'; buf = p+1;
+    } else {
+      ctrl_sendone(120, "princerr %s\n", buf); 
+      break;
+    }
+  }
+}
+
+void CmiPrintf(va_alist) va_dcl
+{
+  char buffer[8192];
+  va_list p;
+  char *f;
+  va_start(p);
+  f = va_arg(p, char *);
+  vsprintf(buffer, f, p);
+  InternalPrintf(buffer);
+}
+
+void CmiError(va_alist) va_dcl
+{
+  char buffer[8192];
+  va_list p;
+  char *f;
+  va_start(p);
+  f = va_arg(p, char *);
+  vsprintf(buffer, f, p);
+  InternalError(buffer);
+}
+
+int CmiScanf(va_alist) va_dcl
+{
+  static int CmiProbe();
+  char *ptr[20];
+  char *fmt; char *p; int nargs, i;
+  va_list l;
+  va_start(l);
+  fmt = va_arg(l, char *);
+  nargs=0;
+  p=fmt;
+  while (*p) {
+    if ((p[0]=='%')&&(p[1]=='*')) { p+=2; continue; }
+    if ((p[0]=='%')&&(p[1]=='%')) { p+=2; continue; }
+    if (p[0]=='%') { nargs++; p++; continue; }
+    if (*p=='\n') *p=' '; p++;
+  }
+  if (nargs > 18) KillEveryone("CmiScanf only does 18 args.\n");
+  for (i=0; i<nargs; i++) ptr[i]=va_arg(l, char *);
+  ctrl_sendone(120, "scanf %s %d %s", self_IP_str, ctrl_port, fmt);
+  while (scanf_data==0) CmiProbe();
+  i = sscanf(scanf_data, fmt, 
+        ptr[ 0], ptr[ 1], ptr[ 2], ptr[ 3], ptr[ 4], ptr[ 5],
+        ptr[ 6], ptr[ 7], ptr[ 8], ptr[ 9], ptr[10], ptr[11],
+        ptr[12], ptr[13], ptr[14], ptr[15], ptr[16], ptr[17]);
+  CmiFree(scanf_data);
+  scanf_data=0;
+  return i;
+}
+
+/*****************************************************************************
+ *
+ * Statistics Variables
+ *
+ *****************************************************************************/
+
+static int NumIntr;
+static int NumIntrCalls;
+static int NumOutsideMc;
+static int NumRetransmits;
+static int NumAcksSent;
+static int NumUseless;
+static int NumSends;
+
+/*****************************************************************************
+ *                                                                           
+ * Neighbour-Lookup functions.                                               
+ *                                                                           
+ * the neighbour information is computed dynamically.  It is computed solely 
+ * from the value of the Topology variable and the Cmi_numpe.             
+ *                                                                           
+ *****************************************************************************/
+
+int CmiNumNeighbours(node)
+     int node;
+{
+  switch (Topology) {
+  case 'F': case 'f':          /* Full interconnectivity */
+    return Cmi_numpe-1;
+  default: KillEveryoneCode(233);
+  }
+}
+
+void CmiGetNodeNeighbours(node, nghbrs)
+     int node; int *nghbrs;
+{
+  int i;
+  switch (Topology) {
+  case 'F': case 'f':          /* Full interconnectivity */
+    for (i=0; i<node; i++) *nghbrs++ = i;
+    for (i=node+1; i<Cmi_numpe; i++) *nghbrs++ = i;
+    break;
+  default: KillEveryoneCode(234);
+  }
+}
+
+int CmiNeighboursIndex(PeNum, neighbourPeNum)
+     int PeNum; int neighbourPeNum;
+{
+  int i=0;
+  switch (Topology) {
+  case 'F': case 'f':          /* Full interconnectivity */
+    if (neighbourPeNum < PeNum) return neighbourPeNum;
+    return neighbourPeNum-1;
+    break;
+  default: KillEveryoneCode(235);
+  }
+}
+
+/*****************************************************************************
+ *
+ * Datagram Transmission Definitions
+ *
+ *****************************************************************************/
+
+/* Types of messages. */
+# define SEND  1
+# define ACK   2
+
+typedef unsigned char BYTE;
+
+/* In bytes.  Make sure this is greater than zero! */
+/* Works out to be about 2018 bytes. */
+# define MAX_FRAG_SIZE (CMK_MAX_DGRAM_SIZE - sizeof(DATA_HDR))
+
+/* Format of the header sent with each fragment. */
+typedef struct DATA_HDR
+{
+  unsigned int seq_num;
+  BYTE send_or_ack;            /* SEND or ACK (acknowledgment). */
+  BYTE msg_type;               /* Currently, always 1. */
+  unsigned int SourcePeNum;
+  unsigned int DestPeNum;
+  unsigned int numfrags;
+  unsigned int size;           /* size of message, not including header. */
+  unsigned int full_size;      /* Size of complete message */
+}
+DATA_HDR;
+
+/* Header combined with data fragment. */
+typedef struct msgspace
+{
+  DATA_HDR hd;
+  char data[CMK_MAX_DGRAM_SIZE-sizeof(DATA_HDR)];
+}
+msgspace;
+
+typedef struct
+{
+  DATA_HDR        *packet;
+  unsigned int     seq_num;
+  int              send_time;
+}
+WindowElement;
+
+typedef struct pkt_queue_elem
+{
+  DATA_HDR *packet;
+  struct pkt_queue_elem *nextptr;
+}
+PacketQueueElem;
+
+typedef struct msg_queue_elem
+{
+  PacketQueueElem *packetlist;
+  struct msg_queue_elem *nextptr;
+}
+MsgQueueElem;
+
+typedef struct new_msg
+{
+  int numpackets;
+  PacketQueueElem *packetlist;
+}
+NewMessage;
+
+#define WINDOW_SIZE 16             /* size of sliding window  */
+
+#define MAX_SEQ_NUM 0xFFFFFFFF     /* 2^32 - 1 */
+
+static int Cmi_insidemachine;
+
+static int free_ack=0;
+static int free_send=0;
+static int alloc_ack=0;
+static int alloc_send=0;
+
+static int Communication_init; /* Communication set up yet? */
+
+
+static WindowElement **send_window;       /* packets awaiting acks  */
+
+static PacketQueueElem **transmit_head;   /* packets awaiting transmission */
+static PacketQueueElem **transmit_tail; 
+                                                   
+
+static int *first_window_index;     
+static int *last_window_index;     
+static int *cur_window_size;
+static unsigned int  *next_seq_num;
+static int *timeout_factor ;
+
+static WindowElement **recv_window;    /* packets awaiting acks  */
+
+static int *next_window_index;         /* index of 1st entry in recv window */
+static unsigned int *expected_seq_num; /* next sequence number expected */
+
+static NewMessage *recd_messages;
+
+static int *needack;
+
+static DATA_HDR ack;
+
+static MsgQueueElem *recd_msg_head, *recd_msg_tail;
+
+
+/****************************************************************************/
+/* ROUTINES FOR SENDING/RECEIVING MESSAGES
+**
+** Definition of terms:
+** Synchronized send -- The send doesn't return until the buffer space of
+**  the data sent is free for re-use, that is, until a write to that buffer
+**  space will not cause the message being sent to be disrupted or altered
+**  in any way.
+**
+** Synchronized receive -- The receive doesn't return until all of the data
+**  has been placed in the receiving buffer.
+**
+** -CW
+*/
+/****************************************************************************/
+
+
+/* Send an acknowledging message to the source PE named in the message header.
+** The acknowledgement has the same header, except that the message type is
+** changed to ACK. (So, the "size" field in the header will be
+** incorrect for ACK's).
+*/
+static void send_ack(packet) 
+    DATA_HDR *packet; 
+    {
+    node_info *dest = node_table + packet->SourcePeNum;
+    struct sockaddr_in addr;
+    addr.sin_family      = AF_INET;
+    addr.sin_port        = htons(dest->dataport);
+    addr.sin_addr.s_addr = htonl(dest->IP);
+    NumSends++;
+    my_sendto(data_skt, (char *)packet, sizeof(DATA_HDR), 0, (struct sockaddr *)&addr, sizeof(addr));
+    }
+
+
+static char *
+msg_tuple(PeNum,msgid,ack_or_send) int PeNum,msgid,ack_or_send; {
+   static char buf[100];
+   char type;
+
+   switch(ack_or_send) {
+   case ACK:type='A';
+      break;
+   case SEND:type='S';
+      break;
+   default:type='?';
+      break;
+   }
+   sprintf(buf,"(%d,%d,%c)",PeNum,msgid,type);
+   return buf;
+}
+
+
+
+/* This section implements a send sliding window protocol for the IPnet 
+   implementation of the Chare kernel. The modification to Chris Walquist's 
+   implementation are as follows:
+
+   1) The sends are not synchronous, i.e. every pack is not acknowledged before
+      the next packet is sent. Instead, packets are sent until WINDOW_SIZE 
+      packets remain unacknowledged.
+
+   2) An ack packet with sequence number N acknowledges all packets upto and
+      including N. Thus, it is not necessary for all packets to be explicitly
+      acknowledged.
+
+   3) After the sends have been completed, no waits are performed. Instead,
+      execution of the Loop resumes. During each pump message phase of the 
+      loop, the sliding window is updated as and when ack packets are received.
+
+   4) One send window per destination is necessary for sequence numbers of
+      acks to be used as required in (2).
+
+              Questions, Comments and Criticisms to be directed to
+
+                        Balkrishna Ramkumar
+                       ramkumar@crhc.uiuc.edu
+
+*/
+   
+      
+static void SendWindowInit()
+{
+    int i,j;
+    int numpe = Cmi_numpe;
+    int mype = Cmi_mype;
+
+    send_window = (WindowElement **) CmiAlloc(numpe * sizeof(WindowElement *));
+    transmit_head = (PacketQueueElem **) CmiAlloc(numpe * sizeof(PacketQueueElem *));
+    transmit_tail = (PacketQueueElem **) CmiAlloc(numpe * sizeof(PacketQueueElem *));
+    first_window_index = (int *) CmiAlloc(numpe * sizeof(int));
+    last_window_index = (int *) CmiAlloc(numpe * sizeof(int));
+    cur_window_size = (int *) CmiAlloc(numpe * sizeof(int));
+    next_seq_num = (unsigned int  *) CmiAlloc(numpe * sizeof(unsigned int ));
+/* Sanjeev */
+    timeout_factor = (int *)CmiAlloc(numpe * sizeof(int)) ;
+
+    for (i = 0; i < numpe; i++)
+    {
+       if (i != mype)
+       {
+           send_window[i] = (WindowElement *) CmiAlloc(WINDOW_SIZE * sizeof(WindowElement));
+           for (j = 0; j < WINDOW_SIZE; j++)
+           {
+               send_window[i][j].packet = NULL;
+               send_window[i][j].seq_num = 0;
+               send_window[i][j].send_time = 0;
+           }
+       }
+       else send_window[i] = NULL;  /* never used */
+
+       first_window_index[i] = 0;
+       last_window_index[i] = 0;
+       cur_window_size[i] = 0;
+       next_seq_num[i] = 0;
+       transmit_head[i] = NULL;
+       transmit_tail[i] = NULL;
+    /* Sanjeev */
+       timeout_factor[i] = 1 ;
+    }
+}
+
+/* This routine adds a packet to the tail of the transmit queue */
+
+static void InsertInTransmitQueue(packet, destpe)
+DATA_HDR *packet;
+int destpe;
+{
+    PacketQueueElem *newelem;
+
+    newelem = (PacketQueueElem *) CmiAlloc(sizeof(PacketQueueElem));
+    newelem->packet = packet;
+    newelem->nextptr = NULL;
+    if  (transmit_tail[destpe] == NULL)
+        transmit_head[destpe] = newelem;
+    else transmit_tail[destpe]->nextptr = newelem;
+    transmit_tail[destpe] = newelem;
+}
+
+
+/* This routine returns the packet at the head of the transmit queue. If no
+   packets exist, NULL is returned */
+
+static DATA_HDR *GetTransmitPacket(destpe)
+int destpe;
+{
+    PacketQueueElem *elem;
+    DATA_HDR *packet;
+
+    if  (transmit_head[destpe] == NULL)
+        return NULL;
+    else 
+    {
+       elem = transmit_head[destpe];
+       transmit_head[destpe] = transmit_head[destpe]->nextptr;
+       if (transmit_head[destpe] == NULL)
+           transmit_tail[destpe] = NULL;
+       packet = elem->packet;
+       CmiFree(elem);
+       return packet;
+    }
+}
+
+/* This routine adds the packet to the send window. If the addition is
+   successful, the function returns TRUE. If the window is full, it returns
+   FALSE - the calling function will then have to insert the packet into 
+   the transmit queue */
+
+static int AddToSendWindow(packet, destpe)
+DATA_HDR *packet;
+int destpe;
+{
+    send_window[destpe][last_window_index[destpe]].packet =  packet;
+    send_window[destpe][last_window_index[destpe]].seq_num = next_seq_num[destpe];
+    send_window[destpe][last_window_index[destpe]].send_time = CmiTimer()*1000;
+    packet->seq_num = next_seq_num[destpe];
+    next_seq_num[destpe]++;
+    last_window_index[destpe] = (last_window_index[destpe] + 1) % WINDOW_SIZE;
+    cur_window_size[destpe]++;
+    return TRUE;
+}
+
+static SendPackets(destpe)
+int destpe;
+{
+    DATA_HDR *GetTransmitPacket();
+    DATA_HDR *packet;
+    int bytes_sent;
+    int i;
+    struct sockaddr_in addr;
+
+    while (cur_window_size[destpe] < WINDOW_SIZE &&
+          ((packet = GetTransmitPacket(destpe)) != NULL))
+    {
+       AddToSendWindow(packet, destpe);
+       TRACE(CmiPrintf("Node %d: sending packet seq_num=%d, num_frags=%d fullsize=%d\n",
+                      Cmi_mype,
+                      packet->seq_num, packet->numfrags, 
+                      packet->full_size));
+
+        addr.sin_family      = AF_INET;
+        addr.sin_port        = htons(node_table[destpe].dataport);
+        addr.sin_addr.s_addr = htonl(node_table[destpe].IP);
+
+        NumSends++ ;
+       bytes_sent = my_sendto(data_skt, (char *)packet,
+                           packet->size + sizeof(DATA_HDR),
+                           0, (struct sockaddr *)&addr, sizeof(addr));
+       /* if (bytes_sent != packet->size + sizeof(DATA_HDR)) KillEveryoneCode(21); */
+    }
+}
+
+/* This routine updates the send window upon receipt of an ack. Old acks
+   are ignored */
+
+static UpdateSendWindow(ack, sourcepe)
+DATA_HDR *ack;
+int sourcepe;
+{
+    int i, index;
+    int found;
+    int count;
+
+    if (cur_window_size[sourcepe] == 0)  /* empty window */
+        return;
+
+    index = first_window_index[sourcepe];
+    found = FALSE;
+    count = 0;
+    while (count < cur_window_size[sourcepe] && !found) 
+    {
+       found = (send_window[sourcepe][index].seq_num == ack->seq_num);
+       index = (index + 1) % WINDOW_SIZE;
+       count++;
+    }
+    if (found)
+    {
+       TRACE(CmiPrintf("Node %d: received ack with seq_num %d\n",
+                      Cmi_mype, ack->seq_num)); 
+       index = first_window_index[sourcepe];
+       for (i = 0; i < count; i++)
+       {
+           CmiFree(send_window[sourcepe][index].packet);
+           send_window[sourcepe][index].packet = NULL;
+           index = (index + 1) % WINDOW_SIZE;
+       }
+        first_window_index[sourcepe] = index;
+       cur_window_size[sourcepe] -= count;
+    }
+    SendPackets(sourcepe);   /* any untransmitted pkts */
+}
+
+/* This routine extracts a packet with a given sequence number. It returns
+   NULL if no packet with the given sequence number exists in the window 
+   This will be used primarily if retransmission is required - the packet 
+   is not removed from the window */
+
+static int RetransmitPackets()
+{
+  int i, index, fnord;
+  DATA_HDR *packet;
+  struct sockaddr_in addr;
+  int sending=0;
+
+  for (i = 0; i < Cmi_numpe; i++) {
+    index = first_window_index[i];
+    if (cur_window_size[i] > 0) {
+      sending = 1;
+      if ((CmiTimer()*1000 - send_window[i][index].send_time) > 
+         (resend_wait * timeout_factor[i])) {
+       /* timeout_factor[i] *= 2 ;  for exponential backoff */
+       if (resend_wait * timeout_factor[i] > resend_fail) {
+         KillEveryone("retransmission failed, timeout.");
+       }
+       packet = send_window[i][index].packet;
+       addr.sin_family      = AF_INET;
+       addr.sin_port        = htons(node_table[i].dataport);
+       addr.sin_addr.s_addr = htonl(node_table[i].IP);
+       
+       NumRetransmits++ ;
+       NumSends++;
+       my_sendto(data_skt, (char *)packet,
+                 packet->size + sizeof(DATA_HDR), 0, (struct sockaddr *)&addr, sizeof(addr)); 
+         send_window[i][index].send_time = CmiTimer() * 1000;
+      }
+    }
+  }
+  return sending;
+}
+
+
+static void fragment_send(destPE,size,msg,full_size,msg_type, numfrags)
+     int destPE;
+     int size;
+     char *msg; 
+     int full_size; 
+     int msg_type; 
+     int numfrags;
+{
+  int send_timeout();
+  int bytes_sent=0;
+  DATA_HDR *hd;
+  
+  /* Is datagram too small to hold fragment and data header? */ 
+  if (MAX_FRAG_SIZE + sizeof(DATA_HDR) > CMK_MAX_DGRAM_SIZE)
+    KillEveryoneCode(5);
+  
+  TRACE(CmiPrintf("Node %d: sending fragment. fragsize=%d msgsize=%d\n", 
+                 Cmi_mype, size, full_size));
+  
+  
+  /* Initialize the data header part of the send space. */
+  hd = (DATA_HDR *)CmiAlloc(sizeof(DATA_HDR) + size);
+  if ( hd == NULL ) {
+    CmiPrintf("*** ERROR *** Memory Allocation Failed.\n");
+    return ;
+  }
+  hd->DestPeNum = destPE;
+  hd->size = size;
+  hd->full_size = full_size;
+  hd->msg_type = msg_type;
+  hd->send_or_ack = SEND;
+  hd->SourcePeNum = Cmi_mype;
+  hd->numfrags = numfrags;
+  
+  /* Transfer the data to the data part of the send space. */
+  Bcopy(msg, (hd + 1), size);
+  InsertInTransmitQueue(hd, destPE);
+}
+
+
+/* This section implements a receive sliding window protocol for the IPnet 
+   implementation of the Chare kernel. The modification to Chris Walquist's 
+   implementation are as follows:
+
+   1) An ack packet with sequence number N acknowledges all packets upto and
+      including N. Thus, it is not necessary for all packets to be explicitly
+      acknowledged.
+
+   2) The sliding window will guarantee that packets are delivered in order
+      once successfully received. 
+
+   3) One receive window per sender is necessary.
+
+              Questions, Comments and Criticisms to be directed to
+
+                        Balkrishna Ramkumar
+                       ramkumar@crhc.uiuc.edu
+*/
+   
+
+static RecvWindowInit()
+{
+    int i,j;
+    int numpe = Cmi_numpe;
+    int mype = Cmi_mype;
+
+    recv_window = (WindowElement **) CmiAlloc(numpe * sizeof(WindowElement *));
+    next_window_index = (int *) CmiAlloc(numpe * sizeof(int));
+    expected_seq_num = (unsigned int *) CmiAlloc(numpe * sizeof(unsigned int));
+    recd_messages = (NewMessage *) CmiAlloc(numpe * sizeof(NewMessage));
+    needack = (int *) CmiAlloc(numpe * sizeof(int));
+    for (i = 0; i < numpe; i++)
+    {
+       if (i != mype)
+       {
+           recv_window[i] = (WindowElement *) CmiAlloc(WINDOW_SIZE * sizeof(WindowElement));
+           for (j = 0; j < WINDOW_SIZE; j++)
+           {
+               recv_window[i][j].packet = NULL;
+               recv_window[i][j].seq_num = 0;
+               recv_window[i][j].send_time = 0;
+           }
+       }
+       else recv_window[i] = NULL;  /* never used */
+
+       next_window_index[i] = 0;
+       expected_seq_num[i] = 0;
+       recd_messages[i].numpackets = 0;
+       recd_messages[i].packetlist = NULL;
+       needack[i] = FALSE;
+    }
+    recd_msg_head = NULL;
+    recd_msg_tail = NULL;
+
+    ack.DestPeNum = Cmi_mype;
+    ack.send_or_ack = ACK;
+}
+
+
+
+
+/* This routine tries to add an incoming packet to the recv window. 
+   If the packet has already been received, the routine discards it and
+   returns FALSE. Otherwise the routine inserts it into the window and
+   returns TRUE
+*/
+
+static int AddToReceiveWindow(packet, sourcepe)
+     DATA_HDR *packet;
+     int sourcepe;
+{
+  int index;
+  unsigned int seq_num = packet->seq_num;
+  unsigned int last_seq_num = expected_seq_num[sourcepe] + WINDOW_SIZE - 1;
+
+  /* 
+     Note that seq_num cannot be > last_seq_num.
+     Otherwise,  > last_seq_num - WINDOW_SIZE has been ack'd.
+     If that were the case, 
+     expected_seq_num[sourcepe] > > last_seq_num - WINDOW_SIZE,
+     which is a contradiction
+     */
+
+  if (expected_seq_num[sourcepe] < last_seq_num)
+    {
+      if (seq_num < expected_seq_num[sourcepe])
+       {
+         CmiFree(packet);      /* already received */
+         needack[sourcepe] = TRUE;
+         NumUseless++ ;
+         return FALSE;
+       }
+      else 
+       {
+         index = (next_window_index[sourcepe] + 
+                  seq_num - expected_seq_num[sourcepe]) % WINDOW_SIZE;
+         /* put needack and NumUseless++ here ??? */
+         if (recv_window[sourcepe][index].packet) CmiFree(packet);
+         else {
+           recv_window[sourcepe][index].packet = packet;
+           recv_window[sourcepe][index].seq_num = seq_num;
+           TRACE(CmiPrintf("Node %d: Inserting packet %d at index %d in recv window\n",
+                          Cmi_mype,
+                          seq_num, index)); 
+         }
+       }
+    }
+  return TRUE;
+}
+
+/* this routine supplies the next packet in the receive window and updates
+   the window. The window entry - packet + sequence number, is no longer
+   available. If the first entry in the window is a null packet - i.e. it
+   has not arrived, the routine returns NULL 
+   */
+
+static DATA_HDR *ExtractNextPacket(sourcepe)
+     int sourcepe;
+{
+  DATA_HDR *packet;
+  int index = next_window_index[sourcepe];
+
+  packet = recv_window[sourcepe][index].packet;
+  if (packet != NULL)
+    {
+      recv_window[sourcepe][index].packet = NULL;
+      needack[sourcepe] = TRUE;
+      expected_seq_num[sourcepe]++;
+      next_window_index[sourcepe] = (next_window_index[sourcepe] + 1) % WINDOW_SIZE;
+    }
+  return packet;
+}
+
+
+/* This routine inserts a completed messages as a list of packets in reverse
+   order into the recd_msg queue */
+
+static InsertInMessageQueue(packetlist)
+     PacketQueueElem *packetlist;
+{
+  MsgQueueElem *newelem;
+
+  newelem = (MsgQueueElem *) CmiAlloc(sizeof(MsgQueueElem));
+  newelem->packetlist = packetlist;
+  newelem->nextptr = NULL;
+  if  (recd_msg_tail == NULL)
+    recd_msg_head = newelem;
+  else recd_msg_tail->nextptr = newelem;
+  recd_msg_tail = newelem;
+  TRACE(CmiPrintf("Node %d: inserted seqnum=%d fullsize=%d in message queue\n", 
+                Cmi_mype,
+                recd_msg_head->packetlist->packet->seq_num,
+                recd_msg_head->packetlist->packet->full_size));
+}
+
+
+static void ConstructMessages()
+{
+  int i;
+  DATA_HDR *packet;
+  DATA_HDR *ExtractNextPacket();
+  PacketQueueElem *packetelem;
+
+  TRACE(CmiPrintf("Node %d: in ConstructMessages().\n",Cmi_mype));
+  for (i = 0; i < Cmi_numpe; i++)
+    if (i != Cmi_mype) {
+      packet = ExtractNextPacket(i);
+      while (packet != NULL) {
+       packetelem = (PacketQueueElem *) CmiAlloc(sizeof(PacketQueueElem));
+       packetelem->packet = packet;
+       /* Note: we are stacking it in reverse order */
+       packetelem->nextptr = recd_messages[i].packetlist; 
+       recd_messages[i].packetlist = packetelem; 
+       recd_messages[i].numpackets++;
+       if (recd_messages[i].numpackets == packet->numfrags) {
+         /* msg complete */
+         if (packet->msg_type == 1) {
+           TRACE(CmiPrintf("Node %d: CK packet complete seqnum=%d numfrags=%d\n",
+                          Cmi_mype,
+                          packet->seq_num, packet->numfrags));
+           InsertInMessageQueue(recd_messages[i].packetlist);
+         }
+         recd_messages[i].packetlist = NULL;
+         recd_messages[i].numpackets = 0;
+       }
+       packet = ExtractNextPacket(i);
+      }
+    }
+}
+
+
+
+static void AckReceivedMsgs()
+{
+  int i;
+  for (i = 0; i < Cmi_numpe; i++)
+    if (needack[i])    {
+      needack[i] = FALSE;
+      ack.SourcePeNum = i;
+      ack.seq_num = expected_seq_num[i] - 1;
+      if (Cmi_mype < Cmi_numpe)
+       TRACE(CmiPrintf("Node %d: acking seq_num %d on window %d\n",
+                      Cmi_mype, ack.seq_num, i)); 
+      NumAcksSent++ ;
+      send_ack(&ack);
+    }
+}
+
+static int data_getone()
+{
+  msgspace *recv_buf=NULL;
+  struct sockaddr_in src;
+  int i, srclen=sizeof(struct sockaddr_in);
+  int arrived = FALSE;
+  node_info *sender; int kind;
+  int AddToReceiveWindow();
+  int n;
+
+  recv_buf = (msgspace *)CmiAlloc(CMK_MAX_DGRAM_SIZE);
+  do n=recvfrom(data_skt,(char *)recv_buf,CMK_MAX_DGRAM_SIZE,0,(struct sockaddr *)&src,&srclen);
+  while ((n<0)&&(errno==EINTR));
+  if (n<0) { KillEveryone(strerror(errno)); }
+  kind = recv_buf->hd.send_or_ack;
+  if (kind == ACK)
+    {
+      /* remove it from the socket */
+      if (recv_buf->hd.SourcePeNum != Cmi_mype) 
+       KillEveryoneCode(7);
+      UpdateSendWindow(recv_buf, (int) recv_buf->hd.DestPeNum);
+      CmiFree(recv_buf);
+    }
+  else if (kind == SEND)
+    {
+      sender = node_table + recv_buf->hd.SourcePeNum;
+      /* sender->IP       = htonl(src.sin_addr.s_addr); */
+      if((sender->dataport)&&(sender->dataport!=htons(src.sin_port)))
+       KillEveryoneCode(38473);
+      sender->dataport = htons(src.sin_port);
+      arrived = TRUE;
+      AddToReceiveWindow(recv_buf, (int) recv_buf->hd.SourcePeNum);
+    }
+  else KillEveryoneCode(8); /* invalid datagram type. */
+  return kind;
+}
+
+static void dgram_scan()
+{
+  fd_set rfds;
+  struct timeval tmo;
+  int nreadable, gotsend=0;
+
+  while (1) {
+    FD_ZERO(&rfds);
+    FD_SET(data_skt, &rfds);
+    FD_SET(ctrl_skt, &rfds);
+    tmo.tv_sec = 0;
+    tmo.tv_usec = 0;
+    do nreadable = select(FD_SETSIZE, &rfds, NULL, NULL, &tmo);
+    while ((nreadable<0)&&(errno==EINTR));
+    if (nreadable <= 0) break;
+    if (FD_ISSET(ctrl_skt, &rfds))
+      ctrl_getone();
+    if (FD_ISSET(data_skt, &rfds)) {
+      int kind = data_getone();
+      if (kind==SEND) gotsend=1;
+    }
+  }
+  if (gotsend) {
+    ConstructMessages();
+    AckReceivedMsgs();
+  }
+}
+
+static void InterruptHandler()
+{
+  int prevmask ;
+  void dgram_scan();
+
+  NumIntrCalls++;
+  if ( Cmi_insidemachine)
+    return ;
+  NumOutsideMc++;
+  if (CmiInsideMem)
+    return ;
+  sighold(SIGIO) ;
+
+  dgram_scan();
+  RetransmitPackets();
+
+  sigrelse(SIGIO) ;
+  NumIntr++ ;
+}
+
+static void InterruptInit()
+{
+  if (Cmi_enableinterrupts) {
+    jsignal(SIGIO, InterruptHandler);
+    enable_async(data_skt);
+  }
+}
+
+
+/*
+** Synchronized send of "msg", of "size" bytes, to "destPE".
+** Returns the number of bytes of "msg" actually sent.
+** 
+** This routine differentiates between Chare Kernel messages and machine-level
+** messages by including a msg_type parameter.  It's called by the 
+** CmiSyncSend() macro, defined in conv-mach.h.
+**
+** -CW
+*/
+static int netSend(destPE, size, msg, msg_type) 
+    int destPE, size; 
+    char * msg; 
+    int msg_type;
+    {
+    int saveflag ;
+
+    if (!Communication_init) return -1;
+
+    if (destPE==Cmi_mype) 
+        {
+       CmiError("illegal send to myself\n");
+       return -1;
+        } 
+
+    saveflag = Cmi_insidemachine ;
+    Cmi_insidemachine = TRUE ;
+
+    if (size > MAX_FRAG_SIZE) 
+        {
+       /* Break the message into pieces and send each piece; start numbering
+        ** fragments with one.
+        */
+       int i;
+       int frags = ((size-1)/MAX_FRAG_SIZE) + 1;
+
+       for(i=1;i<frags;i++) 
+           fragment_send(destPE, MAX_FRAG_SIZE, msg+((i-1)*MAX_FRAG_SIZE), 
+                         size, msg_type, frags);
+
+       /* Last fragment is (probably) a different size. */
+       fragment_send(destPE, size - MAX_FRAG_SIZE*(frags-1),
+                     msg+(frags-1)*MAX_FRAG_SIZE,  size, msg_type, frags);
+
+        } 
+    else fragment_send(destPE, size, msg, size, msg_type, 1);
+
+    SendPackets(destPE);
+
+    Cmi_insidemachine = saveflag ;
+    }
+
+void *CmiLocalQueue;
+
+static int CmiProbe() 
+{
+  int val, saveflag;
+  void dgram_scan();
+
+  saveflag = Cmi_insidemachine ;
+  Cmi_insidemachine = TRUE ;
+
+  dgram_scan();
+  RetransmitPackets();
+  val = (recd_msg_head != NULL);
+
+  Cmi_insidemachine = saveflag ;
+  return (val);
+}
+
+void *CmiGetNonLocal()
+{
+  int i;
+  char *nextptr;
+  PacketQueueElem *packetelem, *nextpacket;
+  MsgQueueElem *msgelem;
+  DATA_HDR *packet;
+  void *newmsg;
+  int msglength;
+  int saveflag;
+
+  saveflag = Cmi_insidemachine;
+  Cmi_insidemachine = TRUE;
+
+  dgram_scan();
+  RetransmitPackets();
+  if (recd_msg_head==NULL) { newmsg=NULL; goto done; }
+  
+  msgelem = recd_msg_head;
+  packetelem = msgelem->packetlist;
+  if (recd_msg_head == recd_msg_tail) {
+    recd_msg_head = NULL;
+    recd_msg_tail = NULL;
+  }
+  else recd_msg_head = recd_msg_head->nextptr;
+  CmiFree(msgelem);
+  
+  /* now construct message */
+  msglength = packetelem->packet->full_size;
+  newmsg = (void *)CmiAlloc(msglength);
+  nextptr = newmsg + msglength;
+  while (packetelem != NULL) {
+    nextpacket = packetelem->nextptr;
+    packet = packetelem->packet;
+    nextptr -= packet->size;
+    Bcopy(packet+1, nextptr, packet->size);
+    CmiFree(packetelem);
+    CmiFree(packet);
+    packetelem = nextpacket;
+  }
+
+ done:
+  Cmi_insidemachine = saveflag;
+  return newmsg;
+}
+
+
+void CmiSyncSend(destPE, size, msg)
+int destPE;
+int size;
+char *msg;
+{
+  netSend(destPE,size,msg,1);
+}
+
+void CmiBroadcast(size,msg)
+     int size; char *msg;
+{
+  int i;
+  for (i=0;i<Cmi_numpe;i++)
+    {
+      if (i != Cmi_mype) netSend(i,size,msg,1);
+    }
+  CmiFree(msg) ;
+}
+
+void CmiSyncBroadcast(size,msg)
+     int size; char *msg;
+{
+  int i;
+  for (i=0;i<Cmi_numpe;i++)
+    {
+      if (i != Cmi_mype) netSend(i,size,msg,1);
+    }
+}
+
+void CmiSyncBroadcastAllAndFree(size,msg)
+     int size; char *msg;
+{
+  int i;
+  for (i=0;i<Cmi_numpe;i++)
+    if (i != Cmi_mype) netSend(i,size,msg,1);
+  FIFO_EnQueue(CmiLocalQueue,msg);
+}
+
+void CmiSyncBroadcastAll(size,msg)
+     int size; char *msg;
+{
+  int i;
+  char *msg1;
+  for (i=0;i<Cmi_numpe;i++)
+    if (i != Cmi_mype) netSend(i,size,msg,1);
+  msg1 = (char *)CmiAlloc(size);
+  memcpy(msg1,msg,size);
+  FIFO_EnQueue(CmiLocalQueue,msg1);
+}
+
+CmiCommHandle *CmiAsyncBroadcast(size, msg)
+     int size; char *msg;
+{
+  CmiSyncBroadcast(size, msg);
+  return NULL;
+}
+
+CmiCommHandle *CmiAsyncBroadcastAll(size, msg)
+     int size; char *msg;
+{
+  CmiSyncBroadcastAll(size, msg);
+  return NULL;
+}
+
+static void CmiSleep()
+{
+  if (Cmi_enableinterrupts) sigpause(0L);
+}
+
+CmiCommHandle *CmiAsyncSend(destPE, size, msg)
+     int destPE, size;
+     char *msg;
+{
+  CmiSyncSend(destPE, size, msg);
+  return NULL;
+}
+
+int CmiAsyncMsgSent(phandle)
+     CmiCommHandle *phandle;
+{
+  return TRUE;
+}
+
+void CmiReleaseCommHandle(phandle)
+     CmiCommHandle *phandle;
+{
+}
+
+void CmiGrabBuffer(pbuf)
+     char **pbuf;
+{
+}
+
+
+/******************************************************************************
+ *
+ * CmiInitMc and CmiExit
+ *
+ *****************************************************************************/
+
+CmiInitMc(argv)
+char **argv;
+{
+  static int initmc=0;
+  void *FIFO_Create();
+  Cmi_insidemachine = TRUE;
+  Communication_init = FALSE;
+  
+  if (initmc==1) KillEveryone("CmiInit called twice");
+  initmc=1;
+  
+  ExtractArgs(argv);
+  ParseNetstart();
+  InitializePorts();
+  CmiLocalQueue = FIFO_Create();
+  KillInit();
+  ctrl_sendone(120,"notify-die %s %d\n",self_IP_str,ctrl_port);
+  outlog_init(outputfile, Cmi_mype);
+  node_addresses_receive();
+  CmiTimerInit();
+  SendWindowInit();
+  RecvWindowInit();
+  InterruptInit();
+  Communication_init = TRUE;
+
+  Cmi_insidemachine = FALSE ;
+}
+
+CmiExit()
+{
+  static int exited;
+  int begin, saveflag;
+  
+  if (exited==1) KillEveryone("CmiExit called twice");
+  exited=1;
+  
+  saveflag = Cmi_insidemachine;
+  Cmi_insidemachine = TRUE;
+
+  ctrl_sendone(120,"aget %s %d done 0 %d\n",
+              self_IP_str,ctrl_port,Cmi_numpe-1);
+  ctrl_sendone(120,"aset done %d TRUE\n",Cmi_mype);
+  ctrl_sendone(120,"ending\n");
+  begin = time(0);
+  while(!all_done && (time(0)<begin+120))
+    { RetransmitPackets(); dgram_scan(); sleep(1); }
+  outlog_done();
+
+  Cmi_insidemachine = saveflag;
+}
diff --git a/src/arch/net/spantree.c b/src/arch/net/spantree.c
new file mode 100644 (file)
index 0000000..cece594
--- /dev/null
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * RCS INFORMATION:
+ *
+ *     $RCSfile$
+ *     $Author$        $Locker$                $State$
+ *     $Revision$      $Date$
+ *
+ ***************************************************************************
+ * DESCRIPTION:
+ *
+ ***************************************************************************
+ * REVISION HISTORY:
+ *
+ * $Log$
+ * Revision 2.0  1995-06-05 19:05:23  brunner
+ * Reorganized directory structure
+ *
+ * Revision 1.2  1995/04/13  05:51:12  narain
+ * Mc -> Cmi
+ *
+ * Revision 1.1  1994/11/03  17:37:04  brunner
+ * Initial revision
+ *
+ ***************************************************************************/
+static char ident[] = "@(#)$Header$";
+#include "converse.h"
+
+/**************************
+**
+** Spanning Tree Functions
+**
+**************************/
+
+/*
+** These are identical to the ipsc2 spanning tree functions.
+*/
+
+#define MAXSPAN    4          /* The maximum permitted span on 
+                                each node of the spanning tree */
+
+CmiSpanTreeInit() {}
+
+
+int
+CmiSpanTreeParent(node) int node; {
+    if (node == 0)
+         return -1;
+    else 
+       return ((node - 1) / MAXSPAN);   /* integer division */
+}
+
+
+int
+CmiSpanTreeRoot() { return 0; }
+
+
+CmiSpanTreeChildren(node, children) int node, *children; {
+    int i;
+
+    for (i = 1; i <= MAXSPAN ; i++)
+       if (MAXSPAN * node + i < CmiNumPe())
+            children[i-1] = node * MAXSPAN + i;
+       else children[i-1] = -1;
+}
+
+
+int
+CmiNumSpanTreeChildren(node) int node; {
+    if ((node + 1) * MAXSPAN < CmiNumPe()) return MAXSPAN;
+    else if (node * MAXSPAN + 1 >= CmiNumPe()) return 0;
+    else return ((CmiNumPe() - 1) - node * MAXSPAN);
+}
+
+
+CmiSendToSpanTreeLeaves(size, msg) int size; char * msg; {
+    int node;
+
+    for (node = (CmiNumPe() - 2) / MAXSPAN;   /* integer division */
+        node < CmiNumPe(); node++)
+       CmiSyncSend(node,size,msg);
+}
+
+
+
+PrintSpanTree() {
+    int i,j;
+    int children[MAXSPAN];
+    for (i = 0; i < CmiNumPe(); i++) {
+       CmiPrintf("node: %d, parent: %d, numchildren: %d, children: ",
+                i, CmiSpanTreeParent(i), CmiNumSpanTreeChildren(i));
+       CmiSpanTreeChildren(i, children);
+       for (j = 0; j < CmiNumSpanTreeChildren(i); j++)
+            CmiPrintf("%d ", children[j]);
+       CmiPrintf("\n");
+    }
+}
diff --git a/src/arch/tcp/conv-host.c b/src/arch/tcp/conv-host.c
new file mode 100644 (file)
index 0000000..bb33c84
--- /dev/null
@@ -0,0 +1,2065 @@
+
+#include "conv-mach.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <setjmp.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <varargs.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <strings.h>
+#include <varargs.h>
+
+#ifdef CMK_HAVE_WAITFLAGS_H
+#include <waitflags.h>
+#endif
+#ifdef CMK_HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef CMK_NEED_DECLARATION_FOR_STRING_FNS
+char *strchr(), *strrchr(), *strdup();
+#endif
+
+#ifdef CMK_STRERROR_USE_SYS_ERRLIST
+extern char *sys_errlist[];
+#define strerror(i) (sys_errlist[i])
+#endif
+
+#ifdef CMK_RSH_IS_A_COMMAND
+#define RSH_CMD "rsh"
+#endif
+
+#ifdef CMK_RSH_USE_REMSH
+#define RSH_CMD "remsh"
+#endif
+
+/****************************************************************************
+ *
+ * Death-notification
+ *
+ ****************************************************************************/
+
+int *notify_ip;
+int *notify_port;
+int  notify_count;
+int  notify_max;
+
+void notify_die(int ip, int port)
+{
+  if (notify_count==notify_max) {
+    notify_max  = (notify_max*2)+100;
+    if (notify_ip  ==0) notify_ip   = (int *)malloc(sizeof(int));
+    if (notify_port==0) notify_port = (int *)malloc(sizeof(int));
+    notify_ip   = (int *)realloc(notify_ip,   notify_max*sizeof(int));
+    notify_port = (int *)realloc(notify_port, notify_max*sizeof(int));
+  }
+  notify_ip[notify_count] = ip;
+  notify_port[notify_count] = port;
+  notify_count++;
+}
+
+void notify_die_doit(char *msg)
+{
+  int skt_connect();
+  char buffer[1024];
+  int i, fd;
+  sprintf(buffer,"die %s\n",msg);
+  for (i=0; i<notify_count; i++) {
+    int ip = notify_ip[i];
+    int port = notify_port[i];
+    fd = skt_connect(ip, port);
+    if (fd>=0) { write(fd, buffer, strlen(buffer)); close(fd); }
+  }
+  fprintf(stderr,"aborting: %s\n",msg);
+  exit(1);
+}
+
+void notify_abort()
+{
+  notify_die_doit("");
+}
+
+void notify_die_segv()
+{
+  notify_die_doit("host: seg fault.");
+}
+
+void notify_die_intr()
+{
+  notify_die_doit("host: interrupted.");
+}
+
+void notify_die_init()
+{
+  signal(SIGSEGV, notify_die_segv);
+  signal(SIGBUS,  notify_die_segv);
+  signal(SIGILL,  notify_die_segv);
+  signal(SIGABRT, notify_die_segv);
+  signal(SIGFPE,  notify_die_segv);
+
+#ifdef SIGSYS
+  signal(SIGSYS,  notify_die_segv);
+#endif
+  
+  signal(SIGPIPE, notify_die_segv);
+  signal(SIGURG,  notify_die_segv);
+
+  signal(SIGTERM, notify_die_intr);
+  signal(SIGQUIT, notify_die_intr);
+  signal(SIGINT,  notify_die_intr);
+}
+
+/**************************************************************************
+ *
+ * SKT - socket routines
+ *
+ * Uses Module: SCHED  [implicitly TIMEVAL, QUEUE, THREAD]
+ *
+ *
+ * unsigned int skt_ip()
+ *
+ *   - returns the IP address of the current machine.
+ *
+ * void skt_server(unsigned int *pip, unsigned int *ppo, unsigned int *pfd)
+ *
+ *   - create a tcp server socket.  Performs the whole socket/bind/listen
+ *     procedure.  Returns the IP address of the socket (eg, the IP of the
+ *     current machine), the port of the socket, and the file descriptor.
+ *
+ * void skt_accept(int src,
+ *                 unsigned int *pip, unsigned int *ppo, unsigned int *pfd)
+ *
+ *   - accepts a connection to the specified socket.  Returns the
+ *     IP of the caller, the port number of the caller, and the file
+ *     descriptor to talk to the caller.
+ *
+ * int skt_connect(unsigned int ip, int port)
+ *
+ *   - Opens a connection to the specified server.  Returns a socket for
+ *     communication.
+ *
+ *
+ **************************************************************************/
+
+unsigned int skt_ip()
+{
+  static unsigned int ip = 0;
+  struct hostent *hostent;
+  char hostname[100];
+  if (ip==0) {
+    if (gethostname(hostname, 99)<0) ip=0x7f000001;
+    hostent = gethostbyname(hostname);
+    if (hostent == 0) return 0x7f000001;
+    ip = htonl(*((int *)(hostent->h_addr_list[0])));
+  }
+  return ip;
+}
+
+void skt_server(unsigned int *pip, unsigned int *ppo, unsigned int *pfd)
+{
+  int fd= -1;
+  int ok, len;
+  struct sockaddr_in addr;
+  
+  fd = socket(PF_INET, SOCK_STREAM, 0);
+  if (fd < 0) { perror("socket"); exit(1); }
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  ok = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+  if (ok < 0) { perror("bind"); exit(1); }
+  ok = listen(fd,5);
+  if (ok < 0) { perror("listen"); exit(1); }
+  len = sizeof(addr);
+  ok = getsockname(fd, (struct sockaddr *)&addr, &len);
+  if (ok < 0) { perror("getsockname"); exit(1); }
+
+  *pfd = fd;
+  *pip = skt_ip();
+  *ppo = ntohs(addr.sin_port);
+}
+
+void skt_accept(int src,
+               unsigned int *pip, unsigned int *ppo, unsigned int *pfd)
+{
+  int i, fd, ok;
+  struct sockaddr_in remote;
+  i = sizeof(remote);
+ acc:
+  fd = accept(src, (struct sockaddr *)&remote, &i);
+  if ((fd<0)&&(errno==EINTR)) goto acc;
+  if ((fd<0)&&(errno==EMFILE)) goto acc;
+  if (fd<0) { perror("accept"); notify_abort(); }
+  *pip=htonl(remote.sin_addr.s_addr);
+  *ppo=htons(remote.sin_port);
+  *pfd=fd;
+}
+
+int skt_connect(unsigned int ip, int port)
+{
+  struct sockaddr_in remote; short sport=port;
+  int fd, ok, len;
+    
+  /* create an address structure for the server */
+  memset(&remote, 0, sizeof(remote));
+  remote.sin_family = AF_INET;
+  remote.sin_port = htons(sport);
+  remote.sin_addr.s_addr = htonl(ip);
+    
+ sock:
+  fd = socket(AF_INET, SOCK_STREAM, 0);
+  if ((fd<0)&&(errno=EMFILE)) goto sock;
+  if (fd < 0) return -1;
+  
+ conn:
+  ok = connect(fd, (struct sockaddr *)&(remote), sizeof(remote));
+  if (ok<0) {
+    switch (errno) {
+    case EADDRINUSE: close(fd); goto sock;
+    default: return -1;
+    }
+  }
+  return fd;
+}
+
+/****************************************************************************
+ *
+ * Miscellaneous minor routines.
+ *
+ ****************************************************************************/
+
+zap_newline(char *s)
+{
+  char *p;
+  p = s + strlen(s)-1;
+  if (*p == '\n') *p = '\0';
+}
+
+char *substr(char *lo, char *hi)
+{
+  int len = hi-lo;
+  char *res = (char *)malloc(1+len);
+  memcpy(res, lo, len);
+  res[len]=0;
+  return res;
+}
+
+/* advance pointer over blank characters */
+char *skipblanks(char *p)
+{
+  while ((*p==' ')||(*p=='\t')) p++;
+  return p;
+}
+
+/* advance pointer over nonblank characters */
+char *skipstuff(char *p)
+{
+  while ((*p)&&(*p!=' ')&&(*p!='\t')) p++;
+  return p;
+}
+
+char *text_ip(unsigned int ip)
+{
+  static char buffer[100];
+  sprintf(buffer,"%d.%d.%d.%d",
+         (ip>>24)&0xFF,
+         (ip>>16)&0xFF,
+         (ip>>8)&0xFF,
+         (ip>>0)&0xFF);
+  return buffer;
+}
+
+int readhex(FILE *f, int len)
+{
+  char buffer[100];
+  char *p;
+  int res;
+  if (fread(buffer, len, 1, f)!=1) return -1;
+  buffer[len]=0;
+  res=strtol(buffer, &p, 16);
+  if (p!=buffer+len) return -1;
+  return res;
+}
+
+char *getenv_display()
+{
+  static char result[100];
+  char *e, *p;
+  
+  e = getenv("DISPLAY");
+  if (e==0) return 0;
+  p = strrchr(e, ':');
+  if (p==0) return 0;
+  if ((e[0]==':')||(strncmp(e,"unix:",5)==0)) {
+    sprintf(result,"%s:%s",text_ip(skt_ip()),p+1);
+  }
+  else strcpy(result, e);
+  return result;
+}
+
+char *mylogin()
+{
+  struct passwd *self;
+  self = getpwuid(getuid());
+  if (self==0) { perror("getpwuid"); exit(1); }
+  return self->pw_name;
+} 
+
+unsigned int lookup_ip(char *name)
+{
+  struct hostent *h;
+  unsigned int ip1,ip2,ip3,ip4; int nread;
+  nread = sscanf(name,"%d.%d.%d.%d",&ip1,&ip2,&ip3,&ip4);
+  if (nread==4) return (ip1<<24)|(ip2<<16)|(ip3<<8)|ip4;
+  h = gethostbyname(name);
+  if (h==0) return 0;
+  return htonl(*((int *)(h->h_addr_list[0])));
+}
+
+/*****************************************************************************
+ *                                                                           *
+ * PPARAM - obtaining "program parameters" from the user.                    *
+ *                                                                           *
+ *****************************************************************************/
+
+typedef struct ppdef
+{
+  union
+    {
+      double r;
+      int i;
+      char *s;
+      int f;
+    } value;
+  char *lname;
+  char *doc;
+  char  type;
+  struct ppdef *next;
+}
+*ppdef;
+
+static ppdef ppdefs;
+
+static int     pparam_pos;
+static char  **pparam_argv;
+static char    pparam_optc='-';
+char           pparam_error[100];
+
+static ppdef pparam_find(char *lname)
+{
+  ppdef def;
+  for (def=ppdefs; def; def=def->next)
+    if (strcmp(def->lname, lname)==0)
+      return def;
+  return 0;
+}
+
+static ppdef pparam_cell(char *lname)
+{
+  ppdef def = pparam_find(lname);
+  if (def) return def;
+  def = (ppdef)malloc(sizeof(struct ppdef));
+  def->lname = lname;
+  def->type  = 's';
+  def->doc   = "(undocumented)";
+  def->next  = ppdefs;
+  ppdefs = def;
+  return def;
+}
+
+void pparam_doc(char *lname, char *doc)
+{
+  ppdef def = pparam_cell(lname);
+  def->doc = doc;
+}
+
+void pparam_defint(char *lname, int value)
+{
+  ppdef def = pparam_cell(lname);
+  def->type  = 'i';
+  def->value.i = value;
+}
+
+void pparam_defreal(char *lname, double value)
+{
+  ppdef def = pparam_cell(lname);
+  def->type  = 'r';
+  def->value.r = value;
+}
+
+void pparam_defstr(char *lname, char *value)
+{
+  ppdef def = pparam_cell(lname);
+  def->type  = 's';
+  def->value.s = value;
+}
+
+void pparam_defflag(char *lname)
+{
+  ppdef def = pparam_cell(lname);
+  def->type  = 'f';
+  def->value.f = 0;
+}
+
+static ppdef pparam_hfind(char *lname)
+{
+  ppdef def = pparam_find(lname);
+  if (def) return def;
+  printf("No such program parameter %s\n",lname);
+  exit(1);
+}
+
+int pparam_getint(char *lname)
+{
+  ppdef def = pparam_hfind(lname);
+  if (def->type != 'i') return 0;
+  return def->value.i;
+}
+
+double pparam_getreal(char *lname)
+{
+  ppdef def = pparam_hfind(lname);
+  if (def->type != 'r') return 0.0;
+  return def->value.r;
+}
+
+char *pparam_getstr(char *lname)
+{
+  ppdef def = pparam_hfind(lname);
+  if (def->type != 's') return 0;
+  return def->value.s;
+}
+
+int pparam_getflag(char *lname)
+{
+  ppdef def = pparam_hfind(lname);
+  if (def->type != 'f') return 0;
+  return def->value.f;
+}
+
+static int pparam_setdef(ppdef def, char *value)
+{
+  char *p;
+  switch(def->type)
+    {
+    case 'i' :
+      def->value.i = strtol(value, &p, 10);
+      if (*p) return -1;
+      return 0;
+    case 'r' :
+      def->value.r = strtod(value, &p);
+      if (*p) return -1;
+      return 0;
+    case 's' :
+      def->value.s = value;
+      return 0;
+    case 'f' :
+      def->value.i = strtol(value, &p, 10);
+      if (*p) return -1;
+      return 0;
+    }
+}
+
+int pparam_set(char *lname, char *value)
+{
+  ppdef def = pparam_cell(lname);
+  return pparam_setdef(def, value);
+}
+
+char *pparam_getdef(ppdef def)
+{
+  static char result[100];
+  switch(def->type)
+    {
+    case 'i': sprintf(result,"%d", def->value.i); return result;
+    case 'r': sprintf(result,"%lf",def->value.r); return result;
+    case 's': return def->value.s;
+    case 'f': sprintf(result,"%d", def->value.f); return result;
+    }
+}
+
+void pparam_printdocs()
+{
+  ppdef def; int i, len, maxname, maxdoc;
+  maxname = 0;
+  maxdoc = 0;
+  for (def=ppdefs; def; def=def->next)
+    {
+      len = strlen(def->lname);
+      if (len>maxname) maxname=len;
+      len = strlen(def->doc);
+      if (len>maxdoc) maxdoc=len;
+    }
+  printf("\n");
+  printf("parameters recognized are:\n");
+  printf("\n");
+  for (def=ppdefs; def; def=def->next)
+    {
+      len = strlen(def->lname);
+      printf("  %c%c%s ",pparam_optc,pparam_optc,def->lname);
+      for(i=0; i<maxname-len; i++) printf(" ");
+      len = strlen(def->doc);
+      printf("  %s ",def->doc);
+      for(i=0; i<maxdoc-len; i++) printf(" ");
+      printf("[%s]\n",pparam_getdef(def));
+    }
+  printf("\n");
+}
+
+void pparam_delarg(int i)
+{
+  int j;
+  for (j=i; pparam_argv[j]; j++)
+    pparam_argv[j]=pparam_argv[j+1];
+}
+
+int pparam_countargs(char **argv)
+{
+  int argc;
+  for (argc=0; argv[argc]; argc++);
+  return argc;
+}
+
+int pparam_parseopt()
+{
+  int ok; ppdef def;
+  char *opt = pparam_argv[pparam_pos];
+  /* handle ++ by skipping to end */
+  if ((opt[1]=='+')&&(opt[2]==0))
+    {
+      pparam_delarg(pparam_pos);
+      while (pparam_argv[pparam_pos]) pparam_pos++;
+      return 0;
+    }
+  /* handle + by itself - an error */
+  if (opt[1]==0) 
+    {
+      sprintf(pparam_error,"Illegal option +\n");
+      return -1;
+    }
+  /* look up option definition */
+  if (opt[1]=='+') def = pparam_find(opt+2);
+  else
+    {
+      char name[2];
+      name[0]=opt[1];
+      name[1]=0;
+      def = pparam_find(name);
+    }
+  if (def==0)
+    {
+      pparam_pos++;
+      return 0;
+/*
+   sprintf(pparam_error,"Option %s not recognized.",opt);
+   return -1;
+*/
+    }
+  /* handle flag-options */
+  if ((def->type=='f')&&(opt[1]!='+')&&(opt[2]))
+    {
+      sprintf(pparam_error,"Option %s should not include a value",opt);
+      return -1;
+    }
+  if (def->type=='f')
+    {
+      def->value.f = 1;
+      pparam_delarg(pparam_pos);
+      return 0;
+    }
+  /* handle non-flag options */
+  if ((opt[1]=='+')||(opt[2]==0))
+    {
+      pparam_delarg(pparam_pos);
+      opt = pparam_argv[pparam_pos];
+    }
+  else opt+=2;
+  if ((opt == 0)||(opt[0] == 0))
+    {
+      sprintf(pparam_error,"%s must be followed by a value.",opt);
+      return -1;
+    }
+  ok = pparam_setdef(def, opt);
+  pparam_delarg(pparam_pos);
+  if (ok<0)
+    {
+      sprintf(pparam_error,"Illegal value for %s",opt);
+      return -1;
+    }
+  return 0;
+}
+
+int pparam_parsecmd(char optchr, char **argv)
+{
+  pparam_error[0]=0;
+  pparam_argv = argv;
+  pparam_optc = optchr;
+  pparam_pos  = 0;
+  while(1)
+    {
+      char *opt = pparam_argv[pparam_pos];
+      if (opt==0) break;
+      if (opt[0]!=optchr) pparam_pos++;
+      else if (pparam_parseopt()<0) return -1;
+    }
+  return 0;
+}
+
+/****************************************************************************
+ *                                                                           
+ * PATH                                                                      
+ *                                                                           
+ * path_simplify(P)                                                          
+ *                                                                           
+ *  - P is a pointer to a buffer containing a path.  All ".." and "."        
+ *    components of the path are expanded out.                               
+ *                                                                           
+ * path_concat(P, rel)                                                       
+ *                                                                           
+ *  - P is a pointer to a buffer containing a path, rel is another path      
+ *    relative to P.  The logical concatenation of the two paths are         
+ *    stored in the buffer.                                                  
+ *                                                                           
+ * path_absolute(P)                                                          
+ *                                                                           
+ *  - If P is a relative path, it is assumed to be relative to the current   
+ *    directory, and it is thereby converted into an absolute path.          
+ *                                                                           
+ * path_search(name, searchpath)                                             
+ *                                                                           
+ *  - name is a pointer to a buffer containing a program name or program     
+ *    path, and searchpath is a string containing a list of directories      
+ *   (as might be returned by getenv("PATH")).  The program's executable     
+ *    is located and its absolute, readlinked path is stored in the name     
+ *    buffer.                                                                
+ *                                                                           
+ * int path_isprefix(path1, path2)
+ * 
+ *  -  Routine to check whether path1 is a prefix of path2.  Returns 0 if
+ *     not a prefix, or number of chars to chop off 'ipath' if it is a
+ *     prefix.  path1 must be a path without a trailing slash.
+ *
+ *****************************************************************************/
+
+static char *path_segs[100];
+static int   path_nsegs;
+
+static void path_segs_free()
+{
+  while (path_nsegs) free(path_segs[--path_nsegs]);
+}
+
+static void path_dissect(char *path)
+{
+  char buf[1000];
+  int len=0;
+  while (1)
+    {
+      if ((*path=='/')||(*path==0))
+       {
+         buf[len]=0;
+         path_segs[path_nsegs++] = strdup(buf);
+         len=0;
+       }
+      else buf[len++] = *path;
+      if (*path==0) break;
+      path++;
+    }
+}
+
+static void path_reduce()
+{
+  int src, dst;
+  src = 0; dst = 0;
+  for (src=0; src<path_nsegs; src++)
+    {
+      char *t;
+      if ((strcmp(path_segs[src],"")==0)&&(src!=0)) continue;
+      if (strcmp(path_segs[src],".")==0) continue;
+      if (strcmp(path_segs[src],"..")==0) { if (dst) dst--; continue; }
+      t = path_segs[dst]; path_segs[dst]=path_segs[src]; path_segs[src]=t;
+      dst ++;
+    }
+  while (src>dst) free(path_segs[--src]);
+  path_nsegs = dst;
+}
+
+static void path_reconstitute(char *buff)
+{
+  int i;
+  for (i=0; i<path_nsegs; i++)
+    {
+      strcpy(buff, path_segs[i]);
+      buff+=strlen(buff);
+      *buff++ = '/';
+    }
+  *(--buff)=0;
+}
+
+void path_simplify(char *path)
+{
+  path_nsegs = 0;
+  path_dissect(path);
+  path_reduce();
+  path_reconstitute(path);
+  path_segs_free();
+}
+
+void path_concat(char *base, char *rel)
+{
+  path_nsegs = 0;
+  if (rel[0]!='/') path_dissect(base);
+  path_dissect(rel);
+  path_reduce();
+  path_reconstitute(base);
+  path_segs_free();
+}
+
+void path_absolute(char *path)
+{
+  char buff[1024];
+  if (path[0]=='/') return;
+  getcwd(buff, 1023);
+  path_concat(buff, path);
+  strcpy(path, buff);
+}
+
+int path_exists(char *path)
+{
+  struct stat s;
+  int ok = stat(path, &s);
+  if (ok>=0) return 1;
+  return 0;
+}
+
+int path_executable(char *path)
+{
+  struct stat s;
+  int ok = stat(path, &s);
+  if (ok<0) return 0;
+  if (!S_ISREG(s.st_mode)) return 0;
+  if((s.st_mode&S_IXOTH)&&(s.st_mode&S_IROTH)) return 1;
+  if((s.st_mode&S_IXGRP)&&(s.st_mode&S_IRGRP)&&(s.st_gid==getgid()))return 1;
+  if((s.st_mode&S_IXUSR)&&(s.st_mode&S_IRUSR)&&(s.st_uid==getuid()))return 1;
+  return 0;
+}
+
+int path_nonzero(char *path)
+{
+  struct stat s;
+  int ok = stat(path, &s);
+  if (ok<0) return 0;
+  if (!S_ISREG(s.st_mode)) return 0;
+  if (s.st_size==0) return 0;
+  return 1;
+}
+
+int path_search(char *prog, char *path)
+{
+  char *end;
+  if (strchr(prog,'/'))
+    {
+      path_absolute(prog);
+      if (path_exists(prog)) return 0;
+      prog[0]=0; return -1;
+    }
+  if ((path)&&(*path)) while (1)
+    {
+      char buff[1024];
+      int len;
+      end = strchr(path, ':');
+      if (end==0) { end=path+strlen(path); }
+      len = (end - path);
+      memcpy(buff, path, len);
+      buff[len]=0;
+      path_concat(buff, prog);
+      path_absolute(buff);
+      if (path_executable(buff)) { strcpy(prog, buff); return 0; }
+      if (*end==0) break;
+      path=end+1;
+    }
+  prog[0]=0; errno=ENOENT; return -1;
+}
+
+int path_isprefix(char *ipre, char *ipath)
+{
+  char pre[MAXPATHLEN];
+  char path[MAXPATHLEN];
+  struct stat preinfo;
+  struct stat pathinfo;
+  int ok, prelen; char *p;
+  strcpy(pre, ipre);
+  strcpy(path, ipath);
+  prelen = strlen(pre);
+  if (prelen==0) return 0;
+  if (pre[prelen-1]=='/') return 0;
+  if (strncmp(pre, path, prelen)==0) return prelen;
+  ok = stat(pre, &preinfo);
+  if (ok<0) return 0;
+  p=path;
+  while (1) {
+    int ch = *p;
+    if ((ch=='/')||(ch==0)) {
+      *p = 0;
+      ok = stat(path, &pathinfo);
+      if (ok<0) return 0;
+      if ((pathinfo.st_ino == preinfo.st_ino)&&
+          (pathinfo.st_dev == preinfo.st_dev)) return p-path;
+      *p = ch;
+    }
+    if (ch==0) break;
+    p++;
+  }
+  return 0;
+}
+
+/****************************************************************************
+ *                                                                           
+ * xstr                                                                      
+ *                                                                           
+ *  extendable (and otherwise dynamically-changing) strings.                 
+ *                                                                           
+ *  These are handy for implementing character buffers of all types.         
+ *                                                                           
+ *  This module tries to guarantee reasonable speed efficiency for all       
+ *  operations.                                                              
+ *                                                                           
+ *  Each xstr takes around 3*len bytes (where 'len' is the length of the     
+ *  string being stored), so it isn't very space efficient.  This is done    
+ *  to improve the efficiency of updates.                                    
+ *                                                                           
+ *  xstr_alloc()                                                             
+ *                                                                           
+ *      - allocates an empty buffer.                                         
+ *                                                                           
+ *  xstr_free(str)                                                           
+ *                                                                           
+ *      - frees an allocated buffer.                                         
+ *                                                                           
+ *  xstr_lptr(s)                                                             
+ *                                                                           
+ *      - returns a pointer to leftmost char in buffer.                      
+ *                                                                           
+ *  xstr_rptr(s)                                                             
+ *                                                                           
+ *      - returns a pointer beyond rightmost char in buffer.                 
+ *                                                                           
+ *  xstr_rexpand(str, nbytes)                                                
+ *                                                                           
+ *     - add uninitialized bytes to the right end of the string.             
+ *                                                                           
+ *  xstr_lexpand(str, nbytes)                                                
+ *                                                                           
+ *     - add uninitialized bytes to the left end of the string.              
+ *                                                                           
+ *  xstr_rshrink(str, nbytes)                                                
+ *                                                                           
+ *     - remove bytes from the right end of the string.                      
+ *                                                                           
+ *  xstr_lshrink(str, nbytes)                                                
+ *                                                                           
+ *     - remove bytes from the left end of the string.                       
+ *                                                                           
+ *  xstr_write(str, bytes, nbytes)                                           
+ *                                                                           
+ *     - append the specified bytes to the right end of the xstr.            
+ *                                                                           
+ *  xstr_printf(str, ...)                                                    
+ *                                                                           
+ *     - print the specified message onto the end of the xstr.               
+ *                                                                           
+ *****************************************************************************/
+
+typedef struct xstr
+    {
+    char *lptr;
+    char *rptr;
+    char *lend;
+    char *rend;
+    }
+    *xstr;
+
+char *xstr_lptr(l) xstr l; { return l->lptr; }
+char *xstr_rptr(l) xstr l; { return l->rptr; }
+
+int xstr_len(xstr l)
+{
+  return l->rptr - l->lptr;
+}
+
+xstr xstr_alloc()
+{
+  xstr res = (xstr)malloc(sizeof(struct xstr));
+  res->lend = (char *)malloc(257);
+  res->lptr = res->lend + 128;
+  res->rptr = res->lend + 128;
+  res->rend = res->lend + 256;
+  return res;
+}
+
+void xstr_free(xstr s)
+{
+  free(s->lend);
+  free(s);
+}
+
+void xstr_rexpand(xstr l, int nbytes)
+{
+  int lspace, rspace, uspace, needed; char *nbuf;
+  if (l->rend - l->rptr>=nbytes) { l->rptr += nbytes; return; }
+  uspace = (l->rptr - l->lptr);
+  needed = uspace + nbytes;
+  if (needed<64) needed=64;
+  nbuf = (char *)malloc(1+(needed*3));
+  memcpy(nbuf+needed, l->lptr, uspace);
+  free(l->lend);
+  l->lend = nbuf;
+  l->lptr = nbuf + needed;
+  l->rptr = nbuf + needed + uspace + nbytes;
+  l->rend = nbuf + needed + needed + needed;
+}
+
+void xstr_lexpand(xstr l, int nbytes)
+{
+  int lspace, rspace, uspace, needed; char *nbuf;
+  if (l->rend - l->rptr>=nbytes) { l->rptr += nbytes; return; }
+  uspace = (l->rptr - l->lptr);
+  needed = uspace + nbytes;
+  if (needed<64) needed=64;
+  nbuf = (char *)malloc(1+(needed*3));
+  memcpy(nbuf+needed+nbytes, l->lptr, uspace);
+  free(l->lend);
+  l->lend = nbuf;
+  l->lptr = nbuf + needed;
+  l->rptr = nbuf + needed + uspace + nbytes;
+  l->rend = nbuf + needed + needed + needed;
+}
+
+void xstr_rshrink(xstr l, int nbytes)
+{
+  if (l->rptr - l->lptr < nbytes) { l->rptr=l->lptr; return; }
+  l->rptr -= nbytes;
+}
+
+void xstr_lshrink(xstr l, int nbytes)
+{
+  if (l->rptr - l->lptr < nbytes) { l->lptr=l->rptr; return; }
+  l->lptr += nbytes;
+}
+
+void xstr_write(xstr l, char *bytes, int nbytes)
+{
+  xstr_rexpand(l, nbytes);
+  memcpy(xstr_lptr(l)+xstr_len(l)-nbytes, bytes, nbytes);
+}
+
+void xstr_printf(va_alist) va_dcl
+{
+  char buffer[10000];
+  xstr l; char *fmt;
+  va_list p;
+  va_start(p);
+  l = va_arg(p, xstr);
+  fmt = va_arg(p, char *);
+  vsprintf(buffer, fmt, p);
+  xstr_write(l, buffer, strlen(buffer));
+}
+
+char *xstr_gets(char *buff, int size, xstr s)
+{
+  char *p; int len;
+  xstr_rptr(s)[0]=0;
+  p = strchr(xstr_lptr(s),'\n');
+  if (p==0) return 0;
+  *p = 0;
+  len = p - xstr_lptr(s);
+  if (len > size) len=size;
+  memcpy(buff, xstr_lptr(s), len);
+  buff[len] = 0;
+  xstr_lshrink(s, len+1);
+  return buff;
+}
+
+/****************************************************************************
+ *
+ * PROG - much like 'popen', but better.
+ *
+ *
+ * typedef prog
+ *
+ *  - represents an opened, running program.
+ *
+ * prog prog_start(char *prog, char **argv, use_err)
+ *
+ *  - starts a program in the background (with the same args as execv).
+ *    The prog returned can be used to read the standard input and standard
+ *    output of the resulting program.  'use_err' is a flag, if zero, then
+ *    the program's standard error is merged with its standard output,
+ *    otherwise it is kept separate.
+ *
+ *    The program P has three file descriptors (P->ifd, P->ofd, P->efd)
+ *    which can be used to access its standard input, output, and error.
+ *    In addition, it has three xstr buffers (P->ibuf, P->obuf, P->ebuf)
+ *    which are used for buffered IO on those descriptors.
+ *
+ * int prog_flush(prog p)
+ *
+ *  - flushes the contents of P->ibuf into P->ifd.
+ *
+ * void prog_iclose(prog p)
+ * 
+ *  - close the input-side of the specified program.  You may not write to
+ *    the standard input of the program after prog_iclose.
+ *
+ * void prog_close(prog p)
+ *
+ *  - close the standard inputs and outputs of the specified program,
+ *    and free all resources used by the handle.  The program may continue
+ *    to exist in the background if it is capable of doing so without a
+ *    standard input and output.
+ *
+ ****************************************************************************/
+
+typedef struct prog
+{
+  int ifd; xstr ibuf;
+  int ofd; xstr obuf;
+  int efd; xstr ebuf;
+  int pid;
+}
+*prog;
+
+int prog_flush(prog c)
+{
+  xstr ibuf = c->ibuf;
+  int ifd = c->ifd;
+  
+  if (ibuf==0) return;
+  while (xstr_lptr(ibuf)!=xstr_rptr(ibuf))
+    {
+      int nwrote = write(ifd, xstr_lptr(ibuf), xstr_len(ibuf));
+      if (nwrote < 0) return -1;
+      if (nwrote==0)
+       { fprintf(stderr,"error: write returned 0???\n"); exit(1); }
+      xstr_lshrink(ibuf, nwrote);
+    }
+  return 0;
+}
+
+void prog_iclose(prog c)
+{
+  prog_flush(c);
+  if (c->ibuf) { xstr_free(c->ibuf); close(c->ifd); }
+  c->ibuf = 0;
+}
+
+void prog_close(prog c)
+{
+  prog_flush(c);
+  if (c->ibuf) { xstr_free(c->ibuf); close(c->ifd); }
+  if (c->obuf) { xstr_free(c->obuf); close(c->ofd); }
+  if (c->ebuf) { xstr_free(c->ebuf); close(c->efd); }
+  free(c);
+}
+
+prog prog_make(int ifd, int ofd, int efd, int pid)
+{
+  prog res = (prog)malloc(sizeof(struct prog));
+  res->ifd = ifd;
+  res->ofd = ofd;
+  res->efd = efd;
+  res->ibuf = (ifd >= 0) ? xstr_alloc() : NULL;
+  res->obuf = (ofd >= 0) ? xstr_alloc() : NULL;
+  res->ebuf = (efd >= 0) ? xstr_alloc() : NULL;
+  res->pid = pid;
+  return res;
+}
+
+prog prog_start(char *p, char **argv, int useerr)
+{
+  int p_stdin[2];
+  int p_stdout[2];
+  int p_stderr[2];
+  int pid;
+  p_stdin[0]= -1; p_stdout[0]= -1; p_stderr[0]= -1;
+  p_stdin[1]= -1; p_stdout[1]= -1; p_stderr[1]= -1;
+  if (pipe(p_stdin )<0) goto abort;
+  if (pipe(p_stdout)<0) goto abort;
+  if (pipe(p_stderr)<0) goto abort;
+  pid = 0;
+  pid = fork();
+  if (pid < 0) goto abort;
+  if (pid == 0)
+    {
+      int i;
+      dup2(p_stdin[0],0);
+      dup2(p_stdout[1],1);
+      dup2(useerr?p_stderr[1]:p_stdout[1],2);
+      for(i=3; i<128; i++) close(i);
+      execv(p, argv);
+      exit(1);
+    }
+  close(p_stdin[0]);
+  close(p_stdout[1]);
+  close(p_stderr[1]);
+  return prog_make(p_stdin[1], p_stdout[0], p_stderr[0], pid);
+ abort:
+  if (p_stdin[0]!= -1) close(p_stdin[0]);
+  if (p_stdin[1]!= -1) close(p_stdin[1]);
+  if (p_stdout[0]!= -1) close(p_stdout[0]);
+  if (p_stdout[1]!= -1) close(p_stdout[1]);
+  if (p_stderr[0]!= -1) close(p_stderr[0]);
+  if (p_stderr[1]!= -1) close(p_stderr[1]);
+  return 0;
+}
+
+/****************************************************************************
+ * 
+ * ARG
+ *
+ * The following module computes a whole bunch of miscellaneous values, which
+ * are all constant throughout the program.  Naturally, this includes the
+ * value of the command-line arguments.
+ *
+ *****************************************************************************/
+
+
+#define MAX_NODES 100
+#define MAX_LINE_LENGTH 1000
+
+char **arg_argv;
+int    arg_argc;
+
+int   arg_requested_pes;
+int   arg_debug;
+int   arg_debug_no_pause;
+int   arg_in_xterm;
+int   arg_maxrsh;
+char *arg_nodesfile;
+char *arg_display;
+char *arg_nodeprog_a;
+char *arg_nodeprog_r;
+char *arg_rshprog;
+char *arg_currdir_a;
+char *arg_currdir_r;
+char *arg_mylogin;
+
+arg_init(int argc, char **argv)
+{
+  static char buf[1024]; int len, i;
+  
+  pparam_defint ("p"             , -1);
+  pparam_defflag("debug"             );
+  pparam_defflag("debug-no-pause"    );
+  pparam_defflag("in-xterm"          );
+  pparam_defint ("maxrsh"        ,  5);
+  pparam_defstr ("nodesfile"     ,  0);
+  
+  pparam_doc("p",             "number of processes to create");
+  pparam_doc("in-xterm",      "Run each node in an xterm window");
+  pparam_doc("debug",         "Run each node under gdb in an xterm window");
+  pparam_doc("debug-no-pause","Like debug, except doesn't pause at beginning");
+  pparam_doc("maxrsh",        "Maximum number of rsh's to run at a time");
+  pparam_doc("nodesfile",     "file containing list of nodes");
+
+  if (pparam_parsecmd('+', argv) < 0) {
+    fprintf(stderr,"syntax: %s\n",pparam_error);
+    pparam_printdocs();
+    exit(1);
+  }
+  arg_argv = argv+2;
+  arg_argc = pparam_countargs(argv+2);
+
+  arg_requested_pes  = pparam_getint("p");
+  arg_in_xterm       = pparam_getflag("in-xterm");
+  arg_debug          = pparam_getflag("debug");
+  arg_debug_no_pause = pparam_getflag("debug-no-pause");
+  arg_maxrsh         = pparam_getint("maxrsh");
+  arg_nodesfile      = pparam_getstr("nodesfile");
+
+  /* Find the current value of the DISPLAY variable */
+  arg_display = getenv_display();
+  if ((arg_debug || arg_debug_no_pause || arg_in_xterm) && (arg_display==0)) {
+    fprintf(stderr,"DISPLAY must be set to use debugging mode\n");
+    exit(1);
+  }
+
+  /* find the node-program, absolute version */
+  if (argc<2) {
+    fprintf(stderr,"You must specify a node-program.\n");
+    exit(1);
+  }
+  strcpy(buf, argv[1]);
+  path_search(buf, getenv("PATH"));
+  if (buf[0]==0)
+    { fprintf(stderr,"No such program %s\n",argv[1]); exit(1); }
+  arg_nodeprog_a = strdup(buf);
+  
+  /* find the node-program, relative version */
+  sprintf(buf,"%s",getenv("HOME"));
+  if ((len=path_isprefix(buf,arg_nodeprog_a))!=0) {
+    sprintf(buf,"$HOME/%s",arg_nodeprog_a+len);
+    arg_nodeprog_r = strdup(buf);
+  }
+  else arg_nodeprog_r = arg_nodeprog_a;
+
+  strcpy(buf, RSH_CMD);
+  path_search(buf, getenv("PATH"));
+  if (buf[0]==0)
+    { fprintf(stderr,"Cannot find '%s' in path.\n", RSH_CMD); exit(1); }
+  arg_rshprog = strdup(buf);
+
+  /* find the current directory, absolute version */
+  getcwd(buf, 1023);
+  arg_currdir_a = strdup(buf);
+  
+  /* find the current directory, relative version */
+  sprintf(buf,"%s",getenv("HOME"));
+  if ((len=path_isprefix(buf, arg_currdir_a))!=0) {
+    sprintf(buf,"$HOME/%s",arg_currdir_a+len);
+    arg_currdir_r = strdup(buf);
+  }
+  else arg_currdir_r = arg_currdir_a;
+
+  arg_mylogin = mylogin();
+}
+
+/****************************************************************************
+ *                                                                           
+ * NODE:  The nodes file and nodes table.
+ *
+ * void nodetab_init()
+ *
+ *  - initialize the nodes table.
+ *    
+ *
+ * int nodetab_size;
+ *
+ *  - number of nodes in the nodes table.
+ *
+ * char *nodetab_name(int i)
+ *
+ *  - returns the name of node i.
+ *
+ * char *nodetab_login(int i)
+ *
+ *  - returns the login name for node i.
+ *
+ * char *nodetab_passwd(int i)
+ *
+ *  - returns the password for node I.
+ *
+ * char *nodetab_setup(int i)
+ *
+ *  - returns the setup command for node I.
+ *
+ * unsigned int nodetab_ip(int i)
+ *
+ *  - returns the IP address of node I.
+ *
+ * The routines described above retrieve their information from the nodesfile.
+ * This module looks in several places for the nodes file, in the following
+ * order:                                                   
+ *                                                                           
+ *      a file specified by ++nodesfile                                      
+ *      a file whose name is getenv("NODES")                                 
+ *      a file called "nodes" in the current directory.                      
+ *      a file called ".nodes" in the user's home directory.                 
+ *                                                                           
+ ****************************************************************************/
+
+typedef struct nodetab_info {
+   char *name;
+   char *login;
+   char *passwd;
+   char *setup;
+   unsigned int ip;
+} *nodetab_info;
+
+nodetab_info nodetab_table;
+int          nodetab_size;
+
+char *nodetab_file_find()
+{
+  /* Find a nodes-file as specified by ++nodesfile */
+  if (arg_nodesfile)
+    {
+      char *path = arg_nodesfile;
+      if (path_nonzero(path)) return strdup(path);
+      fprintf(stderr,"No such nodes file %s\n",path);
+      exit(1);
+    }
+  /* Find a nodes-file as specified by getenv("NODES") */
+  if (getenv("NODES"))
+    {
+      char *path = getenv("NODES");        
+      if (path && path_nonzero(path)) return strdup(path);
+      fprintf(stderr,"Cannot find NODES file %s\n",path);
+      exit(1);
+    }
+  /* Find a nodes-file by looking under 'nodes' in the current directory */
+  if (path_nonzero("./nodes")) return strdup("./nodes");
+  if (getenv("HOME"))
+    {
+      char buffer[MAXPATHLEN];
+      strcpy(buffer,getenv("HOME"));
+      path_concat(buffer,".nodes");
+      if (path_nonzero(buffer)) return strdup(buffer);
+    }
+  fprintf(stderr,"Cannot find a nodes file.\n");
+  exit(1);
+}
+
+
+void nodetab_init()
+{
+  FILE *f,*fopen();
+  char *nodesfile;
+  char *tok_ptr;
+  char input_line[MAX_LINE_LENGTH];
+  int i;
+  
+  /* Open the NODES_FILE. */
+  nodesfile = nodetab_file_find();
+  if (!(f = fopen(nodesfile,"r"))) {
+    fprintf(stderr,"Cannot read %s: %s\n",nodesfile,strerror(errno));
+    exit(1);
+  }
+  
+  nodetab_table= (nodetab_info)malloc(MAX_NODES * sizeof(struct nodetab_info));
+
+  /* Read in the machine definitions */
+  nodetab_size=0;
+  while(fgets(input_line,sizeof(input_line)-1,f)!=0) {
+    char *b,*e;
+    nodetab_info node = nodetab_table+nodetab_size;
+    if (input_line[0]=='#') continue;
+    zap_newline(input_line);
+    b=skipblanks(input_line);
+    if (*b==0) continue;
+    if (nodetab_size == MAX_NODES) {
+      fprintf(stderr,"Too many nodes, truncating nodesfile.\n");
+      break;
+    }
+    e=skipstuff(b);
+    node->name=substr(b,e);
+    /* put default information */
+    node->login="*";
+    node->passwd="*";
+    node->setup="";
+    b=skipblanks(e);
+    if (*b==0) goto endnode;
+    e=skipstuff(b);
+    node->login=substr(b,e);
+    b=skipblanks(e);
+    if (*b==0) goto endnode;
+    e=skipstuff(b);
+    node->passwd=substr(b,e);
+    b=skipblanks(e);
+    if (*b==0) goto endnode;
+    e=b+strlen(b);
+    node->setup=substr(b,e);
+  endnode:;
+    if (strcmp(node->login,"*")==0)
+      node->login = arg_mylogin;
+    node->ip = lookup_ip(node->name);
+    if (node->ip==0) {
+      fprintf(stderr,"cannot get IP of %s\n",node->name);
+      exit(1);
+    }
+    nodetab_size++;
+    if (nodetab_size == arg_requested_pes) break;
+  }
+  if ((arg_requested_pes > 0)&&(nodetab_size != arg_requested_pes)) {
+    fprintf(stderr,"Cannot read %d nodes from nodesfile %s\n",
+           arg_requested_pes, nodesfile);
+    exit(1);
+  }
+  fclose(f);
+}
+
+nodetab_info nodetab_getinfo(int i) {
+  if (nodetab_table==0) {
+    fprintf(stderr,"Node table not initialized.\n");
+    exit(1);
+  }
+  if ((i<0)||(i>=nodetab_size)) {
+    fprintf(stderr,"No such node %d\n",i);
+    exit(1);
+  }
+  return nodetab_table+i;
+}
+
+char        *nodetab_name(int i)   { return nodetab_getinfo(i)->name; }
+char        *nodetab_login(int i)  { return nodetab_getinfo(i)->login; }
+char        *nodetab_passwd(int i) { return nodetab_getinfo(i)->passwd; }
+char        *nodetab_setup(int i)  { return nodetab_getinfo(i)->setup; }
+unsigned int nodetab_ip(int i)     { return nodetab_getinfo(i)->ip; }
+/****************************************************************************
+ *
+ * ARVAR - array variables
+ *
+ * This host can store arrays for its clients.
+ *
+ * arvar_set(char *var, int index, char *val)
+ *
+ *  - set the specified position in the specified array to the specified
+ *    value.  If the named array does not exist, it is created.  If the
+ *    specified index does not exist, it is created.
+ *
+ * arvar_get(char *var, int lo, int hi)
+ *
+ *  - retrieve the specified subrange of the array.  If the entire subrange
+ *    has not been assigned, NULL is returned. Values are separated by
+ *    spaces.
+ *
+ ****************************************************************************/
+
+typedef struct arvar
+{
+  char *name;
+  int lo;
+  int hi;
+  int tot;
+  char **data;
+  struct arvar *next;
+}
+*arvar;
+
+arvar arvar_list;
+
+arvar arvar_find(char *var)
+{
+  arvar v = arvar_list;
+  while (v && (strcmp(v->name, var))) v=v->next;
+  return v;
+}
+
+arvar arvar_obtain(char *var)
+{
+  arvar v = arvar_find(var);
+  if (v==0) { 
+    v = (arvar)malloc(sizeof(struct arvar));
+    v->name = strdup(var);
+    v->lo = 0;
+    v->hi = -1;
+    v->data = 0;
+    v->next = arvar_list;
+    arvar_list = v;
+  }
+  return v;
+}
+
+void arvar_set(char *var, int index, char *val)
+{
+  char *old;
+  int i, lo, hi;
+  char **data;
+  arvar v = arvar_obtain(var);
+  data = v->data; lo = v->lo; hi = v->hi;
+  if ((index<lo)||(index>=hi)) {
+    if (lo>hi) lo=hi=index;
+    if (index<lo) lo=index;
+    if (index>=hi) hi=index+1;
+    data = (char **)calloc(1, (hi-lo)*sizeof(char *));
+    if (v->data) {
+      memcpy(data+((v->lo)-lo), v->data, (v->hi - v->lo)*sizeof(char *));
+      free(v->data);
+    }
+    v->data = data; v->lo = lo; v->hi = hi;
+  }
+  old = v->data[index-(v->lo)];
+  if (old) free(old);
+  else v->tot++;
+  v->data[index-(v->lo)] = strdup(val);
+}
+
+char *arvar_get(char *var, int lo, int hi)
+{
+  int len=0; int i;
+  arvar v = arvar_find(var);
+  char **data, *res;
+  if (v==0) return 0;
+  data = v->data;
+  if (lo<v->lo) return 0;
+  if (hi>v->hi) return 0;
+  for (i=lo; i<hi; i++) {
+    char *val = data[i-(v->lo)];
+    if (val==0) return 0;
+    len += strlen(val)+1;
+  }
+  res = (char *)malloc(len);
+  len=0;
+  for (i=lo; i<hi; i++) {
+    char *val = data[i-(v->lo)];
+    strcpy(res+len, val);
+    len+=strlen(val);
+    res[len++] = ' ';
+  }
+  res[--len] = 0;
+  return res;
+}
+
+/****************************************************************************
+ *
+ * input handling
+ *
+ * You can use this module to read the standard input.  It supports
+ * one odd function, input_scanf_chars, which is what makes it useful.
+ * if you use this module, you may not read stdin yourself.
+ *
+ * void input_init(void)
+ * char *input_gets(void)
+ * char *input_scanf_chars(char *fmt)
+ *
+ ****************************************************************************/
+
+char *input_buffer;
+
+void input_extend(void)
+{
+  char line[1024];
+  int len = input_buffer?strlen(input_buffer):0;
+  fflush(stdout);
+  if (fgets(line, 1023, stdin)==0) { notify_die_doit("end-of-file on stdin"); }
+  input_buffer = realloc(input_buffer, len + strlen(line) + 1);
+  strcpy(input_buffer+len, line);
+}
+
+void input_init(void)
+{
+  input_buffer = strdup("");
+}
+
+char *input_extract(int nchars)
+{
+  char *res = substr(input_buffer, input_buffer+nchars);
+  char *tmp = substr(input_buffer+nchars, input_buffer+strlen(input_buffer));
+  free(input_buffer);
+  input_buffer = tmp;
+  return res;
+}
+
+char *input_gets(void)
+{
+  char *p, *res; int len;
+  while(1) {
+    p = strchr(input_buffer,'\n');
+    if (p) break;
+    input_extend();
+  }
+  len = p-input_buffer;
+  res = input_extract(len+1);
+  res[len]=0;
+  return res;
+}
+
+char *input_scanf_chars(char *fmt)
+{
+  char buf[8192]; int len, pos;
+  static int fd; static FILE *file;
+  fflush(stdout);
+  if (file==0) {
+    unlink("/tmp/fnord");
+    fd = open("/tmp/fnord",O_RDWR | O_CREAT | O_TRUNC);
+    if (fd<0) { notify_die_doit("cannot open temp file /tmp/fnord"); }
+    file = fdopen(fd, "r+");
+    unlink("/tmp/fnord");
+  }
+  while (1) {
+    len = strlen(input_buffer);
+    rewind(file);
+    fwrite(input_buffer, len, 1, file);
+    fflush(file);
+    rewind(file);
+    ftruncate(fd, len);
+    fscanf(file, fmt, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf);
+    pos = ftell(file);
+    if (pos<len) break;
+    input_extend();
+  }
+  return input_extract(pos);
+}
+
+/****************************************************************************
+ *
+ * REQUEST SERVICER
+ *
+ * The request servicer accepts connections on a TCP port.  The client
+ * sends a sequence of commands (each is one line).  It then closes the
+ * connection.  The server must then contact the client, sending replies.
+ *
+ ****************************************************************************/
+
+typedef struct req_node
+{
+  struct req_node *next;
+  char request[1];
+}
+*req_node;
+
+unsigned int req_fd;
+unsigned int req_ip;
+unsigned int req_port;
+req_node     req_saved;
+
+#define REQ_OK 0
+#define REQ_POSTPONE -1
+#define REQ_FAILED -2
+
+int req_handle_aset(char *line)
+{
+  char cmd[100], var[100], val[1000]; int index, ok;
+  ok = sscanf(line,"%s %s %d %s",cmd,var,&index,val);
+  if (ok!=4) return REQ_FAILED;
+  arvar_set(var,index,val);
+  return REQ_OK;
+}
+
+int req_reply(int ip, int port, char *pre, char *ans)
+{
+  int fd = skt_connect(ip, port);
+  if (fd<=0) return REQ_FAILED;
+  write(fd, pre, strlen(pre));
+  write(fd, " ", 1);
+  write(fd, ans, strlen(ans));
+  write(fd, "\n", 1);
+  close(fd);
+  return REQ_OK;
+}
+
+int req_handle_aget(char *line)
+{
+  char cmd[100], host[1000], pre[1000], var[100]; int ip, port, lo, hi, ok;
+  char *res;
+  ok = sscanf(line,"%s %s %d %s %d %d",cmd,host,&port,var,&lo,&hi);
+  if (ok!=6) return REQ_FAILED;
+  ip = lookup_ip(host);
+  if (ip==0) return REQ_FAILED;
+  res = arvar_get(var,lo,hi+1);
+  if (res==0) return REQ_POSTPONE;
+  sprintf(pre, "aval %s %d %d", var, lo, hi);
+  ok = req_reply(ip,port,pre,res);
+  free(res);
+  return ok;
+}
+
+int req_handle_print(char *line)
+{
+  printf("%s\n",line+6);
+  return REQ_OK;
+}
+
+int req_handle_princ(char *line)
+{
+  printf("%s",line+6);
+  return REQ_OK;
+}
+
+int req_handle_printerr(char *line)
+{
+  fprintf(stderr,"%s\n",line+9);
+  return REQ_OK;
+}
+
+int req_handle_princerr(char *line)
+{
+  fprintf(stderr,"%s",line+9);
+  return REQ_OK;
+}
+
+int req_handle_notify_die(char *line)
+{
+  char cmd[100], host[100]; int ip, port, nread;
+  nread = sscanf(line,"%s%s%d",cmd,host,&port);
+  if (nread != 3) return REQ_FAILED;
+  ip = lookup_ip(host);
+  if (ip==0) return REQ_FAILED;
+  notify_die(ip, port);
+  return REQ_OK;
+}
+
+int req_handle_die(char *line)
+{
+  notify_die_doit(line+4);
+}
+
+int ending_count=0;
+
+int req_handle_ending(char *line)
+{
+  ending_count++;
+  if (ending_count == nodetab_size) exit(0);
+  return REQ_OK;
+}
+
+int req_handle_scanf(char *line)
+{
+  char cmd[100], host[100]; int ip, port, ok;
+  char *fmt, *res, *p;
+  ok = sscanf(line,"%s %s %d",cmd,host,&port);
+  if (ok!=3) return REQ_FAILED;
+  ip = lookup_ip(host);
+  if (ip==0) return REQ_FAILED;
+  fmt = line;
+  fmt = skipblanks(fmt); fmt = skipstuff(fmt);
+  fmt = skipblanks(fmt); fmt = skipstuff(fmt);
+  fmt = skipblanks(fmt); fmt = skipstuff(fmt);
+  fmt = fmt+1;
+  res = input_scanf_chars(fmt);
+  p = res; while (*p) { if (*p=='\n') *p=' '; p++; }
+  req_reply(ip, port, "scanf-data ", res);
+  free(res);
+  return REQ_OK;
+}
+
+int req_handle(char *line)
+{
+  char cmd[100];
+  sscanf(line,"%s",cmd);
+  if      (strcmp(cmd,"aset")==0)       return req_handle_aset(line);
+  else if (strcmp(cmd,"aget")==0)       return req_handle_aget(line);
+  else if (strcmp(cmd,"scanf")==0)      return req_handle_scanf(line);
+  else if (strcmp(cmd,"print")==0)      return req_handle_print(line);
+  else if (strcmp(cmd,"princ")==0)      return req_handle_princ(line);
+  else if (strcmp(cmd,"printerr")==0)   return req_handle_printerr(line);
+  else if (strcmp(cmd,"princerr")==0)   return req_handle_princerr(line);
+  else if (strcmp(cmd,"ending")==0)     return req_handle_ending(line);
+  else if (strcmp(cmd,"notify-die")==0) return req_handle_notify_die(line);
+  else if (strcmp(cmd,"die")==0)        return req_handle_die(line);
+  else return REQ_FAILED;
+}
+
+void req_run_saved()
+{
+  int ok;
+  req_node saved = req_saved;
+  req_saved = 0;
+  while (saved) {
+    req_node t = saved;
+    saved = saved->next;
+    ok = req_handle(t->request);
+    if (ok==REQ_POSTPONE) {
+      t->next = req_saved;
+      req_saved = t;
+    } else if (ok==REQ_FAILED) {
+      fprintf(stderr,"bad request: %s\n",t->request);
+      free(t);
+    } else free(t);
+  }
+}
+
+req_serve_client(FILE *f)
+{
+  char line[1000]; int status;
+  while (1) {
+    line[0]=0;
+    if (fgets(line, 999, f)==0) break;
+    zap_newline(line);
+    status = req_handle(line);
+    if (status==REQ_OK) req_run_saved();
+    else if (status==REQ_POSTPONE) {
+      req_node n = (req_node)malloc(sizeof(struct req_node)+strlen(line));
+      strcpy(n->request, line);
+      n->next = req_saved;
+      req_saved = n;
+    }
+    else fprintf(stderr,"bad request: %s\n",line);
+    line[0]=0;
+  }
+}
+
+req_serve()
+{
+  int client_ip, client_port, client_fd;
+  while (1) {
+    FILE *f;
+    skt_accept(req_fd, &client_ip, &client_port, &client_fd);
+    if (client_fd==0) {
+      perror("accept");
+      notify_abort();
+    }
+    f = fdopen(client_fd, "r+");
+    req_serve_client(f);
+    fclose(f);
+    close(client_fd);
+  }
+}
+
+req_init()
+{
+  skt_server(&req_ip, &req_port, &req_fd);
+  req_saved = 0;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* start_nodes                                                              */
+/*                                                                          */
+/* this starts all the node programs.  It executes fully in the background. */
+/*                                                                          */
+/****************************************************************************/
+
+prog rsh_start(int nodeno)
+{
+  char *rshargv[6];
+  prog rsh;
+  
+  rshargv[0]=RSH_CMD;
+  rshargv[1]=nodetab_name(nodeno);
+  rshargv[2]="-l";
+  rshargv[3]=nodetab_login(nodeno);
+  rshargv[4]="exec /bin/csh -f";
+  rshargv[5]=0;
+  rsh = prog_start(arg_rshprog, rshargv, 0);
+  if ((rsh==0)&&(errno!=EMFILE)) { perror("starting rsh"); exit(1); }
+  if (rsh==0)
+    {
+      fprintf(stderr,"caution: cannot start specified number of rsh's\n");
+      fprintf(stderr,"(not enough file descriptors available).\n");
+    }
+  if (rsh && (arg_debug || arg_debug_no_pause))
+    fprintf(stderr,"node %d: rsh initiated...\n",nodeno);
+  return rsh;
+}
+
+int rsh_pump(prog p, int nodeno, char **argv)
+{
+  xstr ibuf = p->ibuf;
+  int randno = rand();
+  
+  xstr_printf(ibuf,"echo 'remote responding...'\n");
+
+  if (arg_display)
+    xstr_printf(ibuf,"setenv DISPLAY %s\n",arg_display);
+  xstr_printf(ibuf,"setenv NETSTART '%d %d %d %d %d'\n",
+    nodeno, nodetab_size, nodetab_ip(nodeno), req_ip, req_port);
+  prog_flush(p);
+
+  if (arg_debug || arg_debug_no_pause || arg_in_xterm) {
+    xstr_printf(ibuf,"foreach dir ($path)\n");
+    xstr_printf(ibuf,"  if (-e $dir/xterm) setenv F_XTERM $dir/xterm\n");
+    xstr_printf(ibuf,"  if (-e $dir/xdpyinfo) setenv F_XDPYINFO $dir/xdpyinfo\n");
+    xstr_printf(ibuf,"end\n");
+    xstr_printf(ibuf,"if ($?F_XTERM == 0) then\n");
+    xstr_printf(ibuf,"   echo 'xterm not in path --- set your path in your cshrc.'\n");
+    xstr_printf(ibuf,"   kill -9 $$\n");
+    xstr_printf(ibuf,"endif\n");
+    xstr_printf(ibuf,"if ($?F_XDPYINFO == 0) then\n");
+    xstr_printf(ibuf,"   echo 'xdpyinfo not in path - set your path in your cshrc.'\n");
+    xstr_printf(ibuf,"   kill -9 $$\n");
+    xstr_printf(ibuf,"endif\n");
+    prog_flush(p);
+  }
+
+  if (arg_debug || arg_debug_no_pause) {
+    xstr_printf(ibuf,"foreach dir ($path)\n");
+    xstr_printf(ibuf,"  if (-e $dir/gdb) setenv F_GDB $dir/gdb\n");
+    xstr_printf(ibuf,"end\n");
+    xstr_printf(ibuf,"if ($?F_GDB == 0) then\n");
+    xstr_printf(ibuf,"   echo 'gdb not in path - set your path in your cshrc.'\n");
+    xstr_printf(ibuf,"   kill -9 $$\n");
+    xstr_printf(ibuf,"endif\n");
+    prog_flush(p);
+  }
+
+  if (arg_debug || arg_debug_no_pause || arg_in_xterm) {
+    xstr_printf(ibuf,"xdpyinfo > /dev/null\n");
+    xstr_printf(ibuf,"if ($status != 0) then\n");
+    xstr_printf(ibuf,"   echo 'Run xhost to enable display.'\n");
+    xstr_printf(ibuf,"   echo '(See manual for xhost for security issues)'\n");
+    xstr_printf(ibuf,"   kill -9 $$\n");
+    xstr_printf(ibuf,"endif\n");
+    prog_flush(p);
+  }
+  
+  xstr_printf(ibuf,"if (! -x %s) then\n",arg_nodeprog_r);
+  xstr_printf(ibuf,"  echo 'Cannot execute this node-program:'\n");
+  xstr_printf(ibuf,"  echo '%s'\n",arg_nodeprog_r);
+  xstr_printf(ibuf,"  kill -9 $$\n");
+  xstr_printf(ibuf,"endif\n");
+  
+  xstr_printf(ibuf,"cd %s\n",arg_currdir_r);
+  xstr_printf(ibuf,"if ($status == 1) then\n");
+  xstr_printf(ibuf,"  echo 'Cannot propagate this current directory:'\n"); 
+  xstr_printf(ibuf,"  echo '%s'\n",arg_currdir_r);
+  xstr_printf(ibuf,"  kill -9 $$\n");
+  xstr_printf(ibuf,"endif\n");
+  
+  if (nodetab_setup(nodeno)) {
+    xstr_printf(ibuf,"cd .\n");
+    xstr_printf(ibuf,"%s\n",nodetab_setup(nodeno));
+    xstr_printf(ibuf,"if ($status == 1) then\n");
+    xstr_printf(ibuf,"  echo 'this initialization command failed:'\n");
+    xstr_printf(ibuf,"  echo '\"%s\"'\n",nodetab_setup(nodeno));
+    xstr_printf(ibuf,"  echo 'edit your nodes file to fix it.'\n");
+    xstr_printf(ibuf,"  kill -9 $$\n");
+    xstr_printf(ibuf,"endif\n");
+  }
+  
+  if (arg_debug || arg_debug_no_pause) {
+    xstr_printf(ibuf,"cat > /tmp/gdb%08x << END_OF_SCRIPT\n",randno);
+    xstr_printf(ibuf,"shell rm -f /tmp/gdb%08x\n",randno);
+    xstr_printf(ibuf,"set args");
+    while (*argv) { xstr_printf(ibuf," %s",*argv); argv++; }
+    xstr_printf(ibuf,"\n");
+    if (arg_debug_no_pause) xstr_printf(ibuf,"run\n");
+    xstr_printf(ibuf,"END_OF_SCRIPT\n");
+  }
+  
+  if (arg_debug || arg_debug_no_pause) {
+    xstr_printf(ibuf,"$F_XTERM");
+    xstr_printf(ibuf," -T 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
+    xstr_printf(ibuf," -n 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
+    xstr_printf(ibuf," -e $F_GDB %s -x /tmp/gdb%08x",arg_nodeprog_r,randno);
+    xstr_printf(ibuf," < /dev/null >& /dev/null &");
+    xstr_printf(ibuf,"\n");
+  } else if (arg_in_xterm) {
+    xstr_printf(ibuf,"$F_XTERM");
+    xstr_printf(ibuf," -T 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
+    xstr_printf(ibuf," -n 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
+    xstr_printf(ibuf," -e %s", arg_nodeprog_r);
+    while (*argv) { xstr_printf(ibuf," %s",*argv); argv++; }
+    xstr_printf(ibuf," < /dev/null >& /dev/null &");
+    xstr_printf(ibuf,"\n");
+  } else {
+    xstr_printf(ibuf,"%s",arg_nodeprog_r);
+    while (*argv) { xstr_printf(ibuf," %s",*argv); argv++; }
+    xstr_printf(ibuf," < /dev/null >& /dev/null &");
+    xstr_printf(ibuf,"\n");
+  }
+  
+  xstr_printf(ibuf,"echo 'rsh phase successful.'\n");
+  xstr_printf(ibuf,"kill -9 $$\n");
+  
+  prog_flush(p);
+  prog_iclose(p);
+}
+
+
+int start_nodes()
+{
+  prog        rsh_prog[200];
+  int         rsh_node[200];
+  int         rsh_nstarted;
+  int         rsh_nfinished;
+  int         rsh_freeslot;
+  int         rsh_maxsim;
+  fd_set rfds; int i;
+  
+  /* Return immediately.  That way, the nodes which are starting */
+  /* Will be able to establish communication with the host */
+  /* if (fork()) return; */
+  
+  /* Obtain the values from the command line options */
+  rsh_maxsim = arg_maxrsh;
+  if (rsh_maxsim < 1) rsh_maxsim=1;
+  if (rsh_maxsim > nodetab_size) rsh_maxsim=nodetab_size;
+  if (rsh_maxsim > 200) rsh_maxsim=200;
+  
+  /* start initial group of rsh's */
+  for (i=0; i<rsh_maxsim; i++) {
+    prog p = rsh_start(i);
+    if (p==0) { rsh_maxsim=i; break; }
+    rsh_pump(p, i, arg_argv);
+    rsh_prog[i] = p;
+    rsh_node[i] = i;
+  }
+  if (rsh_maxsim==0) { perror("starting rsh"); exit(1); }
+  rsh_nstarted = rsh_maxsim;
+  rsh_nfinished = 0;
+  
+  while (rsh_nfinished < nodetab_size) {
+    int maxfd=0; int ok;
+    FD_ZERO(&rfds);
+    for (i=0; i<rsh_maxsim; i++) {
+      prog p = rsh_prog[i];
+      if (p==0) continue;
+      FD_SET(p->ofd, &rfds);
+      if (p->ofd > maxfd) maxfd = p->ofd;
+    }
+    do ok = select(maxfd+1, &rfds, NULL, NULL, NULL);
+    while ((ok<0)&&(errno==EINTR));
+    if (ok<0) { perror("select"); exit(1); }
+    do ok = waitpid((pid_t)(-1), NULL, WNOHANG);
+    while (ok>=0);
+    for (i=0; i<rsh_maxsim; i++) {
+      char *line = 0;
+      char buffer[1000];
+      int nread, done = 0;
+      prog p = rsh_prog[i];
+      if (p==0) continue;
+      if (!FD_ISSET(p->ofd, &rfds)) continue;
+      do nread = read(p->ofd, buffer, 1000);
+      while ((nread<0)&&(errno==EINTR));
+      if (nread<0) { perror("read"); exit(1); }
+      if (nread==0) {
+       fprintf(stderr,"node %d: rsh phase failed.\n",rsh_node[i]);
+       exit(1);
+      }
+      xstr_write(p->obuf, buffer, nread);
+      while (1) {
+       line = xstr_gets(buffer, 999, p->obuf);
+       if (line==0) break;
+       if (strncmp(line,"[1] ",4)==0) continue;
+       if (arg_debug || arg_debug_no_pause ||
+           (strcmp(line,"rsh phase successful.")
+            &&strcmp(line,"remote responding...")))
+         fprintf(stderr,"node %d: %s\n",rsh_node[i],line);
+       if (strcmp(line,"rsh phase successful.")==0) { done=1; break; }
+      }
+      if (!done) continue;
+      rsh_nfinished++;
+      prog_close(p);
+      rsh_prog[i] = 0;
+      if (rsh_nstarted==nodetab_size) break;
+      p = rsh_start(rsh_nstarted);
+      if (p==0) { perror("starting rsh"); exit(1); }
+      rsh_pump(p, rsh_nstarted, arg_argv);
+      rsh_prog[i] = p;
+      rsh_node[i] = rsh_nstarted;
+      rsh_nstarted++;
+    }
+  }
+}
+
+/****************************************************************************
+ *
+ *  The Main Program
+ *
+ ****************************************************************************/
+
+main(int argc, char **argv) {
+  srand(time(0));
+  /* Compute the values of all constants */
+  arg_init(argc, argv);
+  /* Initialize the node-table by reading nodesfile */
+  nodetab_init();
+  /* Initialize the request-server */
+  req_init();
+  /* Initialize the kill-handler */
+  notify_die_init();
+  /* Initialize the IO module */
+  input_init();
+  /* start the node processes */
+  start_nodes();
+  /* enter request-service mode */
+  req_serve();
+}
+
diff --git a/src/arch/tcp/machine.c b/src/arch/tcp/machine.c
new file mode 100644 (file)
index 0000000..f8f4f4d
--- /dev/null
@@ -0,0 +1,1956 @@
+/*****************************************************************************
+ *
+ * Machine-Specific Definitions
+ *
+ ****************************************************************************/
+
+#include "converse.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <setjmp.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <varargs.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <strings.h>
+#include <varargs.h>
+
+#ifdef CMK_NEED_DECLARATION_FOR_STRING_FNS
+char *strdup();
+char *strchr();
+#endif
+
+#ifdef CMK_RSH_IS_A_COMMAND
+#define RSH_CMD "rsh"
+#endif
+#ifdef CMK_RSH_USE_REMSH
+#define RSH_CMD "remsh"
+#endif
+
+#ifdef CMK_STRERROR_USE_SYS_ERRLIST
+extern char *sys_errlist[];
+#define strerror(i) (sys_errlist[i])
+#endif
+
+#ifdef CMK_SIGHOLD_USE_SIGMASK
+int sighold(sig) int sig;
+{ if (sigblock(sigmask(sig)) < 0) return -1;
+  else return 0; }
+int sigrelse(sig) int sig;
+{ if (sigsetmask(sigblock(0)&(~sigmask(sig))) < 0) return -1;
+  else return 0; }
+#endif
+
+static void KillEveryone();
+static void KillEveryoneCode();
+
+#ifdef DEBUG
+#define TRACE(p) p
+#else
+#define TRACE(p)
+#endif
+
+
+/*****************************************************************************
+ *
+ * CmiAlloc, CmiSize, and CmiFree
+ *
+ *****************************************************************************/
+
+static int CmiInsideMem = 1;
+
+void *CmiAlloc(size)
+int size;
+{
+char *res;
+res =(char *)malloc(size+8);
+if (res==0) KillEveryone("Memory allocation failed.");
+((int *)res)[0]=size;
+return (void *)(res+8);
+}
+
+int CmiSize(blk)
+char *blk;
+{
+return ((int *)(blk-8))[0];
+}
+
+void CmiFree(blk)
+char *blk;
+{
+free(blk-8);
+}
+
+/*****************************************************************************
+ *
+ *     Utility routines for network machine interface.
+ *
+ *
+ * Bcopy(char *s1, char *s2, int size)
+ *
+ *    - Temporary bcopy routine.  There seems to be a problem with the
+ *      usual one
+ *
+ * zap_newline(char *s)
+ *
+ *   - Remove the '\n' from the end of a string.
+ *
+ * char *substr(char *lo, char *hi)
+ *
+ *   - return an allocated copy of a string subsequence
+ *
+ * char *skipblanks(char *s)
+ *
+ *   - advance pointer over blank characters
+ *
+ * char *skipstuff(char *s)
+ *
+ *   - advance pointer over nonblank characters
+ *
+ * char *strdupl(char *s)
+ *
+ *   - return a freshly-allocated duplicate of a string
+ *
+ * int my_sendto
+ *     (int s, char *msg, int len, int flags, struct sockaddr *to, int tolen)
+ * 
+ *   - performs a "sendto", automatically retrying on trivial errors.
+ *
+ *****************************************************************************/
+
+
+static void Bcopy (s1,s2,size) char *s1,*s2; int size;
+{
+  int i;
+  for (i=0;i<size;i++) s2[i]=s1[i];
+}
+
+static void zap_newline(s) char *s;
+{
+  char *p;
+  p = s + strlen(s)-1;
+  if (*p == '\n') *p = '\0';
+}
+
+static char *substr(lo, hi) char *lo; char *hi;
+{
+  int len = hi-lo;
+  char *res = (char *)CmiAlloc(1+len);
+  memcpy(res, lo, len);
+  res[len]=0;
+  return res;
+}
+
+static char *skipblanks(p) char *p;
+{
+  while ((*p==' ')||(*p=='\t')||(*p=='\n')) p++;
+  return p;
+}
+
+static char *skipstuff(p) char *p;
+{
+  while ((*p)&&(*p!=' ')&&(*p!='\t')) p++;
+  return p;
+}
+
+static char *readint(p, value) char *p; int *value;
+{
+  int val = 0;
+  while (((*p)==' ')||((*p)=='.')) p++;
+  if (((*p)<'0')||((*p)>'9')) KillEveryone("badly-formed number");
+  while ((*p>='0')&&(*p<='9')) { val*=10; val+=(*p)-'0'; p++; }
+  *value = val;
+  return p;
+}
+
+static char *strdupl(s) char *s;
+{
+  int len = strlen(s);
+  char *res = (char *)CmiAlloc(len+1);
+  strcpy(res, s);
+  return res;
+}
+
+static int my_sendto(s, msg, len, flags, to, tolen)
+int s; char *msg; int len; int flags; struct sockaddr *to; int tolen;
+{
+  int ok;
+  while (1) {
+    ok = sendto(s, msg, len, flags, to, tolen);
+    if (ok>=0) break;
+  }
+  return ok;
+}
+
+static int wait_readable(fd, sec) int fd; int sec;
+{
+  fd_set rfds;
+  struct timeval tmo;
+  int begin, nreadable;
+  
+  begin = time(0);
+  FD_ZERO(&rfds);
+  FD_SET(fd, &rfds);
+ retry:
+  tmo.tv_sec = (time(0) - begin) + sec;
+  tmo.tv_usec = 0;
+  nreadable = select(FD_SETSIZE, &rfds, NULL, NULL, &tmo);
+  if ((nreadable<0)&&(errno==EINTR)) goto retry;
+  if (nreadable == 0) { errno=ETIMEDOUT; return -1; }
+  return 0;
+}
+
+/*****************************************************************************
+ *
+ * Logging Module
+ *
+ *****************************************************************************/
+
+static FILE *outlog_file;
+
+static void outlog_init(outputfile, index) char *outputfile; int index;
+{
+  char fn[MAXPATHLEN];
+  if (outputfile) {
+    sprintf(fn,outputfile,index);
+    outlog_file = fopen(fn,"w");
+  }
+  else outlog_file = 0;
+}
+
+static void outlog_done()
+{
+  fclose(outlog_file);
+}
+
+static void outlog_output(buf) char *buf;
+{
+  if (outlog_file) {
+    fprintf(outlog_file,"%s",buf);
+    fflush(outlog_file);
+  }
+}
+
+/**************************************************************************
+ *
+ * enable_async (enables signal-driven IO on a single descriptor)
+ *
+ **************************************************************************/
+
+#ifdef CMK_ASYNC_USE_SIOCGPGRP_AND_FIOASYNC
+static void enable_async(fd)
+int fd;
+{
+  int pid = getpid();
+  int async = 1;
+  if ( ioctl(fd, SIOCGPGRP, &pid) < 0  ) {
+    CmiError("getting socket owner") ;
+    KillEveryoneCode(65788) ;
+  }
+  if ( ioctl(fd, FIOASYNC, &async) < 0 ) {
+    CmiError("setting socket async") ;
+    KillEveryoneCode(94458) ;
+  }
+}
+#endif
+
+#ifdef CMK_ASYNC_USE_SETOWN_AND_SETFL
+static void enable_async(fd)
+int fd;
+{
+  if ( fcntl(fd, F_SETOWN, getpid()) < 0 ) {
+    CmiError("setting socket owner") ;
+    KillEveryoneCode(8789) ;
+  }
+  if ( fcntl(fd, F_SETFL, FASYNC) < 0 ) {
+    CmiError("setting socket async") ;
+    KillEveryoneCode(28379) ;
+  }
+}
+#endif
+
+#ifdef CMK_SIGNAL_USE_SIGACTION
+static void jsignal(sig, handler)
+int sig;
+void (*handler)();
+{
+  struct sigaction in, out ;
+  in.sa_handler = handler;
+  sigaction(sig, &in, &out);
+}
+#endif
+
+#ifdef CMK_SIGNAL_USE_SIGACTION_AND_SIGEMPTYSET
+static void jsignal(sig, handler)
+int sig;
+void (*handler)();
+{
+  struct sigaction in, out ;
+  in.sa_handler = handler ;
+  sigemptyset(&in.sa_mask);
+  in.sa_flags = SA_RESTART;
+  if(sigaction(sig, &in, &out) == -1)
+      KillEveryone("sigaction failed.");
+}
+#endif
+
+#ifdef CMK_SIGNAL_IS_A_BUILTIN
+static void jsignal(sig, handler)
+int sig;
+void (*handler)();
+{
+  signal(sig, handler) ;
+}
+#endif
+
+/**************************************************************************
+ *
+ * SKT - socket routines
+ *
+ *
+ * void skt_server(unsigned int *ppo, unsigned int *pfd)
+ *
+ *   - create a tcp server socket.  Performs the whole socket/bind/listen
+ *     procedure.  Returns the IP address of the socket (eg, the IP of the
+ *     current machine), the port of the socket, and the file descriptor.
+ *
+ * void skt_datagram(unsigned int *ppo, unsigned int *pfd)
+ *
+ *   - creates a UDP datagram socket.  Performs the whole socket/bind/
+ *     getsockname procedure.  Returns the IP address of the socket (eg,
+ *     the IP address of the current machine), the port of the socket, and
+ *     the file descriptor.
+ *
+ * void skt_accept(int src,
+ *                 unsigned int *pip, unsigned int *ppo, unsigned int *pfd)
+ *
+ *   - accepts a connection to the specified socket.  Returns the
+ *     IP of the caller, the port number of the caller, and the file
+ *     descriptor to talk to the caller.
+ *
+ * int skt_connect(unsigned int ip, int port, int timeout)
+ *
+ *   - Opens a connection to the specified server.  Returns a socket for
+ *     communication.
+ *
+ *
+ **************************************************************************/
+
+static void skt_server(ppo, pfd)
+unsigned int *ppo;
+unsigned int *pfd;
+{
+  int fd= -1;
+  int ok, len;
+  struct sockaddr_in addr;
+  
+  retry: fd = socket(PF_INET, SOCK_STREAM, 0);
+  if ((fd<0)&&(errno==EINTR)) goto retry;
+  if (fd < 0) { perror("socket"); KillEveryoneCode(93483); }
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  ok = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+  if (ok < 0) { perror("bind"); KillEveryoneCode(22933); }
+  ok = listen(fd,5);
+  if (ok < 0) { perror("listen"); KillEveryoneCode(3948); }
+  len = sizeof(addr);
+  ok = getsockname(fd, (struct sockaddr *)&addr, &len);
+  if (ok < 0) { perror("getsockname"); KillEveryoneCode(93583); }
+
+  *pfd = fd;
+  *ppo = ntohs(addr.sin_port);
+}
+
+static void skt_datagram(ppo, pfd)
+unsigned int *ppo;
+unsigned int *pfd;
+{
+  struct sockaddr_in name;
+  int length, ok, skt;
+
+  /* Create data socket */
+  retry: skt = socket(AF_INET,SOCK_DGRAM,0);
+  if ((skt<0)&&(errno==EINTR)) goto retry;
+  if (skt < 0)
+    { perror("socket"); KillEveryoneCode(8934); }
+  name.sin_family = AF_INET;
+  name.sin_port = 0;
+  name.sin_addr.s_addr = htonl(INADDR_ANY);
+  if (bind(skt, (struct sockaddr *)&name, sizeof(name)) == -1)
+    { perror("binding data socket"); KillEveryoneCode(2983); }
+  length = sizeof(name);
+  if (getsockname(skt, (struct sockaddr *)&name , &length))
+    { perror("getting socket name"); KillEveryoneCode(39483); }
+  *pfd = skt;
+  *ppo = htons(name.sin_port);
+}
+
+static void skt_accept(src, pip, ppo, pfd)
+int src;
+unsigned int *pip;
+unsigned int *ppo;
+unsigned int *pfd;
+{
+  int i, fd, ok;
+  struct sockaddr_in remote;
+  i = sizeof(remote);
+ acc:
+  fd = accept(src, (struct sockaddr *)&remote, &i);
+  if ((fd<0)&&(errno==EINTR)) goto acc;
+  if (fd<0) { perror("accept"); KillEveryoneCode(39489); }
+  *pip=htonl(remote.sin_addr.s_addr);
+  *ppo=htons(remote.sin_port);
+  *pfd=fd;
+}
+
+static int skt_connect(ip, port, seconds)
+unsigned int ip; int port; int seconds;
+{
+  struct sockaddr_in remote; short sport=port;
+  int fd, ok, len, retry, begin;
+    
+  /* create an address structure for the server */
+  memset(&remote, 0, sizeof(remote));
+  remote.sin_family = AF_INET;
+  remote.sin_port = htons(sport);
+  remote.sin_addr.s_addr = htonl(ip);
+    
+  begin = time(0);
+  while (time(0)-begin < seconds) {
+  sock:
+    fd = socket(AF_INET, SOCK_STREAM, 0);
+    if ((fd<0)&&(errno==EINTR)) goto sock;
+    if (fd < 0) { perror("socket"); exit(1); }
+    
+  conn:
+    ok = connect(fd, (struct sockaddr *)&(remote), sizeof(remote));
+    if ((ok<0)&&(errno==EINTR)) { close(fd); goto sock; }
+    if ((ok<0)&&(errno==EADDRINUSE)) { close(fd); goto sock; }
+    if (ok>=0) break;
+    if (errno!=ECONNREFUSED) break;
+    
+    sleep(1);
+  }
+  if (ok<0) {
+    perror("connect"); exit(1);
+  }
+  return fd;
+}
+
+/******************************************************************************
+ *
+ * CmiTimer
+ *
+ *****************************************************************************/
+
+#ifdef CMK_TIMER_USE_TIMES
+
+static struct tms inittime;
+
+static void CmiTimerInit()
+{
+  times(&inittime);
+}
+
+double CmiTimer()
+{
+  double currenttime;
+  int clk_tck;
+    struct tms temp;
+
+    times(&temp);
+    clk_tck=sysconf(_SC_CLK_TCK);
+    currenttime = 
+     (((temp.tms_utime - inittime.tms_utime)+
+       (temp.tms_stime - inittime.tms_stime))*1.0)/clk_tck;
+    return (currenttime);
+}
+
+#endif
+
+#ifdef CMK_TIMER_USE_GETRUSAGE
+
+static struct rusage inittime;
+
+static void CmiTimerInit()
+{
+  getrusage(0, &inittime); 
+}
+
+double CmiTimer() {
+  double currenttime;
+
+  struct rusage temp;
+  getrusage(0, &temp);
+  currenttime =
+    (temp.ru_utime.tv_usec - inittime.ru_utime.tv_usec) * 0.000001+
+      (temp.ru_utime.tv_sec - inittime.ru_utime.tv_sec) +
+       (temp.ru_stime.tv_usec - inittime.ru_stime.tv_usec) * 0.000001+
+         (temp.ru_stime.tv_sec - inittime.ru_stime.tv_sec) ; 
+  
+  return (currenttime);
+}
+
+#endif
+
+/*****************************************************************************
+ *
+ * Readonly Data
+ *
+ * Note that the default resend-wait and resend-fail are 10 and 600000
+ * milliseconds, respectively. Both are set very high, to
+ * ameliorate a known bug in the machine version.  If an entry-point is
+ * executing a CmiScanf, then it won't acknowledge messages.  To everyone
+ * else, it appears dead.  Therefore, the default_resend_fail is set very
+ * high to keep things going during long CmiScanfs.  (You have 10 minutes to
+ * respond).
+ *
+ *****************************************************************************/
+
+static int    resend_wait;        /* millisecs to wait before re-sending. */
+static int    resend_fail;        /* millisecs to wait before giving up. */
+static int    Cmi_enableinterrupts;
+static char   Topology;
+static char  *outputfile;
+
+int    Cmi_mype;
+int    Cmi_numpe;
+
+static int    host_IP;
+static char   host_IP_str[16];
+static int    host_port;
+static int    self_IP;
+static char   self_IP_str[16];
+static int    ctrl_port, ctrl_skt;
+static int    data_port, data_skt;
+
+#define MAX_NODES 100
+
+typedef struct {
+   int IP;
+   int dataport;
+   int ctrlport;
+} node_info;
+
+/* Information table about host and other nodes. */
+static node_info node_table[MAX_NODES];
+static int       node_table_fill;
+
+
+static void ParseNetstart()
+{
+  char *ns;
+  int nread;
+  ns = getenv("NETSTART");
+  if (ns==0) goto abort;
+  nread = sscanf(ns, "%d%d%d%d%d",
+                &Cmi_mype,&Cmi_numpe,&self_IP,&host_IP,&host_port);
+  if (nread!=5) goto abort;
+  return;
+ abort:
+  fprintf(stderr,"program not started using NETSTART utility. aborting.\n");
+  exit(1);
+}
+
+static char *DeleteArg(argv)
+char **argv;
+{
+  char *res = argv[0];
+  if (res==0) KillEveryone("Illegal Arglist");
+  while (*argv) { argv[0]=argv[1]; argv++; }
+  return res;
+}
+
+static void ExtractArgs(argv)
+char **argv;
+{
+  resend_wait = 10;
+  resend_fail = 600000;
+  Cmi_enableinterrupts = 1;
+  Topology = 'F';
+  outputfile = NULL;
+
+  while (*argv) {
+    if (strcmp(*argv,"++resend-wait")==0) {
+      DeleteArg(argv); resend_wait = atoi(DeleteArg(argv));
+    } else
+    if (strcmp(*argv,"++resend-fail")==0) {
+      DeleteArg(argv); resend_fail = atoi(DeleteArg(argv));
+    } else
+    if (strcmp(*argv,"++no-interrupts")==0) {
+      DeleteArg(argv); Cmi_enableinterrupts=0;
+    } else
+    if (strcmp(*argv,"++topology")==0) {
+      DeleteArg(argv); Topology=DeleteArg(argv)[0];
+    } else
+    if (strcmp(*argv,"++outputfile")==0) {
+      DeleteArg(argv); outputfile=DeleteArg(argv);
+    } else
+    argv++;
+  }
+}
+
+static void InitializePorts()
+{
+  skt_datagram(&data_port, &data_skt);
+  skt_server(&ctrl_port, &ctrl_skt);
+  
+  sprintf(self_IP_str,"%d.%d.%d.%d",
+         (self_IP>>24)&0xFF,(self_IP>>16)&0xFF,
+         (self_IP>>8)&0xFF,self_IP&0xFF);
+  sprintf(host_IP_str,"%d.%d.%d.%d",
+         (host_IP>>24)&0xFF,(host_IP>>16)&0xFF,
+         (host_IP>>8)&0xFF,host_IP&0xFF);
+}
+
+/****************************************************************************
+ *                                                                          
+ * Fast shutdown                                                            
+ *                                                                          
+ ****************************************************************************/
+
+static int KillIndividual(cmd, ip, port, sec)
+char *cmd; unsigned int ip; unsigned int port; int sec;
+{
+  int fd;
+  fd = skt_connect(ip, port, sec);
+  if (fd<0) return -1;
+  write(fd, cmd, strlen(cmd));
+  close(fd);
+  return 0;  
+}
+
+static void KillEveryone(msg)
+char *msg;
+{
+  char buffer[1024]; int i;
+  sprintf(buffer,"die %s",msg);
+  KillIndividual(buffer, host_IP, host_port, 30);
+  for (i=0; i<Cmi_numpe; i++)
+    KillIndividual(buffer, node_table[i].IP, node_table[i].ctrlport, 3);
+  exit(1);
+}
+
+static void KillEveryoneCode(n)
+int n;
+{
+  char buffer[1024];
+  sprintf(buffer,"Internal error #%d (node %d)\n(Contact CHARM developers)\n", n,Cmi_mype);
+  KillEveryone(buffer);
+}
+
+static void KillOnSegv()
+{
+  char buffer[1024];
+  sprintf(buffer, "Node %d: Segmentation fault.\n",Cmi_mype);
+  KillEveryone(buffer);
+}
+
+static void KillOnIntr()
+{
+  char buffer[1000];
+  sprintf(buffer, "Node %d: Interrupted.\n",Cmi_mype);
+  KillEveryone(buffer);
+}
+
+static void KillInit()
+{
+  signal(SIGSEGV, KillOnSegv);
+  signal(SIGBUS,  KillOnSegv);
+  signal(SIGILL,  KillOnSegv);
+  signal(SIGABRT, KillOnSegv);
+  signal(SIGFPE,  KillOnSegv);
+
+#ifdef SIGSYS
+  signal(SIGSYS,  KillOnSegv);
+#endif
+
+  signal(SIGPIPE, KillOnSegv);
+  signal(SIGURG,  KillOnSegv);
+
+  signal(SIGTERM, KillOnIntr);
+  signal(SIGQUIT, KillOnIntr);
+  signal(SIGINT,  KillOnIntr);
+}
+
+/****************************************************************************
+ *
+ * ctrl_getone
+ *
+ * Receive a command (on the control socket) from the host or another node,
+ * and process it.  This is just a dispatcher, none of the actual processing
+ * is done here.
+ *
+ ****************************************************************************/
+
+static void ctrl_sendone(va_alist) va_dcl
+{
+  char buffer[1024];
+  char *f; int fd, delay;
+  va_list p;
+  va_start(p);
+  delay = va_arg(p, int);
+  f = va_arg(p, char *);
+  vsprintf(buffer, f, p);
+  fd = skt_connect(host_IP, host_port, delay);
+  if (fd<0) KillEveryone("cannot contact host");
+  write(fd, buffer, strlen(buffer));
+  shutdown(fd, 1);
+  while (read(fd, buffer, 1023)>0);
+  close(fd);
+}
+
+static char *scanf_data;
+static int all_done = 0;
+static void node_addresses_store();
+
+static void ctrl_getone()
+{
+  char line[10000];
+  int ok, ip, port, fd;  FILE *f;
+  skt_accept(ctrl_skt, &ip, &port, &fd);
+  f = fdopen(fd,"r");
+  while (fgets(line, 9999, f)) {
+    if      (strncmp(line,"aval addr ",10)==0) node_addresses_store(line);
+    else if (strncmp(line,"aval done ",10)==0) all_done = 1;
+    else if (strncmp(line,"scanf-data ",11)==0) scanf_data=strdup(line+11);
+    else if (strncmp(line,"die ",4)==0) {
+      fprintf(stderr,"aborting: %s\n",line+4);
+      exit(0);
+    }
+    else KillEveryoneCode(2932);
+  }
+  fclose(f);
+  close(fd);
+}
+
+/*****************************************************************************
+ *
+ * node_addresses
+ *
+ *  These two functions fill the node-table.
+ *
+ *
+ *   This node, like all others, first sends its own address to the host
+ *   using this command:
+ *
+ *     aset addr <my-nodeno> <my-ip-addr>.<my-ctrlport>.<my-dataport>
+ *
+ *   Then requests all addresses from the host using this command:
+ *
+ *     aget <my-ip-addr> <my-ctrlport> addr 0 <numnodes>
+ *
+ *   when the host has all the addresses, he sends a table to me:
+ *
+ *     aval addr <ip-addr-0>.<ctrlport-0>.<dataport-0> ...
+ *
+ *****************************************************************************/
+
+static void node_addresses_receive()
+{
+  ctrl_sendone(120, "aset addr %d %s.%d.%d\n",
+              Cmi_mype, self_IP_str, ctrl_port, data_port);
+  ctrl_sendone(120, "aget %s %d addr 0 %d\n",
+    self_IP_str,ctrl_port,Cmi_numpe-1);
+  while (node_table_fill != Cmi_numpe) {
+    if (wait_readable(ctrl_skt, 300)<0)
+      { perror("waiting for data"); KillEveryoneCode(21323); }
+    ctrl_getone();
+  }
+}
+
+static void node_addresses_store(addrs) char *addrs;
+{
+  char *p, *e; int i, lo, hi;
+  if (strncmp(addrs,"aval addr ",10)!=0) KillEveryoneCode(83473);
+  p = skipblanks(addrs+10);
+  p = readint(p,&lo);
+  p = readint(p,&hi);
+  if ((lo!=0)||(hi!=Cmi_numpe-1)) KillEveryoneCode(824793);
+  for (i=0; i<Cmi_numpe; i++) {
+    unsigned int ip0,ip1,ip2,ip3,cport,dport;
+    p = readint(p,&ip0);
+    p = readint(p,&ip1);
+    p = readint(p,&ip2);
+    p = readint(p,&ip3);
+    p = readint(p,&cport);
+    p = readint(p,&dport);
+    node_table[i].IP = (ip0<<24)+(ip1<<16)+(ip2<<8)+ip3;
+    node_table[i].ctrlport = cport;
+    node_table[i].dataport = dport;
+  }
+  p = skipblanks(p);
+  if (*p!=0) KillEveryoneCode(82283);
+  node_table_fill = Cmi_numpe;
+}
+
+/*****************************************************************************
+ *
+ * CmiPrintf, CmiError, CmiScanf
+ *
+ *****************************************************************************/
+
+static void InternalPrintf(buf) char *buf; 
+{
+  char *p;
+  outlog_output(buf);
+  while (*buf) {
+    p = strchr(buf, '\n');
+    if (p) {
+      *p=0; ctrl_sendone(120, "print %s\n", buf);
+      *p='\n'; buf=p+1;
+    } else {
+      ctrl_sendone(120, "princ %s\n", buf); 
+      break;
+    }
+  }
+}
+
+static void InternalError(buf) char *buf;
+{
+  char *p;
+  outlog_output(buf);
+  while (*buf) {
+    p = strchr(buf, '\n');
+    if (p) {
+      *p=0; ctrl_sendone(120, "printerr %s\n", buf);
+      *p='\n'; buf = p+1;
+    } else {
+      ctrl_sendone(120, "princerr %s\n", buf); 
+      break;
+    }
+  }
+}
+
+void CmiPrintf(va_alist) va_dcl
+{
+  char buffer[8192];
+  va_list p;
+  char *f;
+  va_start(p);
+  f = va_arg(p, char *);
+  vsprintf(buffer, f, p);
+  InternalPrintf(buffer);
+}
+
+void CmiError(va_alist) va_dcl
+{
+  char buffer[8192];
+  va_list p;
+  char *f;
+  va_start(p);
+  f = va_arg(p, char *);
+  vsprintf(buffer, f, p);
+  InternalError(buffer);
+}
+
+int CmiScanf(va_alist) va_dcl
+{
+  static int CmiProbe();
+  char *ptr[20];
+  char *fmt; char *p; int nargs, i;
+  va_list l;
+  va_start(l);
+  fmt = va_arg(l, char *);
+  nargs=0;
+  p=fmt;
+  while (*p) {
+    if ((p[0]=='%')&&(p[1]=='*')) { p+=2; continue; }
+    if ((p[0]=='%')&&(p[1]=='%')) { p+=2; continue; }
+    if (p[0]=='%') { nargs++; p++; continue; }
+    if (*p=='\n') *p=' '; p++;
+  }
+  if (nargs > 18) KillEveryone("CmiScanf only does 18 args.\n");
+  for (i=0; i<nargs; i++) ptr[i]=va_arg(l, char *);
+  ctrl_sendone(120, "scanf %s %d %s", self_IP_str, ctrl_port, fmt);
+  while (scanf_data==0) CmiProbe();
+  i = sscanf(scanf_data, fmt, 
+        ptr[ 0], ptr[ 1], ptr[ 2], ptr[ 3], ptr[ 4], ptr[ 5],
+        ptr[ 6], ptr[ 7], ptr[ 8], ptr[ 9], ptr[10], ptr[11],
+        ptr[12], ptr[13], ptr[14], ptr[15], ptr[16], ptr[17]);
+  CmiFree(scanf_data);
+  scanf_data=0;
+  return i;
+}
+
+/*****************************************************************************
+ *
+ * Statistics Variables
+ *
+ *****************************************************************************/
+
+static int NumIntr;
+static int NumIntrCalls;
+static int NumOutsideMc;
+static int NumRetransmits;
+static int NumAcksSent;
+static int NumUseless;
+static int NumSends;
+
+/*****************************************************************************
+ *                                                                           
+ * Neighbour-Lookup functions.                                               
+ *                                                                           
+ * the neighbour information is computed dynamically.  It is computed solely 
+ * from the value of the Topology variable and the Cmi_numpe.             
+ *                                                                           
+ *****************************************************************************/
+
+int CmiNumNeighbours(node)
+     int node;
+{
+  switch (Topology) {
+  case 'F': case 'f':          /* Full interconnectivity */
+    return Cmi_numpe-1;
+  default: KillEveryoneCode(233);
+  }
+}
+
+void CmiGetNodeNeighbours(node, nghbrs)
+     int node; int *nghbrs;
+{
+  int i;
+  switch (Topology) {
+  case 'F': case 'f':          /* Full interconnectivity */
+    for (i=0; i<node; i++) *nghbrs++ = i;
+    for (i=node+1; i<Cmi_numpe; i++) *nghbrs++ = i;
+    break;
+  default: KillEveryoneCode(234);
+  }
+}
+
+int CmiNeighboursIndex(PeNum, neighbourPeNum)
+     int PeNum; int neighbourPeNum;
+{
+  int i=0;
+  switch (Topology) {
+  case 'F': case 'f':          /* Full interconnectivity */
+    if (neighbourPeNum < PeNum) return neighbourPeNum;
+    return neighbourPeNum-1;
+    break;
+  default: KillEveryoneCode(235);
+  }
+}
+
+/*****************************************************************************
+ *
+ * Datagram Transmission Definitions
+ *
+ *****************************************************************************/
+
+/* Types of messages. */
+# define SEND  1
+# define ACK   2
+
+typedef unsigned char BYTE;
+
+/* In bytes.  Make sure this is greater than zero! */
+/* Works out to be about 2018 bytes. */
+# define MAX_FRAG_SIZE (CMK_MAX_DGRAM_SIZE - sizeof(DATA_HDR))
+
+/* Format of the header sent with each fragment. */
+typedef struct DATA_HDR
+{
+  unsigned int seq_num;
+  BYTE send_or_ack;            /* SEND or ACK (acknowledgment). */
+  BYTE msg_type;               /* Currently, always 1. */
+  unsigned int SourcePeNum;
+  unsigned int DestPeNum;
+  unsigned int numfrags;
+  unsigned int size;           /* size of message, not including header. */
+  unsigned int full_size;      /* Size of complete message */
+}
+DATA_HDR;
+
+/* Header combined with data fragment. */
+typedef struct msgspace
+{
+  DATA_HDR hd;
+  char data[CMK_MAX_DGRAM_SIZE-sizeof(DATA_HDR)];
+}
+msgspace;
+
+typedef struct
+{
+  DATA_HDR        *packet;
+  unsigned int     seq_num;
+  int              send_time;
+}
+WindowElement;
+
+typedef struct pkt_queue_elem
+{
+  DATA_HDR *packet;
+  struct pkt_queue_elem *nextptr;
+}
+PacketQueueElem;
+
+typedef struct msg_queue_elem
+{
+  PacketQueueElem *packetlist;
+  struct msg_queue_elem *nextptr;
+}
+MsgQueueElem;
+
+typedef struct new_msg
+{
+  int numpackets;
+  PacketQueueElem *packetlist;
+}
+NewMessage;
+
+#define WINDOW_SIZE 16             /* size of sliding window  */
+
+#define MAX_SEQ_NUM 0xFFFFFFFF     /* 2^32 - 1 */
+
+static int Cmi_insidemachine;
+
+static int free_ack=0;
+static int free_send=0;
+static int alloc_ack=0;
+static int alloc_send=0;
+
+static int Communication_init; /* Communication set up yet? */
+
+
+static WindowElement **send_window;       /* packets awaiting acks  */
+
+static PacketQueueElem **transmit_head;   /* packets awaiting transmission */
+static PacketQueueElem **transmit_tail; 
+                                                   
+
+static int *first_window_index;     
+static int *last_window_index;     
+static int *cur_window_size;
+static unsigned int  *next_seq_num;
+static int *timeout_factor ;
+
+static WindowElement **recv_window;    /* packets awaiting acks  */
+
+static int *next_window_index;         /* index of 1st entry in recv window */
+static unsigned int *expected_seq_num; /* next sequence number expected */
+
+static NewMessage *recd_messages;
+
+static int *needack;
+
+static DATA_HDR ack;
+
+static MsgQueueElem *recd_msg_head, *recd_msg_tail;
+
+
+/****************************************************************************/
+/* ROUTINES FOR SENDING/RECEIVING MESSAGES
+**
+** Definition of terms:
+** Synchronized send -- The send doesn't return until the buffer space of
+**  the data sent is free for re-use, that is, until a write to that buffer
+**  space will not cause the message being sent to be disrupted or altered
+**  in any way.
+**
+** Synchronized receive -- The receive doesn't return until all of the data
+**  has been placed in the receiving buffer.
+**
+** -CW
+*/
+/****************************************************************************/
+
+
+/* Send an acknowledging message to the source PE named in the message header.
+** The acknowledgement has the same header, except that the message type is
+** changed to ACK. (So, the "size" field in the header will be
+** incorrect for ACK's).
+*/
+static void send_ack(packet) 
+    DATA_HDR *packet; 
+    {
+    node_info *dest = node_table + packet->SourcePeNum;
+    struct sockaddr_in addr;
+    addr.sin_family      = AF_INET;
+    addr.sin_port        = htons(dest->dataport);
+    addr.sin_addr.s_addr = htonl(dest->IP);
+    NumSends++;
+    my_sendto(data_skt, (char *)packet, sizeof(DATA_HDR), 0, (struct sockaddr *)&addr, sizeof(addr));
+    }
+
+
+static char *
+msg_tuple(PeNum,msgid,ack_or_send) int PeNum,msgid,ack_or_send; {
+   static char buf[100];
+   char type;
+
+   switch(ack_or_send) {
+   case ACK:type='A';
+      break;
+   case SEND:type='S';
+      break;
+   default:type='?';
+      break;
+   }
+   sprintf(buf,"(%d,%d,%c)",PeNum,msgid,type);
+   return buf;
+}
+
+
+
+/* This section implements a send sliding window protocol for the IPnet 
+   implementation of the Chare kernel. The modification to Chris Walquist's 
+   implementation are as follows:
+
+   1) The sends are not synchronous, i.e. every pack is not acknowledged before
+      the next packet is sent. Instead, packets are sent until WINDOW_SIZE 
+      packets remain unacknowledged.
+
+   2) An ack packet with sequence number N acknowledges all packets upto and
+      including N. Thus, it is not necessary for all packets to be explicitly
+      acknowledged.
+
+   3) After the sends have been completed, no waits are performed. Instead,
+      execution of the Loop resumes. During each pump message phase of the 
+      loop, the sliding window is updated as and when ack packets are received.
+
+   4) One send window per destination is necessary for sequence numbers of
+      acks to be used as required in (2).
+
+              Questions, Comments and Criticisms to be directed to
+
+                        Balkrishna Ramkumar
+                       ramkumar@crhc.uiuc.edu
+
+*/
+   
+      
+static void SendWindowInit()
+{
+    int i,j;
+    int numpe = Cmi_numpe;
+    int mype = Cmi_mype;
+
+    send_window = (WindowElement **) CmiAlloc(numpe * sizeof(WindowElement *));
+    transmit_head = (PacketQueueElem **) CmiAlloc(numpe * sizeof(PacketQueueElem *));
+    transmit_tail = (PacketQueueElem **) CmiAlloc(numpe * sizeof(PacketQueueElem *));
+    first_window_index = (int *) CmiAlloc(numpe * sizeof(int));
+    last_window_index = (int *) CmiAlloc(numpe * sizeof(int));
+    cur_window_size = (int *) CmiAlloc(numpe * sizeof(int));
+    next_seq_num = (unsigned int  *) CmiAlloc(numpe * sizeof(unsigned int ));
+/* Sanjeev */
+    timeout_factor = (int *)CmiAlloc(numpe * sizeof(int)) ;
+
+    for (i = 0; i < numpe; i++)
+    {
+       if (i != mype)
+       {
+           send_window[i] = (WindowElement *) CmiAlloc(WINDOW_SIZE * sizeof(WindowElement));
+           for (j = 0; j < WINDOW_SIZE; j++)
+           {
+               send_window[i][j].packet = NULL;
+               send_window[i][j].seq_num = 0;
+               send_window[i][j].send_time = 0;
+           }
+       }
+       else send_window[i] = NULL;  /* never used */
+
+       first_window_index[i] = 0;
+       last_window_index[i] = 0;
+       cur_window_size[i] = 0;
+       next_seq_num[i] = 0;
+       transmit_head[i] = NULL;
+       transmit_tail[i] = NULL;
+    /* Sanjeev */
+       timeout_factor[i] = 1 ;
+    }
+}
+
+/* This routine adds a packet to the tail of the transmit queue */
+
+static void InsertInTransmitQueue(packet, destpe)
+DATA_HDR *packet;
+int destpe;
+{
+    PacketQueueElem *newelem;
+
+    newelem = (PacketQueueElem *) CmiAlloc(sizeof(PacketQueueElem));
+    newelem->packet = packet;
+    newelem->nextptr = NULL;
+    if  (transmit_tail[destpe] == NULL)
+        transmit_head[destpe] = newelem;
+    else transmit_tail[destpe]->nextptr = newelem;
+    transmit_tail[destpe] = newelem;
+}
+
+
+/* This routine returns the packet at the head of the transmit queue. If no
+   packets exist, NULL is returned */
+
+static DATA_HDR *GetTransmitPacket(destpe)
+int destpe;
+{
+    PacketQueueElem *elem;
+    DATA_HDR *packet;
+
+    if  (transmit_head[destpe] == NULL)
+        return NULL;
+    else 
+    {
+       elem = transmit_head[destpe];
+       transmit_head[destpe] = transmit_head[destpe]->nextptr;
+       if (transmit_head[destpe] == NULL)
+           transmit_tail[destpe] = NULL;
+       packet = elem->packet;
+       CmiFree(elem);
+       return packet;
+    }
+}
+
+/* This routine adds the packet to the send window. If the addition is
+   successful, the function returns TRUE. If the window is full, it returns
+   FALSE - the calling function will then have to insert the packet into 
+   the transmit queue */
+
+static int AddToSendWindow(packet, destpe)
+DATA_HDR *packet;
+int destpe;
+{
+    send_window[destpe][last_window_index[destpe]].packet =  packet;
+    send_window[destpe][last_window_index[destpe]].seq_num = next_seq_num[destpe];
+    send_window[destpe][last_window_index[destpe]].send_time = CmiTimer()*1000;
+    packet->seq_num = next_seq_num[destpe];
+    next_seq_num[destpe]++;
+    last_window_index[destpe] = (last_window_index[destpe] + 1) % WINDOW_SIZE;
+    cur_window_size[destpe]++;
+    return TRUE;
+}
+
+static SendPackets(destpe)
+int destpe;
+{
+    DATA_HDR *GetTransmitPacket();
+    DATA_HDR *packet;
+    int bytes_sent;
+    int i;
+    struct sockaddr_in addr;
+
+    while (cur_window_size[destpe] < WINDOW_SIZE &&
+          ((packet = GetTransmitPacket(destpe)) != NULL))
+    {
+       AddToSendWindow(packet, destpe);
+       TRACE(CmiPrintf("Node %d: sending packet seq_num=%d, num_frags=%d fullsize=%d\n",
+                      Cmi_mype,
+                      packet->seq_num, packet->numfrags, 
+                      packet->full_size));
+
+        addr.sin_family      = AF_INET;
+        addr.sin_port        = htons(node_table[destpe].dataport);
+        addr.sin_addr.s_addr = htonl(node_table[destpe].IP);
+
+        NumSends++ ;
+       bytes_sent = my_sendto(data_skt, (char *)packet,
+                           packet->size + sizeof(DATA_HDR),
+                           0, (struct sockaddr *)&addr, sizeof(addr));
+       /* if (bytes_sent != packet->size + sizeof(DATA_HDR)) KillEveryoneCode(21); */
+    }
+}
+
+/* This routine updates the send window upon receipt of an ack. Old acks
+   are ignored */
+
+static UpdateSendWindow(ack, sourcepe)
+DATA_HDR *ack;
+int sourcepe;
+{
+    int i, index;
+    int found;
+    int count;
+
+    if (cur_window_size[sourcepe] == 0)  /* empty window */
+        return;
+
+    index = first_window_index[sourcepe];
+    found = FALSE;
+    count = 0;
+    while (count < cur_window_size[sourcepe] && !found) 
+    {
+       found = (send_window[sourcepe][index].seq_num == ack->seq_num);
+       index = (index + 1) % WINDOW_SIZE;
+       count++;
+    }
+    if (found)
+    {
+       TRACE(CmiPrintf("Node %d: received ack with seq_num %d\n",
+                      Cmi_mype, ack->seq_num)); 
+       index = first_window_index[sourcepe];
+       for (i = 0; i < count; i++)
+       {
+           CmiFree(send_window[sourcepe][index].packet);
+           send_window[sourcepe][index].packet = NULL;
+           index = (index + 1) % WINDOW_SIZE;
+       }
+        first_window_index[sourcepe] = index;
+       cur_window_size[sourcepe] -= count;
+    }
+    SendPackets(sourcepe);   /* any untransmitted pkts */
+}
+
+/* This routine extracts a packet with a given sequence number. It returns
+   NULL if no packet with the given sequence number exists in the window 
+   This will be used primarily if retransmission is required - the packet 
+   is not removed from the window */
+
+static int RetransmitPackets()
+{
+  int i, index, fnord;
+  DATA_HDR *packet;
+  struct sockaddr_in addr;
+  int sending=0;
+
+  for (i = 0; i < Cmi_numpe; i++) {
+    index = first_window_index[i];
+    if (cur_window_size[i] > 0) {
+      sending = 1;
+      if ((CmiTimer()*1000 - send_window[i][index].send_time) > 
+         (resend_wait * timeout_factor[i])) {
+       /* timeout_factor[i] *= 2 ;  for exponential backoff */
+       if (resend_wait * timeout_factor[i] > resend_fail) {
+         KillEveryone("retransmission failed, timeout.");
+       }
+       packet = send_window[i][index].packet;
+       addr.sin_family      = AF_INET;
+       addr.sin_port        = htons(node_table[i].dataport);
+       addr.sin_addr.s_addr = htonl(node_table[i].IP);
+       
+       NumRetransmits++ ;
+       NumSends++;
+       my_sendto(data_skt, (char *)packet,
+                 packet->size + sizeof(DATA_HDR), 0, (struct sockaddr *)&addr, sizeof(addr)); 
+         send_window[i][index].send_time = CmiTimer() * 1000;
+      }
+    }
+  }
+  return sending;
+}
+
+
+static void fragment_send(destPE,size,msg,full_size,msg_type, numfrags)
+     int destPE;
+     int size;
+     char *msg; 
+     int full_size; 
+     int msg_type; 
+     int numfrags;
+{
+  int send_timeout();
+  int bytes_sent=0;
+  DATA_HDR *hd;
+  
+  /* Is datagram too small to hold fragment and data header? */ 
+  if (MAX_FRAG_SIZE + sizeof(DATA_HDR) > CMK_MAX_DGRAM_SIZE)
+    KillEveryoneCode(5);
+  
+  TRACE(CmiPrintf("Node %d: sending fragment. fragsize=%d msgsize=%d\n", 
+                 Cmi_mype, size, full_size));
+  
+  
+  /* Initialize the data header part of the send space. */
+  hd = (DATA_HDR *)CmiAlloc(sizeof(DATA_HDR) + size);
+  if ( hd == NULL ) {
+    CmiPrintf("*** ERROR *** Memory Allocation Failed.\n");
+    return ;
+  }
+  hd->DestPeNum = destPE;
+  hd->size = size;
+  hd->full_size = full_size;
+  hd->msg_type = msg_type;
+  hd->send_or_ack = SEND;
+  hd->SourcePeNum = Cmi_mype;
+  hd->numfrags = numfrags;
+  
+  /* Transfer the data to the data part of the send space. */
+  Bcopy(msg, (hd + 1), size);
+  InsertInTransmitQueue(hd, destPE);
+}
+
+
+/* This section implements a receive sliding window protocol for the IPnet 
+   implementation of the Chare kernel. The modification to Chris Walquist's 
+   implementation are as follows:
+
+   1) An ack packet with sequence number N acknowledges all packets upto and
+      including N. Thus, it is not necessary for all packets to be explicitly
+      acknowledged.
+
+   2) The sliding window will guarantee that packets are delivered in order
+      once successfully received. 
+
+   3) One receive window per sender is necessary.
+
+              Questions, Comments and Criticisms to be directed to
+
+                        Balkrishna Ramkumar
+                       ramkumar@crhc.uiuc.edu
+*/
+   
+
+static RecvWindowInit()
+{
+    int i,j;
+    int numpe = Cmi_numpe;
+    int mype = Cmi_mype;
+
+    recv_window = (WindowElement **) CmiAlloc(numpe * sizeof(WindowElement *));
+    next_window_index = (int *) CmiAlloc(numpe * sizeof(int));
+    expected_seq_num = (unsigned int *) CmiAlloc(numpe * sizeof(unsigned int));
+    recd_messages = (NewMessage *) CmiAlloc(numpe * sizeof(NewMessage));
+    needack = (int *) CmiAlloc(numpe * sizeof(int));
+    for (i = 0; i < numpe; i++)
+    {
+       if (i != mype)
+       {
+           recv_window[i] = (WindowElement *) CmiAlloc(WINDOW_SIZE * sizeof(WindowElement));
+           for (j = 0; j < WINDOW_SIZE; j++)
+           {
+               recv_window[i][j].packet = NULL;
+               recv_window[i][j].seq_num = 0;
+               recv_window[i][j].send_time = 0;
+           }
+       }
+       else recv_window[i] = NULL;  /* never used */
+
+       next_window_index[i] = 0;
+       expected_seq_num[i] = 0;
+       recd_messages[i].numpackets = 0;
+       recd_messages[i].packetlist = NULL;
+       needack[i] = FALSE;
+    }
+    recd_msg_head = NULL;
+    recd_msg_tail = NULL;
+
+    ack.DestPeNum = Cmi_mype;
+    ack.send_or_ack = ACK;
+}
+
+
+
+
+/* This routine tries to add an incoming packet to the recv window. 
+   If the packet has already been received, the routine discards it and
+   returns FALSE. Otherwise the routine inserts it into the window and
+   returns TRUE
+*/
+
+static int AddToReceiveWindow(packet, sourcepe)
+     DATA_HDR *packet;
+     int sourcepe;
+{
+  int index;
+  unsigned int seq_num = packet->seq_num;
+  unsigned int last_seq_num = expected_seq_num[sourcepe] + WINDOW_SIZE - 1;
+
+  /* 
+     Note that seq_num cannot be > last_seq_num.
+     Otherwise,  > last_seq_num - WINDOW_SIZE has been ack'd.
+     If that were the case, 
+     expected_seq_num[sourcepe] > > last_seq_num - WINDOW_SIZE,
+     which is a contradiction
+     */
+
+  if (expected_seq_num[sourcepe] < last_seq_num)
+    {
+      if (seq_num < expected_seq_num[sourcepe])
+       {
+         CmiFree(packet);      /* already received */
+         needack[sourcepe] = TRUE;
+         NumUseless++ ;
+         return FALSE;
+       }
+      else 
+       {
+         index = (next_window_index[sourcepe] + 
+                  seq_num - expected_seq_num[sourcepe]) % WINDOW_SIZE;
+         /* put needack and NumUseless++ here ??? */
+         if (recv_window[sourcepe][index].packet) CmiFree(packet);
+         else {
+           recv_window[sourcepe][index].packet = packet;
+           recv_window[sourcepe][index].seq_num = seq_num;
+           TRACE(CmiPrintf("Node %d: Inserting packet %d at index %d in recv window\n",
+                          Cmi_mype,
+                          seq_num, index)); 
+         }
+       }
+    }
+  return TRUE;
+}
+
+/* this routine supplies the next packet in the receive window and updates
+   the window. The window entry - packet + sequence number, is no longer
+   available. If the first entry in the window is a null packet - i.e. it
+   has not arrived, the routine returns NULL 
+   */
+
+static DATA_HDR *ExtractNextPacket(sourcepe)
+     int sourcepe;
+{
+  DATA_HDR *packet;
+  int index = next_window_index[sourcepe];
+
+  packet = recv_window[sourcepe][index].packet;
+  if (packet != NULL)
+    {
+      recv_window[sourcepe][index].packet = NULL;
+      needack[sourcepe] = TRUE;
+      expected_seq_num[sourcepe]++;
+      next_window_index[sourcepe] = (next_window_index[sourcepe] + 1) % WINDOW_SIZE;
+    }
+  return packet;
+}
+
+
+/* This routine inserts a completed messages as a list of packets in reverse
+   order into the recd_msg queue */
+
+static InsertInMessageQueue(packetlist)
+     PacketQueueElem *packetlist;
+{
+  MsgQueueElem *newelem;
+
+  newelem = (MsgQueueElem *) CmiAlloc(sizeof(MsgQueueElem));
+  newelem->packetlist = packetlist;
+  newelem->nextptr = NULL;
+  if  (recd_msg_tail == NULL)
+    recd_msg_head = newelem;
+  else recd_msg_tail->nextptr = newelem;
+  recd_msg_tail = newelem;
+  TRACE(CmiPrintf("Node %d: inserted seqnum=%d fullsize=%d in message queue\n", 
+                Cmi_mype,
+                recd_msg_head->packetlist->packet->seq_num,
+                recd_msg_head->packetlist->packet->full_size));
+}
+
+
+static void ConstructMessages()
+{
+  int i;
+  DATA_HDR *packet;
+  DATA_HDR *ExtractNextPacket();
+  PacketQueueElem *packetelem;
+
+  TRACE(CmiPrintf("Node %d: in ConstructMessages().\n",Cmi_mype));
+  for (i = 0; i < Cmi_numpe; i++)
+    if (i != Cmi_mype) {
+      packet = ExtractNextPacket(i);
+      while (packet != NULL) {
+       packetelem = (PacketQueueElem *) CmiAlloc(sizeof(PacketQueueElem));
+       packetelem->packet = packet;
+       /* Note: we are stacking it in reverse order */
+       packetelem->nextptr = recd_messages[i].packetlist; 
+       recd_messages[i].packetlist = packetelem; 
+       recd_messages[i].numpackets++;
+       if (recd_messages[i].numpackets == packet->numfrags) {
+         /* msg complete */
+         if (packet->msg_type == 1) {
+           TRACE(CmiPrintf("Node %d: CK packet complete seqnum=%d numfrags=%d\n",
+                          Cmi_mype,
+                          packet->seq_num, packet->numfrags));
+           InsertInMessageQueue(recd_messages[i].packetlist);
+         }
+         recd_messages[i].packetlist = NULL;
+         recd_messages[i].numpackets = 0;
+       }
+       packet = ExtractNextPacket(i);
+      }
+    }
+}
+
+
+
+static void AckReceivedMsgs()
+{
+  int i;
+  for (i = 0; i < Cmi_numpe; i++)
+    if (needack[i])    {
+      needack[i] = FALSE;
+      ack.SourcePeNum = i;
+      ack.seq_num = expected_seq_num[i] - 1;
+      if (Cmi_mype < Cmi_numpe)
+       TRACE(CmiPrintf("Node %d: acking seq_num %d on window %d\n",
+                      Cmi_mype, ack.seq_num, i)); 
+      NumAcksSent++ ;
+      send_ack(&ack);
+    }
+}
+
+static int data_getone()
+{
+  msgspace *recv_buf=NULL;
+  struct sockaddr_in src;
+  int i, srclen=sizeof(struct sockaddr_in);
+  int arrived = FALSE;
+  node_info *sender; int kind;
+  int AddToReceiveWindow();
+  int n;
+
+  recv_buf = (msgspace *)CmiAlloc(CMK_MAX_DGRAM_SIZE);
+  do n=recvfrom(data_skt,(char *)recv_buf,CMK_MAX_DGRAM_SIZE,0,(struct sockaddr *)&src,&srclen);
+  while ((n<0)&&(errno==EINTR));
+  if (n<0) { KillEveryone(strerror(errno)); }
+  kind = recv_buf->hd.send_or_ack;
+  if (kind == ACK)
+    {
+      /* remove it from the socket */
+      if (recv_buf->hd.SourcePeNum != Cmi_mype) 
+       KillEveryoneCode(7);
+      UpdateSendWindow(recv_buf, (int) recv_buf->hd.DestPeNum);
+      CmiFree(recv_buf);
+    }
+  else if (kind == SEND)
+    {
+      sender = node_table + recv_buf->hd.SourcePeNum;
+      /* sender->IP       = htonl(src.sin_addr.s_addr); */
+      if((sender->dataport)&&(sender->dataport!=htons(src.sin_port)))
+       KillEveryoneCode(38473);
+      sender->dataport = htons(src.sin_port);
+      arrived = TRUE;
+      AddToReceiveWindow(recv_buf, (int) recv_buf->hd.SourcePeNum);
+    }
+  else KillEveryoneCode(8); /* invalid datagram type. */
+  return kind;
+}
+
+static void dgram_scan()
+{
+  fd_set rfds;
+  struct timeval tmo;
+  int nreadable, gotsend=0;
+
+  while (1) {
+    FD_ZERO(&rfds);
+    FD_SET(data_skt, &rfds);
+    FD_SET(ctrl_skt, &rfds);
+    tmo.tv_sec = 0;
+    tmo.tv_usec = 0;
+    do nreadable = select(FD_SETSIZE, &rfds, NULL, NULL, &tmo);
+    while ((nreadable<0)&&(errno==EINTR));
+    if (nreadable <= 0) break;
+    if (FD_ISSET(ctrl_skt, &rfds))
+      ctrl_getone();
+    if (FD_ISSET(data_skt, &rfds)) {
+      int kind = data_getone();
+      if (kind==SEND) gotsend=1;
+    }
+  }
+  if (gotsend) {
+    ConstructMessages();
+    AckReceivedMsgs();
+  }
+}
+
+static void InterruptHandler()
+{
+  int prevmask ;
+  void dgram_scan();
+
+  NumIntrCalls++;
+  if ( Cmi_insidemachine)
+    return ;
+  NumOutsideMc++;
+  if (CmiInsideMem)
+    return ;
+  sighold(SIGIO) ;
+
+  dgram_scan();
+  RetransmitPackets();
+
+  sigrelse(SIGIO) ;
+  NumIntr++ ;
+}
+
+static void InterruptInit()
+{
+  if (Cmi_enableinterrupts) {
+    jsignal(SIGIO, InterruptHandler);
+    enable_async(data_skt);
+  }
+}
+
+
+/*
+** Synchronized send of "msg", of "size" bytes, to "destPE".
+** Returns the number of bytes of "msg" actually sent.
+** 
+** This routine differentiates between Chare Kernel messages and machine-level
+** messages by including a msg_type parameter.  It's called by the 
+** CmiSyncSend() macro, defined in conv-mach.h.
+**
+** -CW
+*/
+static int netSend(destPE, size, msg, msg_type) 
+    int destPE, size; 
+    char * msg; 
+    int msg_type;
+    {
+    int saveflag ;
+
+    if (!Communication_init) return -1;
+
+    if (destPE==Cmi_mype) 
+        {
+       CmiError("illegal send to myself\n");
+       return -1;
+        } 
+
+    saveflag = Cmi_insidemachine ;
+    Cmi_insidemachine = TRUE ;
+
+    if (size > MAX_FRAG_SIZE) 
+        {
+       /* Break the message into pieces and send each piece; start numbering
+        ** fragments with one.
+        */
+       int i;
+       int frags = ((size-1)/MAX_FRAG_SIZE) + 1;
+
+       for(i=1;i<frags;i++) 
+           fragment_send(destPE, MAX_FRAG_SIZE, msg+((i-1)*MAX_FRAG_SIZE), 
+                         size, msg_type, frags);
+
+       /* Last fragment is (probably) a different size. */
+       fragment_send(destPE, size - MAX_FRAG_SIZE*(frags-1),
+                     msg+(frags-1)*MAX_FRAG_SIZE,  size, msg_type, frags);
+
+        } 
+    else fragment_send(destPE, size, msg, size, msg_type, 1);
+
+    SendPackets(destPE);
+
+    Cmi_insidemachine = saveflag ;
+    }
+
+void *CmiLocalQueue;
+
+static int CmiProbe() 
+{
+  int val, saveflag;
+  void dgram_scan();
+
+  saveflag = Cmi_insidemachine ;
+  Cmi_insidemachine = TRUE ;
+
+  dgram_scan();
+  RetransmitPackets();
+  val = (recd_msg_head != NULL);
+
+  Cmi_insidemachine = saveflag ;
+  return (val);
+}
+
+void *CmiGetNonLocal()
+{
+  int i;
+  char *nextptr;
+  PacketQueueElem *packetelem, *nextpacket;
+  MsgQueueElem *msgelem;
+  DATA_HDR *packet;
+  void *newmsg;
+  int msglength;
+  int saveflag;
+
+  saveflag = Cmi_insidemachine;
+  Cmi_insidemachine = TRUE;
+
+  dgram_scan();
+  RetransmitPackets();
+  if (recd_msg_head==NULL) { newmsg=NULL; goto done; }
+  
+  msgelem = recd_msg_head;
+  packetelem = msgelem->packetlist;
+  if (recd_msg_head == recd_msg_tail) {
+    recd_msg_head = NULL;
+    recd_msg_tail = NULL;
+  }
+  else recd_msg_head = recd_msg_head->nextptr;
+  CmiFree(msgelem);
+  
+  /* now construct message */
+  msglength = packetelem->packet->full_size;
+  newmsg = (void *)CmiAlloc(msglength);
+  nextptr = newmsg + msglength;
+  while (packetelem != NULL) {
+    nextpacket = packetelem->nextptr;
+    packet = packetelem->packet;
+    nextptr -= packet->size;
+    Bcopy(packet+1, nextptr, packet->size);
+    CmiFree(packetelem);
+    CmiFree(packet);
+    packetelem = nextpacket;
+  }
+
+ done:
+  Cmi_insidemachine = saveflag;
+  return newmsg;
+}
+
+
+void CmiSyncSend(destPE, size, msg)
+int destPE;
+int size;
+char *msg;
+{
+  netSend(destPE,size,msg,1);
+}
+
+void CmiBroadcast(size,msg)
+     int size; char *msg;
+{
+  int i;
+  for (i=0;i<Cmi_numpe;i++)
+    {
+      if (i != Cmi_mype) netSend(i,size,msg,1);
+    }
+  CmiFree(msg) ;
+}
+
+void CmiSyncBroadcast(size,msg)
+     int size; char *msg;
+{
+  int i;
+  for (i=0;i<Cmi_numpe;i++)
+    {
+      if (i != Cmi_mype) netSend(i,size,msg,1);
+    }
+}
+
+void CmiSyncBroadcastAllAndFree(size,msg)
+     int size; char *msg;
+{
+  int i;
+  for (i=0;i<Cmi_numpe;i++)
+    if (i != Cmi_mype) netSend(i,size,msg,1);
+  FIFO_EnQueue(CmiLocalQueue,msg);
+}
+
+void CmiSyncBroadcastAll(size,msg)
+     int size; char *msg;
+{
+  int i;
+  char *msg1;
+  for (i=0;i<Cmi_numpe;i++)
+    if (i != Cmi_mype) netSend(i,size,msg,1);
+  msg1 = (char *)CmiAlloc(size);
+  memcpy(msg1,msg,size);
+  FIFO_EnQueue(CmiLocalQueue,msg1);
+}
+
+CmiCommHandle *CmiAsyncBroadcast(size, msg)
+     int size; char *msg;
+{
+  CmiSyncBroadcast(size, msg);
+  return NULL;
+}
+
+CmiCommHandle *CmiAsyncBroadcastAll(size, msg)
+     int size; char *msg;
+{
+  CmiSyncBroadcastAll(size, msg);
+  return NULL;
+}
+
+static void CmiSleep()
+{
+  if (Cmi_enableinterrupts) sigpause(0L);
+}
+
+CmiCommHandle *CmiAsyncSend(destPE, size, msg)
+     int destPE, size;
+     char *msg;
+{
+  CmiSyncSend(destPE, size, msg);
+  return NULL;
+}
+
+int CmiAsyncMsgSent(phandle)
+     CmiCommHandle *phandle;
+{
+  return TRUE;
+}
+
+void CmiReleaseCommHandle(phandle)
+     CmiCommHandle *phandle;
+{
+}
+
+void CmiGrabBuffer(pbuf)
+     char **pbuf;
+{
+}
+
+
+/******************************************************************************
+ *
+ * CmiInitMc and CmiExit
+ *
+ *****************************************************************************/
+
+CmiInitMc(argv)
+char **argv;
+{
+  static int initmc=0;
+  void *FIFO_Create();
+  Cmi_insidemachine = TRUE;
+  Communication_init = FALSE;
+  
+  if (initmc==1) KillEveryone("CmiInit called twice");
+  initmc=1;
+  
+  ExtractArgs(argv);
+  ParseNetstart();
+  InitializePorts();
+  CmiLocalQueue = FIFO_Create();
+  KillInit();
+  ctrl_sendone(120,"notify-die %s %d\n",self_IP_str,ctrl_port);
+  outlog_init(outputfile, Cmi_mype);
+  node_addresses_receive();
+  CmiTimerInit();
+  SendWindowInit();
+  RecvWindowInit();
+  InterruptInit();
+  Communication_init = TRUE;
+
+  Cmi_insidemachine = FALSE ;
+}
+
+CmiExit()
+{
+  static int exited;
+  int begin, saveflag;
+  
+  if (exited==1) KillEveryone("CmiExit called twice");
+  exited=1;
+  
+  saveflag = Cmi_insidemachine;
+  Cmi_insidemachine = TRUE;
+
+  ctrl_sendone(120,"aget %s %d done 0 %d\n",
+              self_IP_str,ctrl_port,Cmi_numpe-1);
+  ctrl_sendone(120,"aset done %d TRUE\n",Cmi_mype);
+  ctrl_sendone(120,"ending\n");
+  begin = time(0);
+  while(!all_done && (time(0)<begin+120))
+    { RetransmitPackets(); dgram_scan(); sleep(1); }
+  outlog_done();
+
+  Cmi_insidemachine = saveflag;
+}
diff --git a/src/arch/tcp/spantree.c b/src/arch/tcp/spantree.c
new file mode 100644 (file)
index 0000000..cece594
--- /dev/null
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * RCS INFORMATION:
+ *
+ *     $RCSfile$
+ *     $Author$        $Locker$                $State$
+ *     $Revision$      $Date$
+ *
+ ***************************************************************************
+ * DESCRIPTION:
+ *
+ ***************************************************************************
+ * REVISION HISTORY:
+ *
+ * $Log$
+ * Revision 2.0  1995-06-05 19:05:23  brunner
+ * Reorganized directory structure
+ *
+ * Revision 1.2  1995/04/13  05:51:12  narain
+ * Mc -> Cmi
+ *
+ * Revision 1.1  1994/11/03  17:37:04  brunner
+ * Initial revision
+ *
+ ***************************************************************************/
+static char ident[] = "@(#)$Header$";
+#include "converse.h"
+
+/**************************
+**
+** Spanning Tree Functions
+**
+**************************/
+
+/*
+** These are identical to the ipsc2 spanning tree functions.
+*/
+
+#define MAXSPAN    4          /* The maximum permitted span on 
+                                each node of the spanning tree */
+
+CmiSpanTreeInit() {}
+
+
+int
+CmiSpanTreeParent(node) int node; {
+    if (node == 0)
+         return -1;
+    else 
+       return ((node - 1) / MAXSPAN);   /* integer division */
+}
+
+
+int
+CmiSpanTreeRoot() { return 0; }
+
+
+CmiSpanTreeChildren(node, children) int node, *children; {
+    int i;
+
+    for (i = 1; i <= MAXSPAN ; i++)
+       if (MAXSPAN * node + i < CmiNumPe())
+            children[i-1] = node * MAXSPAN + i;
+       else children[i-1] = -1;
+}
+
+
+int
+CmiNumSpanTreeChildren(node) int node; {
+    if ((node + 1) * MAXSPAN < CmiNumPe()) return MAXSPAN;
+    else if (node * MAXSPAN + 1 >= CmiNumPe()) return 0;
+    else return ((CmiNumPe() - 1) - node * MAXSPAN);
+}
+
+
+CmiSendToSpanTreeLeaves(size, msg) int size; char * msg; {
+    int node;
+
+    for (node = (CmiNumPe() - 2) / MAXSPAN;   /* integer division */
+        node < CmiNumPe(); node++)
+       CmiSyncSend(node,size,msg);
+}
+
+
+
+PrintSpanTree() {
+    int i,j;
+    int children[MAXSPAN];
+    for (i = 0; i < CmiNumPe(); i++) {
+       CmiPrintf("node: %d, parent: %d, numchildren: %d, children: ",
+                i, CmiSpanTreeParent(i), CmiNumSpanTreeChildren(i));
+       CmiSpanTreeChildren(i, children);
+       for (j = 0; j < CmiNumSpanTreeChildren(i); j++)
+            CmiPrintf("%d ", children[j]);
+       CmiPrintf("\n");
+    }
+}
diff --git a/src/xlat++/xp-extn.h b/src/xlat++/xp-extn.h
new file mode 100644 (file)
index 0000000..e8a5dd8
--- /dev/null
@@ -0,0 +1,130 @@
+/***************************************************************************
+ * RCS INFORMATION:
+ *
+ *     $RCSfile$
+ *     $Author$        $Locker$                $State$
+ *     $Revision$      $Date$
+ *
+ ***************************************************************************
+ * DESCRIPTION:
+ *
+ ***************************************************************************
+ * REVISION HISTORY:
+ *
+ * $Log$
+ * Revision 2.0  1995-06-05 19:01:24  brunner
+ * Reorganized directory structure
+ *
+ * Revision 1.3  1995/03/23  05:11:53  sanjeev
+ * changes for printing call graph
+ *
+ * Revision 1.2  1994/11/11  05:32:43  brunner
+ * Removed ident added by accident with RCS header
+ *
+ * Revision 1.1  1994/11/07  15:41:10  brunner
+ * Initial revision
+ *
+ ***************************************************************************/
+
+extern StackStruct *StackTop ;
+extern StackStruct *GlobalStack ;
+
+extern AggState *PermanentAggTable[] ;
+extern int PermanentAggTableSize ;
+
+extern ChareInfo * ChareTable[] ;
+extern ChareInfo * BOCTable[] ;
+extern MsgStruct MessageTable[] ;
+extern AccStruct * AccTable[] ;
+extern AccStruct * MonoTable[] ;
+extern char * DTableTable[] ;
+extern char * ReadTable[] ;
+extern char * ReadMsgTable[] ;
+extern FunctionStruct FunctionTable[] ;
+extern SymEntry SymTable[] ;
+
+extern int charecount ;
+extern int boccount ;
+extern int TotalEntries ;
+extern int TotalMsgs ;
+extern int TotalAccs ;
+extern int TotalMonos ;
+extern int TotalDTables ;
+extern int TotalReads ;
+extern int TotalReadMsgs ;
+extern int TotalFns ;
+extern int TotalSyms ;
+
+extern HandleEntry ChareHandleTable[] ;
+extern HandleEntry BOCHandleTable[] ;
+extern HandleEntry AccHandleTable[] ;
+extern HandleEntry MonoHandleTable[] ;
+extern HandleEntry WrOnHandleTable[] ;
+
+extern int ChareHandleTableSize ;
+extern int BOCHandleTableSize ;
+extern int AccHandleTableSize ;
+extern int MonoHandleTableSize ;
+extern int WrOnHandleTableSize ;
+
+extern int CurrentLine ;
+extern int CurrentScope ;  /* 1 means file scope, >1 means inside a block*/
+extern char CurrentFileName[] ;
+extern int CurrentAccess, CurrentAggType, CurrentStorage;
+extern int CurrentCharmType ;
+extern int CurrentCharmNameIndex ;
+extern char CurrentTypedef[] ;
+extern char CurrentDeclType[] ;
+extern char CurrentAggName[] ;
+extern char CurrentChare[] ;
+extern char CurrentEP[] ;
+extern char CurrentFn[] ;
+extern char CurrentMsgParm[] ;
+extern char CurrentSharedHandle[] ;
+extern AccStruct *CurrentAcc ;
+extern ChareInfo *CurrentCharePtr ;
+extern char *EpMsg;
+extern char SendEP[] ;
+extern char SendChare[] ;
+extern char SendPe[] ;
+extern char *ParentArray[] ;
+extern int SendType ;
+extern int main_argc_argv ;
+extern int foundargs ;
+extern int numparents ;
+extern int SendMsgBranchPoss ;
+extern int FoundHandle ;
+extern int FilledAccMsg ;
+extern int FoundConstructorBody ;
+extern int IsMonoCall ;
+extern int FoundParms ;
+extern int FoundLocalBranch ;
+extern int FoundTable ;
+extern int FoundVarSize ;
+extern int FoundReadOnly ;
+extern int StructScope ;
+
+extern FILE *yyin ;
+extern FILE *outfile ;
+extern FILE *headerfile ;
+extern FILE *graphfile ;
+
+extern int MakeGraph ;
+
+extern char prevtoken[] ;
+/* extern char modname[] ;  */
+extern char OutBuf[] ;
+extern char CoreName[] ;
+
+extern char * EpMsg ;
+
+extern int main_argc_argv ;
+extern int shouldprint ;
+extern int foundargs ;
+
+extern int ErrVal ;
+extern int AddedScope ;
+extern int FoundGlobalScope ;
+
+extern int InsideChareCode ;
+
diff --git a/src/xlat++/xp-process.c b/src/xlat++/xp-process.c
new file mode 100644 (file)
index 0000000..a5424e5
--- /dev/null
@@ -0,0 +1,653 @@
+/***************************************************************************
+ * RCS INFORMATION:
+ *
+ *     $RCSfile$
+ *     $Author$        $Locker$                $State$
+ *     $Revision$      $Date$
+ *
+ ***************************************************************************
+ * DESCRIPTION:
+ *
+ ***************************************************************************
+ * REVISION HISTORY:
+ *
+ * $Log$
+ * Revision 2.0  1995-06-05 19:01:24  brunner
+ * Reorganized directory structure
+ *
+ * Revision 1.7  1995/05/05  22:55:38  sanjeev
+ * Fixed ReadOnlyMsg bug
+ *
+ * Revision 1.6  1995/05/03  20:58:33  sanjeev
+ * initialize module struct etc for detecting uninitialized modules
+ *
+ * Revision 1.5  1995/04/23  17:50:07  sanjeev
+ * stuff to output PPG
+ *
+ * Revision 1.4  1995/03/23  05:11:33  sanjeev
+ * changes for printing call graph
+ *
+ * Revision 1.3  1995/02/14  00:08:35  sanjeev
+ * removed module.list stuff, no longer reqd in new runtime
+ *
+ * Revision 1.2  1994/12/10  19:00:20  sanjeev
+ * interoperability stuff
+ *
+ * Revision 1.1  1994/11/03  17:42:10  brunner
+ * Initial revision
+ *
+ ***************************************************************************/
+static char ident[] = "@(#)$Header$";
+
+
+/*------- VIEW THIS FILE IN A 130 COLUMN WINDOW ---------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "xp-t.h"
+#include "xp-extn.h"
+
+int foundMain = 0 ;
+
+static int TotalEps=0 ;
+
+void GenerateStructsFns() ;
+void GenerateRegisterCalls() ;
+
+
+main(argc,argv)
+int argc ;
+char *argv[] ;
+{
+       int retval ;
+
+       InitFiles(argc,argv) ;
+
+       InsertSymTable("writeonce") ;
+       InsertSymTable("EntryPointType") ;
+       InsertSymTable("FunctionRefType") ;
+       InsertSymTable("ChareIDType") ; /* for the table class */
+       retval = yyparse() ;
+
+       if ( shouldprint )
+               strcat(OutBuf,prevtoken) ;
+       fprintf(outfile,"%s",OutBuf) ;
+
+       if ( ErrVal || retval>0 ) {
+               fprintf(stderr,"\nThere are errors in the input.\n");
+               CloseFiles() ;
+               exit(1) ;
+       }
+
+       /* Generate _CK_chare_ChareType,  _CK_ep_ChareType_EP, 
+          _CK_acc_AccType, _CK_mono_MonoType, _CK_func_FnName  variables.
+          Also generate the _CK_ModuleName struct which holds all the 
+          _CK_msg_MessageType variables.
+          Also generate _CK_create_ChareType() and _CK_call_ChareType_EP()
+          functions */
+
+       GenerateStructsFns() ;
+
+
+       /* Generate calls to all the "register" routines */
+
+       GenerateRegisterCalls() ;
+
+       if ( MakeGraph )
+               OutputNames() ;
+
+       CloseFiles() ;
+
+       return(0) ;
+}
+
+
+
+InitFiles(argc,argv)
+int argc ;
+char *argv[] ;
+{
+       char pgm[MAX_NAME_LENGTH], headername[MAX_NAME_LENGTH] ;
+        char *bgn, *end;
+       FILE *modfp ;
+       char buf[256], thismod[256] ;
+
+       char *envstring ;
+       char graphname[MAX_NAME_LENGTH] ;
+
+
+       if (argc!=3) { 
+               fprintf(stderr,"Usage: translate <InFile> <OutFile>. Stop.\n");
+               exit(1); 
+       }
+
+       strcpy(pgm,argv[1]);
+
+        bgn = strrchr(argv[1], '/');
+        if (bgn==0) bgn=argv[1];
+        end = bgn;
+        while (1)
+            {
+            char c = *end;
+            if (!(((c>='a')&&(c<='z'))||
+                  ((c>='A')&&(c<='Z'))||
+                  ((c>='0')&&(c<='9'))||
+                  (c=='_'))) break;
+            end++;
+            }
+       strncpy(CoreName, bgn, end-bgn);
+       CoreName[(end-bgn)] = '\0' ;
+
+       sprintf(headername,"%s.headers",CoreName) ;
+
+       yyin = fopen(argv[1],"r") ;
+       outfile = fopen(argv[2],"w") ;
+       headerfile = fopen(headername,"w") ;
+
+       if ( yyin==NULL || outfile==NULL || headerfile==NULL ) {
+               fprintf(stderr,"ERROR : Cannot open input or output file(s). Stop.\n") ;
+               exit(1) ;
+       }
+       
+       fprintf(outfile,"#define CPLUS_FILE\n") ;
+       fprintf(outfile,"#include \"ckdefs.h\" \n") ;
+/*     fprintf(outfile,"#include \"env_macros.h\" \n") ;  Amitabh put this */
+       fprintf(outfile,"#include \"chare.h\" \n") ;
+       fprintf(outfile,"#include \"c++interface.h\" \n") ;
+       fprintf(outfile,"#include \"%s\"\n",headername) ;
+/*     fprintf(outfile,"#include \"stdio.h\"\n") ; */
+/*     fprintf(outfile,"#line 1 \"%s.P\"\n",CoreName) ;   */
+
+/*     fprintf(outfile,"extern \"C\" char * sprintf(char *, const char* ...);") ;      */
+
+       strcpy(prevtoken,"") ;
+       strcpy(OutBuf,"") ;
+
+
+
+       /* Create pgm.graph if required */
+       
+       envstring = getenv("GRAPH") ;   
+       if ( envstring == NULL || *envstring == '0' )
+               return ;
+
+       MakeGraph = 1 ;
+
+       sprintf(graphname,"%s.graph",CoreName) ;
+       graphfile = fopen(graphname,"w") ;
+       if ( graphfile == NULL ) {
+               fprintf(stderr,"ERROR : Cannot open graph file. Stop.\n") ;
+               exit(1) ;
+       }
+}
+
+
+CloseFiles()
+{
+
+       fclose(yyin) ;
+       fclose(outfile) ;
+       fclose(headerfile) ;
+       if ( MakeGraph )
+               fclose(graphfile) ;
+}
+
+
+
+
+#define EXT(x) ( x ? " " : "extern " )
+#define INIT(x) ( x ? "=0" : " " )
+
+
+void GenerateStructsFns()
+{
+        int i, j, nv ;
+       FILE *epfile ;
+       ChareInfo *chare ;
+       EP *ep ;
+       int thisismain ;
+       char extstr[16] ;
+       char InitStr[128] ;
+
+       TotalEps = 0 ;
+
+       epfile = headerfile ;
+       fprintf(epfile,"\n\n\n/******************************************************************/\n\n") ;
+       fprintf(outfile,"\n\n\n/******************************************************************/\n\n") ;
+
+/* Output all chare and boc names */
+       for ( i=0; i<=charecount; i++ ) {
+               if ( ChareTable[i]->eps != NULL )
+                       fprintf(epfile,"%sint _CK_chare_%s %s ;\n",EXT(ChareTable[i]->eps->defined),ChareTable[i]->name,INIT(ChareTable[i]->eps->defined)) ;
+       }
+
+       for ( i=0; i<=boccount; i++ ) {
+               if ( BOCTable[i]->eps != NULL )
+                       fprintf(epfile,"%sint _CK_chare_%s %s ;\n",EXT(BOCTable[i]->eps->defined),BOCTable[i]->name,INIT(BOCTable[i]->eps->defined)) ;
+       }
+
+
+/* Output Chare variables and functions */
+       thisismain = 0 ;
+       for ( i=0; i<=charecount; i++ ) {
+               chare = ChareTable[i] ;
+               if ( chare->eps == NULL )
+                       continue ;
+               if ( strcmp(chare->name,"main") == 0 )
+                       thisismain = 1 ;
+               if ( chare->eps->defined ) {
+                   for  ( ep=chare->eps; ep!=NULL; ep=ep->next,TotalEps++ ) {
+                       fprintf(epfile,"\tint _CK_ep_%s_%s =0 ;\n",chare->name,ep->epname) ;
+                       if (thisismain && strcmp(ep->epname,"main")==0) {
+                               foundMain = 1 ;
+                               fprintf(outfile,"\nvoid _CK_call_main_main(_CK_Object *obj, int argc, char *argv[])\n{\n");
+                               if ( main_argc_argv )
+                                               fprintf(outfile,"\t((main *)obj)->_CKmain(argc,argv) ;\n") ;
+                               else {
+                                               fprintf(outfile,"\targc = 0 ;\n") ;
+                                               fprintf(outfile,"\targv = NULL ;\n") ;
+                                               fprintf(outfile,"\t((main *)obj)->_CKmain() ;\n") ;
+                               }
+                               fprintf(outfile,"}\n") ;
+                       }
+                       else {
+                               fprintf(outfile,"void _CK_call_%s_%s(void *m, _CK_Object *obj)\n{\n",chare->name,ep->epname) ;
+                               fprintf(outfile,"\t((%s *)obj)->%s((%s *)m) ;\n}\n",chare->name,ep->epname,ep->msgname) ;
+                       }
+                   }
+               }
+               else {
+                       for  ( ep=chare->eps; ep!=NULL; ep=ep->next,TotalEps++)
+                               fprintf(epfile,"\textern int _CK_ep_%s_%s ;\n",chare->name,ep->epname) ;
+               }
+
+               if ( chare->eps->defined ) {
+                   fprintf(outfile,"_CK_Object *_CK_create_%s(MAGIC_NUMBER_TYPE m) {\n",chare->name) ;
+                   fprintf(outfile,"\treturn(new %s(m)) ;\n}\n\n",chare->name);
+               }
+       }
+
+
+/* output BOC variables and fns */
+       for ( i=0; i<=boccount; i++ ) {
+               chare = BOCTable[i] ;
+               if ( chare->eps == NULL )
+                       continue ;
+               if ( chare->eps->defined ) {
+                       for  ( ep=chare->eps; ep!=NULL; ep=ep->next,TotalEps++)
+                       {
+                               fprintf(epfile,"\tint _CK_ep_%s_%s =0 ;\n",chare->name,ep->epname) ;
+                               fprintf(outfile,"void _CK_call_%s_%s(void *m, _CK_Object *obj)\n{\n", chare->name,ep->epname) ;
+                               fprintf(outfile,"\t((%s *)obj)->%s((%s *)m) ;\n}\n", chare->name,ep->epname,ep->msgname) ;
+                       }
+               }
+               else {
+                       for  ( ep=chare->eps; ep!=NULL; ep=ep->next,TotalEps++)
+                               fprintf(epfile,"\textern int _CK_ep_%s_%s ;\n",chare->name,ep->epname) ;
+               }
+
+               if ( chare->eps->defined ) {
+                   fprintf(outfile,"_CK_BOC *_CK_create_%s() {\n",chare->name) ;
+                   fprintf(outfile,"\treturn(new %s()) ;\n}\n\n",chare->name) ;
+               }
+       }
+
+/* Output all acc and mono names */
+       for ( i=0; i<TotalAccs; i++ ) {
+               fprintf(epfile,"%sint _CK_acc_%s %s ;\n",EXT(AccTable[i]->defined),AccTable[i]->name,INIT(AccTable[i]->defined)) ;
+               if ( AccTable[i]->defined ) {
+                   fprintf(outfile,"void *_CK_create_%s(void *msg) {\n",AccTable[i]->name) ;
+                   fprintf(outfile,"\treturn(new %s((%s *)msg)) ;\n}\n\n",AccTable[i]->name,AccTable[i]->initmsgtype) ;
+               }
+       }
+       for ( i=0; i<TotalMonos; i++ ) {
+               fprintf(epfile,"%sint _CK_mono_%s %s ;\n",EXT(MonoTable[i]->defined),MonoTable[i]->name,INIT(MonoTable[i]->defined)) ;
+               if ( MonoTable[i]->defined ) {
+                   fprintf(outfile,"void *_CK_create_%s(void *msg) {\n",MonoTable[i]->name) ;
+                   fprintf(outfile,"\treturn(new %s((%s *)msg)) ;\n}\n\n",MonoTable[i]->name,MonoTable[i]->initmsgtype) ;
+               }
+       }
+
+
+        for ( i=0; i<TotalReadMsgs; i++ )
+                fprintf(epfile,"int _CK_index_%s ;\n",ReadMsgTable[i]) ;
+
+/* Output all global Function Names */
+       for ( i=0; i<TotalFns; i++ ) {
+           if ( !(FunctionTable[i].defined) ) 
+               fprintf(epfile,"extern int _CK_func_%s ;\n",FunctionTable[i].name) ;
+           else
+               fprintf(epfile,"int _CK_func_%s =0;\n",FunctionTable[i].name) ;
+       }
+
+       fprintf(epfile,"\n\n") ;
+
+
+
+
+/* generate the _CK_ModuleName struct which holds all the _CK_msg_MessageType 
+   variables.  */
+
+       fprintf(headerfile,"\n\n\n/******************************************************************/\n\n") ;
+
+       strcpy(InitStr,"0") ;
+       for ( i=1; i<TotalMsgs; i++ ) 
+               strcat(InitStr,",0") ;
+
+       fprintf(headerfile,"struct {\n",CoreName) ;
+       for ( i=0; i<TotalMsgs; i++ ) {
+               fprintf(headerfile,"\tint _CK_msg_%s ;\n",MessageTable[i].name) ;
+       }
+       fprintf(headerfile,"} _CK_%s ={%s} ;\n\n",CoreName,InitStr) ;
+
+
+/* for all MsgTypes output the pack - unpack call functions and the alloc fns  */
+       for ( i=0; i<TotalMsgs; i++ ) {
+               char *nam = MessageTable[i].name ;
+               if ( MessageTable[i].pack ) {
+                       fprintf(outfile,"static void _CK_pack_%s(void *in, void **out,int *length)\n{\n",nam) ; 
+                       fprintf(outfile,"\t(*out) = ((%s *)in)->pack(length) ;\n}\n",nam) ;
+                       if ( MessageTable[i].numvarsize > 0 ) {
+                               fprintf(outfile,"static void _CK_unpack_%s(void *in, void **out)\n{\n",nam) ; 
+                               fprintf(outfile,"\t(*out) = in ;\n") ;
+                               fprintf(outfile,"\t((%s *)in)->unpack() ;\n}\n",nam) ;
+                       }
+                       else {
+                               fprintf(outfile,"static void _CK_unpack_%s(void *in, void **out)\n{\n",nam) ; 
+                               fprintf(outfile,"\t%s * m = (%s *)GenericCkAlloc(_CK_%s._CK_msg_%s,sizeof(%s),0) ;\n", nam, nam, 
+                                                                                                       CoreName, nam, nam) ;
+                               fprintf(outfile,"\t(*out) = (void *) m ;\n") ;
+                               fprintf(outfile,"\tm->unpack(in) ;\n}\n") ;
+                       }
+               }
+               /* Output the alloc function if this is a varsize msg */
+               if ( (nv=MessageTable[i].numvarsize) > 0 ) {
+                   VarSizeStruct *vs = MessageTable[i].varsizearray ;
+                   fprintf(outfile,"static void *_CK_alloc_%s(int msgno, int size, int *array, int prio)\n{\n",nam) ; 
+                   fprintf(outfile,"\tint totsize=0, temp, dummy, sarray[%d] ;\n",nv) ;
+                   fprintf(outfile,"\t%s * ptr ;\n",nam) ;
+                   fprintf(outfile,"\ttotsize = temp = (size%%_CK_VARSIZE_UNIT)?_CK_VARSIZE_UNIT*((size+_CK_VARSIZE_UNIT)/_CK_VARSIZE_UNIT):size;\n\n") ;
+                   for ( j=0; j<nv; j++ ) {
+                       fprintf(outfile,"\tsize = sizeof(%s)*array[%d];\n",vs[j].type,j) ;
+                       fprintf(outfile,"\tdummy = (size%%_CK_VARSIZE_UNIT)?_CK_VARSIZE_UNIT*((size+_CK_VARSIZE_UNIT)/_CK_VARSIZE_UNIT):size;\n") ;
+                       fprintf(outfile,"\tsarray[%d]=dummy;\n",j) ;
+                       fprintf(outfile,"\ttotsize += dummy;\n") ;
+                   }
+
+                   fprintf(outfile,"\n\tptr = (%s *)GenericCkAlloc(msgno,totsize,prio);\n",nam) ;
+                   fprintf(outfile,"\tdummy=temp;\n\n") ;
+                   for ( j=0; j<nv; j++ ) {
+                       fprintf(outfile,"\tptr->%s = (%s *)((char *)ptr + dummy);\n", vs[j].name, vs[j].type) ;
+                       fprintf(outfile,"\tdummy += sarray[%d];\n",j) ;
+                   }
+                   fprintf(outfile,"\nreturn((void *)ptr);\n}\n\n") ;
+               }
+       }
+
+
+/* Output _CK_mod_CopyFromBuffer, _CK_mod_CopyToBuffer for readonly vars */
+       fprintf(outfile,"extern \"C\" void _CK_13CopyFromBuffer(void *,int) ;\n") ;
+       fprintf(outfile,"void _CK_%s_CopyFromBuffer(void **_CK_ReadMsgTable)\n",CoreName) ;
+       fprintf(outfile,"{\n") ;
+       for ( i=0; i<TotalReads; i++ ) 
+               fprintf(outfile,"\t_CK_13CopyFromBuffer(&%s,sizeof(%s)) ;\n",ReadTable[i],ReadTable[i]) ;
+       for ( i=0; i<TotalReadMsgs; i++ ) {
+               fprintf(outfile,"    {   void **temp = (void **)(&%s);\n",ReadMsgTable[i]) ;
+               fprintf(outfile,"        *temp = _CK_ReadMsgTable[_CK_index_%s];\n",ReadMsgTable[i]) ;
+               fprintf(outfile,"    }\n") ;
+       }
+       fprintf(outfile,"}\n\n") ;
+
+       fprintf(outfile,"extern \"C\" void _CK_13CopyToBuffer(void *,int) ;\n") ;
+       fprintf(outfile,"extern \"C\" void ReadMsgInit(void *,int) ;\n") ;
+
+       fprintf(outfile,"void _CK_%s_CopyToBuffer()\n",CoreName) ;
+       fprintf(outfile,"{\n") ;
+       for ( i=0; i<TotalReads; i++ ) 
+               fprintf(outfile,"\t_CK_13CopyToBuffer(&%s,sizeof(%s)) ;\n",ReadTable[i],ReadTable[i]) ;
+       for ( i=0; i<TotalReadMsgs; i++ ) 
+               fprintf(outfile,"\tReadMsgInit(%s,_CK_index_%s) ;\n",ReadMsgTable[i],ReadMsgTable[i]) ;
+       fprintf(outfile,"}\n\n") ;
+
+}
+
+
+
+void GenerateRegisterCalls()
+{
+       char *nam ;
+       int i, j, count ;
+       ChareInfo **Table, *chare ;
+       EP *ep ;
+
+/* generate the beginning of this Module's Init function */
+       fprintf(outfile,"extern \"C\" void _CK_%s_init() ;\n",CoreName) ;
+       fprintf(outfile,"void _CK_%s_init()\n{\n",CoreName) ;
+
+/* first register all messages */
+       for ( i=0; i<TotalMsgs; i++ ) {
+               nam = MessageTable[i].name ;
+               fprintf(outfile,"_CK_%s._CK_msg_%s = registerMsg(\"%s\", ", CoreName, nam, nam) ;
+
+               if ( MessageTable[i].numvarsize == 0 )
+                       fprintf(outfile,"(FUNCTION_PTR)&GenericCkAlloc, ") ; 
+               else
+                       fprintf(outfile,"(FUNCTION_PTR)&_CK_alloc_%s, ",nam) ;
+
+               if ( MessageTable[i].pack == FALSE ) 
+                       fprintf(outfile,"NULL, NULL, ") ; 
+               else 
+                       fprintf(outfile,"(FUNCTION_PTR)&_CK_pack_%s, (FUNCTION_PTR)&_CK_unpack_%s, ", nam, nam) ;
+
+               fprintf(outfile,"sizeof(%s)) ;\n\n",nam) ;
+       }
+       fprintf(outfile,"\n\n") ;
+
+
+/* now register all chares and BOCs and their EPs */
+       for ( j=0; j<=1; j++ ) {
+           if ( j == 0 ) {
+               count = charecount ;
+               Table = ChareTable ;
+           }
+           else if ( j == 1 ) {
+               count = boccount ;
+               Table = BOCTable ;
+           }
+           for ( i=0; i<=count; i++ ) {
+               chare = Table[i] ;
+               if ( chare->eps == NULL )
+                       continue ;
+               if ( !chare->eps->defined ) 
+                       continue ;
+               fprintf(outfile,"_CK_chare_%s = registerChare(\"%s\", 0, (FUNCTION_PTR)&_CK_create_%s) ;\n\n",chare->name,chare->name,chare->name) ;
+
+                for  ( ep=chare->eps; ep!=NULL; ep=ep->next ) {
+                       if ( j == 0 ) 
+                               fprintf(outfile,"_CK_ep_%s_%s = registerEp(\"%s\", (FUNCTION_PTR)&_CK_call_%s_%s, CHARMPLUSPLUS,", chare->name,
+                                                                               ep->epname, ep->epname, chare->name,ep->epname) ;
+                       else
+                               fprintf(outfile,"_CK_ep_%s_%s = registerBocEp(\"%s\", (FUNCTION_PTR)&_CK_call_%s_%s, CHARMPLUSPLUS,",chare->name,
+                                                                               ep->epname, ep->epname, chare->name,ep->epname) ;
+
+                       if ( j==0 && strcmp(chare->name,"main")==0 && 
+                            strcmp(ep->epname,"main")==0 ) 
+                               fprintf(outfile,"0, _CK_chare_%s) ;\n\n",chare->name) ;
+                       else
+                               fprintf(outfile,"_CK_%s._CK_msg_%s, _CK_chare_%s) ;\n\n",CoreName, ep->msgname, chare->name) ;
+               }                       
+           }
+       }
+       fprintf(outfile,"\n\n") ;
+
+
+/* register the main chare */
+       if ( foundMain ) 
+               fprintf(outfile,"registerMainChare(_CK_chare_main, _CK_ep_main_main, CHARMPLUSPLUS) ;\n\n\n") ;
+       fprintf(outfile,"\n\n") ;
+
+
+/* now register all global fns */
+        for ( i=0; i<TotalFns; i++ ) {
+               if ( FunctionTable[i].defined )
+                       fprintf(outfile,"_CK_func_%s = registerFunction((FUNCTION_PTR)&%s) ;\n",FunctionTable[i].name, FunctionTable[i].name) ;
+        }
+       fprintf(outfile,"\n\n") ;
+
+
+/* now register all accs, monotonics, tables */
+        for ( i=0; i<TotalAccs; i++ ) {
+                if ( AccTable[i]->defined )
+                       fprintf(outfile,"_CK_acc_%s = registerAccumulator(\"%s\", (FUNCTION_PTR)&_CK_create_%s, NULL, NULL, CHARMPLUSPLUS) ;\n",
+                                                                       AccTable[i]->name,AccTable[i]->name,AccTable[i]->name) ;
+        }
+        for ( i=0; i<TotalMonos; i++ ) {
+                if ( MonoTable[i]->defined )
+                       fprintf(outfile,"_CK_mono_%s = registerMonotonic(\"%s\", (FUNCTION_PTR)&_CK_create_%s, NULL, CHARMPLUSPLUS) ;\n",
+                                                                       MonoTable[i]->name,MonoTable[i]->name,MonoTable[i]->name) ;
+        }
+        for ( i=0; i<TotalDTables; i++ ) {
+                fprintf(outfile,"%s.SetId(registerTable(\"%s\", NULL, NULL)) ;\n",DTableTable[i],DTableTable[i]) ;
+        }
+       fprintf(outfile,"\n\n") ;
+
+
+/* now register readonlies and readonli messages */
+        fprintf(outfile,"int readonlysize=0 ;\n") ;
+        for ( i=0; i<TotalReads; i++ )
+                fprintf(outfile,"readonlysize += sizeof(%s) ;\n",ReadTable[i]) ;
+
+        fprintf(outfile,"\nregisterReadOnly(readonlysize, (FUNCTION_PTR)&_CK_%s_CopyFromBuffer, (FUNCTION_PTR)&_CK_%s_CopyToBuffer) ;\n",CoreName,CoreName) ;
+
+       /* this is only needed to give a unique index to all all readonly msgs */
+        for ( i=0; i<TotalReadMsgs; i++ )
+                fprintf(outfile,"_CK_index_%s = registerReadOnlyMsg() ;\n",ReadMsgTable[i]) ;
+
+
+/* This is the closing brace of the Module-init function */
+        fprintf(outfile,"\n}\n") ;
+}
+
+
+
+
+OutputNames()
+{
+/* Output all chare and EP names into the pgm.graph file */
+/* Try to make format same as Projections' pgm.sts file */
+
+       int numchares=-1, numeps=-1 ;
+       int i, j, count ;
+       ChareInfo **Table, *chare ;
+       EP *ep ;
+       FN *fn ;
+       int toteps = 0 ;
+
+/* first output counts of chares, eps, msgs */
+       fprintf(graphfile,"TOTAL_CHARES %d\n",charecount+1+boccount+1) ;
+       fprintf(graphfile,"TOTAL_EPS %d\n",TotalEps) ;
+       fprintf(graphfile,"TOTAL_MSGS %d\n",TotalMsgs) ;
+
+/* first output all messages */
+       for ( i=0; i<TotalMsgs; i++ ) { 
+         /* 0 below is because I dont know the message size at compile time */
+               fprintf(graphfile,"MESSAGE %d 0 %s\n",i,MessageTable[i].name);
+       }
+
+/* now register all chares and BOCs and their EPs */
+       for ( j=0; j<=1; j++ ) {
+           if ( j == 0 ) {
+               count = charecount ;
+               Table = ChareTable ;
+           }
+           else if ( j == 1 ) {
+               count = boccount ;
+               Table = BOCTable ;
+           }
+           for ( i=0; i<=count; i++ ) {
+               chare = Table[i] ;
+
+               /* count number of EPs */
+                for  ( toteps=0,ep=chare->eps; ep!=NULL; ep=ep->next ) 
+                       toteps++ ;
+                for  ( fn=chare->fns; fn!=NULL; fn=fn->next ) 
+                       toteps++ ;
+
+               fprintf(graphfile,"CHARE %d %s %d\n",++numchares,chare->name,
+                                                       toteps) ;
+
+               if ( chare->eps == NULL )
+                       continue ;
+                for  ( ep=chare->eps; ep!=NULL; ep=ep->next ) {
+                   if ( j == 0 ) {
+                       fprintf(graphfile,"ENTRY CHARE %d %s %d %d\n",++numeps,
+                                               ep->epname, numchares, 
+                                               FoundInMsgTable(ep->msgname)) ;
+                   }
+                   else {
+                       fprintf(graphfile,"ENTRY BOC %d %s %d %d\n",++numeps,
+                                               ep->epname, numchares, 
+                                               FoundInMsgTable(ep->msgname)) ;
+                   }
+               }       
+                for  ( fn=chare->fns; fn!=NULL; fn=fn->next ) {
+                   if ( j == 0 ) {
+                       fprintf(graphfile,"FUNCTION CHARE %d %s %d\n",++numeps,
+                                               fn->fnname, numchares ) ;
+                   }
+                   else {
+                       fprintf(graphfile,"FUNCTION BOC %d %s %d\n",++numeps,
+                                               fn->fnname, numchares ) ;
+                   }
+               }       
+           }
+       }
+       fprintf(graphfile,"END\n") ;
+}
+
+
+Graph_OutputCreate(chareboc, LastArg, LastChare, LastEP)
+char *chareboc;
+char *LastArg;
+char *LastChare;
+char *LastEP;
+{
+       if ( strcmp(chareboc,"_CK_CreateBoc") == 0 ) {
+               fprintf(graphfile,"CREATEBOC %s %s : %s %s\n", CurrentChare,
+                                       CurrentEP, LastChare, LastEP) ;
+       }
+       else if ( strcmp(chareboc,"_CK_CreateChare") == 0 ) {
+                fprintf(graphfile,"CREATECHARE %s %s : %s %s %s\n",
+                        CurrentChare, CurrentEP, LastChare, LastEP, LastArg) ;
+       }
+}
+
+Graph_OutputPrivateCall(fnname)
+char *fnname ;
+{
+       /* First find if this is indeed a public/privatecall */
+       FN *f ;
+
+       for ( f=CurrentCharePtr->fns; f!=NULL; f=f->next )
+               if ( strcmp(fnname,f->fnname) == 0 ) {
+                       if (FoundInChareTable(ChareTable,charecount+1,
+                                                        CurrentChare)!=-1) 
+                               fprintf(graphfile,"CALLCHARE %s %s : %s %s\n", 
+                               CurrentChare, CurrentEP, CurrentChare, fnname);
+                       else if (FoundInChareTable(BOCTable,boccount+1,
+                                                        CurrentChare)!=-1) 
+                               fprintf(graphfile,"CALLBOC %s %s : %s %s\n", 
+                               CurrentChare, CurrentEP, CurrentChare, fnname);
+                       return ;
+               }
+}
+
+
+
+
+
+
diff --git a/src/xlat++/xp-table.c b/src/xlat++/xp-table.c
new file mode 100644 (file)
index 0000000..8087392
--- /dev/null
@@ -0,0 +1,1242 @@
+/***************************************************************************
+ * RCS INFORMATION:
+ *
+ *     $RCSfile$
+ *     $Author$        $Locker$                $State$
+ *     $Revision$      $Date$
+ *
+ ***************************************************************************
+ * DESCRIPTION:
+ *
+ ***************************************************************************
+ * REVISION HISTORY:
+ *
+ * $Log$
+ * Revision 2.0  1995-06-05 19:01:24  brunner
+ * Reorganized directory structure
+ *
+ * Revision 1.5  1995/05/02  22:06:51  sanjeev
+ * Acc bug fix for Tim
+ *
+ * Revision 1.4  1995/04/23  17:50:28  sanjeev
+ * stuff to output PPG
+ *
+ * Revision 1.3  1995/03/23  05:11:38  sanjeev
+ * changes for printing call graph
+ *
+ * Revision 1.2  1994/12/10  19:00:34  sanjeev
+ * interoperability stuff
+ *
+ * Revision 1.1  1994/11/03  17:42:13  brunner
+ * Initial revision
+ *
+ ***************************************************************************/
+static char ident[] = "@(#)$Header$";
+#include "xp-ytab.h"
+#include "xp-t.h"
+#include "xp-extn.h"
+
+
+char *CheckSendError() ;
+char *Mystrstr() ;
+char *Strstr() ;
+EP *SearchEPList() ;
+
+ProcessEP(epname,defined)
+char *epname ;
+int defined ;
+{
+/* called after the header of an EP has been parsed */ 
+
+       int val ;
+       EP *ep, *e, *eprev ;
+       ChareInfo *chare ;
+
+       strcpy(CurrentEP,epname) ;
+       TotalEntries++ ;
+
+
+       if ( strcmp(CurrentChare,"main")==0 && strcmp(epname,"main")==0 ) {
+               if ( foundargs )
+                       main_argc_argv = TRUE ;
+               else
+                       main_argc_argv = FALSE ;
+       }
+
+/* Enter EP into Chare / BOC table */
+        if ( CurrentAggType == CHARE )
+                chare = ChareTable[FoundInChareTable(ChareTable,charecount+1,CurrentChare)] ;
+        else if ( CurrentAggType == BRANCHED )
+                chare = BOCTable[FoundInChareTable(BOCTable,boccount+1,CurrentChare)] ;
+
+       /* check if the EP is already there */
+       for ( e=chare->eps; e!=NULL; e=e->next ) {
+               if ( strcmp(epname,e->epname)==0 ) {
+                       e->defined = defined ;
+                       return ;
+               }
+       }
+
+
+        ep = (EP *)malloc(sizeof(EP)) ;
+        strcpy(ep->epname,epname) ;
+       ep->chare = chare ;
+        ep->inherited = 0 ;
+        ep->defined = defined ;
+       if ( CurrentStorage == VIRTUAL )
+               ep->isvirtual = TRUE ;
+       else
+               ep->isvirtual = FALSE ;
+       if ( chare->eps == NULL ) {
+               chare->eps = ep ;
+               ep->next = NULL ;
+       }
+       else { /* insert in lexicographic order */
+               InsertAlpha(chare,ep) ;
+       }
+               
+       
+/* Find message name in this ep */
+       if ( strcmp(CurrentChare,"main")==0 && strcmp(CurrentEP,"main")==0 )
+       {/*     fprintf(stderr,"Got main::%s\n",ep->epname) ;  */
+               ;
+       }
+       else {
+               strcpy(ep->msgname,EpMsg) ;
+       }
+}
+
+
+ProcessFn(fnname)
+char *fnname ;
+{
+/* called after the header of an EP has been parsed */ 
+
+       FN *fn, *f ;
+       ChareInfo *chare ;
+
+       strcpy(CurrentEP,fnname) ;
+
+/* Enter EP into Chare / BOC table */
+        if ( CurrentAggType == CHARE )
+                chare = ChareTable[FoundInChareTable(ChareTable,charecount+1,CurrentChare)] ;
+        else if ( CurrentAggType == BRANCHED )
+                chare = BOCTable[FoundInChareTable(BOCTable,boccount+1,CurrentChare)] ;
+
+       /* check if the FN is already there */
+       for ( f=chare->fns; f!=NULL; f=f->next ) {
+               if ( strcmp(fnname,f->fnname)==0 ) 
+                       return ;
+       }
+
+        fn = (FN *)malloc(sizeof(FN)) ;
+        strcpy(fn->fnname,fnname) ;
+       fn->next = chare->fns ;
+       chare->fns = fn ;
+}
+
+
+
+
+
+
+InsertSymTable(string)
+char *string ;
+{
+       if ( isaTYPE(string) ) {
+       /* Not necessarily a redefinition : the first could have been
+          just a declaration. A real redef will be reported by C++ compiler */
+       /* Also possiblility : typedefs with same name (class X and enum X) */
+               return ;
+       }
+
+       if ( TotalSyms >= MAXSYMBOLS ) {
+               printf("INTERNAL ERROR : Symbol Table overflow : Cannot handle more than %d typenames\n",MAXSYMBOLS ) ;
+               printf("TO FIX ERROR : Increase MAXSYMBOLS variable in translator/t.h\n") ;
+       }
+
+       SymTable[TotalSyms].name = (char *)malloc((strlen(string)+1)*sizeof(char)) ;
+       strcpy(SymTable[TotalSyms].name,string) ;
+       SymTable[TotalSyms].permanentindex = -1 ;
+
+       TotalSyms++ ;
+}
+
+
+
+int FoundInChareTable(table,tablelen,name)
+ChareInfo *table[] ;
+int tablelen ;
+char *name ;
+{
+       int i ;
+
+       for ( i=tablelen-1; i>=0; i-- ) 
+               if ( strcmp(table[i]->name,name) == 0 )
+                       return(i) ;
+
+       return(-1) ;
+}      
+
+
+int FoundInAccTable(table,tablelen,name)
+AccStruct *table[] ;
+int tablelen ;
+char *name ;
+{
+       int i ;
+       char *nptr = strstr(name,"::") ;
+
+       if ( nptr == NULL )
+               nptr = name ;
+       else
+               nptr += 2 ;
+
+       for ( i=tablelen-1; i>=0; i-- ) 
+               if ( strcmp(table[i]->name,nptr) == 0 )
+                       return(i) ;
+
+       return(-1) ;
+}      
+
+int FoundInMsgTable(name)
+char *name ;
+{
+       int i ;
+
+       for ( i=TotalMsgs-1; i>=0; i-- ) 
+               if ( strcmp(MessageTable[i].name,name) == 0 )
+                       return(i) ;
+
+       return(-1) ;
+}      
+
+
+CheckCharmName()
+{
+/* Check if CurrentTypedef is CHARM type, for use by the 
+   possibly upcoming handle decl */
+       int i, ind ;
+       int ScopedType ;
+       char *lastagg ;
+       char *type ;
+       int printtype=1 ;
+
+/*     FLUSHBUF() ;cant flush here because we want to remove 
+       the CurrentTypedef */
+       
+       char *sptr = Mystrstr(OutBuf,CurrentTypedef) ;
+       if ( sptr != NULL ) {   /* This will happen for 1st var in the list */
+               *sptr = '\0' ;
+               type = CurrentTypedef ;
+       }
+       else if ( strcmp(CurrentDeclType,"") != 0 ){
+               type = CurrentDeclType ;
+               printtype = 0 ;
+       }
+       else
+               fprintf(stderr,"TRANSLATOR ERROR in handle decl: %s, line %d: \n",CurrentFileName,CurrentLine) ;
+       FLUSHBUF() ;
+
+       if ( Strstr(type,"::") != NULL ) {
+               AddScope(type) ;
+               ScopedType = TRUE ;
+               lastagg = Mystrstr(type,"::") + 2 ;
+       }       
+       else
+               lastagg = type ;
+
+
+       if ( (ind=FoundInChareTable(ChareTable,charecount+1,lastagg)) != -1 ) {
+               CurrentCharmType = CHARE ;
+               if ( printtype )
+                       fprintf(outfile,"ChareIDType") ;
+       }
+       else if ( (ind=FoundInChareTable(BOCTable,boccount+1,lastagg)) != -1 ){
+               CurrentCharmType = BRANCHED ;
+               if ( printtype )
+                       fprintf(outfile,"int") ;
+       }
+       else if ( (ind=FoundInAccTable(AccTable,TotalAccs,lastagg)) != -1 ) {
+               CurrentCharmType = ACCUMULATOR ;
+               if ( printtype )
+                       fprintf(outfile,"AccIDType") ;
+       }
+       else if ( (ind=FoundInAccTable(MonoTable,TotalMonos,lastagg)) != -1 ) {
+               CurrentCharmType = MONOTONIC ;
+               if ( printtype )
+                       fprintf(outfile,"MonoIDType") ;
+       }
+       else if ( strcmp(lastagg,"writeonce")==0 ) {
+               CurrentCharmType = WRITEONCE ;
+               if ( printtype )
+                       fprintf(outfile,"WriteOnceID") ;
+               ind = -1 ;
+       }
+       else {
+               CurrentCharmType = -1 ;
+               ind = -1 ;
+       }
+
+       if ( ind != -1 ) {
+               if ( !ScopedType )
+                       CurrentCharmNameIndex = ind ;
+               else { /* find the PermanentAggTable index of lastagg */
+                       for ( i=TotalSyms-1; i>=0; i-- )
+                               if ( strcmp(SymTable[i].name,lastagg)==0 )
+                                       break ;
+                       if ( i==-1 )
+                               fprintf(stderr,"TRANSLATOR ERROR: %s, line %d : aggregate not found in symbol table\n",CurrentFileName,CurrentLine) ;
+                       CurrentCharmNameIndex = BASE_PERM_INDEX + SymTable[i].permanentindex ;
+                       /* > BASE_PERM_INDEX means it is a permanentindex*/
+               }
+       }
+       else
+               CurrentCharmNameIndex = -1 ;
+
+       strcpy(prevtoken,"") ;
+
+
+       if ( ScopedType )
+               RemoveScope(type) ;
+
+}
+
+                       
+SyntaxError(string)
+char *string ;
+{
+       if ( strcmp(string,"") != 0 )
+               fprintf(stderr," in %s.\n",string);
+       else 
+               fprintf(stderr,".\n") ;
+       ErrVal = TRUE ;
+}
+
+CharmError(string)
+{
+       fprintf(stderr,"ERROR : %s, line %d : %s.\n",CurrentFileName,CurrentLine,string) ;
+       ErrVal = TRUE ;
+}
+
+
+InsertHandleTable(table,size,id)
+HandleEntry table[] ;
+int *size ;
+char *id ;
+{
+       table[*size].name = (char *)malloc(sizeof(char)*strlen(id)) ;
+       strcpy(table[*size].name,id) ;
+       table[*size].typestr = (char *)malloc((strlen(CurrentTypedef)+1)*sizeof(char)) ;
+       strcpy(table[*size].typestr, CurrentTypedef) ;
+       (*size)++ ;
+}
+
+
+SearchHandleTable(table,size,name)
+HandleEntry table[] ;
+int size ;
+char *name ;
+{
+       int i ;
+
+       for ( i=size-1; i>=0; i-- ) {
+               if ( strcmp(table[i].name,name) == 0 ) 
+                       return(i) ;
+       }
+       return(-1) ;
+}
+
+EP *SearchEPList(eplist,ep)
+EP *eplist ;
+char *ep ;
+{
+       EP *anep ;
+
+       for ( anep=eplist; anep!=NULL; anep=anep->next ) 
+               if ( strcmp(anep->epname,ep) == 0 )
+                       return(anep) ;
+       return(NULL) ;
+}
+
+
+char *CheckSendError(SendChare,SendEP,Msg,SendType,charename)
+char *SendChare, *SendEP, *Msg ;
+int SendType ;
+char **charename ;
+{
+       int ind, len ;
+       char errstr[256] ;
+       EP *ep, *e ;
+       ChareInfo *chare ;
+       char *ident, *lastcoln, *scopestr ;
+
+       if ( strcmp(SendChare,"thishandle")==0 ) {
+               *charename = (char *)malloc(sizeof(char)*(strlen(CurrentChare)+1));
+               strcpy(*charename,CurrentChare) ;
+               scopestr = (char *)malloc(sizeof(char)*2) ;
+               strcpy(scopestr," ") ;
+               return scopestr ;
+       }
+       else if ( strcmp(SendChare,"mainhandle")==0 ) {
+               *charename = (char *)malloc(sizeof(char)*5);
+               strcpy(*charename,"main") ;
+               scopestr = (char *)malloc(sizeof(char)*2) ;
+               strcpy(scopestr," ") ;
+               return scopestr ;
+       }
+
+       if ( (ident=Mystrstr(SendChare,"::")) != NULL ){ 
+               /* handle itself is elsewhere */
+               AddScope(SendChare) ;
+               ident += 2 ;  /* so it points to the handle identifier */
+       }
+       else
+               ident = SendChare ;
+               
+
+       if ( SendType == SIMPLE ) {
+               ind = SearchHandleTable(ChareHandleTable,ChareHandleTableSize,ident) ;
+               if ( ind == -1 ) {
+                       sprintf(errstr,"%s is not a Chare handle or is a field inside an aggregate",ident) ;
+                       CharmError(errstr) ;
+                       scopestr = NULL ;
+                       *charename = NULL ;
+                       goto endfn ;
+               }
+
+               len = strlen(ChareHandleTable[ind].typestr) ;
+               scopestr = (char *)malloc(sizeof(char)*(len+1)) ;
+               strcpy(scopestr,ChareHandleTable[ind].typestr) ;
+
+               lastcoln = Mystrstr(scopestr,"::") ;
+               if ( lastcoln != NULL ) {
+                       *lastcoln = '\0' ;
+                       *charename = lastcoln + 2 ;
+                       goto endfn ;
+               }
+
+               *charename = scopestr ; 
+               scopestr = (char *)malloc(sizeof(char)*2) ;
+               strcpy(scopestr," ") ;
+
+               /* Search for charename in ChareTable */
+
+               ind = FoundInChareTable(ChareTable,charecount+1,*charename) ;
+               if ( ind == -1 )
+                       goto endfn ;
+               for ( e=ChareTable[ind]->eps; e!=NULL; e=e->next ) {
+                       if ( strcmp(e->epname,SendEP) == 0 ) {
+                               break ;
+                       }
+               }
+               if ( e == NULL ) /* didnt find EP, so it is EntryPointType */
+                       *charename = NULL ;
+
+       }
+       else if ( SendType == BRANCH || SendType == BROADCAST ) {
+               ind = SearchHandleTable(BOCHandleTable,BOCHandleTableSize,ident) ;
+               if ( ind == -1 ) {
+                       sprintf(errstr,"%s is not a Branched Chare handle or is a field inside an aggregate",ident) ;
+                       CharmError(errstr) ;
+                       scopestr = NULL ;
+                       goto endfn ;
+               }
+
+               len = strlen(BOCHandleTable[ind].typestr) ;
+               scopestr = (char *)malloc(sizeof(char)*(len+1)) ;
+               strcpy(scopestr,BOCHandleTable[ind].typestr) ;
+
+               lastcoln = Mystrstr(scopestr,"::") ;
+               if ( lastcoln != NULL ) {
+                       *lastcoln = '\0' ;
+                       *charename = lastcoln + 2 ;
+                       goto endfn ;
+               }
+
+               *charename = scopestr ; 
+               scopestr = (char *)malloc(sizeof(char)*2) ;
+               strcpy(scopestr," ") ;
+               /* Search for charename in BOCTable */
+
+               ind = FoundInChareTable(BOCTable,boccount+1,*charename) ;
+               if ( ind == -1 )
+                       goto endfn ;
+               for ( e=BOCTable[ind]->eps; e!=NULL; e=e->next ) {
+                       if ( strcmp(e->epname,SendEP) == 0 ) {
+                               break ;
+                       }
+               }
+               if ( e == NULL ) /* didnt find EP, so it is EntryPointType */
+                       *charename = NULL ;
+       }
+
+endfn:  if ( Strstr(SendChare,"::") != NULL ) 
+               RemoveScope(SendChare) ;
+
+       return(scopestr) ;
+}
+
+
+
+
+OutputSend(SendChare, SendEP, msg, SendType, charename, scopestr, SendPe)
+char *SendChare; 
+char *SendEP; 
+char *msg; 
+int SendType;
+char *charename; 
+char *scopestr; 
+char *SendPe;
+{
+    if ( charename != NULL ) {
+       if ( SendType == SIMPLE ) {
+                 /* the cid is a handle=ChareIDType, so put &cid */
+               fprintf(outfile,"SendMsg(%s_CK_ep_%s_%s,(void *)%s,&(%s)",
+                               scopestr,charename,SendEP,msg,SendChare) ;
+               if ( MakeGraph )
+                       fprintf(graphfile,"SENDCHARE %s %s : %s %s\n", 
+                               CurrentChare, CurrentEP, charename, SendEP) ;
+       }
+       else if ( SendType == BRANCH ) {
+               fprintf(outfile,"_CK_SendMsgBranch(%s_CK_ep_%s_%s,(void *)%s,(int)(%s),%s",scopestr,charename,SendEP,msg,SendChare,SendPe) ;
+               if ( MakeGraph )
+                       fprintf(graphfile,"SENDBOC %s %s : %s %s %s\n", 
+                       CurrentChare, CurrentEP, charename, SendEP, SendPe) ;
+       }
+       else if ( SendType == BROADCAST ) {
+               fprintf(outfile,"_CK_BroadcastMsgBranch(%s_CK_ep_%s_%s,(void *)%s,(int)(%s)",scopestr,charename,SendEP,msg,SendChare) ;
+               if ( MakeGraph )
+                       fprintf(graphfile,"BROADCASTBOC %s %s : %s %s\n", 
+                               CurrentChare, CurrentEP, charename, SendEP) ;
+       }
+       else 
+               fprintf(stderr,"TRANSLATOR ERROR: SendType unknown\n");
+    }
+    else {
+       /* We have an EntryPointType as the SendEP */
+       if ( SendType == SIMPLE ) {
+                 /* the cid is a handle=ChareIDType, so put &cid */
+               fprintf(outfile,"SendMsg(%s,(void *)%s,&(%s)",SendEP,msg,
+                                                               SendChare) ;
+       }
+       else if ( SendType == BRANCH ){
+               fprintf(outfile,"_CK_SendMsgBranch(%s,(void *)%s,(int)(%s),%s",
+                                               SendEP,msg,SendChare,SendPe) ;
+       }
+       else if ( SendType == BROADCAST ){
+               fprintf(outfile,"_CK_BroadcastMsgBranch(%s,(void *)%s,(int)(%s)",SendEP,msg,SendChare) ;
+       }
+       else 
+               fprintf(stderr,"TRANSLATOR ERROR: SendType unknown\n");
+    }
+}
+
+
+InsertObjTable(name)
+char *name ;
+{
+       int num, i ;    
+       ChareInfo *chare ;
+       char *mymsg ;
+       char *myacc ;
+
+       CurrentCharePtr = NULL ;
+       strcpy(CurrentChare,"_CK_NOTACHARE") ; 
+
+       if ( CurrentAggType == CHARE || CurrentAggType == BRANCHED )
+       {       strcpy(CurrentChare,name) ;     
+               if ( CurrentAggType == CHARE ) {
+                       if ((num=FoundInChareTable(ChareTable,charecount+1,
+                                                       CurrentChare))!=-1) {
+                               CurrentCharePtr = ChareTable[num] ;
+                               return ;
+                       }
+                       else
+                               num = ++charecount ;    
+               }
+               else {
+                       if ((num=FoundInChareTable(BOCTable,boccount+1,
+                                                       CurrentChare))!=-1) {
+                               CurrentCharePtr = BOCTable[num] ;
+                               return ;
+                       }
+                       else
+                               num = ++boccount ;
+               }
+               chare = (ChareInfo *) malloc(sizeof(ChareInfo)) ;
+               strcpy(chare->name,CurrentChare) ;
+               chare->eps = NULL ;
+               chare->parents = NULL ;
+               if ( CurrentAggType == CHARE )
+                       ChareTable[num] = chare ;
+               else /* CurrentAggType == BRANCHED */
+                       BOCTable[num] = chare ;
+               CurrentCharePtr = chare ;
+       }       
+       else if ( CurrentAggType == MESSAGE ) {
+               mymsg = (char *)malloc((strlen(name)+1)*sizeof(char)) ;
+               strcpy(mymsg,name) ;
+               MessageTable[TotalMsgs].name = mymsg ;
+               MessageTable[TotalMsgs].pack = FALSE ;
+               MessageTable[TotalMsgs].numvarsize = 0 ;
+               MessageTable[TotalMsgs].varsizearray = NULL ;
+               TotalMsgs++ ;
+       }
+       else if ( CurrentAggType == ACCUMULATOR ) { 
+               /* this is an acc defn */
+               CurrentAcc = AccTable[TotalAccs] = (AccStruct *)malloc(sizeof(AccStruct)) ;
+
+               CurrentAcc->name = (char *)malloc((strlen(name)+1)*sizeof(char)) ;
+               strcpy(CurrentAcc->name,name) ;
+               TotalAccs++ ;
+       }
+       else if ( CurrentAggType == MONOTONIC ) { 
+               /* this is a mono defn */
+               CurrentAcc = MonoTable[TotalMonos] = (AccStruct *)malloc(sizeof(AccStruct)) ;
+
+               CurrentAcc->name = (char *)malloc((strlen(name)+1)*sizeof(char)) ;
+               strcpy(CurrentAcc->name,name) ;
+               TotalMonos++ ;
+       }
+       else if ( CurrentAggType == READONLY ) { 
+               /* this is a readonly defn */
+               ReadTable[TotalReads] = (char *)malloc((strlen(name)+1)*sizeof(char)) ;
+               strcpy(ReadTable[TotalReads],name) ;
+               TotalReads++ ;
+       }
+       else if ( CurrentAggType == READMSG ) { 
+               /* this is a readonly msg defn */
+               ReadMsgTable[TotalReadMsgs] = (char *)malloc((strlen(name)+1)*sizeof(char)) ;
+               strcpy(ReadMsgTable[TotalReadMsgs],name) ;
+               TotalReadMsgs++ ;
+       }
+       else if ( CurrentAggType == DTABLE ) { 
+               /* this is a table defn */
+               DTableTable[TotalDTables] = (char *)malloc((strlen(name)+1)*sizeof(char)) ;
+               strcpy(DTableTable[TotalDTables],name) ;
+               TotalDTables++ ;
+       }
+} 
+
+
+
+CheckSharedHandle(name)
+char *name ;
+{
+       int ind ;
+       char *sptr ;
+
+       ind = SearchHandleTable(AccHandleTable,AccHandleTableSize,name) ;
+        if ( ind == -1 ) {
+               ind = SearchHandleTable(MonoHandleTable,MonoHandleTableSize,name) ;
+               if ( ind == -1 ) {
+                       ind = SearchHandleTable(WrOnHandleTable,WrOnHandleTableSize,name) ;
+                       if ( ind == -1 ) 
+                               return ;
+               }
+       }
+
+       strcpy(CurrentSharedHandle,name) ;
+}
+
+
+SetDefinedIfEp(str)
+char *str ;
+{
+       char *col ;
+       char chare[128], *ep ;
+       ChareInfo *chptr = NULL ;
+       int ch, bo ;
+       EP *e ;
+       FN *f ;
+       int i ;
+
+       col = Mystrstr(str,"::") ;
+       if ( col == NULL )
+               return ;
+
+       /* sscanf(str,"%s::%s",chare,ep) ; */
+
+       for ( i=0; str!=col; i++,str++ )
+               chare[i] = *str ;
+       chare[i] = '\0' ;
+       ep = col + 2 ;
+
+       ch = FoundInChareTable(ChareTable,charecount+1,chare) ;
+       bo = FoundInChareTable(BOCTable,boccount+1,chare) ;
+
+       if ( ch != -1 )
+               chptr = ChareTable[ch] ;
+       else if ( bo != -1 )
+               chptr = BOCTable[bo] ;
+       if ( chptr != NULL ) {
+               for ( e=chptr->eps; e!=NULL; e=e->next ) {
+                       if ( strcmp(e->epname,ep) == 0 ) {
+                               e->defined = TRUE ;
+                               strcpy(CurrentChare,chptr->name) ;
+                               strcpy(CurrentEP,e->epname) ;
+                               CurrentCharePtr = chptr ;
+                               InsideChareCode = 1 ;
+                               return 1 ;
+                       }
+               }
+               for ( f=chptr->fns; f!=NULL; f=f->next ) {
+                       if ( strcmp(f->fnname,ep) == 0 ) {
+                               strcpy(CurrentChare,chptr->name) ;
+                               strcpy(CurrentEP,f->fnname) ;
+                               CurrentCharePtr = chptr ;
+                               InsideChareCode = 1 ;
+                               return 1 ;
+                       }
+               }
+       }
+       return 0 ;
+}
+
+
+
+char *Mystrstr(big,small)
+char *big, *small ;
+{
+/* The idea is to find the LAST position in big where small occurs ;
+   the usual strstr gives the FIRST occurrence of small in big */
+       
+       char *last ;
+       char * first = Strstr(big,small) ;
+
+       while ( first != NULL ) {
+               last = Strstr(first+1,small) ;
+               if ( last == NULL )
+                       return(first) ;
+               first = last ;
+       }
+       return(first) ;
+}
+
+
+MonoFN()
+{
+       return 0;
+}
+
+
+
+PushStack()
+{
+/* called when the prevtoken is a '{', from t.l  */
+/* Also from AddScope */
+
+       StackStruct *newtop = (StackStruct *)malloc(sizeof(StackStruct)) ;
+
+       if ( StackTop == NULL )
+               GlobalStack = newtop ;
+
+       newtop->next = StackTop ;
+
+       newtop->charecount = charecount ;
+       newtop->boccount = boccount ;
+       newtop->TotalMsgs = TotalMsgs ;
+       newtop->TotalAccs = TotalAccs ;
+       newtop->TotalMonos = TotalMonos ;
+       newtop->TotalReads = TotalReads ;
+       newtop->TotalReadMsgs = TotalReadMsgs ;
+       newtop->TotalSyms = TotalSyms ;
+       newtop->ChareHandleTableSize = ChareHandleTableSize ;
+       newtop->BOCHandleTableSize = BOCHandleTableSize ;
+       newtop->AccHandleTableSize = AccHandleTableSize ;
+       newtop->MonoHandleTableSize = MonoHandleTableSize ;
+
+       StackTop = newtop ;
+}
+
+PopStack()
+{
+/* called on when the prevtoken is a '}', from t.l  */
+/* Also from RemoveScope */
+
+       StackStruct *prevtop ;
+
+       if ( StackTop == NULL ) {
+               fprintf(stderr,"ERROR : %s, line %d : unmatched { and } braces.\n", CurrentFileName, CurrentLine) ;
+               return ;
+       }
+               
+
+       charecount = StackTop->charecount ;
+       boccount = StackTop->boccount ;
+       TotalMsgs = StackTop->TotalMsgs ;
+       TotalAccs = StackTop->TotalAccs ;
+       TotalMonos = StackTop->TotalMonos ;
+       TotalReads = StackTop->TotalReads ;
+       TotalReadMsgs = StackTop->TotalReadMsgs ;
+       TotalSyms = StackTop->TotalSyms ;
+       ChareHandleTableSize = StackTop->ChareHandleTableSize ;
+       BOCHandleTableSize = StackTop->BOCHandleTableSize ;
+       AccHandleTableSize = StackTop->AccHandleTableSize ;
+       MonoHandleTableSize = StackTop->MonoHandleTableSize ;
+
+       prevtop = StackTop ;
+       StackTop = StackTop->next ;
+
+       if ( StackTop == NULL )
+               GlobalStack = NULL ;
+
+       free(prevtop) ;
+}
+
+
+
+
+FillPermanentAggTable(name)
+char *name ;
+{
+       int i ;
+       AggState *n = PermanentAggTable[PermanentAggTableSize++] = (AggState *)
+                                                    malloc(sizeof(AggState)) ;
+       strcpy(n->name,name) ;
+/* put the index of this agg into symbol table */
+       for ( i=0; i<TotalSyms; i++ ) {
+               if ( strcmp(SymTable[i].name,name) == 0 ) {
+                       SymTable[i].permanentindex = PermanentAggTableSize-1;
+                       break ;
+               }
+       }
+
+
+/* First fill in all the Handle tables */
+
+       if ( (n->ChareHandleTableSize = ChareHandleTableSize - StackTop->ChareHandleTableSize) != 0 ) {
+               n->ChareHandleTable = (HandleEntry *)malloc(n->ChareHandleTableSize*sizeof(HandleEntry)) ;
+               for ( i=0; i<n->ChareHandleTableSize; i++ )
+                       n->ChareHandleTable[i] = ChareHandleTable[i+StackTop->ChareHandleTableSize] ;
+       }
+       if ( (n->BOCHandleTableSize = BOCHandleTableSize - StackTop->BOCHandleTableSize) != 0 ) {
+               n->BOCHandleTable = (HandleEntry *)malloc(n->BOCHandleTableSize*sizeof(HandleEntry)) ;
+               for ( i=0; i<n->BOCHandleTableSize; i++ )
+                       n->BOCHandleTable[i] = BOCHandleTable[i+StackTop->BOCHandleTableSize] ;
+       }
+       if ( (n->AccHandleTableSize = AccHandleTableSize - StackTop->AccHandleTableSize) != 0 ) {
+               n->AccHandleTable = (HandleEntry *)malloc(n->AccHandleTableSize*sizeof(HandleEntry)) ;
+               for ( i=0; i<n->AccHandleTableSize; i++ )
+                       n->AccHandleTable[i] = AccHandleTable[i+StackTop->AccHandleTableSize] ;
+       }
+       if ( (n->MonoHandleTableSize = MonoHandleTableSize - StackTop->MonoHandleTableSize) != 0 ) {
+               n->MonoHandleTable = (HandleEntry *)malloc(n->MonoHandleTableSize*sizeof(HandleEntry)) ;
+               for ( i=0; i<n->MonoHandleTableSize; i++ )
+                       n->MonoHandleTable[i] = MonoHandleTable[i+StackTop->MonoHandleTableSize] ;
+       }
+
+
+/* Now fill in all the typeDEF tables */
+
+       if ( TotalSyms == StackTop->TotalSyms ) {
+               n->TotalSyms = 0 ;  /* No new typeDEFS introduced in this agg*/
+               return ;
+       }
+
+       if ( (n->TotalSyms = TotalSyms - StackTop->TotalSyms) != 0 ) {
+               n->SymTable = (SymEntry *)malloc(n->TotalSyms*sizeof(SymEntry)) ;
+               for ( i=0; i<n->TotalSyms; i++ )
+                       n->SymTable[i] = SymTable[i+StackTop->TotalSyms] ;
+       }
+        if ( (n->charecount = charecount - StackTop->charecount) != 0){
+               n->ChareTable = (ChareInfo **)malloc(n->charecount*sizeof(ChareInfo *)) ;
+               for ( i=1; i<=n->charecount; i++ ) 
+                       n->ChareTable[i] = ChareTable[i+StackTop->charecount] ;
+       }
+               if ( (n->boccount = boccount - StackTop->boccount) != 0 ){
+               n->BOCTable = (ChareInfo **)malloc(n->boccount*sizeof(ChareInfo *)) ;
+               for ( i=1; i<=n->boccount; i++ ) 
+                       n->BOCTable[i] = BOCTable[i+StackTop->boccount] ;
+       }
+               if ( (n->TotalMsgs = TotalMsgs - StackTop->TotalMsgs) != 0 ){
+               n->MessageTable = (MsgStruct *)malloc(n->TotalMsgs*sizeof(MsgStruct));
+               for ( i=0; i<n->TotalMsgs; i++ ) {
+                       n->MessageTable[i].name = MessageTable[i+StackTop->TotalMsgs].name;
+                       n->MessageTable[i].pack = MessageTable[i+StackTop->TotalMsgs].pack;
+               }
+       }
+               if ( (n->TotalAccs = TotalAccs - StackTop->TotalAccs) != 0 ){
+               n->AccTable = (AccStruct **)malloc(n->TotalAccs*sizeof(AccStruct *)) ;
+               for ( i=0; i<n->TotalAccs; i++ ) 
+                       n->AccTable[i] = AccTable[i+StackTop->TotalAccs] ;
+       }
+               if ( (n->TotalMonos = TotalMonos - StackTop->TotalMonos) != 0){
+               n->MonoTable = (AccStruct **)malloc(n->TotalMonos*sizeof(AccStruct *)) ;
+               for ( i=0; i<n->TotalMonos; i++ ) 
+                       n->MonoTable[i] = MonoTable[i+StackTop->TotalMonos] ;
+       }
+}
+
+       
+int InsideAddScope=0 ;
+               
+AddScope(name)
+char *name;
+{
+       int i ;
+       char *firstcoln, *ptr, *rest ;
+       char classname[MAX_NAME_LENGTH] ;
+
+
+       firstcoln=Strstr(name,"::") ;
+
+       if ( firstcoln == NULL ) 
+               return ;
+       if ( firstcoln==name ) {
+               FoundGlobalScope = 1 ;
+               firstcoln += 2 ;
+       }
+
+       InsideAddScope = 1 ;    
+       PushStack() ;   
+       /* record state before the function is entered. This matches
+          with the call in RemoveScope() */
+
+       rest = name ;
+       
+       while ( firstcoln != NULL ) {
+               for ( i=0,ptr=rest; *ptr!=':'; ptr++ )
+                       classname[i++] = *ptr ;
+               classname[i] = '\0' ;
+               rest = firstcoln+2 ;
+
+               AddOneScope(classname) ;
+
+               firstcoln=Strstr(rest,"::") ;
+       }
+       InsideAddScope = 0 ;    
+}
+       
+
+AddOneScope(name)
+char *name ;
+{
+       int i, ind = -1 ;
+       AggState *n ;
+
+       if ( strcmp(CurrentAggName,name) == 0 )
+               return ;
+
+       /* The AddedScope variable is to be used only for indicating that
+          a TEMPORARY scope has been added, eg in :: stuff.
+          It is used when we dont know (from context) whether a scope has
+          been added or not, eg when the adding and removing occur in 
+          different parts of the yacc file */
+       /* For functions, etc, the AddScope() and RemoveScope() pair is always
+          called, so AddedScope should not be set (it causes confusion) */
+
+       if ( AddedScope==0 && !InsideAddScope ) {
+       /* second condition is to prevent two PushStacks */
+               PushStack() ;
+               AddedScope = 1  ;
+       }
+
+       /* find name's entry in PermanentAggTable */
+       if ( !FoundGlobalScope || GlobalStack==NULL ) {
+               for ( i=TotalSyms-1; i>=0; i-- ) { 
+               /* name HAS to be there in the SymTable because it
+                  gets updated every time by AddOneScope */
+                       if ( strcmp(name,SymTable[i].name)==0 ) {       
+                               ind = SymTable[i].permanentindex ; 
+                               break ; 
+                       }
+               }
+       }
+       else {
+               for ( i=0; i<GlobalStack->TotalSyms; i++ ) { 
+                       if ( strcmp(name,SymTable[i].name)==0 ) {       
+                               ind = SymTable[i].permanentindex ; 
+                               break ; 
+                       }
+               }
+               FoundGlobalScope = 0 ;
+       }
+       if ( i == TotalSyms || ind == -1 ) {
+               fprintf(stderr,"POSSIBLE ERROR: %s, line %d : is %s an aggregate name in current scope ?\n",CurrentFileName,CurrentLine,name) ;
+               return ;
+       }
+
+       n = PermanentAggTable[ind] ;
+
+       for ( i=0; i<n->ChareHandleTableSize; i++ )
+               ChareHandleTable[ChareHandleTableSize++] = n->ChareHandleTable[i] ;
+       for ( i=0; i<n->BOCHandleTableSize; i++ )
+               BOCHandleTable[BOCHandleTableSize++] = n->BOCHandleTable[i] ;
+       for ( i=0; i<n->AccHandleTableSize; i++ )
+               AccHandleTable[AccHandleTableSize++] = n->AccHandleTable[i] ;
+       for ( i=0; i<n->MonoHandleTableSize; i++ )
+               MonoHandleTable[MonoHandleTableSize++] = n->MonoHandleTable[i];
+
+       if ( n->TotalSyms == 0 ) {
+               /* No new typeDEFS introduced in this agg*/
+               return ;
+       }
+
+       for ( i=0; i<n->TotalSyms; i++ )
+               SymTable[TotalSyms++] = n->SymTable[i] ;
+       for ( i=0; i<n->charecount; i++ ) 
+               ChareTable[++charecount] = n->ChareTable[i] ;
+       for ( i=0; i<n->boccount; i++ ) 
+               BOCTable[++boccount] = n->BOCTable[i] ;
+       for ( i=0; i<n->TotalMsgs; i++ ) {
+               MessageTable[TotalMsgs++].name =n->MessageTable[i].name ;
+               MessageTable[TotalMsgs++].pack =n->MessageTable[i].pack ;
+       }
+       for ( i=0; i<n->TotalAccs; i++ ) 
+               AccTable[TotalAccs++] = n->AccTable[i] ;
+       for ( i=0; i<n->TotalMonos; i++ ) 
+               MonoTable[TotalMonos++] = n->MonoTable[i] ;
+}
+
+
+RemoveScope(name)
+char *name ;
+{
+        char *firstcoln ;
+
+        firstcoln=Strstr(name,"::") ;
+
+        if ( firstcoln == NULL )
+                return ;
+
+       PopStack() ;    
+       /* restore state to before entering function. This matches
+           with the call in AddScope() */
+
+}
+
+
+InsertVarSize(type, name)
+char *type, *name ;
+{      MsgStruct *thismsg ;
+
+        thismsg = &(MessageTable[TotalMsgs-1]) ;
+        if ( thismsg->numvarsize == 0 ) {
+                thismsg->varsizearray = (VarSizeStruct *)
+                          malloc(sizeof(VarSizeStruct)*MAX_VARSIZE) ;
+        }
+        thismsg->varsizearray[thismsg->numvarsize].type = 
+                        (char *)malloc((sizeof(char)+1)*strlen(type)) ;
+        thismsg->varsizearray[thismsg->numvarsize].name =
+                        (char *)malloc((sizeof(char)+1)*strlen(name)) ;
+       strcpy(thismsg->varsizearray[thismsg->numvarsize].type,type) ;
+       strcpy(thismsg->varsizearray[thismsg->numvarsize].name,name) ;
+
+       thismsg->numvarsize++ ;
+       thismsg->pack = TRUE ;
+}
+
+
+
+InsertFunctionTable(name,defined)
+char *name ;
+int defined ;
+{
+       int i, j ;
+
+       if ( Strstr(name,"::") != NULL )
+               return ;        /* this is a aggregate member function defn */
+
+       if ( Strstr(name,"operator") != NULL )
+               return ;  /* for now, dont put operators in function table */
+
+       if ( defined ) { /* search for overloading */
+           for ( i=0; i<TotalFns; i++ ) {
+               if ( strcmp(FunctionTable[i].name,name) == 0 &&
+                    FunctionTable[i].defined ) {
+                       /* HACK : cant handle overloading yet : 
+                          so remove from table */
+                       for ( j=i; j<TotalFns-1; j++ ) {
+                               FunctionTable[j].name = FunctionTable[j+1].name ;
+                               FunctionTable[j].defined = FunctionTable[j+1].defined ;
+                       }
+                       TotalFns-- ;
+                       return ;
+               }
+           }
+       }
+
+       FunctionTable[TotalFns].name = (char *)malloc((strlen(name)+1)*sizeof(char)) ;
+       strcpy(FunctionTable[TotalFns].name,name) ;
+       FunctionTable[TotalFns].defined = defined ;
+       TotalFns++ ;
+}
+       
+
+
+EP * AlreadyInList(thisep,eplist)
+EP *thisep, *eplist ;
+{
+       EP *epl ;
+
+       for ( epl=eplist; epl!=NULL; epl=epl->next )
+               if ( strcmp(epl->epname, thisep->epname) == 0 )
+                       return epl ;
+       return NULL ;
+}
+
+
+AddInheritedEps(chare)
+ChareInfo *chare ;
+{
+       int i, j, count ;
+       ChareInfo *p ;
+       ChareList *pl ;
+       EP *newep, *parep, *thisep ;
+
+       for ( pl=chare->parents; pl!=NULL; pl=pl->next ) {
+               p = pl->chare ;
+               /* Add eplist of parent to eplist of this chare 
+                  for inheritance */
+               for ( parep=p->eps; parep!=NULL; parep=parep->next ) {
+                               if ((thisep=AlreadyInList(parep,chare->eps))) {
+                               thisep->inherited = 1 ;
+                               thisep->parentep = parep ;
+                               if ( parep->isvirtual )
+                                       thisep->isvirtual = TRUE ;
+                       }
+                               else {
+                                       newep = (EP *)malloc(sizeof(EP)) ;
+                                       strcpy(newep->epname,parep->epname) ;
+                                       strcpy(newep->msgname,parep->msgname) ;
+                               newep->parentep = parep ;
+                                       newep->inherited = 1 ;
+                               newep->defined = 0 ;
+                               if ( parep->isvirtual )
+                                       newep->isvirtual = TRUE ;
+                               newep->chare = chare ;
+                               InsertAlpha(chare,newep) ;
+                       }
+               }
+       }
+}
+
+       
+       
+
+InsertAlpha(chare,ep)
+ChareInfo *chare ;
+EP *ep ;
+{
+       int val ;
+       EP *e, *eprev ;
+
+       if ( chare->eps == NULL ) {
+               chare->eps = ep ;
+               return ;
+       }
+       for ( eprev=NULL,e=chare->eps; e!=NULL; eprev=e,e=e->next ) {
+               val = strcmp(ep->epname,e->epname) ;
+               if ( val < 0 ) {        
+                       /* insert ep before e */        
+                       if ( eprev == NULL )
+                               chare->eps = ep ;
+                       else
+                               eprev->next = ep ;
+                       ep->next = e ;
+                       break ;
+               }
+               else if ( val == 0 ) /* already in list OR overloaded*/
+                       break ;
+       }
+       if ( e == NULL ) { /* insert at end of list */
+               eprev->next = ep ;
+               ep->next = NULL ;
+       }
+}
+
+
+CheckConstructorEP(name,defined)
+char *name ;
+int defined ;
+{
+       char *begin ;
+
+       if ( CurrentAggType==CHARE || CurrentAggType==BRANCHED ) {
+                if ( CurrentAccess == ENTRY )
+                        ProcessEP(name,defined);
+                else if ( strcmp(CurrentChare,"main")==0 &&
+                          strcmp(name,"main")==0 )
+                {       /* replace main by _CK_main */
+                        char *sptr = Mystrstr(OutBuf,name) ;
+                       char save[1024] ;
+                       strcpy(save,sptr) ;
+                        *sptr = '\0' ;
+                        strcat(OutBuf,"void _CK") ;
+                       strcat(OutBuf,save) ;
+                        ProcessEP(name,defined);
+                }
+        }
+       else if ( (begin=Mystrstr(OutBuf,"main::main")) != NULL ) {
+       /* constructor definition outside the chare body */
+                char save[1024] ;
+               strcpy(save,begin) ;
+               *begin = '\0' ;
+               strcat(OutBuf,"void main::_CKmain") ;
+                strcat(OutBuf,save+10) ;
+       }
+
+}
+
+
+
+
+InsertParent(chare, parent, table, tablecount)
+ChareInfo *chare ;
+char *parent ;
+ChareInfo **table ;
+int tablecount ;
+{
+       int i, found=0 ;
+       ChareList *save ;
+       ChareInfo *p ;
+       EP *ep, *newep ;
+
+       for ( i=0; i<tablecount; i++ ) {
+               if ( strcmp(table[i]->name,parent) == 0 ) {
+                       found = 1 ;
+                       break ;
+               }
+       }
+       if ( !found )
+               return ;
+       save = chare->parents ;
+       chare->parents = (ChareList *)malloc(sizeof(ChareList)) ;
+       p = chare->parents->chare = table[i] ;
+       chare->parents->next = save ;
+}
+
+               
+
+
+char *Strstr(b,s)
+char *b, *s ;
+{
+       int i=0, j=0, nextbeg=1 ;
+       int ls, lb ;
+
+       ls = strlen(s) ;
+       lb = strlen(b) ;
+
+       if ( ls > lb )
+               return(NULL) ;
+
+       while ( i < ls && j < lb )      {
+               if ( s[i] == b[j] ) {
+                       i++ ;
+                       j++ ;
+               }
+               else {
+                       i = 0 ;
+                       j = nextbeg ;
+                       nextbeg++ ;
+               }
+       }
+       
+       if ( j == lb && i != ls ) 
+               return(NULL) ;
+       else
+               return(b+j-ls) ;
+}