1 /* ibmpc/ms_ansi.c: a set of routines to provide either PCcurses or ANSI output
2 
3    Copyright (c) 1989-94 James E. Wilson, Don Kneller
4 
5    This software may be copied and distributed for educational, research, and
6    not for profit purposes provided that this copyright and statement are
7    included in all such copies. */
8 
9 #include <curses.h>
10 #include <stdio.h>
11 
12 #if defined(MSDOS) && defined(ANSI)
13 
14 #ifdef LINT_ARGS
15 static int curses_move(int, int);
16 static char *getent(char *,char * *,int );
17 static void initansistr(void);
18 static int ansi_initscr(void);
19 static int ansi_endwin(void);
20 static int ansi_addch(int );
21 static int ansi_mvaddstr(int ,int ,char *);
22 static int ansi_mvprintw(int ,int ,char *,int ,int ,int ,int );
23 static int ansi_move(int ,int );
24 static int ansi_move_tgoto(int ,int );
25 static int ansi_clrtobot(void);
26 static int ansi_clrtoeol(void);
27 static int ansi_mvaddch(int ,int ,char );
28 static int ansi_clear(void);
29 static int ansi_refresh(void);
30 static int ansi_noop(void);
31 int ansi_prep(int ,int, int);
32 #else
33 static int	ansi_addch(), ansi_mvaddstr(), ansi_mvprintw(), ansi_move(),
34 		ansi_move_tgoto(),
35 		ansi_clrtobot(), ansi_clrtoeol(), ansi_mvaddch(), ansi_endwin(),
36 		ansi_refresh(), ansi_clear(), ansi_noop(), ansi_initscr();
37 int ansi_prep();
38 #endif
39 
40 extern char *tgetstr();
41 extern char *getenv();
42 extern char *tgoto();
43 
44 /* Must supply a functional form of the PCcurses "move" routine */
45 static int
curses_move(y,x)46 curses_move(y, x)
47 int	y, x;
48 {
49 	return wmove(stdscr, y, x);
50 }
51 
52 /* Default is for curses to be used */
53 int	(*output_addch)() = addch;
54 int	(*output_mvaddstr)() = mvaddstr;
55 int	(*output_mvprintw)() = mvprintw;
56 int	(*output_move)() = curses_move;
57 int	(*output_endwin)() = endwin;
58 int	(*output_clrtobot)() = clrtobot;
59 int	(*output_clrtoeol)() = clrtoeol;
60 int	(*output_mvaddch)() = mvaddch;
61 int	(*output_initscr)() = initscr;
62 int	(*output_refresh)() = refresh;
63 int	(*output_clear)() = clear;
64 
65 int	(*output_nocrmode)() = nocrmode;
66 int	(*output_crmode)() = crmode;
67 int	(*output_nonl)() = nonl;
68 int	(*output_nl)() = nl;
69 int	(*output_noecho)() = noecho;
70 int	(*output_echo)() = echo;
71 int	ansi;
72 int	LI;
73 
74 #define LEFTFIELD	-10;
75 #define	NEED		1
76 
77 static int	moveopt = 1;
78 static char	*CE, *CL, *CM, *DO, *LE, *ND, *TE, *TI, *UP;
79 static int	currow = 0;
80 static int	curcol = LEFTFIELD;
81 
82 static char	*
getent(str,tbufp,need)83 getent(str, tbufp, need)
84 char	*str, **tbufp;
85 int	need;
86 {
87 	char	*value;
88 
89 	if ((value = tgetstr(str, tbufp)) == NULL && need == NEED)
90 		error("termcap:  Moria needs %s\n", str);
91 	return value;
92 }
93 
94 static void
initansistr()95 initansistr()
96 {
97 	static	char tbuf[512];
98 	char	temp[1024], *tbufp, *term;
99 
100 	if ((term = getenv("TERM")) == NULL)
101 		term = "ibmpc-mono";
102 	if (tgetent(temp, term) < 1)
103 		error("Unknown terminal type: %s.", term);
104 	tbufp = tbuf;
105 	LE = getent("le", &tbufp, NEED);
106 	CE = getent("ce", &tbufp, NEED);
107 	CL = getent("cl", &tbufp, NEED);
108 	CM = getent("cm", &tbufp, NEED);
109 	ND = getent("nd", &tbufp, NEED);
110 	TE = getent("te", &tbufp, !NEED);
111 	TI = getent("ti", &tbufp, !NEED);
112 	UP = getent("up", &tbufp, NEED);
113 	DO = getent("do", &tbufp, NEED);
114 	LI = tgetnum("li");
115 	if (LI <= 0)
116 		LI = 24;
117 }
118 
ansi_prep(check_ansi,domoveopt,truetgoto)119 ansi_prep(check_ansi, domoveopt, truetgoto)
120 int	check_ansi;
121 int	domoveopt;
122 int	truetgoto;
123 {
124 	moveopt = domoveopt;
125 
126 	/* Check for ANSI.SYS */
127 	if (check_ansi) {
128 		/* Clear the input queue */
129 		while (kbhit())
130 			(void) getch();
131 
132 		/* Send out the DSR string */
133 		fputs("\033[6n", stdout);
134 		fflush(stdout);
135 
136 		/* Is there anything in the input?  If so ANSI responded. */
137 		if (kbhit()) {
138 			while (kbhit())
139 				(void) getch();
140 		}
141 		else {
142 			putchar('\n');
143 			error("ANSI.SYS not installed!  See MORIA.DOC for details!\n");
144 		}
145 	}
146 
147 	/* get the ANSI strings */
148 	initansistr();
149 
150 	/* change function pointers to ANSI versions */
151 	output_addch = ansi_addch;
152 	output_mvaddstr = ansi_mvaddstr;
153 	output_mvprintw = ansi_mvprintw;
154 	if (truetgoto)
155 		output_move = ansi_move_tgoto;
156 	else
157 		output_move = ansi_move;
158 	output_clrtobot = ansi_clrtobot;
159 	output_clrtoeol = ansi_clrtoeol;
160 	output_mvaddch = ansi_mvaddch;
161 	output_refresh = ansi_refresh;
162 	output_clear = ansi_clear;
163 	output_initscr = ansi_initscr;
164 	output_endwin = ansi_endwin;
165 
166 	output_nocrmode =
167 	output_crmode =
168 	output_nonl =
169 	output_nl =
170 	output_noecho =
171 	output_echo = ansi_noop;
172 
173 	ansi = 1;
174 }
175 
176 static int
ansi_initscr()177 ansi_initscr()
178 {
179 	if (TI != NULL)
180 		fputs(TI, stdout);
181 	return OK;
182 }
183 
184 static int
ansi_endwin()185 ansi_endwin()
186 {
187 	if (TI != NULL)
188 		fputs(TE, stdout);
189 	return OK;
190 }
191 
192 static int
ansi_addch(ch)193 ansi_addch(ch)
194 int	ch;
195 {
196 	putc(ch, stdout);
197 	curcol++;
198 	return OK;
199 }
200 
201 static int
ansi_mvaddstr(row,col,str)202 ansi_mvaddstr(row, col, str)
203 int	row, col;
204 char	*str;
205 {
206 	(void) ansi_move(row, col);
207 	fputs(str, stdout);
208 	curcol = LEFTFIELD;
209 	return OK;
210 }
211 
212 static int
ansi_mvprintw(row,col,fmt,a1,a2,a3,a4)213 ansi_mvprintw(row, col, fmt, a1, a2, a3, a4)
214 int	row, col;
215 char	*fmt;
216 int	a1, a2, a3, a4;	/* large enough for %c%s%c of files.c ! */
217 {
218 	(void) ansi_move(row, col);
219 	fprintf(stdout, fmt, a1, a2, a3, a4);
220 	curcol = LEFTFIELD;
221 	return OK;
222 }
223 
224 #define abs(x)	((x) < 0 ? -(x) : (x))
225 
226 /* For a bit more speed, don't use tgoto() from termcap */
227 static int
ansi_move(row,col)228 ansi_move(row, col)
229 int	row, col;
230 {
231 	if (moveopt && abs(currow - row) < 3 && abs(curcol - col) < 3) {
232 		while (row > currow)
233 			fputs(DO, stdout), currow++;
234 		while (row < currow)
235 			fputs(UP, stdout), currow--;
236 		while (col > curcol)
237 			fputs(ND, stdout), curcol++;
238 		while (col < curcol)
239 			fputs(LE, stdout), curcol--;
240 	}
241 	else
242 		fprintf(stdout, "\033[%d;%dH\0__cursor motion__", row+1,col+1);
243 	currow = row;
244 	curcol = col;
245 	return OK;
246 }
247 
248 /* Use tgoto (which is rather slow) */
249 static int
ansi_move_tgoto(row,col)250 ansi_move_tgoto(row, col)
251 int	row, col;
252 {
253 	if (moveopt && abs(currow - row) < 3 && abs(curcol - col) < 3) {
254 		while (row > currow)
255 			fputs(DO, stdout), currow++;
256 		while (row < currow)
257 			fputs(UP, stdout), currow--;
258 		while (col > curcol)
259 			fputs(ND, stdout), curcol++;
260 		while (col < curcol)
261 			fputs(LE, stdout), curcol--;
262 	}
263 	else {
264 		fputs(tgoto(CM, col, row), stdout);
265 	}
266 	currow = row;
267 	curcol = col;
268 	return OK;
269 }
270 
271 static int
ansi_clrtobot()272 ansi_clrtobot()
273 {
274 	ansi_clrtoeol();
275 	ansi_move(++currow, 0);
276 	ansi_clrtoeol();
277 	for (; currow <= LI; currow++) {
278 		fputs(DO, stdout);
279 		ansi_clrtoeol();
280 	}
281 	curcol = LEFTFIELD;
282 	return OK;
283 }
284 
285 static int
ansi_clrtoeol()286 ansi_clrtoeol()
287 {
288 	fputs(CE, stdout);
289 	return OK;
290 }
291 
292 static int
ansi_mvaddch(row,col,ch)293 ansi_mvaddch(row, col, ch)
294 int	row, col;
295 char	ch;
296 {
297 	ansi_move(row, col);
298 	putchar(ch);
299 	curcol++;
300 	return OK;
301 }
302 
303 static int
ansi_clear()304 ansi_clear()
305 {
306 	fputs(CL, stdout);
307 	return OK;
308 }
309 
310 static int
ansi_refresh()311 ansi_refresh()
312 {
313 	fflush(stdout);
314 	return OK;
315 }
316 
317 static int
ansi_noop()318 ansi_noop()
319 {
320 	return OK;
321 }
322 #endif
323