📄 getkey.c
字号:
/* * Getkey: * * A machine dependent function to prompt for and read a keystring from stdin * * Input: * prompt - A string output to display prior to requesting input * str - where to put the characters * size - the number of storage locations reserved for the key - 1 * * Returns: * The number of characters read (not counting terminating '\n') * * Display a prompt on the screen (not stdout!) before entry. * Reads in upto <size> characters from the terminal (not stdin!). * Terminated by EOF or '\n'. * The trailing terminator is removed if present. * String will be '\0' terminated if its less than size bytes. * The characters are not echoed as they are typed. */#if !defined(__msdos) && !defined(__MSDOS__) && !defined(__BSD) /* { */#define _POSIX_SOURCE#include <unistd.h> /* read write getpid */#include <termios.h> /* termio stuff */#include <signal.h> /* signal stuff */#include <string.h> /* strlen */#include <fcntl.h> /* O_RDWR */#include <stdio.h> /* ctermid on dec alpha *//* * The type of a signal handler is declared inconsistantly in the header files. * Extremely picky compilers may require adjustment here; most don't complain. * The problem is what the type of signal's argument really is. POSIX doesn't * state this precisely; what is the prototype of the signal handler's * declaration supposed to look like exactly? Like Sun, I would guess * void handler(int,...) * but most vendors use void handler(). Sigh. */#if defined(_HPUX_SOURCE) && defined(__cplusplus)typedef void (*pfv)(int); /* HPUX 9.0 C++ */#elsetypedef void (*pfv)(); /* POSIX (normal case) *//* typedef void (*pfv)(int, ...); /* sunOS 4.1.2 C++ */#endif/* * Signal with posix signal semantics */static pfv psignal(sig, handler) int sig; pfv handler;{ struct sigaction sact, oact; int res; sact.sa_handler = handler; /* some compilers break here; see typedef pfv */ sact.sa_flags = 0; sigemptyset(&sact.sa_mask); res = sigaction(sig, &sact, &oact); if (res < 0) { return (pfv) -1; } return (pfv) oact.sa_handler;}/* * Set tty echo on(1) or off(0); returns previous setting or -1 */static int setTtyEcho(fd, echo) int fd; int echo;{ register int res, oldecho; struct termios modes; res = tcgetattr(fd, &modes); if (res < 0) return -1; oldecho = ((modes.c_lflag & ECHO) != 0); if (echo) { modes.c_lflag |= ECHO; } else { modes.c_lflag &= ~ECHO; } res = tcsetattr(fd, TCSANOW, &modes); if (res < 0) return -2; return oldecho;}static int oldEcho = 1; /* previous tty echo state */static int ttyfd = -1; /* controlling terminal */pfv oldsigint; /* previous handler */static void restoreEcho(sig) int sig;{ if (ttyfd >= 0) { setTtyEcho(ttyfd, oldEcho); close(ttyfd); } (void) psignal(SIGINT, oldsigint); /* restore old handler */ kill(getpid(), SIGINT); /* invoke old handler on return */}/* * Display prompt to the screen, read from the keyboard without echo until CR. */int getkey(prompt, str, size) char *prompt; char *str; register unsigned size;{ unsigned len = strlen(prompt); register int count; register char *chp = str; register int res = -1; char ch; ttyfd = open(ctermid((char *) 0), O_RDWR); if (ttyfd < 0) return -1; oldsigint = psignal(SIGINT, restoreEcho); oldEcho = setTtyEcho(ttyfd, 0); count = write(ttyfd, prompt, len); if (count != len) return -1; if (size != 0) do { count = read(ttyfd, &ch, 1); if (count == 0) break; if (count != 1) break; if (ch == '\n') break; *chp++ = ch; } while (--size != 0); if (count >= 0) { res = chp - str; } *chp = '\0'; count = write(ttyfd, "\n", 1); /* goto next line */ oldEcho = setTtyEcho(ttyfd, oldEcho); psignal(SIGINT, oldsigint); close(ttyfd); ttyfd = -1; return res;}#endif /* } POSIX */#if defined(__msdos) || defined(__MSDOS__) /* { */#include <dos.h>/* * Output a character to the console independent of I/O redirection */void conOut(ch) int ch;{ union REGS regs; regs.h.ah = 14 ; /* INT 10h, function 0EH, for video driver */ regs.h.al = (unsigned char) ch; int86(16, ®s, ®s) ;}/* * Input a character from the console independent of I/O redirection (no echo) */char conIn(){ union REGS regs; regs.h.ah = 0 ; /* INT 16h, function 00H, get char from keyboard */ int86(22, ®s, ®s) ; return (char) regs.h.al;}int getkey(prompt, str, size) register char *prompt; char *str; register unsigned size;{ register int ch; register char *chp = str;; while (*prompt != '\0') { conOut(*prompt++); /* write char to console */ } if (size != 0) do { ch = conIn(); /* read char from console without echo */ if (ch == '\r') break; /* carriage return */ *chp++ = ch; } while (--size != 0); if (size != 0) { *chp = '\0'; } conOut('\r'); conOut('\n'); return chp - str;}#endif /* } MSDOS */#if defined(__BSD) /* Are you *sure* you don't have Posix? { *//* * This code taken from ciper's original release. I don't mess with * BSD-specific stuff anymore since POSIX now works almost everywhere * (including every BSD machine I can find these days). * * Tested on SunOS 4.1 on SPARC IPC (sun4c/40) 28-Mar-94 by Dave Barrett * (That OS *does* have POSIX; I just wanted to make *sure* BSD worked) */#include <string.h>#include <fcntl.h>#if defined(_LINUX_SOURCE) /* or whatever linux cpp sets automagically */#include <bsd/sgtty.h>#else#include <sgtty.h> /* *my* BSD manual says; works on Sun SPARC */#endif#include <signal.h>int setEcho(fd, echo) int fd; int echo;{ struct sgttyb modes; int res, oldecho; res = ioctl(fd, TIOCGETP, &modes); oldecho = modes.sg_flags & ECHO; if (echo >= 0) { if (echo) { modes.sg_flags |= ECHO; } else { modes.sg_flags &= ~ECHO; } res = ioctl(fd, TIOCSETN, &modes); } return oldecho;}static void (*oldSigInt)();static int oldEcho = 1; /* assume echo was on */static int fd = -1;void intHandler(){ setEcho(fd, oldEcho); /* restore echoing */ close(fd); /* close /dev/tty */ (void) signal(SIGINT, oldSigInt); /* restore old handler */ kill(getpid(), SIGINT); /* invoke old handler */}/* * A machine dependent function to prompt for and read a keystring from stdin * * Input: * prompt - A string output to display prior to requesting input * str - where to put the characters * size - the number of storage locations reserved for the key * * Returns: * The number of characters read (not counting terminating '\n') * * Reads in upto <size> characters from the terminal. Terminated by EOF * or '\n'. String will be '\0' terminated if its less than size bytes. */int getkey(prompt, str, size) char *prompt; char *str; register unsigned size;{ int count, len; char buf[1], *chp = str;; fd = open("/dev/tty", O_RDWR); if (fd < 0) return fd; oldSigInt = signal(SIGINT, intHandler); oldEcho = setEcho(fd, 0); /* disable printing of input */ len = strlen(prompt); count = write(fd, prompt, len); if (size != 0) do { count = read(fd, buf, 1); if (count != 1) break; if (buf[0] == '\n') break; *chp++ = buf[0]; } while (--size != 0); if (size != 0) { *chp = '\0'; }#if !defined(_LINUX_SOURCE) /* * This code is definitely correct on Sun BSD machines. I'd like to * know why it's wrong on some others. Please send me mail if you disagree. * Dave Barrett <barrett@asgard.cs.Colorado.EDU> */ write(fd, "\n", 1); /* goto next line */#endif setEcho(fd, oldEcho); /* restore echo to previous state */ (void) signal(SIGINT, oldSigInt); close(fd); return chp - str;}#endif /* } __BSD but not POSIX (must be an OLD machine) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -