[BACK]Return to midicat.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / midicat

File: [local] / src / usr.bin / midicat / midicat.c (download)

Revision 1.7, Fri Dec 2 22:36:34 2022 UTC (17 months, 2 weeks ago) by cheloha
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, OPENBSD_7_4_BASE, OPENBSD_7_4, OPENBSD_7_3_BASE, OPENBSD_7_3, HEAD
Changes since 1.6: +19 -33 lines

midicat(1): use err(3) everywhere

This is consistent with style(9) and makes the program shorter, too.

Tweaked by ratchov@.

Link: https://marc.info/?l=openbsd-tech&m=166982129428027&w=2

ok millert@ kn@ ratchov@

/*	$OpenBSD: midicat.c,v 1.7 2022/12/02 22:36:34 cheloha Exp $	*/
/*
 * Copyright (c) 2015 Alexandre Ratchov <alex@caoua.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include <err.h>
#include <fcntl.h>
#include <sndio.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

void __dead usage(void);

int
main(int argc, char **argv)
{
#define MIDI_BUFSZ	1024
	unsigned char buf[MIDI_BUFSZ];
	struct mio_hdl *ih, *oh;
	char *port0, *port1, *ifile, *ofile;
	int ifd, ofd;
	int dump, c, i, len, n, sep, mode;

	dump = 0;
	port0 = port1 = ifile = ofile = NULL;
	ih = oh = NULL;
	ifd = ofd = -1;

	while ((c = getopt(argc, argv, "di:o:q:")) != -1) {
		switch (c) {
		case 'd':
			dump = 1;
			break;
		case 'q':
			if (port0 == NULL)
				port0 = optarg;
			else if (port1 == NULL)
				port1 = optarg;
			else
				errx(1, "too many -q options");
			break;
		case 'i':
			ifile = optarg;
			break;
		case 'o':
			ofile = optarg;
			break;
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (argc != 0)
		usage();

	/* we don't support more than one data flow */
	if (ifile != NULL && ofile != NULL)
		errx(1, "-i and -o are exclusive");

	/* second port makes sense only for port-to-port transfers */
	if (port1 != NULL && !(ifile == NULL && ofile == NULL))
		errx(1, "too many -q options");

	/* if there're neither files nor ports, then we've nothing to do */
	if (port0 == NULL && ifile == NULL && ofile == NULL)
		usage();

	/* if no port specified, use default one */
	if (port0 == NULL)
		port0 = MIO_PORTANY;

	/* open input or output file (if any) */
	if (ifile) {
		if (strcmp(ifile, "-") == 0) {
			ifile = "stdin";
			ifd = STDIN_FILENO;
		} else {
			ifd = open(ifile, O_RDONLY);
			if (ifd == -1)
				err(1, "%s", ifile);
		}
	} else if (ofile) {
		if (strcmp(ofile, "-") == 0) {
			ofile = "stdout";
			ofd = STDOUT_FILENO;
		} else {
			ofd = open(ofile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
			if (ofd == -1)
				err(1, "%s", ofile);
		}
	}

	/* open first port for input and output (if output needed) */
	if (ofile)
		mode = MIO_IN;
	else if (ifile)
		mode = MIO_OUT;
	else if (port1 == NULL)
		mode = MIO_IN | MIO_OUT;
	else
		mode = MIO_IN;
	ih = mio_open(port0, mode, 0);
	if (ih == NULL)
		errx(1, "%s: couldn't open port", port0);

	/* open second port, output only */
	if (port1 == NULL)
		oh = ih;
	else {
		oh = mio_open(port1, MIO_OUT, 0);
		if (oh == NULL)
			errx(1, "%s: couldn't open port", port1);
	}

	if (pledge("stdio", NULL) == -1)
		err(1, "pledge");

	/* transfer until end-of-file or error */
	for (;;) {
		if (ifile != NULL) {
			len = read(ifd, buf, sizeof(buf));
			if (len == 0)
				break;
			if (len == -1) {
				warn("%s", ifile);
				break;
			}
		} else {
			len = mio_read(ih, buf, sizeof(buf));
			if (len == 0) {
				warnx("%s: disconnected", port0);
				break;
			}
		}
		if (ofile != NULL) {
			n = write(ofd, buf, len);
			if (n != len) {
				warn("%s: short write", ofile);
				break;
			}
		} else {
			n = mio_write(oh, buf, len);
			if (n != len) {
				warnx("%s: disconnected", port1);
				break;
			}
		}
		if (dump) {
			for (i = 0; i < len; i++) {
				sep = (i % 16 == 15 || i == len - 1) ?
				    '\n' : ' ';
				fprintf(stderr, "%02x%c", buf[i], sep);
			}
		}
	}

	/* clean-up */
	if (port0)
		mio_close(ih);
	if (port1)
		mio_close(oh);
	if (ifile)
		close(ifd);
	if (ofile)
		close(ofd);
	return 0;
}

void __dead
usage(void)
{
	fprintf(stderr, "usage: midicat [-d] [-i in-file] [-o out-file] "
	    "[-q in-port] [-q out-port]\n");
	exit(1);
}