diff options
author | Björn-Egil Dahlberg <[email protected]> | 2009-12-15 10:33:33 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-12-15 12:24:17 +0100 |
commit | fe272a8454d2379c2ed5b0f9f04b493574316a8d (patch) | |
tree | 38e09b9529109886886241b03a20f589c3559d04 /lib/erl_interface/test/all_SUITE_data | |
parent | de4639e46760493bad61ae48a5d894001216720e (diff) | |
download | otp-fe272a8454d2379c2ed5b0f9f04b493574316a8d.tar.gz otp-fe272a8454d2379c2ed5b0f9f04b493574316a8d.tar.bz2 otp-fe272a8454d2379c2ed5b0f9f04b493574316a8d.zip |
Include the test suites for erl_interface
Diffstat (limited to 'lib/erl_interface/test/all_SUITE_data')
-rw-r--r-- | lib/erl_interface/test/all_SUITE_data/Makefile.first | 20 | ||||
-rw-r--r-- | lib/erl_interface/test/all_SUITE_data/Makefile.src | 45 | ||||
-rw-r--r-- | lib/erl_interface/test/all_SUITE_data/ei_runner.c | 400 | ||||
-rw-r--r-- | lib/erl_interface/test/all_SUITE_data/ei_runner.h | 61 | ||||
-rw-r--r-- | lib/erl_interface/test/all_SUITE_data/gccifier.c | 317 | ||||
-rwxr-xr-x | lib/erl_interface/test/all_SUITE_data/gccifier.sh | 26 | ||||
-rw-r--r-- | lib/erl_interface/test/all_SUITE_data/init_tc.erl | 101 | ||||
-rw-r--r-- | lib/erl_interface/test/all_SUITE_data/reclaim.h | 151 | ||||
-rw-r--r-- | lib/erl_interface/test/all_SUITE_data/runner.c | 457 | ||||
-rw-r--r-- | lib/erl_interface/test/all_SUITE_data/runner.h | 50 |
10 files changed, 1628 insertions, 0 deletions
diff --git a/lib/erl_interface/test/all_SUITE_data/Makefile.first b/lib/erl_interface/test/all_SUITE_data/Makefile.first new file mode 100644 index 0000000000..b9ce689057 --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/Makefile.first @@ -0,0 +1,20 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-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% +# +all: + erlc -W init_tc.erl diff --git a/lib/erl_interface/test/all_SUITE_data/Makefile.src b/lib/erl_interface/test/all_SUITE_data/Makefile.src new file mode 100644 index 0000000000..9be2360656 --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/Makefile.src @@ -0,0 +1,45 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-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% +# +include @erl_interface_mk_include@@[email protected] + +CC0 = @CC@ +CC = .@DS@gccifier@exe@ -CC"$(CC0)" +CFLAGS0 = @CFLAGS@ -I@erl_interface_include@ +CFLAGS = @EI_CFLAGS@ $(THR_DEFS) -I@erl_interface_include@ +EI_COMMON_OBJS = runner@obj@ ei_runner@obj@ +ALL_OBJS = gccifier@exe@ $(EI_COMMON_OBJS) + +CP=cp +CHMOD=chmod + +all: $(ALL_OBJS) + +@IFEQ@ (@erl_interface_cross_compile@, true) +gccifier@exe@: + $(CP) gccifier.sh gccifier@exe@ + $(CHMOD) a+x gccifier@exe@ +@ELSE@ +gccifier@exe@: gccifier.c + $(CC0) $(CFLAGS0) -o gccifier@exe@ gccifier.c +@ENDIF@ + +clean: + $(RM) $(EI_COMMON_OBJS) + $(RM) init_tc.beam + $(RM) gccifier@exe@ diff --git a/lib/erl_interface/test/all_SUITE_data/ei_runner.c b/lib/erl_interface/test/all_SUITE_data/ei_runner.c new file mode 100644 index 0000000000..205f911e38 --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/ei_runner.c @@ -0,0 +1,400 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-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% + */ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#ifndef __WIN32__ +#include <unistd.h> +#endif +#include <stdarg.h> + +#include "ei_runner.h" + +#ifndef __WIN32__ +#define _O_BINARY 0 +#define _setmode(fd, mode) +#endif + +#define HEADER_SIZE 4 + +static char* progname; /* Name of this program (from argv[0]). */ +static int fd_from_erl; /* File descriptor from Erlang. */ +static int fd_to_erl; /* File descriptor to Erlang. */ + +static int packet_loop(); +static void ensure_buf_big_enough(); +static int readn(); +static void reply(char* buf, unsigned size); +static void dump(); + +void +run_tests(char* argv0, TestCase test_cases[], unsigned number) +{ + int i; + int n; + char* packet; + + progname = argv0; + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); + fd_from_erl = 0; + fd_to_erl = 1; + + packet = read_packet(&n); + + /* + * Dispatch to the appropriate test function. + */ + + i = packet[0] * 256 + packet[1]; + if (i >= number) { + fprintf(stderr, "%s: bad test case number %d", + progname, i); + free(packet); + exit(1); + } else { + (*test_cases[i])(); + free(packet); + } +} + + +/*********************************************************************** + * + * R e a d i n g p a c k e t s + * + ************************************************************************/ + +/* + * Reads an Erlang term. + * + * Only accepts 't' (term) or 'e' (end of test), + * exits program on error + * returns 1 on 'e', 0 on 't' + */ +int get_bin_term(ei_x_buff* x, ei_term* term) +{ + int len, version; + + ei_x_free(x); + x->buff = read_packet(&len); + x->buffsz = len; + x->index = 0; + switch (x->buff[x->index++]) { + case 'e': + return 1; + case 't': + if (ei_decode_version(x->buff, &x->index, &version) < 0 + || ei_decode_ei_term(x->buff, &x->index, term) < 0) { + fail("Failed to decode term"); + exit(0); + } + return 0; + default: + fprintf(stderr, "Garbage received: "); + dump(x->buff, len, 16); + putc('\n', stderr); + fail("C program received garbage"); + exit(1); + } +} + + +/* + * Reads a packet from Erlang. The packet must be a standard {packet, 2} + * packet. This function aborts if any error is detected (including EOF). + * + * Returns: The number of bytes in the packet. + */ + +char *read_packet(int *len) +{ + + unsigned char* io_buf = NULL; /* Buffer for file i/o. */ + int i; + unsigned char header[HEADER_SIZE]; + unsigned packet_length; /* Length of current packet. */ + int bytes_read; + + /* + * Read the packet header. + */ + + bytes_read = readn(fd_from_erl, header, HEADER_SIZE); + + if (bytes_read == 0) { + fprintf(stderr, "%s: Unexpected end of file\n", progname); + exit(1); + } + if (bytes_read != HEADER_SIZE) { + fprintf(stderr, "%s: Failed to read packet header\n", progname); + exit(1); + } + + /* + * Get the length of this packet. + */ + + packet_length = 0; + + for (i = 0; i < HEADER_SIZE; i++) + packet_length = (packet_length << 8) | header[i]; + + if (len) *len=packet_length; /* report length only if caller requested it */ + + if ((io_buf = (char *) malloc(packet_length)) == NULL) { + fprintf(stderr, "%s: insufficient memory for i/o buffer of size %d\n", + progname, packet_length); + exit(1); + } + + /* + * Read the packet itself. + */ + + bytes_read = readn(fd_from_erl, io_buf, packet_length); + if (bytes_read != packet_length) { + fprintf(stderr, "%s: couldn't read packet of length %d\r\n", + progname, packet_length); + free(io_buf); + exit(1); + } + + return io_buf; +} + + +/*********************************************************************** + * S e n d i n g r e p l i e s + * + * The functions below send various types of replies back to Erlang. + * Each reply start with a letter indicating the type of reply. + * + * Reply Translated to on Erlang side + * ----- ---------------------------- + * [$b|Bytes] {bytes, Bytes} + * [$e] eot + * [$f] test_server:fail() + * [$f|Reason] test_server:fail(Reason) + * [$t|EncodedTerm] {term, Term} + * [$N] 'NULL' + * [$m|Message] io:format("~s", [Message]) (otherwise ignored) + * + ***********************************************************************/ + +/* + * This function reports the outcome of a test fail. It is useful if + * you implement a test case entirely in C code. + * + * If the ok argument is zero, a [$f] reply will be sent to the + * Erlang side (causing test_server:fail() to be called); otherwise, + * the atom 'eot' will be sent to Erlang. + * + * If you need to provide more details on a failure, use the fail() function. + */ + +void +do_report(file, line, ok) + char* file; + int line; + int ok; /* Zero if failed; non-zero otherwise. */ +{ + char reason; + /*unsigned long ab; + unsigned long fb;*/ + + reason = ok ? 'e' : 'f'; + + if (!ok) { + do_fail(file, line, "Generic failure"); + } else { + /* release all unallocated blocks */ + /*erl_eterm_release();*/ + /* check mem usage stats */ + /*erl_eterm_statistics(&ab, &fb);*/ + /*if ((ab == 0) && (fb == 0) ) {*/ + reply(&reason, 1); + /*} + else { + char sbuf[128]; + + sprintf(sbuf, "still %lu terms allocated," + " %lu on freelist at end of test", ab, fb); + do_fail(file, line, sbuf); + }*/ + } +} + + +/* + * This function causes a call to test_server:fail(Reason) on the + * Erlang side. + */ + +void do_fail(char* file, int line, char* reason) +{ + char sbuf[2048]; + + sbuf[0] = 'f'; + sprintf(sbuf+1, "%s, line %d: %s", file, line, reason); + reply(sbuf, 1+strlen(sbuf+1)); +} + +/* + * This function sends a message to the Erlang side. + * The message will be written to the test servers log file, + * but will otherwise be completly ignored. + */ + +void message(char* format, ...) +{ + va_list ap; + char sbuf[1024]; + + sbuf[0] = 'm'; + va_start(ap, format); + vsprintf(sbuf+1, format, ap); + va_end(ap); + + reply(sbuf, 1+strlen(sbuf+1)); +} + +/* + * This function sends the given binary term to the Erlang side, + * where it will be received as {term, Term} (prefix 't'). + */ +void send_bin_term(ei_x_buff* x) +{ + ei_x_buff x2; + ei_x_new(&x2); + x2.buff[x2.index++] = 't'; + ei_x_append(&x2, x); + reply(x2.buff, x2.index); + ei_x_free(&x2); +} + +/* + * This function sends a raw buffer of data to the + * Erlang side, where it will be received as {bytes, Bytes} (prefix 'b'). + */ +void send_buffer(char* buf, int size) +{ + char* send_buf; + + send_buf = (char *) malloc(size+1); + send_buf[0] = 'b'; + memcpy(send_buf+1, buf, size); + reply(send_buf, size+1); + free(send_buf); +} + +/*********************************************************************** + * + * P r i v a t e h e l p e r s + * + ***********************************************************************/ + +/* + * Sends a packet back to Erlang. + */ +static void reply(char* reply_buf, unsigned size) +{ + int n; /* Temporary to hold size. */ + int i; /* Loop counter. */ + char* buf; + + + buf = (char *) malloc(size+HEADER_SIZE); + memcpy(buf+HEADER_SIZE, reply_buf, size); + + /* + * Fill the header starting with the least significant byte. + */ + n = size; + for (i = HEADER_SIZE-1; i >= 0; i--) { + buf[i] = (char) n; /* Store least significant byte. */ + n = n >> 8; + } + + size += HEADER_SIZE; + write(fd_to_erl, buf, size); + free(buf); +} + + +/* + * Reads len number of bytes. + */ + +static int +readn(fd, buf, len) + int fd; /* File descriptor to read from. */ + unsigned char *buf; /* Store in this buffer. */ + int len; /* Number of bytes to read. */ +{ + int n; /* Byte count in last read call. */ + int sofar = 0; /* Bytes read so far. */ + + do { + if ((n = read(fd, buf+sofar, len-sofar)) <= 0) + /* error or EOF in read */ + return(n); + sofar += n; + } while (sofar < len); + return sofar; +} + +void +dump(buf, sz, max) + unsigned char* buf; + int sz; + int max; +{ + int i, imax; + char comma[5] = ","; + + if (!sz) + return; + if (sz > max) + imax = max; + else + imax = sz; + + for (i=0; i<imax; i++) { + if (i == imax-1) { + if (sz > max) + strcpy(comma, ",..."); + else + comma[0] = 0; + } + if (isdigit(buf[i])) + fprintf(stderr, "%u%s", (int)(buf[i]), comma); + else { + if (isalpha(buf[i])) { + fprintf(stderr, "%c%s", buf[i], comma); + } + else + fprintf(stderr, "%u%s", (int)(buf[i]), comma); + } + } +} + diff --git a/lib/erl_interface/test/all_SUITE_data/ei_runner.h b/lib/erl_interface/test/all_SUITE_data/ei_runner.h new file mode 100644 index 0000000000..96d6a1cbf7 --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/ei_runner.h @@ -0,0 +1,61 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-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% + */ + +#include "ei.h" + +typedef void (*TestCase)(void); + +#define TESTCASE(name) void name(void) +#define ASIZE(a) (sizeof(a)/sizeof(a[0])) + +void run_tests(char* argv0, TestCase cases[], unsigned number); + +#ifndef _MSC_VER +# define ll(val) (val##LL) +#else /* assume gcc or C99 */ +# define ll(val) (val##i64) +#endif + +#ifndef _MSC_VER +# define ull(val) (val##LL) +#else /* assume gcc or C99 */ +# define ull(val) (val##i64) +#endif + +/* + * Reading. + */ + +int get_bin_term(ei_x_buff* x, ei_term* term); +char *read_packet(int *len); + +/* + * Sending replies. + */ + +#define fail(reason) do_fail(__FILE__, __LINE__, reason) +#define report(ok) do_report(__FILE__, __LINE__, ok) + +void do_report(char* file, int line, int ok); +void do_fail(char* file, int line, char* reason); +void send_buffer(char* buf, int size); +void message(char* format, ...); + +void send_bin_term(ei_x_buff* x); + diff --git a/lib/erl_interface/test/all_SUITE_data/gccifier.c b/lib/erl_interface/test/all_SUITE_data/gccifier.c new file mode 100644 index 0000000000..9f556fc4ed --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/gccifier.c @@ -0,0 +1,317 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2005-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% + * + + */ + +/* + * A compiler wrapper that translate (some) gcc command line arguments + * to the Visual C++ compiler and (of course) the gcc compiler. It also + * makes some changes in the command line arguments when debug compiling. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + + +#if !defined(__WIN32__) +#define USE_EXEC +#include <unistd.h> +#endif + + +#ifdef __WIN32__ +#define EOL "\r\n" +#else +#define EOL "\n" +#endif + +#define ARGS_INCR 20 + +static char *prog; + +typedef struct { + char **vec; + int no; + int ix; + int chars; +} args_t; + +static void +enomem(void) +{ + fprintf(stderr, "%s: Out of memory%s", prog, EOL); + exit(1); +} + +static void +save_arg(args_t *args, char *arg1, ...) +{ + char *carg; + va_list argp; + + va_start(argp, arg1); + carg = arg1; + while (carg) { + if (args->no <= args->ix) { + args->vec = (char **) (args->no + ? realloc((void *) args->vec, + (sizeof(char *) + *(args->no + ARGS_INCR + 1))) + : malloc((sizeof(char *) + *(args->no + ARGS_INCR + 1)))); + if (!args->vec) + enomem(); + args->no += ARGS_INCR; + } + args->vec[args->ix++] = carg; + args->chars += strlen(carg); + carg = va_arg(argp, char *); + } + args->vec[args->ix++] = " "; + args->chars++; + va_end(argp); +} + +static int +is_prefix(char *prfx, char **str) +{ + int i; + for (i = 0; prfx[i] && (*str)[i]; i++) { + if (prfx[i] != (*str)[i]) + return 0; + } + if (!prfx[i]) { + *str = &(*str)[i]; + return 1; + } + return 0; +} + +static void +cpy(char **dst, char *src) +{ + int i; + for (i = 0; src[i]; i++) + (*dst)[i] = src[i]; + *dst = &(*dst)[i]; +} + +typedef enum { + STDLIB_NONE, + STDLIB_MD, + STDLIB_ML, + STDLIB_MT +} stdlib_t; + +int +main(int argc, char *argv[]) +{ + int res; + int i; + size_t cmd_len; + char *cmd; + char *cmd_end; + char *cc = NULL; + args_t args = {0}; + int is_debug = 0; + int is_purify = 0; + int is_quantify = 0; + int is_purecov = 0; +#ifdef __WIN32__ + int is_shared = 0; + stdlib_t stdlib = STDLIB_NONE; + char *shared_flag = ""; + char *stdlib_flag = ""; + int have_link_args = 0; + args_t link_args = {0}; + +#define CHECK_FIRST_LINK_ARG \ + if (!have_link_args) { \ + save_arg(&link_args, "-link", NULL); \ + have_link_args = 1; \ + } +#else /* #ifdef __WIN32__ */ +#define CHECK_FIRST_LINK_ARG +#endif /* #ifdef __WIN32__ */ + + prog = argv[0]; + + + for (i = 1; i < argc; i++) { + char *arg = argv[i]; + if (is_prefix("-CC", &arg)) { + cc = arg; + } + else if (is_prefix("-O", &arg)) { + if (!is_debug) + save_arg(&args, argv[i], NULL); + } + else if (strcmp("-DDEBUG", arg) == 0) { + save_arg(&args, arg, NULL); +#ifdef __WIN32__ + set_debug: +#endif + if (!is_debug) { + int j; + is_debug = 1; +#ifdef __WIN32__ + save_arg(&args, "-Z7", NULL); + CHECK_FIRST_LINK_ARG; + save_arg(&link_args, "-debug", NULL); + save_arg(&link_args, "-pdb:none", NULL); +#endif + for (j = 0; j < args.ix; j++) { + char *tmp_arg = args.vec[j]; + if (is_prefix("-O", &tmp_arg)) + args.vec[j] = ""; + } + } + } + else if (strcmp("-DPURIFY", arg) == 0) { + save_arg(&args, arg, NULL); + is_purify = 1; + } + else if (strcmp("-DQUANTIFY", arg) == 0) { + save_arg(&args, arg, NULL); + is_quantify = 1; + } + else if (strcmp("-DPURECOV", arg) == 0) { + save_arg(&args, arg, NULL); + is_purecov = 1; + } +#ifdef __WIN32__ + else if (strcmp("-g", arg) == 0) { + goto set_debug; + } + else if (strcmp("-MD", arg) == 0) + stdlib = STDLIB_MD; + else if (strcmp("-MDd", arg) == 0) { + stdlib = STDLIB_MD; + goto set_debug; + } + else if (strcmp("-ML", arg) == 0) + stdlib = STDLIB_ML; + else if (strcmp("-MLd", arg) == 0) { + stdlib = STDLIB_ML; + goto set_debug; + } + else if (strcmp("-MT", arg) == 0) + stdlib = STDLIB_MT; + else if (strcmp("-MTd", arg) == 0) { + stdlib = STDLIB_MT; + goto set_debug; + } + else if (strcmp("-shared", arg) == 0 || strcmp("-LD", arg) == 0) + is_shared = 1; + else if (strcmp("-LDd", arg) == 0) { + is_shared = 1; + goto set_debug; + } + else if (strcmp("-Wall", arg) == 0) { + save_arg(&args, "-W3", NULL); + } + else if (is_prefix("-L", &arg)) { + CHECK_FIRST_LINK_ARG; + save_arg(&link_args, "-libpath:", arg, NULL); + } +#endif /* #ifdef __WIN32__ */ + else if (is_prefix("-l", &arg)) { + CHECK_FIRST_LINK_ARG; + if (is_debug && strcmp("ethread", arg) == 0) + arg = "ethread.debug"; + else if (is_purify && strcmp("ethread", arg) == 0) + arg = "ethread.purify"; + else if (is_quantify && strcmp("ethread", arg) == 0) + arg = "ethread.quantify"; + else if (is_purecov && strcmp("ethread", arg) == 0) + arg = "ethread.purecov"; +#ifdef __WIN32__ + else if (strcmp("socket", arg) == 0) + arg = "ws2_32"; + save_arg(&link_args, arg, ".lib", NULL); +#else + save_arg(&args, "-l", arg, NULL); +#endif + } + else + save_arg(&args, argv[i], NULL); + } + + if (!cc || !cc[0]) { + fprintf(stderr, "%s: Missing compulsory -CC flag%s", prog, EOL); + exit(1); + } + + cmd_len = strlen(cc) + 1 + args.chars + 1; + +#ifdef __WIN32__ + if (is_shared) + shared_flag = is_debug ? "-LDd " : "-LD "; + switch (stdlib) { + case STDLIB_MD: stdlib_flag = is_debug ? "-MDd " : "-MD "; break; + case STDLIB_ML: stdlib_flag = is_debug ? "-MLd " : "-ML "; break; + case STDLIB_MT: stdlib_flag = is_debug ? "-MTd " : "-MT "; break; + case STDLIB_NONE: break; + } + + cmd_len += strlen(shared_flag) + strlen(stdlib_flag) + link_args.chars; +#endif + + cmd = (char *) malloc(sizeof(char) * cmd_len); + + if (!cmd) + enomem(); + cmd_end = cmd; + cpy(&cmd_end, cc); + cpy(&cmd_end, " "); +#ifdef __WIN32__ + cpy(&cmd_end, stdlib_flag); + cpy(&cmd_end, shared_flag); +#endif + for (i = 0; i < args.ix; i++) + cpy(&cmd_end, args.vec[i]); +#ifdef __WIN32__ + for (i = 0; i < link_args.ix; i++) + cpy(&cmd_end, link_args.vec[i]); +#endif + *cmd_end = '\0'; + + printf("==> %s%s", cmd, EOL); + fflush(stdout); + +#ifdef USE_EXEC + (void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL); + perror(NULL); + res = 1; +#else + res = system(cmd); +#endif + + free((void *) args.vec); +#ifdef __WIN32__ + free((void *) link_args.vec); +#endif + free((void *) cmd); + + if (res < 0) + res = 1; + return res; +} diff --git a/lib/erl_interface/test/all_SUITE_data/gccifier.sh b/lib/erl_interface/test/all_SUITE_data/gccifier.sh new file mode 100755 index 0000000000..42253213b1 --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/gccifier.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2005-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% +# + +CC=`echo "$1" | sed -e "s/-CC//"` +shift +echo "->" +echo "$CC $*" +$CC $* +echo "" diff --git a/lib/erl_interface/test/all_SUITE_data/init_tc.erl b/lib/erl_interface/test/all_SUITE_data/init_tc.erl new file mode 100644 index 0000000000..8157d590fc --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/init_tc.erl @@ -0,0 +1,101 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-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% +%% + +%% +-module(init_tc). + +-export([run/1]). + +%% The argument should be a list of filenames (atoms), without extension +%% A .c extension is assumed. +%% + +run([Name|Rest]) -> + case catch run1(atom_to_list(Name)) of + {'EXIT', Reason} -> + io:format("Failed: ~p~n", [Reason]), + halt(1); + _Other -> + run(Rest) + end; +run([]) -> + ok. + +run1(Name) -> + CFile = Name ++ ".c", + {ok, Bin} = file:read_file(CFile), + String = binary_to_list(Bin), + + %% This ConstPart stuff is because you can't retrieve part of a match. + %% Long live Perl! + + ConstPart = "\nTESTCASE\\(", + ConstPartLen = 10, + {match, Matches} = regexp:matches(String, ConstPart++"[_a-zA-Z]*"), + Cases = get_names(Matches, ConstPartLen, Bin, []), + generate(Name, Cases). + +get_names([{Start, Length}|Rest], Skip, Bin, Result) -> + Name = binary_to_list(Bin, Start+Skip, Start+Length-1), + get_names(Rest, Skip, Bin, [Name|Result]); +get_names([], _Skip, _Bin, Result) -> + lists:reverse(Result). + +generate(TcName, Cases) -> + Hrl = TcName ++ "_cases.hrl", + {ok, HrlFile} = file:open(Hrl, write), + {ok, Dir} = file:get_cwd(), + generate_hrl(Cases, HrlFile, {filename:join(Dir, TcName), 0}), + file:close(HrlFile), + C = TcName ++ "_decl.c", + {ok, CFile} = file:open(C, write), + generate_c(Cases, CFile, TcName), + file:close(CFile). + +generate_hrl([Case|Rest], File, {Name, Number}) -> + io:format(File, "-define(~s, {\"~s\", ~w}).~n", [Case, Name, Number]), + generate_hrl(Rest, File, {Name, Number+1}); +generate_hrl([], _, _) -> + ok. + +generate_c(Cases, File, TcName) -> + E= case lists:prefix("ei_", TcName) of + true -> "ei_"; + false -> "" + end, + io:format(File, "#include \"~srunner.h\"\n", [E]), + lists:foreach( + fun(Case) -> + io:format(File, "extern void ~s(void);~n", + [Case]) end, + Cases), + io:format(File, "~nstatic TestCase test_cases[] = {~n", []), + lists:foreach(fun(Case) -> io:format(File, " ~s,~n", [Case]) end, Cases), + io:format(File, "~s", + [["};\n\n", + "#ifdef VXWORKS\n", + "int ", TcName, "(int argc, char* argv[])\n", + "#else\n", + "int main(int argc, char* argv[])\n", + "#endif\n", + "{\n", + " run_tests(argv[0], test_cases, ", + "sizeof(test_cases)/sizeof(test_cases[0]));\n", + " return 0;\n", + "}\n"]]). diff --git a/lib/erl_interface/test/all_SUITE_data/reclaim.h b/lib/erl_interface/test/all_SUITE_data/reclaim.h new file mode 100644 index 0000000000..00fdfc38dc --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/reclaim.h @@ -0,0 +1,151 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-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% + * + + */ +#ifndef _RECLAIM_H +#define _RECLAIM_H + + +/* The Erlang release for VxWorks includes a simple mechanism for + "resource reclamation" at task exit - it allows replacement of the + functions that open/close "files" and malloc/free memory with versions + that keep track, to be able to "reclaim" file descriptors and memory + when a task exits (regardless of *how* it exits). + + The interface to this mechanism is made available via this file, + with the following caveats: + + - The interface may change (or perhaps even be removed, though that + isn't likely until VxWorks itself provides similar functionality) + in future releases - i.e. you must always use the version of this + file that comes with the Erlang release you are using. + + - Disaster is guaranteed if you use the mechanism incorrectly (see + below for the correct way), e.g. allocate memory with the "tracking" + version of malloc() and free it with the "standard" version of free(). + + - The mechanism (of course) incurs some performance penalty - thus + for a simple program you may be better off with careful programming, + making sure that you do whatever close()/free()/etc calls that are + appropriate at all exit points (though if you need to guard against + taskDelete() etc, things get messy...). + + To use the mechanism, simply program your application normally, i.e. + use open()/close()/malloc()/free() etc as usual, but #include this + file before any usage of the relevant functions. NOTE: To avoid the + "disaster" mentioned above, you *must* #include it in *all* (or none) + of the files that manipulate a particular file descriptor, allocated + memory area, etc. + + Before any task that uses this utility is loaded (which includes the + erlang emulator), the reclaim.o object file has to be loaded and + the function reclaim_init() has to be called. reclaim_init should be called + only _ONCE_ in a systems lifetime and has only a primitive guard + against multiple calls (i.e. a global variable is checked). Therefore + the initialization should occur either in the start script of the system + or (even better) in the usrInit() part of system initialization. The + object file itself should be loaded only once, so linking it with the + kernel is a good idea, linking with each application is an extremely bad + dito. Make really sure that it's loaded _before_ any application that + uses it if You want to load it in the startup script. + + If You dont want to have #define's for the posix/stdio names + of the file/memory operations (i.e. no #define malloc save_malloc etc), + #define RECLAIM_NO_ALIAS in Your source before reclaim.h is included. +*/ + +#include <vxWorks.h> /* STATUS, size_t */ +#include <sockLib.h> /* struct sockaddr */ +#include <stdio.h> /* FILE */ + +#if defined(__STDC__) +#define _RECLAIM_DECL_FUN(RetType, FunName, ParamList) \ +extern RetType FunName##ParamList +#define _RECLAIM_VOID_PTR void * +#define _RECLAIM_VOID_PARAM void +#define _RECLAIM_VOID_RETURN void +#elif defined(__cplusplus) +#define _RECLAIM_DECL_FUN(RetType, FunName, ParamList) \ +extern "C" RetType FunName##ParamList +#define _RECLAIM_VOID_PTR void * +#define _RECLAIM_VOID_PARAM +#define _RECLAIM_VOID_RETURN void +#else +#define _RECLAIM_DECL_FUN(RetType, FunName, Ignore) extern RetType FunName() +#define DECLARE_FUNCTION_TYPE(RetType, Type, PList) typedef RetType (* Type)() +#define _RECLAIM_VOID_PTR char * +#define _RECLAIM_VOID_PARAM +#define _RECLAIM_VOID_RETURN +#endif /* __STDC__ / __cplusplus */ + +/* Initialize the facility, on a per system basis. */ +_RECLAIM_DECL_FUN(STATUS, reclaim_init, (_RECLAIM_VOID_PARAM)); + +/* File descriptor operations */ +_RECLAIM_DECL_FUN(int,save_open,(char *, int, ...)); +_RECLAIM_DECL_FUN(int,save_creat,(char *, int)); +_RECLAIM_DECL_FUN(int,save_socket,(int, int, int)); +_RECLAIM_DECL_FUN(int,save_accept,(int, struct sockaddr *, int *)); +_RECLAIM_DECL_FUN(int,save_close,(int)); +/* Interface to add an fd to what's reclaimed even though it's not open with + one of the above functions */ +_RECLAIM_DECL_FUN(_RECLAIM_VOID_RETURN, save_fd, (int fd)); +#ifndef RECLAIM_NO_ALIAS +#define open save_open +#define creat save_creat +#define socket save_socket +#define accept save_accept +#define close save_close +#endif +/* Stdio file operations */ +_RECLAIM_DECL_FUN(FILE *, save_fopen, (char *, char *)); +_RECLAIM_DECL_FUN(FILE *, save_fdopen, (int, char *)); +_RECLAIM_DECL_FUN(FILE *, save_freopen, (char *, char *, FILE *)); +_RECLAIM_DECL_FUN(int, save_fclose, (FILE *)); +/* XXX Should do opendir/closedir too... */ +#ifndef RECLAIM_NO_ALIAS +#define fopen save_fopen +#define fdopen save_fdopen +#define freopen save_freopen +#define fclose save_fclose +#endif +/* Memory allocation */ +_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, save_malloc, (size_t)); +_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, save_calloc, (size_t, size_t)); +_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, save_realloc, + (_RECLAIM_VOID_PTR, size_t)); +_RECLAIM_DECL_FUN(void, save_free, (_RECLAIM_VOID_PTR)); +_RECLAIM_DECL_FUN(void, save_cfree, (_RECLAIM_VOID_PTR)); +#ifndef RECLAIM_NO_ALIAS +#define malloc save_malloc +#define calloc save_calloc +#define realloc save_realloc +#define free save_free +#define cfree save_cfree +#endif +/* Generic interfaces to malloc etc... */ +_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, plain_malloc, (size_t)); +_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, plain_realloc, + (_RECLAIM_VOID_PTR, size_t)); +_RECLAIM_DECL_FUN(void, plain_free, (_RECLAIM_VOID_PTR)); +#endif /* _RECLAIM_H */ + + + + diff --git a/lib/erl_interface/test/all_SUITE_data/runner.c b/lib/erl_interface/test/all_SUITE_data/runner.c new file mode 100644 index 0000000000..24df0f5f40 --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/runner.c @@ -0,0 +1,457 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-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% + */ + +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#ifndef __WIN32__ +#include <unistd.h> +#endif +#include <stdarg.h> + +#include "runner.h" + +#ifndef __WIN32__ +#define _O_BINARY 0 +#define _setmode(fd, mode) +#endif + +#define HEADER_SIZE 4 + +static char* progname; /* Name of this program (from argv[0]). */ +static int fd_from_erl; /* File descriptor from Erlang. */ +static int fd_to_erl; /* File descriptor to Erlang. */ + +static int packet_loop(); +static void ensure_buf_big_enough(); +static int readn(); +static void reply(char* buf, unsigned size); +static void dump(); + +void +run_tests(char* argv0, TestCase test_cases[], unsigned number) +{ + int i; + int n; + char* packet; + + progname = argv0; + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); + fd_from_erl = 0; + fd_to_erl = 1; + + packet = read_packet(&n); + + /* + * Dispatch to the appropriate test function. + */ + + i = packet[0] * 256 + packet[1]; + if (i >= number) { + fprintf(stderr, "%s: bad test case number %d", + progname, i); + free(packet); + exit(1); + } else { + (*test_cases[i])(); + free(packet); + } +} + + +/*********************************************************************** + * + * R e a d i n g p a c k e t s + * + ************************************************************************/ + +/* + * Reads an Erlang term. + * + * Returns: A pointer to a term (an ETERM structure) if there was + * at term available, or a NULL pointer if there was an 'eot' (end-of-test) + * packet. Aborts if anything else received. + */ + +ETERM* +get_term(void) +{ + char* encoded; + ETERM* term; + int n; + + encoded = read_packet(&n); + + switch (encoded[0]) { + case 'e': + free(encoded); + return NULL; + case 't': + term = erl_decode(encoded+1); + free(encoded); + if (term == NULL) { + fail("Failed to decode term"); + exit(0); + } + return term; + default: + fprintf(stderr, "Garbage received: "); + dump(encoded, n, 16); + putc('\n', stderr); + fail("C program received garbage"); + free(encoded); + exit(1); + } +} + + +/* + * Reads a packet from Erlang. The packet must be a standard {packet, 2} + * packet. This function aborts if any error is detected (including EOF). + * + * Returns: The number of bytes in the packet. + */ + +char *read_packet(int *len) +{ + + unsigned char* io_buf = NULL; /* Buffer for file i/o. */ + int i; + unsigned char header[HEADER_SIZE]; + unsigned packet_length; /* Length of current packet. */ + int bytes_read; + + /* + * Read the packet header. + */ + + bytes_read = readn(fd_from_erl, header, HEADER_SIZE); + + if (bytes_read == 0) { + fprintf(stderr, "%s: Unexpected end of file\n", progname); + exit(1); + } + if (bytes_read != HEADER_SIZE) { + fprintf(stderr, "%s: Failed to read packet header\n", progname); + exit(1); + } + + /* + * Get the length of this packet. + */ + + packet_length = 0; + + for (i = 0; i < HEADER_SIZE; i++) + packet_length = (packet_length << 8) | header[i]; + + if (len) *len=packet_length; /* report length only if caller requested it */ + + if ((io_buf = (char *) malloc(packet_length)) == NULL) { + fprintf(stderr, "%s: insufficient memory for i/o buffer of size %d\n", + progname, packet_length); + exit(1); + } + + /* + * Read the packet itself. + */ + + bytes_read = readn(fd_from_erl, io_buf, packet_length); + if (bytes_read != packet_length) { + fprintf(stderr, "%s: couldn't read packet of length %d\r\n", + progname, packet_length); + free(io_buf); + exit(1); + } + + return io_buf; +} + + +/*********************************************************************** + * S e n d i n g r e p l i e s + * + * The functions below send various types of replies back to Erlang. + * Each reply start with a letter indicating the type of reply. + * + * Reply Translated to on Erlang side + * ----- ---------------------------- + * [$b|Bytes] {bytes, Bytes} + * [$e] eot + * [$f] test_server:fail() + * [$f|Reason] test_server:fail(Reason) + * [$t|EncodedTerm] {term, Term} + * [$N] 'NULL' + * [$m|Message] io:format("~s", [Message]) (otherwise ignored) + * + ***********************************************************************/ + +/* + * This function reports the outcome of a test fail. It is useful if + * you implement a test case entirely in C code. + * + * If the ok argument is zero, a [$f] reply will be sent to the + * Erlang side (causing test_server:fail() to be called); otherwise, + * the atom 'eot' will be sent to Erlang. + * + * If you need to provide more details on a failure, use the fail() function. + */ + +void +do_report(file, line, ok) + char* file; + int line; + int ok; /* Zero if failed; non-zero otherwise. */ +{ + char reason; + unsigned long ab; + unsigned long fb; + + reason = ok ? 'e' : 'f'; + + if (!ok) { + do_fail(file, line, "Generic failure"); + } else { + /* release all unallocated blocks */ + erl_eterm_release(); + /* check mem usage stats */ + erl_eterm_statistics(&ab, &fb); + if ((ab == 0) && (fb == 0) ) { + reply(&reason, 1); + } + else { + char sbuf[128]; + + sprintf(sbuf, "still %lu terms allocated," + " %lu on freelist at end of test", ab, fb); + do_fail(file, line, sbuf); + } + } +} + + +/* + * This function causes a call to test_server:fail(Reason) on the + * Erlang side. + */ + +void +do_fail(char* file, int line, char* reason) +{ + char sbuf[2048]; + + sbuf[0] = 'f'; + sprintf(sbuf+1, "%s, line %d: %s", file, line, reason); + reply(sbuf, 1+strlen(sbuf+1)); +} + +/* + * This function sends a message to the Erlang side. + * The message will be written to the test servers log file, + * but will otherwise be completly ignored. + */ + +void +message(char* format, ...) +{ + va_list ap; + char sbuf[1024]; + + sbuf[0] = 'm'; + va_start(ap, format); + vsprintf(sbuf+1, format, ap); + va_end(ap); + + reply(sbuf, 1+strlen(sbuf+1)); +} + +/* + * This function sends the given term to the Erlang side, + * where it will be received as {term, Term}. + * + * If the given pointer is NULL (indicating an invalid term), + * the result on the Erlang side will be the atom 'NULL'. + * + * After sending the term, this function frees the term by + * calling erl_free_term(). + */ + +void +send_term(term) + ETERM* term; /* Term to be sent to Erlang side. */ +{ + char encoded[64*1024]; + int n; + + if (term == NULL) { + encoded[0] = 'N'; + n = 1; + } else { + encoded[0] = 't'; + n = 1 + erl_encode(term, encoded+1); + erl_free_term(term); + } + reply(encoded, n); +} + +#if 0 + +/* Seriously broken!!! */ + +void +send_bin_term(x_ei_buff* x) +{ + x_ei_buff x2; + x_ei_new(&x2); + x2.buff[x2.index++] = 't'; + x_ei_append(&x2, x); + reply(x2.buff, x2.index); + free(x2.buff); +} +#endif + +/* + * This function sends a raw buffer of data to the + * Erlang side, where it will be received as {bytes, Bytes}. + */ + +void +send_buffer(buf, size) + char* buf; /* Buffer with bytes to send to Erlang. */ + int size; /* Size of data to send to Erlang. */ +{ + char* send_buf; + + send_buf = (char *) malloc(size+1); + send_buf[0] = 'b'; + memcpy(send_buf+1, buf, size); + reply(send_buf, size+1); + free(send_buf); +} + +/*********************************************************************** + * + * P r i v a t e h e l p e r s + * + ***********************************************************************/ + +/* + * Sends a packet back to Erlang. + */ + +static void +reply(reply_buf, size) + char* reply_buf; /* Buffer with reply. */ + unsigned size; /* Size of reply. */ +{ + int n; /* Temporary to hold size. */ + int i; /* Loop counter. */ + char* buf; + + + buf = (char *) malloc(size+HEADER_SIZE); + memcpy(buf+HEADER_SIZE, reply_buf, size); + + /* + * Fill the header starting with the least significant byte. + */ + + n = size; + for (i = HEADER_SIZE-1; i >= 0; i--) { + buf[i] = (char) n; /* Store least significant byte. */ + n = n >> 8; + } + + size += HEADER_SIZE; +/* + fprintf(stderr, "\r\nReply size: %u\r\n", + (unsigned)buf[0] << 8 + (unsigned)buf[1]); + + for (i = 0; i < size; i++) { + fprintf(stderr,"%u %c\r\n",buf[i],buf[i]); + } + + fprintf(stderr, "\r\n"); +*/ + write(fd_to_erl, buf, size); + free(buf); +} + + +/* + * Reads len number of bytes. + */ + +static int +readn(fd, buf, len) + int fd; /* File descriptor to read from. */ + unsigned char *buf; /* Store in this buffer. */ + int len; /* Number of bytes to read. */ +{ + int n; /* Byte count in last read call. */ + int sofar = 0; /* Bytes read so far. */ + + do { + if ((n = read(fd, buf+sofar, len-sofar)) <= 0) + /* error or EOF in read */ + return(n); + sofar += n; + } while (sofar < len); + return sofar; +} + +void +dump(buf, sz, max) + unsigned char* buf; + int sz; + int max; +{ + int i, imax; + char comma[5] = ","; + + if (!sz) + return; + if (sz > max) + imax = max; + else + imax = sz; + + for (i=0; i<imax; i++) { + if (i == imax-1) { + if (sz > max) + strcpy(comma, ",..."); + else + comma[0] = 0; + } + if (isdigit(buf[i])) + fprintf(stderr, "%u%s", (int)(buf[i]), comma); + else { + if (isalpha(buf[i])) { + fprintf(stderr, "%c%s", buf[i], comma); + } + else + fprintf(stderr, "%u%s", (int)(buf[i]), comma); + } + } +} + diff --git a/lib/erl_interface/test/all_SUITE_data/runner.h b/lib/erl_interface/test/all_SUITE_data/runner.h new file mode 100644 index 0000000000..fb29d5166d --- /dev/null +++ b/lib/erl_interface/test/all_SUITE_data/runner.h @@ -0,0 +1,50 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-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% + */ + +#include "erl_interface.h" + +typedef void (*TestCase)(void); + +#define TESTCASE(name) void name(void) +#define ASIZE(a) (sizeof(a)/sizeof(a[0])) + +void run_tests(char* argv0, TestCase cases[], unsigned number); + +/* + * Reading. + */ + +ETERM* get_term(void); +char *read_packet(int *len); + +/* + * Sending replies. + */ + +#define fail(reason) do_fail(__FILE__, __LINE__, reason) +#define report(ok) do_report(__FILE__, __LINE__, ok) + +void do_report(char* file, int line, int ok); +void do_fail(char* file, int line, char* reason); +void send_term(ETERM* term); +void send_buffer(char* buf, int size); +void message(char* format, ...); + +void send_bin_term(ei_x_buff* x); + |