/*
 * tcattr
 *
 * by Hans Schou
 */

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

#define TURN_OFF	0
#define TURN_ON		1

struct flagtext {
	tcflag_t code;
	char *text;
};

struct flagtext iflagtext[] = {
	{IGNBRK,	"IGNBRK"},
	{BRKINT,	"BRKINT"},
	{IGNPAR,	"IGNPAR"},
	{PARMRK,	"PARMRK"},
	{INPCK,		"INPCK"},
	{ISTRIP,	"ISTRIP"},
	{INLCR,		"INLCR"},
	{IGNCR,		"IGNCR"},
	{ICRNL,		"ICRNL"},
	{IUCLC,		"IUCLC"},
	{IXON,		"IXON"},
	{IXANY,		"IXANY"},
	{IXOFF,		"IXOFF"},
	{IMAXBEL,	"IMAXBEL"},
	{0,0}
};

struct flagtext oflagtext[] = {
	{OPOST,	"OPOST"},
	{OLCUC,	"OLCUC"},
	{ONLCR,	"ONLCR"},
	{OCRNL,	"OCRNL"},
	{ONOCR,	"ONOCR"},
	{ONLRET,"ONLRET"},
	{OFILL,	"OFILL"},
	{OFDEL,	"OFDEL"},
#if defined __USE_MISC || defined __USE_XOPEN
	{NLDLY,	"NLDLY"},
	{NL0,	"NL0"},
	{NL1,	"NL1"},
	{CRDLY,	"CRDLY"},
	{CR0,	"CR0"},
	{CR1,	"CR1"},
	{CR2,	"CR2"},
	{CR3,	"CR3"},
	{TABDLY,"TABDLY"},
	{TAB0,	"TAB0"},
	{TAB1,	"TAB1"},
	{TAB2,	"TAB2"},
	{TAB3,	"TAB3"},
	{BSDLY,	"BSDLY"},
	{BS0,	"BS0"},
	{BS1,	"BS1"},
	{FFDLY,	"FFDLY"},
	{FF0,	"FF0"},
	{FF1,   "FF1"},
#endif
	{VTDLY,	"VTDLY"},
	{VT0,	"VT0"},
	{VT1,	"VT1"},
#ifdef __USE_MISC
	{XTABS,	"XTABS"},
#endif
	{0,0}
};

struct flagtext cflagtext[] = {
#ifdef __USE_MISC
	{CBAUD, "CBAUD"},	
#endif
	//{B0, "B0"},  /* hang up */
	{B50, "B50"},  
	{B75, "B75"},  
	{B110, "B110"},  
	{B134, "B134"},  
	{B150, "B150"},  
	{B200, "B200"},  
	{B300, "B300"},  
	{B600, "B600"},  
	{B1200, "B1200"},  
	{B1800, "B1800"},  
	{B2400, "B2400"},  
	{B4800, "B4800"},  
	{B9600, "B9600"},  
	{B19200, "B19200"},	
	{B38400, "B38400"},	
	{CSIZE, "CSIZE"},	
	{CS5, "CS5"},	
	{CS6, "CS6"},	
	{CS7, "CS7"},	
	{CS8, "CS8"},	
	{CSTOPB, "CSTOPB"},	
	{CREAD, "CREAD"},	
	{PARENB, "PARENB"},	
	{PARODD, "PARODD"},	
	{HUPCL, "HUPCL"},	
	{CLOCAL, "CLOCAL"},	
#ifdef __USE_MISC
	{CBAUDEX, "CBAUDEX"},
#endif
	{B57600, "B57600"},
	{B115200, "B115200"},
	{B230400, "B230400"},
	{B460800, "B460800"},
	{B500000, "B500000"},
	{B576000, "B576000"},
	{B921600, "B921600"},
	{B1000000, "B1000000"},
	{B1152000, "B1152000"},
	{B1500000, "B1500000"},
	{B2000000, "B2000000"},
	{B2500000, "B2500000"},
	{B3000000, "B3000000"},
	{B3500000, "B3500000"},
	{B4000000, "B4000000"},
#ifdef __USE_MISC
	{CIBAUD, "CIBAUD"},	 		/* input baud rate (not used) */
	{CRTSCTS, "CRTSCTS"}, 		/* flow control */
#endif
	{0,0}
};

struct flagtext lflagtext[] = {
/* c_lflag bits */
	{ISIG, "ISIG"},	
	{ICANON, "ICANON"},	
#if defined __USE_MISC || defined __USE_XOPEN
	{XCASE, "XCASE"},	
#endif
	{ECHO, "ECHO"},	
	{ECHOE, "ECHOE"},	
	{ECHOK, "ECHOK"},	
	{ECHONL, "ECHONL"},	
	{NOFLSH, "NOFLSH"},	
	{TOSTOP, "TOSTOP"},	
#ifdef __USE_MISC
	{ECHOCTL, "ECHOCTL"},
	{ECHOPRT, "ECHOPRT"},
	{ECHOKE, "ECHOKE"},	
	{FLUSHO, "FLUSHO"},	
	{PENDIN, "PENDIN"},	
#endif
	{IEXTEN, "IEXTEN"},	
	{0,0}
};

//s/\(^[A-Z]*\)/{\1, "\1"},/

int printflags(struct flagtext *ftext, tcflag_t f, char label) {
	int i;
	int dirt;
	tcflag_t flag, mask;
	int on = 0;

	mask = 0;
	i = 0;
	while (ftext[i].code) {
		mask |= ftext[i].code;
		i++;
	}

	while (on<2) {
		flag = (on ? f : ~f) & mask;
		//printf("\t/* flag: %04x */\n", flag & 0xFFFF);
		if (flag) {
			printf("\tterm.c_%cflag %c= %c( ", label, on?'|':'&', on?' ':'~');
			dirt = 0;
			i = 0;
			while (ftext[i].code) {
				if ((label == 'c') && on && (ftext[i].code == (f & CBAUD))) {
					if (dirt) {
						printf("| ");
					}
					printf("%s ", ftext[i].text);
					dirt++;
				}
				if (ftext[i].code & flag) {
					if (dirt) {
						printf("| ");
					}
					printf("%s ", ftext[i].text);
					dirt++;
				}
				i++;
			}
			printf(");\n");
		}
		on++;
	}

	return EXIT_SUCCESS;
}

int main(int argc, char **argv) {
	struct termios term;

	if (argc < 2) {
		tcgetattr(fileno(stdin), &term);
	} else {
		printf("\t/* Device: %s */\n", argv[1]);
		int fd;
		if (fd = open(argv[1], O_RDWR | O_NOCTTY ) > 0) {
			tcgetattr(fd, &term);
		} else {
			printf("ERROR, can not open: %s\n", argv[1]);
			perror(NULL);
			return EXIT_FAILURE;
		}
	}
	printf("\tstruct termios term;\n");
	printflags( iflagtext, term.c_iflag, 'i');
	printflags( oflagtext, term.c_oflag, 'o');
	printflags( lflagtext, term.c_lflag, 'l');

	return EXIT_SUCCESS;
}

