// SPDX-License-Identifier: LGPL-2.1-or-later
/*
 * This file is part of libgpiod.
 *
 * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
 */

#include <getopt.h>
#include <gpiod.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>

#include "tools-common.h"

static const struct option longopts[] = {
	{ "help",	no_argument,		NULL,	'h' },
	{ "version",	no_argument,		NULL,	'v' },
	{ "active-low",	no_argument,		NULL,	'l' },
	{ "bias",	required_argument,	NULL,	'B' },
	{ GETOPT_NULL_LONGOPT },
};

static const char *const shortopts = "+hvlB:";

static void print_help(void)
{
	printf("Usage: %s [OPTIONS] <chip name/number> <offset 1> <offset 2> ...\n",
	       get_progname());
	printf("\n");
	printf("Read line value(s) from a GPIO chip\n");
	printf("\n");
	printf("Options:\n");
	printf("  -h, --help:\t\tdisplay this message and exit\n");
	printf("  -v, --version:\tdisplay the version and exit\n");
	printf("  -l, --active-low:\tset the line active state to low\n");
	printf("  -B, --bias=[as-is|disable|pull-down|pull-up] (defaults to 'as-is'):\n");
	printf("		set the line bias\n");
	printf("\n");
	print_bias_help();
}

int main(int argc, char **argv)
{
	unsigned int *offsets, i, num_lines;
	int *values, optc, opti, rv;
	bool active_low = false;
	int flags = 0;
	char *device, *end;

	for (;;) {
		optc = getopt_long(argc, argv, shortopts, longopts, &opti);
		if (optc < 0)
			break;

		switch (optc) {
		case 'h':
			print_help();
			return EXIT_SUCCESS;
		case 'v':
			print_version();
			return EXIT_SUCCESS;
		case 'l':
			active_low = true;
			break;
		case 'B':
			flags = bias_flags(optarg);
			break;
		case '?':
			die("try %s --help", get_progname());
		default:
			abort();
		}
	}

	argc -= optind;
	argv += optind;

	if (argc < 1)
		die("gpiochip must be specified");

	if (argc < 2)
		die("at least one GPIO line offset must be specified");

	device = argv[0];
	num_lines = argc - 1;

	values = malloc(sizeof(*values) * num_lines);
	offsets = malloc(sizeof(*offsets) * num_lines);
	if (!values || !offsets)
		die("out of memory");

	for (i = 0; i < num_lines; i++) {
		offsets[i] = strtoul(argv[i + 1], &end, 10);
		if (*end != '\0' || offsets[i] > INT_MAX)
			die("invalid GPIO offset: %s", argv[i + 1]);
	}

	rv = gpiod_ctxless_get_value_multiple_ext(device, offsets, values,
						  num_lines, active_low,
						  "gpioget", flags);
	if (rv < 0)
		die_perror("error reading GPIO values");

	for (i = 0; i < num_lines; i++) {
		printf("%d", values[i]);
		if (i != num_lines - 1)
			printf(" ");
	}
	printf("\n");

	free(values);
	free(offsets);

	return EXIT_SUCCESS;
}
