1 /*	AMIGADOS.C:	Operating specific I/O and Spawning functions
2 			for MicroEMACS 4.00
3 			(C)Copyright 1995 by Daniel M. Lawrence
4 */
5 
6 #include        <stdio.h>
7 #include	"estruct.h"
8 #if	AMIGA
9 #include	<exec/types.h>
10 #include	<exec/io.h>
11 #include	<intuition/intuition.h>
12 #include	<devices/console.h>
13 #include	"eproto.h"
14 #include        "edef.h"
15 #include	"elang.h"
16 
17 #define INTUITION_REV	0L
18 #define	NEW 		1006L
19 #define	CRWIDTH		8
20 #define	CRHEIGHT	8
21 
22 struct IntuitionBase *IntuitionBase;
23 struct Window *win;
24 struct IOStdReq con;		/* ptr to console device driver handle */
25 
26 /*	Intuition Function type declarations	*/
27 
28 struct IntuitionBase *OpenLibrary();
29 struct Window *OpenWindow();
30 struct IntuiMessage *GetMsg();
31 
32 typedef struct {
33 	short rw_code;		/* normal keycode to generate */
34 	short rw_scode;		/* shifted  "  */
35 	short rw_ccode;		/* control  "  */
36 } RKEY;
37 
38 /* raw keycode scan code to emacs keycode translation table */
39 
40 RKEY keytrans[0x60] = {
41 
42 /*	CODE	NORM	SHIFT	CTRL */
43 /*	0x00,*/	'`',	'~',	0,
44 /*	0x01,*/	'1',	'!',	0,
45 /*	0x02,*/	'2',	'@',	0,
46 /*	0x03,*/	'3',	'#',	0,
47 /*	0x04,*/	'4',	'$',	0,
48 /*	0x05,*/	'5',	'%',	0,
49 /*	0x06,*/	'6',	'^',	0,
50 /*	0x07,*/	'7',	'&',	0,
51 /*	0x08,*/	'8',	'*',	0,
52 /*	0x09,*/	'9',	'(',	0,
53 /*	0x0a,*/	'0',	')',	0,
54 /*	0x0b,*/	'-',	'_',	0,
55 /*	0x0c,*/	'=',	'+',	0,
56 /*	0x0d,*/	'\\',	'|',	0,
57 /*	0x0e,*/	0,	0,	0,
58 /*	0x0f,*/	0,	0,	0,
59 /*	0x10,*/	'q',	'Q',	CTRL|'Q',
60 /*	0x11,*/	'w',	'W',	CTRL|'W',
61 /*	0x12,*/	'e',	'E',	CTRL|'E',
62 /*	0x13,*/	'r',	'R',	CTRL|'R',
63 /*	0x14,*/	't',	'T',	CTRL|'T',
64 /*	0x15,*/	'y',	'Y',	CTRL|'Y',
65 /*	0x16,*/	'u',	'U',	CTRL|'U',
66 /*	0x17,*/	'i',	'I',	CTRL|'I',
67 /*	0x18,*/	'o',	'O',	CTRL|'O',
68 /*	0x19,*/	'p',	'P',	CTRL|'P',
69 /*	0x1a,*/	'[',	'{',	0,
70 /*	0x1b,*/	']',	'}',	0,
71 /*	0x1c,*/	0,	0,	0,
72 /*	0x1d,*/	'1',	SPEC|'>',	0,
73 /*	0x1e,*/	'2',	SPEC|'N',	0,
74 /*	0x1f,*/	'3',	SPEC|'V',	0,
75 /*	0x20,*/	'a',	'A',	CTRL|'A',
76 /*	0x21,*/	's',	'S',	CTRL|'S',
77 /*	0x22,*/	'd',	'D',	CTRL|'D',
78 /*	0x23,*/	'f',	'F',	CTRL|'F',
79 /*	0x24,*/	'g',	'G',	CTRL|'G',/*	0x25,*/	'h',	'H',	CTRL|'H',
80 /*	0x26,*/	'j',	'J',	CTRL|'J',
81 /*	0x27,*/	'k',	'K',	CTRL|'K',
82 /*	0x28,*/	'l',	'L',	CTRL|'L',
83 /*	0x29,*/	';',	':',	0,
84 /*	0x2a,*/	39,	34,	0,
85 /*	0x2b,*/	0,	0,	0,
86 /*	0x2c,*/	0,	0,	0,
87 /*	0x2d,*/	'4',	SPEC|'B',	0,
88 /*	0x2e,*/	'5',	0,		0,
89 /*	0x2f,*/	'6',	SPEC|'F',	0,
90 	/* this key is probably mapped on forign AIMIGA keyboards */
91 /*	0x30,*/	0,	0,	0,
92 /*	0x31,*/	'z',	'Z',	CTRL|'Z',
93 /*	0x32,*/	'x',	'X',	CTRL|'X',
94 /*	0x33,*/	'c',	'C',	CTRL|'C',
95 /*	0x34,*/	'v',	'V',	CTRL|'V',
96 /*	0x35,*/	'b',	'B',	CTRL|'B',
97 /*	0x36,*/	'n',	'N',	CTRL|'N',
98 /*	0x37,*/	'm',	'M',	CTRL|'M',
99 /*	0x38,*/	',',	'<',	0,
100 /*	0x39,*/	'.',	'>',	0,
101 /*	0x3a,*/	'/',	'?',	0,
102 /*	0x3b,*/	0,	0,	0,
103 /*	0x3c,*/	'.',	SPEC|'D',	0,
104 /*	0x3d,*/	'7',	SPEC|'<',	0,
105 /*	0x3e,*/	'8',	SPEC|'P',	0,
106 /*	0x3f,*/	'9',	SPEC|'Z',	0,
107 /*	0x40,*/	' ',	SHFT|' ',	0,
108 /*	0x41,*/	CTRL|'H',	SHFT|'D',	0,
109 /*	0x42,*/	CTRL|'I',	SHFT|'I',	0,
110 /*	0x43,*/	CTRL|'M', CTRL|'M', CTRL|'M',
111 /*	0x44,*/	CTRL|'M', CTRL|'M', CTRL|'M',
112 /*	0x45,*/	CTRL|'[',	0,	0,
113 /*	0x46,*/	SPEC|'D',	0,	0,
114 /*	0x47,*/	0,	0,	0,
115 /*	0x48,*/	0,	0,	0,
116 /*	0x49,*/	0,	0,	0,
117 /*	0x4a,*/	'-',	0,	0,
118 /*	0x4b,*/	0,	0,	0,
119 /*	0x4c,*/	SPEC|'P',	SHFT|SPEC|'P',	CTRL|SPEC|'P',
120 /*	0x4d,*/	SPEC|'N',	SHFT|SPEC|'N',	CTRL|SPEC|'N',
121 /*	0x4e,*/	SPEC|'F',	SHFT|SPEC|'F',	CTRL|SPEC|'F',
122 /*	0x4f,*/	SPEC|'B',	SHFT|SPEC|'B',	CTRL|SPEC|'B',
123 /*	0x50,*/	SPEC|'1',	SHFT|SPEC|'1',	CTRL|SPEC|'1',
124 /*	0x51,*/	SPEC|'2',	SHFT|SPEC|'2',	CTRL|SPEC|'2',
125 /*	0x52,*/	SPEC|'3',	SHFT|SPEC|'3',	CTRL|SPEC|'3',
126 /*	0x53,*/	SPEC|'4',	SHFT|SPEC|'4',	CTRL|SPEC|'4',
127 /*	0x54,*/	SPEC|'5',	SHFT|SPEC|'5',	CTRL|SPEC|'5',
128 /*	0x55,*/	SPEC|'6',	SHFT|SPEC|'6',	CTRL|SPEC|'6',
129 /*	0x56,*/	SPEC|'7',	SHFT|SPEC|'7',	CTRL|SPEC|'7',
130 /*	0x57,*/	SPEC|'8',	SHFT|SPEC|'8',	CTRL|SPEC|'8',
131 /*	0x58,*/	SPEC|'9',	SHFT|SPEC|'9',	CTRL|SPEC|'9',
132 /*	0x59,*/	SPEC|'0',	SHFT|SPEC|'0',	CTRL|SPEC|'0',
133 /*	0x5a,*/	'(',	0,	0,
134 /*	0x5b,*/	')',	0,	0,
135 /*	0x5c,*/	'/',	0,	0,
136 /*	0x5d,*/	'*',	0,	0,
137 /*	0x5e,*/	0,	0,	0,
138 /*	0x5f,*/	SPEC|'?',	0,	0,
139 };
140 
141 /* some keyboard keys current states */
142 
143 int r_shiftflag;	/* right shift key */
144 int l_shiftflag;	/* left shift key */
145 int r_altflag;		/* right alt key */
146 int l_altflag;		/* left alt key */
147 int r_amiflag;		/* right amiga key */
148 int l_amiflag;		/* left amiga key */
149 int ctrlflag;		/* control key */
150 int lockflag;		/* shift lock key */
151 
152 /*	output buffers and pointers	*/
153 
154 #define OBUFSIZE	1024L
155 #define	IBUFSIZE	64	/* this must be a power of 2 */
156 
157 char out_buf[OBUFSIZE+1];	/* output character buffer */
158 int out_ptr = 0;		/* index to next char to put in buffer */
159 
160 /*	input buffers and pointers	*/
161 
162 #define	IBUFSIZE	64	/* this must be a power of 2 */
163 
164 unsigned char in_buf[IBUFSIZE];	/* input character buffer */
165 int in_next = 0;		/* pos to retrieve next input character */
166 int in_last = 0;		/* pos to place most recent input character */
167 
in_init()168 in_init()	/* initialize the input buffer */
169 
170 {
171 	in_next = in_last = 0;
172 }
173 
in_check()174 in_check()	/* is the input buffer non-empty? */
175 
176 {
177 	if (in_next == in_last)
178 		return(FALSE);
179 	else
180 		return(TRUE);
181 }
182 
in_put(event)183 in_put(event)
184 
185 int event;	/* event to enter into the input buffer */
186 
187 {
188 	in_buf[in_last++] = event;
189 	in_last &= (IBUFSIZE - 1);
190 }
191 
in_get()192 int in_get()	/* get an event from the input buffer */
193 
194 {
195 	register int event;	/* event to return */
196 
197 	event = in_buf[in_next++];
198 	in_next &= (IBUFSIZE - 1);
199 	return(event);
200 }
201 
202 /*
203  * This function is called once to set up the terminal device streams.
204  * On VMS, it translates TT until it finds the terminal, then assigns
205  * a channel to it and sets it raw. On CPM it is a no-op.
206  */
ttopen()207 ttopen()
208 {
209 	struct NewWindow new_win;
210 	int i;
211 #if	AZTEC
212 	extern	Enable_Abort;	/* Turn off ctrl-C interrupt */
213 
214 	Enable_Abort = 0;	/* for the Manx compiler */
215 #endif
216 	strcpy(os, "AMIGADOS");
217 
218 	/* open the intuition library */
219 	IntuitionBase = (struct IntuitionBase *)
220 		OpenLibrary("intuition.library", INTUITION_REV);
221 	if (IntuitionBase == NULL) {
222 		printf("%%Can not open Intuition\n");
223 		exit(-1);
224 	}
225 
226 	/* initialize the new windows attributes */
227 	new_win.LeftEdge = 0;
228 	new_win.TopEdge = 0;
229 	new_win.Width = 640;
230 	new_win.Height = 200;
231 	new_win.DetailPen = 0;
232 	new_win.BlockPen = 1;
233 	new_win.Title = (unsigned char *)"MicroEMACS 4.00/Amiga";
234 	new_win.Flags = WINDOWCLOSE | SMART_REFRESH | ACTIVATE |
235 		WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING | SIZEBRIGHT |
236 		RMBTRAP | NOCAREREFRESH;
237 	new_win.IDCMPFlags = CLOSEWINDOW | NEWSIZE | MOUSEBUTTONS |
238 		RAWKEY;
239 	new_win.Type = WBENCHSCREEN;
240 	new_win.FirstGadget = NULL;
241 	new_win.CheckMark = NULL;
242 	new_win.Screen = NULL;
243 	new_win.BitMap = NULL;
244 	new_win.MinWidth = 100;
245 	new_win.MinHeight = 25;
246 	new_win.MaxWidth = 640;
247 	new_win.MaxHeight = 200;
248 
249 	/* open the window! */
250 	win = (struct Window *)OpenWindow(&new_win);
251 	if (win == NULL) {
252 		printf("%%Can not open a window\n");
253 		exit(-2);
254 	}
255 
256 	/* and open up the console for output */
257 	con.io_Data = (APTR)win;
258 	OpenDevice("console.device", 0, &con, 0);
259 
260 	/* and init all the keyboard flags */
261 	r_shiftflag = FALSE;
262 	l_shiftflag = FALSE;	r_altflag = FALSE;
263 	l_altflag = FALSE;
264 	r_amiflag = FALSE;
265 	l_amiflag = FALSE;
266 	ctrlflag = FALSE;
267 	lockflag = FALSE;
268 
269 	/* initialize our private event queue */
270 	in_init();
271 
272 	/* set the current sizes */
273 	newwidth(TRUE, 77);
274 	newsize(TRUE, 23);
275 
276 	/* on all screens we are not sure of the initial position
277 	   of the cursor					*/
278 	ttrow = 999;
279 	ttcol = 999;
280 }
281 
282 /*
283  * This function gets called just before we go back home to the command
284  * interpreter. On VMS it puts the terminal back in a reasonable state.
285  * Another no-operation on CPM.
286  */
ttclose()287 ttclose()
288 
289 {
290 	/* make sure there is no pending output */
291 	ttflush();
292 
293 	/* and now close up shop */
294 	CloseDevice(&con);
295 	CloseWindow(win);
296 	OpenWorkBench();
297 }
298 
299 /*
300  * Write a character to the display. On VMS, terminal output is buffered, and
301  * we just put the characters in the big array, after checking for overflow.
302  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
303  * MS-DOS (use the very very raw console output routine).
304  */
305 
ttputc(c)306 ttputc(c)
307 
308 char c;
309 
310 {
311 	/* add the character to the output buffer */
312         out_buf[out_ptr++] = c;
313 
314         /* send the buffer out if we are at the limit */
315         if (out_ptr >= OBUFSIZE)
316                 ttflush();
317 }
318 
319 /*
320  * Flush terminal buffer. Does real work where the terminal output is buffered
321  * up. A no-operation on systems where byte at a time terminal I/O is done.
322  */
323 
ttflush()324 ttflush()
325 
326 {
327 	/* if there are any characters waiting to display... */
328         if (out_ptr) {
329         	out_buf[out_ptr] = 0;	/* terminate the buffer string */
330         	sendcon(out_buf);	/* send them out */
331 	        out_ptr = 0;		/* and reset the buffer */
332 	}
333 }
334 
335 /*
336  * Read a character from the terminal.
337  */
338 
ttgetc()339 ttgetc()
340 
341 {
342 	/* make sure there is no pending output */
343 nxtchr:	ttflush();
344 
345 	/* if it is already buffered up, get it */
346 	if (in_check())
347 		return(in_get());
348 
349 	/* process an INTUITION event (possibly loading the input buffer) */
350 	doevent();
351 	goto nxtchr;
352 }
353 
354 #if	TYPEAH
355 /* typahead:	Check to see if any characters are already in the
356 		keyboard buffer
357 */
358 
typahead()359 typahead()
360 
361 {
362 tcheck:	/* if type ahead is already pending... */
363 	if (in_check())
364 		return(TRUE);
365 
366 	/* check the signal for IDCMP events pending */
367 	if ((1 << win->UserPort->mp_SigBit) != 0)
368 		return(TRUE);
369 
370 	/* no event in queue... no typeahead ready */
371 	return(FALSE);
372 }
373 #endif
374 
doevent()375 doevent()
376 
377 {
378 	register int eventX, eventY;	/* local copies of the event info */
379 	struct IntuiMessage *event;	/* current event to repond to */
380 	ULONG class;	/* class of event */
381 	USHORT code;	/* data code */
382 	SHORT x,y;	/* mouse x/y position at time of event */
383 	char buf[128];	/*temp buff*/
384 
385 	/* wait for an event to occur */
386 	Wait(1 << win->UserPort->mp_SigBit);
387 
388 	/* get the event and parse it up */
389 	while (event = GetMsg(win->UserPort)) {
390 		class = event->Class;
391 		code = event->Code;
392 		eventX = event->MouseX;
393 		eventY = event->MouseY;
394 		ReplyMsg(event);
395 
396 		/* a normal keystroke? */
397 		if (class == RAWKEY) {			dokey(code);
398 			continue;
399 		}
400 
401 		/* User clicked on the close gadget! */
402 		if (class == CLOSEWINDOW) {
403 			quit(FALSE, 0);
404 			stuffibuf(255, 0, 0);	/* fake a char to force quit to work */
405 		}
406 
407 		/* resolve the mouse address (border adjusted) */
408 		if (class == NEWSIZE) {
409 			x = (win->Width - 5) / CRWIDTH;
410 			y = (win->Height - 10) / CRHEIGHT;
411 		} else {
412 			x = (eventX - 5) / CRWIDTH;
413 			y = (eventY - 10) / CRHEIGHT;
414 		}
415 		if (x > 77)
416 			x = 77;
417 		if (y > 23)
418 			y = 23;
419 
420 		/* are we resizing the window? */
421 		if (class == NEWSIZE) {
422 			stuffibuf(MOUS | '1', x, y);
423 			continue;
424 		}
425 
426 		/* and lastly, a mouse button press */
427 		switch (code) {
428 			case 104:	stuffibuf(MOUS | mod('a'), x, y);
429 					break;
430 			case 232:	stuffibuf(MOUS | mod('b'), x, y);
431 					break;
432 			case 105:	stuffibuf(MOUS | mod('e'), x, y);
433 					break;
434 			case 233:	stuffibuf(MOUS | mod('f'), x, y);
435 					break;
436 		}
437 	}
438 	return;
439 }
440 
mod(c)441 int mod(c)	/* modify a character by the current shift and control flags */
442 
443 int c;		/* original character */
444 
445 {
446 	/* first apply the shift and control modifiers */
447 	if (l_shiftflag || r_shiftflag || lockflag)
448 		c -= 32;
449 	if (ctrlflag)
450 		c |= CTRL;
451 	return(c);
452 }
453 
sendcon(buf)454 sendcon(buf)	/* send a string to the console */
455 
456 char *buf;	/* buffer to write out */
457 
458 {
459 	/* initialize the IO request */
460 	con.io_Data = (APTR)buf;
461 	con.io_Length = strlen(buf);
462 	con.io_Command = CMD_WRITE;
463 
464 	/* and perform the I/O */
465 	SendIO(&con);
466 }
467 
468 
469 /* process an incomming keyboard code */
470 
dokey(code)471 dokey(code)
472 
473 int code;	/* raw keycode to convert */
474 
475 {
476 	register int ekey;	/* translate emacs key */
477 	register int dir;	/* key direction (up/down) */
478 	char buf[NSTRING];
479 
480 	/* decode the direction of the key */
481 	dir = TRUE;
482 	if (code > 127) {
483 		code = code & 127;
484 		dir = FALSE;
485 	}
486 
487 	/* process various shift keys */
488 	if (code >= 0x60) {
489 		switch (code) {
490 
491 			case 0x60:	l_shiftflag = dir;	break;
492 			case 0x61:	r_shiftflag = dir;	break;
493 			case 0x62:	lockflag    = dir;	break;
494 			case 0x63:	ctrlflag    = dir;	break;
495 			case 0x64:	l_altflag   = dir;	break;
496 			case 0x65:	r_altflag   = dir;	break;
497 			case 0x66:	l_amiflag   = dir;	break;
498 			case 0x67:	r_amiflag   = dir;	break;
499 
500 		}
501 		return;
502 	}
503 
504 	/* up keystrokes are ignored for the rest of these */
505 	if (dir == FALSE)
506 		return;
507 
508 	/* first apply the shift and control modifiers */
509 	if (ctrlflag)
510 		ekey = keytrans[code].rw_ccode;
511 	else if (l_shiftflag || r_shiftflag || lockflag)
512 		ekey = keytrans[code].rw_scode;
513 	else
514 		ekey = keytrans[code].rw_code;
515 
516 	/* now apply the ALTD modifier */
517 	if (r_altflag || l_altflag)
518 		ekey |= ALTD;
519 
520 	/* apply the META prefix */
521 	if (r_amiflag || l_amiflag) {
522 		if ('a' <= ekey && ekey <= 'z')
523 			ekey -= 32;
524 		ekey |= META;
525 	}
526 
527 	/* and place it in the input buffer */
528 	stuffibuf(ekey, 0, 0);
529 }
530 
stuffibuf(key,x,y)531 stuffibuf(key, x, y)	/* stuff a key in the input buffer */
532 
533 int key;	/* extended keystroke to remember */
534 int x, y;	/* mouse position to record */
535 
536 {
537 	register int upper;	/* upper extended bits of key */
538 
539 	/* split the extended keystroke */
540 	upper = key >> 8;
541 	key = key & 255;
542 
543 	/* if it is JUST control... encode it in! */
544 	if (upper == (CTRL >> 8)) {
545 		in_put(key - 64);
546 		return;
547 	}
548 
549 	/* if it is normal, just place it inqueue */
550 	if (upper == 0) {
551 		in_put(key);
552 		return;
553 	}
554 
555 	/* queue up an extended escape sequence */
556 	in_put(0);		/* escape indicator */
557 	in_put(upper);		/* event type */
558 	if (upper & (MOUS >> 8)) {
559 		in_put(x);	/* x position */
560 		in_put(y);	/* y position */
561 	}
562 	in_put(key);		/* event code */
563 	return;
564 }
565 
566 /*
567  * Create a subjob with a copy of the command intrepreter in it. When the
568  * command interpreter exits, mark the screen as garbage so that you do a full
569  * repaint. Bound to "^X C". The message at the start in VMS puts out a newline.
570  * Under some (unknown) condition, you don't get one free when DCL starts up.
571  */
spawncli(f,n)572 spawncli(f, n)
573 {
574         long newcli;
575 
576 	/* don't allow this command if restricted */
577 	if (restflag)
578 		return(resterr());
579 
580         mlwrite(TEXT1);
581 /*              "[Starting new CLI]" */
582         sgarbf = TRUE;
583         Execute("NEWCLI \"CON:0/0/640/200/MicroEMACS Subprocess\"", 0L, 0L);
584         return(TRUE);
585 }
586 
587 /*
588  * Run a one-liner in a subjob. When the command returns, wait for a single
589  * character to be typed, then mark the screen as garbage so a full repaint is
590  * done. Bound to "C-X !".
591  */
spawn(f,n)592 spawn(f, n)
593 {
594         register int    s;
595         char            line[NLINE];
596 
597         long newcli;
598 
599 	/* don't allow this command if restricted */
600 	if (restflag)
601 		return(resterr());
602 
603         if ((s=mlreply("!", line, NLINE)) != TRUE)
604                 return (s);
605         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
606         Execute(line, 0L, newcli);
607         Close(newcli);
608         tgetc();     /* Pause.               */
609         sgarbf = TRUE;
610         return(TRUE);
611 }
612 
613 /*
614  * Run an external program with arguments. When it returns, wait for a single
615  * character to be typed, then mark the screen as garbage so a full repaint is
616  * done. Bound to "C-X $".
617  */
618 
execprg(f,n)619 execprg(f, n)
620 
621 {
622         register int    s;
623         char            line[NLINE];
624 
625         long newcli;
626 
627 	/* don't allow this command if restricted */
628 	if (restflag)
629 		return(resterr());
630 
631         if ((s=mlreply("!", line, NLINE)) != TRUE)
632                 return (s);
633         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
634         Execute(line, 0L, newcli);
635         Close(newcli);
636         tgetc();     /* Pause.               */
637         sgarbf = TRUE;
638         return(TRUE);
639 }
640 
641 /*
642  * Pipe a one line command into a window
643  * Bound to ^X @
644  */
pipecmd(f,n)645 pipecmd(f, n)
646 {
647         register int    s;	/* return status from CLI */
648 	register EWINDOW *wp;	/* pointer to new window */
649 	register BUFFER *bp;	/* pointer to buffer to zot */
650         char	line[NLINE];	/* command line send to shell */
651 	static char bname[] = "command";
652 
653 	static char filnam[] = "ram:command";
654         long newcli;
655 
656 	/* don't allow this command if restricted */
657 	if (restflag)
658 		return(resterr());
659 
660 	/* get the command to pipe in */
661         if ((s=mlreply("@", line, NLINE)) != TRUE)
662                 return(s);
663 
664 	/* get rid of the command output buffer if it exists */
665         if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
666 		/* try to make sure we are off screen */
667 		wp = wheadp;
668 		while (wp != NULL) {
669 			if (wp->w_bufp == bp) {
670 				onlywind(FALSE, 1);
671 				break;
672 			}
673 			wp = wp->w_wndp;
674 		}
675 		if (zotbuf(bp) != TRUE)
676 
677 			return(FALSE);
678 	}
679 
680         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
681 	strcat(line, " >");
682 	strcat(line, filnam);
683         Execute(line, 0L, newcli);
684 	s = TRUE;
685         Close(newcli);
686         sgarbf = TRUE;
687 
688 	if (s != TRUE)
689 		return(s);
690 
691 	/* split the current window to make room for the command output */
692 	if (splitwind(FALSE, 1) == FALSE)
693 			return(FALSE);
694 
695 	/* and read the stuff in */
696 	if (getfile(filnam, FALSE) == FALSE)
697 		return(FALSE);
698 
699 	/* make this window in VIEW mode, update all mode lines */
700 	curwp->w_bufp->b_mode |= MDVIEW;
701 	wp = wheadp;
702 	while (wp != NULL) {
703 		wp->w_flag |= WFMODE;
704 		wp = wp->w_wndp;
705 	}
706 
707 	/* and get rid of the temporary file */
708 	unlink(filnam);
709 	return(TRUE);
710 }
711 
712 /*
713  * filter a buffer through an external DOS program
714  * Bound to ^X #
715  */
filter(f,n)716 filter(f, n)
717 
718 {
719         register int    s;	/* return status from CLI */
720 	register BUFFER *bp;	/* pointer to buffer to zot */
721         char line[NLINE];	/* command line send to shell */
722 	char tmpnam[NFILEN];	/* place to store real file name */
723 	static char bname1[] = "fltinp";
724 
725 	static char filnam1[] = "ram:fltinp";
726 	static char filnam2[] = "ram:fltout";
727         long newcli;
728 
729 	/* don't allow this command if restricted */
730 	if (restflag)
731 		return(resterr());
732 
733 	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
734 		return(rdonly());	/* we are in read only mode	*/
735 
736 	/* get the filter name and its args */
737         if ((s=mlreply("#", line, NLINE)) != TRUE)
738                 return(s);
739 
740 	/* setup the proper file names */
741 	bp = curbp;
742 	strcpy(tmpnam, bp->b_fname);	/* save the original name */
743 	strcpy(bp->b_fname, bname1);	/* set it to our new one */
744 
745 	/* write it out, checking for errors */
746 	if (writeout(filnam1, "w") != TRUE) {
747 		mlwrite(TEXT2);
748 /*                      "[Cannot write filter file]" */
749 		strcpy(bp->b_fname, tmpnam);
750 		return(FALSE);
751 	}
752 
753         newcli = Open("CON:0/0/640/200/MicroEMACS Subprocess", NEW);
754 	strcat(line, " <ram:fltinp >ram:fltout");
755         Execute(line,0L,newcli);
756 	s = TRUE;
757         Close(newcli);
758         sgarbf = TRUE;
759 
760 	/* on failure, escape gracefully */
761 	if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
762 		mlwrite(TEXT3);
763 /*                      "[Execution failed]" */
764 		strcpy(bp->b_fname, tmpnam);
765 		unlink(filnam1);
766 		unlink(filnam2);
767 		return(s);
768 	}
769 
770 	/* reset file name */
771 	strcpy(bp->b_fname, tmpnam);	/* restore name */
772 	bp->b_flag |= BFCHG;		/* flag it as changed */
773 
774 	/* and get rid of the temporary file */
775 	unlink(filnam1);
776 	unlink(filnam2);
777 	return(TRUE);
778 }
779 
780 /* return a system dependant string with the current time */
781 
timeset()782 char *PASCAL NEAR timeset()
783 
784 {
785 	return(errorm);
786 }
787 
788 #if	AZTEC
789 /*	FILE Directory routines		*/
790 
791 char path[NFILEN];	/* path of file to find */
792 char rbuf[NFILEN];	/* return file buffer */
793 extern char *scdir();
794 
795 /*	do a wild card directory search (for file name completion) */
796 
getffile(fspec)797 char *PASCAL NEAR getffile(fspec)
798 
799 char *fspec;	/* pattern to match */
800 
801 {
802 	register int index;		/* index into various strings */
803 	char fname[NFILEN];		/* file/path for DOS call */
804 
805 	/* first parse the file path off the file spec */
806 	strcpy(path, fspec);
807 	index = strlen(path) - 1;
808 	while (index >= 0 && (path[index] != '/' &&
809 				path[index] != '\\' && path[index] != ':'))
810 		--index;
811 	path[index+1] = 0;
812 
813 	/* construct the composite wild card spec */
814 	strcpy(fname, path);
815 	strcat(fname, &fspec[index+1]);
816 	strcat(fname, "*.*");
817 
818 	/* save the path/wildcard off */
819 	strcpy(path, fname);
820 
821 	/* and call for the first file */
822 	return(getnfile());
823 }
824 
getnfile()825 char *PASCAL NEAR getnfile()
826 
827 {
828 	register char *sp;	/* return from scdir */
829 
830 	/* and call for the next file */
831 	sp = scdir(path);
832 	if (sp == NULL)
833 		return(NULL);
834 
835 	/* return the next file name! */
836 	strcpy(rbuf, sp);
837 	return(rbuf);
838 }
839 #else
getffile(fspec)840 char *PASCAL NEAR getffile(fspec)
841 
842 char *fspec;	/* file to match */
843 
844 {
845 	return(NULL);
846 }
847 
getnfile()848 char *PASCAL NEAR getnfile()
849 
850 {
851 	return(NULL);
852 }
853 #endif
854 
855 #if	AZTEC
856 
857 /*	Big flame..... AZTEC C documents, but seems to be missing the
858 	standard library realloc() function.  A quick replacement is
859 	below.  Note that this ALWAYS copies to a new block, and is
860 	thus inherently less efficient than a native one would be.
861 */
862 
realloc(ptr,size)863 char *realloc(ptr, size)
864 
865 char *ptr;	/* original pointer */
866 int size;	/* # of bytes for newly allocated block */
867 
868 {
869 	char *src, *dest;	/* ptrs for byte copying */
870 	char *nptr;		/* newly allocated pointer */
871 
872 	/* allocate the new memory block */
873 	nptr = malloc(size);
874 	if (nptr == NULL)
875 		return(NULL);
876 
877 	/* copy the bytes from the old one */
878 	src = ptr;
879 	dest = nptr;
880 	while (size--)
881 		*dest++ = *src++;
882 
883 	/* and free the old one */
884 	free(ptr);
885 	return(nptr);
886 }
887 
888 #else
adoshello()889 adoshello()
890 {
891 }
892 #endif
893