1 /* terminal.c -- termcap support
2  *
3  * This code is Copyright (c) 2002, by the authors of nmh.  See the
4  * COPYRIGHT file in the root directory of the nmh distribution for
5  * complete copyright information.
6  */
7 
8 #include <h/mh.h>
9 #include <h/utils.h>
10 
11 #include <sys/ioctl.h>
12 
13 #include <curses.h>
14 #include <term.h>
15 #include <termios.h>
16 
17 #ifdef WINSIZE_IN_PTEM
18 # include <sys/stream.h>
19 # include <sys/ptem.h>
20 #endif
21 
22 static int initLI = 0;
23 static int initCO = 0;
24 
25 static int LI = 40;                /* number of lines                        */
26 static int CO = 80;                /* number of columns                      */
27 static char *ti_clear = NULL;      /* terminfo string to clear screen        */
28 static char *ti_standend = NULL;   /* terminfo string to end standout mode   */
29 static char *ti_standbegin = NULL; /* terminfo string to begin standout mode */
30 static int termstatus = 0;	   /* terminfo initialization status         */
31 static char *termcbuf = NULL;	   /* tputs() output buffer                  */
32 static char *termcbufp = NULL;	   /* tputs() output buffer pointer          */
33 static size_t termcbufsz = 0;	   /* Size of termcbuf                       */
34 
35 static void initialize_terminfo(void);
36 static int termbytes(TPUTS_PUTC_ARG);
37 
38 /*
39  * Initialize the terminfo library.
40  */
41 
42 static void
initialize_terminfo(void)43 initialize_terminfo(void)
44 {
45     int errret, rc;
46 
47     if (termstatus)
48     	return;
49 
50     rc = setupterm(NULL, fileno(stdout), &errret);
51 
52     if (rc != 0 || errret != 1) {
53     	termstatus = -1;
54 	return;
55     }
56     termstatus = 1;
57 
58     if (!initCO && (CO = tigetnum ("cols")) <= 0)
59 	CO = 80;
60     if (!initLI && (LI = tigetnum ("lines")) <= 0)
61 	LI = 24;
62 
63     ti_clear = tigetstr ("clear");
64     ti_standbegin = tigetstr ("smso");
65     ti_standend = tigetstr ("rmso");
66 }
67 
68 
69 int
sc_width(void)70 sc_width (void)
71 {
72 #ifdef TIOCGWINSZ
73     struct winsize win;
74     int width;
75 
76     if (ioctl (fileno (stderr), TIOCGWINSZ, &win) != NOTOK
77 	    && (width = win.ws_col) > 0) {
78 	CO = width;
79 	initCO++;
80     } else
81 #endif /* TIOCGWINSZ */
82 	initialize_terminfo();
83 
84     return CO;
85 }
86 
87 
88 int
sc_length(void)89 sc_length (void)
90 {
91 #ifdef TIOCGWINSZ
92     struct winsize win;
93 
94     if (ioctl (fileno (stderr), TIOCGWINSZ, &win) != NOTOK
95 	    && (LI = win.ws_row) > 0)
96 	initLI++;
97     else
98 #endif /* TIOCGWINSZ */
99 	initialize_terminfo();
100 
101     return LI;
102 }
103 
104 
105 static int
outc(TPUTS_PUTC_ARG c)106 outc (TPUTS_PUTC_ARG c)
107 {
108     return putchar(c);
109 }
110 
111 
112 void
nmh_clear_screen(void)113 nmh_clear_screen (void)
114 {
115     initialize_terminfo ();
116 
117     if (ti_clear)
118 	tputs (ti_clear, LI, outc);
119     else {
120 	putchar('\f');
121     }
122 
123     fflush (stdout);
124 }
125 
126 
127 /*
128  * print in standout mode
129  */
130 int
SOprintf(char * fmt,...)131 SOprintf (char *fmt, ...)
132 {
133     va_list ap;
134 
135     initialize_terminfo ();
136     if (!(ti_standbegin && ti_standend))
137 	return NOTOK;
138 
139     tputs (ti_standbegin, 1, outc);
140 
141     va_start(ap, fmt);
142     vprintf (fmt, ap);
143     va_end(ap);
144 
145     tputs (ti_standend, 1, outc);
146 
147     return OK;
148 }
149 
150 /*
151  * Return the specified capability as a string that has already been
152  * processed with tputs().
153  */
154 
155 char *
get_term_stringcap(char * capability)156 get_term_stringcap(char *capability)
157 {
158     char *parm;
159 
160     initialize_terminfo();
161 
162     if (termstatus == -1)
163     	return NULL;
164 
165     termcbufp = termcbuf;
166 
167     parm = tigetstr(capability);
168 
169     if (parm == (char *) -1 || parm == NULL) {
170     	return NULL;
171     }
172 
173     tputs(parm, 1, termbytes);
174 
175     *termcbufp = '\0';
176 
177     return termcbuf;
178 }
179 
180 /*
181  * Return a parameterized terminfo capability
182  */
183 
184 char *
get_term_stringparm(char * capability,long arg1,long arg2)185 get_term_stringparm(char *capability, long arg1, long arg2)
186 {
187     char *parm;
188 
189     initialize_terminfo();
190 
191     if (termstatus == -1)
192     	return NULL;
193 
194     termcbufp = termcbuf;
195 
196     parm = tigetstr(capability);
197 
198     if (parm == (char *) -1 || parm == NULL) {
199     	return NULL;
200     }
201 
202     parm = tparm(parm, arg1, arg2, 0, 0, 0, 0, 0, 0, 0);
203 
204     tputs(parm, 1, termbytes);
205 
206     *termcbufp = '\0';
207 
208     return termcbuf;
209 }
210 
211 /*
212  * Return the value of the specified numeric capability
213  */
214 
215 int
get_term_numcap(char * capability)216 get_term_numcap(char *capability)
217 {
218     initialize_terminfo();
219 
220     if (termstatus == -1)
221     	return -1;
222 
223     return tigetnum(capability);
224 }
225 
226 /*
227  * Store a sequence of characters in our local buffer
228  */
229 
230 static int
termbytes(TPUTS_PUTC_ARG c)231 termbytes(TPUTS_PUTC_ARG c)
232 {
233     size_t offset;
234 
235     /*
236      * Bump up the buffer size if we've reached the end (leave room for
237      * a trailing NUL)
238      */
239 
240     if ((offset = termcbufp - termcbuf) - 1 >= termcbufsz) {
241         termcbufsz += 64;
242     	termcbuf = mh_xrealloc(termcbuf, termcbufsz);
243 	termcbufp = termcbuf + offset;
244     }
245 
246     *termcbufp++ = c;
247 
248     return 0;
249 }
250