Fix mdoc(7)/man(7) mix up.
[netbsd-mini2440.git] / lib / libterm / tgoto.c
blob6e92371c4a1a4283573ebd436a3759d3e6ab238f
1 /* $NetBSD: tgoto.c,v 1.24 2006/08/27 08:28:38 christos Exp $ */
3 /*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)tgoto.c 8.1 (Berkeley) 6/4/93";
36 #else
37 __RCSID("$NetBSD: tgoto.c,v 1.24 2006/08/27 08:28:38 christos Exp $");
38 #endif
39 #endif /* not lint */
41 #include <assert.h>
42 #include <errno.h>
43 #include <termcap.h>
44 #include <termcap_private.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
49 #define CTRL(c) ((c) & 037)
51 #define MAXRETURNSIZE 128
53 char *UP;
54 char *BC;
57 * Routine to perform cursor addressing.
58 * CM is a string containing printf type escapes to allow
59 * cursor addressing. We start out ready to print the destination
60 * line, and switch each time we print row or column.
61 * The following escapes are defined for substituting row/column:
63 * %d as in printf
64 * %2 like %2d
65 * %3 like %3d
66 * %. gives %c hacking special case characters
67 * %+x like %c but adding x first
69 * The codes below affect the state but don't use up a value.
71 * %>xy if value > x add y
72 * %r reverses row/column
73 * %i increments row/column (for one origin indexing)
74 * %% gives %
75 * %B BCD (2 decimal digits encoded in one byte)
76 * %D Delta Data (backwards bcd)
78 * all other characters are ``self-inserting''.
80 char *
81 tgoto(const char *CM, int destcol, int destline)
83 static char result[MAXRETURNSIZE];
85 (void)t_goto(NULL, CM, destcol, destline, result, sizeof(result));
86 return result;
90 * New interface. Functionally the same as tgoto but uses the tinfo struct
91 * to set UP and BC. The arg buffer is filled with the result string, limit
92 * defines the maximum number of chars allowed in buffer. The function
93 * returns 0 on success, -1 otherwise, the result string contains an error
94 * string on failure.
96 int
97 t_goto(struct tinfo *info, const char *CM, int destcol, int destline,
98 char *buffer, size_t limit)
100 char added[32];
101 const char *cp = CM;
102 char *dp = buffer;
103 int c;
104 int oncol = 0;
105 int which = destline;
106 char *buf_lim = buffer + limit;
107 char dig_buf[64];
108 char *ap = added;
109 char *eap = &added[sizeof(added) / sizeof(added[0])];
110 int k;
112 /* CM is checked below */
113 _DIAGASSERT(buffer != NULL);
115 if (info != NULL) {
116 if (!UP)
117 UP = info->up;
118 if (!BC)
119 BC = info->bc;
122 if (cp == 0) {
123 (void)strlcpy(buffer, "no fmt", limit);
124 errno = EINVAL;
125 return -1;
127 added[0] = '\0';
128 while ((c = *cp++) != '\0') {
129 if (c != '%' || ((c = *cp++) == '%')) {
130 *dp++ = c;
131 if (dp >= buf_lim) {
132 (void)strlcpy(buffer, "no space copying %",
133 limit);
134 errno = E2BIG;
135 return -1;
137 continue;
139 switch (c) {
141 #ifdef CM_N
142 case 'n':
143 destcol ^= 0140;
144 destline ^= 0140;
145 /* flip oncol here so it doesn't actually change */
146 oncol = 1 - oncol;
147 break;
148 #endif
150 case '3':
151 case '2':
152 case 'd':
153 /* Generate digits into temp buffer in reverse order */
154 k = 0;
156 dig_buf[k++] = which % 10 | '0';
157 while ((which /= 10) != 0);
159 if (c != 'd') {
160 c -= '0';
161 if (k > c) {
162 (void)snprintf(buffer, limit,
163 "digit buf overflow %d %d",
164 k, c);
165 errno = EINVAL;
166 return -1;
168 while (k < c)
169 dig_buf[k++] = '0';
172 if (dp + k >= buf_lim) {
173 (void)strlcpy(buffer, "digit buf copy", limit);
174 errno = E2BIG;
175 return -1;
177 /* then unwind into callers buffer */
179 *dp++ = dig_buf[--k];
180 while (k);
181 break;
183 #ifdef CM_GT
184 case '>':
185 if (which > *cp++)
186 which += *cp++;
187 else
188 cp++;
189 continue;
190 #endif
192 case '+':
193 which += *cp++;
194 /* FALLTHROUGH */
196 case '.':
198 * This code is worth scratching your head at for a
199 * while. The idea is that various weird things can
200 * happen to nulls, EOT's, tabs, and newlines by the
201 * tty driver, arpanet, and so on, so we don't send
202 * them if we can help it.
204 * Tab is taken out to get Ann Arbors to work, otherwise
205 * when they go to column 9 we increment which is wrong
206 * because bcd isn't continuous. We should take out
207 * the rest too, or run the thing through more than
208 * once until it doesn't make any of these, but that
209 * would make termlib (and hence pdp-11 ex) bigger,
210 * and also somewhat slower. This requires all
211 * programs which use termlib to stty tabs so they
212 * don't get expanded. They should do this anyway
213 * because some terminals use ^I for other things,
214 * like nondestructive space.
216 if (which == 0 || which == CTRL('d') ||
217 /* which == '\t' || */ which == '\n') {
218 if (oncol || UP) { /* Assumption: backspace works */
219 char *add = oncol ? (BC ? BC : "\b") : UP;
222 * Loop needed because newline happens
223 * to be the successor of tab.
225 do {
226 char *as = add;
228 while ((*ap++ = *as++) != '\0')
229 if (ap >= eap) {
230 (void)strlcpy(
231 buffer,
232 "add ovfl",
233 limit);
234 errno = E2BIG;
235 return -1;
237 which++;
238 } while (which == '\n');
241 *dp++ = which;
242 if (dp >= buf_lim) {
243 (void)strlcpy(buffer, "dot copy", limit);
244 errno = E2BIG;
245 return -1;
247 break;
249 case 'r':
250 oncol = 0;
251 break;
253 case 'i':
254 destcol++;
255 destline++;
256 which++;
257 continue;
259 #ifdef CM_B
260 case 'B':
261 which = (which / 10 << 4) + which % 10;
262 continue;
263 #endif
265 #ifdef CM_D
266 case 'D':
267 which = which - 2 * (which % 16);
268 continue;
269 #endif
271 default:
272 (void)snprintf(buffer, limit, "bad format `%c'", c);
273 errno = EINVAL;
274 return -1;
277 /* flip to other number... */
278 oncol = 1 - oncol;
279 which = oncol ? destcol : destline;
281 if (dp + (ap - added) >= buf_lim) {
282 (void)strlcpy(buffer, "big added", limit);
283 errno = E2BIG;
284 return -1;
287 *ap = '\0';
288 for (ap = added; (*dp++ = *ap++) != '\0';)
289 continue;
291 return 0;