xref: /freebsd/contrib/ncurses/ncurses/tinfo/lib_tputs.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
1 /****************************************************************************
2  * Copyright (c) 1998 Free Software Foundation, Inc.                        *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28 
29 /****************************************************************************
30  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
31  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32  ****************************************************************************/
33 
34 
35 /*
36  *	tputs.c
37  *		delay_output()
38  *		_nc_outch()
39  *		tputs()
40  *
41  */
42 
43 #include <curses.priv.h>
44 #include <ctype.h>
45 #include <term.h>	/* padding_baud_rate, xon_xoff */
46 #include <termcap.h>	/* ospeed */
47 #include <tic.h>
48 
49 MODULE_ID("$Id: lib_tputs.c,v 1.39 1999/02/25 10:44:29 tom Exp $")
50 
51 #define OUTPUT ((SP != 0) ? SP->_ofp : stdout)
52 
53 char PC;		/* used by termcap library */
54 speed_t ospeed;		/* used by termcap library */
55 
56 int _nc_nulls_sent;	/* used by 'tack' program */
57 
58 static int (*my_outch)(int c) = _nc_outch;
59 
60 int delay_output(int ms)
61 {
62 	T((T_CALLED("delay_output(%d)"), ms));
63 
64 	if (no_pad_char)
65 		napms(ms);
66 	else {
67 		register int	nullcount;
68 
69 		nullcount = (ms * _nc_baudrate(ospeed)) / 10000;
70 		for (_nc_nulls_sent += nullcount; nullcount > 0; nullcount--)
71 			my_outch(PC);
72 		if (my_outch == _nc_outch)
73 			(void) fflush(OUTPUT);
74 	}
75 
76 	returnCode(OK);
77 }
78 
79 int _nc_outch(int ch)
80 {
81 #ifdef TRACE
82     	_nc_outchars++;
83 #endif /* TRACE */
84 
85 	putc(ch, OUTPUT);
86 	return OK;
87 }
88 
89 int putp(const char *string)
90 {
91 	return tputs(string, 1, _nc_outch);
92 }
93 
94 int tputs(const char *string, int affcnt, int (*outc)(int))
95 {
96 bool	always_delay;
97 bool	normal_delay;
98 int	number;
99 #ifdef BSD_TPUTS
100 int	trailpad;
101 #endif /* BSD_TPUTS */
102 
103 #ifdef TRACE
104 char	addrbuf[32];
105 
106 	if (_nc_tracing & TRACE_TPUTS)
107 	{
108 		if (outc == _nc_outch)
109 			(void) strcpy(addrbuf, "_nc_outch");
110 		else
111 			(void) sprintf(addrbuf, "%p", outc);
112 		if (_nc_tputs_trace) {
113 			TR(TRACE_MAXIMUM, ("tputs(%s = %s, %d, %s) called", _nc_tputs_trace, _nc_visbuf(string), affcnt, addrbuf));
114 		}
115 		else {
116 			TR(TRACE_MAXIMUM, ("tputs(%s, %d, %s) called", _nc_visbuf(string), affcnt, addrbuf));
117 		}
118 		_nc_tputs_trace = (char *)NULL;
119 	}
120 #endif /* TRACE */
121 
122 	if (!VALID_STRING(string))
123 		return ERR;
124 
125 	if (cur_term == 0) {
126 		always_delay = FALSE;
127 		normal_delay = TRUE;
128 	} else {
129 		always_delay = (string == bell) || (string == flash_screen);
130 		normal_delay =
131 		 !xon_xoff
132 		 && padding_baud_rate
133 #ifdef NCURSES_NO_PADDING
134 		 && (SP == 0 || !(SP->_no_padding))
135 #endif
136 		 && (_nc_baudrate(ospeed) >= padding_baud_rate);
137 	}
138 
139 #ifdef BSD_TPUTS
140 	/*
141 	 * This ugly kluge deals with the fact that some ancient BSD programs
142 	 * (like nethack) actually do the likes of tputs("50") to get delays.
143 	 */
144 	trailpad = 0;
145 	if (isdigit(*string)) {
146 		while (isdigit(*string)) {
147 			trailpad = trailpad * 10 + (*string - '0');
148 			string++;
149 		}
150 		trailpad *= 10;
151 		if (*string == '.') {
152 			string++;
153 			if (isdigit(*string)) {
154 				trailpad += (*string - '0');
155 				string++;
156 			}
157 			while (isdigit(*string))
158 				string++;
159 		}
160 
161 		if (*string == '*') {
162 			trailpad *= affcnt;
163 			string++;
164 		}
165 	}
166 #endif /* BSD_TPUTS */
167 
168 	my_outch = outc;	/* redirect delay_output() */
169 	while (*string) {
170 		if (*string != '$')
171 			(*outc)(*string);
172 		else {
173 			string++;
174 			if (*string != '<') {
175 				(*outc)('$');
176 				if (*string)
177 				    (*outc)(*string);
178 			} else {
179 				bool mandatory;
180 
181 				string++;
182 				if ((!isdigit(*string) && *string != '.') || !strchr(string, '>')) {
183 					(*outc)('$');
184 					(*outc)('<');
185 					continue;
186 				}
187 
188 				number = 0;
189 				while (isdigit(*string)) {
190 					number = number * 10 + (*string - '0');
191 					string++;
192 				}
193 				number *= 10;
194 				if (*string == '.') {
195 					string++;
196 					if (isdigit(*string)) {
197 						number += (*string - '0');
198 						string++;
199 					}
200 					while (isdigit(*string))
201 						string++;
202 				}
203 
204 				mandatory = FALSE;
205 				while (*string == '*' || *string == '/')
206 				{
207 					if (*string == '*') {
208 						number *= affcnt;
209 						string++;
210 					}
211 					else /* if (*string == '/') */ {
212 						mandatory = TRUE;
213 						string++;
214 					}
215 				}
216 
217 				if (number > 0
218 				 && (always_delay
219 				  || normal_delay
220 				  || mandatory))
221 					delay_output(number/10);
222 
223 			} /* endelse (*string == '<') */
224 		} /* endelse (*string == '$') */
225 
226 		if (*string == '\0')
227 			break;
228 
229 		string++;
230 	}
231 
232 #ifdef BSD_TPUTS
233 	/*
234 	 * Emit any BSD-style prefix padding that we've accumulated now.
235 	 */
236 	if (trailpad > 0
237 	 && (always_delay || normal_delay))
238 		delay_output(trailpad/10);
239 #endif /* BSD_TPUTS */
240 
241 	my_outch = _nc_outch;
242 	return OK;
243 }
244