#include <stdio.h>
#include <varargs.h>
#include <malloc.h>
#include <errno.h>
#define _NO_PROTO
#include "sckstdio.h"

FILE _SOCKstdin;
FILE _SOCKstdout;

FILE *
SOCKfdreopen(f, fd, mode)
FILE *f;
int fd;
char *mode;
{
	f->_file = fd;
	f->_base = malloc(BUFSIZ);
	if(!f->_base) return NULL;
	f->_ptr = f->_base;
	if(*mode == 'w') {
		f->_cnt = BUFSIZ;
		f->_flag = _IOWRT;
	} else {
		f->_cnt = 0;
		f->_flag = _IOREAD;
	}
}

FILE *
SOCKfdopen(fd, mode)
int fd;
const char *mode;
{
	FILE *f;

	if(f = (FILE *)malloc(sizeof(FILE))) {
		if(!SOCKfdreopen(f, fd, mode)) {
			free(f);
			return NULL;
		}
	}
	return f;
}

void
SOCKfflush(f)
FILE *f;
{
	int cnt;
	int scnt;
	char *p;

	if(!(f->_flag & _IOWRT)) return;

	/* Note that nothing bad will happen if f->_ptr == f->_base */

	cnt = f->_ptr - f->_base;
	/* Free up the space in the buffer now so we can reuse cnt */
	f->_cnt += cnt;
	f->_ptr = f->_base;

	for(p = f->_base; cnt > 0; cnt-=scnt, p += scnt) {
		scnt = send(fileno(f), p, cnt, 0);
		if(scnt < 0) {
			f->_flag |= _IOERR;
			break;
		}
	}
}

int
SOCKfclose(f)
FILE *f;
{
	SOCKfflush(f);
	so_close(fileno(f));
	if(f->_base) free(f->_base);
	free((char *)f);
}

int SOCKvprintf(fmt, ap)
char *fmt;
va_list ap;
{
	SOCKvfprintf(SOCKstdout, fmt, ap);
}

SOCKvfprintf(f, fmt, ap)
FILE *f;
char *fmt;
va_list ap;
{
	unsigned char buf[512];
	unsigned char *p;

	vsprintf(buf, fmt, ap);
	for(p = buf; *p; p++) SOCKputc(*p, f);
}

/*VARARGS*/
SOCKfprintf(f, fmt, va_alist)
FILE *f;
const char *fmt;
va_dcl
{
	va_list ap;

	va_start(ap);
	SOCKvfprintf(f, fmt, ap);
}

int
SOCKgetc(f)
FILE *f;
{
	if(f->_cnt <= 0) {
		f->_ptr = f->_base;
		f->_cnt = recv(fileno(f), f->_base, BUFSIZ, 0);
		if(f->_cnt == 0) return EOF;
		if(f->_cnt < 0) {
			f->_flag |= _IOERR;
			return EOF;
		}
	}
	f->_cnt--;
	return *f->_ptr++ & 0xff;
}

int
SOCKputc(c, f)
char c;
FILE *f;
{
	if(f->_cnt == 0) SOCKfflush(f);
	*f->_ptr++ = c;
	f->_cnt--;
}

int
SOCKferror(f)
FILE *f;
{
	return f->_flag & _IOERR;
}

/*VARARGS*/
SOCKprintf(fmt, va_alist)
char *fmt;
va_dcl
{
	va_list ap;

	va_start(ap);
	SOCKvfprintf(SOCKstdout, fmt, ap);
}

char *
SOCKfgets(buf0, size, f)
char *buf0;
int size;
FILE *f;
{
	char *buf;
	int c;

	buf = buf0;

	while(size > 1) {
		c = SOCKgetc(f);
		if(c == EOF) return NULL;
		*buf++ = c;
		if(c == '\n') break;
		size--;
	}
	*buf = '\0';
	return buf0;
}

