/*
 * Copyright(C) Paul und Scherer (mct.de/mct.net)
 *
 * This example demonstrates how to...
 *
 *  ... install a user-defined I/O function.
 */

#include <stdio.h>
#include <stdlib.h>

/*
 * User I/O
 *
 * Operations on file descriptors 0, 1 and 2 (stdin/stdout/stderr) are handled
 * by functions in the system lib (libs). The function pointer "_usriop" allows
 * non-standard I/O (e.g printf to a LCD) without the need to modify libs.
 *
 * For any file descriptor >2 the requested operation is forwarded to _usriop().
 * _usriop() is called with the file descriptor fd, the operation action and in
 * case of putc and ungetc the character c.
 *
 * The default file descriptor array looks as follows
 *
 *  stdin  -> _iodev[0] = 0 handled
 *  stdout -> _iodev[1] = 1  by
 *  stderr -> _iodev[2] = 2  libs
 *
 *  auxin  -> _iodev[3] = 3 forwarded
 *  auxout -> _iodev[4] = 4  to
 *  extio  -> _iodev[5] = 5  _usriop()
 *
 * The contents of the array may be modified at runtime. Be sure to set _usriop
 * to the address of your user I/O function before (!) using any fd >2 or auxin,
 * auxout or extio.
 *
 * Codes for action:
 *
 *  0 =flush
 *  1 =getc
 *  2 =putc
 *  3 =ungetc
 *
 * Return byte read or <0 if no byte available for getc, else don't care.
 */
static int
myio(int fd, int action, int c)
{
	/*
	 * No real I/O is done here, the function
	 * only prints a message, indicating what
	 * would be done...
	 */

	printf("myio: fd = %d, action = %d", fd, action);
	if (action > 1) printf(", c = %02x", (unsigned char)c);
	putchar('\n');

	return 0;
}

/*
 * Set the user I/O address and call some test functions.
 */
int
main(void)
{
	char c;

	_usriop = myio;				// set user I/O addr

	/*
	 * All following operations on file
	 * descriptors fd >2 use now myio().
	 */

	read(3, &c, 1);				// fd =3
	write(3, "A", 1);

	read(4, &c, 1);				// fd =4
	write(4, "A", 1);

	read(5, &c, 1);				// ...
	write(5, "A", 1);

	/*
	 * Use auxin/auxout/extio for high-level access.
	 */

	fgetc(auxin);				// auxin
	ungetc('B', auxin);

	fputc('A', auxout);			// auxout
	fflush(auxout);

	fgetc(extio);				// extio
	fputc('A', extio);
	ungetc('B', extio);
	fflush(extio);

	/*
	 * Redirect extio for other devices.
	 */

	*extio = 6;				// extio -> 6

	fgetc(extio);
	fputc('A', extio);
	ungetc('B', extio);
	fflush(extio);

	*extio = 7;				// ...

	fgetc(extio);
	fputc('A', extio);
	ungetc('B', extio);
	fflush(extio);

	return 0;
}
