1: #include "parms.h" 2: #include "structs.h" 3: 4: #ifdef RCSIDENT 5: static char rcsid[] = "$Header: miscio.c,v 1.7.0.1 85/09/28 11:23:51 notes Rel $"; 6: #endif RCSIDENT 7: 8: 9: /* miscio stuff: 10: * 11: * ttystrt/ttystop switch back and forth to character-at-a-time mode 12: * 13: * catchem makes our program ignore kills and coredumps. 14: * 15: * getnum is a char at a time input routine 16: * 17: * gchar sucks in 1 character. masks off parity. Uses raw mode to do this 18: * 19: */ 20: 21: 22: #include <signal.h> 23: #include <errno.h> 24: 25: 26: #ifdef USG /* Bell's Sys III and V */ 27: #include <termio.h> 28: struct termio tty, 29: otty; 30: #endif defined(USG) 31: 32: #if defined(V7) || defined(BSD4x) 33: /* Standard Bell V7 and Berkeley too */ 34: #include <sgtty.h> 35: int oldmode; /* prev mode bits */ 36: long oldlocalbits; /* prev local bits */ 37: struct sgttyb tty; 38: #endif defined(V7) || defined(BSD4x) 39: 40: #ifdef BSD2x /* Berkeley PDP-11 Unix */ 41: #include <sgtty.h> 42: int oldmode; /* prev mode bits */ 43: int oldlocalbits; /* 2.8 Bsd uses 16 bits */ 44: struct sgttyb tty; 45: #endif defined(BSD2x) 46: 47: char ttyerase, /* user's chosen erase character */ 48: ttykill; /* and his line kill character */ 49: int modeset = 0; /* == 1 if ttyflags messed with */ 50: short ospeed; /* for tputs padding */ 51: 52: 53: 54: ttystrt () 55: { 56: #if defined(BSD2x) 57: int localbits; /* 2.8 Bsd uses 16 bits */ 58: #endif defined(BSD2x) 59: 60: #if defined(BSD4x) 61: long localbits; /* for ctlecho and tildes */ 62: #endif defined(BSD4x) 63: 64: 65: /* 66: * Grab the current tty state 67: */ 68: 69: #ifdef V7 /* V7 has simple tty controls */ 70: if (gtty (0, &tty) < 0) /* failure to grab */ 71: { 72: fprintf (stderr, "%s: Unable to gtty\n", Invokedas); 73: exit (1); 74: } 75: #endif defined(V7) 76: 77: #ifdef USG /* BTL SYS III & V */ 78: if (ioctl (0, TCGETA, &tty) < 0 || 79: ioctl (0, TCGETA, &otty) < 0) /* one failed */ 80: { 81: fprintf (stderr, "%s: Unable to get tty state\n", Invokedas); 82: exit (1); 83: } 84: #endif defined(USG) 85: 86: #if defined(BSD4x) || defined(BSD2x) 87: /* Berkeley Unices */ 88: if (ioctl (0, TIOCGETP, &tty) < 0 || 89: ioctl (0, TIOCLGET, &oldlocalbits) < 0) 90: { 91: fprintf (stderr, "%s: Unable to get tty states\n"); 92: exit (1); 93: } 94: #endif defined(BSD4x) || defined(BSD2x) 95: 96: /* 97: * Modify the state to what we want: cbreak, fix tildes for cursor 98: * and disable "control-echo" (berkeley) 99: */ 100: 101: #if defined(USG) 102: tty.c_lflag &= NOT ICANON; 103: tty.c_cc[VEOF] = 1; 104: tty.c_cc[VEOL] = 1; 105: ospeed = tty.c_cflag & CBAUD; 106: ttyerase = tty.c_cc[VERASE]; /* grab erase char */ 107: ttykill = tty.c_cc[VKILL]; /* and kill char */ 108: #endif defined(USG) 109: 110: #if defined(BSD4x) || defined(BSD2x) || defined(V7) 111: oldmode = tty.sg_flags; 112: tty.sg_flags |= CBREAK; 113: ospeed = tty.sg_ospeed; /* speed of terminal */ 114: ttyerase = tty.sg_erase; /* grab erase character */ 115: ttykill = tty.sg_kill; /* and kill character */ 116: #endif defined(BSD4x) || defined(BSD2x) || defined(V7) 117: 118: 119: /* 120: * Now actually tell the system that we want it this way 121: */ 122: 123: #if defined(V7) 124: if (stty (0, &tty) < 0) /* failed */ 125: { 126: fprintf (stderr, "%s: Unable to stty\n", Invokedas); 127: exit (1); 128: } 129: #endif defined(V7) 130: 131: #if defined(USG) 132: if (ioctl (0, TCSETA, &tty) < 0) 133: { 134: fprintf (stderr, "%s: Unable to set tty state\n", Invokedas); 135: exit (1); 136: } 137: #endif defined(USG) 138: 139: #if defined(BSD4x) || defined(BSD2x) 140: localbits = LTILDE | LCTLECH; /* zap tildes (hazeltines) and ctlecho */ 141: if (ioctl (0, TIOCSETN, &tty) < 0 || 142: ioctl (0, TIOCLBIC, &localbits) < 0) 143: { 144: fprintf (stderr, "%s: Unable to set tty state\n", Invokedas); 145: exit (1); 146: } 147: #endif defined(BSD4x) || defined(BSD2x) 148: 149: modeset = 1; 150: cmstart (); /* so can cursor address reliably */ 151: } 152: 153: ttystop () 154: { 155: if (modeset) 156: { 157: #if defined(V7) || defined(BSD4x) || defined(BSD2x) 158: tty.sg_flags = oldmode; 159: #endif defined(V7) || defined(BSD4x) || defined(BSD2x) 160: 161: #if defined(V7) 162: if (stty (0, &tty) < 0) /* vanilla Version 7 */ 163: printf ("ttystop: stty"); /* cant use x cause he calls us */ 164: #endif defined(V7) 165: 166: #if defined(USG) 167: if (ioctl (0, TCSETA, &otty) < 0) /* Unix 4.0 */ 168: printf ("ttystop: stty"); /* cant use x cause he calls us */ 169: #endif defined(USG) 170: 171: #if defined(BSD4x) || defined(BSD2x) 172: if ((ioctl (0, TIOCSETN, &tty) < 0) || 173: (ioctl (0, TIOCLSET, &oldlocalbits) < 0)) 174: printf ("ttystop: stty"); /* cant use x cause he calls us */ 175: #endif defined(BSD4x) || defined(BSD2x) 176: } 177: cmstop (); /* get out of cursor addressing mode */ 178: modeset = 0; 179: } 180: 181: 182: static int (*osigint) (), 183: (*osigquit) (); /* hold signal status */ 184: #if defined(SIGTSTP) 185: static int (*osigtstp) (); /* control-z job stop */ 186: #endif defined(SIGTSTP) 187: 188: catchint () 189: { 190: intflag = 1; 191: signal (SIGINT, catchint); /* fix em up again */ 192: #ifndef DEBUG 193: signal (SIGQUIT, catchint); 194: #endif DEBUG 195: } 196: 197: #if defined(SIGTSTP) 198: catchz () /* handle ^Z gracefully */ 199: { 200: int wasset; /* tty mode flag */ 201: 202: if (ignoresigs) /* if in critical section */ 203: { 204: signal (SIGTSTP, catchz); /* re-catch */ 205: return; /* and ignore */ 206: } 207: if ((wasset = modeset) != 0) /* want assignment */ 208: { 209: at (0, 1); /* go to bottom corner */ 210: fflush (stdout); 211: ttystop (); /* fix tty modes */ 212: } 213: 214: signal (SIGTSTP, SIG_DFL); /* make sure it nabs us */ 215: #if defined(BSD42) 216: /* 217: * since 4.2 Bsd blocks signals while we are handling them, we 218: * have to explicitly tell the kernel that we want the signals 219: * to come through. 220: * It would probably be more correct to only let some signals 221: * through instead of all. 222: */ 223: (void) sigsetmask (0); /* pass signals */ 224: #endif BSD42 225: kill (0, SIGTSTP); /* halt myself */ 226: signal (SIGTSTP, catchz); /* ready to catch again */ 227: if (wasset) 228: ttystrt (); /* fix his tty */ 229: } 230: #endif defined(SIGTSTP) 231: 232: catchem () 233: { 234: osigint = signal (SIGINT, catchint); /* interrupts */ 235: #ifndef DEBUG 236: osigquit = signal (SIGQUIT, catchint); /* quits */ 237: #endif DEBUG 238: #if defined(SIGTSTP) 239: osigtstp = signal (SIGTSTP, catchz); /* control Z */ 240: #endif 241: } 242: 243: uncatchem () /* restore signal status */ 244: { 245: signal (SIGINT, osigint); 246: #ifndef DEBUG 247: signal (SIGQUIT, osigquit); 248: #endif DEBUG 249: #if defined(SIGTSTP) 250: signal (SIGTSTP, osigtstp); 251: #endif 252: } 253: 254: gchar () 255: /* 256: * Return next character from tty. 257: * this is all done in cbreak mode of course 258: */ 259: { 260: char c; 261: register int retcode; 262: fflush (stdout); /* get rid of what's there */ 263: while ((retcode = read (0, &c, 1)) <= 0) /* try reading */ 264: if (retcode == 0 || errno != EINTR) /* if bizarre */ 265: { 266: fprintf (stderr, "%s: Bad tty read\n", Invokedas); 267: exit (1); 268: } 269: intflag = 0; /* remove any pending */ 270: 271: return (c & 0177); 272: } 273: 274: /* 275: * getnum (c) 276: * grab a number from the terminal. "c" is the first digit o 277: * the number. 278: * 279: * Originally coded: Rob Kolstad Fall 1980 280: * Modified: Ray Essick (with help from Malcolm Slaney) 281: * July 1982 282: * to handle user defined erase and kill 283: * characters. 284: */ 285: 286: getnum (c) /* c is the initial character! */ 287: char c; 288: { 289: int num, 290: numin; 291: num = c - '0'; 292: numin = 1; 293: putc (c, stdout); 294: while (1) 295: { 296: c = gchar (); /* get next digit */ 297: if (c == ttyerase) /* want to erase? */ 298: { 299: if (numin > 0) /* if have some */ 300: { 301: if (c != '\10') /* Assumes physically */ 302: printf ("\10\10 \10\10"); /* backspaces on ^H */ 303: else 304: printf (" \10"); 305: numin--; 306: num /= 10; /* drop that digit */ 307: } 308: else 309: { /* nothing to zap */ 310: if (c != '\10') /* non-backspace char */ 311: printf ("\10\10 "); 312: else 313: putchar (' '); /* backspace */ 314: } 315: } 316: else 317: if (c == ttykill) 318: { 319: num = 0; /* blast it away */ 320: numin++; 321: while (numin > 0) /* erase the screen */ 322: { 323: numin--; 324: printf ("\10 \10"); 325: } 326: numin = 0; /* in case */ 327: } 328: else 329: switch (c) 330: { 331: case '\n': 332: case '\r': 333: return num; /* done */ 334: 335: default: 336: if (c < '0' || c > '9') 337: { 338: printf ("\10 \10\07"); 339: continue; 340: } 341: numin++; 342: num = 10 * num + (c - '0'); 343: break; 344: } 345: } 346: } 347: 348: /* 349: * gline( p, i) - suck a maximum of i characters from the tty. 350: * do erase and kill processing. 351: * The line is terminated by the user typing a <cr> or <nl>. This 352: * character is converted to null and left on the end of the 353: * string returned. The count of characters (including the null 354: * terminator) is returned. 355: * The array passed in is assumed to have i+1 elements 356: * (enough for the characters plus the terminator) 357: * 358: * Original Coding: Ray Essick December 1981 359: * Repaired to use user's erase and kill characters 360: * Malcolm Slaney July 1982 361: * 362: */ 363: 364: gline (p, max) 365: char *p; 366: { 367: register int numin; 368: register char *q; /* pointer to buffer */ 369: register char c; /* hold the input character */ 370: 371: q = p; /* get base */ 372: numin = 0; 373: while (1) 374: { 375: c = gchar (); /* flushes stdout also */ 376: if (c == ttyerase) 377: { 378: if (numin > 0) 379: { 380: if (c != '\10') /* Assumes TTY physically */ 381: printf ("\10\10 \10\10"); /* backspaces on ^H */ 382: else 383: printf (" \10"); 384: numin--; 385: q--; /* back up in buffer also */ 386: } 387: else 388: { 389: if (c != '\10') 390: printf ("\10 \10"); 391: else 392: printf (" "); 393: } 394: } 395: else 396: if (c == ttykill) 397: { 398: numin++; 399: while (numin > 0) /* erase the screen */ 400: { 401: numin--; 402: printf ("\10 \10"); 403: } 404: q = p; /* reset pointer */ 405: numin = 0; /* in case .. */ 406: } 407: else 408: switch (c) 409: { 410: case '\n': 411: case '\r': 412: if (numin >= max) /* should only ever be = */ 413: { 414: p[max] = '\0'; /* put a null at the end */ 415: return max + 1; /* which is how many we return */ 416: } 417: *q = '\0'; 418: numin++; 419: return numin; 420: 421: case '\\': /* escape character */ 422: printf ("\010"); /* back space to it */ 423: c = gchar (); /* grab escaped character */ 424: /* and fall through to default */ 425: 426: default: /* add character to buffer */ 427: if (numin < max) 428: { 429: *q++ = c; 430: numin++; 431: } 432: else 433: { 434: printf ("\10 \10"); /* show him I ignored char */ 435: } 436: break; 437: } 438: } 439: } 440: 441: askyn (p) char *p; /* returns y or n to the question */ 442: { 443: char c; /* return temp */ 444: printf ("%s", p); 445: while (1) 446: { 447: c = gchar (); 448: if (c == 'y' || c == 'n') 449: break; 450: printf ("\07 y or n please\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); 451: } 452: return c; 453: } 454: 455: /* 456: * return 1 if there is input from the terminal, 457: * 0 otherwise. systems without the appropriate 458: * call should always return 0. 459: */ 460: isinput () 461: { 462: #ifdef FIONREAD /* BSD 4.1, 4.1a, 4.2 */ 463: long retval; 464: if (ioctl (0, FIONREAD, &retval)) 465: return 0; /* failed, say no input */ 466: return (retval != 0); /* count of characters */ 467: #endif FIONREAD 468: 469: return 0; /* for other systems */ 470: } 471: 472: /* 473: * mapch(c) char c; 474: * 475: * prints control characters as ^x style. 476: * others as normal. 477: */ 478: mapch (c) 479: char c; 480: { 481: if (c < 40) 482: { 483: putchar ('^'); 484: putchar (c | 0100); /* make visible */ 485: } 486: else 487: if (c == 0177) 488: { 489: putchar ('^'); 490: putchar ('?'); 491: } 492: else 493: putchar (c); 494: }