1 /* -*-C-*-
2  *
3  * Module : amiga.c
4  *
5  * Author : Simon J Raybould.    (sie@fulcrum.bt.co.uk).
6  *
7  * Date   : Tuesday 11th June 1991.
8  *
9  * Desc   : amiga specifics for beav binary editor.
10  *
11  *
12  * This file is public domain and you can do what you want with it, even roll
13  * it up into a ball and toss it for your cat to chase. I accept no
14  * resposibility for it being unfit for any purpose (including a feline toy).
15  * Any bugs you can either fix them yourself or tell me and I'll do it.
16  * Any major fixes should be reported to me and I will inform the main keeper
17  * of beav to be sure they are fixed in the next release. This only applies to
18  * bugs in THIS FILE or in AMIGA sections of other files. Any other bugs to the
19  * original author.
20  *
21  * SJR - 25.Aug.91
22  *
23  *
24  */
25 
26 #ifdef AMIGA
27 
28 #include <stdio.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <signal.h>
32 #include <libraries/dosextens.h>
33 #include <exec/memory.h>
34 #include <intuition/intuition.h>
35 
36 #include "def.h"
37 
38 #define SCRBUFSIZ        1024	/* buffered screen io */
39 
40 struct NewWindow nw =
41 {
42     0, 0, 640, 256, -1, -1, NULL,
43     WINDOWDEPTH | WINDOWDRAG | SMART_REFRESH | ACTIVATE | BORDERLESS,
44     NULL, NULL,
45     "BEAV Amiga Port by S.J.Raybould (sie@fulcrum.bt.co.uk)  Sep 1991",
46     NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN
47 };
48 
49 /* Opens/allocations we'll need to clean up */
50 struct Library *IntuitionBase = NULL;
51 struct Window *win = NULL, *OpenWindow ();
52 struct IOStdReq *writeReq = NULL;	/* I/O request block pointer */
53 struct MsgPort *writePort = NULL;	/* replyport for writes      */
54 
55 struct IOStdReq *readReq = NULL;/* I/O request block pointer */
56 struct MsgPort *readPort = NULL;/* replyport for reads       */
57 
58 struct MsgPort *CreatePort ();
59 BOOL OpenedConsole = FALSE;
60 UBYTE ibuf;
61 BYTE OpenConsole ();
62 void CloseConsole (), QueueRead (), ConWrite ();
63 
64 
65 int nrow;			/* Terminal size, rows.         */
66 int ncol;			/* Terminal size, columns.      */
67 #ifdef CRAP
68 int tceeol = 3;			/* Costs.                       */
69 #endif /* CRAP */
70 
71 int kbdpoll;			/* in O_NDELAY mode         */
72 int kbdqp;			/* there is a char in kbdq  */
73 
74 char scrbuf[SCRBUFSIZ];		/* buffered screen io */
75 short scrbufpos = 0;		/* current write position */
76 
77 /* CODE TO REPLACE STUFF IN termio.c */
78 
79 /*
80  * This function gets called just before we go back home to the command
81  * interpreter. On VMS it puts the terminal back in a reasonable state.
82  * Another no-operation on CPM.
83  */
84 void
ttclose()85 ttclose ()
86 {
87     /* Put TTY back in sesible state */
88     if (!(CheckIO (readReq)))
89 	AbortIO (readReq);
90     WaitIO (readReq);
91     if (OpenedConsole)
92 	CloseConsole (writeReq);
93     if (readReq)
94 	DeleteExtIO (readReq);
95     if (readPort)
96 	DeletePort (readPort);
97     if (writeReq)
98 	DeleteExtIO (writeReq);
99     if (writePort)
100 	DeletePort (writePort);
101     if (win)
102 	CloseWindow (win);
103     if (IntuitionBase)
104 	CloseLibrary (IntuitionBase);
105 }
106 
107 /*
108  * Flush terminal buffer. Does real work where the terminal output is buffered
109  * up. A no-operation on systems where byte at a time terminal I/O is done.
110  */
111 void
ttflush()112 ttflush ()
113 {
114     if (scrbufpos > 0)
115     {
116 	ConWrite (writeReq, scrbuf, scrbufpos);
117 	scrbufpos = 0;
118     }
119 }
120 
121 /*
122  * Write a character to the display. On VMS, terminal output is buffered, and
123  * we just put the characters in the big array, after checking for overflow.
124  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
125  * MS-DOS (use the very very raw console output routine).
126  */
127 void
ttputc(c)128 ttputc (c)
129 {
130     if (scrbufpos < SCRBUFSIZ)
131 	scrbuf[scrbufpos++] = c;
132     else
133     {
134 	ConWrite (writeReq, scrbuf, scrbufpos);
135 	scrbufpos = 0;
136 	scrbuf[scrbufpos++] = c;
137     }
138 }
139 
140 void
ttputs(char * str)141 ttputs (char *str)
142 {
143     while (*str)
144 	ttputc (*str++);
145 }
146 
147 /*
148  * Read a character from the terminal, performing no editing and doing no echo
149  * at all. More complex in VMS that almost anyplace else, which figures. Very
150  * simple on CPM, because the system can do exactly what you want.
151  */
ttgetc()152 ttgetc ()
153 {
154     char c, ConGetChar ();
155     static char Buffer[8], ri = 0, wi = 0;
156 
157     if (kbdqp)
158 	kbdqp = FALSE;
159     /* If we stil have chars from last time, return them */
160     if (ri < wi)
161 	return Buffer[ri++] & 0x7f;
162 
163     /* Else empty the buffer and start a new read */
164     ri = wi = 0;
165     c = ConGetChar (readPort, &ibuf);
166     /*
167   * Attempt some translations !
168   * This is the place to extend, if you wish to add some more.
169   * SEE RKM L&D 1.3 pg 654 for more info.
170   */
171     if ((unsigned char) c == (unsigned char) 0x9b)
172     {				/* ANSI esc start */
173 	c = ConGetChar (readPort, &ibuf);
174 	switch (c)
175 	{
176 	case 'A':		/* UP */
177 	    Buffer[wi++] = 0x10;/* ^P */
178 	    break;
179 	case 'B':		/* DOWN */
180 	    Buffer[wi++] = 0x0e;/* ^N */
181 	    break;
182 	case 'C':		/* RIGHT */
183 	    Buffer[wi++] = 0x06;/* ^F */
184 	    break;
185 	case 'D':		/* LEFT */
186 	    Buffer[wi++] = 0x02;/* ^B */
187 	    break;
188 	case '0':		/* F1 */
189 	    ConGetChar (readPort, &ibuf);	/* discard tilde */
190 	    Buffer[wi++] = 0x1b;/* HELP = "ESC ?" */
191 	    Buffer[wi++] = '?';
192 	    break;
193 	case '1':		/* F2 or SHIFTED function key */
194 	    c = ConGetChar (readPort, &ibuf);	/* Get next char to see if it's a tilde */
195 	    switch (c)
196 	    {
197 	    case '~':		/* was definately F2 */
198 		Buffer[wi++] = 0x1b;	/* mark-set = "ESC ." */
199 		Buffer[wi++] = '.';
200 		break;
201 	    case '0':		/* SHIFTED F1 */
202 		ConGetChar (readPort, &ibuf);	/* Discard the tilde */
203 		Buffer[wi++] = 0x18;	/* binding-for-key = "Ctl-X ?" */
204 		Buffer[wi++] = '?';
205 		break;
206 	    case '1':		/* SHIFTED F2 */
207 		ConGetChar (readPort, &ibuf);	/* Discard the tilde */
208 		Buffer[wi++] = 0x18;	/* file-read = "Ctl-X Ctl-R" */
209 		Buffer[wi++] = 0x12;
210 		break;
211 	    case '2':		/* SHIFTED F3 */
212 		ConGetChar (readPort, &ibuf);	/* Discard the tilde */
213 		Buffer[wi++] = 0x18;	/* file-save = "Ctl-X Ctl-S" */
214 		Buffer[wi++] = 0x13;
215 		break;
216 	    case '3':		/* SHIFTED F4 */
217 		ConGetChar (readPort, &ibuf);	/* Discard the tilde */
218 		Buffer[wi++] = 0x18;	/* file-visit = "Ctl-X Ctl-V" */
219 		Buffer[wi++] = 0x16;
220 		break;
221 	    case '4':		/* SHIFTED F5 */
222 		ConGetChar (readPort, &ibuf);	/* Discard the tilde */
223 		Buffer[wi++] = 0x18;	/* file-write = "Ctl-X Ctl-W" */
224 		Buffer[wi++] = 0x17;
225 		break;
226 	    case '5':		/* SHIFTED F6 */
227 		ConGetChar (readPort, &ibuf);	/* Discard the tilde */
228 		Buffer[wi++] = 0x18;	/* save-all-buffers = "Ctl-X return" */
229 		Buffer[wi++] = '\r';
230 		break;
231 	    case '6':		/* SHIFTED F7 */
232 		ConGetChar (readPort, &ibuf);	/* Discard the tilde */
233 		Buffer[wi++] = 0x18;	/* buffer-set-file-name = "Ctl-X Ctl-F" */
234 		Buffer[wi++] = 0x06;
235 		break;
236 	    case '7':		/* SHIFTED F8 */
237 		ConGetChar (readPort, &ibuf);	/* Discard the tilde */
238 		Buffer[wi++] = 0x18;	/* insert-file = "Ctl-X TAB" */
239 		Buffer[wi++] = '\t';
240 		break;
241 	    case '8':		/* SHIFTED F9 */
242 		ConGetChar (readPort, &ibuf);	/* Discard the tilde */
243 		Buffer[wi++] = 0x18;	/* quit-save-all = "Ctl-X Ctl-E" */
244 		Buffer[wi++] = 0x05;
245 		break;
246 	    case '9':		/* SHIFTED F10 */
247 		ConGetChar (readPort, &ibuf);	/* Discard the tilde */
248 		Buffer[wi++] = 0x03;	/* quit-no-save = "Ctl-C" */
249 		break;
250 	    }
251 	    break;
252 	case '2':		/* F3 */
253 	    ConGetChar (readPort, &ibuf);	/* Discard the tilde */
254 	    Buffer[wi++] = 0x1b;/* search-forv = "ESC s" */
255 	    Buffer[wi++] = 's';
256 	    break;
257 	case '3':		/* F4 */
258 	    ConGetChar (readPort, &ibuf);	/* Discard the tilde */
259 	    Buffer[wi++] = 0x1b;/* search-again = "ESC t" */
260 	    Buffer[wi++] = 't';
261 	    break;
262 	case '4':		/* F5 */
263 	    ConGetChar (readPort, &ibuf);	/* Discard the tilde */
264 	    Buffer[wi++] = 0x1b;/* replace = "ESC %" */
265 	    Buffer[wi++] = '%';
266 	    break;
267 	case '5':		/* F6 */
268 	    ConGetChar (readPort, &ibuf);	/* Discard the tilde */
269 	    Buffer[wi++] = 0x19;/* yank = "Ctl-Y" */
270 	    break;
271 	case '6':		/* F7 */
272 	    ConGetChar (readPort, &ibuf);	/* Discard the tilde */
273 	    Buffer[wi++] = 0x1b;/* copy-mark-to-cursor = "ESC w" */
274 	    Buffer[wi++] = 'w';
275 	    break;
276 	case '7':		/* F8 */
277 	    ConGetChar (readPort, &ibuf);	/* Discard the tilde */
278 	    Buffer[wi++] = 0x17;/* delete-mark-to-cursor = "Ctl-W" */
279 	    break;
280 	case '8':		/* F9 */
281 	    ConGetChar (readPort, &ibuf);	/* Discard the tilde */
282 	    Buffer[wi++] = 0x18;/* move-to-byte = "Ctl-X G" */
283 	    Buffer[wi++] = 'G';
284 	    break;
285 	case '9':		/* F10 */
286 	    ConGetChar (readPort, &ibuf);	/* Discard the tilde */
287 	    Buffer[wi++] = 0x07;/* abort-cmd = "Ctl-G" */
288 	    break;
289 	case '?':		/* HELP */
290 	    ConGetChar (readPort, &ibuf);	/* Discard the tilde */
291 	    Buffer[wi++] = 0x1b;/* help = "ESC ?" */
292 	    Buffer[wi++] = '?';
293 	    break;
294 	}
295 	return Buffer[ri++] & 0x7f;
296     }
297     else			/* not an ANSI sequence */
298 	return c & 0x7f;
299 }
300 
301 /*
302  * This function is called once to set up the terminal device streams.
303  * On VMS, it translates TT until it finds the terminal, then assigns
304  * a channel to it and sets it raw. On CPM it is a no-op.
305  */
306 
307 void
ttopen()308 ttopen ()
309 {
310     int Sig;
311     ULONG conreadsig, windowsig;
312     BYTE error;
313     struct Screen Screen;	/* get a copy of WBENCHSCREEN in here */
314 
315 
316     if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 0)))
317     {
318 	printf ("Can't open intuition\n");
319 	ttclose ();
320 	exit (10);
321     }
322     /* Create reply port and io block for writing to console */
323     if (!(writePort = CreatePort ("LARN.console.write", 0)))
324     {
325 	printf ("Can't create write port\n");
326 	ttclose ();
327 	exit (10);
328     }
329     if (!(writeReq = (struct IOStdReq *)
330 	  CreateExtIO (writePort, (LONG) sizeof (struct IOStdReq))))
331     {
332 	printf ("Can't create write request\n");
333 	ttclose ();
334 	exit (10);
335     }
336     /* Create reply port and io block for reading from console */
337     if (!(readPort = CreatePort ("LARN.console.read", 0)))
338     {
339 	printf ("Can't create read port\n");
340 	ttclose ();
341 	exit (10);
342     }
343     if (!(readReq = (struct IOStdReq *)
344 	  CreateExtIO (readPort, (LONG) sizeof (struct IOStdReq))))
345     {
346 	printf ("Can't create read request\n");
347 	ttclose ();
348 	exit (10);
349     }
350     if (!GetScreenData (&Screen, sizeof (struct Screen), WBENCHSCREEN, NULL))
351     {
352 	printf ("Can't get screen size\n");
353 	ttclose ();
354 	exit (10);
355     }
356     nrow = Screen.Height / 8 - 3;
357     ncol = Screen.Width / 8;
358     nw.Height = Screen.Height;
359     nw.Width = Screen.Width;
360 
361     /* don't allow a larger number of rows than we can handle */
362     if (nrow > NROW)
363 	nrow = NROW;
364     /* don't allow a larger number of cols than we can handle */
365     if (ncol > NCOL)
366 	ncol = NCOL;
367 
368     /* Open a window */
369     if (!(win = OpenWindow (&nw)))
370     {
371 	printf ("Can't open window\n");
372 	ttclose ();
373 	exit (10);
374     }
375     /* Now, attach a console to the window */
376     if (error = OpenConsole (writeReq, readReq, win))
377     {
378 	printf ("Can't open console.device\n");
379 	ttclose ();
380 	exit (10);
381     }
382     else
383 	OpenedConsole = TRUE;
384 
385     QueueRead (readReq, &ibuf);	/* send the first console read request */
386     conreadsig = 1 << readPort->mp_SigBit;
387     windowsig = 1 << win->UserPort->mp_SigBit;
388     for (Sig = 0; Sig < NSIG; Sig++)
389 	signal (Sig, SIG_IGN);
390 
391     kbdpoll = FALSE;
392     /* on all screens we are not sure of the initial position of the cursor */
393     ttrow = 999;
394     ttcol = 999;
395 }
396 
397 /* END OF TERMIO REPLACEMENT CODE */
398 
399 /* Attach console device to an open Intuition window.
400  * This function returns a value of 0 if the console
401  * device opened correctly and a nonzero value (the error
402  * returned from OpenDevice) if there was an error.
403  */
404 BYTE
OpenConsole(writereq,readreq,window)405 OpenConsole (writereq, readreq, window)
406     struct IOStdReq *writereq;
407     struct IOStdReq *readreq;
408     struct Window *window;
409 {
410     BYTE error;
411 
412     writereq->io_Data = (APTR) window;
413     writereq->io_Length = sizeof (struct Window);
414     error = OpenDevice ("console.device", 0, writereq, 0);
415     readreq->io_Device = writereq->io_Device;	/* clone required parts */
416     readreq->io_Unit = writereq->io_Unit;
417     return (error);
418 }
419 
420 void
CloseConsole(struct IOStdReq * writereq)421 CloseConsole (struct IOStdReq *writereq)
422 {
423     CloseDevice (writereq);
424 }
425 
426 /* Output a single character to a specified console
427  */
428 void
ConPutChar(struct IOStdReq * writereq,UBYTE character)429 ConPutChar (struct IOStdReq *writereq, UBYTE character)
430 {
431     writereq->io_Command = CMD_WRITE;
432     writereq->io_Data = (APTR) & character;
433     writereq->io_Length = 1;
434     DoIO (writereq);
435     /* command works because DoIO blocks until command is done
436   * (otherwise ptr to the character could become invalid)
437   */
438 }
439 
440 /* Output a stream of known length to a console
441  */
442 void
ConWrite(struct IOStdReq * writereq,UBYTE * string,LONG length)443 ConWrite (struct IOStdReq *writereq, UBYTE * string, LONG length)
444 {
445     writereq->io_Command = CMD_WRITE;
446     writereq->io_Data = (APTR) string;
447     writereq->io_Length = length;
448     DoIO (writereq);
449     /* command works because DoIO blocks until command is done
450   * (otherwise ptr to string could become invalid in the meantime)
451   */
452 }
453 
454 /* Output a NULL-terminated string of characters to a console
455  */
456 void
ConPuts(struct IOStdReq * writereq,UBYTE * string)457 ConPuts (struct IOStdReq *writereq, UBYTE * string)
458 {
459     writereq->io_Command = CMD_WRITE;
460     writereq->io_Data = (APTR) string;
461     writereq->io_Length = -1;	/* means print till terminating null */
462     DoIO (writereq);
463 }
464 
465 /* Queue up a read request to console, passing it pointer
466  * to a buffer into which it can read the character
467  */
468 void
QueueRead(struct IOStdReq * readreq,UBYTE * whereto)469 QueueRead (struct IOStdReq *readreq, UBYTE * whereto)
470 {
471     readreq->io_Command = CMD_READ;
472     readreq->io_Data = (APTR) whereto;
473     readreq->io_Length = 1;
474     SendIO (readreq);
475 }
476 
477 struct IOStdReq *readreq;	/* ttkeyready() needs to be able to see this */
478 
479 /* Wait for a character
480  */
481 char
ConGetChar(struct MsgPort * msgport,UBYTE * whereto)482 ConGetChar (struct MsgPort *msgport, UBYTE * whereto)
483 {
484     register temp;
485 
486     WaitPort (msgport);
487     readreq = (struct IOStdReq *) GetMsg (msgport);
488     temp = *whereto;		/* get the character */
489     QueueRead (readreq, whereto);	/* then re-use the request block*/
490     return ((char) temp);
491 }
492 
493 /* typahead():    Check to see if any characters are already in the
494         keyboard buffer
495    On the amiga, we do this by checking if the outstanding read request
496    has been satisfied yet by calling CheckIO().
497 */
ttkeyready()498 ttkeyready ()
499 {
500     if (!kbdqp)
501 	kbdqp = CheckIO (readreq) ? 1 : 0;
502     return kbdqp;
503 }
504 
505 /* UNIX support stuff */
506 
507 #define BLOCKSIZE  4096
508 
link(char * SPath,char * DPath)509 link (char *SPath, char *DPath)
510 {
511     int sfd, dfd, Bytes;
512     char BlkBuf[BLOCKSIZE];
513 
514     if ((sfd = open (SPath, O_RDONLY)) == -1)
515 	return -1;
516     if ((dfd = open (DPath, O_WRONLY | O_CREAT | O_TRUNC)) == -1)
517 	return -1;
518     while ((Bytes = read (sfd, BlkBuf, BLOCKSIZE)) > 0)
519 	write (dfd, BlkBuf, Bytes);
520     close (sfd);
521     close (dfd);
522     return 0;
523 }
524 
525 #endif /* AMIGA */
526