dterm-nuc

annotate dterm.c @ 2:68e6bdd9c9df

minor copyright message adjustment
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 08 Apr 2017 00:00:47 +0300
parents ad098a33fd34
children
rev   line source
nuclear@2 1 /* dterm - Dumb terminal program
nuclear@0 2 * Copyright 2007 Knossos Networks Ltd.
nuclear@0 3 * Copyright 2017 John Tsiombikas <nuclear@member.fsf.org>
nuclear@0 4 *
nuclear@0 5 * This program is free software; you can redistribute it and/or
nuclear@0 6 * modify it under the terms of the GNU General Public License version 2
nuclear@0 7 * as published by the Free Software Foundation.
nuclear@0 8 *
nuclear@0 9 * This program is distributed in the hope that it will be useful,
nuclear@0 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nuclear@0 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
nuclear@0 12 * GNU General Public License
nuclear@0 13 *
nuclear@0 14 * You should have received a copy of the GNU General Public License
nuclear@0 15 * along with this program; if not, write to the Free Software
nuclear@0 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
nuclear@0 17 * 02110-1301, USA.
nuclear@0 18 */
nuclear@0 19
nuclear@0 20 #ifndef VERSION
nuclear@0 21 #define VERSION "unknown"
nuclear@0 22 #endif
nuclear@0 23 #define COPYRIGHT \
nuclear@2 24 "dterm version " VERSION "\n" \
nuclear@2 25 "Copyright 2007 Knossos Networks Ltd.\n" \
nuclear@2 26 "Copyright 2017 John Tsiombikas <nuclear@member.fsf.org>\n" \
nuclear@0 27 "\n" \
nuclear@0 28 "This program is free software; you can redistribute it and/or\n" \
nuclear@0 29 "modify it under the terms of the GNU General Public License version 2\n" \
nuclear@0 30 "as published by the Free Software Foundation.\n" \
nuclear@0 31 "\n" \
nuclear@0 32 "This program is distributed in the hope that it will be useful,\n" \
nuclear@0 33 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
nuclear@0 34 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \
nuclear@0 35 "GNU General Public License for more details.\n" \
nuclear@0 36 "\n" \
nuclear@0 37 "You should have received a copy of the GNU General Public License\n" \
nuclear@0 38 "along with this program; if not, write to the Free Software\n" \
nuclear@0 39 "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\n" \
nuclear@0 40 "02110-1301, USA.\n"
nuclear@0 41
nuclear@0 42
nuclear@0 43 #include <stdio.h>
nuclear@0 44 #include <ctype.h>
nuclear@0 45 #include <sys/types.h>
nuclear@0 46 #include <sys/signal.h>
nuclear@0 47 #include <sys/stat.h>
nuclear@0 48 #include <sys/wait.h>
nuclear@0 49 #include <fcntl.h>
nuclear@0 50 #include <termios.h>
nuclear@0 51 #include <string.h>
nuclear@0 52 #include <unistd.h>
nuclear@0 53 #include <stdlib.h>
nuclear@0 54 #include <time.h>
nuclear@0 55 #include <signal.h>
nuclear@0 56 #include <sys/select.h>
nuclear@0 57 #include <sys/stat.h>
nuclear@0 58 #include <sys/ioctl.h>
nuclear@0 59 #include <errno.h>
nuclear@0 60
nuclear@0 61 #define FIXTTY if(istty) tcsetattr(0, TCSADRAIN, &savetio)
nuclear@0 62 #define DIEP(s) { FIXTTY; perror(s); exit(1); }
nuclear@0 63 #define DIE(s,m) { FIXTTY; fprintf(stderr, "%s: %s\n", s, m); exit(1); }
nuclear@0 64
nuclear@0 65 /*
nuclear@0 66 Sigh
nuclear@0 67 */
nuclear@0 68 #ifndef CCTS_OFLOW
nuclear@0 69 #ifdef CRTSCTS
nuclear@0 70 #define CCTS_OFLOW CRTSCTS
nuclear@0 71 #endif /* CRTSCTS */
nuclear@0 72 #endif /* ! CCTS_OFLOW */
nuclear@0 73
nuclear@0 74
nuclear@0 75 /*
nuclear@0 76 Valid speed settings.
nuclear@0 77 */
nuclear@0 78 static struct { int s, c; } speeds[] = {
nuclear@0 79 { 50, B50 },
nuclear@0 80 { 75, B75 },
nuclear@0 81 { 110, B110 },
nuclear@0 82 { 134, B134 },
nuclear@0 83 { 150, B150 },
nuclear@0 84 { 200, B200 },
nuclear@0 85 { 300, B300 },
nuclear@0 86 { 600, B600 },
nuclear@0 87 { 1200, B1200 },
nuclear@0 88 { 1800, B1800 },
nuclear@0 89 { 2400, B2400 },
nuclear@0 90 { 4800, B4800 },
nuclear@0 91 { 9600, B9600 },
nuclear@0 92 { 19200, B19200 },
nuclear@0 93 { 38400, B38400 },
nuclear@0 94 #ifdef B7200
nuclear@0 95 { 7200, B7200 },
nuclear@0 96 #endif
nuclear@0 97 #ifdef B14400
nuclear@0 98 { 14400, B14400 },
nuclear@0 99 #endif
nuclear@0 100 #ifdef B28800
nuclear@0 101 { 28800, B28800 },
nuclear@0 102 #endif
nuclear@0 103 #ifdef B57600
nuclear@0 104 { 57600, B57600 },
nuclear@0 105 #endif
nuclear@0 106 #ifdef B76800
nuclear@0 107 { 76800, B76800 },
nuclear@0 108 #endif
nuclear@0 109 #ifdef B115200
nuclear@0 110 { 115200, B115200 },
nuclear@0 111 #endif
nuclear@0 112 #ifdef B230400
nuclear@0 113 { 230400, B230400 },
nuclear@0 114 #endif
nuclear@0 115 #ifdef B460800
nuclear@0 116 { 460800, B460800 },
nuclear@0 117 #endif
nuclear@0 118 #ifdef B921600
nuclear@0 119 { 921600, B921600 },
nuclear@0 120 #endif
nuclear@0 121 { 0, 0 }};
nuclear@0 122
nuclear@0 123
nuclear@0 124 /*
nuclear@0 125 Save the terminal settings here
nuclear@0 126 */
nuclear@0 127 static struct termios intio, savetio;
nuclear@0 128
nuclear@0 129 static int fd = -1; /* Channel to port */
nuclear@0 130 static int cmdchar = 035; /* Command character, default ^] */
nuclear@0 131 static char *device = 0; /* Device, no default */
nuclear@0 132 static int ispeed = B9600; /* Input speed, default 9600 bps */
nuclear@0 133 static int ospeed = B9600; /* Output speed, default 9600 bps */
nuclear@0 134 static int twostop = 0; /* Stop bits, if set to CSTOPB, use two */
nuclear@0 135 static int parity = 0; /* Parity, -1 = mark, -2 = space 0=none */
nuclear@0 136 /* PARENB enables parity, PARODD = odd */
nuclear@0 137 static int bits = CS8; /* CS5-CS8 for 5-8 bits per character */
nuclear@0 138 static int ctsflow = 0; /* CCTS_OFLOW enables CTS flow control */
nuclear@0 139 static int xonflow = 0; /* IXON | IXOFF for in & out soft F/c */
nuclear@0 140 static int modemcontrol = 0; /* Set to HUPCLto enable modem control */
nuclear@0 141 static int markparity = 0; /* Mark parity -- set high bit on out */
nuclear@0 142 static int backspace = 0; /* Backspace char, send on BS or DEL */
nuclear@0 143 static int maplf = 0; /* If set, map LF to CR */
nuclear@0 144 static int ignorecr = 0; /* Ignore carriage returns */
nuclear@0 145 static int crlf = 0; /* Send CRLF on CR */
nuclear@0 146 static int istty; /* Result of isatty() */
nuclear@0 147 static char *connname = 0; /* Connection name found in config */
nuclear@0 148 static int sendbreak = 0; /* Break requested */
nuclear@0 149 static int modem = 0; /* Current modem status */
nuclear@0 150 static int setmodem = 0; /* Set modem status to this */
nuclear@0 151 static int delay = 0; /* Millisecond delay after each key */
nuclear@0 152 static int linedelay = 0; /* Millisecond delay after each CR */
nuclear@0 153 static int showspecial = 0; /* Show special chars as [xx] */
nuclear@0 154
nuclear@0 155 static void
nuclear@0 156 help() {
nuclear@0 157 fprintf(stderr,
nuclear@0 158 "dterm commands:\n"
nuclear@0 159 "^%c Enter command mode quit, q Exit\n"
nuclear@0 160 "show Display configuration help, h, ? Display this message\n"
nuclear@0 161 "!<command> Execute shell command version Display version\n"
nuclear@0 162 "@<filename> Get configuration from <filename>\n"
nuclear@0 163 "<device> Connect to <device> 300,1200,9600 Set speed\n"
nuclear@0 164 "5, 6, 7, 8 Set bits per character 1, 2 Set stop bits\n"
nuclear@0 165 "e, o, n, m, s Set parity"
nuclear@0 166 #ifdef CCTS_OFLOW
nuclear@0 167 " cts,nocts Enable / disable CTS\n"
nuclear@0 168 #else
nuclear@0 169 "\n"
nuclear@0 170 #endif
nuclear@0 171 "dtr, nodtr Raise / lower DTR b Send a 500ms break\n"
nuclear@0 172 "rts, norts Raise / lower RTS d, r Toggle DTR, RTS\n"
nuclear@0 173 "rx <filename> Receive file (XMODEM) sx <filename> Send file (XMODEM)\n"
nuclear@0 174 "rz Receive file (ZMODEM) sz <filename> Send file (ZMODEM)\n"
nuclear@0 175 "xon,noxon Enable / disable XON/XOFF flow control\n"
nuclear@0 176 "modem Hang up modem on exit, exit if modem hangs up\n"
nuclear@0 177 "nomodem Do not do modem control\n"
nuclear@0 178 "bs, nobs Enable / disable mapping of Delete to Backspace\n"
nuclear@0 179 "del, nodel Enable / disable mapping of Backspace to Delete\n"
nuclear@0 180 "maplf, nomaplf Enable / disable mapping of LF to CR\n"
nuclear@0 181 "igncr, noigncr Ignore / output carriage returns\n"
nuclear@0 182 "crlf, nocrlf Enable / disable sending LF after each CR\n"
nuclear@0 183 "delay=<n> Add delay of <n> ms after each charachter sent\n"
nuclear@0 184 "crwait=<n> Add delay of <n> ms after each line sent\n"
nuclear@0 185 "esc=<c> Set command mode character to Ctrl/<c>\n"
nuclear@0 186 "ctrl,hex,noctrl Show control characters as ^n (except tab, CR, LF)\n"
nuclear@0 187
nuclear@0 188
nuclear@0 189
nuclear@0 190 , cmdchar + '@');
nuclear@0 191 }
nuclear@0 192
nuclear@0 193
nuclear@0 194
nuclear@0 195
nuclear@0 196 /*
nuclear@0 197 Show current setup
nuclear@0 198 */
nuclear@0 199 static void
nuclear@0 200 showsetup() {
nuclear@0 201 int i;
nuclear@0 202 fprintf(stderr, "Port: %s\n", device);
nuclear@0 203 fprintf(stderr, "Communications parameters: ");
nuclear@0 204 for(i = 0; speeds[i].s && speeds[i].c != ispeed; )
nuclear@0 205 i++;
nuclear@0 206 fprintf(stderr, "%d", speeds[i].s);
nuclear@0 207 if(ospeed != ispeed) {
nuclear@0 208 for(i = 0; speeds[i].s && speeds[i].c != ospeed; )
nuclear@0 209 i++;
nuclear@0 210 fprintf(stderr, "/%d", speeds[i].s);
nuclear@0 211 }
nuclear@0 212 if(bits == CS5) fprintf(stderr, " 5");
nuclear@0 213 if(bits == CS6) fprintf(stderr, " 6");
nuclear@0 214 if(bits == CS7) fprintf(stderr, " 7");
nuclear@0 215 if(bits == CS8) fprintf(stderr, " 8");
nuclear@0 216 if(parity == 0) fprintf(stderr, " n");
nuclear@0 217 if(parity == PARENB) fprintf(stderr, " e");
nuclear@0 218 if(parity == (PARENB|PARODD)) fprintf(stderr, " o");
nuclear@0 219 if(parity == -1) fprintf(stderr, " m");
nuclear@0 220 if(parity == -2) fprintf(stderr, " s");
nuclear@0 221 if(twostop) fprintf(stderr, " 2\n");
nuclear@0 222 else fprintf(stderr, " 1\n");
nuclear@0 223 fprintf(stderr, "Flow/modem control:");
nuclear@0 224 if(xonflow) fprintf(stderr, " xon");
nuclear@0 225 if(ctsflow) fprintf(stderr, " cts");
nuclear@0 226 if(modemcontrol)fprintf(stderr, " modem");
nuclear@0 227 putc('\n', stderr);
nuclear@0 228 fprintf(stderr, "Character mappings:");
nuclear@0 229 if(backspace == 8) fprintf(stderr, " bs");
nuclear@0 230 if(backspace == 127) fprintf(stderr, " del");
nuclear@0 231 if(maplf) fprintf(stderr, " maplf");
nuclear@0 232 if(ignorecr) fprintf(stderr, " igncr");
nuclear@0 233 if(crlf) fprintf(stderr, " crlf");
nuclear@0 234 if(showspecial == 1) fprintf(stderr, " ctrl");
nuclear@0 235 if(showspecial == 2) fprintf(stderr, " hex");
nuclear@0 236 putc('\n', stderr);
nuclear@0 237 printf("Modem control: DTR: %s RTS: %s CTS: %s DSR: %s DCD: %s\n",
nuclear@0 238 setmodem & TIOCM_DTR ? "on" : "off",
nuclear@0 239 setmodem & TIOCM_RTS ? "on" : "off",
nuclear@0 240 modem & TIOCM_CTS ? "on" : "off",
nuclear@0 241 modem & TIOCM_DSR ? "on" : "off",
nuclear@0 242 modem & TIOCM_CD ? "on" : "off");
nuclear@0 243 fprintf(stderr, "Escape character: ^%c\n", cmdchar + '@');
nuclear@0 244 fflush(stderr);
nuclear@0 245 }
nuclear@0 246
nuclear@0 247
nuclear@0 248 /*
nuclear@0 249 Use the rzsz or lrzsz package to do file transfer
nuclear@0 250 Mode should be "rx", "rb" or "rz" to receive a file, "sx", "sb" or "sz"
nuclear@0 251 to send. "rz" & "rb" don't require a file name; the others do.
nuclear@0 252 */
nuclear@0 253 static int
nuclear@0 254 rzsz(char *mode, char *file) {
nuclear@0 255 static char *loc[] = { "/usr/bin/", "/usr/local/bin/l",
nuclear@0 256 "/usr/bin/l", "/usr/local/bin/", 0 };
nuclear@0 257 char path[128];
nuclear@0 258 char *cmd;
nuclear@0 259 int i;
nuclear@0 260 struct stat sb;
nuclear@0 261 pid_t pid;
nuclear@0 262
nuclear@0 263 /*
nuclear@0 264 Check file name
nuclear@0 265 */
nuclear@0 266 if(*file == 0 && (mode[0] != 'r' || mode[1] == 'x')) {
nuclear@0 267 fprintf(stderr, "File name required for %c%c\n",
nuclear@0 268 mode[0], mode[1]);
nuclear@0 269 return -1;
nuclear@0 270 }
nuclear@0 271
nuclear@0 272 /*
nuclear@0 273 Find the appropriate command
nuclear@0 274 */
nuclear@0 275 for(i = 0; loc[i]; i++) {
nuclear@0 276 if(mode[1] == 'a') {
nuclear@0 277 sprintf(path, "%sascii-xfr", loc[i]);
nuclear@0 278 } else {
nuclear@0 279 sprintf(path, "%s%c%c", loc[i], mode[0], mode[1]);
nuclear@0 280 }
nuclear@0 281 if(!stat(path, &sb) && (sb.st_mode & S_IXUSR))
nuclear@0 282 break;
nuclear@0 283 }
nuclear@0 284 if(!loc[i]) {
nuclear@0 285 fprintf(stderr, "RZ/SZ/ascii-xfr not installed\n");
nuclear@0 286 return -1;
nuclear@0 287 }
nuclear@0 288
nuclear@0 289 /*
nuclear@0 290 Get the command name
nuclear@0 291 */
nuclear@0 292 cmd = strrchr(path, '/');
nuclear@0 293 if(cmd) cmd++;
nuclear@0 294 else cmd = path;
nuclear@0 295
nuclear@0 296 /*
nuclear@0 297 Fork subprocess. Set stdin & stdout to the serial line
nuclear@0 298 stderr remains on the console for progress messages
nuclear@0 299 */
nuclear@0 300 pid = fork();
nuclear@0 301 if(pid == 0) {
nuclear@0 302 dup2(fd, 0);
nuclear@0 303 dup2(fd, 1);
nuclear@0 304 if(mode[1] == 'a') {
nuclear@0 305 char delay_str[64];
nuclear@0 306 sprintf(delay_str, "%d", linedelay);
nuclear@0 307 if(*file) execl(path, cmd, "-s", "-l", delay_str, file, NULL);
nuclear@0 308 else execl(path, cmd, "-r", NULL);
nuclear@0 309 } else {
nuclear@0 310 if(*file) execl(path, cmd, file, NULL);
nuclear@0 311 else execl(path, cmd, NULL);
nuclear@0 312 }
nuclear@0 313 _exit(127);
nuclear@0 314 }
nuclear@0 315 else if(pid == -1) {
nuclear@0 316 perror("fork");
nuclear@0 317 return -1;
nuclear@0 318 }
nuclear@0 319
nuclear@0 320 /*
nuclear@0 321 Wait for the process to complete and give a meaningful
nuclear@0 322 response
nuclear@0 323 */
nuclear@0 324 signal(SIGINT, SIG_IGN);
nuclear@0 325 signal(SIGQUIT, SIG_IGN);
nuclear@0 326 signal(SIGTERM, SIG_IGN);
nuclear@0 327 while(waitpid(pid, &i, 0) != pid) {}
nuclear@0 328 signal(SIGINT, SIG_DFL);
nuclear@0 329 signal(SIGQUIT, SIG_DFL);
nuclear@0 330 signal(SIGTERM, SIG_DFL);
nuclear@0 331
nuclear@0 332 if(WIFSIGNALED(i)) {
nuclear@0 333 fprintf(stderr, "Terminated on signal %d%s\n", WTERMSIG(i),
nuclear@0 334 WCOREDUMP(i) ? " (core dumped)" : "");
nuclear@0 335 return -1;
nuclear@0 336 }
nuclear@0 337 if(WTERMSIG(i))
nuclear@0 338 return -1;
nuclear@0 339 return 0;
nuclear@0 340 }
nuclear@0 341
nuclear@0 342
nuclear@0 343
nuclear@0 344 static int readconfig(char *, char *);
nuclear@0 345
nuclear@0 346 /*
nuclear@0 347 Process commands passed as strings, may be several commands on a line
nuclear@0 348 Allow ugliness like 8n1 -- treat as 8, n, 1
nuclear@0 349 */
nuclear@0 350 static int
nuclear@0 351 setup(char *s, char *cffile, int cfline) {
nuclear@0 352 char *t, *d;
nuclear@0 353 int j,k;
nuclear@0 354 int ret = 0;
nuclear@0 355 struct stat sb;
nuclear@0 356 char ttybuf[128];
nuclear@0 357 int justospeed = 0;
nuclear@0 358
nuclear@0 359 while(*s) {
nuclear@0 360 /*
nuclear@0 361 Skip whitespace, commas
nuclear@0 362 */
nuclear@0 363 while(isspace(*s) || *s == ',')
nuclear@0 364 s++;
nuclear@0 365 if(!*s) break;
nuclear@0 366
nuclear@0 367 /*
nuclear@0 368 '?' = help
nuclear@0 369 */
nuclear@0 370 if(*s == '?') {
nuclear@0 371 help();
nuclear@0 372 return -4;
nuclear@0 373 }
nuclear@0 374
nuclear@0 375 /*
nuclear@0 376 '!' = shell command
nuclear@0 377 */
nuclear@0 378 if(*s == '!') {
nuclear@0 379 if((t = strchr(s, '\n')))
nuclear@0 380 *t = 0;
nuclear@0 381 system(++s);
nuclear@0 382 break;
nuclear@0 383 }
nuclear@0 384
nuclear@0 385 /*
nuclear@0 386 File transfer (sx, sz, rx, rz, sa, ra)
nuclear@0 387 Run rzsz or ascii-xfr to perform the actual file transfer
nuclear@0 388 Allow "sxfilename", "sx filename" or just "rz"
nuclear@0 389 */
nuclear@0 390 if((s[0] == 's' || s[0] == 'r') &&
nuclear@0 391 (s[1] == 'x' || s[1] == 'z' || s[1] == 'a')) {
nuclear@0 392 if((t = strchr(s, '\n')))
nuclear@0 393 *t = 0;
nuclear@0 394 for(t = s + 2; isspace(*t); ) t++;
nuclear@0 395 return rzsz(s, t);
nuclear@0 396 }
nuclear@0 397
nuclear@0 398 /*
nuclear@0 399 If a number, process it.
nuclear@0 400 If it's a valid speed, use that -- if nnn/mmm, set both to nnn
nuclear@0 401 for the first time, and flag things so mmm just sets ospeed
nuclear@0 402 5-8 = data bits, 1,2 sets stops
nuclear@0 403 Anything else is error
nuclear@0 404 */
nuclear@0 405 if(isdigit(*s)) {
nuclear@0 406 j = strtol(s, &s, 10);
nuclear@0 407 for(k = 1; speeds[k].s; k++)
nuclear@0 408 if(speeds[k].s == j)
nuclear@0 409 break;
nuclear@0 410 if(speeds[k].s) {
nuclear@0 411 ospeed = speeds[k].c;
nuclear@0 412 if(!justospeed)
nuclear@0 413 ispeed = ospeed;
nuclear@0 414 if(*s == '/') {
nuclear@0 415 s++;
nuclear@0 416 justospeed = 1;
nuclear@0 417 }
nuclear@0 418 else justospeed = 0;
nuclear@0 419 }
nuclear@0 420 else if(j == 5) bits = CS5;
nuclear@0 421 else if(j == 6) bits = CS6;
nuclear@0 422 else if(j == 7) bits = CS7;
nuclear@0 423 else if(j == 8) bits = CS8;
nuclear@0 424 else if(j == 1) twostop = 0;
nuclear@0 425 else if(j == 2) twostop = CSTOPB;
nuclear@0 426 else {
nuclear@0 427 if(cffile)
nuclear@0 428 fprintf(stderr, "in %s:%d: ",
nuclear@0 429 cffile, cfline);
nuclear@0 430 fprintf(stderr, "%d: invalid speed/bits\n", j);
nuclear@0 431 ret = -1;
nuclear@0 432 }
nuclear@0 433 }
nuclear@0 434
nuclear@0 435 /*
nuclear@0 436 Otherwise, get the alpha-only keyword, see if it matches anything
nuclear@0 437 useful.
nuclear@0 438 */
nuclear@0 439 else {
nuclear@0 440 t = s;
nuclear@0 441 while(isalpha(*t)) t++;
nuclear@0 442 j = *t;
nuclear@0 443 *t = 0;
nuclear@0 444 if( !strcasecmp(s, "xon"))
nuclear@0 445 xonflow = IXON | IXOFF;
nuclear@0 446 else if(!strcasecmp(s, "noxon"))
nuclear@0 447 xonflow = 0;
nuclear@0 448
nuclear@0 449 #ifdef CCTS_OFLOW
nuclear@0 450 else if(!strcasecmp(s, "cts"))
nuclear@0 451 ctsflow = CCTS_OFLOW;
nuclear@0 452 else if(!strcasecmp(s, "nocts"))
nuclear@0 453 ctsflow = 0;
nuclear@0 454 #endif
nuclear@0 455 else if(!strcasecmp(s, "modem"))
nuclear@0 456 modemcontrol = HUPCL;
nuclear@0 457 else if(!strcasecmp(s, "nomodem"))
nuclear@0 458 modemcontrol = 0;
nuclear@0 459 else if(!strcasecmp(s, "E"))
nuclear@0 460 parity = PARENB;
nuclear@0 461 else if(!strcasecmp(s, "O"))
nuclear@0 462 parity = PARENB | PARODD;
nuclear@0 463 else if(!strcasecmp(s, "M"))
nuclear@0 464 parity = -1;
nuclear@0 465 else if(!strcasecmp(s, "S"))
nuclear@0 466 parity = -2;
nuclear@0 467 else if(!strcasecmp(s, "N"))
nuclear@0 468 parity = 0;
nuclear@0 469 else if(!strcasecmp(s, "q") || !strcasecmp(s, "quit"))
nuclear@0 470 ret = -3;
nuclear@0 471 else if(!strcasecmp(s, "h") || !strcasecmp(s, "help"))
nuclear@0 472 help();
nuclear@0 473 else if(!strcasecmp(s, "del"))
nuclear@0 474 backspace = 127;
nuclear@0 475 else if(!strcasecmp(s, "bs"))
nuclear@0 476 backspace = 8;
nuclear@0 477 else if(!strcasecmp(s,"nobs") || !strcasecmp(s,"nodel"))
nuclear@0 478 backspace = 0;
nuclear@0 479 else if(!strcasecmp(s, "noesc"))
nuclear@0 480 cmdchar = 0;
nuclear@0 481 else if(!strcasecmp(s, "maplf"))
nuclear@0 482 maplf = 1;
nuclear@0 483 else if(!strcasecmp(s, "nomaplf"))
nuclear@0 484 maplf = 0;
nuclear@0 485 else if(!strcasecmp(s, "igncr"))
nuclear@0 486 ignorecr = 1;
nuclear@0 487 else if(!strcasecmp(s, "noigncr"))
nuclear@0 488 ignorecr = 0;
nuclear@0 489 else if(!strcasecmp(s, "crlf"))
nuclear@0 490 crlf = 1;
nuclear@0 491 else if(!strcasecmp(s, "nocrlf"))
nuclear@0 492 crlf = 0;
nuclear@0 493 else if(!strcasecmp(s, "b"))
nuclear@0 494 sendbreak = 1;
nuclear@0 495 else if(!strcasecmp(s, "d"))
nuclear@0 496 setmodem ^= TIOCM_DTR;
nuclear@0 497 else if(!strcasecmp(s, "r"))
nuclear@0 498 setmodem ^= TIOCM_RTS;
nuclear@0 499 else if(!strcasecmp(s, "dtr"))
nuclear@0 500 setmodem |= TIOCM_DTR;
nuclear@0 501 else if(!strcasecmp(s, "rts"))
nuclear@0 502 setmodem |= TIOCM_RTS;
nuclear@0 503 else if(!strcasecmp(s, "nodtr"))
nuclear@0 504 setmodem &= ~TIOCM_DTR;
nuclear@0 505 else if(!strcasecmp(s, "norts"))
nuclear@0 506 setmodem &= ~TIOCM_RTS;
nuclear@0 507 else if(!strcasecmp(s, "show"))
nuclear@0 508 showsetup();
nuclear@0 509 else if(!strcasecmp(s, "version"))
nuclear@0 510 fputs(COPYRIGHT, stderr);
nuclear@0 511 else if(!strcasecmp(s, "ctrl"))
nuclear@0 512 showspecial = 1;
nuclear@0 513 else if(!strcasecmp(s, "hex"))
nuclear@0 514 showspecial = 2;
nuclear@0 515 else if(!strcasecmp(s, "noctrl") ||
nuclear@0 516 !strcasecmp(s, "noctrl"))
nuclear@0 517 showspecial = 0;
nuclear@0 518
nuclear@0 519 /*
nuclear@0 520 No?
nuclear@0 521 @<filename> includes a file
nuclear@0 522 !cmd Run a command
nuclear@0 523 esc=c sets escape char
nuclear@0 524 <device> select device
nuclear@0 525 */
nuclear@0 526 else {
nuclear@0 527 *t = j;
nuclear@0 528 while(*t && !isspace(*t) && *t != ',')
nuclear@0 529 t++;
nuclear@0 530 j = *t;
nuclear@0 531 *t = 0;
nuclear@0 532 if(*s == '@') {
nuclear@0 533 k = readconfig(++s, 0);
nuclear@0 534 if(k == -2) {
nuclear@0 535 if(cffile)
nuclear@0 536 fprintf(stderr,
nuclear@0 537 "in %s:%d: ",
nuclear@0 538 cffile, cfline);
nuclear@0 539 fprintf(stderr, "%s: %s\n",
nuclear@0 540 s, strerror(errno));
nuclear@0 541 ret = -1;
nuclear@0 542 }
nuclear@0 543 goto next;
nuclear@0 544 }
nuclear@0 545 if(!strncasecmp(s, "esc=", 4)) {
nuclear@0 546 cmdchar = s[4] & 0x1f;
nuclear@0 547 goto next;
nuclear@0 548 }
nuclear@0 549 else if(!strncasecmp(s, "delay=", 6)) {
nuclear@0 550 delay = atoi(s+6);
nuclear@0 551 goto next;
nuclear@0 552 }
nuclear@0 553 else if(!strncasecmp(s, "crwait=", 7)) {
nuclear@0 554 linedelay = atoi(s+7);
nuclear@0 555 goto next;
nuclear@0 556 }
nuclear@0 557 d = s;
nuclear@0 558 k = stat(d, &sb);
nuclear@0 559 if(k && *d != '/') {
nuclear@0 560 sprintf(ttybuf, "/dev/%.100s", d);
nuclear@0 561 d = ttybuf;
nuclear@0 562 k = stat(d, &sb);
nuclear@0 563 }
nuclear@0 564 if(!k) {
nuclear@0 565 if((sb.st_mode & S_IFMT) == S_IFCHR) {
nuclear@0 566 ret = 1;
nuclear@0 567 device = strdup(d);
nuclear@0 568 goto next;
nuclear@0 569 }
nuclear@0 570 }
nuclear@0 571 if(cffile)
nuclear@0 572 fprintf(stderr, "in %s:%d: ",
nuclear@0 573 cffile, cfline);
nuclear@0 574 fprintf(stderr,
nuclear@0 575 "%s: unrecognised keyword/device\n", s);
nuclear@0 576 ret = -1;
nuclear@0 577 }
nuclear@0 578 next: *t = j;
nuclear@0 579 s = t;
nuclear@0 580 }
nuclear@0 581 }
nuclear@0 582 return ret;
nuclear@0 583 }
nuclear@0 584
nuclear@0 585
nuclear@0 586 /*
nuclear@0 587 Read a config file
nuclear@0 588 Input lines can be lists of config words, or in the form
nuclear@0 589 name: words
nuclear@0 590 If name: form, only lines matching passed name are used
nuclear@0 591 */
nuclear@0 592 static int
nuclear@0 593 readconfig(char *file, char *name) {
nuclear@0 594 char buf[1024];
nuclear@0 595 FILE *f;
nuclear@0 596 char *s, *t;
nuclear@0 597 int lineno = 0;
nuclear@0 598 int ret = 0, r;
nuclear@0 599
nuclear@0 600 /*
nuclear@0 601 ~/file = get file from $HOME/file
nuclear@0 602 */
nuclear@0 603 if(*file == '~' && file[1] == '/' && (s = getenv("HOME"))) {
nuclear@0 604 snprintf(buf, sizeof(buf), "%s/%s", s, file+2);
nuclear@0 605 file = buf;
nuclear@0 606 }
nuclear@0 607
nuclear@0 608 /*
nuclear@0 609 Return -2 if can't open
nuclear@0 610 */
nuclear@0 611 f = fopen(file, "r");
nuclear@0 612 if(!f) return -2;
nuclear@0 613
nuclear@0 614 /*
nuclear@0 615 Read input, strip # commends
nuclear@0 616 Count lines
nuclear@0 617 Keep track of return code
nuclear@0 618 */
nuclear@0 619 while(fgets(buf, sizeof(buf), f)) {
nuclear@0 620 lineno++;
nuclear@0 621 if((s = strchr(buf, '#')))
nuclear@0 622 *s = 0;
nuclear@0 623 for(s = buf; isspace(*s);)
nuclear@0 624 s++;
nuclear@0 625 if(!*s) continue;
nuclear@0 626 for(t = s; *t && *t != ':' && *t != ',' && !isspace(*t); )
nuclear@0 627 t++;
nuclear@0 628 if(*t == ':') {
nuclear@0 629 *t++ = 0;
nuclear@0 630 if(!name)
nuclear@0 631 continue;
nuclear@0 632 if(strcmp(name, s))
nuclear@0 633 continue;
nuclear@0 634 s = t;
nuclear@0 635 connname = name;
nuclear@0 636 }
nuclear@0 637
nuclear@0 638 r = setup(s, file, lineno);
nuclear@0 639 if(r < 0)
nuclear@0 640 ret = r;
nuclear@0 641 if(r > 0 && !ret)
nuclear@0 642 ret = 1;
nuclear@0 643 }
nuclear@0 644
nuclear@0 645 fclose(f);
nuclear@0 646 return ret;
nuclear@0 647 }
nuclear@0 648
nuclear@0 649
nuclear@0 650 /*
nuclear@0 651 Sleep n milliseconds
nuclear@0 652 */
nuclear@0 653 static void
nuclear@0 654 millisleep(int n) {
nuclear@0 655 struct timespec t;
nuclear@0 656 t.tv_sec = n / 1000;
nuclear@0 657 t.tv_nsec = (n % 1000) * 1000000;
nuclear@0 658 nanosleep(&t, 0);
nuclear@0 659 }
nuclear@0 660
nuclear@0 661
nuclear@0 662 /*
nuclear@0 663 Set up the port
nuclear@0 664 */
nuclear@0 665 static int
nuclear@0 666 setupport(int fd) {
nuclear@0 667 int parityflags;
nuclear@0 668 int modemflags;
nuclear@0 669 int spaceparity = 0;
nuclear@0 670 struct termios tio;
nuclear@0 671 int m;
nuclear@0 672
nuclear@0 673 /*
nuclear@0 674 See what to do with parity
nuclear@0 675 */
nuclear@0 676 markparity = 0;
nuclear@0 677 parityflags = parity;
nuclear@0 678 if(parity == -1) {
nuclear@0 679 parityflags = 0;
nuclear@0 680 markparity = ISTRIP;
nuclear@0 681 }
nuclear@0 682 else if(parity == -2) {
nuclear@0 683 parityflags = 0;
nuclear@0 684 spaceparity = ISTRIP;
nuclear@0 685 }
nuclear@0 686
nuclear@0 687 /*
nuclear@0 688 If no modem control, use local mode
nuclear@0 689 */
nuclear@0 690 modemflags = ctsflow | modemcontrol;
nuclear@0 691 if(!modemflags)
nuclear@0 692 modemflags = CLOCAL;
nuclear@0 693
nuclear@0 694 /*
nuclear@0 695 Set the speed and params
nuclear@0 696 */
nuclear@0 697 tcgetattr(fd, &tio);
nuclear@0 698 tio.c_iflag = IGNBRK | IGNPAR | xonflow | spaceparity | markparity;
nuclear@0 699 tio.c_cflag = CREAD | HUPCL | modemflags | bits | parityflags;
nuclear@0 700 tio.c_oflag = 0;
nuclear@0 701 tio.c_lflag = 0;
nuclear@0 702 cfsetispeed(&tio, ispeed);
nuclear@0 703 cfsetospeed(&tio, ospeed);
nuclear@0 704 if(tcsetattr(fd, TCSAFLUSH, &tio) == -1)
nuclear@0 705 return -1;
nuclear@0 706
nuclear@0 707 /*
nuclear@0 708 Set up the modem lines
nuclear@0 709 */
nuclear@0 710 ioctl(fd, TIOCMGET, &modem);
nuclear@0 711 if((modem & (TIOCM_RTS | TIOCM_DTR)) != (setmodem & (TIOCM_RTS |
nuclear@0 712 TIOCM_DTR))) {
nuclear@0 713 m = setmodem & (TIOCM_RTS | TIOCM_DTR);
nuclear@0 714 ioctl(fd, TIOCMBIS, &m);
nuclear@0 715 m = (~setmodem) & (TIOCM_RTS | TIOCM_DTR);
nuclear@0 716 ioctl(fd, TIOCMBIC, &m);
nuclear@0 717 }
nuclear@0 718
nuclear@0 719 /*
nuclear@0 720 Send a break if requested
nuclear@0 721 */
nuclear@0 722 if(sendbreak) {
nuclear@0 723 ioctl(fd, TIOCSBRK, 0);
nuclear@0 724 millisleep(500);
nuclear@0 725 ioctl(fd, TIOCCBRK, 0);
nuclear@0 726 sendbreak = 0;
nuclear@0 727 }
nuclear@0 728
nuclear@0 729 /*
nuclear@0 730 Get the current modem status
nuclear@0 731 */
nuclear@0 732 ioctl(fd, TIOCMGET, &modem);
nuclear@0 733 setmodem = modem;
nuclear@0 734
nuclear@0 735 return 0;
nuclear@0 736 }
nuclear@0 737
nuclear@0 738
nuclear@0 739 /*
nuclear@0 740 Set up the modem. This is a little tricky due to the need to
nuclear@0 741 ensure the modem does not block before we set it up.
nuclear@0 742 */
nuclear@0 743 static int
nuclear@0 744 openport(char *device) {
nuclear@0 745 int fd;
nuclear@0 746
nuclear@0 747 if((fd = open(device, O_RDWR|O_NONBLOCK, 0)) < 0)
nuclear@0 748 DIEP(device)
nuclear@0 749 if(setupport(fd) < 0)
nuclear@0 750 DIEP(device)
nuclear@0 751 millisleep(10);
nuclear@0 752 fcntl(fd, F_SETFL, 0);
nuclear@0 753
nuclear@0 754 ioctl(fd, TIOCMGET, &modem);
nuclear@0 755 setmodem = modem;
nuclear@0 756
nuclear@0 757 setenv("DTERM_PORT", device, 1);
nuclear@0 758 return fd;
nuclear@0 759 }
nuclear@0 760
nuclear@0 761
nuclear@0 762 /*
nuclear@0 763 Usage
nuclear@0 764 */
nuclear@0 765 static void
nuclear@0 766 usage(char *this) {
nuclear@0 767 fprintf(stderr, "Usage: %s port/setup\n"
nuclear@0 768 " '%s help' for help\n", this, this);
nuclear@0 769 exit(1);
nuclear@0 770 }
nuclear@0 771
nuclear@0 772
nuclear@0 773 int
nuclear@0 774 main(int argc, char **argv) {
nuclear@0 775 int nfd;
nuclear@0 776 int i, j, c;
nuclear@0 777 unsigned char inbuf;
nuclear@0 778 char buf[256];
nuclear@0 779 char cbuf[8];
nuclear@0 780 char *s;
nuclear@0 781 int done;
nuclear@0 782 fd_set fds;
nuclear@0 783 struct timeval delay_tv, *readdelay;
nuclear@0 784 struct stat sb;
nuclear@0 785
nuclear@0 786 /*
nuclear@0 787 Do the right things depending on whether stdin & stdout are TTYs
nuclear@0 788 If the input is a TTY, we need to put it into non-canonical mode
nuclear@0 789 (which we'll actually do later); otherwise, default to turning
nuclear@0 790 LFs from a file into CRs. (See [no]maplf setup command.)
nuclear@0 791 If the output is a TTY, default to passing CR transparently;
nuclear@0 792 otherwise default to ignoring CR so that output is logged to a
nuclear@0 793 files etc nicely. (See [no]igncr.)
nuclear@0 794 */
nuclear@0 795 istty = isatty(0);
nuclear@0 796 if(istty) {
nuclear@0 797 tcgetattr(0, &savetio);
nuclear@0 798 maplf = 0;
nuclear@0 799 }
nuclear@0 800 else maplf = 1;
nuclear@0 801 if(isatty(1))
nuclear@0 802 ignorecr = 0;
nuclear@0 803 else ignorecr = 1;
nuclear@0 804
nuclear@0 805 /*
nuclear@0 806 Read default config, if no private .dtermrc, use /etc/dtermrc
nuclear@0 807 */
nuclear@0 808 setmodem = modem = TIOCM_DTR | TIOCM_RTS;
nuclear@0 809 if(readconfig("~/.dtermrc", argv[1]) == -2)
nuclear@0 810 readconfig("/etc/dtermrc", argv[1]);
nuclear@0 811
nuclear@0 812 /*
nuclear@0 813 Parse args
nuclear@0 814 If only arg is "help", exit
nuclear@0 815 */
nuclear@0 816 i = 1;
nuclear@0 817 if(connname) i = 2;
nuclear@0 818 for(; i < argc; i++)
nuclear@0 819 if(setup(argv[i], 0, 0) < 0)
nuclear@0 820 usage(argv[0]);
nuclear@0 821 if(argc == 2 && !strcasecmp(argv[1], "help"))
nuclear@0 822 exit(0);
nuclear@0 823
nuclear@0 824 /*
nuclear@0 825 If no device specified, have a crack at finding a default device
nuclear@0 826 Look for the first on-board device first; failing that look for
nuclear@0 827 the first USB device. For Linux & BSD these are:
nuclear@0 828 OS Onboard USB
nuclear@0 829 Linux ttyS0 ttyUSB0
nuclear@0 830 BSD ttyd0 ttyU0
nuclear@0 831 Note that this rather assumes that the existence of a device
nuclear@0 832 name in /dev indicates the actual existence of a device. Mostly
nuclear@0 833 this is the case on modern systems. Mostly.
nuclear@0 834 */
nuclear@0 835 if(!device) {
nuclear@0 836 if( !stat("/dev/ttyS0", &sb)) device = "/dev/ttyS0";
nuclear@0 837 else if(!stat("/dev/ttyd0", &sb)) device = "/dev/ttyd0";
nuclear@0 838 else if(!stat("/dev/ttyUSB0", &sb)) device = "/dev/ttyUSB0";
nuclear@0 839 else if(!stat("/dev/ttyU0", &sb)) device = "/dev/ttyU0";
nuclear@0 840 else {
nuclear@0 841 fprintf(stderr, "Could not find default device\n");
nuclear@0 842 usage(argv[0]);
nuclear@0 843 }
nuclear@0 844 }
nuclear@0 845
nuclear@0 846 /*
nuclear@0 847 If the controlling TTY is in fact a TTY, set it up
nuclear@0 848 */
nuclear@0 849 if(istty) {
nuclear@0 850 intio = savetio;
nuclear@0 851 intio.c_oflag = 0;
nuclear@0 852 intio.c_lflag = 0;
nuclear@0 853 intio.c_iflag = savetio.c_iflag & ~(INLCR|IGNCR|ICRNL);
nuclear@0 854
nuclear@0 855 intio.c_cc[VEOF] = _POSIX_VDISABLE;
nuclear@0 856 intio.c_cc[VEOL] = _POSIX_VDISABLE;
nuclear@0 857 intio.c_cc[VEOL2] = _POSIX_VDISABLE;
nuclear@0 858 intio.c_cc[VERASE] = _POSIX_VDISABLE;
nuclear@0 859 intio.c_cc[VWERASE] = _POSIX_VDISABLE;
nuclear@0 860 intio.c_cc[VKILL] = _POSIX_VDISABLE;
nuclear@0 861 intio.c_cc[VREPRINT] = _POSIX_VDISABLE;
nuclear@0 862 intio.c_cc[VINTR] = _POSIX_VDISABLE;
nuclear@0 863 intio.c_cc[VQUIT] = _POSIX_VDISABLE;
nuclear@0 864 intio.c_cc[VSUSP] = _POSIX_VDISABLE;
nuclear@0 865 #ifdef VDSUSP
nuclear@0 866 intio.c_cc[VDSUSP] = _POSIX_VDISABLE;
nuclear@0 867 #endif
nuclear@0 868 intio.c_cc[VLNEXT] = _POSIX_VDISABLE;
nuclear@0 869 intio.c_cc[VDISCARD] = _POSIX_VDISABLE;
nuclear@0 870 #ifdef VSTATUS
nuclear@0 871 intio.c_cc[VSTATUS] = _POSIX_VDISABLE;
nuclear@0 872 #endif
nuclear@0 873 tcsetattr(0, TCSADRAIN, &intio);
nuclear@0 874 }
nuclear@0 875
nuclear@0 876 /*
nuclear@0 877 Connect to serial port
nuclear@0 878 */
nuclear@0 879 fd = openport(device);
nuclear@0 880 if(fd < 0) exit(1);
nuclear@0 881
nuclear@0 882 /*
nuclear@0 883 Main loop
nuclear@0 884 */
nuclear@0 885 readdelay = 0;
nuclear@0 886 done = 0;
nuclear@0 887 while(!done) {
nuclear@0 888
nuclear@0 889 /*
nuclear@0 890 Set up the select() call
nuclear@0 891 If readdelay is not 0, we're waiting for things to go quiet so we
nuclear@0 892 can exit.
nuclear@0 893 Errors kill us, execpt for interrupted calls
nuclear@0 894 0 return only happens if readdelay is set, so we exit then
nuclear@0 895 */
nuclear@0 896 FD_ZERO(&fds);
nuclear@0 897 if(!readdelay)
nuclear@0 898 FD_SET(0, &fds);
nuclear@0 899 FD_SET(fd, &fds);
nuclear@0 900 i = select(fd + 1, &fds, 0,0, readdelay);
nuclear@0 901 if(i == -1 && errno != EINTR)
nuclear@0 902 DIEP("select");
nuclear@0 903 if(i == 0 && readdelay)
nuclear@0 904 break;
nuclear@0 905
nuclear@0 906 /*
nuclear@0 907 If input from line, read a full buffer in
nuclear@0 908 IgnoreCR means sucking CRs out of the buffer (yuck)
nuclear@0 909 If EOF (e.g. hangup), exit nicely.
nuclear@0 910 */
nuclear@0 911 if(FD_ISSET(fd, &fds)) {
nuclear@0 912 i = read(fd, buf, sizeof(buf));
nuclear@0 913 if(i < 0)
nuclear@0 914 DIEP(device);
nuclear@0 915 if(!i) break;
nuclear@0 916 if(showspecial) {
nuclear@0 917 s = buf;
nuclear@0 918 do {
nuclear@0 919 c = 0;
nuclear@0 920 for(j = 0; j < i; j++) {
nuclear@0 921 c = (unsigned char) s[j];
nuclear@0 922 if(showspecial == 2 && (
nuclear@0 923 c == '\t' || c > '~'))
nuclear@0 924 break;
nuclear@0 925 if(c == '\r' && ignorecr)
nuclear@0 926 break;
nuclear@0 927 if(( c < ' ' && c != '\t'
nuclear@0 928 && c != '\r' && c != '\n')
nuclear@0 929 || (c > '~' && c < 160))
nuclear@0 930 break;
nuclear@0 931 }
nuclear@0 932 if(j) write(1, s, j);
nuclear@0 933 if(j >= i)
nuclear@0 934 break;
nuclear@0 935 if(c == '\r' && ignorecr) {
nuclear@0 936 /* Do nothing */
nuclear@0 937 }
nuclear@0 938 else if(c < 32 && showspecial != 2) {
nuclear@0 939 cbuf[0] = '^';
nuclear@0 940 cbuf[1] = c + '@';
nuclear@0 941 write(1, cbuf, 2);
nuclear@0 942 }
nuclear@0 943 else if(c == 127 && showspecial != 2)
nuclear@0 944 write(1, "[DEL]", 5);
nuclear@0 945 else {
nuclear@0 946 sprintf(cbuf, "[%02x]", c);
nuclear@0 947 write(1, cbuf, 4);
nuclear@0 948 }
nuclear@0 949 j++;
nuclear@0 950 s += j;
nuclear@0 951 i -= j;
nuclear@0 952 } while(i > 0);
nuclear@0 953 }
nuclear@0 954 else {
nuclear@0 955 if(ignorecr) {
nuclear@0 956 j = 0;
nuclear@0 957 for(s = buf; s < buf + i; s++)
nuclear@0 958 if(*s != '\r')
nuclear@0 959 buf[j++] = *s;
nuclear@0 960 i = j;
nuclear@0 961 }
nuclear@0 962 write(1, buf, i);
nuclear@0 963 }
nuclear@0 964 }
nuclear@0 965
nuclear@0 966 /*
nuclear@0 967 Input on stdin
nuclear@0 968 Read a character
nuclear@0 969 If EOF, set readdelay to 1 second
nuclear@0 970 */
nuclear@0 971 if(FD_ISSET(0, &fds)) {
nuclear@0 972 if(read(0, &inbuf, 1) < 1) {
nuclear@0 973 delay_tv.tv_sec = 1;
nuclear@0 974 delay_tv.tv_usec = 0;
nuclear@0 975 readdelay = &delay_tv;
nuclear@0 976 continue;
nuclear@0 977 }
nuclear@0 978 /*
nuclear@0 979 If command character received, read commands
nuclear@0 980 */
nuclear@0 981 if(inbuf == cmdchar && istty) {
nuclear@0 982 FIXTTY;
nuclear@0 983 putchar('\n');
nuclear@0 984 for(;;) {
nuclear@0 985 fprintf(stderr, "dterm> ");
nuclear@0 986 if(!fgets(buf, sizeof(buf), stdin))
nuclear@0 987 return 0;
nuclear@0 988 if((s = strchr(buf, '#')))
nuclear@0 989 *s = 0;
nuclear@0 990 for(s = buf; *s; s++)
nuclear@0 991 if(!isspace(*s)) break;
nuclear@0 992 if(!*s) break;
nuclear@0 993 ioctl(fd, TIOCMGET, &modem);
nuclear@0 994 i = setup(buf, 0, 0);
nuclear@0 995 if(i == -3)
nuclear@0 996 return 0;
nuclear@0 997 if(i == 1) {
nuclear@0 998 nfd = openport(device);
nuclear@0 999 if(nfd >= 0) {
nuclear@0 1000 close(fd);
nuclear@0 1001 fd = nfd;
nuclear@0 1002 }
nuclear@0 1003 }
nuclear@0 1004 else if(setupport(fd))
nuclear@0 1005 fprintf(stderr,
nuclear@0 1006 "invalid parameters\n");
nuclear@0 1007 }
nuclear@0 1008 if(istty) tcsetattr(0, TCSADRAIN, &intio);
nuclear@0 1009 }
nuclear@0 1010 /*
nuclear@0 1011 Otherwise do any processing on the character
nuclear@0 1012 Add dread high bit disease if mark parity
nuclear@0 1013 BS <-> DEL mapping
nuclear@0 1014 LF -> CR mapping for files
nuclear@0 1015 CR -> CRLF mapping for TTYs
nuclear@0 1016 */
nuclear@0 1017 else {
nuclear@0 1018 if(markparity)
nuclear@0 1019 inbuf |= 0x80;
nuclear@0 1020 if(backspace && (inbuf == 8 || inbuf == 127))
nuclear@0 1021 inbuf = backspace;
nuclear@0 1022 if(maplf && inbuf == '\n')
nuclear@0 1023 inbuf = '\r';
nuclear@0 1024 write(fd, &inbuf, 1);
nuclear@0 1025 if(crlf && inbuf == '\r') {
nuclear@0 1026 inbuf = '\n';
nuclear@0 1027 write(fd, &inbuf, 1);
nuclear@0 1028 }
nuclear@0 1029 if(linedelay && inbuf == '\r')
nuclear@0 1030 millisleep(linedelay);
nuclear@0 1031 else if(delay)
nuclear@0 1032 millisleep(delay);
nuclear@0 1033 }
nuclear@0 1034 }
nuclear@0 1035
nuclear@0 1036 }
nuclear@0 1037
nuclear@0 1038 /*
nuclear@0 1039 Fall out the bottom, cleaning up
nuclear@0 1040 */
nuclear@0 1041 FIXTTY;
nuclear@0 1042 return 0;
nuclear@0 1043 }