/*
 * File...........: s390-tools/tape390/tape390_display.c
 * Author(s)......: Despina Papadopoulou <despina_p@de.ibm.com>
 *                  Stefan Bader <shbader@de.ibm.com>
 * Bugreports.to..: <Linux390@de.ibm.com>
 * 
 * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *
 * Description: The tape390_display tool is used to display 
 *              messages on the display unit of a zSeries tape drive.
 *
 */
#include <ctype.h>
#include <stdio.h> 
#include <unistd.h>
#include <fcntl.h> 
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/mtio.h>

#include "tape390.h"

/*  definitions  */

char *help_text= \
	"tape390_display: display one or two 8-byte messages on the display"
	"unit of a tape drive\n"
	"\n"
	"Usage: tape390_display <options> \"<message1>\" [\"<message2>\"] "
	"<device>"
	"\n\n"
	"where <options> are:\n"
	"\t-b | --blink\n"
	"\t\twill cause a single message to blink every 2 seconds\n"
	"\t\t(this option has only effect with a single message)\n"
	"\t-h | --help\n"
	"\t\tprint this text\n"
	"\t-l | --load\n"
	"\t\twill try to load the next tape if the loader is in system mode\n"
	"\t-q | --quiet\n"
	"\t\twill suppress all warning messages\n"
	"\t-t | --type \"standard|load|unload|noop|reload\"\n"
	"\t\tcontrols how the message is displayed:\n"
	"\t\t\tstandard = until the next tape movement (default)\n"
	"\t\t\tload     = until a tape is loaded\n"
	"\t\t\tunload   = until a tape is unloaded\n"
	"\t\t\tnoop     = not at all (test purposes)\n"
	"\t\t\treload   = message1 until tape is unloaded and message2\n"
	"\t\t\t           when the next tape is loaded\n"
	"\n"
	"Note: Characters to be displayed include capital letters (A-Z), "
	"numerics (0-9)\n"
	"and special characters within single quotes. However not all "
	"characters\n"
	"might be displayed on all tape devices. Special characters that "
	"are supported\n"
	"for 3490 are '@$#,./()*&+-=%|:_<>?;'.\n"
	"\n";

int	quiet = 0;

/* end of definitions */

int typename2int(char *name)
{
	char *typenames[] = {
		"standard",
		"unload",
		"load",
		"noop",
		NULL,
		NULL,
		NULL,
		"reload"
	};
	int	i;

	for(i = 0; i < 8; i++) {
		if(typenames[i] == NULL)
			continue;
		if(strcmp(typenames[i], name) == 0) {
			return i;
		}
	}

	fprintf(stderr, "Invalid message type <%s>\n", name);
	return -1;
}

void
strchkcpy(char *tgt, const char *src) {
	static	char *nowarn = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
			       "@$#,./'()*&+-=%:_<>?; ";
	char	c;
	char	warned;

	warned = 0;
	for(c=0; c<8 && *(src+c); c++) {
		*(tgt+c) = toupper(*(src+c));
		if(index(nowarn, *(tgt+c)) == 0 && !quiet && !warned) {
			fprintf(
				stderr,
				"WARNING: Some special characters may not "
				"display on all device types.\n"
			);
			warned = 1;
		}
	}
	*(tgt+c) = '\0';
}

int main(int argc, char *argv[]) {

	char			*options = "hblqt:";
	struct option		 long_options[] = {
		{ "help",	 no_argument,		NULL, 'h' },
		{ "blink",	 no_argument,		NULL, 'b' },
		{ "load",	 no_argument,		NULL, 'l' },
		{ "quiet",	 no_argument,		NULL, 'q' },
		{ "type",	 required_argument,	NULL, 't' },
		{ NULL,		 0,			NULL, 0   }
	};
	char			*pathname;
	int			 c;
	int			 fd, ret = 0;
	struct display_struct	 ds;

	memset(&ds, 0, sizeof(ds));
	ds.cntrl.type = TAPE_MSGTYPE_STANDARD;

	while(
		(c = getopt_long(argc, argv, options, long_options, NULL))
		!= EOF
	) {
		switch(c) {
			case 'h':
				fprintf(stderr, help_text);
				exit(0);
			case 'b':
				ds.cntrl.blink = 1;
				break;
			case 'l':
				ds.cntrl.load_request = 1;
				break;
			case 'q':
				quiet = 1;
				break;
			case 't': {
				int type = typename2int(optarg);

				if(type < 0)
					exit(1);

				ds.cntrl.type = type;
				break;
			}
			default:
				fprintf(stderr, "invalid option(%c)\n", c);
				exit(1);
		}
	}

	if(optind + 2 < argc ) {
		if(
			ds.cntrl.type == TAPE_MSGTYPE_LOAD &&
			ds.cntrl.load_request
		) {
			if(!quiet) {
				fprintf(
					stderr,
					"WARNING: "
					"A <load> message with the "
					"--load option will only "
					"display the first"
					"\nmessage.\n"
				);
			}
		} else if(
			ds.cntrl.type == TAPE_MSGTYPE_UNLOAD_LOAD &&
			ds.cntrl.load_request
		) {
			if(!quiet) {
				fprintf(
					stderr,
					"WARNING: "
					"A <reload> message with the "
					"--load option will only "
					"display the second"
					"\nmessage.\n"
				);
			}
		} else {
			ds.cntrl.alternate = 1;

			if(ds.cntrl.blink) {
				ds.cntrl.blink = 0;
				if(!quiet) {
					fprintf(
						stderr,
						"Alternate messages "
						"override blinking\n"
					);
				}
			}
		}
		strchkcpy(ds.message1, argv[optind]);
		strchkcpy(ds.message2, argv[optind+1]);
		pathname = argv[optind+2];
	} else if(optind + 1 < argc) {
		if(ds.cntrl.type == TAPE_MSGTYPE_UNLOAD_LOAD) {
			fprintf(stderr, "Reload message type requires "
					"two messages.\n");
			exit(1);
		} else if(ds.cntrl.type == TAPE_MSGTYPE_LOAD) {
			strchkcpy(ds.message2, argv[optind]);
		}
		strchkcpy(ds.message1, argv[optind]);
		pathname = argv[optind+1];
	} else {
		fprintf(stderr, help_text);
		exit(1);
	}

	fd = open(pathname, O_RDONLY);
	if (fd < 0) {
	        fprintf(stderr, "Cannot open device %s.\n", pathname);
	        exit(1);
	}

	ret = ioctl(fd, TAPE390_DISPLAY, &ds);
        if (ret != 0)
                fprintf(stderr, "TAPE390_DISPLAY failed\n");

        close(fd);

        return ret;
}







