xref: /original-bsd/lib/libterm/tgoto.c (revision 241757c4)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)tgoto.c	5.1 (Berkeley) 06/05/85";
9 #endif not lint
10 
11 #define	CTRL(c)	('c' & 037)
12 
13 #define MAXRETURNSIZE 64
14 
15 char	*UP;
16 char	*BC;
17 
18 /*
19  * Routine to perform cursor addressing.
20  * CM is a string containing printf type escapes to allow
21  * cursor addressing.  We start out ready to print the destination
22  * line, and switch each time we print row or column.
23  * The following escapes are defined for substituting row/column:
24  *
25  *	%d	as in printf
26  *	%2	like %2d
27  *	%3	like %3d
28  *	%.	gives %c hacking special case characters
29  *	%+x	like %c but adding x first
30  *
31  *	The codes below affect the state but don't use up a value.
32  *
33  *	%>xy	if value > x add y
34  *	%r	reverses row/column
35  *	%i	increments row/column (for one origin indexing)
36  *	%%	gives %
37  *	%B	BCD (2 decimal digits encoded in one byte)
38  *	%D	Delta Data (backwards bcd)
39  *
40  * all other characters are ``self-inserting''.
41  */
42 char *
43 tgoto(CM, destcol, destline)
44 	char *CM;
45 	int destcol, destline;
46 {
47 	static char result[MAXRETURNSIZE];
48 	static char added[10];
49 	char *cp = CM;
50 	register char *dp = result;
51 	register int c;
52 	int oncol = 0;
53 	register int which = destline;
54 
55 	if (cp == 0) {
56 toohard:
57 		/*
58 		 * ``We don't do that under BOZO's big top''
59 		 */
60 		return ("OOPS");
61 	}
62 	added[0] = 0;
63 	while (c = *cp++) {
64 		if (c != '%') {
65 			*dp++ = c;
66 			continue;
67 		}
68 		switch (c = *cp++) {
69 
70 #ifdef CM_N
71 		case 'n':
72 			destcol ^= 0140;
73 			destline ^= 0140;
74 			goto setwhich;
75 #endif
76 
77 		case 'd':
78 			if (which < 10)
79 				goto one;
80 			if (which < 100)
81 				goto two;
82 			/* fall into... */
83 
84 		case '3':
85 			*dp++ = (which / 100) | '0';
86 			which %= 100;
87 			/* fall into... */
88 
89 		case '2':
90 two:
91 			*dp++ = which / 10 | '0';
92 one:
93 			*dp++ = which % 10 | '0';
94 swap:
95 			oncol = 1 - oncol;
96 setwhich:
97 			which = oncol ? destcol : destline;
98 			continue;
99 
100 #ifdef CM_GT
101 		case '>':
102 			if (which > *cp++)
103 				which += *cp++;
104 			else
105 				cp++;
106 			continue;
107 #endif
108 
109 		case '+':
110 			which += *cp++;
111 			/* fall into... */
112 
113 		case '.':
114 casedot:
115 			/*
116 			 * This code is worth scratching your head at for a
117 			 * while.  The idea is that various weird things can
118 			 * happen to nulls, EOT's, tabs, and newlines by the
119 			 * tty driver, arpanet, and so on, so we don't send
120 			 * them if we can help it.
121 			 *
122 			 * Tab is taken out to get Ann Arbors to work, otherwise
123 			 * when they go to column 9 we increment which is wrong
124 			 * because bcd isn't continuous.  We should take out
125 			 * the rest too, or run the thing through more than
126 			 * once until it doesn't make any of these, but that
127 			 * would make termlib (and hence pdp-11 ex) bigger,
128 			 * and also somewhat slower.  This requires all
129 			 * programs which use termlib to stty tabs so they
130 			 * don't get expanded.  They should do this anyway
131 			 * because some terminals use ^I for other things,
132 			 * like nondestructive space.
133 			 */
134 			if (which == 0 || which == CTRL(d) || /* which == '\t' || */ which == '\n') {
135 				if (oncol || UP) /* Assumption: backspace works */
136 					/*
137 					 * Loop needed because newline happens
138 					 * to be the successor of tab.
139 					 */
140 					do {
141 						strcat(added, oncol ? (BC ? BC : "\b") : UP);
142 						which++;
143 					} while (which == '\n');
144 			}
145 			*dp++ = which;
146 			goto swap;
147 
148 		case 'r':
149 			oncol = 1;
150 			goto setwhich;
151 
152 		case 'i':
153 			destcol++;
154 			destline++;
155 			which++;
156 			continue;
157 
158 		case '%':
159 			*dp++ = c;
160 			continue;
161 
162 #ifdef CM_B
163 		case 'B':
164 			which = (which/10 << 4) + which%10;
165 			continue;
166 #endif
167 
168 #ifdef CM_D
169 		case 'D':
170 			which = which - 2 * (which%16);
171 			continue;
172 #endif
173 
174 		default:
175 			goto toohard;
176 		}
177 	}
178 	strcpy(dp, added);
179 	return (result);
180 }
181