1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 1997 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
26 */
27
28/*	Copyright (c) 1988 AT&T	*/
29/*	  All Rights Reserved  	*/
30
31/* Copyright (c) 1979 Regents of the University of California */
32
33#pragma ident	"%Z%%M%	%I%	%E% SMI"
34
35/*LINTLIBRARY*/
36
37#include	<sys/types.h>
38#include	<ctype.h>
39#include	"curses_inc.h"
40
41/*
42 * Put the character string cp out, with padding.
43 * The number of affected lines is affcnt, and the routine
44 * used to output one character is outc.
45 */
46static	char	*ocp;
47
48static	char	*
49_tpad(char *, int, int (*)(char));
50
51static	char	*
52_tpad(char *cp, int affcnt, int (*outc)(char x))
53{
54	int	delay = 0;
55	char	*icp = cp;
56	int	ignorexon = 0, doaffcnt = 0;
57
58#ifdef	_VR2_COMPAT_CODE
59	/*
60	 * Why is this here?
61	 * Because mandatory padding must be used for flash_screen
62	 * and bell. We cannot force users to code mandatory padding
63	 * in their terminfo entries, as that would break compatibility.
64	 * We therefore, do it here.
65	 *
66	 * When compatibility is to be broken, it will go away
67	 * and users will be informed that they MUST use mandatory
68	 * padding for flash and bell.
69	 */
70	if (ocp == bell || ocp == flash_screen)
71		ignorexon = TRUE;
72#endif	/* _VR2_COMPAT_CODE */
73
74	/* Eat initial $< */
75	cp += 2;
76
77	/* Convert the number representing the delay. */
78	if (isdigit(*cp)) {
79		do
80			delay = delay * 10 + *cp++ - '0';
81		while (isdigit(*cp));
82	}
83	delay *= 10;
84	if (*cp == '.') {
85		cp++;
86		if (isdigit(*cp))
87			delay += *cp - '0';
88	/* Only one digit to the right of the decimal point. */
89		while (isdigit(*cp))
90			cp++;
91	}
92
93	/*
94	 * If the delay is followed by a `*', then
95	 * multiply by the affected lines count.
96	 * If the delay is followed by a '/', then
97	 * the delay is done irregardless of xon/xoff.
98	 */
99	/*CONSTCOND*/
100	while (TRUE) {
101		if (*cp == '/')
102			ignorexon = TRUE;
103		else
104			if (*cp == '*')
105				doaffcnt = TRUE;
106			else
107				break;
108		cp++;
109	}
110	if (doaffcnt)
111		delay *= affcnt;
112	if (*cp == '>')
113		cp++;	/* Eat trailing '>' */
114	else {
115	/*
116	 * We got a "$<" with no ">".  This is usually caused by
117	 * a cursor addressing sequence that happened to generate
118	 * $ < .  To avoid an infinite loop, we output the $ here
119	 * and pass back the rest.
120	 */
121		(*outc)(*icp++);
122		return (icp);
123	}
124
125	/*
126	 * If no delay needed, or output speed is
127	 * not comprehensible, then don't try to delay.
128	 */
129	if (delay == 0)
130		return (cp);
131	/*
132	 * Let handshaking take care of it - no extra cpu load from pads.
133	 * Also, this will be more optimal since the pad info is usually
134	 * worst case.  We only use padding info for such terminals to
135	 * estimate the cost of a capability in choosing the cheapest one.
136	 * Some capabilities, such as flash_screen, really want the
137	 * padding irregardless.
138	 */
139	if (xon_xoff && !ignorexon)
140		return (cp);
141	(void) _delay(delay, outc);
142	return (cp);
143}
144
145int
146tputs(char *cp, int affcnt, int (*outc)(char))
147{
148	if (cp != 0) {
149		ocp = cp;
150
151		/* The guts of the string. */
152		while (*cp)
153			if (*cp == '$' && cp[1] == '<')
154				cp = _tpad(cp, affcnt, outc);
155			else
156				(*outc)(*cp++);
157	}
158	return (OK);
159}
160