1/*	$NetBSD: sti.c,v 1.7 2008/04/28 20:24:17 martin Exp $	*/
2
3/*-
4 * Copyright (c) 2005 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31#include <sys/cdefs.h>
32#ifdef __RCSID
33__RCSID("$NetBSD: sti.c,v 1.7 2008/04/28 20:24:17 martin Exp $");
34#endif
35
36#include <sys/param.h>
37#include <sys/ioctl.h>
38#include <ctype.h>
39#include <stdio.h>
40#include <string.h>
41#include <stdlib.h>
42#include <unistd.h>
43#include <fcntl.h>
44#include <err.h>
45#include <errno.h>
46#ifdef __RCSID
47#include <vis.h>
48#else
49#define setprogname(a)
50extern const char *__progname;
51#define getprogname() __progname
52#endif
53
54static int
55unescape(const char **pp, int *state)
56{
57	char ch, out;
58
59#ifdef __RCSID
60	while ((ch = *(*pp)++) != '\0') {
61		switch(unvis(&out, ch, state, 0)) {
62		case 0:
63		case UNVIS_NOCHAR:
64		        break;
65		case UNVIS_VALID:
66			return out;
67		case UNVIS_VALIDPUSH:
68		        (*pp)--;
69			return out;
70		case UNVIS_SYNBAD:
71			errno = EILSEQ;
72			return -1;
73		}
74	}
75	if (unvis(&out, '\0', state, UNVIS_END) == UNVIS_VALID)
76		return out;
77#else
78	switch ((ch = *(*pp)++)) {
79	case '\0':
80		goto out;
81	case '^':
82		ch = *(*pp)++;
83		return CTRL(ch);
84	case '\\':
85		switch (ch = *(*pp)++) {
86		case 'a': return '\a';
87		case 'b': return '\b';
88		case 'e': return '\e';
89		case 'f': return '\f';
90		case 't': return '\t';
91		case 'n': return '\n';
92		case 'r': return '\r';
93		case 'v': return '\v';
94		case '\\': return '\\';
95
96		case '0': case '1': case '2': case '3':
97		case '4': case '5': case '6': case '7':
98			out = 0;
99			if (ch >= '0' && ch < '8') {
100				out = out * 8 + ch - '0';
101				ch = *(*pp)++;
102				if (ch >= '0' && ch < '8') {
103					out = out * 8 + ch - '0';
104					ch = *(*pp)++;
105					if (ch >= '0' && ch < '8')
106						out = out * 8 + ch - '0';
107				}
108			}
109			return out;
110		default:
111		    break;
112		}
113		break;
114	default:
115		return ch;
116	}
117out:
118#endif
119	errno = ENODATA;
120	return -1;
121}
122
123static void
124sti(int fd, int c)
125{
126	char ch = c;
127
128	if (ioctl(fd, TIOCSTI, &ch) == -1)
129		err(1, "Cannot simulate terminal input");
130}
131
132static void
133sendstr(int fd, const char *str)
134{
135	int c, state = 0;
136	const char *ptr = str;
137
138	while ((c = unescape(&ptr, &state)) != -1)
139		sti(fd, c);
140
141	if (c == -1 && errno != ENODATA)
142		warn("Cannot decode `%s'", str);
143}
144
145int
146main(int argc, char *argv[])
147{
148	const char *tty;
149	char ttydev[MAXPATHLEN];
150	int fd;
151
152	setprogname(*argv);
153
154	if (argc < 2) {
155		(void)fprintf(stderr, "Usage: %s <tty> [arg ...]\n",
156		    getprogname());
157		return 1;
158	}
159
160	argc--;
161	argv++;
162
163	tty = *argv++;
164	argc--;
165
166	if (strncmp(tty, "/dev/", 5) == 0)
167		(void)snprintf(ttydev, sizeof(ttydev), "%s", tty);
168	else if (strncmp(tty, "tty", 3) == 0 || strncmp(tty, "pty", 3) == 0 ||
169	    strncmp(tty, "pts/", 4) == 0)
170		(void)snprintf(ttydev, sizeof(ttydev), "/dev/%s", tty);
171	else if (isdigit((unsigned char)*tty))
172		(void)snprintf(ttydev, sizeof(ttydev), "/dev/pts/%s", tty);
173	else
174		(void)snprintf(ttydev, sizeof(ttydev), "/dev/tty%s", tty);
175
176	if ((fd = open(ttydev, O_RDWR)) == -1)
177		err(1, "Cannot open `%s'", ttydev);
178
179	if (argc == 0) {
180		char *line;
181#ifndef __RCSID
182		line = malloc(10240);
183		while (fgets(line, 10240, stdin) != NULL) {
184			char *p;
185			if ((p = strrchr(line, '\n')) != NULL)
186				*p = '\0';
187			sendstr(fd, line);
188		}
189		free(line);
190#else
191		while ((line = fparseln(stdin, NULL, NULL, NULL, 0)) != NULL) {
192			sendstr(fd, line);
193			free(line);
194		}
195#endif
196	} else {
197		for (; argc--; argv++) {
198			sendstr(fd, *argv);
199			if (argc != 0)
200				sti(fd, ' ');
201		}
202	}
203
204	(void)close(fd);
205	return 0;
206}
207