/* pipe.c from edgars lib */

#include <stat.h>
#include <device.h>
#include <stddef.h>
#include <types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <macros.h>

#ifndef mkdev
#define mkdev(a,b)	((((a) << 8) & 0xff00)|((b) & 0x00ff))
#endif


static size_t	pipe_size;
static size_t	pipe_allocated = 0;
static long	pipe_reading_pos, pipe_writing_pos;
static char	*pipe_buffer = NULL;
static int	pipe_is_open = 0;

static long
pipe_open(const char *name, int flags, unsigned mode)
{
	return(mkdev('P', 0));
}

static long
pipe_close(int fd)
{
	if(pipe_is_open) pipe_is_open--;
	return(0);
}

static long
pipe_read(int fd, void *buf, long nbytes)
{
	long	new_pos, ret;

	new_pos = min(pipe_size, pipe_reading_pos + nbytes);
	ret = new_pos - pipe_reading_pos;
	if(ret) bcopy(pipe_buffer + pipe_reading_pos, buf, ret);
	pipe_reading_pos = new_pos;
	return(ret);
}

static long
pipe_write(int fd, void *buf, long nbytes)
{
	long	new_pos, ret;

	new_pos = min(pipe_allocated, pipe_writing_pos + nbytes);
	ret = new_pos - pipe_writing_pos;
	if(ret) bcopy(buf, pipe_buffer + pipe_writing_pos, ret);
	pipe_writing_pos = new_pos;
	pipe_size = max(new_pos, pipe_size);
	return(ret);
}

static long
pipe_seek(int fd, long where, int how)
{
	if(how == SEEK_CUR) where += pipe_reading_pos;
	else if(how == SEEK_END) where = pipe_size - where;
	where = max(where, 0);
	where = min(where, pipe_size);
	return(pipe_reading_pos = where);
}

static int
pipe_fstat(int fd, struct stat *st)
{
	st->st_blksize = 1024;
	st->st_size = pipe_size;
	st->st_blocks = (pipe_size + 1023) / 1024;
	st->st_ino = fd;
	st->st_rdev = fd;
	st->st_mode = S_IFCHR | 0600;
	st->st_attr = 0x80;
	st->st_ino = st->st_rdev = fd;
	st->st_mtime = st->st_ctime = st->st_atime = 
		time((time_t *)0) - 2;
	st->st_nlink = 2;
	st->st_uid = geteuid();
	st->st_gid = getegid();
	return 0;
}

#define pipe_ioctl	NULL

extern struct _device	*__devices;

struct _device	pipe_dev =
	{"PIPE:", "pipe", mkdev('P', 0),
		 pipe_open, pipe_close, pipe_read, pipe_write, pipe_ioctl, NULL };

static void
_init_pipes()
{
	struct _device	*dev;

	for(dev = __devices; dev; dev = dev->next)
		if(dev->dev == mkdev('P', 0)) return;
	pipe_dev.next = __devices;
	__devices = &pipe_dev;
	pipe_allocated = 8 * 1024L;
	if(!(pipe_buffer = malloc(pipe_allocated))) pipe_allocated = 0;
}

static void
_exit_pipes()
{
	return;
}

int
pipe(fildes)
int	fildes[2];
{
	if(pipe_is_open) return -1; /* can't make this pipe */
	_init_pipes();
	pipe_size = pipe_reading_pos = pipe_writing_pos = 0;
	pipe_is_open = 2;
	fildes[0] = fildes[1] = mkdev('P', 0);
	return 0;
}

