1 /* @(#)tgoto.c 1.12 13/09/19 Copyright 1986-2013 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)tgoto.c 1.12 13/09/19 Copyright 1986-2013 J. Schilling";
6 #endif
7 /*
8 * Copyright (c) 1986-2013 J. Schilling
9 */
10 /*
11 * The contents of this file are subject to the terms of the
12 * Common Development and Distribution License, Version 1.0 only
13 * (the "License"). You may not use this file except in compliance
14 * with the License.
15 *
16 * See the file CDDL.Schily.txt in this distribution for details.
17 * A copy of the CDDL is also available via the Internet at
18 * http://www.opensource.org/licenses/cddl1.txt
19 *
20 * When distributing Covered Code, include this CDDL HEADER in each
21 * file and include the License file CDDL.Schily.txt from this distribution.
22 */
23
24 #include <schily/standard.h>
25 #include <schily/string.h>
26 #include <schily/termcap.h>
27
28 EXPORT char *tgoto __PR((char *CM, int col, int line));
29
30 /*
31 * Define exported variables.
32 */
33 #if defined(IS_MACOS_X)
34 /*
35 * The MAC OS X linker does not grok "common" varaibles.
36 * Make UP/BC a "data" variable.
37 */
38 EXPORT char *UP = 0; /* Cursor up 1 line */
39 EXPORT char *BC = 0; /* Back Cursor movement (Cursor left) */
40 #else
41 EXPORT char *UP; /* Cursor up 1 line */
42 EXPORT char *BC; /* Back Cursor movement (Cursor left) */
43 #endif
44
45 #define OBUF_SIZE 80
46
47 /*
48 * Perform string preparation/conversion for cursor addressing.
49 * The string cm contains a format string.
50 */
51 EXPORT char *
tgoto(cm,col,line)52 tgoto(cm, col, line)
53 char *cm;
54 int col;
55 int line;
56 {
57 static char outbuf[OBUF_SIZE]; /* Where the output goes to */
58 char xbuf[10]; /* for %. corrections */
59 register char *op = outbuf;
60 register char *p = cm;
61 register int c;
62 register int val = line;
63 int usecol = 0;
64
65 if (p == 0) {
66 badfmt:
67 /*
68 * Be compatible to 'vi' in case of bad format.
69 */
70 return ("OOPS");
71 }
72 xbuf[0] = 0;
73 while ((c = *p++) != '\0') {
74 if ((op + 5) >= &outbuf[OBUF_SIZE])
75 return ("OVERFLOW");
76
77 if (c != '%') {
78 *op++ = c;
79 continue;
80 }
81 switch (c = *p++) {
82
83 case '%': /* %% -> % */
84 /* This is from BSD */
85 *op++ = c;
86 continue;
87
88 case 'd': /* output as printf("%d"... */
89 /* This is from BSD (use val) */
90 if (val < 10)
91 goto onedigit;
92 if (val < 100)
93 goto twodigits;
94 /*FALLTHROUGH*/
95
96 case '3': /* output as printf("%03d"... */
97 /* This is from BSD (use val) */
98 if (val >= 1000) {
99 *op++ = '0' + (val / 1000);
100 val %= 1000;
101 }
102 *op++ = '0' + (val / 100);
103 val %= 100;
104 /*FALLTHROUGH*/
105
106 case '2': /* output as printf("%02d"... */
107 /* This is from BSD (use val) */
108 twodigits:
109 *op++ = '0' + val / 10;
110 onedigit:
111 *op++ = '0' + val % 10;
112 nextparam:
113 usecol ^= 1;
114 setval:
115 val = usecol ? col : line;
116 continue;
117
118 case 'C': /* For c-100: print quotient of */
119 /* value by 96, if nonzero, */
120 /* then do like %+. */
121 /* This is from GNU (use val) */
122 if (val >= 96) {
123 *op++ = val / 96;
124 val %= 96;
125 }
126 /*FALLTHROUGH*/
127
128 case '+': /* %+x like %c but add x before */
129 /* This is from BSD (use val) */
130 val += *p++;
131 /*FALLTHROUGH*/
132
133 case '.': /* output as printf("%c" but... */
134 /* This is from BSD (use val) */
135 if (usecol || UP) {
136 /*
137 * We assume that backspace works and we don't
138 * need to test for BC too.
139 *
140 * If you did not call stty tabs while termcap
141 * is used you will get other problems, so we
142 * exclude tab from the execptions.
143 */
144 while (val == 0 || val == '\004' ||
145 /* val == '\t' || */ val == '\n') {
146
147 strcat(xbuf,
148 usecol ? (BC?BC:"\b") : UP);
149 val++;
150 }
151 }
152 *op++ = val;
153 goto nextparam;
154
155 case '>': /* %>xy if val > x add y */
156 /* This is from BSD (chng state) */
157
158 if (val > *p++)
159 val += *p++;
160 else
161 p++;
162 continue;
163
164 case 'B': /* convert to BCD char coding */
165 /* This is from BSD (chng state) */
166
167 val += 6 * (val / 10);
168 continue;
169
170 case 'D': /* weird Delta Data conversion */
171 /* This is from BSD (chng state) */
172
173 val -= 2 * (val % 16);
174 continue;
175
176 case 'i': /* increment row/col by one */
177 /* This is from BSD (chng state) */
178 col++;
179 line++;
180 val++;
181 continue;
182
183 case 'm': /* xor both parameters by 0177 */
184 /* This is from GNU (chng state) */
185 col ^= 0177;
186 line ^= 0177;
187 goto setval;
188
189 case 'n': /* xor both parameters by 0140 */
190 /* This is from BSD (chng state) */
191 col ^= 0140;
192 line ^= 0140;
193 goto setval;
194
195 case 'r': /* reverse row/col */
196 /* This is from BSD (chng state) */
197 usecol = 1;
198 goto setval;
199
200 default:
201 goto badfmt;
202 }
203 }
204 /*
205 * append to output if there is space...
206 */
207 if ((op + strlen(xbuf)) >= &outbuf[OBUF_SIZE])
208 return ("OVERFLOW");
209 for (p = xbuf; *p; )
210 *op++ = *p++;
211 *op = '\0';
212 return (outbuf);
213 }
214