1 /* $OpenBSD: tgoto.c,v 1.3 2003/06/02 20:18:42 millert 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 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)tgoto.c 8.1 (Berkeley) 6/4/93";
36 #else
37 static char rcsid[] = "$OpenBSD: tgoto.c,v 1.3 2003/06/02 20:18:42 millert Exp $";
38 #endif
39 #endif /* not lint */
40
41 #include <string.h>
42 #include <curses.h>
43
44 #define CTRL(c) ((c) & 037)
45
46 #define MAXRETURNSIZE 64
47
48 char *UP;
49 char *BC;
50
51 /*
52 * Routine to perform cursor addressing.
53 * CM is a string containing printf type escapes to allow
54 * cursor addressing. We start out ready to print the destination
55 * line, and switch each time we print row or column.
56 * The following escapes are defined for substituting row/column:
57 *
58 * %d as in printf
59 * %2 like %2d
60 * %3 like %3d
61 * %. gives %c hacking special case characters
62 * %+x like %c but adding x first
63 *
64 * The codes below affect the state but don't use up a value.
65 *
66 * %>xy if value > x add y
67 * %r reverses row/column
68 * %i increments row/column (for one origin indexing)
69 * %% gives %
70 * %B BCD (2 decimal digits encoded in one byte)
71 * %D Delta Data (backwards bcd)
72 *
73 * all other characters are ``self-inserting''.
74 */
75 char *
tgoto(CM,destcol,destline)76 tgoto(CM, destcol, destline)
77 char *CM;
78 int destcol, destline;
79 {
80 static char result[MAXRETURNSIZE];
81 static char added[10];
82 char *cp = CM;
83 register char *dp = result;
84 register int c;
85 int oncol = 0;
86 register int which = destline;
87
88 if (cp == 0) {
89 toohard:
90 /*
91 * ``We don't do that under BOZO's big top''
92 */
93 return ("OOPS");
94 }
95 added[0] = 0;
96 while ((c = *cp++) != '\0') {
97 if (c != '%') {
98 if (dp >= &result[MAXRETURNSIZE])
99 goto toohard;
100 *dp++ = c;
101 continue;
102 }
103 switch (c = *cp++) {
104
105 #ifdef CM_N
106 case 'n':
107 destcol ^= 0140;
108 destline ^= 0140;
109 goto setwhich;
110 #endif
111
112 case 'd':
113 if (which < 10)
114 goto one;
115 if (which < 100)
116 goto two;
117 /* fall into... */
118
119 case '3':
120 if (dp >= &result[MAXRETURNSIZE])
121 goto toohard;
122 *dp++ = (which / 100) | '0';
123 which %= 100;
124 /* fall into... */
125
126 case '2':
127 two:
128 if (dp >= &result[MAXRETURNSIZE])
129 goto toohard;
130 *dp++ = which / 10 | '0';
131 one:
132 if (dp >= &result[MAXRETURNSIZE])
133 goto toohard;
134 *dp++ = which % 10 | '0';
135 swap:
136 oncol = 1 - oncol;
137 setwhich:
138 which = oncol ? destcol : destline;
139 continue;
140
141 #ifdef CM_GT
142 case '>':
143 if (which > *cp++)
144 which += *cp++;
145 else
146 cp++;
147 continue;
148 #endif
149
150 case '+':
151 which += *cp++;
152 /* fall into... */
153
154 case '.':
155 /*
156 * This code is worth scratching your head at for a
157 * while. The idea is that various weird things can
158 * happen to nulls, EOT's, tabs, and newlines by the
159 * tty driver, arpanet, and so on, so we don't send
160 * them if we can help it.
161 *
162 * Tab is taken out to get Ann Arbors to work, otherwise
163 * when they go to column 9 we increment which is wrong
164 * because bcd isn't continuous. We should take out
165 * the rest too, or run the thing through more than
166 * once until it doesn't make any of these, but that
167 * would make termlib (and hence pdp-11 ex) bigger,
168 * and also somewhat slower. This requires all
169 * programs which use termlib to stty tabs so they
170 * don't get expanded. They should do this anyway
171 * because some terminals use ^I for other things,
172 * like nondestructive space.
173 */
174 if ((which == 0 || which == CTRL('d') || which == '\n')
175 && (oncol || UP)) /* Assumption: backspace works */
176 /*
177 * Loop needed because newline happens
178 * to be the successor of tab.
179 */
180 do {
181 if (strlcat(added, oncol ?
182 (BC ? BC : "\b") : UP,
183 sizeof(added)) >= sizeof(added))
184 goto toohard;
185 which++;
186 } while (which == '\n');
187 if (dp >= &result[MAXRETURNSIZE])
188 goto toohard;
189 *dp++ = which;
190 goto swap;
191
192 case 'r':
193 oncol = 1;
194 goto setwhich;
195
196 case 'i':
197 destcol++;
198 destline++;
199 which++;
200 continue;
201
202 case '%':
203 if (dp >= &result[MAXRETURNSIZE])
204 goto toohard;
205 *dp++ = c;
206 continue;
207
208 #ifdef CM_B
209 case 'B':
210 which = (which/10 << 4) + which%10;
211 continue;
212 #endif
213
214 #ifdef CM_D
215 case 'D':
216 which = which - 2 * (which%16);
217 continue;
218 #endif
219
220 default:
221 goto toohard;
222 }
223 }
224 if (strlcpy(dp, added, sizeof(result) - (dp - result))
225 >= sizeof(result) - (dp - result))
226 goto toohard;
227 return (result);
228 }
229