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