Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 84 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
84
Dung lượng
485,54 KB
Nội dung
The two error handling functions declared and defined on lines 10–12 and 62–73, respec- tively, are strictly for convenience. The program creates a signal-handling function to demonstrate that it catches some signals (lines 13, 57–60). The program’s real meat appears in lines 31–39. Line 33 turns off canonical mode, local echo, and ignores sig- nals; line 34 turns of the CR to NL translation, and line 35 turns off all output processing. After updating the terminal attributes, the loop on lines 43–46 reads input one character at a time and outputs it to the screen in octal notation. If you press the Delete key, the program exits after restoring the original terminal settings. A sample run of the program looks like the following: $ ./rawmode In RAW mode. Press DELETE key to exit 154 Type l 151 Type i 156 Type n 165 Type u 170 Type x 3 Type Ctrl-C 32 Type Ctrl-Z 4 Type Ctrl-D $ A newline does not perform a carriage return, so input appears on a new line, but at the location of the cursor from the last line. Because the program turned off signals, signals entered at the keyboard, such as ^C (interrupt), ^Z (suspend), and ^D (EOF) get ignored. Using terminfo Where termios gives you very low-level control over input processing, terminfo gives you a similar level of control over output processing. terminfo provides a portable, low- level interface to operations such as clearing a terminal screen, positioning the cursor, or deleting lines or characters. Due to the wide variety of terminals in existence, UNIX’s designers (eventually) learned to standardize descriptions of terminal capabilities in cen- trally located database files. The word “terminfo” refers both to this database and to the routines that access it. Programming the User Interface P ART IV 422 NOTE Strictly speaking, the termcap database, first used in BSD-derived systems, pre- ceded terminfo (the name “termcap” is a contraction of the phrase “TERMinal CAPability). As the termcap database grew in size, however, it became too slow for interactive use, and was replaced with terminfo in System V-derived UNIX beginning with Release 2. 3172316072 CH26 7/26/99 1:38 PM Page 422 terminfo Capabilities For each possible terminal type, such as VT100 or xterm, terminfo maintains a list of that terminal’s capabilities and features, called a capname, or CAPability NAME. Capnames fall into one of the following categories: • boolean • numeric • string Boolean capnames simply indicate whether or not a terminal supports a specific feature, such as cursor addressing or a fast screen-clearing function. Numeric capnames usually define size-related capabilities; for example, how many columns and lines a terminal has. String capnames define either the escape sequence necessary to access a certain feature or the string that would be output if the user pressed a certain key, such as a function key. Table 26.2 lists a small subset of the capabilities about which terminfo knows; for a complete list, refer to the terminfo(5) man page. Table 26.2 COMMON TERMINAL CAPABILITIES capname Type Description am boolean Terminal has automatic margins bce boolean Terminal uses background color erase km boolean Terminal has a META key ul boolean Underline character overstrikes cols numeric Number of columns on current terminal lines numeric Number of lines/rows on current terminal colors numeric Number of colors current terminal supports clear string Clear the screen and home the cursor cl string Clear to the end of the line ed string Clear to the end of the screen smcup string Enter cursor address mode cup string Move cursor to (row, column) rmcup string Exit cursor address mode bel string Emit audible bell flash string Emit visual bell (flash screen) kf[0-63] string F[0-63] function key Terminal Control the Hard Way C HAPTER 26 423 26 TERMINAL CONTROL THE HARD WAY 3172316072 CH26 7/26/99 1:38 PM Page 423 To use terminfo, include <curses.h> and <term.h>, in that order, in your source file. You also have to link against the curses library, so add -lcurses to the compiler invocation. Using terminfo In pseudo-code, the following is the usual sequence of instructions for using terminfo: 1. Initialize the terminfo data structures 2. Retrieve capname(s) 3. Modify capname(s) 4. Output the modified capname(s) to the terminal 5. Other code as necessary 6. Repeat steps 2–5 Initializing the terminfo data structures is simple, as shown in the following code: #include <curses.h> #include <term.h> int setupterm(const char *term, int filedes, int *errret); term specifies the terminal type. If it is null, setupterm() reads $TERM from the environ- ment; otherwise, setupterm() uses the value to which term points. All output is sent to the file or device opened on the file descriptor filedes. If errret is not null, it will either be 1 to indicate success, 0 if the terminal referenced in term could not be found in the terminfo database, or -1 if the terminfo database could not be found. setupterm() returns OK to indicate success or ERR on failure. If errret is null, setupterm() emits a diagnostic message and exits. Each of the three classes of capabilities (boolean, numeric, and string) has a correspond- ing function to retrieve a capability, as described in the following: int tigetflag(const char *capname); Returns TRUE if the terminal specified by term in setupterm() supports capname, FALSE if it does not, or -1 if capname isn’t a boolean capability. int tigetnum(const char *capname); Returns the numeric value of capname, ERR if the terminal specified by term in setupterm() doesn’t support capname, or -2 if capname isn’t a numeric capability. char *tigetstr(const char *capname); Returns a pointer to char containing the escape sequence for capname, (char *) null if the terminal specified by term in setupterm() doesn’t support capname, or (char *)-1 if capname isn’t a string capability. Programming the User Interface P ART IV 424 3172316072 CH26 7/26/99 1:38 PM Page 424 Listing 26.3 uses these functions to query and print a few of the current terminal’s capabilities. Listing 26.3 getcaps.c 1 /* 2 * Listing 26-3 3 * getcaps.c 4 * Get and show terminal capabilities using terminfo data structures 5 * and functions 6 */ 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <term.h> 10 #include <curses.h> 11 12 #define NUMCAPS 3 13 14 int main(void) 15 { 16 int i; 17 int retval = 0; 18 char *buf; 19 char *boolcaps[NUMCAPS] = { “am”, “bce”, “km” }; 20 char *numcaps[NUMCAPS] = { “cols”, “lines”, “colors” }; 21 char *strcaps[NUMCAPS] = { “cup”, “flash”, “hpa” }; 22 23 if(setupterm(NULL, fileno(stdin), NULL) != OK) { 24 perror(“setupterm()”); 25 exit(EXIT_FAILURE); 26 } 27 28 for(i = 0; i < NUMCAPS; ++i) { 29 retval = tigetflag(boolcaps[i]); 30 if(retval == FALSE) 31 printf(“`%s’ unsupported\n”, boolcaps[i]); 32 else 33 printf(“`%s’ supported\n”, boolcaps[i]); 34 } 35 fputc(‘\n’, stdout); 36 37 for(i = 0; i < NUMCAPS; ++i) { 38 retval = tigetnum(numcaps[i]); 39 if(retval == ERR) 40 printf(“`%s’ unsupported\n”, numcaps[i]); 41 else 42 printf(“`%s’ is %d\n”, numcaps[i], retval); 43 } 44 fputc(‘\n’, stdout); 45 Terminal Control the Hard Way C HAPTER 26 425 26 TERMINAL CONTROL THE HARD WAY continues 3172316072 CH26 7/26/99 1:38 PM Page 425 LISTING 26.3 CONTINUED 46 for(i = 0; i < NUMCAPS; ++i) { 47 buf = tigetstr(strcaps[i]); 48 if(buf == NULL) 49 printf(“`%s’ unsupported\n”, strcaps[i]); 50 else 51 printf(“`%s’ is \\E%s\n”, strcaps[i], &buf[1]); 52 /*printf(“`%s’ is %s\n”, strcaps[i], buf);*/ 52 } 53 54 exit(0); 55 } The program begins by initializing the terminfo data structures and setting up some variables for internal use. Then, it queries and prints three of each of the three classes of terminal capabilities. First, we test for support of the am (automatic margin), bce (back- ground color erase), and km (META key) boolean capabilities (lines 28–34). Then, in lines 37–43, we query the numeric capabilities cols (number of columns the terminal has), lines (the number of rows), and colors (the number of colors the terminal can dis- play). Lines 46–53 attempt to retrieve three string capabilities, cup (the escape sequence to position the cursor), flash (the escape sequence to generate a visual bell),and hpa (absolute horizontal cursor positioning). The only tricky part is lines 51 and 52. If the terminal supports a given string capability, tigetstr() returns a pointer to char that contains the escape sequence necessary to invoke that feature. If you output that string to the terminal, using printf() or puts(), in most cases you actually invoke that escape sequence. So, to avoid invoking, for exam- ple, the visual bell, the program strips off the first character, E\ (ESC), and prints out the rest of the string. For our purposes, however, this approach is not optimal because it doesn’t display the complete escape sequence. As a result, on line 51 we print static text, \\E, to escape the escape sequence. To see how the program would behave if we did not take this precaution, comment out line 51 and uncomment line 52 before compiling and running the program. If your termi- nal supports a visual bell (most do), the screen will flash. Programming the User Interface P ART IV 426 NOTE The infocmp command can list all of a terminal type’s capabilities. To see infocmp in action, issue the command infocmp -v $TERM. See infocmp(1)’s man page for more information. 3172316072 CH26 7/26/99 1:38 PM Page 426 Working with terminfo Capabilities Now that you know how to get terminal capabilities, the next step is to update them and put them into effect. tparm() modifies a capname; putp() and tputs() output the change to the screen. The putp() function, prototyped below, assumes that output device is standard output (stdout). As a result, it has a simple calling convention. int putp(const char *str); putp() outputs str to standard output. It is equivalent to tputs(str, 1, putchar). tputs(), on the other hand, gives you a greater degree of control, and has a correspond- ingly more complex interface. It is prototyped as: int tputs(const char *str, int affcnt, int (*putc)(int)); tputs() outputs str to the term and filedes specified in setupterm(). str must be a terminfo string variable or the return value from a tparm() or tigetstr() call. affcnt is the number of lines affected if str is a line-related capability or 1 if not applicable. putc is a pointer to any putchar-style output function that outputs characters one at a time. Naturally, before you can send a control string, you have to construct it. This is tparm()’s job. It is declared as follows: char *tparm(const char *str, long p1, long p2, , long p9); tparm() constructs a properly formatted parameterized string capname, using str and the parameters p1-p9. It returns a pointer to an updated copy of str containing the new parameters p1-p9 or NULL on error. What is a parameterized string? Recall that tigetstr() returns the escape sequence used to invoke a terminal string capability. When you executed the program in Listing 26.3, one of the lines printed to standard output should have resembled the following: `cup’ is \E[%i%p1%d;%p2%dH This is a parameterized string. This string is called a parameterized string because it defines a generic capability; in this case, moving the cursor to a specific location on the screen, which requires arguments, or parameters. In the case of the cup capability, it needs a row number and a column number to know where to place the cursor. To move the cursor on a standard (monochrome) xterm, xterm expects a command that, in semi- comprehensible language, looks like Escape-[-<row>-;-<column>-H. Terminal Control the Hard Way C HAPTER 26 427 26 TERMINAL CONTROL THE HARD WAY 3172316072 CH26 7/26/99 1:38 PM Page 427 In “terminfo-ese,” this translates to \E[%i%p1%d;%p2%dH. The programmer’s job is to sup- ply the row and column numbers, which are indicated using %pN, where N is a value between 1 and 9. So, to move to the position (10,15) on the screen, p1 = 10 and p2 = 15. For clarity, Table 26.3 describes the terminfo characters and arguments. Table 26.3 terminfo CHARACTERS AND ARGUMENTS Character or Argument Description \E Output Escape to the screen [ Output “[“ to the screen %i Increment all %p values by 1 %p1 Push the value in %p1 onto an internal terminfo stack %d Pop the value in %p1 off the stack and output it to the screen ; Output “;” to the screen %p2 Push the value in %p2 onto (the same) internal terminfo stack %d Pop the value in %p2 off the stack and output %p2 to the screen H Output “H” to the screen These may seem complicated and obscure, but consider the alternative: hard-coding hun- dreds of additional lines of terminal-specific code into your program in order to take into account all the possible terminals on which your program will run. Parameterized strings set up a general format for achieving the same effect on all terminals; all the programmer must do is substitute the correct values for the parameters. In my opinion, trading some cryptic-looking strings for hundreds of lines of code is a great trade! To make all of this more concrete, look at Listing 26.4. It rewrites the last example pro- gram, Listing 26.3, using additional terminal capabilities to create a (hopefully) more esthetically pleasing screen. Listing 26.4 new_getcaps.c 1 /* 2 * Listing 26-4 3 * new_getcaps.c 4 * Get and show terminal capabilities using terminfo data structures 5 * and functions 6 */ 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <term.h> 10 #include <curses.h> Programming the User Interface P ART IV 428 3172316072 CH26 7/26/99 1:38 PM Page 428 11 12 #define NUMCAPS 3 13 14 void clrscr(void); 15 void mv_cursor(int, int); 16 17 int main(void) 18 { 19 char *boolcaps[NUMCAPS] = { “am”, “bce”, “km” }; 20 char *numcaps[NUMCAPS] = { “cols”, “lines”, “colors” }; 21 char *strcaps[NUMCAPS] = { “cup”, “flash”, “hpa” }; 22 char *buf; 23 int retval, i; 24 25 if(setupterm(NULL, fileno(stdout), NULL) != OK) { 26 perror(“setupterm()”); 27 exit(EXIT_FAILURE); 28 } 29 30 clrscr(); 31 for(i = 0; i < NUMCAPS; ++i) { 32 /* position the cursor */ 33 mv_cursor(i, 10); 34 retval = tigetflag(boolcaps[i]); 35 if(retval == FALSE) 36 printf(“`%s’ unsupported\n”, boolcaps[i]); 37 else 38 printf(“`%s’ supported\n”, boolcaps[i]); 39 } 40 sleep(3); 41 42 clrscr(); 43 for(i = 0; i < NUMCAPS; ++i) { 44 mv_cursor(i, 10); 45 retval = tigetnum(numcaps[i]); 46 if(retval == ERR) 47 printf(“`%s’ unsupported\n”, numcaps[i]); 48 else 49 printf(“`%s’ is %d\n”, numcaps[i], retval); 50 } 51 sleep(3); 52 53 clrscr(); 54 for(i = 0; i < NUMCAPS; ++i) { 55 mv_cursor(i, 10); 56 buf = tigetstr(strcaps[i]); 57 if(buf == NULL) 58 printf(“`%s’ unsupported\n”, strcaps[i]); 59 else 60 printf(“`%s’ is \\E%s\n”, strcaps[i], &buf[1]); Terminal Control the Hard Way C HAPTER 26 429 26 TERMINAL CONTROL THE HARD WAY continues 3172316072 CH26 7/26/99 1:38 PM Page 429 LISTING 26.4 CONTINUED 61 } 62 sleep(3); 63 64 exit(0); 65 } 66 67 /* 68 * Clear the screen 69 */ 70 void clrscr(void) 71 { 72 char *buf = tigetstr(“clear”); 73 putp(buf); 74 } 75 76 /* 77 * Move the cursor to the specified row row and column col 78 */ 79 void mv_cursor(int row, int col) 80 { 81 char *cap = tigetstr(“cup”); 82 putp(tparm(cap, row, col)); 83 } Very little has changed between the two programs. First, I declare two utility functions, clrscr() and mv_cursor(), to clear the screen and position the cursor at a specific loca- tion, respectively. Their definitions, lines 70–74 and 79–83, respectively, utilize the putp() function, since we want to update standard output. We save one line of code on line 82 by passing tparm()’s return value directly to putp(). Besides the utility functions, I added a total of nine lines of code to the main program. Before entering the blocks that retrieve and display the terminal capabilities, I want to clear the screen (lines 30, 42, and 53). Inside of each block (lines 32, 44, and 55) the new calls to mv_cursor() position the screen cursor on the i’th row in the tenth column. Finally, after exiting each for loop, a sleep() statement allows you to view the output and see the terminfo function calls do their work. One final note before ending this chapter. I recognize that the programs used to illustrate termios and terminfo features are neither optimized nor efficient. I eschewed fast, effi- cient code for didactic clarity. For example, the three for loops in Listings 26.3 and 26.4 could be collapsed into a single for loop by using a function pointer. I preferred to make the illustrations clear and unambiguous without troubling you to decipher C idioms. Programming the User Interface P ART IV 430 3172316072 CH26 7/26/99 1:38 PM Page 430 Summary This chapter took a detailed look at two very low-level interfaces for terminal manipula- tion. It is a large subject, however, so the coverage was not exhaustive. For additional resources, see the man pages for terminfo(5), termios(3), and term(5). The canonical technical reference is the O’Reilly book, termcap & terminfo, by John Strang, Linda Mui, and Tim O’Reilly. The next chapter looks at ncurses, a much easier way to use a set of libraries for manipulating terminals. Terminal Control the Hard Way C HAPTER 26 431 26 TERMINAL CONTROL THE HARD WAY 3172316072 CH26 7/26/99 1:38 PM Page 431 [...]... #include #include SCREEN MANIPULATION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 initcurs.c 32723 160 72 CH27 7/ 26/ 99 1:37 PM Page 442 442 Programming the User Interface PART IV Listing 27.2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 newterm.c /* * Listing 27.2 * newterm.c -curses initialization and... 26 noecho(); 27 while((c = getch()) != ‘\n’ && i < 80) { 28 str[i++] = c; 29 waddch(pwin, ‘*’); 30 wrefresh(pwin); continues WITH NCURSES Listing 27 .6 27 SCREEN MANIPULATION The manual pages curs_getch(3), curs_getstr(3), and curs_scanw(3) fully document these routines and their various permutations Their usage is illustrated in Listings 27 .6 and 27.7 32723 160 72 CH27 7/ 26/ 99 1:37 PM Page 454 454 Programming. .. printw(“Enter your name: “); refresh(); getnstr(pstr, 20); printw(“You entered: %s\n”, pstr); refresh(); sleep(3); SCREEN MANIPULATION 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 } 455 32723 160 72 CH27 7/ 26/ 99 1:37 PM Page 4 56 4 56 Programming the User Interface PART IV ncurses’ default colors are: COLOR_BLACK COLOR_RED COLOR_GREEN COLOR_YELLOW COLOR_BLUE COLOR_MAGENTA COLOR_CYAN COLOR_WHITE...31723 160 72 CH 26 7/ 26/ 99 1:38 PM Page 432 432 CHAPTER 27 32723 160 72 CH27 7/ 26/ 99 1:37 PM Page 433 Screen Manipulation with ncurses by Kurt Wall IN THIS CHAPTER • A Short History of ncurses • Compiling with ncurses 434 435 • Debugging ncurses Programs • About Windows 4 36 • Initialization and Termination • Input and Output • Color Routines... the screen Lines 21–25 repeat the process using the window-specific routines and stdscr as the target window 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 449 32723 160 72 CH27 7/ 26/ 99 1:37 PM Page 450 450 Programming the User Interface PART IV LISTING 27.4 CONTINUED 26 err_quit(“newwin”); 27 28 mvwaddstr(tmpwin, 1, 1, “This message should appear in a new ➥window”); 29 wborder(tmpwin,... ch); winsch(WINDOW *win, chtype ch); mvinsch(int y, int x, chtype ch); mvwinsch(WINDOW *win, int y, int x, chtype ch); SCREEN MANIPULATION int int int int int int int int int int 32723 160 72 CH27 7/ 26/ 99 1:37 PM Page 4 46 4 46 Programming the User Interface PART IV four routines taking an int n argument, addchnstr(), waddchnstr(), mvaddchnstr(), and mvwaddchnstr(), copy a limit of up to n characters, stopping... NCURSES #include SCREEN MANIPULATION To compile a program with ncurses, you need its function and variable definitions, so include in your source code: 27 32723 160 72 CH27 7/ 26/ 99 1:37 PM Page 4 36 4 36 Programming the User Interface PART IV About Windows This section discusses ncurses’ idea of windows, screens, and terminals Several terms are used repeatedly (and, hopefully, consistently)... output functions Listing 27.3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 curschar.c /* * Listing 27.3 * curschar.c - curses character output functions */ #include #include #include #include “utilfcns.h” int main(void) { app_init(); addch(‘X’); addch(‘Y’ | A_REVERSE); mvaddch(2, 1, ‘Z’ | A_BOLD); refresh(); sleep(3); 32723 160 72 CH27 7/ 26/ 99 1:37 PM Page 449 Screen Manipulation... window border (line 37) Listing 27.7 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cursgstr.c /* * Listing 27.7 * cursgstr.c - curses string input functions */ #include #include #include #include #include “utilfcns.h” int main(int argc, char *argv[]) { int c, i = 0; char str[20]; char *pstr; app_init(); 32723 160 72 CH27 7/ 26/ 99 1:37 PM Page 455 Screen Manipulation with... 35 clear(); 36 wborder(stdscr, ACS_VLINE | A_BOLD, ACS_VLINE | A_BOLD, 37 ACS_HLINE | A_BOLD, ACS_HLINE | A_BOLD, 38 ACS_ULCORNER | A_BOLD, ACS_URCORNER | A_BOLD, \ 39 ACS_LLCORNER | A_BOLD, ACS_LRCORNER | A_BOLD); 40 mvprintw(ymax / 3 - 1, (xmax - 25) / 2, “border drawn with ➥wborder”); 41 refresh(); 42 sleep(3); 43 44 app_exit(); 45 } 451 32723 160 72 CH27 7/ 26/ 99 1:37 PM Page 452 452 Programming the . Way C HAPTER 26 429 26 TERMINAL CONTROL THE HARD WAY continues 31723 160 72 CH 26 7/ 26/ 99 1:38 PM Page 429 LISTING 26. 4 CONTINUED 61 } 62 sleep(3); 63 64 exit(0); 65 } 66 67 /* 68 * Clear the screen 69 */ 70. terminals. Terminal Control the Hard Way C HAPTER 26 431 26 TERMINAL CONTROL THE HARD WAY 31723 160 72 CH 26 7/ 26/ 99 1:38 PM Page 431 432 31723 160 72 CH 26 7/ 26/ 99 1:38 PM Page 432 IN THIS CHAPTER • A Short. visual bell (flash screen) kf[0 -63 ] string F[0 -63 ] function key Terminal Control the Hard Way C HAPTER 26 423 26 TERMINAL CONTROL THE HARD WAY 31723 160 72 CH 26 7/ 26/ 99 1:38 PM Page 423 To use terminfo,