Blob Blame History Raw
/*********************************************************/
/*  ptycon: a pty-console bridge                         */
/*  Copyright (C) 2016--2017  Z. Gilboa                  */
/*  Released under GPLv2 and GPLv3; see COPYING.PTYCON.  */
/*********************************************************/

#include <ntapi/ntapi.h>
#include <stdio.h>

extern const ntapi_vtbl * ptyc_ntapi;

typedef struct ptyc_file {
        void *  hany;
} FILE;

int ptyc_fputs(const char * str, FILE * file)
{
	int32_t			status;
	nt_runtime_data *	rtdata;
	ntapi_zw_write_file *	iofn;
	void *			hio;
	void *			hevent;
	int			fdtype;
	size_t			size;
	size_t			nbytes;
	nt_iosb			iosb;

	/* rtdata */
	if (ptyc_ntapi->tt_get_runtime_data(&rtdata,0))
		return -1;

	/* io type */
	if (file == (void *)0) {
		hio    = rtdata->hstdin;
		fdtype = rtdata->stdin_type;

	} else if (file == (void *)1) {
		hio    = rtdata->hstdout;
		fdtype = rtdata->stdout_type;

	} else if (file == (void *)2) {
		hio    = rtdata->hstderr;
		fdtype = rtdata->stderr_type;
	} else {
		return -1;
	}

	if (!hio)
		return -1;

	/* buffer */
	size   = ptyc_ntapi->tt_string_null_offset_multibyte(str);
	nbytes = size;

	/* iofn */
	iofn = (fdtype ==  NT_FILE_TYPE_PTY)
		? (ntapi_zw_write_file *)ptyc_ntapi->pty_write
		: ptyc_ntapi->zw_write_file;

	/* hevent */
	if ((status = ptyc_ntapi->tt_create_private_event(
			&hevent,
			NT_NOTIFICATION_EVENT,
			NT_EVENT_NOT_SIGNALED)))
		return -1;

	while (nbytes) {
		/* iowrite */
		status = iofn(
			hio,hevent,
			0,0,&iosb,
			(void *)str,
			(uint32_t)nbytes,0,0);

		/* wait */
		if (status == NT_STATUS_PENDING)
			status = ptyc_ntapi->zw_wait_for_single_object(
				hevent,0,0);

		/* check */
		if (status || iosb.status) {
			ptyc_ntapi->zw_close(hevent);
			return -1;
		}

		str    += iosb.info;
		nbytes -= iosb.info;
	}

	/* all done */
	ptyc_ntapi->zw_close(
		hevent);

	return (int)size;
}

int ptyc_fprintf(FILE * file, const char * fmt, ...)
{
	va_list	ap;
	char *	str;
	size_t	buffer[32768/sizeof(size_t)];

	ptyc_ntapi->tt_aligned_block_memset(
		buffer,0,sizeof(buffer));

	str = (char *)buffer;

	va_start(ap, fmt);
	ptyc_ntapi->vsnprintf(str, sizeof(buffer), fmt, ap);
	va_end(ap);

	str[sizeof(buffer)-1] = 0;

	return ptyc_fputs(str,file);
}

int ptyc_sprintf(char * str, const char * fmt, ...)
{
	int     ret;
	va_list ap;

	va_start(ap, fmt);
	ret = ptyc_ntapi->vsprintf(str, fmt, ap);
	va_end(ap);

	return ret;
}

int ptyc_snprintf(char * str, size_t n, const char * fmt, ...)
{
	int     ret;
	va_list ap;

	va_start(ap, fmt);
	ret = ptyc_ntapi->vsnprintf(str, n, fmt, ap);
	va_end(ap);

	return ret;
}

int ptyc_isatty(int fildes)
{
	nt_runtime_data * rtdata;

	if ((ptyc_ntapi->tt_get_runtime_data(&rtdata,0)))
		return 0;

	if (fildes == 0)
		return (rtdata->stdin_type == NT_FILE_TYPE_PTY);

	else if (fildes == 1)
		return (rtdata->stdout_type == NT_FILE_TYPE_PTY);

	else if (fildes == 2)
		return (rtdata->stderr_type == NT_FILE_TYPE_PTY);

	else
		return 0;
}

int ptyc_fileno(void * any)
{
	return (int)(intptr_t)any;
}

int ptyc_write(int fd, const void * buf, size_t size)
{
	int32_t			status;
	nt_runtime_data *	rtdata;
	ntapi_zw_write_file *	iofn;
	void *			hio;
	void *			hevent;
	int			fdtype;
	nt_iosb			iosb;

	/* size */
	if (size >= 0x80000000)
		return NT_STATUS_INVALID_PARAMETER;

	/* rtdata */
	if (ptyc_ntapi->tt_get_runtime_data(&rtdata,0))
		return NT_STATUS_REINITIALIZATION_NEEDED;

	/* hio, io type */
	if (fd == STDIN_FILENO) {
		hio    = rtdata->hstdin;
		fdtype = rtdata->stdin_type;

	} else if (fd == STDOUT_FILENO) {
		hio    = rtdata->hstdout;
		fdtype = rtdata->stdout_type;

	} else if (fd == STDERR_FILENO) {
		hio    = rtdata->hstderr;
		fdtype = rtdata->stderr_type;
	} else {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!hio)
		return NT_STATUS_INVALID_HANDLE;

	/* iofn */
	iofn = (fdtype ==  NT_FILE_TYPE_PTY)
		? (ntapi_zw_write_file *)ptyc_ntapi->pty_write
		: ptyc_ntapi->zw_write_file;

	/* hevent */
	if ((status = ptyc_ntapi->tt_create_private_event(
			&hevent,
			NT_NOTIFICATION_EVENT,
			NT_EVENT_NOT_SIGNALED)))
		return status;

	/* iowrite */
	status = iofn(
		hio,hevent,
		0,0,&iosb,
		(void *)buf,size,
		0,0);

	/* wait */
	if (status == NT_STATUS_PENDING)
		status = ptyc_ntapi->zw_wait_for_single_object(
			hevent,0,0);

	/* hevent */
	ptyc_ntapi->zw_close(hevent);

	/* ret */
	return status ? status : iosb.status;
}