/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * Copyright (C) IBM Corporation, 2005
 *
 * Author: Vernon Mauery <vernux@us.ibm.com>
 *
 */

#include <stdio.h>
#include <dirent.h>
#include <linux/input.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>

int getopt(int argc, char * const argv[],
		const char *optstring);

extern char *optarg;
extern int optind, opterr, optopt;


char *event_name(char *filename, int err)
{
	int fd = open(filename, O_RDWR);
	if (fd < 0) return NULL;

	char name[256]= "Unknown";
	if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) {
		if (err)
			perror("evdev ioctl");
	}
	close(fd);
	return strdup(name);
}

void usage(char *name, int err)
{
	fprintf(stderr,
		"%s [-h] [-v] [-v] [-p path/to/device | -n \"string name of device\"]\n"
		"Find either the device node for a string or the string for a node.\n"
		"It works by searching /dev/input for a device that reports the correct\n"
		"name via ioctl EVIOCGNAME.  When it finds the device, it prints the path\n"
		"to the device to stdout while all other messages are printed to stderr.\n"
		"You can print the device name for a specific device, e.g.\n"
		"/dev/input/event3 by specifying the path to the device with the -p option.\n"
		"\t-p\tprint out string for this device node\n"
		"\t-n\tprint out device node that matches this string name\n"
		"\t-v\tadd a level of verbosity\n"
		"\t-h\tprint this help message\n", name);
	exit(err);
}
int main(int argc, char *argv[])
{
	int verbose = 0;
	char c;
	int xor = 0;
	char *nodefile = NULL, *nodename = NULL;
	while ((c = getopt (argc, argv, "p:n:vh")) != -1) {
		switch (c) {
		case 'v':
			verbose++;
			break;

		case 'h':
			usage(argv[0], 0);
			break;
		case 'p':
			if (xor)
				usage(argv[0], 2);
			nodefile = optarg;
			xor = 1;
			break;
		case 'n':
			if (xor)
				usage(argv[0], 2);
			nodename = optarg;
			xor = 1;
			break;
		default:
			usage(argv[0], 1);
			break;
		}
	}
	if (!xor)
		usage(argv[0], 3);

	if (nodefile) {
		char *name = event_name(nodefile, verbose >= 1);
		printf("%s\n", name);
		if (verbose >= 1)
			fprintf(stderr, "%s -> %s\n", nodefile, name);
		free(name);
		return 0;
	}
	char dirname[] = "/dev/input";
	DIR *dir = opendir(dirname);
	struct dirent *de;
	char filename[256];
	while ((de = readdir(dir)) != NULL) {
		sprintf(filename, "%s/%s", dirname, de->d_name);
		char *name = event_name(filename, verbose >= 2);
		if (!name)
			continue;
		if (strcmp(name, nodename) == 0) {
			printf("%s\n", filename);
		}
		if (verbose >= 1)
			fprintf(stderr, "%s -> %s\n", de->d_name, name);
		free(name);
	}
	closedir(dir);

	return 0;
}
