--- erl_call.c.orig	Sat Oct 15 09:10:16 2005
+++ erl_call.c	Sun Oct 16 12:28:40 2005
@@ -83,6 +83,7 @@
 #include "ei.h"
 #include "ei_resolve.h"
 #include "erl_start.h"		/* FIXME remove dependency */
+#include "erl_interface.h"
 
 #ifdef __WIN32__
 static void initWinSock(void);
@@ -119,8 +120,8 @@
 static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags);
 static int read_stdin(char **buf);
 static void split_apply_string(char *str, char **mod, 
-			       char **fun, char **args);
-
+                               char **fun, char **args, char **pattern);
+char *get_token(char **str, char delim, char *tag, int include_last);
 
 /***************************************************************************
  *
@@ -175,6 +176,8 @@
 	    strcpy(flags.node, argv[i+1]);
 	    i++;
 	    flags.use_long_name = 1;
+        } else if (strcmp(argv[i], "-ssh") == 0) {  /* -ssh */
+            flags.startp = ERL_START_SSH;
 	} else {
 	    if (strlen(argv[i]) != 2) {
 		usage_error(progname, argv[i]);
@@ -182,11 +185,14 @@
 		    
 	    switch (argv[i][1]) {
 	    case 's':
-		flags.startp = 1;
+                flags.startp = ERL_START_REMOTE;
 		break;
 	    case 'q':
 		flags.haltp = 1;
 		break;
+            case 't':
+                flags.haltp = 2;
+                break;
 	    case 'v':
 		flags.verbosep = 1;
 		break;
@@ -272,12 +278,13 @@
     if (flags.verbosep || flags.debugp) {
 	fprintf(stderr,"erl_call: "
 		"node = %s\nCookie = %s\n"
-		"flags = %s %s %s\n"
+                "flags = %s%s %s %s\n"
 		"module: name = %s , size = %d\n"
 		"apply = %s\n",
 		(flags.node ? flags.node : ""),
 		(flags.cookie ? flags.cookie : ""),
-		(flags.startp ? "startp" : ""),
+                ((flags.startp == ERL_START_REMOTE) ? "startp" : ""),
+                ((flags.startp == ERL_START_SSH)    ? "startp_ssh" : ""),
 		(flags.verbosep ? "verbosep" : ""),
 		(flags.debugp ? "debugp" : ""),
 		(modname ? modname : ""), modsize,
@@ -393,6 +400,7 @@
     if (fd && flags.haltp) {
 	int i = 0;
 	char *p;
+        char *mod, *fun;
 	ei_x_buff reply;
 
 	ei_encode_empty_list(NULL, &i);
@@ -404,11 +412,22 @@
 
 	ei_x_new_with_version(&reply);
 
-	/* FIXME if fails we want to exit != 0 ? */
-	ei_rpc(&ec, fd, "erlang", "halt", p, i, &reply);
+        if ( flags.haltp == 1 ) {
+            mod = "erlang";
+            fun = "halt";
+        } else {
+            mod = "init";
+            fun = "stop";
+        }
+        /* FIXME if we use erlang:halt/0, ei_rpc returns -1.  Is this expected? */
+        if ((i = ei_rpc(&ec, fd, mod, fun, p, i, &reply)) < 0 && flags.haltp != 1)
+            fprintf(stderr, "erl_call: failed to halt node %s\n", nodename);
+        else if (flags.verbosep)
+            fprintf(stderr, "node %s stopped using: %s:%s\n", nodename, mod, fun);
+
 	free(p);
 	ei_x_free(&reply);
-	exit(0);
+        exit(i);
     }
 
     if (flags.verbosep) {
@@ -547,13 +566,13 @@
      * Any Erlang call to be made ?
      */
     if (flags.apply != NULL) {
-      char *mod,*fun,*args;
+        char *mod,*fun,*args, *pattern = NULL;
       ei_x_buff e, reply;
 
-      split_apply_string(flags.apply, &mod, &fun, &args);
+        split_apply_string(flags.apply, &mod, &fun, &args, &pattern);
       if (flags.verbosep) {
-	  fprintf(stderr,"erl_call: module = %s, function = %s, args = %s\n",
-		  mod, fun, args);
+            fprintf(stderr,"erl_call: mod='%s', fun='%s', args='%s', pattern='%s'\n",
+                    mod, fun, args, pattern);
       }
 
       ei_x_new(&e);		/* No version to ei_rpc() */
@@ -573,8 +592,32 @@
       } else {
 	  int i = 0;
 	  ei_print_term(stdout,reply.buff,&i);
+            fprintf(stdout, "\n");
 	  ei_x_free(&e);
+            if (pattern == NULL)
+                i = 0;
+            else {
+                ETERM* pat;
+                ETERM* term;
+                erl_init(NULL,0);
+                pat = erl_format(pattern);
+
+                if (pat == NULL) {
+                    fprintf(stderr, "erl_call: invalid pattern in the -a format: \"%s\"\n",
+                            pattern);
+                    exit(1);
+                }
+                i = 0;
+                if (ei_decode_term(reply.buff, &i, &term) < 0) {
+                    fprintf(stderr, "erl_call: cannot decode term using ei_decode_term\n");
+                    exit(1);
+                }
+                i = !erl_match(pat, term);
+                erl_free_term(term);
+                erl_free_term(pat);
+            }
 	  ei_x_free(&reply);
+            exit(i);
       }
     }
 
@@ -627,7 +670,8 @@
     start_flags = ERL_START_ENODE |
 	(flags->use_long_name? ERL_START_LONG : 0) |
 	(flags->verbosep? ERL_START_VERBOSE : 0) |
-	(flags->debugp? ERL_START_DEBUG : 0);
+                  (flags->debugp? ERL_START_DEBUG : 0) |
+                  ((flags->startp == ERL_START_SSH)? ERL_START_SSH : 0);
 
     if ((fd = ei_connect(ec, nodename)) >= 0) {
 	/* success */
@@ -695,18 +739,34 @@
 } /* do_connect */
 
 #define SKIP_SPACE(s) while(isspace((int)*(s))) (s)++
-#define EAT(s) while (!isspace((int)*(s)) && (*(s) != '\0')) (s)++
+#define EAT(s) while (!isspace((int)*(s)) && (*(s) != '=') && (*(s) != ':') && (*(s) != '\0')) (s)++
+#define TRIM(s) while while(isspace(s[strlen(s)])) (s)++
 
 static void split_apply_string(char *str, 
 			       char **mod, 
 			       char **fun, 
-			       char **args)
+                               char **args,
+                               char **pattern)
 {
   char *begin=str;
   char *start="start";
   char *empty_list="[]";
   int len;
+    char *ch;
 
+    /* Determine the syntax 'mod fun args' or 'pattern = mod:fun(args) */
+    if ((ch = strchr(str, '=')) != NULL) {
+        /* This is the 'pattern = mod:fun(args) syntax */
+        *pattern = get_token(&str, '=', "pattern", 0); str++;
+        *mod     = get_token(&str, ':', "mod", 0);     str++;
+        *fun     = get_token(&str, '(', "fun", 0);
+        *args    = get_token(&str, ')', "args", 1);
+        **args = '[';
+        for (ch = *args + strlen(*args); ch != *args && *ch != ')'; --ch);
+        *ch = ']';
+        return;
+    } else {
+      /* This is the old syntax 'mod fun args' */
   SKIP_SPACE(str);
   if (*str == '\0') {
       fprintf(stderr,"erl_call: wrong format of apply string (1)\n");
@@ -741,11 +801,29 @@
 
   *args = (char *) calloc(strlen(str) + 1, sizeof(char));
   strcpy(*args, str);
-  
+    }
   return;
 
 } /* split_apply_string */
 
+char *get_token(char **str, char delim, char *tag, int include_last)
+{
+    char *begin, *result;
+    char *ch;
+    SKIP_SPACE(*str);
+    begin = *str;
+    if ((ch = strchr(*str, delim)) == NULL) {
+        fprintf(stderr, "erl_call: wrong format of apply string (%s) \"%s\"\n", tag, *str);
+        exit(1);
+    } else {
+        *str = ch;
+        if (!include_last)
+            while(*(ch-1) == ' ' && ch != begin) --ch;
+        result = (char *) calloc(ch-begin+1+include_last, sizeof(char));
+        strncpy(result, begin, ch-begin+include_last);
+    }
+    return result;
+} /* get_token */
 
 /* 
  * Read from stdin until EOF is reached.
@@ -823,13 +901,15 @@
 
 static void usage_noexit(const char *progname) {
   fprintf(stderr,"\nUsage: %s [-[demqrsv]] [-c Cookie] [-h HiddenName] \n", progname);
-  fprintf(stderr,"            [-x ErlScript] [-a [Mod [Fun [Args]]]]\n");
+    fprintf(stderr,"            [-x ErlScript]\n");
+    fprintf(stderr,"            [-a ([Mod [Fun [Args]] | Pattern = Mod:Fun(Args))]\n");
   fprintf(stderr,"            (-n Node | -sname Node | -name Node)\n\n");
 #ifdef __WIN32__
   fprintf(stderr,"  where: -a  apply(Mod,Fun,Args) (e.g -a \"erlang length [[a,b,c]]\"\n");
 #else
   fprintf(stderr,"  where: -a  apply(Mod,Fun,Args) (e.g -a 'erlang length [[a,b,c]]'\n");
 #endif
+    fprintf(stderr,"                                    or -a '{_,_,_} = erlang:now()')\n");
   fprintf(stderr,"         -c  cookie string; by default read from ~/.erlang.cookie\n");
   fprintf(stderr,"         -d  direct Erlang output to ~/.erl_call.out.<Nodename>\n");
   fprintf(stderr,"         -e  evaluate contents of standard input (e.g echo \"X=1,Y=2,{X,Y}.\"|erl_call -e ...)\n");
@@ -839,8 +919,10 @@
   fprintf(stderr,"         -name  name of Erlang node, expanded to a fully qualified\n");
   fprintf(stderr,"         -sname name of Erlang node, short form will be used\n");
   fprintf(stderr,"         -q  halt the Erlang node (overrides the -s switch)\n");
+    fprintf(stderr,"         -t   stop the Erlang node using init:stop/0 (overrides the -q switch)\n");
   fprintf(stderr,"         -r  use a random name for the erl_call client node\n");
-  fprintf(stderr,"         -s  start a new Erlang node if necessary\n");
+    fprintf(stderr,"         -s   start a new Erlang node if necessary using rsh\n");
+    fprintf(stderr,"         -ssh start a new Erlang node if necessary using ssh\n");
   fprintf(stderr,"         -v  verbose mode, i.e print some information on stderr\n");
   fprintf(stderr,"         -x  use specified erl start script, default is erl\n");
 }
--- erl_start.c.orig	Sun Oct 16 12:10:29 2005
+++ erl_start.c	Sun Oct 16 12:07:25 2005
@@ -482,9 +482,9 @@
 		       int port)
 {
 #if !defined(__WIN32__) && !defined(VXWORKS) 
-  int fd,len,l,i;
+  int fd,len,l,i,n;
   char **s;
-  char *argv[4];
+  char *argv[6];
   char argbuf[BUFSIZ];
   struct in_addr myaddr;
   struct in_addr *hisaddr = (struct in_addr *)adr;
@@ -493,19 +493,30 @@
 
   /* on this host? */
   /* compare ip addresses, unless forced by flag setting to use rsh */
-  if ((flags & ERL_START_REMOTE) || (hisaddr->s_addr != myaddr.s_addr)) {
+  if ((flags & ERL_START_REMOTE) || (flags & ERL_START_SSH) ||
+      (hisaddr->s_addr != myaddr.s_addr)) {
+    if ( flags & ERL_START_SSH ) {
+        argv[0] = "ssh";
+        argv[1] = "-n";
+        argv[2] = "-f";
+        n = 3;
+    } else {
     argv[0] = RSH;
+        n = 1;
+    }
     len = strlen(inet_ntoa(*hisaddr));
-    argv[1] = malloc(len+1);
-    strcpy(argv[1],inet_ntoa(*hisaddr));
+    argv[n] = malloc(len+1);
+    strcpy(argv[n],inet_ntoa(*hisaddr));
+    n++;
   }
   else {
   /* Yes - use sh to start local Erlang */
     argv[0] = "sh";
     argv[1] = "-c";
+    n = 2;
   }
-  argv[2] = argbuf;
-  argv[3] = NULL;
+  argv[n++] = argbuf;
+  argv[n++] = NULL;
 
   len = 0;
   *argbuf=(char)0;
@@ -544,7 +555,9 @@
   }
 
   if (flags & ERL_START_VERBOSE) {
-    fprintf(stderr,"erl_call: %s %s %s\n",argv[0],argv[1],argv[2]);
+    fprintf(stderr,"erl_call: ");
+    for(i=0; i<(n-1); ++i) fprintf(stderr, "%s ", argv[i]);
+    fprintf(stderr, "\n");
   }
 
   /* close all descriptors in child */
@@ -560,7 +573,9 @@
       dup2(fd,1);
       dup2(fd,2);
       fprintf(stderr,"\n\n===== Log started ======\n%s \n",ctime(&t));
-      fprintf(stderr,"erl_call: %s %s %s\n",argv[0],argv[1],argv[2]);
+      fprintf(stderr,"erl_call: ");
+      for(i=0; i<(n-1); ++i) fprintf(stderr, "%s ", argv[i]);
+      fprintf(stderr, "\n");
     }
   }     
 
@@ -568,8 +583,9 @@
   execvp(argv[0], argv);
 
   if (flags & ERL_START_DEBUG) {
-    fprintf(stderr,"erl_call: exec failed: (%d) %s %s %s\n",
-	    errno,argv[0],argv[1],argv[2]);
+    fprintf(stderr,"erl_call: exec failed: (%d)", errno);
+    for(i=0; i<(n-1); ++i) fprintf(stderr, "%s ", argv[i]);
+    fprintf(stderr, "\n");
   }
 
 #endif
--- erl_start.h.orig	Sun Oct 16 12:10:42 2005
+++ erl_start.h	Sun Oct 16 10:07:16 2005
@@ -30,6 +30,7 @@
 #define ERL_START_DEBUG   0x0010
 #define ERL_START_VERBOSE 0x0020
 #define ERL_START_REMOTE  0x0040
+#define ERL_START_SSH     0x0080
 
 /* error return values */
 #define ERL_S_TIMEOUT    -51  /* a timeout occurred */
--- Makefile.in.orig	Sat Oct 15 23:29:11 2005
+++ Makefile.in	Sat Oct 15 23:30:13 2005
@@ -666,11 +666,11 @@
 ifeq ($(TARGET),win32)
 $(ERL_CALL): $(ERLCALL) ../include/ei.h $(MD_EILIB)
 	$(PURIFY) $(CC) -MD $(PROG_CFLAGS) $(THR_DEFS) -o $@ $(ERLCALL) \
-		-L$(OBJDIR) -lei_md $(THR_LIBS) $(LIBS) -lsocket
+		-L$(OBJDIR) -lei_md $(THR_LIBS) $(LIBS) -lsocket 
 else
 ifeq ($(findstring vxworks,$(TARGET)),vxworks)
 $(ERL_CALL): $(ST_OBJDIR)/erl_call.o $(ST_OBJDIR)/erl_start.o ../include/ei.h $(ST_EILIB)
-	$(LD) -r -d -o $@ $(ST_OBJDIR)/erl_call.o $(ST_OBJDIR)/erl_start.o -L$(OBJDIR) -lei $(LIBS)
+	$(LD) -r -d -o $@ $(ST_OBJDIR)/erl_call.o $(ST_OBJDIR)/erl_start.o -L$(OBJDIR) -lei $(LIBS) -lerl_interface
 
 $(ST_OBJDIR)/erl_call.o: prog/erl_call.c
 	$(CC) $(CFLAGS) -c $< -o $@ 
@@ -685,11 +685,11 @@
 ifdef THR_DEFS
 $(ERL_CALL): $(ERLCALL) ../include/ei.h $(MT_EILIB)
 	$(PURIFY) $(CC) $(PROG_CFLAGS) $(THR_DEFS) -o $@ $(ERLCALL) \
-		-L$(OBJDIR) -lei $(THR_LIBS) $(LIBS)
+		-L$(OBJDIR) -lei $(THR_LIBS) $(LIBS) -lerl_interface
 else
 $(ERL_CALL): $(ERLCALL) ../include/ei.h $(ST_EILIB)
 	$(PURIFY) $(CC) $(PROG_CFLAGS) -o $@ $(ERLCALL) \
-		-L$(OBJDIR) -lei $(LIBS)
+		-L$(OBJDIR) -lei $(LIBS) -lerl_interface
 endif
 endif
 endif
