Line 33 turns off canonical mode, local echo, and ignores sig-nals; line 34 turns of the CRto NLtranslation, and line 35 turns off all output processing.After updating the terminal attri
Trang 1The two error handling functions declared and defined on lines 10–12 and 62–73, tively, are strictly for convenience The program creates a signal-handling function todemonstrate that it catches some signals (lines 13, 57–60) The program’s real meatappears in lines 31–39 Line 33 turns off canonical mode, local echo, and ignores sig-nals; line 34 turns of the CRto NLtranslation, and line 35 turns off all output processing.After updating the terminal attributes, the loop on lines 43–46 reads input one character
respec-at a time and outputs it to the screen in octal notrespec-ation If you press the Delete key, theprogram exits after restoring the original terminal settings
A sample run of the program looks like the following:
Wheretermiosgives you very low-level control over input processing,terminfogivesyou a similar level of control over output processing terminfoprovides a portable, low-level interface to operations such as clearing a terminal screen, positioning the cursor, ordeleting lines or characters Due to the wide variety of terminals in existence, UNIX’sdesigners (eventually) learned to standardize descriptions of terminal capabilities in cen-trally located database files The word “terminfo” refers both to this database and to theroutines that access it
NOTE
Strictly speaking, the termcap database, first used in BSD-derived systems, 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.
Trang 2pre-terminfo Capabilities
For each possible terminal type, such as VT100 or xterm,terminfomaintains 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
• stringBoolean capnames simply indicate whether or not a terminal supports a specific feature,such as cursor addressing or a fast screen-clearing function Numeric capnames usuallydefine 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 terminfoknows; for acomplete list, refer to the terminfo(5)man page
lines numeric Number of lines/rows on current terminal colors numeric Number of colors current terminal supports
Trang 3To 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 -lcursesto the compiler invocation.
Using terminfo
In pseudo-code, the following is the usual sequence of instructions for using terminfo:
1 Initialize the terminfodata 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–5Initializing the terminfodata structures is simple, as shown in the following code:
#include <curses.h>
#include <term.h>
int setupterm(const char *term, int filedes, int *errret);
termspecifies the terminal type If it is null,setupterm()reads $TERMfrom the ment; otherwise,setupterm()uses the value to which termpoints All output is sent tothe file or device opened on the file descriptor filedes If errretis not null, it willeither be 1 to indicate success, 0 if the terminal referenced in termcould not be found inthe terminfodatabase, or -1 if the terminfodatabase could not be found setupterm()
environ-returns OK to indicate success or ERR on failure If errretis null,setupterm()emits adiagnostic message and exits
Each of the three classes of capabilities (boolean, numeric, and string) has a ing function to retrieve a capability, as described in the following:
correspond-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 capnameisn’t a boolean capability
int tigetnum(const char *capname);
Returns the numeric value of capname, ERR if the terminal specified by termin
setupterm()doesn’t support capname, or -2 if capnameisn’t a numeric capability
char *tigetstr(const char *capname);
Returns a pointer to charcontaining the escape sequence for capname, (char *)null if the terminal specified by termin setupterm()doesn’t support capname,
or (char *)-1 if capnameisn’t a string capability
Trang 4Listing 26.3 uses these functions to query and print a few of the current terminal’s capabilities.
19 char *boolcaps[NUMCAPS] = { “am”, “bce”, “km” };
20 char *numcaps[NUMCAPS] = { “cols”, “lines”, “colors” };
21 char *strcaps[NUMCAPS] = { “cup”, “flash”, “hpa” };
Trang 551 printf(“`%s’ is \\E%s\n”, strcaps[i], &buf[1]);
52 /*printf(“`%s’ is %s\n”, strcaps[i], buf);*/
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 charthat contains the escape sequence necessary toinvoke 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 ple, the visual bell, the program strips off the first character,E\(ESC), and prints out therest of the string For our purposes, however, this approach is not optimal because itdoesn’t display the complete escape sequence As a result, on line 51 we print static text,
exam-\\E, to escape the escape sequence
To see how the program would behave if we did not take this precaution, comment outline 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
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.
Trang 6Working with terminfo Capabilities
Now that you know how to get terminal capabilities, the next step is to update them andput them into effect tparm()modifies a capname; putp()and tputs()output thechange 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 strto 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 ingly more complex interface It is prototyped as:
correspond-int tputs(const char *str, correspond-int affcnt, correspond-int (*putc)(correspond-int));
tputs()outputs strto the termand filedesspecified in setupterm() strmust be a
terminfostring variable or the return value from a tparm()or tigetstr()call affcnt
is the number of lines affected if stris a line-related capability or 1 if not applicable
putcis a pointer to any putchar-style output function that outputs characters one at atime
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 strandthe parameters p1-p9 It returns a pointer to an updated copy of strcontaining the newparameters 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 itdefines a generic capability; in this case, moving the cursor to a specific location on thescreen, which requires arguments, or parameters In the case of the cupcapability, itneeds a row number and a column number to know where to place the cursor To movethe cursor on a standard (monochrome) xterm, xterm expects a command that, in semi-comprehensible language, looks like Escape-[-<row>-;-<column>-H
Trang 7In “terminfo-ese,” this translates to \E[%i%p1%d;%p2%dH The programmer’s job is to ply the row and column numbers, which are indicated using %pN, where N is a valuebetween 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 terminfocharacters and arguments.
Character or Argument Description
%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
%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
These may seem complicated and obscure, but consider the alternative: hard-coding dreds of additional lines of terminal-specific code into your program in order to take intoaccount all the possible terminals on which your program will run Parameterized stringsset up a general format for achieving the same effect on all terminals; all the programmermust do is substitute the correct values for the parameters In my opinion, trading somecryptic-looking strings for hundreds of lines of code is a great trade!
hun-To make all of this more concrete, look at Listing 26.4 It rewrites the last example gram, Listing 26.3, using additional terminal capabilities to create a (hopefully) moreesthetically pleasing screen
Trang 819 char *boolcaps[NUMCAPS] = { “am”, “bce”, “km” };
20 char *numcaps[NUMCAPS] = { “cols”, “lines”, “colors” };
21 char *strcaps[NUMCAPS] = { “cup”, “flash”, “hpa” };
31 for(i = 0; i < NUMCAPS; ++i) {
32 /* position the cursor */
Trang 981 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 tion, respectively Their definitions, lines 70–74 and 79–83, respectively, utilize the
loca-putp()function, since we want to update standard output We save one line of code online 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 toclear the screen (lines 30, 42, and 53) Inside of each block (lines 32, 44, and 55) thenew 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 outputand see the terminfofunction calls do their work
One final note before ending this chapter I recognize that the programs used to illustrate
termiosand terminfofeatures are neither optimized nor efficient I eschewed fast, cient code for didactic clarity For example, the three for loops in Listings 26.3 and 26.4could be collapsed into a single for loop by using a function pointer I preferred to makethe illustrations clear and unambiguous without troubling you to decipher C idioms
Trang 10effi-Summary
This chapter took a detailed look at two very low-level interfaces for terminal tion It is a large subject, however, so the coverage was not exhaustive For additionalresources, see the man pages for terminfo(5),termios(3),and term(5) The canonical
manipula-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
Trang 12I N T HIS C HAPTER
by Kurt Wall
Trang 13This chapter introduces ncurses, the free implementation of the classic UNIX handling library, curses ncurses provides a simple, high-level interface for screen controland manipulation Besides a rich set of functions for controlling the screen’s appearance,ncurses also offers powerful routines for handling keyboard and mouse input, creatingand managing multiple windows, using forms, and panels.
screen-A Short History of ncurses
ncurses, which stands for “new curses,” is a freely redistributable clone of the curseslibraries distributed with the System V Release 4.0 (SVR4) UNIX distributed by BellLabs The term “curses” derives from the phrase “cursor optimization,” succinctlydescribing how curses behaves The SVR4 curses package, in turn, was a continued evo-lution of the curses available with System II UNIX, which itself was based on the origi-nal curses implementation shipped with early Berkeley Software Distribution (BSD)UNIX releases
So, how did curses originate? As you saw in the previous chapter, using termiosor, evenworse, the tty interface, to manipulate the screen’s appearance is code-intensive In addi-tion, it is also terminal-specific, subject to the idiosyncrasies of the multitude of terminaltypes and terminal emulators available Enter the old text-based adventure game, rogue.Ken Arnold, at Berkeley, collected rogue’s termcap-based screen-handling and cursormovement routines into a library that was first distributed with BSD UNIX AT&T’s(also known as Bell Labs) System III UNIX included a much improved curses libraryand the terminfoterminal description database, both written by Mark Horton Horton’scurses implementation included support for color-capable terminals and additional videoattributes
The System V UNIX releases continued curses’ march along the feature trail, addingsupport for forms, menus, and panels Forms enable the programmer to create easy-to-use data entry and display windows, simplifying what is usually a difficult and applica-tion-specific coding task Panels extend curses’ ability to deal with overlapping andstacked windows Menus provide, well, menus, again with a simpler, generalized inter-face Due to space limitations, unfortunately, we will not cover these elements of thencurses package
ncurses’ immediate ancestor was Pavel Curtis’ pcurses package Zeyd Ben-Halim oped ncurses using Curtis’ work as a base Eric Raymond incorporated many enhance-ments and continued ncurses’ development Juergen Pfeifer added most of the supportfor forms and menus to the ncurses package Thomas Dickey currently maintains ncurs-
devel-es, has done the lion’s share of ncurses’ configuration for building on multiple systems,
Trang 14and performs most of the testing A proverbial “cast of thousands” (far more than arecurrently listed in the NEWS file in the source distribution, which is current back to ver-sion 1.9.9e) has contributed fixes and patches over the years.
ncurses’ current version is numbered 4.2, although the 5.0 release is currently in beta In
an interesting irony, ncurses is now the approved replacement for the 4.4BSD’s “classic”
curses, thus having come full circle back to the operating system on which curses nated
origi-Compiling with ncurses
To compile a program with ncurses, you need its function and variable definitions, soinclude <curses.h>in your source code:
#include <curses.h>
Many Linux systems make /usr/include/curses.ha symbolic link to the
/usr/include/ncurses.h, so you could conceivably include <ncurses.h> However, formaximum portability, use <curses.h>because, believe it or not, ncurses is not available
on all UNIX and UNIX-like platforms You will also need to link against the ncurseslibraries, so use the -lcursesoption when linking, or add -lcursesto the LDFLAGS make
variable or the $LDFLAGSenvironment variable:
$ gcc curses_prog.c -o curses_prog –lcurses
Debugging ncurses Programs
By default, debug tracing is disabled in ncurses programs To enable debugging, linkagainst ncurses’ debug library,ncurses_g, and either call trace(N)in your code or setthe environment variable $NCURSES_TRACEto N, where Nis a positive, non-zero integer
Doing so forces debugging output to a file named, appropriately,trace, in the currentdirectory The larger N’s value, the more finely grained and voluminous the debuggingoutput Useful values for Nare documented in <ncurses.h> For example, the standardtrace level,TRACE_ORDINARY, is 31
Trang 15About Windows
This section discusses ncurses’ idea of windows, screens, and terminals Several termsare used repeatedly (and, hopefully, consistently) throughout this chapter, so the follow-ing list defines these terms up front to avoid as much confusion as possible
• Screen—Screen refers to the physical terminal screen in character or console
mode Under the X Window system, “screen” means a terminal emulator window
• Window—Window is used to refer to an independent rectangular area displayed on
a screen It may or may not be the same size as the screen
• stdscr—This is an ncurses data structure, a (WINDOW *), that represents what youcurrently see on the screen It might be one window or a set of windows, but it fillsthe entire screen You can think of it as a palette on which you paint using ncursesroutines
• curscr—Another pointer to a WINDOWdata structure,curscrcontains ncurses’ idea
of what the screen currently looks like Like stdscr, its size is the width andheight of the screen Differences between curscrand stdscrare the changes thatappear on the screen
• Refresh—This word refers both to an ncurses function call and a logical process.
The refresh()function compares curscr, ncurses’ notion of what the screen rently looks like, to stdscr, updates any changes to curscr, and then displaysthose changes to the screen Refresh is also used to denote the process of updatingthe screen
cur-• Cursor—This term, like refresh, has two similar meanings, but always refers to the
location where the next character will be displayed On a screen (the physicalscreen), cursor refers to the location of the physical cursor On a window (an ncurs-
es window), it refers to the logical location where the next character will be played Generally, in this chapter, the second meaning applies ncurses uses a (y,x)ordered pair to locate the cursor on a window
dis-ncurses’ Window Design
ncurses defines window layout sanely and predictably Windows are arranged such thatthe upper-left corner has the coordinates (0,0) and the lower-right corner has the coordi-nates (LINES, COLUMNS), as Figure 27.1 illustrates
Trang 16You are perhaps familiar with the $LINESand $COLSenvironment variables These ables have ncurses equivalents,LINESand COLS, that contain ncurses’ notion of the num-ber of rows and columns, respectively, of the current window’s size Rather than usingthese global variables, however, use the function call getmaxyx()to get the size of thewindow with which you are currently working.
vari-One of ncurses’ chief advantages, in addition to complete freedom from terminal dependent code, is the ability to create and manage multiple windows in addition to thencurses provided stdscr These programmer-defined windows come in two varieties,subwindows and independent windows
Subwindows are created using the subwin()function call They are called subwindowsbecause they create a window from an existing window At the C language level, they arepointers to pointers to some subset of an existing WINDOWdata structure The subset caninclude the entire window or only part of it Subwindows, which you could also callchild or derived windows, can be managed independently of their parent windows, butchanges made to the children will be reflected in the parent
Create new or independent windows with the newwin()call This function returns apointer to a new WINDOWstructure that has no connection to other windows Changesmade to an independent window do not show up on the screen unless explicitly requested The newwin()function adds powerful screen manipulation abilities to yourprogramming repertoire, but, as is often the case with added power, it also entails addi-tional complexity You are required to keep track of the window and explicitly to display
it on the screen, whereas subwindows update on the screen automatically
(80, 24)
An ncurses window
F IGURE 27.1
An ncurses window.
Trang 17ncurses’ Function Naming Conventions
While many of ncurses’ functions are defined to use stdscrby default, there will bemany situations in which you want to operate on a window other than stdscr ncursesuses a systematic and consistently applied naming convention for routines that can apply
to any window In general, functions that can operate on an arbitrary window are fixed with the character “w” and take a (WINDOW *)variable as their first argument.Thus, for example, the move(y,x)call, which moves the cursor to the coordinates speci-fied by y and x on stdscr, can be replaced by wmove(win, y, x), which moves the cur-sor to the specified location in the window win That is,
Likewise, many ncurses input and output functions have forms that combine a move and
an I/O operation in a single call These functions prepend mvto the function name andthe desired (y, x) coordinates to the argument list So, for example, you could write
Trang 18As you might guess at this point, functions also exist that combine an I/O and a movedirected to a specific window So code that looks like
wmove(some_win, y, x);
waddchstr(some_win, str);
can be replaced with one line that reads
mvwaddchstr(some_win, y, x, str);
This sort of shorthand permeates ncurses The convention is simple and easy to pick up
Initialization and Termination
Before you can use ncurses, you must properly initialize the ncurses subsystem, set upvarious ncurses data structures, and query the supporting terminal’s display capabilitiesand characteristics Similarly, before exiting an ncurses-based application, you need toreturn the memory resources ncurses allocates and reset the terminal to its original, pre-ncurses state
ncurses Initialization Structures
The initscr()and newterm()functions handle ncurses initialization requirements
initscr()has two tasks, to create and initialize stdscrand curscr, and to find out theterminal’s capabilities and characteristics by querying the terminfoor termcapdatabase
If it is unable to complete one of these tasks, or if some other error occurs,initscr()
displays useful diagnostic information and terminates the application Call initscr()
before you use any other routines that manipulate stdscror curscr Failure to do so willcause your application to abort with a segmentation fault At the same time, however,only call initscr()when you are certain you need it, such as after other routines thatcheck for program startup errors Finally, functions that change a terminal’s status, such
as cbreak()or noecho(), should be called after initscr()returns The first call to
refresh()after initscr()will clear the screen If it succeeds,initscr()returns apointer to stdscr, which you can save for later use, if necessary, otherwise it returnsNULL and exits the program, printing a useful error message to the display
If your program will send output to or receive input from more than one terminal, use the
newterm()function call instead of initscr() For each terminal with which you expect
to interact, call newterm()once newterm()returns a pointer to a C data structure of type
SCREEN(another ncurses-defined type), to use when referring to that terminal Before youcan send output to or receive input from such a terminal, however, you must make it thecurrent terminal The set_term()call accomplishes this Pass as set_term()’s argumentthe pointer to the SCREEN(returned by a previous newterm()call) that you want to makethe current terminal
Trang 19ncurses Termination
The initialization functions allocate memory resources and reset the terminal state to anncurses-friendly mode Accordingly, you need to free the allocated memory and reset theterminal to its pre-ncurses mode The termination functionsendwin()and delscreen()
do this job When you are through working with a SCREEN, call endwin()before makinganother terminal the current terminal, then call delscreen()on that terminal to releasethe SCREENresources allocated to it, because endwin()does not release memory forscreens created by newterm() If you have not called newterm(), however, and have onlyused curscrand stdscr, all that is required is a single call to endwin()before you exityour application endwin()moves the cursor to the lower left-hand corner of the screen,and resets the terminal to its non-visual, pre-ncurses state The memory allocated to
curscrand stdscris not released because your program can temporarily suspend
ncurs-es by calling endwin(), performing other processing, and then calling refresh().The following provides a reference for each of the functions discussed so far:
SCREEN *newterm(const char *type, FILE *outfd, FILE *infd);
Analog of initscr()for programs that use multiple terminals typeis a string to
be used, if required, in place of the $TERMenvironment variable; if NULL,$TERM
will be used outfdis a pointer to a file to be used for output to this terminal, and
infdis a pointer to a file to be used for input from this terminal Returns a pointer
to the new terminal, which should be saved for future references to the terminal,
or NULL on failure
SCREEN *set_term(SCREEN *new);
Sets the current terminal to the terminal specified by new, which must be a SCREEN
pointer returned from a previous call to newterm() All subsequent input and put and other ncurses routines operate on the terminal to which newrefers Returns
out-a pointer to the old terminout-al or NULL on fout-ailure
void delscreen(SCREEN *sp);
Deallocates memory associated with sp Must be called after endwin()for the terminal associated with sp
Trang 20Illustrating ncurses Initialization and Termination
Listings 27.1 and 27.2 illustrate the usage of the ncurses routines we have looked at sofar The first program,initcurs, shows the standard ncurses initialization and termina-tion idioms, using initscr()and endwin(), while the second one,newterm, demon-strates the proper use of newterm()and delscreen()
18 and 22), we terminate the program, calling endwin()(line 23) to free the resources
Trang 21stdinas the FILEpointers for output and input, respectively Before we can use scr,however, we have to make it the current terminal, thus the call to set_term()on line 18.
If this call fails, we have to make sure to call endwin()and delscreen()to free thememory associated with scr, so we added code to accomplish this in the error checking
on lines 20 and 21 After sending some output to our “terminal” (lines 25 and 29), weshut down the curses subsystem, using the required delscreen()call
Trang 22Input and Output
ncurses has many functions for sending output to and receiving input from screens andwindows It is important to understand that C’s standard input and output routines do notwork with ncurses’ windows Fortunately, ncurses’ I/O routines behave very similarly tothe standard I/O (<stdio.h>) routines, so the learning curve is tolerably shallow
cur-If scrolling has been enabled on the current window (with the scrollok()call) and thecursor is at the bottom of the scrollable region, the region scrolls up one line If ch is atab, newline, or backspace, the cursor moves appropriately Other control characters dis-play using ^Xnotation, where Xis the character and the caret (^) indicates that it is a con-trol character If you need to send the literal control character, use the function
echochar(chtype ch) Almost all of the other output functions do their work with calls
“pseudo-These differences are noted in this chapter when and where appropriate.
As mentioned previously,mvaddch()adds a character to a specified window after ing the cursor to the desired location; mvwaddch()combines a move and an output oper-ation on a specific window.waddch()displays a character to a user-specified window
Trang 23mov-The echochar()function, and its window-specific cousin,wechochar(), combine an
addch()call with a refresh()or wrefresh()call, which can result in substantial formance enhancements when used with non-control characters
per-A particularly useful feature of ncurses routines that use chtypecharacters and strings(discussed next) is that the character or string to be output can be logically ORed with avariety of video attributes before it is displayed A partial list of these attributes includes
A_NORMAL Normal display mode
A_STANDOUT Use the terminal’s best highlighting mode
A_UNDERLINE Underlining
A_REVERSE Use reverse video
A_DIM Half-intensity display
A_BOLD Extra-intensity display
A_INVIS Character will not be visible
A_CHARTEXT Creates a bitmask to extract a characterDepending on the terminal emulator or hardware capabilities of the screen, not all attrib-utes may be possible, however See the curs_attr(3)manual page for more details.Other than control characters and characters enhanced with video attributes, the characteroutput functions also display line graphics characters (characters from the high half ofthe ASCII character set), such as box-drawing characters and various special symbols Acomplete list is available in the curs_addch(3)manual page, but a few of the commonones are listed here:
ACS_ULCORNER upper-left corner
ACS_LLCORNER lower-left corner
ACS_URCORNER upper-right corner
ACS_LRCORNER lower-right corner
ACS_HLINE horizontal line
ACS_VLINE vertical lineThe functions described so far effectively “append” characters to a window without dis-turbing the placement of other characters already present Another group of routinesinserts characters at arbitrary locations in existing window text These functions include
insch(),winsch(),mvinsch(), and mvwinsch() Following the naming convention cussed earlier in this chapter, each of these functions inserts a character before (in frontof) the character under the cursor, shifting the following characters to the right one
Trang 24dis-position; if the right-most character is on the right margin, it will be lost Note, however,
that the cursor position does not change after an insert operation Insertions are
com-pletely documented in the curs_insch(3)manual page The prototypes of the functions
we have mentioned so far are in the following list:
int addch(chtype ch);
int waddch(WINDOW *win, chtype ch);
int mvaddch(int y, int x, chtype ch);
int mvwaddch(WINDOW *win, int y, int x, chtype ch);
int echochar(chtype ch);
int wechochar(WINDOW *win, chtype ch);
int insch(chtype ch);
int winsch(WINDOW *win, chtype ch);
int mvinsch(int y, int x, chtype ch);
int mvwinsch(WINDOW *win, int y, int x, chtype ch);
Unless noted otherwise, all functions that return an integer return OK on success or ERR
on failure (OK and ERR and a number of other constants are defined in <ncurses.h>)
The arguments win,y,x, and chare, respectively, the window in which the character will
be displayed, the y and x coordinates at which to locate the cursor, and the character(including optional attributes) to display As a reminder, routines prefixed with a “w”
take a pointer,win, that specifies the target window; the “mv” prefix combines a moveoperation to the (y, x) location with an output operation
String Routines
ncurses’ string routines generally behave similarly to the character routines, except thatthey deal with strings of pseudo-characters or with normal null-terminated strings Again,ncurses’ designers created a standard notation to help programmers distinguish betweenthe two types of functions Function names containing chstroperate on strings of pseu-do-characters, while function names containing only struse standard C-style (null-terminated) strings A partial list of the functions operating on pseudo-character stringsincludes
int addchstr(const chtype *chstr);
int addchnstr(const chtype *chstr, int n);
int waddchstr(WINDOW *win, const chtype *chstr);
int waddchnstr(WINDOW *win, const chtype *chstr, int n);
int mvaddchstr(int y, int x, const chtype *chstr);
int mvaddchnstr(int y, int x, const chtype *chstr, int n);
int mvwaddchstr(WINDOW *win, int y, int x, const chtype *chstr);
int mvwaddchnstr(WINDOW *win, int y, int x, const chtype *chstr, int n);
All the listed functions copy chstronto the desired window beginning at the cursor’s
location, but the cursor is not advanced (unlike the character output functions) If the
string is longer than will fit on the current line, it is truncated at the right margin The
Trang 25four routines taking an int nargument,addchnstr(),waddchnstr(),mvaddchnstr(),and mvwaddchnstr(), copy a limit of up to ncharacters, stopping at the right margin If n
is -1, the entire string will be copied, but truncated at the right margin as necessary.The next set of string output functions operates on null-terminated strings Unlike the
previous set, these functions advance the cursor In addition, the string output will wrap
at the right margin, rather than being truncated Otherwise, they behave like their
similar-ly named chtypecounterparts
int addstr(const char *str);
int addnstr(const char *str, int n);
int waddstr(WINDOW *win, const char *str);
int waddnstr(WINDOW *win, const char *str, int n);
int mvaddstr(int y, int x, const char *str tr);
int mvaddnstr(int y, int x, const char *str, int n);
int mvwaddstr(WINDOWS *win, int y, int x, const char *str);
int mvwaddnstr(WINDOWS *win, int y, int x, const char *str, int n);
Remember,strin these routines is a standard, C-style, null-terminated character array.The next and last group of output routines we look at are a hodgepodge: calls that drawborders and lines, clear and set the background, control output options, move the cursor,and send formatted output to an ncurses window
Miscellaneous Output Routines
To set the background property of a window, use bkgd(), prototyped as
int bkgd(const chtype ch);
chis an ORed combination of a character and one or more of the video attributes ously listed To obtain the current background setting, call chtype getbkgd(WINDOW
previ-*win);where win is the window in question Complete descriptions of functions settingand getting window backgrounds can be found in the curs_bkgd(3)manual page
At least eleven ncurses functions draw boxes, borders, and lines in ncurses windows The
box()call is the simplest, drawing a box around a specified window using one characterfor vertical lines and another for horizontal lines Its prototype is as follows:
int box(WINDOW *win, chtype verch, chtype horch);
verchsets the pseudo-character used to draw vertical lines and horchfor horizontallines
The box()function:
int border(WINDOW *win, chtype ls, chtype rs, chtype ts, chtype bs,
➥chtype tl, chtype tr, chtype bl, chtype br);
Trang 26The arguments are
win-int hline(chtype ch, win-int n);
int vline(chtype ch, int n);
Following ncurses’ function naming convention, you can also specify a window in which
to draw lines using
int whline(WINDOW *win, chtype ch, int n);
int wvline(WINDOW *win, chtype ch, int n);
or move the cursor to a particular location using
int mvhline(int y, int x, chtype ch, int n);
int mvvline(int y, int x, chtype ch, int n);
or even specify a window and request a move operation with
int mvwhline(WINDOW *win, int y, int x, chtype ch, int n);
int mvwvline(WINDOW *win, int y, int x, chtype ch, int n);
As usual, these routines return OK on success or ERR on failure winindicates the targetwindow; nspecifies the maximum line length, up to the maximum window size vertical-
ly or horizontally The line, box, and border drawing functions do not change the cursorposition Subsequent output operations can overwrite the borders, so you must make sureeither to include calls to maintain border integrity or to set up your output calls such thatthey do not overwrite the borders Functions that do not specifically set the cursor loca-tion (line(),vline(),whline(), and wvline()) start drawing at the current cursor position The manual page documenting these routines is curs_border(3) The
curs_outopts(3)page also contains relevant information
Trang 27The final set of miscellaneous functions to consider clears all or part of the screen Asusual, they are available in both plain and window-specific varieties:
int wclrtoeol(WINDOW *win);
erase()writes blanks to every position in a window; clrtobot()clears the screen fromthe current cursor location to the bottom of the window, inclusive; clrtoeol(), finally,erases the current line from the cursor to the right margin, inclusive If you have used
bkgd()or wbkgd()to set background properties on windows that will be cleared orerased, the property set (called a “rendition” in ncurses’ documentation) is applied toeach of the blanks created The relevant manual page for these calls is curs_clear(3).The following listings illustrate how many of the routines discussed in this section might
be used The sample programs only sample ncurses’ interface because of the broad larity in calling conventions for these functions and the large number of routines Toshorten the listings somewhat, we have moved the initialization and termination codeinto a separate file,utilfcns.c, and #included the header file,utilfcns.h,containing the interface (both files are on the CD-ROM that accompanies this book).Listing, 27.3 illustrates ncurses’ character output functions
Trang 28After refreshing the screen (line 17), a short pause allows you to view the results Notethat until the refresh call, no changes will be visible on the screen Lines 21–25 repeatthe process using the window-specific routines and stdscras the target window.
Listing 27.4 briefly demonstrates using the string output functions
20 mvaddstr(3, 0, “This string appears in full\n”);
21 mvaddnstr(5, 0, “This string is truncated\n”, 15);
Trang 29Listing 27.5 illustrates using line graphics characters and also the box()and wborder()
calls Pay particular attention to lines 17–24 Some ncurses output routines move the sor after output, others do not Note also that the line drawing family of functions, such
cur-as vline()and hline(), draw top to bottom and left to right, so be aware of cursorplacement when using them
Trang 3015 getmaxyx(stdscr, ymax, xmax);
23 mvvline(1, xmax - 1, ACS_VLINE, ymax - 2);
24 mvaddch(ymax - 1, xmax - 1, ACS_LRCORNER);
25 mvprintw(ymax / 3 - 1, (xmax - 30) / 2, “border drawn the
30 box(stdscr, ACS_VLINE, ACS_HLINE);
31 mvprintw(ymax / 3 - 1, (xmax - 30) / 2, “border drawn the
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
Output using ncurses requires a few extra steps compared to using C’s standard library
functions; hopefully we have shown that it is much easier than using termiosor filling
up your code with lots of difficult-to-read newlines, backspaces, and tabs
Trang 31Input Routines
ncurses input routines, like its output routines, fall into several groups This chapter willfocus, however, on simple character and string input for two reasons First and foremost,the routines discussed in this section will meet 90 percent of your needs Second, ncursesinput closely parallels ncurses output, so the material from the previous section shouldserve as a solid foundation
The core input functions can be narrowed down to three:getch(),getstr(), and
scanw() getch()’s prototype is
int getch(void);
It fetches a single character from the keyboard, returning the character or ERR on failure
It may or may not echo the fetched character back to stdscr, depending on whetherechoing is enabled or disabled (thus,wgetch()and variants also obtain single charactersfrom the keyboard and may or may not echo them to a program-specified window) Forcharacters to be echoed, first call echo(); to disable echoing, call noecho() Be awarethat with echoing enabled, characters are displayed on a window using waddch()at thecurrent cursor location, which is then advanced one position
The matter is further complicated by the current input mode, which determines theamount of processing the kernel applies before the program receives the character In anncurses program, you will generally want to process most of the keystrokes yourself
Doing so requires either crmode or raw mode (ncurses begins in default mode, meaning
that the kernel buffers text normally, waiting for a newline before passing keystrokes toncurses—you will rarely want this) In raw mode, the kernel does not buffer or otherwiseprocess any input, while in crmode, the kernel process terminal control characters, such
as ^S,^Q,^C, or ^Y, and passes all others to ncurses unmolested On some systems, theliteral “next character,”^V, may need to be repeated Depending on your application’sneeds, crmode should be sufficient In one of our sample programs, we use crmode,enabling and disabling echoing, to simulate shadowed password retrieval
The getstr()function, declared as
intgetstr(char *str);
repeatedly calls getch()until it encounters a newline or carriage return (which will not
be part of the returned string) The characters input are stored in str Because getstr()
performs no bounds checking, we strongly recommend usinggetnstr()instead, whichtakes an additional argument specifying the maximum number of characters to store.Regardless of whether you use getstror getnstr(), the receiving buffer strmust belarge enough to hold the string received plus a terminating null character, which must beadded programmatically
Trang 32scanw()obtains formatted input from the keyboard in the manner of scanf(3)and
fami-ly In fact, ncurses passes the received characters as input to sscanf(3), so input thatdoes not map to available arguments in the format field goes to the bit bucket As usual,
scanw()has variants for movement operations (the “mv” prefix) and that apply to
specif-ic windows (the “w” prefix) In addition, the scanw()family of functions includes amember for dealing with variable length argument lists,vwscanw() The relevant proto-types are:
int scanw(char *fmt [, arg] );
int vwscanw(WINDOW *win, char *fmt, va_list varglist);
The manual pages curs_getch(3),curs_getstr(3), and curs_scanw(3)fully documentthese routines and their various permutations Their usage is illustrated in Listings 27.6and 27.7
20 getmaxyx(stdscr, ymax, xmax);
21 if((pwin = subwin(stdscr, 3, 40, ymax / 3,
Trang 3336 mvwprintw(pwin, 1, 1, “You typed: %s\n”, str);
37 box(pwin, ACS_VLINE, ACS_HLINE);
we use waddch()to add a “*” to the password window for each character the user types(lines 29 and 30) Upon encountering a newline, we exit the loop, re-enable echoing (line32), terminate the string containing the password (line 33), and then show the user whatshe typed (line 36) Note that wprintw()overwrites the box we drew around the pass-word window, so before refreshing the screen, we redraw the window border (line 37)
Trang 34behavior when you attempt to enter a string longer than indicated by the length limit n.
In this case, ncurses stops accepting and echoing input and issues a beep after you havetyped 20 characters
Color Routines
We have already seen that ncurses supports various highlighting modes Interestingly, italso supports color in the same fashion; that is, you can logically OR the desired colorvalue onto the character arguments of an addch()call or any other output routine thattakes a pseudo-character (chtype) argument The method is tedious, however, so ncursesalso has a set of routines to set display attributes on a per-window basis
Before you use ncurses’ color capabilities, you have to make sure that the current nal supports color The has_colors()call returns TRUE or FALSE depending onwhether or not the current terminal has color capabilities
Trang 35ncurses’ default colors are:
COLOR_BLACK COLOR_RED COLOR_GREEN COLOR_YELLOW COLOR_BLUE COLOR_MAGENTA COLOR_CYAN COLOR_WHITE
Once you have determined that the terminal supports color, call the start_color()
20 /* Set up some simple color assignments */
21 init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK);
22 init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
23 init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK);
24 init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK);
25 init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
26 init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
Trang 3627 init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK);
28 init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
int init_pair(short pair, short f, short b);
This associates pairwith a foreground color fand a background color b, returning OK
on success or ERR on failure
Once the color assignments have been made, we display some text using each pair name
in normal text and in standout mode (lines 30–36) Rather than setting the color
attribut-es for each character displayed, we use the attron()call (lines 31 and 33), which setsthe current display attributes for the current window, in this case,stdscr We use
attroff()to turn off standout mode before moving to the next color pair (line 35);
int attron(int attrs);
int attroff(int attrs);
attrscan be one or more logically ORed combinations of colors and video attributes
As usual, ncurses comes with an extensive set of functions for manipulating window play attributes They are fully documented in the curs_attr(3)manual page The
dis-curs_color(3)manual pages discuss in considerable detail ncurses’ color manipulationinterface
Trang 37Window Management
We have already mentioned a couple of ncurses’ window management functions In thissection, we will discuss them in more detail All of the window manipulation routines aredocumented in the curs_window(3)manual page
WINDOW *newwin(int nlines, in ncols, int begin_y, int begin_x);
int delwin(WINDOW *win);
WINDOW *subwin(WINDOW *orig, int nlines, int ncols, int begin_y,
➥int begin_x);
WINDOW *derwin(WINDOW *orig, int nlines, int ncols, int begin_y,
➥int begin_x);
WINDOW *dupwin(WINDOW *win);
newwin()creates and returns a pointer to a new window with ncolscolumns and nlines
lines The new window’s upper-left corner is positioned at begin_y,begin_x subwin()
and derwin()creates and returns a pointer to a window with ncolscolumns and nlines
rows, positioned in the center of the parent windoworig The child window’s upper-leftcorner is positioned at begin_y,begin_xrelative to the screen, not the parent window
derwin()behaves like subwin()except that the child window will be positioned at
begin_y,begin_xrelative to the parent window orig, not the screen dupwin()creates
an exact duplicate of the parent window orig We have already introduced delwin().Functions that return an integer return OK on success or ERR on failure Those thatreturn pointers return NULL on failure Previous listings have illustrated the use of some
of these functions, so we eschew further demonstration of their usage
Miscellaneous Utility Functions
ncurses’ utility routines give you a potpourri of ncurses’ functionality, including level ncurse functions, obtaining environment information, and creating screen dumps.Screen dumps are interesting The putwin()and getwin()write and read all data associ-ated with a window to or from a file
low-int putwin(WINDOW *win, FILE *filep);
WINDOW *getwin(FILE *filep);
putwin()copies all of the data for winto the file opened on filep, while getwin()
returns a pointer to a WINDOWcreated from the contents of filep.The scr_dump()and scr_restore()functions behave similarly, except that they operate
on ncurses screens rather than on windows You cannot, however, mix calls; attempting
to read data withscr_restore()that was written with putwin()causes an error
int scr_dump(const char *filename);
Trang 38int scr_restore(const char *filename);
filenameis the name of the file to write or read
For additional routines to use when reading and writing screen dumps, see the
curs_scr_dump(3)and curs_util(3)manual pages
ncurses’terminfoand termcaproutines, documented in curs_termattrs(3),
curs_termcap(3), and curs_terminfo(3), report environment information and give youdirect access to the termcapand terminfodatabases The following functions obtaininformation from the terminfoand termcapdatabases
int baudrate(void); Returns the terminal’s output speed in bits per
second
char erasechar(void); Returns the user’s current erase character
char killchar(void); Returns the user’s current kill character
char *termname(void); Returns the value of the environment variable
$TERM, truncated to 14 characters
char *longname(void); Returns a long description of the terminal’s
capabilities, up to 128 charactersUnless you will be programming function keys or have other reasons to access the termi-nal databases directly, there is no need to access the termcapand terminfodatabasesdirectly, so we will not discuss those functions here
In addition to getmaxyx()call you have already seen, there are three other routines used
to obtain cursor and window coordinates:getyx(),getparyx(), and getbegyx()
getyx()returns the coordinates of the cursor; getbegyx()returns the beginning left) coordinates of the window; getparyx(), finally, when called on a subwindow,returns the build window’s beginning coordinates, relative to the parent window
(upper-void getyx(WINDOW *win, int y, int x);
void getbegyx(WINDOW *win, int y, int x);
void getparyx(WINDOW *win, int y, int x);
As with getmaxyx(), these three calls are all macros, so yand xdo not need to be passedwith & Our final sample program, Listing 27.9, illustrates using some of these utilityfunctions
Trang 3927 init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK);
28 init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
29 init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
Trang 4062 mvprintw(1, 1, “ERASE character: %s\n”, unctrl(erasechar()));
63 mvprintw(2, 1, “KILL character : %s\n”, uncntrl(killchar()));
64 mvprintw(3, 1, “BAUDRATE (bps) : %d\n”, baudrate());
65 mvprintw(4, 1, “TERMINAL type : %s\n”, termname());
Summary
Hopefully, this chapter has demonstrated enough of ncurses’ abilities to make clear that it
is both an easier and more powerful interface for manipulating the display than termios
ncurses is a ubiquitous library, used in popular programs such as the mutt mail client, theMidnight Commander file manager, lynx, ncftp, and nvi