/*	chars ...
*
* This program generates one byte for each argument, and  writes  them
* to  standard  output.   If  an arg is one byte, it is just copied to
* stdout.  If it is more than one byte, it may be of several forms:
*
*	-x	is an option, described below.
*	#xx	is a hex value.
*	00n	is an octal value.
*	\c	is the usual C digraph for an escape character.
*	^X	means CTRL-X.
*
* Params not in one of these forms are looked up  in  a  table,  which
* includes most of the standard names for various characters.
*
* The options recognized are:
*
* -r<n>
*   repeat the last char <n> times; default is one repeat.
*
* -s<n>
*   sleep <n> seconds between output chars; default is 1 second.  (But
*   note that, without the -s option, no sleep is done at all.)
*/
:1#include "V.h"

struct {
	char *name;
	byte  value;
} tbl[] = {
	{"ACK"	,0x06},
	{"BANG"	,0x21},
	{"BEL"	,0x07},
	{"BELL"	,0x07},
	{"BS"	,0x08},
	{"CAN"	,0x18},
	{"COMMA",0x2C},
	{"CR"	,0x0D},
	{"DC1"	,0x11},
	{"DC2"	,0x12},
	{"DC3"	,0x13},
	{"DC4"	,0x14},
	{"DEL"	,0x7F},
	{"DLE"	,0x10},
	{"DOT"	,0x2E},
	{"EM"	,0x19},
	{"ENQ"	,0x05},
	{"EOT"	,0x04},
	{"ESC" 	,0x1B},
	{"ETB"	,0x17},
	{"ETX"	,0x03},
	{"FS"	,0x1C},
	{"GS"	,0x1D},
	{"HT"	,0x09},
	{"LF"	,0x0A},
	{"NAK"	,0x15},
	{"NL"	,0x0A},
	{"NP"	,0x0C},
	{"FF"	,0x0C},
	{"NUL" 	,0x00},
	{"NULL"	,0x00},
	{"RS"	,0x1E},
	{"SI"	,0x0F},
	{"SO"	,0x0E},
	{"SOH"	,0x01},
	{"SP"	,0x20},
	{"STX"	,0x02},
	{"SUB"	,0x1A},
	{"SYN"	,0x16},
	{"TAB"	,0x09},
	{"US"	,0x1F},
	{"VT"	,0x0B},
	{"ack"	,0x06},
	{"bang"	,0x21},
	{"bel"	,0x07},
	{"bell"	,0x07},
	{"bs"	,0x08},
	{"can"	,0x18},
	{"comma",0x2C},
	{"cr"	,0x0D},
	{"dc1"	,0x11},
	{"dc2"	,0x12},
	{"dc3"	,0x13},
	{"dc4"	,0x14},
	{"del"	,0x7f},
	{"dle"	,0x10},
	{"dot"	,0x2E},
	{"em"	,0x19},
	{"enq"	,0x05},
	{"eot"	,0x04},
	{"esc" 	,0x1B},
	{"etb"	,0x17},
	{"etx"	,0x03},
	{"fs"	,0x1C},
	{"gs"	,0x1D},
	{"ht"	,0x09},
	{"lf"	,0x0A},
	{"nak"	,0x15},
	{"nl"	,0x0A},
	{"np"	,0x0C},
	{"ff"	,0x0C},
	{"nul" 	,0x00},
	{"null"	,0x00},
	{"rs"	,0x1E},
	{"si"	,0x0F},
	{"so"	,0x0E},
	{"soh"	,0x01},
	{"sp"	,0x20},
	{"stx"	,0x02},
	{"sub"	,0x1A},
	{"syn"	,0x16},
	{"tab"	,0x09},
	{"us"	,0x1F},
	{"vt"	,0x0B},
	{0,0}
};
byte lastbyte  = 0;
int  sleeptime = 0;

main(ac,av)
	char **av;
{	int    a, i;
	char  *p;
	int    c0, c1, c2;
	U8     b;

:1	ac = Vinit(ac,av);

	for (a=1; a<ac; a++) {		/* Process the command line */
		if (!(c0 = av[a][0]))	/* Ignore null args */
			continue;
		if ((c1 = av[a][1]) == 0) {	/* One-byte arg? */
			V4 "Arg%d=%02X='%c'",a,B8(c0),Dsp(c0) D;
			onebyte(c0);		/* Write it to output */
			continue;
		}
		c2 = av[a][2];			/* 2 or more bytes in arg */
		switch (c0) {
		  case '-':
		  case '+':
			switch (c1) {
			  case 'd':
			  case 'D':
				Vopt(av[a]+2);
				continue;
			  case 'r':
			  case 'R':
				if (c2 == 0 || sscanf(av[a]+2,"%d",&i) < 1)
					i = 1;
				while (i-- > 0)
					onebyte(lastbyte);
				continue;
			  case 's':
			  case 'S':
				if (c2 == 0 || sscanf(av[a]+2,"%d",&sleeptime) < 1)
					sleeptime = 1;
:3				V3 "sleeptime = %d seconds.",sleeptime D;
				continue;
			  default:
:1				V1 "Unknown option \"%s\" ignored.",av[a] D;
			}
			continue;
		  case '9': case '8': case '7':
		  case '6': case '5': case '4':
		  case '3': case '2': case '1':
			sscanf(av[a],"%d",&c1);
			onebyte(c1);
			continue;
		  case '0':
			sscanf(av[a],"%o",&c1);
			onebyte(c1);
			continue;
		  case '#':
			sscanf(av[a],"%x",&c1);
			onebyte(c1);
			continue;
		  case '^':
			onebyte(c1 & 0x1F);
			continue;
		  case '\\':
			switch (c1) {
			  case 'D': onebyte(0x7F); continue;
			  case '0': onebyte('\0'); continue;
			  case 'b': onebyte('\b'); continue;
			  case 'n': onebyte('\n'); continue;
			  case 'r': onebyte('\r'); continue;
			  case 't': onebyte('\t'); continue;
			  default:
:1			  	V1 "`%s' unknown, ignored.",av[a] D;
			  	continue;
			}
		  default:	/* Look it up in the table */
			for (i=0; tbl[i].name; i++) {
				if (strcmp(av[a],tbl[i].name) == 0) {
:4					V4 "Byte: %02X='%c' %s",B8(tbl[i].value),Dsp(tbl[i].value),tbl[i].name D;
					onebyte(tbl[i].value);
					break;
				}
			}
			continue;
		}
	}
	Exit(0);
}

onebyte(x)
{
	if (sleeptime) sleep(sleeptime);
	lastbyte = x & 0xFF;
:5	V5 "Write %02X='%c'",B8(lastbyte),Dsp(lastbyte) D;
	Write(1,&lastbyte,1);
}
