#ifndef lint static char *RCSid = "$Header: /src/common/usc/bin/qterm/RCS/qterm.c,v 5.4 1991/03/21 02:09:40 mcooper Exp $"; #endif /* * Copyright (c) 1990 Michael A. Cooper. * This software may be freely distributed provided it is not sold for * profit and the author is credited appropriately. */ /* *------------------------------------------------------------------ * * $Source: /src/common/usc/bin/qterm/RCS/qterm.c,v $ * $Revision: 5.4 $ * $Date: 1991/03/21 02:09:40 $ * $State: Exp $ * $Author: mcooper $ * $Locker: $ * *------------------------------------------------------------------ * * Michael A. Cooper * Research and Development Group * University Computing Services * University of Southern California * (mcooper@usc.edu) * *------------------------------------------------------------------ * * $Log: qterm.c,v $ * Revision 5.4 1991/03/21 02:09:40 mcooper * Fix memory buffer problem with some C * compilers. (tp@vtold.vtol.fi) * * Revision 5.3 1991/03/16 05:36:30 mcooper * Fix casting of (char) NULL problem. * * Revision 5.2 1991/03/12 00:46:24 mcooper * Change CMASK to CHAR_CMASK to avoid conflict * under AIX 3.1. * * Revision 5.1 1991/02/20 02:23:33 mcooper * Cleanup #ifdef USG5 as part of port * to UTS 2.1 (System V.3). * * Revision 5.0 1990/12/15 18:30:41 mcooper * Version 5. * * Revision 4.13 90/12/15 18:14:23 mcooper * Add copywrite. * * Revision 4.12 90/11/13 16:00:03 mcooper * Convert OptInt's to OptBool's where needed. * * Revision 4.11 90/11/13 15:38:28 mcooper * Make OLD_SepArg include both * SepArg and StickyArg. * * Revision 4.10 90/11/08 15:41:08 mcooper * Make sure qt_fullname is not 0 length. * * Revision 4.9 90/11/08 13:02:06 mcooper * Fix bug that closes the tty when an error * occurs during command line parsing. * * Revision 4.8 90/11/06 13:19:40 mcooper * Changed command line options to new * longer names. * * Revision 4.7 90/11/05 17:09:30 mcooper * Update option help messages and option names * to be more mnemonic. * * Revision 4.6 90/11/05 16:44:35 mcooper * - Converted to use new ParseOptions() for * command line parsing. * - Major de-linting. * - Convert dprintf() to use varargs (if * HAS_VARARGS is defined). * - Lots of misc. cleanup. * * Revision 4.5 89/10/20 22:50:49 mcooper * Changed code indention to current local * standard of 4. (This should also mess up * everybody trying to do diff's from older versions!) * * Revision 4.4 89/10/20 14:03:48 mcooper * Fixed command line parsing of "-f -q". * * Revision 4.3 88/06/16 19:43:46 mcooper * - Added -T flag to wait until timeout when * listening for response string. This solves * problem when the first entry in a table * doesn't have a response string with a * common ending character to look for. * - Added -I flag for "intense" query mode. * - Cleaned up debugging a bit. * * Revision 4.2 88/06/08 15:30:53 mcooper * Cleanup pass including removing * extraneous debugging messages. * * Revision 4.1 88/04/25 13:24:38 mcooper * Added -S option to print send and recieve * strings as they are sent and recieved as * suggested by David W. Sanderson * (dws@attunix.att.com). * * Revision 4.0 88/03/08 19:30:59 mcooper * Version 4. * * Revision 3.7 88/03/08 19:28:32 mcooper * Major rewrite. * * Revision 3.6 88/03/08 15:31:35 mcooper * General cleanup time. * * Revision 3.5 88/03/08 13:59:39 mcooper * - Catch signals and fix terminal modes. * - Don't allow alarm times of 0. * - Support for HP-UX machines and cleaner * listen() code from Zenon Fortuna, * HP-UX Support, Hewlett-Packard Vienna. * * Revision 3.4 87/10/07 15:16:17 mcooper * - Beautify code a bit. * - Add -w option to set the wait time. * * Revision 3.3 87/08/24 19:25:32 mcooper * The following based on code from Frank Crawford * : * - Use $TERM as output string when the terminal * type is not known instead of "dumb". * - Regular Expressions are now supported. RE are * started with a leading `\'. * - Octal values may now be used in send/recieve strings. * * Revision 3.1 87/08/03 15:21:07 mcooper * As pointed out by Scott H. Robinson , * the -F switch does work. Problem was that it never read * in the ~/.qterm file. * * Revision 3.0 87/06/30 19:07:59 mcooper * Release of version 3. * * Revision 2.4 87/04/29 19:28:35 mcooper * In readtabfile() we now do special * things when opening "file" fails * depending on the bequiet flag. * * Revision 2.3 87/04/29 13:11:37 mcooper * - No more "internal" table. The master * table is read from a file (TABFILE). * This makes ~/.qterm stuff much cleaner. * - Error handling for qtermtab files is * much more informative now. * - More things I can't remember. * * Revision 2.2 87/03/05 21:01:28 mcooper * Fixed system V compiler problem. * * Revision 2.1 87/03/01 19:43:22 mcooper * Be more intelligent about the size of * the default terminal table. * * Revision 2.0 87/03/01 19:20:00 mcooper * General cleanup. * *------------------------------------------------------------------ */ /* * qterm - Query Terminal * * qterm is used to query a terminal to determine the name of the terminal. * This is done by sending a fairly universal string "\33Z" to the terminal, * reading in a response, and comparing it against a master table of responses * and names. The "name" printed to standard output should be one found in * the termcap(5) database. * * Putting a line in your ".login" file such as: * * setenv TERM `qterm` * * or the following lines in your ".profile" file: * * TERM=`qterm` * export TERM * * will set your terminal type automagically. * * If you add a terminal to the master table, please also send me a copy * so that I may put it into my version. * * Michael Cooper * Internet: mcooper@usc.edu * UUCP: ...!rutgers!usc!mcooper * BITNET: mcooper@gamera */ #include #include #include #include #include #include #ifdef USG5 # include #else /*USG5*/ # include # include #endif /*USG5*/ #include "qterm.h" #include "options.h" #ifdef HAS_VARARGS #include #endif /*HAS_VARARGS*/ #ifdef USG5 struct termio _ntty, _otty; #else struct sgttyb _tty; #endif int _tty_ch = 2; char recvbuf[SIZE]; char *progname; char *termfile = NULL; int debug = FALSE; /* Debug mode */ int use_alt_str = FALSE; /* Alternate string */ int towait = FALSE; /* Time out wait flag */ int always_send = FALSE; /* Intense query mode */ int longname = FALSE; /* Print long terminal name */ int sent_chars = FALSE; /* Print strings sent from the terminal */ int watch_chars = FALSE; /* Watch strings as they are sent and recv. */ int quiet = FALSE; /* Quiet mode */ int do_usrtabfile = FALSE; /* Use user's own .qtermtab file */ int do_systabfile = TRUE; /* Use the system's qterm tab file */ int almwait = WAIT; /* Wait (timeout) interval */ /* * Old options should not be visable in help and usage messages. */ #ifdef OPT_COMPAT #define OLD_NoArg NoArg|ArgHidden #define OLD_SepArg SepArg|StickyArg|ArgHidden #define fFLAG "-f" #define FFLAG "-F" #endif /* * Command line options table. */ OptionDescRec opts[] = { #ifdef OPT_COMPAT {"-a", OLD_NoArg, OptInt, (caddr_t) &use_alt_str, "1", (char *)NULL, "Use alternate query string"}, {"-s", OLD_NoArg, OptInt, (caddr_t) &sent_chars, "1", (char *)NULL, "Display the characters the terminal sent"}, {"-t", ArgHidden|OLD_NoArg, OptInt, (caddr_t) &sent_chars, "1", (char *)NULL, "Display the characters the terminal sent"}, {"-I", OLD_NoArg, OptInt, (caddr_t) &always_send, "1", (char *)NULL, "Always send the terminal query string"}, {"-T", OLD_NoArg, OptInt, (caddr_t) &towait, "1", (char *)NULL, "Enable time out wait"}, {"-S", OLD_NoArg, OptInt, (caddr_t) &watch_chars, "1", (char *)NULL, "Print strings as they are sent and received"}, {"-q", OLD_NoArg, OptInt, (caddr_t) &quiet, "1", (char *)NULL, "Enable quite mode"}, {"-f", OLD_SepArg, OptStr, (caddr_t) &termfile, fFLAG, "", "Try , then ~/.qtermtab, then system tabfile"}, {"-F", OLD_SepArg, OptStr, (caddr_t) &termfile, FFLAG, "", "Try , then ~/.qtermtab"}, {"-l", OLD_NoArg, OptInt, (caddr_t) &longname, "1", (char *)NULL, "Output only the long (verbose) terminal name"}, {"-d", OLD_NoArg, OptInt, (caddr_t) &debug, "1", (char *)NULL, "Enable debug mode"}, {"-w", OLD_SepArg, OptInt, (caddr_t) &almwait, __ NULL, "", "Wait (timeout) period (in seconds)"}, #endif /*OPT_COMPAT*/ {"+alt", NoArg, OptBool, (caddr_t) &use_alt_str, "1", (char *)NULL, "Use alternate query string"}, {"-alt", NoArg, OptBool, (caddr_t) &use_alt_str, "0", (char *)NULL, "Don't use alternate query string"}, {"+always", NoArg, OptBool, (caddr_t) &always_send, "1", (char *)NULL, "Always send the terminal query string"}, {"-always", NoArg, OptBool, (caddr_t) &always_send, "0", (char *)NULL, "Don't always send the terminal query string"}, {"-file", SepArg, OptStr, (caddr_t) &termfile, __ NULL, "", "Use to query terminal"}, {"+longname",NoArg, OptBool, (caddr_t) &longname, "1", (char *)NULL, "Output only the long (verbose) terminal name"}, {"-longname",NoArg, OptBool, (caddr_t) &longname, "0", (char *)NULL, "Don't output the long (verbose) terminal name"}, {"+quiet", NoArg, OptBool, (caddr_t) &quiet, "1", (char *)NULL, "Enable quiet mode"}, {"-quiet", NoArg, OptBool, (caddr_t) &quiet, "0", (char *)NULL, "Disable quiet mode"}, {"+sent", NoArg, OptBool, (caddr_t) &sent_chars, "1", (char *)NULL, "Display the characters the terminal sent"}, {"-sent", NoArg, OptBool, (caddr_t) &sent_chars, "0", (char *)NULL, "Don't display the characters the terminal sent"}, {"+timeout",NoArg, OptBool, (caddr_t) &towait, "1", (char *)NULL, "Enable time out wait"}, {"-timeout",NoArg, OptBool, (caddr_t) &towait, "0", (char *)NULL, "Disable time out wait"}, {"+usrtab", NoArg, OptBool, (caddr_t) &do_usrtabfile, "1", (char *)NULL, "Enable using ~/.qtermtab"}, {"-usrtab", NoArg, OptBool, (caddr_t) &do_usrtabfile, "0", (char *)NULL, "Disable using ~/.qtermtab"}, {"-wait", SepArg, OptInt, (caddr_t) &almwait, __ NULL, "", "Wait (timeout) period (in seconds)"}, {"+watch", NoArg, OptBool, (caddr_t) &watch_chars, "1", (char *)NULL, "Watch the characters sent and recieved"}, {"-watch", NoArg, OptBool, (caddr_t) &watch_chars, "0", (char *)NULL, "Don't watch the characters sent and recieved"}, {"+systab", NoArg, OptBool, (caddr_t) &do_usrtabfile, "1", (char *)NULL, "Enable using system qtermtab file"}, {"-systab", NoArg, OptBool, (caddr_t) &do_systabfile, "0", (char *)NULL, "Disable using system qtermtab file"}, {"-debug", ArgHidden|NoArg, OptInt, (caddr_t) &debug, "1", (char *)NULL, "Enable debug mode"}, }; FILE *fopen(); char *decode(); char *getenv(); char *malloc(); char *re_comp(); char *strcat(); char *xmalloc(); int alarm(); int found = FALSE; int modes_set = FALSE; jmp_buf env; struct termtable *compare(); struct passwd *getpwuid(); void catch(); void done(); void dprintf(); void exit(); void myperror(); void mktable(); void notrecognized(); void proctab(); void wakeup(); #ifdef USG5 char *regcmp(); #endif /* USG5 */ main(argc, argv) int argc; char **argv; { config(argc, argv); setmodes(); mktable(); proctab((struct termtable *)NULL); resetmodes(); if (!found) { notrecognized(); } exit(0); } /* * Config() - Perform configuration operations. */ config(argc, argv) int argc; char **argv; { progname = argv[0]; /* * Parse command line args */ if (ParseOptions(opts, Num_Opts(opts), argc, argv) < 0) { done(1); /*NOTREACHED*/ } /* * Check results of command line parsing and perform any * needed post processing. */ if (longname) quiet = TRUE; if (almwait == 0) { (void) fprintf(stderr, "%s: Alarm (wait) time must be greater than 0.\n", progname); done(1); /*NOTREACHED*/ } #ifdef OPT_COMPAT /* * Kludgy stuff to be backwards compatable for command line options. */ if (termfile) { if (strcmp(termfile, fFLAG) == 0) { do_usrtabfile = TRUE; do_systabfile = TRUE; termfile = NULL; } else if (strcmp(termfile, FFLAG) == 0) { do_usrtabfile = TRUE; do_systabfile = FALSE; termfile = NULL; } } #endif /*OPT_COMPAT*/ dprintf("[ %s debug mode enabled ]\n\n", progname); } /* * Set signal catches and terminal modes */ setmodes() { if (!isatty(0)) { (void) fprintf(stderr, "%s: Not a tty.\n", progname); done(0); /*NOTREACHED*/ } /* * Set output buffers */ setbuf(stdout, (char *)0); if (debug) setbuf(stderr, (char *)0); /* * Cleanup terminal modes & such if we are killed */ (void) signal(SIGINT, catch); (void) signal(SIGHUP, catch); (void) signal(SIGTERM, catch); /* * Set terminal modes */ #ifdef USG5 if (ioctl(_tty_ch, TCGETA, &_otty) < 0) #else if (ioctl(_tty_ch, TIOCGETP, &_tty) < 0) #endif /* USG5 */ { myperror("gtty"); done(1); /*NOTREACHED*/ } #ifdef USG5 _ntty = _otty; #endif /* USG5 */ if (crmode() < 0) { myperror("crmode"); done(1); /*NOTREACHED*/ } if (noecho() < 0) { myperror("noecho"); done(1); /*NOTREACHED*/ } modes_set = TRUE; } /* * Reset terminal modes */ resetmodes() { if (modes_set) { (void) nocrmode(); (void) echo(); } } /* * Print info about terminal structure t. */ prinfo(t, what) struct termtable *t; int what; { int len = 0; int st = FALSE; if (t && t->qt_termname && (recvbuf[0] != (char) NULL)) { if (debug || sent_chars) { len = strlen(recvbuf); (void) fprintf(stderr, "%s received %d character%s:", progname, len, (len == 1) ? "" : "s"); (void) fprintf(stderr, " %s\n", decode(recvbuf)); } if (!quiet) { (void) fprintf(stderr, "Terminal recognized as %s", t->qt_termname); if (t->qt_fullname && t->qt_fullname[0]) (void) fprintf(stderr, " (%s)\n", t->qt_fullname); else (void) fprintf(stderr, "\n"); } if (longname) { if (t->qt_fullname && t->qt_fullname[0]) (void) printf("%s\n", t->qt_fullname); else (void) fprintf(stderr, "%s: No full terminal name for %s.\n", progname, t->qt_termname); } else { (void) printf("%s\n", t->qt_termname); } found = TRUE; done(0); /*NOTREACHED*/ } else { found = FALSE; if (what) { notrecognized(); done(1); /*NOTREACHED*/ } } return(st); } /* * compare - actually compare what we received against the table. */ struct termtable *compare(str) char *str; { #ifdef USG5 register char *reexp; #endif /* USG5 */ register struct termtable *t; char buf[BUFSIZ]; dprintf("compare %s\n", (str && str[0]) ? decode(str) : "nothing"); (void) alarm((unsigned)0); if (strlen(str) == 0) return(NULL); for (t = termtab; t != NULL; t = t->nxt) { dprintf(" with %s ", decode(t->qt_recvstr)); (void) sprintf(buf, "^%s$", t->qt_recvstr); #ifdef USG5 if ((reexp = regcmp(buf, NULL)) == NULL) { #else if (re_comp((char *)buf) != NULL) { #endif /* USG5 */ (void) fprintf(stderr, "%s: bad regular expression: \"%s\"\n", progname, t->qt_recvstr); done(1); /*NOTREACHED*/ } #ifdef USG5 if (regex(reexp, str) != NULL) { #else if (re_exec(str) == 1) { #endif /* USG5 */ found = TRUE; dprintf("\tOK\n"); return(t); } dprintf("\tNOPE\n"); #ifdef USG5 (void) free(reexp); #endif /* USG5 */ } found = FALSE; return(NULL); } /* * getch - read in a character at a time. */ getch() { char c; (void) read(0, &c, 1); return(c & CHAR_MASK); } /* * decode - print str in a readable fashion */ char *decode(str) char *str; { register int len; static char buf[BUFSIZ]; char tmp[10]; if (!str) return("(null)"); (void) strcpy(buf, ""); while (*str) { if (*str == ESC) { (void) strcat(buf, " "); } else if ((*str <= 33) || (*str >= 127)) { (void) sprintf(tmp,"\\%#o ", (unsigned) *str); (void) strcat(buf, tmp); } else { (void) sprintf(tmp,"%c ", *str); (void) strcat(buf, tmp); } ++str; } len = strlen(buf); if (len && buf[len - 1] == ' ') { buf[len - 1] = (char) NULL; } return(buf); } /* * Make a termtab table */ void mktable() { char file[BUFSIZ]; struct passwd *pwd; char *home; dprintf("[ initilizing term table... ]\n"); if (termfile != NULL) { (void) readtabfile(termfile, FALSE); } if (do_usrtabfile) { /* * Try to read the user's own table */ if ((home = getenv("HOME")) == NULL) { if ((pwd = getpwuid(getuid())) == NULL) { (void) fprintf(stderr, "%s: Cannot find user info for uid %d.\n", progname, getuid()); done(1); /*NOTREACHED*/ } home = pwd->pw_dir; } (void) sprintf(file, "%s/%s", home, USRFILE); if (readtabfile(file, TRUE) < 0) { (void) sprintf(file, "%s/%s", home, OLDUSRFILE); (void) readtabfile(file, TRUE); } } if (do_systabfile) (void) readtabfile(TABFILE, FALSE); dprintf("[ mktable done ]\n"); } int readtabfile(file, bequiet) char *file; int bequiet; { static int line = 0; char lbuf[4][BUFSIZ]; char buf[BUFSIZ]; FILE *fd; char *p, *fixctl(); char *errmsg = NULL; struct termtable *t; if ((fd = fopen(file, "r")) == NULL) { if (bequiet) { dprintf("[ tab file '%s' can not read ]\n", file); return(-1); } myperror(file); done(1); /*NOTREACHED*/ } dprintf("[ Read tab file '%s' ]\n", file); line = 0; while (fgets(buf, sizeof(buf), fd)) { ++line; if (buf[0] == '#' || buf[0] == '\n') continue; lbuf[0][0] = lbuf[1][0] = lbuf[2][0] = lbuf[3][0] = (char) NULL; (void) sscanf(buf, "%s%s%s\t%[^\n]", lbuf[0], lbuf[1], lbuf[2], lbuf[3]); if (lbuf[0][0] == (char) NULL) continue; if (lbuf[1][0] == (char) NULL) errmsg = "receive string"; if (lbuf[2][0] == (char) NULL) errmsg = "terminal name"; if (errmsg) { (void) fprintf(stderr, "%s: Line %d of %s: Error parsing %s.\n", progname, line, file, errmsg); done(1); /*NOTREACHED*/ } t = (struct termtable *) xmalloc(sizeof(struct termtable)); if (use_alt_str) p = fixctl(ALTSEND, 0); else p = fixctl(lbuf[0], 0); t->qt_sendstr = (char *) xmalloc(strlen(p)+1); (void) strcpy(t->qt_sendstr, p); p = fixctl(lbuf[1], 1); t->qt_recvstr = (char *) xmalloc(strlen(p)+1); (void) strcpy(t->qt_recvstr, p); t->qt_termname = (char *) xmalloc(strlen(lbuf[2])+1); (void) strcpy(t->qt_termname, lbuf[2]); t->qt_fullname = (char *) xmalloc(strlen(lbuf[3])+1); (void) strcpy(t->qt_fullname, lbuf[3]); dprintf("\n Send String = %s\n", decode(t->qt_sendstr)); dprintf("Expect String = %s\n", decode(t->qt_recvstr)); dprintf(" Terminal = '%s'\n", t->qt_termname); dprintf(" Full Name = '%s'\n", t->qt_fullname); (void) addterm(t); } return(0); } /* * Add termtab (n) entry to main termtab. */ int addterm(n) struct termtable *n; { register struct termtable *t; if (!n) return(-1); n->nxt = NULL; if (termtab == NULL) { termtab = n; } else { t = termtab; while(t && t->nxt) t = t->nxt; t->nxt = n; } return(0); } /* * Listen for a response. */ void qterm_listen(q) struct termtable *q; { static int i, len; register char c; char end; (void) alarm((unsigned)0); (void) strcpy(recvbuf, ""); i = 0; len = strlen(q->qt_recvstr); if (len) { end = q->qt_recvstr[len - 1]; } else { end = 'c'; /* Fairly standard ANSI default */ } dprintf("\nlisten for %s\t [ len = %d, end = `%c' ]\n", decode(q->qt_recvstr), len, end); /* * If we don't get an initial character, bounce out * of here and finish with done(0). */ if (setjmp(env)) { if (found) { done(0); /*NOTREACHED*/ } (void) fflush(stdin); proctab(q->nxt); } else { (void) signal(SIGALRM, wakeup); (void) alarm((unsigned)almwait); recvbuf[0] = getch(); (void) alarm((unsigned)0); } /* * Read in remaining response. Loop until ending character * is received or until alarm goes off. If towait is set, * then let alarm go off. */ for (i = 1, c = -1; (!towait && (c != end)) || towait; ) { if (setjmp(env)) { recvbuf[i] = (char) NULL; return; } else { (void) signal(SIGALRM, wakeup); (void) alarm((unsigned)almwait); c = getch(); (void) alarm((unsigned)0); } recvbuf[i++] = c; } recvbuf[i] = (char) NULL; dprintf("listen done. read %d chars.\n\n", i); } /* * Print a message since we didn't recognize this terminal. */ void notrecognized() { char *envterm; if ((envterm = getenv("TERM")) == NULL) envterm = "dumb"; if (!quiet) (void) fprintf(stderr, "Terminal NOT recognized - defaults to \"%s\".\n", envterm); puts(envterm); } /* * Process entries in the termtable. */ void proctab(t) struct termtable *t; { int st = FALSE; static int firsttime = TRUE; static struct termtable *lastt; dprintf("\n[ Processing entries ] \n"); if (firsttime) { t = termtab; lastt = NULL; } while ((!found || do_usrtabfile) && t && t->qt_sendstr && !st) { /* * If this is our first time or the sendstr is the same as * last time, don't send it again. */ if (always_send || firsttime || lastt == NULL || strcmp(t->qt_sendstr, lastt->qt_sendstr) != 0) { if (firsttime) firsttime = FALSE; if (watch_chars) (void) printf("Send: %s\n", decode(t->qt_sendstr)); (void) fflush(stdin); (void) fprintf(stderr, "%s", t->qt_sendstr); (void) fflush(stderr); lastt = t; (void) qterm_listen(t); if (watch_chars) (void) printf("\tRead: %s\n", decode(recvbuf)); } st = prinfo(compare(recvbuf), FALSE); lastt = t; t = t->nxt; } if (!found) notrecognized(); done(0); /*NOTREACHED*/ } char *fixctl(str, rex) char *str; int rex; { register int i; static char buf[BUFSIZ]; for (i = 0; str && *str; ) { switch (*str) { case '\\': if (isdigit(*++str)) { buf[i] = 0; while (isdigit(*str)) buf[i] = (char) (((int)buf[i] * 8) + (int)*str++ - (int) '0'); i++; } else buf[i++] = *str++; continue; case '^': switch (*++str) { case '?': buf[i++] = '\177'; break; default: buf[i++] = *str & 037; break; } break; /* Special R.E. symbols */ case '[': case '*': case '.': case '$': case '{': case '(': if (rex) buf[i++] = '\\'; default: buf[i++] = *str; } *++str; } buf[i] = (char) NULL; return(buf); } /* * xmalloc - Do a malloc with error checking. */ char *xmalloc(size) int size; { char *p; if ((p = malloc((unsigned) size)) == NULL) { myperror("malloc"); done(1); /*NOTREACHED*/ } return(p); } #ifdef HAS_VARARGS void dprintf(va_alist) va_dcl { va_list args; char *fmt; if (!debug) return; va_start(args); fmt = (char *) va_arg(args, char *); (void) vprintf(fmt, args); va_end(args()); (void) fflush(stdout); } #else /*HAS_VARARGS*/ void dprintf(fmt, a1, a2, a3, a4, a5, a6) char *fmt; { if (!debug) return; (void) printf(fmt, a1, a2, a3, a4, a5, a6); (void) fflush(stdout); } #endif /*HAS_VARARGS*/ /* * Catch kill signals and cleanup. */ void catch() { done(2); /*NOTREACHED*/ } void wakeup() { dprintf("wakeup called\n"); longjmp(env, 1); } void myperror(msg) char *msg; { (void) fprintf(stderr, "%s: ", progname); perror(msg); } /* * Reset terminal and exit with status s. */ void done(s) int s; { resetmodes(); exit(s); }