xref: /openbsd/lib/libcurses/tinfo/lib_tputs.c (revision 7b36286a)
1 /*	$OpenBSD: lib_tputs.c,v 1.11 2003/03/18 16:55:54 millert Exp $	*/
2 
3 /****************************************************************************
4  * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc.              *
5  *                                                                          *
6  * Permission is hereby granted, free of charge, to any person obtaining a  *
7  * copy of this software and associated documentation files (the            *
8  * "Software"), to deal in the Software without restriction, including      *
9  * without limitation the rights to use, copy, modify, merge, publish,      *
10  * distribute, distribute with modifications, sublicense, and/or sell       *
11  * copies of the Software, and to permit persons to whom the Software is    *
12  * furnished to do so, subject to the following conditions:                 *
13  *                                                                          *
14  * The above copyright notice and this permission notice shall be included  *
15  * in all copies or substantial portions of the Software.                   *
16  *                                                                          *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
20  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
23  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
24  *                                                                          *
25  * Except as contained in this notice, the name(s) of the above copyright   *
26  * holders shall not be used in advertising or otherwise to promote the     *
27  * sale, use or other dealings in this Software without prior written       *
28  * authorization.                                                           *
29  ****************************************************************************/
30 
31 /****************************************************************************
32  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
33  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
34  ****************************************************************************/
35 
36 /*
37  *	tputs.c
38  *		delay_output()
39  *		_nc_outch()
40  *		tputs()
41  *
42  */
43 
44 #include <curses.priv.h>
45 #include <ctype.h>
46 #include <term.h>		/* padding_baud_rate, xon_xoff */
47 #include <termcap.h>		/* ospeed */
48 #include <tic.h>
49 
50 MODULE_ID("$From: lib_tputs.c,v 1.55 2000/12/10 02:55:08 tom Exp $");
51 
52 NCURSES_EXPORT_VAR(char)
53 PC = 0;				/* used by termcap library */
54 NCURSES_EXPORT_VAR(NCURSES_OSPEED) ospeed = 0;	/* used by termcap library */
55 
56 NCURSES_EXPORT_VAR(int)
57 _nc_nulls_sent = 0;		/* used by 'tack' program */
58 
59      static int (*my_outch) (int c) = _nc_outch;
60 
61 NCURSES_EXPORT(int)
62 delay_output(int ms)
63 {
64     T((T_CALLED("delay_output(%d)"), ms));
65 
66     if (no_pad_char) {
67 	_nc_flush();
68 	napms(ms);
69     } else {
70 	register int nullcount;
71 
72 	nullcount = (ms * _nc_baudrate(ospeed)) / 10000;
73 	for (_nc_nulls_sent += nullcount; nullcount > 0; nullcount--)
74 	    my_outch(PC);
75 	if (my_outch == _nc_outch)
76 	    _nc_flush();
77     }
78 
79     returnCode(OK);
80 }
81 
82 NCURSES_EXPORT(void)
83 _nc_flush(void)
84 {
85     (void) fflush(NC_OUTPUT);
86 }
87 
88 NCURSES_EXPORT(int)
89 _nc_outch(int ch)
90 {
91 #ifdef TRACE
92     _nc_outchars++;
93 #endif /* TRACE */
94 
95     if (SP != 0
96 	&& SP->_cleanup) {
97 	char tmp = ch;
98 	/*
99 	 * POSIX says write() is safe in a signal handler, but the
100 	 * buffered I/O is not.
101 	 */
102 	write(fileno(NC_OUTPUT), &tmp, 1);
103     } else {
104 	putc(ch, NC_OUTPUT);
105     }
106     return OK;
107 }
108 
109 #if USE_WIDEC_SUPPORT
110 /*
111  * Reference: The Unicode Standard 2.0
112  *
113  * No surrogates supported (we're storing only one 16-bit Unicode value per
114  * cell).
115  */
116 NCURSES_EXPORT(int)
117 _nc_utf8_outch(int ch)
118 {
119     static const unsigned byteMask = 0xBF;
120     static const unsigned otherMark = 0x80;
121     static const unsigned firstMark[] =
122     {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
123 
124     int result[7], *ptr;
125     int count = 0;
126 
127     if ((unsigned int) ch < 0x80)
128 	count = 1;
129     else if ((unsigned int) ch < 0x800)
130 	count = 2;
131     else if ((unsigned int) ch < 0x10000)
132 	count = 3;
133     else if ((unsigned int) ch < 0x200000)
134 	count = 4;
135     else if ((unsigned int) ch < 0x4000000)
136 	count = 5;
137     else if ((unsigned int) ch <= 0x7FFFFFFF)
138 	count = 6;
139     else {
140 	count = 3;
141 	ch = 0xFFFD;
142     }
143     ptr = result + count;
144     switch (count) {
145     case 6:
146 	*--ptr = (ch | otherMark) & byteMask;
147 	ch >>= 6;
148 	/* FALLTHRU */
149     case 5:
150 	*--ptr = (ch | otherMark) & byteMask;
151 	ch >>= 6;
152 	/* FALLTHRU */
153     case 4:
154 	*--ptr = (ch | otherMark) & byteMask;
155 	ch >>= 6;
156 	/* FALLTHRU */
157     case 3:
158 	*--ptr = (ch | otherMark) & byteMask;
159 	ch >>= 6;
160 	/* FALLTHRU */
161     case 2:
162 	*--ptr = (ch | otherMark) & byteMask;
163 	ch >>= 6;
164 	/* FALLTHRU */
165     case 1:
166 	*--ptr = (ch | firstMark[count]);
167 	break;
168     }
169     while (count--)
170 	_nc_outch(*ptr++);
171     return OK;
172 }
173 #endif
174 
175 NCURSES_EXPORT(int)
176 putp(const char *string)
177 {
178     return tputs(string, 1, _nc_outch);
179 }
180 
181 NCURSES_EXPORT(int)
182 tputs
183 (const char *string, int affcnt, int (*outc) (int))
184 {
185     bool always_delay;
186     bool normal_delay;
187     int number;
188 #if BSD_TPUTS
189     int trailpad;
190 #endif /* BSD_TPUTS */
191 
192 #ifdef TRACE
193     char addrbuf[32];
194 
195     if (_nc_tracing & TRACE_TPUTS) {
196 	if (outc == _nc_outch)
197 	    (void) strlcpy(addrbuf, "_nc_outch", sizeof(addrbuf));
198 	else
199 	    (void) snprintf(addrbuf, sizeof(addrbuf), "%p", outc);
200 	if (_nc_tputs_trace) {
201 	    _tracef("tputs(%s = %s, %d, %s) called", _nc_tputs_trace,
202 		    _nc_visbuf(string), affcnt, addrbuf);
203 	} else {
204 	    _tracef("tputs(%s, %d, %s) called", _nc_visbuf(string), affcnt, addrbuf);
205 	}
206 	_nc_tputs_trace = (char *) NULL;
207     }
208 #endif /* TRACE */
209 
210     if (!VALID_STRING(string))
211 	return ERR;
212 
213     if (cur_term == 0) {
214 	always_delay = FALSE;
215 	normal_delay = TRUE;
216     } else {
217 	always_delay = (string == bell) || (string == flash_screen);
218 	normal_delay =
219 	    !xon_xoff
220 	    && padding_baud_rate
221 #if NCURSES_NO_PADDING
222 	    && (SP == 0 || !(SP->_no_padding))
223 #endif
224 	    && (_nc_baudrate(ospeed) >= padding_baud_rate);
225     }
226 
227 #if BSD_TPUTS
228     /*
229      * This ugly kluge deals with the fact that some ancient BSD programs
230      * (like nethack) actually do the likes of tputs("50") to get delays.
231      */
232     trailpad = 0;
233     if (isdigit(*string)) {
234 	while (isdigit(*string)) {
235 	    trailpad = trailpad * 10 + (*string - '0');
236 	    string++;
237 	}
238 	trailpad *= 10;
239 	if (*string == '.') {
240 	    string++;
241 	    if (isdigit(*string)) {
242 		trailpad += (*string - '0');
243 		string++;
244 	    }
245 	    while (isdigit(*string))
246 		string++;
247 	}
248 
249 	if (*string == '*') {
250 	    trailpad *= affcnt;
251 	    string++;
252 	}
253     }
254 #endif /* BSD_TPUTS */
255 
256     my_outch = outc;		/* redirect delay_output() */
257     while (*string) {
258 	if (*string != '$')
259 	    (*outc) (*string);
260 	else {
261 	    string++;
262 	    if (*string != '<') {
263 		(*outc) ('$');
264 		if (*string)
265 		    (*outc) (*string);
266 	    } else {
267 		bool mandatory;
268 
269 		string++;
270 		if ((!isdigit(CharOf(*string)) && *string != '.')
271 		    || !strchr(string, '>')) {
272 		    (*outc) ('$');
273 		    (*outc) ('<');
274 		    continue;
275 		}
276 
277 		number = 0;
278 		while (isdigit(CharOf(*string))) {
279 		    number = number * 10 + (*string - '0');
280 		    string++;
281 		}
282 		number *= 10;
283 		if (*string == '.') {
284 		    string++;
285 		    if (isdigit(CharOf(*string))) {
286 			number += (*string - '0');
287 			string++;
288 		    }
289 		    while (isdigit(CharOf(*string)))
290 			string++;
291 		}
292 
293 		mandatory = FALSE;
294 		while (*string == '*' || *string == '/') {
295 		    if (*string == '*') {
296 			number *= affcnt;
297 			string++;
298 		    } else {	/* if (*string == '/') */
299 			mandatory = TRUE;
300 			string++;
301 		    }
302 		}
303 
304 		if (number > 0
305 		    && (always_delay
306 			|| normal_delay
307 			|| mandatory))
308 		    delay_output(number / 10);
309 
310 	    }			/* endelse (*string == '<') */
311 	}			/* endelse (*string == '$') */
312 
313 	if (*string == '\0')
314 	    break;
315 
316 	string++;
317     }
318 
319 #if BSD_TPUTS
320     /*
321      * Emit any BSD-style prefix padding that we've accumulated now.
322      */
323     if (trailpad > 0
324 	&& (always_delay || normal_delay))
325 	delay_output(trailpad / 10);
326 #endif /* BSD_TPUTS */
327 
328     my_outch = _nc_outch;
329     return OK;
330 }
331