1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ 2: static char rcsid[] = "$Header: unix.c,v 2.6 85/08/22 16:09:38 timo Exp $"; 3: 4: /* 5: * B editor -- UNIX interface, i.e. signal and tty fiddling. 6: */ 7: 8: /* #define BADTABSTOPS /* Obsolete -- "b" doesn't set the tabs any more */ 9: /* Defined if (soft) tabs may have been placed at strange positions. */ 10: /* Actually this has only effect if curses(3) is used. 11: However this source file doesn't #include "curses.h" so we can't 12: check for that, and will assume curses(3) is always used. 13: For very slow baudrates when curses(3) is used, it may prove useful 14: to undefine BADTABSTOPS. The "b" shell script must then be modified 15: to keep the tabs at the UNIX 8 space apart default. */ 16: 17: #include "b.h" /* Only for definitions like bool, string, Hidden etc. */ 18: #include "unix.h" /* What kind of UNIX is this? */ 19: 20: #ifdef SIGNAL 21: #include <signal.h> 22: #endif SIGNAL 23: 24: #ifdef SGTTY_H 25: #include <sgtty.h> 26: #endif SGTTY_H 27: 28: extern bool slowterminal; /* Set for speeds <= 600 baud */ 29: extern bool hushbaby; /* Set if no bells are to be heard */ 30: extern bool dflag; /* Debugging mode */ 31: 32: 33: #define COPYSAVEFILE ".Bed_buf" 34: 35: Visible char copysavefile[200] = COPYSAVEFILE; 36: 37: 38: #define Ctl(x) ('x'&037) 39: 40: #ifndef QUITCHAR 41: #define QUITCHAR Ctl(\\) 42: #endif QUITCHAR 43: 44: #ifndef INTRCHAR 45: #define INTRCHAR Ctl(]) 46: #endif INTRCHAR 47: 48: #define REDRAW Ctl(L) /* From "keys.h" */ 49: 50: 51: #ifdef SIGNAL 52: /* 53: * Call exit code when signal arrives, then resend the signal. 54: */ 55: 56: catch(sig) 57: int sig; 58: { 59: signal(sig, SIG_DFL); 60: #ifndef NDEBUG 61: fprintf(stderr, "*** Caught signal %d \n\r", sig); 62: if (sig == SIGQUIT) { /* QUIT only resets terminal modes */ 63: endterm(); 64: endunix(); 65: } 66: else 67: #endif NDEBUG 68: endall(); 69: #ifdef BTOP 70: termchild(); /* Kill possible child, but don't wait for it */ 71: #endif BTOP 72: kill(getpid(), sig); 73: } 74: #endif SIGNAL 75: 76: 77: #ifdef SIGTSTP /* I.e., only on BSD systems with job control. */ 78: /* 79: * Reset tty modes etc. when STOP signal arrives (control-Z). 80: * This is like interrupt but the program may continue later 81: * so we must not do all exit code). 82: * 83: * In order that the code works for 4.1 and 4.2 BSD Unix (V7 and sys III/V 84: * don't have the SIGTSTP signal at all, so there wo don't bother), we use 85: * neither the awkward "-ljobs" mechanism nor the nicer but (yet!) even 86: * less portable sigmask/sigblock system calls. Rather, to kill ourselves 87: * again after the screen and tty modes have been restored, we use another 88: * signal, i.e., SIGSTOP (which is uncatchable). 89: * 90: * Note! Since curses' initscr() also executes signal(SIGTSTP, tstp), 91: * and initscr() is called after initunix(), the name of this routine 92: * must be tstp, overriding a routine of the same name in the curses 93: * library which does not do what we want. 94: */ 95: 96: tstp(sig) 97: int sig; 98: { 99: int (*prevttousig)() = signal(SIGTTOU, SIG_IGN); 100: /* Ignore SIGTTOU so stty calls won't stop us again! */ 101: char cread = REDRAW; 102: 103: #ifndef NDEBUG 104: if (dflag) 105: fprintf(stderr, "*** Caught stop signal %d \n\r", sig); 106: #endif NDEBUG 107: signal(sig, SIG_DFL); 108: endterm(); 109: unfixttymodes(); 110: signal(SIGTTOU, prevttousig); 111: kill(getpid(), SIGSTOP); /* Hard stop */ 112: 113: /* 114: * A stop signal made us go to sleep in Tumbolia. 115: * When we awake, we continue at this point. 116: * The world may well have changed a little bit, 117: * so do the tty initializations anew. 118: */ 119: 120: fixttymodes(); 121: initterm(); 122: 123: #ifdef TIOCSTI 124: /* Simulate receipt of REDRAW initially so we come up 125: with a nice display. */ 126: ioctl(0, TIOCSTI, &cread); 127: #endif TIOCSTI 128: signal(SIGTSTP, tstp); 129: } 130: #endif SIGTSTP 131: 132: 133: /* 134: * Prepare for interrupts (UNIX `signals') to be caught so 135: * we can reset the tty modes and perform miscellaneous other 136: * exit routines. 137: * Note -- if a signal arrives before the call to fixttymodes, 138: * the unfixttymodes may render the terminal useless. The fix is 139: * easy, but I'm too lazy now (just read the statuses BEFORE, 140: * but change them only AFTER signal setting). 141: */ 142: 143: initunix() 144: { 145: #ifdef SIGNAL 146: register int i; 147: #endif SIGNAL 148: 149: #ifndef NDEBUG 150: if (dflag) 151: fprintf(stderr, "*** initunix();\n\r"); 152: #endif NDEBUG 153: 154: #ifdef SIGNAL 155: for (i = 1; i <= NSIG; ++i) { 156: #ifndef NDEBUG 157: if (i == SIGQUIT) 158: continue; 159: #endif NDEBUG 160: #ifdef SIGCONT 161: if (i == SIGCONT) 162: continue; 163: #endif SIGCONT 164: #ifdef SIGCHLD 165: if (i == SIGCHLD) 166: continue; 167: #endif SIGCHLD 168: if (signal(i, SIG_IGN) != SIG_IGN) { 169: signal(i, catch); 170: #ifndef NDEBUG 171: if (dflag) 172: fprintf(stderr, "Catching signal %d\n", i); 173: #endif NDEBUG 174: } 175: } 176: /* Stop/continue must be handled differently, see stop() above. */ 177: #ifdef SIGTSTP 178: if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) 179: signal(SIGTSTP, tstp); 180: #endif SIGTSTP 181: 182: #endif SIGNAL 183: 184: #ifdef SGTTY_H 185: fixttymodes(); 186: #endif SGTTY_H 187: setcopybuffer(); 188: } 189: 190: 191: /* 192: * The last termination routine to be called. 193: * It also resets all signals to their default status. 194: */ 195: 196: endunix() 197: { 198: #ifdef SIGNAL 199: int i; 200: #endif SIGNAL 201: 202: fflush(stdout); 203: #ifndef NDEBUG 204: if (dflag) 205: fprintf(stderr, "*** endunix();\n\r"); 206: #endif NDEBUG 207: #ifdef SGTTY_H 208: unfixttymodes(); 209: #endif SGTTY_H 210: 211: #ifdef SIGNAL 212: for (i = 1; i <= NSIG; ++i) 213: signal(i, SIG_DFL); 214: #endif SIGNAL 215: } 216: 217: 218: /* 219: * Determine the name of the file where the copy buffer is saved. 220: */ 221: 222: Hidden Procedure 223: setcopybuffer() 224: { 225: string home = getenv("HOME"); 226: 227: if (home) 228: sprintf(copysavefile, "%.150s/%.40s", home, COPYSAVEFILE); 229: /* Else, retain default initialization! */ 230: } 231: 232: 233: /* 234: * Return a string like the one that perror(arg) would print 235: * (see UNIX manual page perror(3) for details). 236: * Like all C library routines returning strings, the string points 237: * to static storage that is overwritten on each call. 238: * If arg is fairly long, it may get truncated. 239: */ 240: 241: string 242: unixerror(arg) 243: string arg; 244: { 245: static char msg[200]; 246: #ifdef PERROR 247: extern int sys_nerr, errno; 248: extern string sys_errlist[]; 249: 250: if (errno > 0 && errno < sys_nerr) 251: sprintf(msg, "%.80s: %.80s", arg, sys_errlist[errno]); 252: else 253: sprintf(msg, "%.80s: UNIX error %d", arg, errno); 254: #else !PERROR 255: sprintf(msg, "%.68s: I/O error", arg); 256: #endif !PERROR 257: msg[80] = '\0'; 258: return msg; 259: } 260: 261: 262: #ifdef SGTTY_H 263: /* 264: * Hacks to fix certain peculiarities due to the hostile environment 265: * in which the editor lives. 266: */ 267: 268: Hidden struct sgttyb oldtty; 269: 270: #ifdef TIOCSETC 271: Hidden struct tchars oldtchars; 272: #endif 273: 274: #ifdef TIOCSLTC 275: Hidden struct ltchars oldltchars; 276: #endif 277: 278: Hidden Procedure 279: fixttymodes() 280: { 281: gtty(2, &oldtty); 282: if (oldtty.sg_ospeed <= B600) 283: slowterminal = Yes; 284: #ifdef BADTABSTOPS 285: /* 286: * Turn on XTABS mode, to be able to live when terminal tabs are 287: * set at 4 rather than 8 columns (the B interpreter used to set 288: * this). 289: */ 290: if (!(oldtty.sg_flags & XTABS)) { 291: struct sgttyb newtty; 292: gtty(2, &newtty); 293: newtty.sg_flags |= XTABS; 294: ioctl(0, TIOCSETN, &newtty); 295: } 296: #endif BADTABSTOPS 297: 298: #ifdef TIOCSETC /* I.e., not at pre-version 7 UNIX systems */ 299: /* 300: * Set the quit character to ^\ and the interrupt at DEL. 301: * The start/stop characters are kept only if they are ^S/^Q. 302: */ 303: { 304: struct tchars newtchars; 305: ioctl(0, TIOCGETC, &oldtchars); 306: ioctl(0, TIOCGETC, &newtchars); 307: if ((newtchars.t_intrc & 0377) != 0377 308: && newtchars.t_intrc != 0177/*DEL*/) 309: newtchars.t_intrc = INTRCHAR; 310: if ((newtchars.t_quitc & 0377) != 0377) 311: newtchars.t_quitc = QUITCHAR; 312: if (newtchars.t_startc != Ctl(Q)) 313: newtchars.t_startc = -1; 314: if (newtchars.t_stopc != Ctl(S)) 315: newtchars.t_stopc = -1; 316: ioctl(0, TIOCSETC, &newtchars); 317: } 318: #endif TIOCSETC 319: 320: #ifdef TIOCSLTC /* I.e., at 4.xBSD systems */ 321: /* 322: * Turn off all local control characters except keep stop (^Z) and delayed 323: * stop (^Y) when these are the originals. 324: */ 325: { 326: static struct ltchars newltchars = {-1, -1, -1, -1, -1, -1}; 327: 328: ioctl(0, TIOCGLTC, &oldltchars); 329: if (oldltchars.t_suspc == Ctl(Z)) 330: newltchars.t_dsuspc = Ctl(Z); 331: ioctl(0, TIOCSLTC, &newltchars); 332: } 333: #endif 334: } 335: 336: 337: /* 338: * Undo the effects of fixttymodes(), see comments there. 339: */ 340: 341: Hidden Procedure 342: unfixttymodes() 343: { 344: if (!oldtty.sg_ospeed) 345: return; /* Not yet initialized! */ 346: #ifdef BADTABSTOPS 347: ioctl(0, TIOCSETN, &oldtty); 348: #endif 349: #ifdef TIOCSETC 350: ioctl(0, TIOCSETC, &oldtchars); 351: #endif 352: #ifdef TIOCSLTC 353: ioctl(0, TIOCSLTC, &oldltchars); 354: #endif 355: } 356: #endif SGTTY_H 357: 358: 359: /* 360: * Return Yes if more input immediately available 361: */ 362: 363: #ifdef IBMPC 364: 365: Visible bool 366: moreinput() 367: { 368: return kbhit(); 369: } 370: 371: #else !IBMPC 372: 373: /* 374: * ***** UNIX DEPENDENCE ***** 375: * Assumes the standard UNIX definition of FILE: assumes there is 376: * buffered input if stdin->_cnt > 0, so uses the `_cnt' field. 377: * 378: * ***** 4.2 BSD DEPENDENCE ***** 379: * If the symbol SIGNAL is defined, uses the select() system call to determine 380: * whether more input is available; see select(2) in 4.2 BSD manual. 381: * 382: * ***** 4.1 BSD DEPENDENCE ***** 383: * If the symbol FIONREAD is defined, uses the correponding ioctl call to 384: * determine whether more input is available; see tty(4) in 4.1 BSD manual. 385: */ 386: 387: #ifdef SELECT 388: #include <sys/time.h> 389: #endif SELECT 390: 391: Visible bool 392: moreinput() 393: { 394: if (stdin->_cnt > 0) 395: return Yes; 396: #ifdef SELECT 397: { 398: int readfds; 399: int nfds; 400: static struct timeval timeout = {0, 0}; 401: 402: readfds = 1<<fileno(stdin); 403: nfds = 1+fileno(stdin); 404: nfds = select(nfds, &readfds, (int*)0, (int*)0, &timeout); 405: if (nfds > 0) { 406: if (dflag) 407: fputc('\07', stderr); 408: return Yes; 409: } 410: } 411: #else SELECT 412: #ifdef FIONREAD 413: { 414: long n = 0; 415: 416: if (ioctl(0, FIONREAD, &n) != -1 && n > 0) 417: return Yes; 418: } 419: #endif FIONREAD 420: #endif SELECT 421: return No; 422: } 423: #endif !IBMPC 424: 425: 426: #ifdef SETENV 427: /* 428: * Routine to add or change an environment variable. 429: * (No longer used.) 430: */ 431: 432: extern string *environ; 433: 434: setenv(entry) 435: string entry; 436: { 437: string equals = index(entry, '='); 438: int len; 439: string *ep; 440: static string *myenviron; 441: 442: if (!equals) 443: syserr("setenv: no = sign"); 444: len = equals - entry; 445: for (ep = environ; *ep && !Strnequ(*ep, entry, len+1); ++ep) 446: ; 447: if (*ep) { 448: *ep = entry; 449: return; 450: } 451: len = ep - environ + 2; 452: if (myenviron) { 453: myenviron = (string*) 454: realloc((string)myenviron, (unsigned)(len * sizeof(string))); 455: if (!myenviron) 456: syserr("setenv: realloc"); 457: } 458: else { 459: myenviron = (string*) malloc((unsigned)(len * sizeof(string))); 460: if (!myenviron) 461: syserr("setenv: malloc"); 462: for (ep = environ; *ep; ++ep) 463: myenviron[ep-environ] = *ep; 464: } 465: myenviron[len-1] = (string)NULL; 466: myenviron[len-2] = entry; 467: environ = myenviron; 468: } 469: #endif SETENV 470: 471: 472: #ifdef PWB 473: /* 474: * Substitute getenv routine - there is no environment on PWB systems, 475: * but as a substitute (not te be encouraged!) we allow a file with the 476: * name of the environment variable to contain the desired value; 477: * e.g. the file "TERM" may contain a line saying hp2621 or hp etc. 478: */ 479: 480: Visible string 481: getenv(name) 482: string name; 483: { 484: static char buffer[100]; 485: FILE *fp; 486: string cp; 487: 488: fp = fopen(name, "r"); 489: if (!fp) 490: return NULL; 491: if (!fgets(buffer, sizeof buffer, fp)) 492: buffer[0] = '\0'; 493: else { 494: cp = index(buffer, '\n'); 495: if (cp) 496: *cp = '\0'; 497: } 498: fclose(fp); 499: return buffer; 500: } 501: #endif PWB