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