#line 982 "../../src/builtin/snarf.m4"
/* -*- buffer-read-only: t -*- vi: set ro:
   THIS FILE IS GENERATED AUTOMATICALLY.  PLEASE DO NOT EDIT.
*/
#line 982
#ifdef HAVE_CONFIG_H
#line 982
# include <config.h>
#line 982
#endif
#line 982
#include <sys/types.h>
#line 982

#line 982
#include "mailfromd.h"
#line 982
#include "prog.h"
#line 982
#include "builtin.h"
#line 982

#line 182 "io.bi"
static mu_debug_handle_t debug_handle;
#line 982 "../../src/builtin/snarf.m4"

#line 1022 "../../src/builtin/snarf.m4"

/* End of snarf.m4 */
#line 1 "io.bi"
/* This file is part of Mailfromd.             -*- c -*-
   Copyright (C) 2006-2022 Sergey Poznyakoff

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */



#include <mflib/status.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "global.h"
#include "msg.h"

static size_t nstreams = MAX_IOSTREAMS;

static struct mu_cfg_param io_cfg_param[] = {
	{ "max-streams", mu_c_size, &nstreams, 0, NULL,
	  N_("Maximum number of stream descriptors.") },
	{ NULL }
};

struct io_stream {
	char *name;
	int fd[2];
	pid_t pid;
	char *buf;
	size_t bufsize;
	int (*shutdown)(struct io_stream *, int what);
	void (*cleanup)(void*);
	void *cleanup_data;
	char *delim;
};

#define IFD(s) ((s).fd[0])
#define OFD(s) ((s).fd[1] == -1 ? (s).fd[0] : (s).fd[1])

static void
flush_stream(struct io_stream *str)
{
	/*FIXME*/
}

static void
close_stream(struct io_stream *str)
{
	if (OFD(*str) == -1)
		return;
	flush_stream(str);
	close(OFD(*str));
	if (IFD(*str) != -1)
		close(IFD(*str));
	if (str->pid) {
		int status;
		waitpid(str->pid, &status, 0);
	}
	str->fd[0] = -1;
	str->fd[1] = -1;
	str->pid = 0;
	if (str->cleanup)
		str->cleanup(str->cleanup_data);
	str->cleanup = NULL;
	str->cleanup_data = NULL;
	if (str->name) {
		free(str->name);
		str->name = NULL;
	}
	if (str->delim) {
		free(str->delim);
		str->delim = NULL;
	}
}

/* Read bytes from the stream STR into its buffer, until
   DELIM is encountered. Return number of bytes read. */
static int
read_stream_delim(struct io_stream *str, char *delim)
{
	int fd = IFD(*str);
	size_t i = 0;
	int rc;
	size_t delim_len = strlen(delim);
	
	for (;;) {
		if (str->bufsize == i) {
			if (str->bufsize == 0) 
				str->bufsize = 16;
			str->buf = mu_2nrealloc(str->buf, &str->bufsize,
					      sizeof str->buf[1]);
		}
		rc = read(fd, str->buf + i, 1);
		if (rc == -1)
			return -1;
		else if (rc == 0) {
			if (i > 0)
				str->buf[i] = 0;	
			break;
		}
		i++;
		if (i >= delim_len &&
		    memcmp(str->buf + i - delim_len, delim, delim_len) == 0) {
			str->buf[i - delim_len] = 0;
			break;
		}
	}
	return i;
}

#define REDIRECT_STDIN_P(f) ((f) & (O_WRONLY|O_RDWR))
#define REDIRECT_STDOUT_P(f) (!((f) & O_WRONLY))

#define STDERR_SHUT        0
#define STDERR_NULL        1
#define STDERR_LOG         2
#define STDERR_FILE        3
#define STDERR_FILE_APPEND 4

#define LOG_TAG_PFX "mailfromd:"
#define LOG_TAG_PFX_LEN (sizeof(LOG_TAG_PFX)-1)

static void
stderr_to_log(char *arg, const char *cmd)
{
	int p[2];
	pid_t pid;
	
	if (pipe(p)) {
		mu_error(_("pipe failed: %s"), mu_strerror(errno));
		close(2);
		return;
	}

	pid = fork();

	if (pid == (pid_t) -1) {
		mu_error(_("fork failed: %s"), mu_strerror(errno));
		close(p[0]);
		close(p[1]);
		close(2);
		return;
	}
	
	/* Child */
	if (pid == 0) {
		FILE *fp;
		fd_set fdset;
		size_t len;
		char buf[1024];
		char *tag;
		int fac = mu_log_facility, pri = LOG_ERR;
		
		if (arg) {
			char *p = strchr(arg, '.');

			if (p)
				*p++ = 0;
			if (mu_string_to_syslog_facility(arg, &fac)) {
				mu_error(_("unknown syslog facility (%s), "
					   "redirecting stderr to %s"),
					 arg,
					 mu_syslog_facility_to_string(fac));
			}
			
			if (p && mu_string_to_syslog_priority(p, &pri)) {
				mu_error(_("unknown syslog priority (%s), "
					   "redirecting stderr to %s"),
					 arg,
					 mu_syslog_priority_to_string(pri));
			}
		}
		
#line 182 "io.bi"

#line 182
mu_debug(debug_handle, MU_DEBUG_TRACE2,("redirecting stderr to syslog %s.%s",
		           mu_syslog_facility_to_string(fac),
		           mu_syslog_priority_to_string(pri)));
#line 186
		
		len = strcspn(cmd, " \t");
		tag = malloc(LOG_TAG_PFX_LEN + len + 1);
		if (!tag)
			tag = (char*) cmd;
		else {
			strcpy(tag, LOG_TAG_PFX);
			memcpy(tag + LOG_TAG_PFX_LEN, cmd, len);
			tag[LOG_TAG_PFX_LEN + len] = 0;
		}
		mf_proctitle_format("%s redirector", cmd);

		FD_ZERO(&fdset);
		FD_SET(p[0], &fdset);
		logger_fdset(&fdset);
		close_fds_except(&fdset);

		fp = fdopen(p[0], "r");
		logger_open();
		while (fgets(buf, sizeof(buf), fp))
			syslog(pri, "%s", buf);
		exit(0);
	}

	/* Parent */
	close(p[0]);
	dup2(p[1], 2);
	close(p[1]);
}
	
static void
stderr_handler(int mode, char *arg, const char *cmd)
{
	int fd;
	int append = O_TRUNC;
	
	switch (mode) {
	case STDERR_SHUT:
		close(2);
		break;

	case STDERR_NULL:
		arg = "/dev/null";
	case STDERR_FILE_APPEND:
		append = O_APPEND;
	case STDERR_FILE:
		if (!arg || !*arg) {
			close(2);
			break;
		}
		
#line 236

#line 236
mu_debug(debug_handle, MU_DEBUG_TRACE2,("redirecting stderr to %s", arg));
		fd = open(arg, O_CREAT|O_WRONLY|append, 0644);
		if (fd < 0) {
			mu_error(_("cannot open file %s for appending: %s"),
				 arg, mu_strerror(errno));
			close(2);
			return;
		}
		if (fd != 2) {
			dup2(fd, 2);
			close(fd);
		}
		break;

	case STDERR_LOG:
		stderr_to_log(arg, cmd);
	}
}

static void
parse_stderr_redirect(const char **pcmd, int *perr, char **parg)
{
	int err;
	size_t len;
	char *arg;
	const char *cmdline = *pcmd;
	
	while (*cmdline && mu_isspace(*cmdline))
		cmdline++;
	if (strncmp(cmdline, "2>file:", 7) == 0) {
		cmdline += 7;
		err = STDERR_FILE;
	} else if (strncmp(cmdline, "2>>file:", 8) == 0) {
		cmdline += 8;
		err = STDERR_FILE_APPEND;
	} else if (strncmp(cmdline, "2>null:", 7) == 0) {
		cmdline += 7;
		err = STDERR_NULL;
	} else if (strncmp(cmdline, "2>syslog:", 9) == 0) {
		cmdline += 9;
		err = STDERR_LOG;
	} else
		return;

	len = strcspn(cmdline, " \t");
	if (len > 0 && cmdline[len-1] == 0)
		return;
	if (len == 0)
		arg = NULL;
	else {
		arg = malloc(len + 1);
		if (!arg)
			return;
		memcpy(arg, cmdline, len);
		arg[len] = 0;
	}

	*pcmd = cmdline + len;
	*perr = err;
	*parg = arg;
}


static int
open_program_stream_ioe(eval_environ_t env,
			struct io_stream *str, const char *cmdline,
			int flags,
			int ioe[2])
{
	int rightp[2], leftp[2];
	int rc = 0;
	pid_t pid;
	int err = STDERR_SHUT;
	char *arg = NULL;
	struct mu_wordsplit ws;
	
	parse_stderr_redirect(&cmdline, &err, &arg);
	while (*cmdline && (*cmdline == ' ' || *cmdline == '\t'))
		cmdline++;
	
	if (REDIRECT_STDIN_P(flags)) {
		if (pipe(leftp)) {
			mu_diag_funcall(MU_DIAG_ERROR, "pipe", "leftp",
					errno);
			free(arg);
			(
#line 321
	env_throw_bi(env, mfe_failure, NULL, "pipe failed")
#line 321
);
		}
	}
	
	if (REDIRECT_STDOUT_P(flags)) {
		if (pipe(rightp)) {
			mu_diag_funcall(MU_DIAG_ERROR, "pipe", "rightp",
					errno);
			free(arg);
			if (REDIRECT_STDIN_P(flags)) {
				close(leftp[0]);
				close(leftp[1]);
			}
		}
	}
	
	switch (pid = fork()) {
		/* The child branch.  */
	case 0:
		/* attach the pipes */

		/* Right-end */
		if (REDIRECT_STDOUT_P(flags)) {
			if (rightp[1] != 1)
				dup2(rightp[1], 1);
		} else if (ioe && ioe[1] != -1 && ioe[1] != 1) {
			dup2(ioe[1], 1);
		}

		/* Left-end */
		if (REDIRECT_STDIN_P(flags)) {
			if (leftp[0] != 0)
				dup2(leftp[0], 0);
		} else if (ioe && ioe[0] != -1 && ioe[0] != 0) {
			dup2(ioe[0], 0);
		}

		if (ioe && ioe[2] != -1 && ioe[2] != 2)
			dup2(ioe[2], 2);
		else
			stderr_handler(err, arg, cmdline);
		
		/* Close unneeded descriptors */
		close_fds_above(2);

		
#line 366

#line 366
mu_debug(debug_handle, MU_DEBUG_TRACE3,("running %s", cmdline));
		if (mu_wordsplit(cmdline, &ws,
				 MU_WRDSF_DEFFLAGS & ~MU_WRDSF_CESCAPES)) {
			mu_error(_("cannot parse command line %s: %s"),
				 cmdline, mu_wordsplit_strerror(&ws));
			exit(127);
		}
		execvp(ws.ws_wordv[0], ws.ws_wordv);
		mu_error(_("cannot run %s: %s"),
			 cmdline, mu_strerror(errno));
		exit(127);
		/********************/

		/* Parent branches: */
	case -1:
		/* Fork has failed */
		/* Restore things */
		rc = errno;
		if (REDIRECT_STDOUT_P(flags)) {
			close(rightp[0]);
			close(rightp[1]);
		}
		if (REDIRECT_STDIN_P(flags)) {
			close(leftp[0]);
			close(leftp[1]);
		}
		break;
		
	default:
		str->pid = pid;
		if (REDIRECT_STDOUT_P(flags)) {
			str->fd[0] = rightp[0];
			close(rightp[1]);
		} else
			str->fd[0] = -1;

		if (REDIRECT_STDIN_P(flags)) {
			str->fd[1] = leftp[1];
			close(leftp[0]);
		} else
			str->fd[1] = -1;
	}
	free(arg);
	return rc;
}

static int
open_program_stream(eval_environ_t env,
		    struct io_stream *str, const char *cmdline,
		    int flags)
{
	return open_program_stream_ioe(env, str, cmdline, flags, NULL);
}

static int
open_file_stream(eval_environ_t env,
		 struct io_stream *str, const char *file, int flags)
{
	str->fd[0] = open(file, flags, 0644); /* FIXME: mode? */
	if (str->fd[0] == -1)
		return errno;
	return 0;
}



static int
open_parsed_inet_stream(eval_environ_t env,
			struct io_stream *str,
			const char *cstr,
			char *proto, char *port, char *path,
			int flags)
{
	union {
		struct sockaddr sa;
		struct sockaddr_in s_in;
		struct sockaddr_un s_un;
#ifdef GACOPYZ_IPV6
		struct sockaddr_in6 s_in6;
#endif
	} addr;

	socklen_t socklen;
	int fd;
	int rc;

	if (!proto
	    || strcmp(proto, "unix") == 0 || strcmp(proto, "local") == 0) {
		struct stat st;
		
			if (!(port == NULL))
#line 456
		(
#line 456
	env_throw_bi(env, mfe_failure, NULL, _("invalid connection type: %s; "
			    "port is meaningless for UNIX sockets"),cstr)
#line 456
)
#line 460
;
		
			if (!(strlen(path) <= sizeof addr.s_un.sun_path))
#line 462
		(
#line 462
	env_throw_bi(env, mfe_range, NULL, _("%s: UNIX socket name too long"),path)
#line 462
)
#line 465
;
		
		addr.sa.sa_family = PF_UNIX;
		socklen = sizeof(addr.s_un);
		strcpy(addr.s_un.sun_path, path);
		
		if (stat(path, &st)) {
			(
#line 472
	env_throw_bi(env, mfe_failure, NULL, _("%s: cannot stat socket: %s"),path,strerror(errno))
#line 472
);
#line 475
		} else {
			/* FIXME: Check permissions? */
				if (!(S_ISSOCK(st.st_mode)))
#line 477
		(
#line 477
	env_throw_bi(env, mfe_failure, NULL, _("%s: not a socket"),path)
#line 477
)
#line 480
;
		}

	} else if (strcmp(proto, "inet") == 0) {
		short pnum;
		long num;
		char *p;
		
		addr.sa.sa_family = PF_INET;
		socklen = sizeof(addr.s_in);

			if (!(port != NULL))
#line 491
		(
#line 491
	env_throw_bi(env, mfe_failure, NULL, _("invalid connection type: %s; "
			    "missing port number"),cstr)
#line 491
)
#line 495
;

		num = pnum = strtol(port, &p, 0);
		if (*p == 0) {
				if (!(num == pnum))
#line 499
		(
#line 499
	env_throw_bi(env, mfe_range, NULL, _("invalid connection type: "
				    "%s; bad port number"),cstr)
#line 499
)
#line 503
;
			pnum = htons(pnum);
		} else {
			struct servent *sp = getservbyname(port, "tcp");

				if (!(sp != NULL))
#line 508
		(
#line 508
	env_throw_bi(env, mfe_failure, NULL, _("invalid connection type: "
				    "%s; unknown port name"),cstr)
#line 508
)
#line 512
;
			pnum = sp->s_port;
		}
		
		if (!path)
			addr.s_in.sin_addr.s_addr = INADDR_ANY;
		else {
			struct hostent *hp = gethostbyname(path);
				if (!(hp != NULL))
#line 520
		(
#line 520
	env_throw_bi(env, mfe_failure, NULL, _("unknown host name %s"),path)
#line 520
)
#line 523
;
			addr.sa.sa_family = hp->h_addrtype;
			switch (hp->h_addrtype) {
			case AF_INET:
				memmove(&addr.s_in.sin_addr, hp->h_addr, 4);
				addr.s_in.sin_port = pnum;
				break;

			default:
				(
#line 532
	env_throw_bi(env, mfe_range, NULL, _("invalid connection type: "
					   "%s; unsupported address family"),cstr)
#line 532
);
#line 536
			}
		}
#ifdef GACOPYZ_IPV6
	} else if (strcmp(proto, "inet6") == 0) {
		struct addrinfo hints;
		struct addrinfo *res;
		
			if (!(port != NULL))
#line 543
		(
#line 543
	env_throw_bi(env, mfe_failure, NULL, _("invalid connection type: %s; "
			    "missing port number"),cstr)
#line 543
)
#line 547
;

		memset(&hints, 0, sizeof(hints));
		hints.ai_family = AF_INET6;
		hints.ai_socktype = SOCK_STREAM;
		if (!path)
			hints.ai_flags |= AI_PASSIVE;
		
		rc = getaddrinfo(path, port, &hints, &res);
				
		switch (rc) {
		case 0:
			break;
			
		case EAI_SYSTEM:
			(
#line 562
	env_throw_bi(env, mfe_failure, NULL, _("%s:%s: cannot parse address: %s"),path,port,strerror(errno))
#line 562
);
#line 565
			
		case EAI_BADFLAGS:
		case EAI_SOCKTYPE:
			(
#line 568
	env_throw_bi(env, mfe_failure, NULL, _("%s:%d: internal error converting %s:%s"),__FILE__,__LINE__,path,port)
#line 568
);
#line 571
			
		case EAI_MEMORY:
			mu_alloc_die();
			
		default:
			(
#line 576
	env_throw_bi(env, mfe_failure, NULL, "%s:%s: %s",path,port,gai_strerror(rc))
#line 576
);
#line 579
		}

		socklen = res->ai_addrlen;
		if (socklen > sizeof(addr)) {
			freeaddrinfo(res);
			(
#line 584
	env_throw_bi(env, mfe_failure, NULL, _("%s:%s: address length too big (%lu)"),path,port,(unsigned long) socklen)
#line 584
);
#line 588
		}
		memcpy(&addr, res->ai_addr, res->ai_addrlen);
		freeaddrinfo(res);
#endif
	} else {
		(
#line 593
	env_throw_bi(env, mfe_range, NULL, _("unsupported protocol: %s"),proto)
#line 593
);
#line 596
	}

	fd = socket(addr.sa.sa_family, SOCK_STREAM, 0);
		if (!(fd != -1))
#line 599
		(
#line 599
	env_throw_bi(env, mfe_failure, NULL, _("unable to create new socket: %s"),strerror(errno))
#line 599
)
#line 602
;

	/* FIXME: Bind to the source ? */

	rc = connect(fd, &addr.sa, socklen);
	if (rc) {
		close(fd);
		(
#line 609
	env_throw_bi(env, mfe_failure, NULL, _("cannot connect to %s: %s"),cstr,strerror(errno))
#line 609
);
#line 612
	}
	
	str->fd[0] = fd;
	return 0;
}

static int
shutdown_inet_stream(struct io_stream *str, int how)
{
	switch (how) {
	case 0:
		how = SHUT_RD;
		break;

	case 1:
		how = SHUT_WR;
		break;

	case 2:
		how = SHUT_RDWR;
		break;

	default:
		return EINVAL;
	}
	if (shutdown(str->fd[0], how))
		return errno;
	return 0;
}

static int
open_inet_stream(eval_environ_t env,
		 struct io_stream *str, const char *addr, int flags)
{
	int rc;
	char *proto, *port, *path;

	if (gacopyz_parse_connection(addr, &proto, &port, &path)
	    != MI_SUCCESS) 
		rc = ENOMEM; /* FIXME: or EINVAL? */
	else {
		rc = open_parsed_inet_stream(env,
					     str, addr,
					     proto, port, path, flags);
		str->shutdown = shutdown_inet_stream;
		free(proto);
		free(port);
		free(path);
	}
	return rc;
}


static void *
alloc_streams()
{
	struct io_stream *p, *stab = mu_calloc(nstreams, sizeof *stab);
	for (p = stab; p < stab + nstreams; p++) 
		p->fd[0] = p->fd[1] = -1;
	return stab;
}

static void
destroy_streams(void *data)
{
	struct io_stream *stab = data;
	struct io_stream *p;
	for (p = stab; p < stab + nstreams; p++) {
		close_stream(p);
		free(p->buf);
	}
	free(stab);
}
		

#line 686

#line 686
static int IO_id;
#line 686 "io.bi"


int
_bi_io_fd(eval_environ_t env, int fd, int what)
{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	int descr;

		if (!(fd >= 0 && fd < nstreams && what>=0 && what<=1))
#line 694
		(
#line 694
	env_throw_bi(env, mfe_range, NULL, _("invalid file descriptor"))
#line 694
)
#line 696
;
	descr = what == 0 ? IFD(iotab[fd]) : OFD(iotab[fd]);
		if (!(descr >= 0))
#line 698
		(
#line 698
	env_throw_bi(env, mfe_range, NULL, _("invalid file descriptor"))
#line 698
)
#line 700
;
	return descr;
}


void
#line 705
bi_open(eval_environ_t env)
#line 705

#line 705

#line 705 "io.bi"
{
#line 705
	
#line 705

#line 705

#line 705
char *  name;
#line 705
        
#line 705
get_string_arg(env, 0, &name);
#line 705
        
#line 705

#line 705
        adjust_stack(env, 1);
#line 705

#line 705

#line 705
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 705
		prog_trace(env, "open %s",name);;
#line 705

{
	int i, rc;
	int flags = 0;
	int (*opf)(eval_environ_t env,
		   struct io_stream *, const char *, int) = open_file_stream;
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	
	for (i = 0; i < nstreams; i++) {
		if (iotab[i].fd[0] == -1) 
			break;
	}
		if (!(i < nstreams))
#line 717
		(
#line 717
	env_throw_bi(env, mfe_failure, "open", _("no more files available"))
#line 717
)
#line 719
;

	
#line 721

#line 721
mu_debug(debug_handle, MU_DEBUG_TRACE1,("opening stream %s", name));
	iotab[i].name = mu_strdup(name);
	iotab[i].delim = NULL;
	if (*name == '>') {
		flags |= O_RDWR|O_CREAT;
		name++;
		if (*name == '>') {
			flags |= O_APPEND;
			name++;
		} else
			flags |= O_TRUNC;
	} else if (*name == '|') {
		opf = open_program_stream;
		flags = O_WRONLY;
		name++;
		if (*name == '&') {
			flags = O_RDWR;
			name++;
		} else if (*name == '<') {
			flags = O_RDONLY;
			name++;
		}
	} else if (*name == '@') {
		name++;
		opf = open_inet_stream;
		flags = O_RDWR;
	} else
		flags = O_RDONLY;
	
	for (;*name && mu_isspace(*name); name++)
		;
	
	rc = opf(env, &iotab[i], name, flags);
	
		if (!(rc == 0))
#line 755
		(
#line 755
	env_throw_bi(env, mfe_failure, "open", _("cannot open stream %s: %s"),name,mu_strerror(rc))
#line 755
)
#line 758
;
	
#line 759

#line 759
mu_debug(debug_handle, MU_DEBUG_TRACE1,("open(%s) = %d", name, i));
	
#line 760
do {
#line 760
  push(env, (STKVAL)(mft_number)(i));
#line 760
  goto endlab;
#line 760
} while (0);
}
endlab:
#line 762
        env_function_cleanup_flush(env, NULL);
#line 762
	return;
#line 762
}

void
#line 764
bi_spawn(eval_environ_t env)
#line 764

#line 764

#line 764 "io.bi"
{
#line 764
	
#line 764

#line 764
long __bi_argcnt;
#line 764
char *  name;
#line 764
        long  fin;
#line 764
        long  fout;
#line 764
        long  ferr;
#line 764
        
#line 764
get_string_arg(env, 1, &name);
#line 764
        get_numeric_arg(env, 2, &fin);
#line 764
        get_numeric_arg(env, 3, &fout);
#line 764
        get_numeric_arg(env, 4, &ferr);
#line 764
        
#line 764
get_numeric_arg(env, 0, &__bi_argcnt);
#line 764
        adjust_stack(env, __bi_argcnt + 1);
#line 764

#line 764

#line 764
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 764
		prog_trace(env, "spawn %s %lu %lu %lu",name, ((__bi_argcnt > 1) ? fin : 0), ((__bi_argcnt > 2) ? fout : 0), ((__bi_argcnt > 3) ? ferr : 0));;

{
	int i, rc;
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	int ioe[3];
	int flags;
	
	for (i = 0; i < nstreams; i++) {
		if (iotab[i].fd[0] == -1) 
			break;
	}
		if (!(i < nstreams))
#line 776
		(
#line 776
	env_throw_bi(env, mfe_failure, "spawn", _("no more files available"))
#line 776
)
#line 778
;

	
#line 780

#line 780
mu_debug(debug_handle, MU_DEBUG_TRACE1,("spawning %s", name));
	iotab[i].name = mu_strdup(name);
	iotab[i].delim = NULL;

	flags = O_WRONLY;
	if (*name == '|')
		name++;
	if (*name == '&') {
		flags = O_RDWR;
		name++;
	} else if (*name == '<') {
		flags = O_RDONLY;
		name++;
	}

	for (;*name && mu_isspace(*name); name++)
		;

	if ((__bi_argcnt > 1))
		ioe[0] = _bi_io_fd(env, ((__bi_argcnt > 1) ? fin : 0), 0);
	else
		ioe[0] = -1;
	if ((__bi_argcnt > 2))
		ioe[1] = _bi_io_fd(env, ((__bi_argcnt > 2) ? fout : 0), 1);
	else
		ioe[1] = -1;
	if ((__bi_argcnt > 3))
		ioe[2] = _bi_io_fd(env, ((__bi_argcnt > 2) ? fout : 0), 1);
	else
		ioe[2] = -1;
	
	rc = open_program_stream_ioe(env, &iotab[i], name, flags, ioe);
	
		if (!(rc == 0))
#line 813
		(
#line 813
	env_throw_bi(env, mfe_failure, "spawn", _("cannot open stream %s: %s"),name,mu_strerror(rc))
#line 813
)
#line 816
;
	
#line 817

#line 817
mu_debug(debug_handle, MU_DEBUG_TRACE1,("spawn(%s) = %d", name, i));
	
#line 818
do {
#line 818
  push(env, (STKVAL)(mft_number)(i));
#line 818
  goto endlab;
#line 818
} while (0);
	
}
endlab:
#line 821
        env_function_cleanup_flush(env, NULL);
#line 821
	return;
#line 821
}


void
#line 824
bi_tempfile(eval_environ_t env)
#line 824

#line 824

#line 824 "io.bi"
{
#line 824
	
#line 824

#line 824
long __bi_argcnt;
#line 824
char * MFL_DATASEG tempdir;
#line 824
        
#line 824
get_string_arg(env, 1, &tempdir);
#line 824
        
#line 824
get_numeric_arg(env, 0, &__bi_argcnt);
#line 824
        adjust_stack(env, __bi_argcnt + 1);
#line 824

#line 824

#line 824
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 824
		prog_trace(env, "tempfile %s",((__bi_argcnt > 0) ? tempdir : ""));;
#line 824

{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	int i;
	char *dir = ((__bi_argcnt > 0) ? tempdir : "/tmp");
	size_t dirlen = strlen(dir);
	mode_t u;
	int fd;
	char *template;
#define PATTERN "mfdXXXXXX"

	for (i = 0; i < nstreams; i++) {
		if (iotab[i].fd[0] == -1) 
			break;
	}
		if (!(i < nstreams))
#line 839
		(
#line 839
	env_throw_bi(env, mfe_failure, "tempfile", _("no more files available"))
#line 839
)
#line 841
;


	while (dirlen > 0 && dir[dirlen-1] == '/')
		dirlen--;

	template = mf_c_val(heap_tempspace(env, (dirlen ? dirlen + 1 : 0) +
#line 847
				      sizeof(PATTERN)), ptr);
#line 849
	if (dirlen) {
		memcpy(template, dir, dirlen);
		template[dirlen++] = '/';
	}
	strcpy(template + dirlen, PATTERN);
	u = umask(077);
	fd = mkstemp(template);
	umask(u);
		if (!(fd >= 0))
#line 857
		(
#line 857
	env_throw_bi(env, mfe_failure, "tempfile", "mkstemp failed: %s",mu_strerror(errno))
#line 857
)
#line 860
;
	unlink(template);

	iotab[i].fd[0] = fd;
	
	
#line 865
do {
#line 865
  push(env, (STKVAL)(mft_number)(i));
#line 865
  goto endlab;
#line 865
} while (0);
#undef PATTERN
}
endlab:
#line 868
        env_function_cleanup_flush(env, NULL);
#line 868
	return;
#line 868
}

void
#line 870
bi_close(eval_environ_t env)
#line 870

#line 870

#line 870 "io.bi"
{
#line 870
	
#line 870

#line 870

#line 870
long  fd;
#line 870
        
#line 870
get_numeric_arg(env, 0, &fd);
#line 870
        
#line 870

#line 870
        adjust_stack(env, 1);
#line 870

#line 870

#line 870
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 870
		prog_trace(env, "close %lu",fd);;
#line 870

{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);

		if (!(fd >= 0 && fd < nstreams))
#line 874
		(
#line 874
	env_throw_bi(env, mfe_range, "close", _("invalid file descriptor"))
#line 874
)
#line 876
;
	close_stream(&iotab[fd]);
}

#line 879
        env_function_cleanup_flush(env, NULL);
#line 879
	return;
#line 879
}	

static struct builtin_const_trans shutdown_modes[] = {
	{ _MFL_SHUT_RD, SHUT_RD },
	{ _MFL_SHUT_WR, SHUT_WR },
	{ _MFL_SHUT_RDWR, SHUT_RDWR }
};

void
#line 887
bi_shutdown(eval_environ_t env)
#line 887

#line 887

#line 887 "io.bi"
{
#line 887
	
#line 887

#line 887

#line 887
long  fd;
#line 887
        long  how;
#line 887
        
#line 887
get_numeric_arg(env, 0, &fd);
#line 887
        get_numeric_arg(env, 1, &how);
#line 887
        
#line 887

#line 887
        adjust_stack(env, 2);
#line 887

#line 887

#line 887
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 887
		prog_trace(env, "shutdown %lu %lu",fd, how);;
#line 887

{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	struct io_stream *ioptr;
	int mode;
	
		if (!(fd >= 0 && fd < nstreams))
#line 893
		(
#line 893
	env_throw_bi(env, mfe_range, "shutdown", _("invalid file descriptor"))
#line 893
)
#line 895
;
		if (!(how >= 0 && how <= 2))
#line 896
		(
#line 896
	env_throw_bi(env, mfe_range, "shutdown", _("invalid file descriptor"))
#line 896
)
#line 898
;
		if (!(_builtin_const_to_c(shutdown_modes,
#line 899
				      MU_ARRAY_SIZE(shutdown_modes),
#line 899
				      how,
#line 899
				      &mode) == 0))
#line 899
		(
#line 899
	env_throw_bi(env, mfe_failure, "shutdown", "bad shutdown mode")
#line 899
)
#line 904
;
	
	ioptr = &iotab[fd];
	if (ioptr->shutdown) {
		int rc = ioptr->shutdown(ioptr, mode);
			if (!(rc == 0))
#line 909
		(
#line 909
	env_throw_bi(env, mfe_io, "shutdown", "shutdown failed: %s",mu_strerror(rc))
#line 909
)
#line 912
;
	} else if (how == 2)
		close_stream(ioptr);
	else if (ioptr->fd[how]) {
		close(ioptr->fd[how]);
		ioptr->fd[how] = -1;
	}
}

#line 920
        env_function_cleanup_flush(env, NULL);
#line 920
	return;
#line 920
}

void
#line 922
bi_write(eval_environ_t env)
#line 922

#line 922

#line 922 "io.bi"
{
#line 922
	
#line 922

#line 922
long __bi_argcnt;
#line 922
long  fd;
#line 922
        char *  str;
#line 922
        long  n;
#line 922
        
#line 922
get_numeric_arg(env, 1, &fd);
#line 922
        get_string_arg(env, 2, &str);
#line 922
        get_numeric_arg(env, 3, &n);
#line 922
        
#line 922
get_numeric_arg(env, 0, &__bi_argcnt);
#line 922
        adjust_stack(env, __bi_argcnt + 1);
#line 922

#line 922

#line 922
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 922
		prog_trace(env, "write %lu %s %lu",fd, str, ((__bi_argcnt > 2) ? n : 0));;
#line 922

{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	int rc;
	
	
#line 927

#line 927
mu_debug(debug_handle, MU_DEBUG_TRACE1,("writing %s to %lu", str, fd));
		if (!(fd >= 0 && fd < nstreams && OFD(iotab[fd]) != -1))
#line 928
		(
#line 928
	env_throw_bi(env, mfe_range, "write", _("invalid file descriptor"))
#line 928
)
#line 930
;
	if (!(__bi_argcnt > 2))
		n = strlen (str);
	rc = write(OFD(iotab[fd]), str, n);
		if (!(n == rc))
#line 934
		(
#line 934
	env_throw_bi(env, mfe_io, "write", _("write error on %s: %s"),iotab[fd].name,mu_strerror(errno))
#line 934
)
#line 937
;
}

#line 939
        env_function_cleanup_flush(env, NULL);
#line 939
	return;
#line 939
}


void
#line 942
bi_write_body(eval_environ_t env)
#line 942

#line 942

#line 942 "io.bi"
{
#line 942
	
#line 942

#line 942

#line 942
long  fd;
#line 942
        void *  str;
#line 942
        long  n;
#line 942
        
#line 942
get_numeric_arg(env, 0, &fd);
#line 942
        get_pointer_arg(env, 1, &str);
#line 942
        get_numeric_arg(env, 2, &n);
#line 942
        
#line 942

#line 942
        adjust_stack(env, 3);
#line 942

#line 942

#line 942
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 942
		prog_trace(env, "write_body %lu %p %lu",fd, str, n);;
#line 942

{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	int rc;

		if (!(fd >= 0 && fd < nstreams && OFD(iotab[fd]) != -1))
#line 947
		(
#line 947
	env_throw_bi(env, mfe_range, "write_body", _("invalid file descriptor"))
#line 947
)
#line 949
;
	rc = write(OFD(iotab[fd]), str, n);
		if (!(n == rc))
#line 951
		(
#line 951
	env_throw_bi(env, mfe_io, "write_body", _("write error on %s: %s"),iotab[fd].name,mu_strerror(errno))
#line 951
)
#line 954
;
}

#line 956
        env_function_cleanup_flush(env, NULL);
#line 956
	return;
#line 956
}

void
#line 958
bi_read(eval_environ_t env)
#line 958

#line 958

#line 958 "io.bi"
{
#line 958
	
#line 958

#line 958

#line 958
long  fd;
#line 958
        long  size;
#line 958
        
#line 958
get_numeric_arg(env, 0, &fd);
#line 958
        get_numeric_arg(env, 1, &size);
#line 958
        
#line 958

#line 958
        adjust_stack(env, 2);
#line 958

#line 958

#line 958
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 958
		prog_trace(env, "read %lu %lu",fd, size);;
#line 958

{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	int rc;
	size_t off;
	char *s = (char*) env_data_ref(env, (off = heap_reserve(env, size + 1)));

		if (!(fd >= 0 && fd < nstreams && IFD(iotab[fd]) != -1))
#line 965
		(
#line 965
	env_throw_bi(env, mfe_range, "read", _("invalid file descriptor"))
#line 965
)
#line 967
;
	
	rc = read(IFD(iotab[fd]), s, size);
	if (rc == 0)
		(
#line 971
	env_throw_bi(env, mfe_eof, "read", _("EOF on %s"),iotab[fd].name)
#line 971
);
#line 973
		if (!(rc == size))
#line 973
		(
#line 973
	env_throw_bi(env, mfe_io, "read", _("read error on %s: %s"),iotab[fd].name,mu_strerror(errno))
#line 973
)
#line 976
;
	s[size] = 0;
	
#line 978
do {
#line 978
  push(env, (STKVAL) (mft_size) (off));
#line 978
  goto endlab;
#line 978
} while (0);
}	
endlab:
#line 980
        env_function_cleanup_flush(env, NULL);
#line 980
	return;
#line 980
}

void
#line 982
bi_rewind(eval_environ_t env)
#line 982

#line 982

#line 982 "io.bi"
{
#line 982
	
#line 982

#line 982

#line 982
long  fd;
#line 982
        
#line 982
get_numeric_arg(env, 0, &fd);
#line 982
        
#line 982

#line 982
        adjust_stack(env, 1);
#line 982

#line 982

#line 982
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 982
		prog_trace(env, "rewind %lu",fd);;
#line 982

{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);

		if (!(fd >= 0 && fd < nstreams && IFD(iotab[fd]) != -1))
#line 986
		(
#line 986
	env_throw_bi(env, mfe_range, "rewind", _("invalid file descriptor"))
#line 986
)
#line 988
;
	if (lseek(IFD(iotab[fd]), 0, SEEK_SET) == -1)
		(
#line 990
	env_throw_bi(env, mfe_io, "rewind", "seek failed: %s",mu_strerror(errno))
#line 990
);
#line 993
}

#line 994
        env_function_cleanup_flush(env, NULL);
#line 994
	return;
#line 994
}
	

#define MINBUFSIZE 128
#define MAXBUFSIZE 65535

void
#line 1000
bi_copy(eval_environ_t env)
#line 1000

#line 1000

#line 1000 "io.bi"
{
#line 1000
	
#line 1000

#line 1000

#line 1000
long  dst;
#line 1000
        long  src;
#line 1000
        
#line 1000
get_numeric_arg(env, 0, &dst);
#line 1000
        get_numeric_arg(env, 1, &src);
#line 1000
        
#line 1000

#line 1000
        adjust_stack(env, 2);
#line 1000

#line 1000

#line 1000
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 1000
		prog_trace(env, "copy %lu %lu",dst, src);;
#line 1000

{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	int ifd, ofd;
	char *buffer;
	size_t bufsize = MAXBUFSIZE;
	char bs[MINBUFSIZE];
	off_t cur, end;
	size_t total = 0;
	ssize_t rdbytes;
	
		if (!(src >= 0 && src < nstreams && (ifd = IFD(iotab[src])) != -1))
#line 1011
		(
#line 1011
	env_throw_bi(env, mfe_range, "copy", _("invalid source file descriptor"))
#line 1011
)
#line 1013
;
		if (!(dst >= 0 && dst < nstreams && (ofd = OFD(iotab[dst])) != -1))
#line 1014
		(
#line 1014
	env_throw_bi(env, mfe_range, "copy", _("invalid destination file descriptor"))
#line 1014
)
#line 1016
;

	cur = lseek (ifd, 0, SEEK_CUR);
	if (cur != -1) {
		end = lseek (ifd, 0, SEEK_END);
		if (end != -1) {
			if (end < MAXBUFSIZE)
				bufsize = end;
			lseek (ifd, cur, SEEK_SET);
		}
	}

	for (; (buffer = malloc (bufsize)) == NULL; bufsize >>= 1)
		if (bufsize < MINBUFSIZE) {
			buffer = bs;
			bufsize = MINBUFSIZE;
			break;
		}

	while ((rdbytes = read(ifd, buffer, bufsize)) > 0) {
		char *p = buffer;
		while (rdbytes) {
			ssize_t wrbytes = write(ofd, p, rdbytes);
			if (wrbytes == -1) {
				if (buffer != bs)
					free(buffer);
				(
#line 1042
	env_throw_bi(env, mfe_io, "copy", "write error: %s",mu_strerror(errno))
#line 1042
);
#line 1045
			} else if (wrbytes == 0) {
				if (buffer != bs)
					free(buffer);
				(
#line 1048
	env_throw_bi(env, mfe_io, "copy", "short write")
#line 1048
);
#line 1050
			}
			p += wrbytes;
			rdbytes -= wrbytes;
			total += wrbytes;
		}
	}
	if (buffer != bs)
		free(buffer);
	
#line 1058
do {
#line 1058
  push(env, (STKVAL)(mft_number)(total));
#line 1058
  goto endlab;
#line 1058
} while (0);
}
endlab:
#line 1060
        env_function_cleanup_flush(env, NULL);
#line 1060
	return;
#line 1060
}

void
#line 1062
bi_getdelim(eval_environ_t env)
#line 1062

#line 1062

#line 1062 "io.bi"
{
#line 1062
	
#line 1062

#line 1062

#line 1062
long  fd;
#line 1062
        char * MFL_DATASEG delim;
#line 1062
        
#line 1062
get_numeric_arg(env, 0, &fd);
#line 1062
        get_string_arg(env, 1, &delim);
#line 1062
        
#line 1062

#line 1062
        adjust_stack(env, 2);
#line 1062

#line 1062

#line 1062
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 1062
		prog_trace(env, "getdelim %lu %s",fd, delim);;
#line 1062

{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	struct io_stream *ioptr;
	int rc;
	
		if (!(fd >= 0 && fd < nstreams && IFD(iotab[fd]) != -1))
#line 1068
		(
#line 1068
	env_throw_bi(env, mfe_range, "getdelim", _("invalid file descriptor"))
#line 1068
)
#line 1070
;
	ioptr = &iotab[fd];
	rc = read_stream_delim(ioptr, delim); 
	if (rc == 0)
		(
#line 1074
	env_throw_bi(env, mfe_eof, "getdelim", _("EOF on %s"),ioptr->name)
#line 1074
);
		if (!(rc > 0))
#line 1075
		(
#line 1075
	env_throw_bi(env, mfe_io, "getdelim", _("read error on %s: %s"),ioptr->name,mu_strerror(errno))
#line 1075
)
#line 1078
;
	
#line 1079
do {
#line 1079
  pushs(env, ioptr->buf);
#line 1079
  goto endlab;
#line 1079
} while (0);
}	
endlab:
#line 1081
        env_function_cleanup_flush(env, NULL);
#line 1081
	return;
#line 1081
}

void
#line 1083
bi_getline(eval_environ_t env)
#line 1083

#line 1083

#line 1083 "io.bi"
{
#line 1083
	
#line 1083

#line 1083

#line 1083
long  fd;
#line 1083
        
#line 1083
get_numeric_arg(env, 0, &fd);
#line 1083
        
#line 1083

#line 1083
        adjust_stack(env, 1);
#line 1083

#line 1083

#line 1083
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 1083
		prog_trace(env, "getline %lu",fd);;
#line 1083

{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	struct io_stream *ioptr;
	int rc;

		if (!(fd >= 0 && fd < nstreams && IFD(iotab[fd]) != -1))
#line 1089
		(
#line 1089
	env_throw_bi(env, mfe_range, "getline", _("invalid file descriptor"))
#line 1089
)
#line 1091
;
	ioptr = &iotab[fd];
	rc = read_stream_delim(ioptr, ioptr->delim ? ioptr->delim : "\n");
	if (rc == 0)
		(
#line 1095
	env_throw_bi(env, mfe_eof, "getline", _("EOF on %s"),ioptr->name)
#line 1095
);
#line 1097
		if (!(rc > 0))
#line 1097
		(
#line 1097
	env_throw_bi(env, mfe_io, "getline", _("read error on %s: %s"),ioptr->name,mu_strerror(errno))
#line 1097
)
#line 1100
;
	
#line 1101
do {
#line 1101
  pushs(env, ioptr->buf);
#line 1101
  goto endlab;
#line 1101
} while (0);
}	
endlab:
#line 1103
        env_function_cleanup_flush(env, NULL);
#line 1103
	return;
#line 1103
}

void
#line 1105
bi_fd_set_delimiter(eval_environ_t env)
#line 1105

#line 1105

#line 1105 "io.bi"
{
#line 1105
	
#line 1105

#line 1105

#line 1105
long  fd;
#line 1105
        char *  delim;
#line 1105
        
#line 1105
get_numeric_arg(env, 0, &fd);
#line 1105
        get_string_arg(env, 1, &delim);
#line 1105
        
#line 1105

#line 1105
        adjust_stack(env, 2);
#line 1105

#line 1105

#line 1105
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 1105
		prog_trace(env, "fd_set_delimiter %lu %s",fd, delim);;
#line 1105

{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	struct io_stream *ioptr;

		if (!(fd >= 0 && fd < nstreams && IFD(iotab[fd]) != -1))
#line 1110
		(
#line 1110
	env_throw_bi(env, mfe_range, "fd_set_delimiter", _("invalid file descriptor"))
#line 1110
)
#line 1112
;
	ioptr = &iotab[fd];
	free(ioptr->delim);
	ioptr->delim = mu_strdup(delim);
}

#line 1117
        env_function_cleanup_flush(env, NULL);
#line 1117
	return;
#line 1117
}

void
#line 1119
bi_fd_delimiter(eval_environ_t env)
#line 1119

#line 1119

#line 1119 "io.bi"
{
#line 1119
	
#line 1119

#line 1119

#line 1119
long  fd;
#line 1119
        char * MFL_DATASEG delim;
#line 1119
        
#line 1119
get_numeric_arg(env, 0, &fd);
#line 1119
        get_string_arg(env, 1, &delim);
#line 1119
        
#line 1119

#line 1119
        adjust_stack(env, 2);
#line 1119

#line 1119

#line 1119
	if (builtin_module_trace(BUILTIN_IDX_io))
#line 1119
		prog_trace(env, "fd_delimiter %lu %s",fd, delim);;
#line 1119

{
	struct io_stream *iotab = env_get_builtin_priv(env,IO_id);
	struct io_stream *ioptr;

		if (!(fd >= 0 && fd < nstreams && IFD(iotab[fd]) != -1))
#line 1124
		(
#line 1124
	env_throw_bi(env, mfe_range, "fd_delimiter", _("invalid file descriptor"))
#line 1124
)
#line 1126
;
	ioptr = &iotab[fd];
	
#line 1128
do {
#line 1128
  pushs(env, ioptr->delim ? ioptr->delim : "\n");
#line 1128
  goto endlab;
#line 1128
} while (0);
}
endlab:
#line 1130
        env_function_cleanup_flush(env, NULL);
#line 1130
	return;
#line 1130
}

 
#line 982 "../../src/builtin/snarf.m4"

#line 982

#line 982

#line 982
void
#line 982
io_init_builtin(void)
#line 982
{
#line 982
		debug_handle = mu_debug_register_category("bi_io");
#line 982

#line 982
	#line 686 "io.bi"
IO_id = builtin_priv_register(alloc_streams, destroy_streams,
#line 686
NULL);
#line 705 "io.bi"
va_builtin_install_ex("open", bi_open, 0, dtype_number, 1, 0, 0|0, dtype_string);
#line 764 "io.bi"
va_builtin_install_ex("spawn", bi_spawn, 0, dtype_number, 4, 3, 0|0, dtype_string, dtype_number, dtype_number, dtype_number);
#line 824 "io.bi"
va_builtin_install_ex("tempfile", bi_tempfile, 0, dtype_number, 1, 1, 0|0, dtype_string);
#line 870 "io.bi"
va_builtin_install_ex("close", bi_close, 0, dtype_unspecified, 1, 0, 0|0, dtype_number);
#line 887 "io.bi"
va_builtin_install_ex("shutdown", bi_shutdown, 0, dtype_unspecified, 2, 0, 0|0, dtype_number, dtype_number);
#line 922 "io.bi"
va_builtin_install_ex("write", bi_write, 0, dtype_unspecified, 3, 1, 0|0, dtype_number, dtype_string, dtype_number);
#line 942 "io.bi"
va_builtin_install_ex("write_body", bi_write_body, STATMASK(smtp_state_body), dtype_unspecified, 3, 0, 0|0, dtype_number, dtype_pointer, dtype_number);
#line 958 "io.bi"
va_builtin_install_ex("read", bi_read, 0, dtype_string, 2, 0, 0|0, dtype_number, dtype_number);
#line 982 "io.bi"
va_builtin_install_ex("rewind", bi_rewind, 0, dtype_unspecified, 1, 0, 0|0, dtype_number);
#line 1000 "io.bi"
va_builtin_install_ex("copy", bi_copy, 0, dtype_number, 2, 0, 0|0, dtype_number, dtype_number);
#line 1062 "io.bi"
va_builtin_install_ex("getdelim", bi_getdelim, 0, dtype_string, 2, 0, 0|0, dtype_number, dtype_string);
#line 1083 "io.bi"
va_builtin_install_ex("getline", bi_getline, 0, dtype_string, 1, 0, 0|0, dtype_number);
#line 1105 "io.bi"
va_builtin_install_ex("fd_set_delimiter", bi_fd_set_delimiter, 0, dtype_unspecified, 2, 0, 0|0, dtype_number, dtype_string);
#line 1119 "io.bi"
va_builtin_install_ex("fd_delimiter", bi_fd_delimiter, 0, dtype_string, 2, 0, 0|0, dtype_number, dtype_string);

#line 982 "../../src/builtin/snarf.m4"
	
#line 982
	 mf_add_runtime_params(io_cfg_param);
#line 982
	 
#line 982
}
#line 982 "../../src/builtin/snarf.m4"

