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