1 /*	UNIX:	Unix specific terminal driver
2 		for MicroEMACS 4.0
3 	(C)Copyright 1995 D. Lawrence, C. Smith
4 */
5 
6 /**
7 	New features: (as of version 3.10)
8 
9 	1. Timeouts waiting on a function key have been changed from
10 	35000 to 500000 microseconds.
11 
12 	2. Additional keymapping entries can be made from the command
13 	language by issuing a 'set $palette xxx'.  The format of
14 	xxx is a string as follows:
15 		"KEYMAP keybinding escape-sequence".
16 	To add "<ESC><[><A>" as a keybinding of FNN, issue:
17 		"KEYMAP FNN ~e[A".
18 	Note that the "~e" sequence represents the escape character in
19 	the MicroEMACS command language.
20 
21 	3. Colors are supported.  Under AIX the colors will be pulled
22 	in automaticly.  For other environments, you can either add
23 	the termcap entries, C0 to D7.  Or the colors may be defined
24 	using the command language by issuing a 'set $palette xxx'
25 	command.  The format of xxx is a string as follows:
26 		"CLRMAP # escape-sequence".
27 	The number is a number from 0 to 15, where 0 to 7 is the
28 	foreground colors, and 8 to 15 as background colors.
29 	To add foreground color 0 for ansi terminals, issue:
30 		"CLRMAP 0 ~e[30m".
31 
32 	'Porting notes:
33 
34 	I have tried to create this file so that it should work
35 	as well as possible without changes on your part.
36 
37 	However, if something does go wrong, read the following
38 	helpful hints:
39 
40 	1. On SUN-OS4, there is a problem trying to include both
41 	the termio.h and ioctl.h files.  I wish Sun would get their
42 	act together.  Even though you get lots of redefined messages,
43 	it shouldn't cause any problems with the final object.
44 
45 	2. In the type-ahead detection code, the individual UNIX
46 	system either has a FIONREAD or a FIORDCHK ioctl call.
47 	Hopefully, your system uses one of them and this be detected
48 	correctly without any intervention.
49 
50 	3. Also lookout for directory handling.  The SCO Xenix system
51 	is the weirdest I've seen, requiring a special load file
52 	(see below).  Some machine call the result of a readdir() call
53 	a "struct direct" or "struct dirent".  Includes files are
54 	named differently depending of the O/S.  If your system doesn't
55 	have an opendir()/closedir()/readdir() library call, then
56 	you should use the public domain utility "ndir".
57 
58 	To compile:
59 		Compile all files normally.
60 	To link:
61 		Select one of the following operating systems:
62 			SCO Xenix:
63 				use "-ltermcap" and "-lx";
64 			SUN 3 and 4:
65 				use "-ltermcap";
66 			IBM-RT, IBM-AIX, ATT UNIX, Altos UNIX, Interactive:
67 				use "-lcurses".
68 
69 	- 20 feb 95	New version 4.00 features
70 	  We added new code to implient a TERMIOS driver
71 **/
72 
73 /** Include files **/
74 #include <stdio.h>			/* Standard I/O definitions	*/
75 #include "estruct.h"			/* Emacs definitions		*/
76 
77 /** Do nothing routine **/
scnothing()78 int scnothing()
79 {
80 	return(0);
81 }
82 
83 /** Only compile for UNIX machines **/
84 #if BSD || FREEBSD || USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || SUN || XENIX || (AVVION || TERMIOS)
85 
86 /** Include files **/
87 #include "eproto.h"			/* Function definitions		*/
88 #include "edef.h"			/* Global variable definitions	*/
89 #include "elang.h"			/* Language definitions		*/
90 
91 /** Kill predefined **/
92 #undef CTRL				/* Problems with CTRL		*/
93 
94 
95 /** Overall include files **/
96 #include <sys/types.h>			/* System type definitions	*/
97 #include <sys/stat.h>			/* File status definitions	*/
98 #include <sys/ioctl.h>			/* I/O control definitions	*/
99 
100 /** Additional include files **/
101 #if	FREEBSD
102 #define TERMIOS 1
103 #include <sys/time.h>
104 #undef	BSD
105 #include <sys/param.h>
106 #undef BSD
107 #define	BSD	0
108 #endif
109 #if (BSD && !TERMIOS)
110 #include <sys/time.h>			/* Timer definitions		*/
111 #endif /* (BSD && !TERMIOS) */
112 #if BSD || FREEBSD || SUN || HPUX8 || HPUX9 || (AVVION || TERMIOS) || AIX
113 #include <signal.h>			/* Signal definitions		*/
114 #endif /* BSD || FREEBSD || SUN || HPUX8 || HPUX9 || (AVVION || TERMIOS) */
115 #if USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || SUN || XENIX
116 #include <termio.h>			/* Terminal I/O definitions	*/
117 #endif /* USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || SUN || XENIX */
118 #if (AVVION || TERMIOS)
119 #include <termios.h>			/* Terminal I/O definitions	*/
120 #include <unistd.h>
121 #endif /* (AVVION || TERMIOS) */
122 #if CURSES
123 #include <curses.h>			/* Curses screen output		*/
124 #undef WINDOW				/* Oh no!			*/
125 #endif /* CURSES */
126 
127 /** Completion include files **/
128 /** Directory accessing: Try and figure this out... if you can! **/
129 #if ((BSD || FREEBSD) && !TERMIOS)
130 #include <sys/dir.h>			/* Directory entry definitions	*/
131 #define DIRENTRY	direct
132 #endif /* (BSD && !TERMIOS) */
133 #if XENIX || VAT
134 #include <sys/ndir.h>			/* Directory entry definitions	*/
135 #define DIRENTRY	direct
136 #endif /* XENIX */
137 #if ((USG || AIX || AUX) && !VAT) || SMOS || HPUX8 || HPUX9 || SUN || (AVVION || TERMIOS)
138 #include <dirent.h>			/* Directory entry definitions	*/
139 #define DIRENTRY	dirent
140 #endif /* ((USG || AIX || AUX) && !VAT) || SMOS || HPUX8 || HPUX9 || SUN || (AVVION || TERMIOS) */
141 
142 /** Restore predefined definitions **/
143 #undef CTRL				/* Restore CTRL			*/
144 #define CTRL 0x0100
145 
146 /** Parameters **/
147 #define NINCHAR		64		/* Input buffer size		*/
148 #define NOUTCHAR	256		/* Output buffer size		*/
149 #if TERMCAP || TERMIOS
150 #define NCAPBUF		1024		/* Termcap storage size		*/
151 #endif /* TERMCAP */
152 #define MARGIN		8		/* Margin size			*/
153 #define SCRSIZ		64		/* Scroll for margin		*/
154 #define NPAUSE		10		/* # times thru update to pause */
155 
156 /** CONSTANTS **/
157 #define TIMEOUT		255		/* No character available	*/
158 
159 #if TERMCAP || TERMIOS
160 struct capbind {			/* Capability binding entry	*/
161 	char * name;			/* Termcap name			*/
162 	char * store;			/* Storage variable		*/
163 };
164 struct keybind {			/* Keybinding entry		*/
165 	char * name;			/* Termcap name			*/
166 	int value;			/* Binding value		*/
167 };
168 char *reset = (char*) NULL;		/* reset string kjc */
169 #endif /* TERMCAP */
170 
171 /** Local variables **/
172 #if (BSD && !TERMIOS)
173 static struct sgttyb cursgtty;		/* Current modes		*/
174 static struct sgttyb oldsgtty;		/* Original modes		*/
175 static struct tchars oldtchars;		/* Current tchars		*/
176 static struct ltchars oldlchars;	/* Current ltchars		*/
177 static char blank[6] =			/* Blank out character set	*/
178 	{ -1, -1, -1, -1, -1, -1 };
179 #endif /* (BSD && !TERMIOS) */
180 #if USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX
181 static struct termio curterm;		/* Current modes		*/
182 static struct termio oldterm;		/* Original modes		*/
183 #endif /* USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX */
184 #if (AVVION || TERMIOS)
185 static struct termios curterm;		/* Current modes		*/
186 static struct termios oldterm;		/* Original modes		*/
187 #endif /* (AVVION || TERMIOS) */
188 #if TERMCAP || TERMIOS
189 static char tcapbuf[NCAPBUF];		/* Termcap character storage	*/
190 #define CAP_CL		0		/* Clear to end of page		*/
191 #define CAP_CM		1		/* Cursor motion		*/
192 #define CAP_CE		2		/* Clear to end of line		*/
193 #define CAP_SE		3		/* Standout ends		*/
194 #define CAP_SO		4		/* Standout (reverse video)	*/
195 #define CAP_IS		5		/* Initialize screen		*/
196 #define CAP_KS		6		/* Keypad mode starts		*/
197 #define CAP_KE		7		/* Keypad mode ends		*/
198 #define CAP_VB		8		/* Visible bell			*/
199 #if COLOR
200 #define CAP_C0		9		/* Foreground color #0		*/
201 #define CAP_C1		10		/* Foreground color #1		*/
202 #define CAP_C2		11		/* Foreground color #2		*/
203 #define CAP_C3		12		/* Foreground color #3		*/
204 #define CAP_C4		13		/* Foreground color #4		*/
205 #define CAP_C5		14		/* Foreground color #5		*/
206 #define CAP_C6		15		/* Foreground color #6		*/
207 #define CAP_C7		16		/* Foreground color #7		*/
208 #define CAP_D0		17		/* Background color #0		*/
209 #define CAP_D1		18		/* Background color #1		*/
210 #define CAP_D2		19		/* Background color #2		*/
211 #define CAP_D3		20		/* Background color #3		*/
212 #define CAP_D4		21		/* Background color #4		*/
213 #define CAP_D5		22		/* Background color #5		*/
214 #define CAP_D6		23		/* Background color #6		*/
215 #define CAP_D7		24		/* Background color #7		*/
216 #if USG || AIX || AUX
217 #define CAP_SF		25		/* Set foreground color		*/
218 #define CAP_SB		26		/* Set background color		*/
219 #endif /* USG || AIX || AUX */
220 #endif /* COLOR */
221 static struct capbind capbind[] = {	/* Capability binding list	*/
222 	{ "cl" },			/* Clear to end of page		*/
223 	{ "cm" },			/* Cursor motion		*/
224 	{ "ce" },			/* Clear to end of line		*/
225 	{ "se" },			/* Standout ends		*/
226 	{ "so" },			/* Standout (reverse video)	*/
227 	{ "is" },			/* Initialize screen		*/
228 	{ "ks" },			/* Keypad mode starts		*/
229 	{ "ke" },			/* Keypad mode ends		*/
230 	{ "vb" },			/* Visible bell			*/
231 #if COLOR
232 	{ "c0" },			/* Foreground color #0		*/
233 	{ "c1" },			/* Foreground color #1		*/
234 	{ "c2" },			/* Foreground color #2		*/
235 	{ "c3" },			/* Foreground color #3		*/
236 	{ "c4" },			/* Foreground color #4		*/
237 	{ "c5" },			/* Foreground color #5		*/
238 	{ "c6" },			/* Foreground color #6		*/
239 	{ "c7" },			/* Foreground color #7		*/
240 	{ "d0" },			/* Background color #0		*/
241 	{ "d1" },			/* Background color #1		*/
242 	{ "d2" },			/* Background color #2		*/
243 	{ "d3" },			/* Background color #3		*/
244 	{ "d4" },			/* Background color #4		*/
245 	{ "d5" },			/* Background color #5		*/
246 	{ "d6" },			/* Background color #6		*/
247 	{ "d7" },			/* Background color #7		*/
248 #if USG || AIX || AUX
249 	{ "Sf" },			/* Set foreground color		*/
250 	{ "Sb" },			/* Set background color		*/
251 #endif /* USG || AIX || AUX */
252 #endif /* COLOR */
253 };
254 #if COLOR
255 static int cfcolor = -1;		/* Current forground color	*/
256 static int cbcolor = -1;		/* Current background color	*/
257 #endif /* COLOR */
258 static struct keybind keybind[] = {	/* Keybinding list		*/
259 	{ "bt", SHFT|CTRL|'i' },	/* Back-tab key			*/
260 	{ "k1", SPEC|'1' },		/* F1 key			*/
261 	{ "k2", SPEC|'2' },		/* F2 key			*/
262 	{ "k3", SPEC|'3' },		/* F3 key			*/
263 	{ "k4", SPEC|'4' },		/* F4 key			*/
264 	{ "k5", SPEC|'5' },		/* F5 key			*/
265 	{ "k6", SPEC|'6' },		/* F6 key			*/
266 	{ "k7", SPEC|'7' },		/* F7 key			*/
267 	{ "k8", SPEC|'8' },		/* F8 key			*/
268 	{ "k9", SPEC|'9' },		/* F9 key			*/
269 	{ "k0", SPEC|'0' },		/* F0 or F10 key		*/
270  	{ "k;", SPEC|'0' },		/* F0 or F10 key	(kjc)	*/
271 	{ "F1", SHFT|SPEC|'1' },	/* Shift-F1 or F11 key		*/
272 	{ "F2", SHFT|SPEC|'2' },	/* Shift-F2 or F12 key		*/
273 	{ "F3", SHFT|SPEC|'3' },	/* Shift-F3 or F13 key		*/
274 	{ "F4", SHFT|SPEC|'4' },	/* Shift-F4 or F14 key		*/
275 	{ "F5", SHFT|SPEC|'5' },	/* Shift-F5 or F15 key		*/
276 	{ "F6", SHFT|SPEC|'6' },	/* Shift-F6 or F16 key		*/
277 	{ "F7", SHFT|SPEC|'7' },	/* Shift-F7 or F17 key		*/
278 	{ "F8", SHFT|SPEC|'8' },	/* Shift-F8 or F18 key		*/
279 	{ "F9", SHFT|SPEC|'9' },	/* Shift-F9 or F19 key		*/
280 	{ "FA", SHFT|SPEC|'0' },	/* Shift-F0 or F20 key		*/
281 	{ "kA", CTRL|'O' },		/* Insert line key		*/
282 	{ "kb", CTRL|'H' },		/* Backspace key		*/
283 	{ "kC", CTRL|'L' },		/* Clear screen key		*/
284 	{ "kD", SPEC|'D' },		/* Delete character key		*/
285 	{ "kd", SPEC|'N' },		/* Down arrow key		*/
286 	{ "kE", CTRL|'K' },		/* Clear to end of line key	*/
287 	{ "kF", CTRL|'V' },		/* Scroll forward key		*/
288 	{ "kH", SPEC|'>' },		/* Home down key		*/
289  	{ "@7", SPEC|'>' },		/* Home down key	(kjc)	*/
290 	{ "kh", SPEC|'<' },		/* Home key			*/
291 	{ "kI", SPEC|'C' },		/* Insert character key		*/
292 	{ "kL", CTRL|'K' },		/* Delete line key		*/
293 	{ "kl", SPEC|'B' },		/* Left arrow key		*/
294 	{ "kN", SPEC|'V' },		/* Next page key		*/
295 	{ "kP", SPEC|'Z' },		/* Previous page key		*/
296 	{ "kR", CTRL|'Z' },		/* Scroll backward key		*/
297 	{ "kr", SPEC|'F' },		/* Right arrow key		*/
298 	{ "ku", SPEC|'P' },		/* Up arrow key			*/
299         { "K1", SPEC|'<' },		/* Keypad 7 -> Home		*/
300         { "K2", SPEC|'V' },		/* Keypad 9 -> Page Up		*/
301         { "K3", ' ' },			/* Keypad 5 			*/
302         { "K4", SPEC|'>' },		/* Keypad 1 -> End		*/
303         { "K5", CTRL|'V' },		/* Keypad 3 -> Page Down	*/
304  	{ "kw", CTRL|'E' }		/* End of line			*/
305 };
306 #endif /* TERMCAP */
307 static int inbuf[NINCHAR];		/* Input buffer			*/
308 static int * inbufh =			/* Head of input buffer		*/
309 	inbuf;
310 static int * inbuft =			/* Tail of input buffer		*/
311 	inbuf;
312 #if TERMCAP
313 static unsigned char outbuf[NOUTCHAR];	/* Output buffer		*/
314 static unsigned char * outbuft = 	/* Output buffer tail		*/
315 	outbuf;
316 #endif /* TERMCAP */
317 
318 static DIR *dirptr = NULL;		/* Current directory stream	*/
319 static char path[NFILEN];		/* Path of file to find		*/
320 static char rbuf[NFILEN];		/* Return file buffer		*/
321 static char *nameptr;			/* Ptr past end of path in rbuf	*/
322 
323 /** Terminal definition block **/
324 int scopen(), scclose(), ttgetc(), ttputc(), ttflush();
325 int scmove(), sceeol(), sceeop(), scbeep(), screv();
326 int sckopen(), sckclose();
327 #if COLOR
328 int scfcol(), scbcol();
329 #endif /* COLOR */
330 
331 #if	TERMCAP && FLABEL
332 static void dis_sfk(), dis_ufk();
333 #endif
334 
335 TERM term = {
336 	120,				/* Maximum number of rows	*/
337 	0,				/* Current number of rows	*/
338 	132,				/* Maximum number of columns	*/
339 	0,				/* Current number of columns	*/
340 	0, 0,				/* upper left corner default screen */
341 	MARGIN,				/* Margin for extending lines	*/
342 	SCRSIZ,				/* Scroll size for extending	*/
343 	NPAUSE,				/* # times thru update to pause	*/
344 	scopen,				/* Open terminal routine	*/
345 	scclose,			/* Close terminal routine	*/
346 	sckopen,			/* Open keyboard routine	*/
347 	sckclose,			/* Close keyboard routine	*/
348 	ttgetc,				/* Get character routine	*/
349 	ttputc,				/* Put character routine	*/
350 	ttflush,			/* Flush output routine		*/
351 	scmove,				/* Move cursor routine		*/
352 	sceeol,				/* Erase to end of line routine	*/
353 	sceeop,				/* Erase to end of page routine	*/
354 	sceeop,				/* Clear the desktop		*/
355 	scbeep,				/* Beep! routine		*/
356 	screv,				/* Set reverse video routine	*/
357 	scnothing,			/* Set resolution routine	*/
358 #if COLOR
359 	scfcol,				/* Set forground color routine	*/
360 	scbcol,				/* Set background color routine	*/
361 #endif /* COLOR */
362 #if	INSDEL
363 	scinsline,			 /* insert a screen line 	*/
364 	scdelline,			 /* delete a screen line 	*/
365 #endif	/* INSDEL */
366 };
367 
368 int hpterm;				/* global flag braindead HP-terminal */
369 
370 /** Open terminal device **/
ttopen()371 int ttopen()
372 {
373 	strcpy(os, "UNIX");
374 #if (BSD && !TERMIOS)
375 	/* Get tty modes */
376 	if (ioctl(0, TIOCGETP, &oldsgtty) ||
377 		ioctl(0, TIOCGETC, &oldtchars) ||
378 		ioctl(0, TIOCGLTC, &oldlchars))
379 		return(-1);
380 
381 	/* Save to original mode variables */
382 	cursgtty = oldsgtty;
383 
384 	/* Set new modes */
385 	cursgtty.sg_flags |= CBREAK;
386 	cursgtty.sg_flags &= ~(ECHO|CRMOD);
387 
388 	/* Set tty modes */
389 	if (ioctl(0, TIOCSETP, &cursgtty) ||
390 		ioctl(0, TIOCSETC, blank) ||
391 		ioctl(0, TIOCSLTC, blank))
392 		return(-1);
393 #endif /* (BSD && !TERMIOS) */
394 #if USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX
395 
396 #if SMOS
397 	/* Extended settings; 890619mhs A3 */
398 	set_parm(0,-1,-1);
399 #endif /* SMOS */
400 
401 	/* Get modes */
402 	if (ioctl(0, TCGETA, &oldterm)) {
403 		perror("Cannot TCGETA");
404 		return(-1);
405 	}
406 
407 	/* Save to original mode variable */
408 	curterm = oldterm;
409 
410 	/* Set new modes */
411 	/* I do not believe the flow control settings of the OS should
412 	   be diddled by an application program. But if you do, change this
413 	   1 to a 0, but be warned, all sorts of terminals will get grief
414 	   with this */
415 #if	1
416 	curterm.c_iflag &= ~(INLCR|ICRNL|IGNCR);
417 #else
418 	curterm.c_iflag &= ~(INLCR|ICRNL|IGNCR|IXON|IXANY|IXOFF);
419 #endif
420 
421 	curterm.c_lflag &= ~(ICANON|ISIG|ECHO|IEXTEN);
422 	curterm.c_cc[VMIN] = 1;
423 	curterm.c_cc[VTIME] = 0;
424 
425 #if SMOS
426 	/****THIS IS A BIG GUESS ON MY PART... the code changed
427 	  too much between versions for me to be sure this will work - DML */
428 
429 	/* Allow multiple (dual) sessions if already enabled */
430 	curterm.c_lflag = oldterm.c_lflag & ISIG;
431 
432 	/* Use old SWTCH char if necessary */
433 	if (curterm.c_lflag != 0)
434 		curterm.c_cc[VSWTCH] = oldterm.c_cc[VSWTCH];
435 
436 	/* Copy VTI settings	*/
437 	curterm.c_cc[VTBIT] = oldterm.c_cc[VTBIT];
438 
439 	/* Extended settings; 890619mhs A3 */
440 	set_parm(0,-1,-1);
441 #endif /* SMOS */
442 
443 	/* Set tty mode */
444 	if (ioctl(0, TCSETA, &curterm)) {
445 		perror("Cannot TCSETA");
446 		return(-1);
447 	}
448 #endif /* USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX */
449 #if (AVVION || TERMIOS)
450 	/* Get modes */
451 	if (tcgetattr(0, &oldterm)) {
452 		perror("Cannot tcgetattr");
453 		return(-1);
454 	}
455 
456 	/* Save to original mode variable */
457 	curterm = oldterm;
458 
459 	/* Set new modes */
460         /* disable XON/XOFF. We want to use ^S/^Q */
461 	curterm.c_iflag &= ~(INLCR|ICRNL|IGNCR|IXON|IXANY|IXOFF);
462 	curterm.c_lflag &= ~(ICANON|ISIG|ECHO|IEXTEN);
463 	curterm.c_cc[VMIN] = 1;
464 	curterm.c_cc[VTIME] = 0;
465 #ifdef	VLNEXT
466 	curterm.c_cc[VLNEXT] = -1;
467 #endif
468 
469 #if	AVVION
470 	/* Set line discipline for Data General */
471 	curterm.c_line = 0;
472 #endif
473 
474 	/* Set tty mode */
475 	if (tcsetattr(0, TCSANOW, &curterm)) {
476 		perror("Cannot tcsetattr");
477 		return(-1);
478 	}
479 #endif /* (AVVION || TERMIOS) */
480 
481 	/* Success */
482 	return(0);
483 }
484 
485 /** Close terminal device **/
ttclose()486 int ttclose()
487 {
488 #if ((AIX == 0) && (TERMIOS == 0)) || (FREEBSD == 1)
489 	/* Restore original terminal modes */
490 	if (reset != (char*)NULL)
491 		write(1, reset, strlen(reset));
492 #endif
493 
494 #if (BSD && !TERMIOS)
495 	if (ioctl(0, TIOCSETP, &oldsgtty) ||
496 		ioctl(0, TIOCSETC, &oldtchars) ||
497 		ioctl(0, TIOCSLTC, &oldlchars))
498 		return(-1);
499 #endif /* (BSD && !TERMIOS) */
500 
501 #if USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX
502 #if SMOS
503 	/* Extended settings; 890619mhs A3 */
504 	set_parm(0,-1,-1);
505 #endif /* SMOS */
506 	if (ioctl(0, TCSETA, &oldterm))
507 		return(-1);
508 #endif /* USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX */
509 
510 #if (AVVION || TERMIOS)
511 	/* Set tty mode */
512 	if (tcsetattr(0, TCSANOW, &oldterm)) {
513 		perror("Cannot tcsetattr");
514 		return(-1);
515 	}
516 #endif /* (AVVION || TERMIOS) */
517 
518 	/* Success */
519 	return(0);
520 }
521 
522 /** Flush output buffer to display **/
ttflush()523 int ttflush()
524 {
525 #if TERMCAP
526 	int len;
527 
528 	/* Compute length of write */
529 	len = outbuft - outbuf;
530 	if (len == 0)
531 		return(0);
532 
533 	/* Reset buffer position */
534 	outbuft = outbuf;
535 
536 	/* Perform write to screen */
537 	return(write(1, outbuf, len) != len);
538 #else /* TERMCAP */
539 #if	CURSES
540 	refresh();
541 #endif /* CURSES */
542 	return(0);
543 #endif	/* TERMCAP */
544 }
545 
546 /** Put character onto display **/
ttputc(ch)547 int ttputc(ch)
548 char ch;				/* Character to display		*/
549 {
550 #if TERMCAP
551 	/* Check for buffer full */
552 	if (outbuft == &outbuf[sizeof(outbuf)])
553 		ttflush();
554 
555 	/* Add to buffer */
556 	*outbuft++ = ch;
557 #endif /* TERMCAP */
558 
559 #if CURSES
560 	/* Put character on screen */
561 	addch(ch);
562 #endif /* CURSES */
563 
564 	return(0);
565 }
566 
567 
568 /** Grab input characters, with wait **/
grabwait()569 unsigned char grabwait()
570 {
571 #if (BSD && !TERMIOS)
572 	unsigned char ch;
573 
574 	/* Perform read */
575 	if (read(0, &ch, 1) != 1) {
576 		puts("** Horrible read error occured **");
577 		exit(1);
578 	}
579 	return(ch);
580 #endif /* (BSD && !TERMIOS) */
581 #if USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX || (AVVION || TERMIOS)
582 	unsigned char ch;
583 
584 	/* Change mode, if necessary */
585 	if (curterm.c_cc[VTIME]) {
586 		curterm.c_cc[VMIN] = 1;
587 		curterm.c_cc[VTIME] = 0;
588 #if USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX
589 		ioctl(0, TCSETA, &curterm);
590 #endif /* USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || SUN || XENIX */
591 #if (AVVION || TERMIOS)
592 		tcsetattr(0, TCSANOW, &curterm);
593 #endif /* (AVVION || TERMIOS) */
594 	}
595 
596 	/* Perform read */
597 #if HANDLE_WINCH
598 	while (read(0, &ch, 1) != 1) {
599 		if (winch_flag)
600 			return 0;
601 	}
602 #else
603 	if (read(0, &ch, 1) != 1) {
604 		puts("** Horrible read error occured **");
605 		exit(1);
606 	}
607 #endif
608 	/* Return new character */
609 	return(ch);
610 #endif /* USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX || (AVVION || TERMIOS) */
611 }
612 
613 /** Grab input characters, short wait **/
grabnowait()614 unsigned char grabnowait()
615 {
616 #if (BSD && !TERMIOS)
617 	static struct timeval timout = { 0, 500000L };
618 	int count, r;
619 
620 	/* Select input */
621 	r = 1;
622 	count = select(1, &r, NULL, NULL, &timout);
623 	if (count == 0)
624 		return(TIMEOUT);
625 	if (count < 0) {
626 		puts("** Horrible select error occured **");
627 		exit(1);
628 	}
629 
630 	/* Perform read */
631 	return(grabwait());
632 #endif /* (BSD && !TERMIOS) */
633 #if USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || SUN || XENIX || (AVVION || TERMIOS)
634 	int count;
635 	unsigned char ch;
636 
637 	/* Change mode, if necessary */
638 	if (curterm.c_cc[VTIME] == 0) {
639 		curterm.c_cc[VMIN] = 0;
640 		curterm.c_cc[VTIME] = 5;
641 #if USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX
642 		ioctl(0, TCSETA, &curterm);
643 #endif /* USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX */
644 #if (AVVION || TERMIOS)
645 		tcsetattr(0, TCSANOW, &curterm);
646 #endif /* (AVVION || TERMIOS) */
647 	}
648 
649 	/* Perform read */
650 #if HANDLE_WINCH
651 	while ((count = read(0, &ch, 1)) < 0) {
652 		if (winch_flag)
653 			return 0;
654 	}
655 #else
656 	count = read(0, &ch, 1);
657 	if (count < 0) {
658 		puts("** Horrible read error occured **");
659 		exit(1);
660 	}
661 #endif
662 	if (count == 0)
663 		return(TIMEOUT);
664 
665 	/* Return new character */
666 	return(ch);
667 #endif /* USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || SUN || XENIX || (AVVION || TERMIOS) */
668 }
669 
670 /*
671  * qin - queue in a character to the input buffer.
672  */
673 #if PROTO
qin(int ch)674 VOID qin(int ch)
675 #else
676 VOID qin( ch)
677 int ch;
678 #endif
679 {
680 	/* Check for overflow */
681 	if (inbuft == &inbuf[sizeof(inbuf)]) {
682 		/* Annoy user */
683 		scbeep();
684 		return;
685 	}
686 
687 	/* Add character */
688 	*inbuft++ = ch;
689 }
690 
691 /*
692  * qrep - replace a key sequence with a single character in the input buffer.
693  */
694 #if PROTO
qrep(int ch)695 VOID qrep(int ch)
696 #else
697 VOID qrep( ch)
698 int ch;
699 #endif
700 {
701 	inbuft = inbuf;
702 	qin(ch);
703 }
704 
705 
706 /** Return cooked characters **/
ttgetc()707 int ttgetc()
708 {
709 	int ch;
710 ttflush();
711 	/* Loop until character is in input buffer */
712 	while (inbufh == inbuft)
713 		cook();
714 
715 	/* Get input from buffer, now that it is available */
716 	ch = *inbufh++;
717 
718 	/* reset us to the beginning of the buffer if there are no more
719 	   pending characters */
720 	if (inbufh == inbuft)
721 		inbufh = inbuft = inbuf;
722 
723 	/* Return next character */
724 	return(ch);
725 }
726 
727 #if TYPEAH
typahead()728 int typahead()
729 {
730 	int count;
731 
732 	/* See if internal buffer is non-empty */
733 	if (inbufh != inbuft)
734 		return(1);
735 
736 	/* Now check with system */
737 #ifdef FIONREAD  /* Watch out!  This could bite you! */
738 	/* Get number of pending characters */
739 	if (ioctl(0, FIONREAD, &count))
740 		return(0);
741 	return(count);
742 #else /* not FIONREAD */
743 #ifdef VAT
744 	return(0);
745 #else /* not VAT */
746 	/* Ask hardware for count */
747 	count = ioctl(0, FIORDCHK, 0);
748 	if (count < 0)
749 		return(0);
750 	return(count);
751 #endif	/* VAT */
752 #endif /* FIONREAD */
753 }
754 #endif /* TYPEAH */
755 
756 #if TERMCAP || TERMIOS
757 /** Put out sequence, with padding **/
putpad(seq)758 void putpad(seq)
759 char * seq;				/* Character sequence		*/
760 {
761 	/* Check for null */
762 	if (!seq)
763 		return;
764 
765 	/* Call on termcap to send sequence */
766 	tputs(seq, 1, ttputc);
767 }
768 #endif /* TERMCAP */
769 
770 /** Initialize screen package **/
scopen()771 int scopen()
772 {
773 #if TERMCAP || TERMIOS
774 	char * cp, tcbuf[1024];
775 	int status;
776 	struct capbind * cb;
777 	struct keybind * kp;
778 	char err_str[NSTRING];
779 
780 	char  * tgetstr();
781 
782 #ifndef VAT
783 #define TGETSTR(a,b)	tgetstr((a), (b))
784 #else
785 #define TGETSTR(a,b)	tgetstr((a), *(b))
786 #endif
787 
788 #if HPUX8 || HPUX9 || VAT || AUX || (AVVION || TERMIOS) || AIX
789 
790 	/* HP-UX and AUX doesn't seem to have these in the termcap library */
791 	char PC, * UP;
792 	short ospeed;
793 #else /* not HPUX8 || HPUX9 || VAT || AUX */
794 	extern char PC, * UP;
795 	extern short ospeed;
796 #endif /* HPUX8 || HPUX9 || VAT || AUX */
797 
798 	/* Get terminal type */
799 	cp = getenv("TERM");
800 	if (!cp) {
801 		puts(TEXT182);
802 /*		"Environment variable \"TERM\" not define!" */
803 		exit(1);
804 	}
805 
806 	/* Try to load termcap */
807 	status = tgetent(tcbuf, cp);
808 	if (status == -1) {
809 		puts("Cannot open termcap file");
810 		exit(1);
811 	}
812 	if (status == 0) {
813 		sprintf(err_str, TEXT183, cp);
814 /*		"No entry for terminal type \"%s\"\n" */
815 		puts(err_str);
816 		exit(1);
817 	}
818 
819 	/*
820 	 * If LINES and/or COLUMNS are set in the environment then use those
821 	 * values, otherwise get them from termcap.
822 	 */
823 	if ((cp = getenv("LINES")) == NULL || sscanf(cp, "%d",
824 	    &term.t_nrow) != 1)
825 		term.t_nrow = tgetnum("li");
826 	term.t_nrow -= 1;
827 
828 	if ((cp = getenv("COLUMNS")) == NULL || sscanf(cp, "%d",
829 	    &term.t_ncol) != 1)
830 		term.t_ncol = tgetnum("co");
831 
832 	if (term.t_nrow < 3 || term.t_ncol < 3) {
833 		puts("Screen size is too small!");
834 		exit(1);
835 	}
836 
837 	/* initialize max number of rows and cols	 */
838 	term.t_mrow = term.t_nrow;
839 	term.t_mcol = term.t_ncol;
840 
841 	/* Start grabbing termcap commands */
842 	cp = tcapbuf;
843 
844 	/* Get the reset string */
845 	reset = TGETSTR("is", &cp);
846 
847 	/* Get the pad character */
848 	if (tgetstr("pc", &cp))
849 		PC = tcapbuf[0];
850 
851 	/* Get up line capability */
852 	UP = TGETSTR("up", &cp);
853 
854 	/* Get other capabilities */
855 	cb = capbind;
856 	while (cb < &capbind[sizeof(capbind)/sizeof(*capbind)]) {
857 		cb->store = TGETSTR(cb->name, &cp);
858 		cb++;
859 	}
860 
861 	/* Check for minimum */
862 	if (!capbind[CAP_CL].store && (!capbind[CAP_CM].store || !UP)) {
863 		puts("This terminal doesn't have enough power to run microEmacs!");
864 		exit(1);
865 	}
866 
867 	/* Set reverse video and erase to end of line */
868 	if (capbind[CAP_SO].store && capbind[CAP_SE].store)
869 		revexist = TRUE;
870 	if (!capbind[CAP_CE].store)
871 		eolexist = FALSE;
872 
873 	/* Get keybindings */
874 	kp = keybind;
875 	while (kp < &keybind[sizeof(keybind)/sizeof(*keybind)]) {
876 		addkey(TGETSTR(kp->name, &cp), kp->value);
877 		kp++;
878 	}
879 
880 	/* check for HP-Terminal (so we can label its function keys) */
881 	hpterm = tgetflag("xs");
882 
883 	/* Open terminal device */
884 	if (ttopen()) {
885 		puts("Cannot open terminal");
886 		exit(1);
887 	}
888 
889 	/* Set speed for padding sequences */
890 #if (BSD && !TERMIOS)
891 	ospeed = cursgtty.sg_ospeed;
892 #endif /* (BSD && !TERMIOS) */
893 #if USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX
894 	ospeed = curterm.c_cflag & CBAUD;
895 #endif /* USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || (SUN && !TERMIOS) || XENIX */
896 #if (AVVION || TERMIOS)
897 	ospeed = cfgetospeed(&curterm);
898 #endif /* (AVVION || TERMIOS) */
899 
900 	/* Send out initialization sequences */
901 #if AIX == 0
902 	putpad(capbind[CAP_IS].store);
903 #endif
904 	putpad(capbind[CAP_KS].store);
905 	sckopen();
906 #endif /* TERMCAP */
907 
908 #if CURSES
909 	/* Initialize screen */
910 	initscr();
911 
912 	/* Set size of screen */
913 	term.t_nrow = LINES - 1;
914 	term.t_ncol = COLS;
915 
916 	/* Open terminal device */
917 	if (ttopen()) {
918 		puts("Cannot open terminal");
919 		exit(1);
920 	}
921 #endif /* CURSES */
922 
923 	/* Success */
924 	return(0);
925 }
926 
927 /** Close screen package **/
scclose()928 int scclose()
929 {
930 #if TERMCAP
931 	/* Turn off keypad mode */
932 	putpad(capbind[CAP_KE].store);
933 	sckclose();
934 
935 	/* Close terminal device */
936 	ttflush();
937 	ttclose();
938 #endif /* TERMCAP */
939 
940 #if	TERMIOS
941 	/* Close terminal device */
942 	ttflush();
943 	ttclose();
944 #endif	/* TERMIOS */
945 
946 #if CURSES
947 	/* Turn off curses */
948 	endwin();
949 
950 	/* Close terminal device */
951 	ttflush();
952 	ttclose();
953 #endif /* CURSES */
954 
955 	/* Success */
956 	return(0);
957 }
958 
959 /* open keyboard -hm */
sckopen()960 int sckopen()
961 {
962 #if TERMCAP
963 	putpad(capbind[CAP_KS].store);
964 	ttflush();
965 #if	FLABEL
966 	dis_ufk();
967 #endif
968 #endif
969 }
970 
971 /* close keyboard -hm */
sckclose()972 int sckclose()
973 {
974 #if TERMCAP
975 	putpad(capbind[CAP_KE].store);
976 	ttflush();
977 #if	FLABEL
978 	dis_sfk();
979 #endif
980 #endif
981 }
982 
983 /** Move cursor **/
scmove(row,col)984 int scmove(row, col)
985 int row;				/* Row number			*/
986 int col;				/* Column number		*/
987 {
988 	char *tgoto();
989 
990 #if TERMCAP || TERMIOS
991 	/* Call on termcap to create move sequence */
992 	putpad(tgoto(capbind[CAP_CM].store, col, row));
993 #endif /* TERMCAP */
994 
995 #if CURSES
996 	move(row, col);
997 #endif /* CURSES */
998 
999 	/* Success */
1000 	return(0);
1001 }
1002 
1003 /** Erase to end of line **/
sceeol()1004 int sceeol()
1005 {
1006 #if TERMCAP || TERMIOS
1007 	/* Send erase sequence */
1008 	putpad(capbind[CAP_CE].store);
1009 #endif /* TERMCAP */
1010 
1011 #if CURSES
1012 	clrtoeol();
1013 #endif /* CURSES */
1014 
1015 	/* Success */
1016 	return(0);
1017 }
1018 
1019 /** Clear screen **/
sceeop()1020 int sceeop()
1021 {
1022 #if TERMCAP || TERMIOS
1023 #if COLOR
1024 	scfcol(gfcolor);
1025 	scbcol(gbcolor);
1026 #endif /* COLOR */
1027 	/* Send clear sequence */
1028 	putpad(capbind[CAP_CL].store);
1029 #endif /* TERMCAP */
1030 
1031 #if CURSES
1032 	erase();
1033 #endif /* CURSES */
1034 
1035 
1036 	/* Success */
1037 	return(0);
1038 }
1039 
1040 /** Set reverse video state **/
screv(state)1041 int screv(state)
1042 int state;				/* New state			*/
1043 {
1044 #if TERMCAP || TERMIOS
1045 #if COLOR
1046 	int ftmp, btmp;		/* temporaries for colors */
1047 #endif /* COLOR */
1048 
1049 	/* Set reverse video state */
1050 	putpad(state ? capbind[CAP_SO].store : capbind[CAP_SE].store);
1051 
1052 #if COLOR
1053 	if (state == FALSE) {
1054 		ftmp = cfcolor;
1055 		btmp = cbcolor;
1056 		cfcolor = -1;
1057 		cbcolor = -1;
1058 		scfcol(ftmp);
1059 		scbcol(btmp);
1060 	}
1061 #endif /* COLOR */
1062 #endif /* TERMCAP */
1063 
1064 #if CURSES
1065 	if (state)
1066 		standout();
1067 	else
1068 		standend();
1069 #endif /* CURSES */
1070 
1071 	/* Success */
1072 	return(0);
1073 }
1074 
1075 /** Beep **/
scbeep()1076 scbeep()
1077 {
1078 #if TERMCAP || TERMIOS
1079 #if !NOISY
1080 	/* Send out visible bell, if it exists */
1081 	if (capbind[CAP_VB].store)
1082 		putpad(capbind[CAP_VB].store);
1083 	else
1084 #endif /* not NOISY */
1085 		/* The old standby method */
1086 		ttputc('\7');
1087 #endif /* TERMCAP */
1088 
1089 #if CURSES
1090 	addch('\7');		/* FIX THIS! beep() and flash comes up undefined */
1091 #endif /* CURSES */
1092 
1093 	/* Success */
1094 	return(0);
1095 }
1096 
1097 #if COLOR
1098 static char cmap[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
1099 
1100 /** Set foreground color **/
scfcol(color)1101 int scfcol(color)
1102 int color;		/* Color to set			*/
1103 {
1104 #if TERMCAP || TERMIOS
1105 	/* Skip if already the correct color */
1106 	if (color == cfcolor)
1107 		return(0);
1108 
1109 	/* Send out color sequence */
1110 	if (capbind[CAP_C0].store) {
1111 		putpad(capbind[CAP_C0 + (color & 7)].store);
1112 		cfcolor = color;
1113 	}
1114 #if USG || AUX
1115 	else if (capbind[CAP_SF].store) {
1116 		putpad(tparm(capbind[CAP_SF].store, cmap[color & 7]));
1117 		cfcolor = color;
1118 	}
1119 #endif /* USG || AUX */
1120 #endif /* TERMCAP */
1121 
1122 #if CURSES
1123 	/* ? */
1124 #endif /* CURSES */
1125 	return(0);
1126 }
1127 
1128 /** Set background color **/
scbcol(color)1129 int scbcol(color)
1130 int color;			/* Color to set			*/
1131 {
1132 #if TERMCAP || TERMIOS
1133 	/* Skip if already the correct color */
1134 	if (color == cbcolor)
1135 		return(0);
1136 
1137 	/* Send out color sequence */
1138 	if (capbind[CAP_C0].store) {
1139 		putpad(capbind[CAP_D0 + (color & 7)].store);
1140 		cbcolor = color;
1141 	}
1142 #if USG || AUX
1143 	else if (capbind[CAP_SB].store) {
1144 		putpad(tparm(capbind[CAP_SB].store, cmap[color & 7]));
1145 		cbcolor = color;
1146 	}
1147 #endif /* USG || AUX */
1148 #endif /* TERMCAP */
1149 
1150 #if CURSES
1151 	/* ? */
1152 #endif /* CURSES */
1153 	return(0);
1154 }
1155 #endif /* COLOR */
1156 
1157 /** Set palette **/
spal(cmd)1158 int spal(cmd)
1159 char * cmd;				/* Palette command		*/
1160 {
1161 	int code, dokeymap;
1162 	char * cp;
1163 
1164 	/* Check for keymapping command */
1165 	if (strncmp(cmd, "KEYMAP ", 7) == 0)
1166 		dokeymap = 1;
1167 	else
1168 #if TERMCAP
1169 #if COLOR
1170 	if (strncmp(cmd, "CLRMAP ", 7) == 0)
1171 		dokeymap = 0;
1172 	else
1173 #endif /* COLOR */
1174 #endif /* TERMCAP */
1175 		return(0);
1176 	cmd += 7;
1177 
1178 	/* Look for space */
1179 	for (cp = cmd; *cp != '\0'; cp++)
1180 		if (*cp == ' ') {
1181 			*cp++ = '\0';
1182 			break;
1183 		}
1184 	if (*cp == '\0')
1185 		return(1);
1186 
1187 	/* Perform operation */
1188 	if (dokeymap) {
1189 
1190 		/* Convert to keycode */
1191 		code = stock(cmd);
1192 
1193 		/* Add to tree */
1194 		addkey(cp, code);
1195 	}
1196 #if TERMCAP
1197 #if COLOR
1198 	else {
1199 
1200 		/* Convert to color number */
1201 		code = atoi(cmd);
1202 		if (code < 0 || code > 15)
1203 			return(1);
1204 
1205 		/* Move color code to capability structure */
1206 		capbind[CAP_C0 + code].store = malloc(strlen(cp) + 1);
1207 		if (capbind[CAP_C0 + code].store)
1208 			strcpy(capbind[CAP_C0 + code].store, cp);
1209 	}
1210 #endif /* COLOR */
1211 #endif /* TERMCAP */
1212 	return(0);
1213 }
1214 
1215 #if BSD || FREEBSD || SUN || HPUX8 || HPUX9 || (AVVION || TERMIOS)
1216 /* Surely more than just BSD systems do this */
1217 
1218 /** Perform a stop signal **/
bktoshell(f,n)1219 int bktoshell(f, n)
1220 {
1221 	/* Reset the terminal and go to the last line */
1222 	vttidy();
1223 
1224 	/* Okay, stop... */
1225 	kill(getpid(), SIGTSTP);
1226 
1227 	/* We should now be back here after resuming */
1228 
1229 	/* Reopen the screen and redraw */
1230 	scopen();
1231 	curwp->w_flag = WFHARD;
1232 	sgarbf = TRUE;
1233 
1234 	/* Success */
1235 	return(0);
1236 }
1237 
1238 #endif /* BSD || FREEBSD || SUN || HPUX8 || HPUX9 || (AVVION || TERMIOS) */
1239 
1240 /** Get time of day **/
timeset()1241 char * timeset()
1242 {
1243 	long int buf; /* Should be time_t */
1244 	char * sp, * cp;
1245 
1246 	char * ctime();
1247 
1248 	/* Get system time */
1249 	time(&buf);
1250 
1251 	/* Pass system time to converter */
1252 	sp = ctime(&buf);
1253 
1254 	/* Eat newline character */
1255 	for (cp = sp; *cp; cp++)
1256 		if (*cp == '\n') {
1257 			*cp = '\0';
1258 			break;
1259 		}
1260 	return(sp);
1261 }
1262 
1263 #if USG || AUX || SMOS || HPUX8 || XENIX
1264 /** Rename a file **/
rename(file1,file2)1265 int rename(file1, file2)
1266 char * file1;				/* Old file name		*/
1267 char * file2;				/* New file name		*/
1268 {
1269 	struct stat buf1;
1270 	struct stat buf2;
1271 
1272 	/* No good if source file doesn't exist */
1273 	if (stat(file1, &buf1))
1274 		return(-1);
1275 
1276 	/* Check for target */
1277 	if (stat(file2, &buf2) == 0) {
1278 
1279 		/* See if file is the same */
1280 		if (buf1.st_dev == buf2.st_dev &&
1281 			buf1.st_ino == buf2.st_ino)
1282 
1283 			/* Not necessary to rename file */
1284 			return(0);
1285 	}
1286 
1287 	/* Get rid of target */
1288 	unlink(file2);
1289 
1290 	/* Link two files together */
1291 	if (link(file1, file2))
1292 		return(-1);
1293 
1294 	/* Unlink original file */
1295 	return(unlink(file1));
1296 }
1297 #endif /* USG || AUX || SMOS || HPUX8 || XENIX */
1298 
1299 /** Callout to system to perform command **/
callout(cmd)1300 int callout(cmd)
1301 char * cmd;				/* Command to execute		*/
1302 {
1303 	int status;
1304 
1305 	/* Close down */
1306 	scmove(term.t_nrow, 0);
1307 	ttflush();
1308 	sckclose();
1309 	ttclose();
1310 
1311 	/* Do command */
1312 	status = system(cmd) == 0;
1313 
1314 	/* Restart system */
1315         sgarbf = TRUE;
1316 	sckopen();
1317 	if (ttopen()) {
1318 		puts("** Error reopening terminal device **");
1319 		exit(1);
1320 	}
1321 
1322 	/* Success */
1323         return(status);
1324 }
1325 
1326 /** Create subshell **/
spawncli(f,n)1327 int spawncli(f, n)
1328 int f;					/* Flags			*/
1329 int n;					/* Argument count		*/
1330 {
1331 	char * sh;
1332 
1333 	/* Don't allow this command if restricted */
1334 	if (restflag)
1335 		return(resterr());
1336 
1337 	/* Get shell path */
1338 	sh = getenv("SHELL");
1339 	if (!sh)
1340 #if BSD || FREEBSD || SUN
1341 		sh = "/bin/csh";
1342 #endif /* BSD || FREEBSD || SUN */
1343 #if USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || XENIX || (AVVION || TERMIOS)
1344 		sh = "/bin/sh";
1345 #endif /* USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || XENIX || (AVVION || TERMIOS) */
1346 
1347 	/* Do shell */
1348 	return(callout(sh));
1349 }
1350 
1351 /** Spawn a command **/
spawn(f,n)1352 int spawn(f, n)
1353 int f;					/* Flags			*/
1354 int n;					/* Argument count		*/
1355 {
1356 	char line[NLINE];
1357 	int s;
1358 
1359 	/* Don't allow this command if restricted */
1360 	if (restflag)
1361 		return(resterr());
1362 
1363 	/* Get command line */
1364 	s = mlreply("!", line, NLINE);
1365 	if (!s)
1366 		return(s);
1367 
1368 	/* Perform the command */
1369 	s = callout(line);
1370 
1371 	/* if we are interactive, pause here */
1372 	if (clexec == FALSE) {
1373 	        mlwrite("[End]");
1374 		ttflush();
1375 		ttgetc();
1376         }
1377         return(s);
1378 }
1379 
1380 /** Execute program **/
execprg(f,n)1381 int execprg(f, n)
1382 int f;					/* Flags			*/
1383 int n;					/* Argument count		*/
1384 {
1385 	/* Same as spawn */
1386 	return(spawn(f, n));
1387 }
1388 
1389 /** Pipe output of program to buffer **/
pipecmd(f,n)1390 int pipecmd(f, n)
1391 int f;					/* Flags			*/
1392 int n;					/* Argument count		*/
1393 {
1394 	char line[NLINE];
1395 	int s;
1396 	BUFFER * bp;
1397 	EWINDOW * wp;
1398 	static char filnam[] = "command";
1399 
1400 	/* Don't allow this command if restricted */
1401 	if (restflag)
1402 		return(resterr());
1403 
1404 	/* Get pipe-in command */
1405 	s = mlreply("@", line, NLINE);
1406 	if (!s)
1407 		return(s);
1408 
1409 	/* Get rid of the command output buffer if it exists */
1410 	bp = bfind(filnam, FALSE, 0);
1411 	if (bp) {
1412 		/* Try to make sure we are off screen */
1413 		wp = wheadp;
1414 		while (wp) {
1415 			if (wp->w_bufp == bp) {
1416 				onlywind(FALSE, 1);
1417 				break;
1418 			}
1419 			wp = wp->w_wndp;
1420 		}
1421 		if (!zotbuf(bp))
1422 			return(0);
1423 	}
1424 
1425 	/* Add output specification */
1426 	strcat(line, ">");
1427 	strcat(line, filnam);
1428 
1429 	/* Do command */
1430 	s = callout(line);
1431 	if (!s)
1432 		return(s);
1433 
1434 	/* Split the current window to make room for the command output */
1435 	if (!splitwind(FALSE, 1))
1436 		return(0);
1437 
1438 	/* ...and read the stuff in */
1439 	if (!getfile(filnam, FALSE))
1440 		return(0);
1441 
1442 	/* Make this window in VIEW mode, update all mode lines */
1443 	curwp->w_bufp->b_mode |= MDVIEW;
1444 	wp = wheadp;
1445 	while (wp) {
1446 		wp->w_flag |= WFMODE;
1447 		wp = wp->w_wndp;
1448 	}
1449 
1450 	/* ...and get rid of the temporary file */
1451 	unlink(filnam);
1452 	return(1);
1453 }
1454 
1455 /** Filter buffer through command **/
filter(f,n)1456 int filter(f, n)
1457 int f;					/* Flags			*/
1458 int n;					/* Argument count		*/
1459 {
1460 	char line[NLINE], tmpnam[NFILEN];
1461 	int s;
1462 	BUFFER * bp;
1463 	static char bname1[] = "fltinp";
1464 	static char filnam1[] = "fltinp";
1465 	static char filnam2[] = "fltout";
1466 
1467 	/* Don't allow this command if restricted */
1468 	if (restflag)
1469 		return(resterr());
1470 
1471 	/* Don't allow filtering of VIEW mode buffer */
1472 	if (curbp->b_mode & MDVIEW)
1473 		return(rdonly());
1474 
1475 	/* Get the filter name and its args */
1476 	s = mlreply("#", line, NLINE);
1477 	if (!s)
1478 		return(s);
1479 
1480 	/* Setup the proper file names */
1481 	bp = curbp;
1482 	strcpy(tmpnam, bp->b_fname);	/* Save the original name */
1483 	strcpy(bp->b_fname, bname1);	/* Set it to our new one */
1484 
1485 	/* Write it out, checking for errors */
1486 	if (!writeout(filnam1, "w")) {
1487 		mlwrite("[Cannot write filter file]");
1488 		strcpy(bp->b_fname, tmpnam);
1489 		return(0);
1490 	}
1491 
1492 	/* Setup input and output */
1493 	strcat(line," <fltinp >fltout");
1494 
1495 	/* Perform command */
1496 	s = callout(line);
1497 
1498 	/* If successful, read in file */
1499 	if (s) {
1500 		s = readin(filnam2, FALSE);
1501 		if (s)
1502 			/* Mark buffer as changed */
1503 			bp->b_flag |= BFCHG;
1504 	}
1505 
1506 
1507 	/* Reset file name */
1508 	strcpy(bp->b_fname, tmpnam);
1509 
1510 	/* and get rid of the temporary file */
1511 	unlink(filnam1);
1512 	unlink(filnam2);
1513 
1514 	/* Show status */
1515 	if (!s)
1516 		mlwrite("[Execution failed]");
1517 	return(s);
1518 }
1519 
1520 /** Get first filename from pattern **/
getffile(fspec)1521 char *getffile(fspec)
1522 char *fspec;				/* Filename specification	*/
1523 {
1524 	int index, point, extflag;
1525 
1526 	/* First parse the file path off the file spec */
1527 	strcpy(path, fspec);
1528 	index = strlen(path) - 1;
1529 	while (index >= 0 && (path[index] != '/'))
1530 		--index;
1531 	path[index+1] = '\0';
1532 
1533 
1534 	/* Check for an extension */
1535 	point = strlen(fspec) - 1;
1536 	extflag = FALSE;
1537 	while (point >= 0) {
1538 		if (fspec[point] == '.') {
1539 			extflag = TRUE;
1540 			break;
1541 		}
1542 		point--;
1543 	}
1544 
1545 	/* Open the directory pointer */
1546 	if (dirptr) {
1547 		closedir(dirptr);
1548 		dirptr = NULL;
1549 	}
1550 
1551 	dirptr = opendir((path[0] == '\0') ? "./" : path);
1552 
1553 	if (!dirptr)
1554 		return(NULL);
1555 
1556 	strcpy(rbuf, path);
1557 	nameptr = &rbuf[strlen(rbuf)];
1558 
1559 	/* ...and call for the first file */
1560 	return(getnfile());
1561 }
1562 
1563 /** Get next filename from pattern **/
getnfile()1564 char *getnfile()
1565 {
1566 	int index;
1567 	struct DIRENTRY * dp;
1568 	struct stat fstat;
1569 
1570 	/* ...and call for the next file */
1571 	do {
1572 		dp = readdir(dirptr);
1573 		if (!dp)
1574 			return(NULL);
1575 
1576 		/* Check to make sure we skip all weird entries except directories */
1577 		strcpy(nameptr, dp->d_name);
1578 
1579 	} while (stat(rbuf, &fstat) ||
1580 		((fstat.st_mode & S_IFMT) & (S_IFREG | S_IFDIR)) == 0);
1581 
1582 	/* if this entry is a directory name, say so */
1583 	if ((fstat.st_mode & S_IFMT) == S_IFDIR)
1584 		strcat(rbuf, DIRSEPSTR);
1585 
1586 	/* Return the next file name! */
1587 	return(rbuf);
1588 }
1589 
1590 #if FLABEL
1591 /*---------------------------------------------------------------------------*
1592 
1593       handle the function keys and function key labels on HP-Terminals
1594       -----------------------------------------------------------------
1595 
1596       Hellmuth Michaelis	e-mail: hm@hcshh.hcs.de
1597 
1598  *---------------------------------------------------------------------------*/
1599 
1600 static unsigned char flabstor[8][50];		/* label & xmit backup store */
1601 static char flabstof[8] = {0,0,0,0,0,0,0,0};	/* filled flag */
1602 
fnclabel(f,n)1603 int fnclabel(f, n)		/* label a function key */
1604 
1605 int f;		/* Default argument */
1606 int n;		/* function key number 1...8 on hp-terminals */
1607 
1608 {
1609 	char lbl[20];	/* label string buffer */
1610 	char xmit[5];	/* transmitted string ( ESC 'p'...'w' ) */
1611 	char buf[80];	/* writeout buffer */
1612 	int i;		/* general purpose index */
1613 	int status;	/* return status */
1614 
1615 	/* check if we are connected to an hp-terminal */
1616 	if (!hpterm)
1617 		return(FALSE);
1618 
1619 	/* must be called with an argument */
1620 	if (f == FALSE) {
1621 		mlwrite(TEXT246);
1622 /*			"%%Need function key number"*/
1623 		return(FALSE);
1624 	}
1625 
1626 	/* and it must be a legal key number */
1627 	if (n < 1 || n > 8) {
1628 		mlwrite(TEXT247);
1629 /*			"%%Function key number out of range"*/
1630 		return(FALSE);
1631 	}
1632 
1633 	/* get the string to send */
1634 	lbl[0] = '\0';	/* we don't now the label yet */
1635 
1636 	if ((status = mlreply(TEXT248, lbl, 19)) != TRUE)
1637 /*			      "Enter Label String: "*/
1638 		return(status);
1639 
1640 	lbl[16] = '\0';
1641  	i = strlen(lbl);
1642 
1643 	/* set up escape sequence to send to terminal */
1644 	xmit[0] = 0x1b;
1645 	xmit[1] = 'o' + n;
1646 	xmit[2] = '\0';
1647 
1648 	sprintf(flabstor[n-1], "%c&f0a%dk%dd2L%s%s", (char)0x1b, n, i,
1649 					lbl, xmit);
1650 	write(1, flabstor[n-1], strlen(flabstor[n-1]));
1651 	flabstof[n-1] = 1;
1652 
1653 	sprintf(buf, "%c&jB", (char)0x1b);
1654 	write(1, buf, strlen(buf));
1655 
1656 	return(TRUE);
1657 }
1658 
1659 /* display user function key labels */
dis_ufk()1660 static void dis_ufk()
1661 
1662 {
1663 	int label_num;
1664 	char buf[6];
1665 
1666 	if (!hpterm)
1667 		return;
1668 
1669 	for (label_num = 0; label_num < 8; label_num++)
1670 		if (flabstof[label_num])
1671 			write(1, flabstor[label_num],
1672 				strlen(flabstor[label_num]));
1673 	sprintf(buf, "%c&jB", (char)0x1b);
1674 	write(1, buf, strlen(buf));
1675 }
1676 
1677 /* display system function key labels */
dis_sfk()1678 static void dis_sfk()
1679 
1680 {
1681 	char buf[6];
1682 
1683 	if (!hpterm)
1684 		return;
1685 	sprintf(buf, "%c&jA", (char)0x1b);
1686 	write(1, buf, strlen(buf));
1687 }
1688 #endif /* FLABEL */
1689 
1690 #if XENIX && FILOCK
mkdir(name,mode)1691 int mkdir(name, mode)
1692 char *name;	/* name of directory to create */
1693 int mode;	/* umask for creation (which we blissfully ignore...) */
1694 {
1695 	char buf[80];
1696 
1697 	strcpy(buf, "mkdir ");
1698 	strcat(buf, name);
1699 	strcat(buf, " > /dev/null 2>&1");
1700 	return(system(buf));
1701 }
1702 
rmdir(name)1703 int rmdir(name)
1704 char *name;	/* name of directory to delete */
1705 {
1706 	char buf[80];
1707 
1708 	strcpy(buf,"rmdir ");
1709 	strcat(buf, name);
1710 	strcat(buf, " > /dev/null 2>&1");
1711 	return(system(buf));
1712 }
1713 #endif /* XENIX & FILOCK */
1714 
1715 #if HANDLE_WINCH
1716 /*
1717  * Window size changes handled via signals.
1718  */
winch_changed()1719 void winch_changed()
1720 {
1721 	signal(SIGWINCH,winch_changed);
1722 	winch_flag = 1;
1723 }
1724 
winch_new_size()1725 void winch_new_size()
1726 {
1727 	EWINDOW *wp;
1728 	struct winsize win;
1729 
1730 	winch_flag=0;
1731 	ioctl(fileno(stdin),TIOCGWINSZ,&win);
1732 	winch_vtresize(win.ws_row,win.ws_col);
1733 	onlywind(0,0);
1734 	TTmove(0,0);
1735 	TTeeop();
1736 }
1737 #endif
1738 
1739 #endif /* BSD || FREEBSD || USG || AIX || AUX || SMOS || HPUX8 || HPUX9 || SUN || XENIX || (AVVION || TERMIOS) */
1740