aboutsummaryrefslogtreecommitdiffstats
path: root/lib/erl_interface/src/prog/erl_call.c
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/erl_interface/src/prog/erl_call.c
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/erl_interface/src/prog/erl_call.c')
-rw-r--r--lib/erl_interface/src/prog/erl_call.c906
1 files changed, 906 insertions, 0 deletions
diff --git a/lib/erl_interface/src/prog/erl_call.c b/lib/erl_interface/src/prog/erl_call.c
new file mode 100644
index 0000000000..f0d638324d
--- /dev/null
+++ b/lib/erl_interface/src/prog/erl_call.c
@@ -0,0 +1,906 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ *
+
+ */
+/*
+ * Function: Makes it possible to send and receive Erlang
+ * messages from the (Unix) command line.
+ * Note: We don't free any memory at all since we only
+ * live for a short while.
+ *
+ */
+
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <direct.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+
+#include <stdio.h>
+#include <string.h>
+#include <vxWorks.h>
+#include <hostLib.h>
+#include <selectLib.h>
+#include <ifLib.h>
+#include <sockLib.h>
+#include <taskLib.h>
+#include <inetLib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <time.h>
+
+#else /* unix */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <netdb.h>
+#include <sys/times.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "ei.h"
+#include "ei_resolve.h"
+#include "erl_start.h" /* FIXME remove dependency */
+
+#ifdef __WIN32__
+static void initWinSock(void);
+#endif
+
+/*
+ * Some nice global variables
+ * (I don't think "nice" is the right word actually... -gordon)
+ */
+/* FIXME problem for threaded ? */
+
+struct call_flags {
+ int startp;
+ int cookiep;
+ int modp;
+ int evalp;
+ int randomp;
+ int use_long_name; /* indicates if -name was used, else -sname or -n */
+ int debugp;
+ int verbosep;
+ int haltp;
+ char *cookie;
+ char *node;
+ char *hidden;
+ char *apply;
+ char *script;
+};
+
+static void usage_arg(const char *progname, const char *switchname);
+static void usage_error(const char *progname, const char *switchname);
+static void usage(const char *progname);
+static int get_module(char **mbuf, char **mname);
+static struct hostent* get_hostent(char *host);
+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);
+
+
+/***************************************************************************
+ *
+ * XXXXX
+ *
+ ***************************************************************************/
+
+/* FIXME isn't VxWorks to handle arguments differently? */
+/* FIXME check errors from malloc */
+
+#if !defined(VXWORKS)
+int main(int argc, char *argv[])
+#else
+int erl_call(int argc, char **argv)
+#endif
+{
+ int i = 1,fd,creation;
+ struct hostent *hp;
+ char host_name[EI_MAXHOSTNAMELEN+1];
+ char nodename[MAXNODELEN+1];
+ char *p = NULL;
+ char *ct = NULL; /* temporary used when truncating nodename */
+ int modsize = 0;
+ char *host = NULL;
+ char *module = NULL;
+ char *modname = NULL;
+ struct call_flags flags = {0}; /* Default 0 and NULL in all fields */
+ char* progname = argv[0];
+ ei_cnode ec;
+
+ /* Get the command line options */
+ while (i < argc) {
+ if (argv[i][0] != '-') {
+ usage_error(progname, argv[i]);
+ }
+
+ if (strcmp(argv[i], "-sname") == 0) { /* -sname NAME */
+ if (i+1 >= argc) {
+ usage_arg(progname, "-sname ");
+ }
+
+ flags.node = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.node, argv[i+1]);
+ i++;
+ flags.use_long_name = 0;
+ } else if (strcmp(argv[i], "-name") == 0) { /* -name NAME */
+ if (i+1 >= argc) {
+ usage_arg(progname, "-name ");
+ }
+
+ flags.node = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.node, argv[i+1]);
+ i++;
+ flags.use_long_name = 1;
+ } else {
+ if (strlen(argv[i]) != 2) {
+ usage_error(progname, argv[i]);
+ }
+
+ switch (argv[i][1]) {
+ case 's':
+ flags.startp = 1;
+ break;
+ case 'q':
+ flags.haltp = 1;
+ break;
+ case 'v':
+ flags.verbosep = 1;
+ break;
+ case 'd':
+ flags.debugp = 1;
+ break;
+ case 'r':
+ flags.randomp = 1;
+ break;
+ case 'e':
+ flags.evalp = 1;
+ break;
+ case 'm':
+ flags.modp = 1;
+ break;
+ case 'c':
+ if (i+1 >= argc) {
+ usage_arg(progname, "-c ");
+ }
+ flags.cookiep = 1;
+ flags.cookie = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.cookie, argv[i+1]);
+ i++;
+ break;
+ case 'n':
+ if (i+1 >= argc) {
+ usage_arg(progname, "-n ");
+ }
+ flags.node = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.node, argv[i+1]);
+ flags.use_long_name = 1;
+ i++;
+ break;
+ case 'h':
+ if (i+1 >= argc) {
+ usage_arg(progname, "-h ");
+ }
+ flags.hidden = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.hidden, argv[i+1]);
+ i++;
+ break;
+ case 'x':
+ if (i+1 >= argc) {
+ usage_arg(progname, "-x ");
+ }
+ flags.script = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.script, argv[i+1]);
+ i++;
+ break;
+ case 'a':
+ if (i+1 >= argc) {
+ usage_arg(progname, "-a ");
+ }
+ flags.apply = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.apply, argv[i+1]);
+ i++;
+ break;
+ case '?':
+ usage(progname);
+ default:
+ usage_error(progname, argv[i]);
+ }
+ }
+ i++;
+
+ } /* while */
+
+
+ /*
+ * Can't have them both !
+ */
+ if (flags.modp && flags.evalp) {
+ usage(progname);
+ }
+
+ /*
+ * Read an Erlang module from stdin.
+ */
+ if (flags.modp) {
+ modsize = get_module(&module, &modname);
+ }
+
+ if (flags.verbosep || flags.debugp) {
+ fprintf(stderr,"erl_call: "
+ "node = %s\nCookie = %s\n"
+ "flags = %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.verbosep ? "verbosep" : ""),
+ (flags.debugp ? "debugp" : ""),
+ (modname ? modname : ""), modsize,
+ (flags.apply ? flags.apply : "" ));
+ }
+
+ /*
+ * What we, at least, requires !
+ */
+ if (flags.node == NULL) {
+ usage(progname);
+ }
+
+ if (!flags.cookiep) {
+ flags.cookie = NULL;
+ }
+
+ /* FIXME decide how many bits etc or leave to connect_xinit? */
+ creation = (time(NULL) % 3) + 1; /* "random" */
+
+ if (flags.hidden == NULL) {
+ /* As default we are c17@gethostname */
+ i = flags.randomp ? (time(NULL) % 997) : 17;
+ /* FIXME allocates to small !!! */
+ flags.hidden = (char *) malloc(3 + 2 ); /* c17 or cXYZ */
+#if defined(VXWORKS)
+ sprintf(flags.hidden, "c%d",
+ i < 0 ? (int) taskIdSelf() : i);
+#else
+ sprintf(flags.hidden, "c%d",
+ i < 0 ? (int) getpid() : i);
+#endif
+ }
+ {
+ /* A name for our hidden node was specified */
+ char h_hostname[EI_MAXHOSTNAMELEN+1];
+ char h_nodename[MAXNODELEN+1];
+ char *h_alivename=flags.hidden;
+ struct in_addr h_ipadr;
+ char* ct;
+
+#ifdef __WIN32__
+ /*
+ * FIXME Extremly ugly, but needed to get ei_gethostbyname() below
+ * to work.
+ */
+ initWinSock();
+#endif
+
+ gethostname(h_hostname, EI_MAXHOSTNAMELEN);
+ if ((hp = ei_gethostbyname(h_hostname)) == 0) {
+ fprintf(stderr,"erl_call: can't resolve hostname %s\n", h_hostname);
+ exit(1);
+ }
+ /* If shortnames cut of the name at first '.' */
+ if (flags.use_long_name == 0 && (ct = strchr(hp->h_name, '.')) != NULL) {
+ *ct = '\0';
+ }
+ strcpy(h_hostname, hp->h_name);
+ memcpy(&h_ipadr.s_addr, *hp->h_addr_list, sizeof(struct in_addr));
+ sprintf(h_nodename, "%s@%s", h_alivename, h_hostname);
+
+ if (ei_connect_xinit(&ec, h_hostname, h_alivename, h_nodename,
+ (Erl_IpAddr)&h_ipadr, flags.cookie,
+ (short) creation) < 0) {
+ fprintf(stderr,"erl_call: can't create C node %s; %d\n",
+ h_nodename, erl_errno);
+ exit(1);
+ }
+
+ }
+ if ((p = strchr((const char *)flags.node, (int) '@')) == 0) {
+ strcpy(host_name, ei_thishostname(&ec));
+ host = host_name;
+ } else {
+ *p = 0;
+ host = p+1;
+ }
+
+ /*
+ * Expand name to a real name (may be ip-address)
+ */
+ /* FIXME better error string */
+ if ((hp = get_hostent(host)) == 0) {
+ fprintf(stderr,"erl_call: can't get_hostent(%s)\n", host);
+ exit(1);
+ }
+ /* If shortnames cut of the name at first '.' */
+ if (flags.use_long_name == 0 && (ct = strchr(hp->h_name, '.')) != NULL) {
+ *ct = '\0';
+ }
+ strcpy(host_name, hp->h_name);
+ sprintf(nodename, "%s@%s", flags.node, host_name);
+
+ /*
+ * Try to connect. Start an Erlang system if the
+ * start option is on and no system is running.
+ */
+ if (flags.startp && !flags.haltp) {
+ fd = do_connect(&ec, nodename, &flags);
+ } else if ((fd = ei_connect(&ec, nodename)) < 0) {
+ /* We failed to connect ourself */
+ /* FIXME do we really know we failed because of node not up? */
+ if (flags.haltp) {
+ exit(0);
+ } else {
+ fprintf(stderr,"erl_call: failed to connect to node %s\n",
+ nodename);
+ exit(1);
+ }
+ }
+
+ /* If we are connected and the halt switch is set */
+ if (fd && flags.haltp) {
+ int i = 0;
+ char *p;
+ ei_x_buff reply;
+
+ ei_encode_empty_list(NULL, &i);
+
+ p = (char *)malloc(i);
+ i = 0; /* Reset */
+
+ ei_encode_empty_list(p, &i);
+
+ ei_x_new_with_version(&reply);
+
+ /* FIXME if fails we want to exit != 0 ? */
+ ei_rpc(&ec, fd, "erlang", "halt", p, i, &reply);
+ free(p);
+ ei_x_free(&reply);
+ exit(0);
+ }
+
+ if (flags.verbosep) {
+ fprintf(stderr,"erl_call: we are now connected to node \"%s\"\n",
+ nodename);
+ }
+
+ /*
+ * Compile the module read from stdin.
+ */
+ if (flags.modp && (modname != NULL)) {
+ char fname[256];
+
+ strcpy(fname, modname);
+ strcat(fname, ".erl");
+
+ /*
+ * ei_format("[~s,~w]", fname, erl_mk_binary(module, modsize));
+ */
+
+ {
+ int i = 0;
+ char *p;
+ ei_x_buff reply;
+
+ ei_encode_list_header(NULL, &i, 2);
+ ei_encode_string(NULL, &i, fname);
+ ei_encode_binary(NULL, &i, module, modsize);
+ ei_encode_empty_list(NULL, &i);
+
+ p = (char *)malloc(i);
+ i = 0; /* Reset */
+
+ ei_encode_list_header(p, &i, 2);
+ ei_encode_string(p, &i, fname);
+ ei_encode_binary(p, &i, module, modsize);
+ ei_encode_empty_list(p, &i);
+
+ ei_x_new_with_version(&reply);
+
+ if (ei_rpc(&ec, fd, "file", "write_file", p, i, &reply) < 0) {
+ free(p);
+ ei_x_free(&reply);
+ fprintf(stderr,"erl_call: can't write to source file %s\n",
+ fname);
+ exit(1);
+ }
+ free(p);
+ ei_x_free(&reply);
+ }
+
+ /* Compile AND load file on other node */
+
+ {
+ int i = 0;
+ char *p;
+ ei_x_buff reply;
+
+ ei_encode_list_header(NULL, &i, 2);
+ ei_encode_atom(NULL, &i, fname);
+ ei_encode_empty_list(NULL, &i);
+ ei_encode_empty_list(NULL, &i);
+
+ p = (char *)malloc(i);
+ i = 0; /* Reset */
+
+ ei_encode_list_header(p, &i, 2);
+ ei_encode_atom(p, &i, fname);
+ ei_encode_empty_list(p, &i);
+ ei_encode_empty_list(p, &i);
+
+ ei_x_new_with_version(&reply);
+
+ /* erl_format("[~a,[]]", modname) */
+
+ if (ei_rpc(&ec, fd, "c", "c", p, i, &reply) < 0) {
+ free(p);
+ ei_x_free(&reply);
+ fprintf(stderr,"erl_call: can't compile file %s\n", fname);
+ }
+ free(p);
+ /* FIXME complete this code
+ FIXME print out error message as term
+ if (!erl_match(erl_format("{ok,_}"), reply)) {
+ fprintf(stderr,"erl_call: compiler errors\n");
+ }
+ */
+ ei_x_free(&reply);
+ }
+
+ }
+ /*
+ * Eval the Erlang functions read from stdin/
+ */
+ if (flags.evalp) {
+ char *evalbuf;
+ int len;
+
+ len = read_stdin(&evalbuf);
+ {
+ int i = 0;
+ char *p;
+ ei_x_buff reply;
+
+ ei_encode_list_header(NULL, &i, 1);
+ ei_encode_binary(NULL, &i, evalbuf, len);
+ ei_encode_empty_list(NULL, &i);
+
+ p = (char *)malloc(i);
+ i = 0; /* Reset */
+
+ ei_encode_list_header(p, &i, 1);
+ ei_encode_binary(p, &i, evalbuf, len);
+ ei_encode_empty_list(p, &i);
+
+ ei_x_new_with_version(&reply);
+
+ /* erl_format("[~w]", erl_mk_binary(evalbuf,len))) */
+
+ if (ei_rpc(&ec, fd, "lib", "eval_str", p, i, &reply) < 0) {
+ fprintf(stderr,"erl_call: evaluating input failed: %s\n",
+ evalbuf);
+ free(p);
+ free(evalbuf); /* Allocated in read_stdin() */
+ ei_x_free(&reply);
+ exit(1);
+ }
+ i = 0;
+ ei_print_term(stdout,reply.buff,&i);
+ free(p);
+ free(evalbuf); /* Allocated in read_stdin() */
+ ei_x_free(&reply);
+ }
+ }
+ /*
+ * Any Erlang call to be made ?
+ */
+ if (flags.apply != NULL) {
+ char *mod,*fun,*args;
+ ei_x_buff e, reply;
+
+ split_apply_string(flags.apply, &mod, &fun, &args);
+ if (flags.verbosep) {
+ fprintf(stderr,"erl_call: module = %s, function = %s, args = %s\n",
+ mod, fun, args);
+ }
+
+ ei_x_new(&e); /* No version to ei_rpc() */
+
+ if (ei_x_format_wo_ver(&e, args) < 0) {
+ /* FIXME no error message and why -1 ? */
+ exit(-1);
+ }
+
+ ei_x_new_with_version(&reply);
+
+ if (ei_rpc(&ec, fd, mod, fun, e.buff, e.index, &reply) < 0) {
+ /* FIXME no error message and why -1 ? */
+ ei_x_free(&e);
+ ei_x_free(&reply);
+ exit(-1);
+ } else {
+ int i = 0;
+ ei_print_term(stdout,reply.buff,&i);
+ ei_x_free(&e);
+ ei_x_free(&reply);
+ }
+ }
+
+ return(0);
+}
+
+
+/***************************************************************************
+ *
+ * XXXXX
+ *
+ ***************************************************************************/
+
+/*
+ * Get host entry (by address or name)
+ */
+/* FIXME: will fail on names like '2fun4you'. */
+static struct hostent* get_hostent(char *host)
+{
+ if (isdigit((int)*host)) {
+ struct in_addr ip_addr;
+ int b1, b2, b3, b4;
+ long addr;
+
+ /* FIXME: Use inet_aton() (or inet_pton() and get v6 for free). */
+ if (sscanf(host, "%d.%d.%d.%d", &b1, &b2, &b3, &b4) != 4) {
+ return NULL;
+ }
+ addr = inet_addr(host);
+ ip_addr.s_addr = htonl(addr);
+
+ return ei_gethostbyaddr((char *)&ip_addr,sizeof(struct in_addr), AF_INET);
+ }
+
+ return ei_gethostbyname(host);
+} /* get_hostent */
+
+
+
+
+/*
+ * This function does only return on success.
+ */
+static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags)
+{
+ int fd;
+ int start_flags;
+ int r;
+
+ 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);
+
+ if ((fd = ei_connect(ec, nodename)) >= 0) {
+ /* success */
+ if (flags->verbosep) {
+ fprintf(stderr,"erl_call: now connected to node %s\n", nodename);
+ }
+ } else {
+ char alive[EI_MAXALIVELEN+1];
+ char *hostname;
+ struct hostent *h;
+ char *cookieargs[3];
+ char **args;
+
+ cookieargs[0] = "-setcookie";
+ cookieargs[1] = flags->cookie;
+ cookieargs[2] = NULL;
+
+ args = (flags->cookie) ? cookieargs : NULL;
+
+ if (!(hostname = strrchr(nodename,'@'))) {
+ return ERL_BADARG;
+ }
+ strncpy(alive,nodename,hostname-nodename);
+ alive[hostname-nodename] = 0x0;
+ hostname++;
+
+ h = ei_gethostbyname(hostname);
+
+
+ if ((r=erl_start_sys(ec,alive,(Erl_IpAddr)(h->h_addr_list[0]),
+ start_flags,flags->script,args)) < 0) {
+ fprintf(stderr,"erl_call: unable to start node, error = %d\n", r);
+ exit(1);
+ }
+
+ if ((fd=ei_connect(ec, nodename)) >= 0) {
+ /* success */
+ if (flags->verbosep) {
+ fprintf(stderr,"erl_call: now connected to node \"%s\"\n",
+ nodename);
+ }
+ } else {
+ /* (failure) */
+ switch (fd) {
+ case ERL_NO_DAEMON:
+ fprintf(stderr,"erl_call: no epmd running\n");
+ exit(1);
+ case ERL_CONNECT_FAIL:
+ fprintf(stderr,"erl_call: connect failed\n");
+ exit(1);
+ case ERL_NO_PORT:
+ fprintf(stderr,"erl_call: node is not running\n");
+ exit(1);
+ case ERL_TIMEOUT:
+ fprintf(stderr,"erl_call: connect timed out\n");
+ exit(1);
+ default:
+ fprintf(stderr,"erl_call: error during connect\n");
+ exit(1);
+ }
+ }
+ }
+
+ return fd;
+} /* do_connect */
+
+#define SKIP_SPACE(s) while(isspace((int)*(s))) (s)++
+#define EAT(s) while (!isspace((int)*(s)) && (*(s) != '\0')) (s)++
+
+static void split_apply_string(char *str,
+ char **mod,
+ char **fun,
+ char **args)
+{
+ char *begin=str;
+ char *start="start";
+ char *empty_list="[]";
+ int len;
+
+ SKIP_SPACE(str);
+ if (*str == '\0') {
+ fprintf(stderr,"erl_call: wrong format of apply string (1)\n");
+ exit(1);
+ }
+
+ EAT(str);
+ len = str-begin;
+ *mod = (char *) calloc(len + 1, sizeof(char));
+ memcpy(*mod, begin, len);
+
+ SKIP_SPACE(str);
+ if (*str == '\0') {
+ *fun = (char *) calloc(strlen(start)+1, sizeof(char));
+ strcpy(*fun, start);
+ *args = (char *) calloc(strlen(empty_list)+1, sizeof(char));
+ strcpy(*args, empty_list);
+ return;
+ }
+ begin = str;
+ EAT(str);
+ len = str-begin;
+ *fun = (char *) calloc(len + 1, sizeof(char));
+ memcpy(*fun, begin, len);
+
+ SKIP_SPACE(str);
+ if (*str == '\0') {
+ *args = (char *) calloc(strlen(empty_list)+1, sizeof(char));
+ strcpy(*args, empty_list);
+ return;
+ }
+
+ *args = (char *) calloc(strlen(str) + 1, sizeof(char));
+ strcpy(*args, str);
+
+ return;
+
+} /* split_apply_string */
+
+
+/*
+ * Read from stdin until EOF is reached.
+ * Allocate the buffer needed.
+ */
+static int read_stdin(char **buf)
+{
+ int bsize = BUFSIZ;
+ int len = 0;
+ int i;
+ char *tmp = (char *) malloc(bsize);
+
+ while (1) {
+ if ((i = read(0, &tmp[len], bsize-len)) < 0) {
+ fprintf(stderr,"erl_call: can't read stdin, errno = %d", errno);
+ exit(1);
+ } else if (i == 0) {
+ break;
+ } else {
+ len += i;
+ if ((len+50) > bsize) {
+ bsize = len * 2;
+ tmp = (char *) realloc(tmp, bsize);
+ } else {
+ continue;
+ }
+ }
+ } /* while */
+ *buf = tmp;
+ return len;
+
+} /* read_stdin */
+
+/*
+ * Get the module from stdin.
+ */
+static int get_module(char **mbuf, char **mname)
+{
+ char *tmp;
+ int len,i;
+
+ len = read_stdin(mbuf);
+ /*
+ * Now, get the module name.
+ */
+ if ((tmp = strstr(*mbuf, "-module(")) != NULL) {
+ char *start;
+ tmp += strlen("-module(");
+ while ((*tmp) == ' ') tmp++; /* eat space */
+ start = tmp;
+ while (1) {
+ if (isalnum((int)*tmp) || (*tmp == '_')) {
+ tmp++;
+ continue;
+ } else {
+ break;
+ }
+ } /* while */
+ i = tmp - start;
+ *mname = (char *) calloc(i+1, sizeof(char));
+ memcpy(*mname, start, i);
+ }
+ free(mbuf); /* Allocated in read_stdin() */
+
+ return len;
+
+} /* get_module */
+
+
+/***************************************************************************
+ *
+ * Different error reporting functions that output usage
+ *
+ ***************************************************************************/
+
+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," (-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," -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");
+ fprintf(stderr," -h specify a name for the erl_call client node\n");
+ fprintf(stderr," -m read and compile Erlang module from stdin\n");
+ fprintf(stderr," -n name of Erlang node, same as -name\n");
+ 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," -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," -v verbose mode, i.e print some information on stderr\n");
+ fprintf(stderr," -x use specified erl start script, default is erl\n");
+}
+
+static void usage_arg(const char *progname, const char *switchname) {
+ fprintf(stderr, "Missing argument(s) for \'%s\'.\n", switchname);
+ usage_noexit(progname);
+ exit(1);
+}
+
+static void usage_error(const char *progname, const char *switchname) {
+ fprintf(stderr, "Illegal argument \'%s\'.\n", switchname);
+ usage_noexit(progname);
+ exit(1);
+}
+
+static void usage(const char *progname) {
+ usage_noexit(progname);
+ exit(0);
+}
+
+
+/***************************************************************************
+ *
+ * OS specific functions
+ *
+ ***************************************************************************/
+
+#ifdef __WIN32__
+/*
+ * FIXME This should not be here. This is a quick fix to make erl_call
+ * work at all on Windows NT.
+ */
+static void initWinSock(void)
+{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+ static int initialized;
+
+ wVersionRequested = MAKEWORD(1, 1);
+ if (!initialized) {
+ initialized = 1;
+ err = WSAStartup(wVersionRequested, &wsaData);
+
+ if (err != 0) {
+ fprintf(stderr,"erl_call: "
+ "Can't initialize windows sockets: %d\n", err);
+ }
+
+ if ( LOBYTE( wsaData.wVersion ) != 1 ||
+ HIBYTE( wsaData.wVersion ) != 1 ) {
+ fprintf(stderr,"erl_call: This version of "
+ "windows sockets not supported\n");
+ WSACleanup();
+ }
+ }
+}
+#endif