Annotation of src/usr.bin/midicat/midicat.c, Revision 1.6
1.6 ! cheloha 1: /* $OpenBSD: midicat.c,v 1.5 2022/12/02 22:21:35 cheloha Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2015 Alexandre Ratchov <alex@caoua.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: #include <err.h>
18: #include <fcntl.h>
19: #include <sndio.h>
20: #include <stdio.h>
21: #include <stdlib.h>
22: #include <unistd.h>
23: #include <string.h>
24:
1.5 cheloha 25: void __dead usage(void);
1.1 ratchov 26:
27: int
28: main(int argc, char **argv)
29: {
30: #define MIDI_BUFSZ 1024
31: unsigned char buf[MIDI_BUFSZ];
32: struct mio_hdl *ih, *oh;
33: char *port0, *port1, *ifile, *ofile;
34: int ifd, ofd;
35: int dump, c, i, len, n, sep, mode;
36:
37: dump = 0;
38: port0 = port1 = ifile = ofile = NULL;
39: ih = oh = NULL;
40: ifd = ofd = -1;
41:
42: while ((c = getopt(argc, argv, "di:o:q:")) != -1) {
43: switch (c) {
44: case 'd':
45: dump = 1;
46: break;
47: case 'q':
48: if (port0 == NULL)
49: port0 = optarg;
50: else if (port1 == NULL)
51: port1 = optarg;
52: else {
53: fputs("too many -q options\n", stderr);
54: return 1;
55: }
56: break;
57: case 'i':
58: ifile = optarg;
59: break;
60: case 'o':
61: ofile = optarg;
62: break;
63: default:
1.5 cheloha 64: usage();
1.1 ratchov 65: }
66: }
67: argc -= optind;
68: argv += optind;
1.5 cheloha 69:
70: if (argc != 0)
71: usage();
1.1 ratchov 72:
73: /* we don't support more than one data flow */
74: if (ifile != NULL && ofile != NULL) {
75: fputs("-i and -o are exclusive\n", stderr);
76: return 1;
77: }
78:
79: /* second port makes sense only for port-to-port transfers */
80: if (port1 != NULL && !(ifile == NULL && ofile == NULL)) {
81: fputs("too many -q options\n", stderr);
82: return 1;
83: }
84:
85: /* if there're neither files nor ports, then we've nothing to do */
86: if (port0 == NULL && ifile == NULL && ofile == NULL)
1.5 cheloha 87: usage();
1.1 ratchov 88:
89: /* if no port specified, use default one */
90: if (port0 == NULL)
91: port0 = MIO_PORTANY;
92:
93: /* open input or output file (if any) */
94: if (ifile) {
1.6 ! cheloha 95: if (strcmp(ifile, "-") == 0) {
! 96: ifile = "stdin";
1.1 ratchov 97: ifd = STDIN_FILENO;
1.6 ! cheloha 98: } else {
1.3 deraadt 99: ifd = open(ifile, O_RDONLY);
1.2 deraadt 100: if (ifd == -1) {
1.1 ratchov 101: perror(ifile);
102: return 1;
103: }
104: }
105: } else if (ofile) {
1.6 ! cheloha 106: if (strcmp(ofile, "-") == 0) {
! 107: ofile = "stdout";
1.1 ratchov 108: ofd = STDOUT_FILENO;
1.6 ! cheloha 109: } else {
1.1 ratchov 110: ofd = open(ofile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
1.2 deraadt 111: if (ofd == -1) {
1.1 ratchov 112: perror(ofile);
113: return 1;
114: }
115: }
116: }
117:
118: /* open first port for input and output (if output needed) */
119: if (ofile)
120: mode = MIO_IN;
121: else if (ifile)
122: mode = MIO_OUT;
123: else if (port1 == NULL)
124: mode = MIO_IN | MIO_OUT;
125: else
126: mode = MIO_IN;
127: ih = mio_open(port0, mode, 0);
128: if (ih == NULL) {
129: fprintf(stderr, "%s: couldn't open port\n", port0);
130: return 1;
131: }
132:
133: /* open second port, output only */
134: if (port1 == NULL)
135: oh = ih;
136: else {
137: oh = mio_open(port1, MIO_OUT, 0);
138: if (oh == NULL) {
139: fprintf(stderr, "%s: couldn't open port\n", port1);
140: exit(1);
141: }
142: }
143:
1.2 deraadt 144: if (pledge("stdio", NULL) == -1)
1.1 ratchov 145: err(1, "pledge");
146:
147: /* transfer until end-of-file or error */
148: for (;;) {
149: if (ifile != NULL) {
150: len = read(ifd, buf, sizeof(buf));
151: if (len == 0)
152: break;
1.2 deraadt 153: if (len == -1) {
1.1 ratchov 154: perror("stdin");
155: break;
156: }
157: } else {
158: len = mio_read(ih, buf, sizeof(buf));
159: if (len == 0) {
160: fprintf(stderr, "%s: disconnected\n", port0);
161: break;
162: }
163: }
164: if (ofile != NULL) {
165: n = write(ofd, buf, len);
166: if (n != len) {
167: fprintf(stderr, "%s: short write\n", ofile);
168: break;
169: }
170: } else {
171: n = mio_write(oh, buf, len);
172: if (n != len) {
173: fprintf(stderr, "%s: disconnected\n", port1);
174: break;
175: }
176: }
177: if (dump) {
178: for (i = 0; i < len; i++) {
179: sep = (i % 16 == 15 || i == len - 1) ?
180: '\n' : ' ';
181: fprintf(stderr, "%02x%c", buf[i], sep);
182: }
183: }
184: }
185:
186: /* clean-up */
187: if (port0)
188: mio_close(ih);
189: if (port1)
190: mio_close(oh);
191: if (ifile)
192: close(ifd);
193: if (ofile)
194: close(ofd);
195: return 0;
1.5 cheloha 196: }
197:
198: void __dead
199: usage(void)
200: {
201: fprintf(stderr, "usage: midicat [-d] [-i in-file] [-o out-file] "
202: "[-q in-port] [-q out-port]\n");
203: exit(1);
1.1 ratchov 204: }