1/*	$OpenBSD: tgoto.c,v 1.2 2015/11/15 07:12:50 deraadt Exp $	*/
2/*	$NetBSD: tgoto.c,v 1.5 1995/06/05 19:45:54 pk Exp $	*/
3
4/*
5 * Copyright (c) 1980, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <string.h>
34#include <curses.h>
35
36#define	CTRL(c)	((c) & 037)
37
38#define MAXRETURNSIZE 64
39
40char	*UP;
41char	*BC;
42
43/*
44 * Routine to perform cursor addressing.
45 * CM is a string containing printf type escapes to allow
46 * cursor addressing.  We start out ready to print the destination
47 * line, and switch each time we print row or column.
48 * The following escapes are defined for substituting row/column:
49 *
50 *	%d	as in printf
51 *	%2	like %2d
52 *	%3	like %3d
53 *	%.	gives %c hacking special case characters
54 *	%+x	like %c but adding x first
55 *
56 *	The codes below affect the state but don't use up a value.
57 *
58 *	%>xy	if value > x add y
59 *	%r	reverses row/column
60 *	%i	increments row/column (for one origin indexing)
61 *	%%	gives %
62 *	%B	BCD (2 decimal digits encoded in one byte)
63 *	%D	Delta Data (backwards bcd)
64 *
65 * all other characters are ``self-inserting''.
66 */
67char *
68tgoto(char *CM, int destcol, int destline)
69{
70	static char result[MAXRETURNSIZE];
71	static char added[10];
72	char *cp = CM;
73	char *dp = result;
74	int c;
75	int oncol = 0;
76	int which = destline;
77
78	if (cp == 0) {
79toohard:
80		/*
81		 * ``We don't do that under BOZO's big top''
82		 */
83		return ("OOPS");
84	}
85	added[0] = 0;
86	while ((c = *cp++) != '\0') {
87		if (c != '%') {
88			if (dp >= &result[MAXRETURNSIZE])
89				goto toohard;
90			*dp++ = c;
91			continue;
92		}
93		switch (c = *cp++) {
94
95#ifdef CM_N
96		case 'n':
97			destcol ^= 0140;
98			destline ^= 0140;
99			goto setwhich;
100#endif
101
102		case 'd':
103			if (which < 10)
104				goto one;
105			if (which < 100)
106				goto two;
107			/* fall into... */
108
109		case '3':
110			if (dp >= &result[MAXRETURNSIZE])
111				goto toohard;
112			*dp++ = (which / 100) | '0';
113			which %= 100;
114			/* fall into... */
115
116		case '2':
117two:
118			if (dp >= &result[MAXRETURNSIZE])
119				goto toohard;
120			*dp++ = which / 10 | '0';
121one:
122			if (dp >= &result[MAXRETURNSIZE])
123				goto toohard;
124			*dp++ = which % 10 | '0';
125swap:
126			oncol = 1 - oncol;
127setwhich:
128			which = oncol ? destcol : destline;
129			continue;
130
131#ifdef CM_GT
132		case '>':
133			if (which > *cp++)
134				which += *cp++;
135			else
136				cp++;
137			continue;
138#endif
139
140		case '+':
141			which += *cp++;
142			/* fall into... */
143
144		case '.':
145			/*
146			 * This code is worth scratching your head at for a
147			 * while.  The idea is that various weird things can
148			 * happen to nulls, EOT's, tabs, and newlines by the
149			 * tty driver, arpanet, and so on, so we don't send
150			 * them if we can help it.
151			 *
152			 * Tab is taken out to get Ann Arbors to work, otherwise
153			 * when they go to column 9 we increment which is wrong
154			 * because bcd isn't continuous.  We should take out
155			 * the rest too, or run the thing through more than
156			 * once until it doesn't make any of these, but that
157			 * would make termlib (and hence pdp-11 ex) bigger,
158			 * and also somewhat slower.  This requires all
159			 * programs which use termlib to stty tabs so they
160			 * don't get expanded.  They should do this anyway
161			 * because some terminals use ^I for other things,
162			 * like nondestructive space.
163			 */
164			if ((which == 0 || which == CTRL('d') || which == '\n')
165			    && (oncol || UP)) /* Assumption: backspace works */
166				/*
167				 * Loop needed because newline happens
168				 * to be the successor of tab.
169				 */
170				do {
171					if (strlcat(added, oncol ?
172					    (BC ? BC : "\b") : UP,
173					    sizeof(added)) >= sizeof(added))
174						goto toohard;
175					which++;
176				} while (which == '\n');
177			if (dp >= &result[MAXRETURNSIZE])
178				goto toohard;
179			*dp++ = which;
180			goto swap;
181
182		case 'r':
183			oncol = 1;
184			goto setwhich;
185
186		case 'i':
187			destcol++;
188			destline++;
189			which++;
190			continue;
191
192		case '%':
193			if (dp >= &result[MAXRETURNSIZE])
194				goto toohard;
195			*dp++ = c;
196			continue;
197
198#ifdef CM_B
199		case 'B':
200			which = (which/10 << 4) + which%10;
201			continue;
202#endif
203
204#ifdef CM_D
205		case 'D':
206			which = which - 2 * (which%16);
207			continue;
208#endif
209
210		default:
211			goto toohard;
212		}
213	}
214	if (strlcpy(dp, added, sizeof(result) - (dp - result))
215	    >= sizeof(result) - (dp - result))
216		goto toohard;
217	return (result);
218}
219