/* * Amiga system-dependent routines. */ #include #include #include #include #include #include #include #include "stevie.h" /* Globals initialized by get_ConUnit() */ struct Window *conWindow; struct ConUnit *conUnit; extern int errno; /* The error variable */ long raw_in = 0; long raw_out = 0; #define BSIZE 2048 static char outbuf[BSIZE]; static int bpos = 0; void flushbuf() { if (bpos != 0) Write(raw_out, outbuf, bpos); bpos = 0; } void outchar(c) char c; { outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf(); } void outstr(s) char *s; { while (*s) { outbuf[bpos++] = *s++; if (bpos >= BSIZE) flushbuf(); } } int GetCharacter() { char c; Read(raw_in, &c, sizeof(c)); return ((int) c); } /* * getCSIsequence - get a CSI sequence * - either cursor keys, help, or function keys */ int getCSIsequence() { int c; int tmp; c = GetCharacter(); if (isdigit(c)) { tmp = 0; while (isdigit(c)) { tmp = tmp * 10 + c - '0'; c = GetCharacter(); } if (c == '~') /* function key */ return ((char) (K_F1 + tmp)); } switch (c) { case 'A': /* cursor up */ return K_UARROW; case 'B': /* cursor down */ return K_DARROW; case 'C': /* cursor right */ return K_RARROW; case 'D': /* cursor left */ return K_LARROW; case 'T': /* shift cursor up */ return K_SUARROW; case 'S': /* shift cursor down */ return K_SDARROW; case ' ': /* shift cursor left or right */ c = GetCharacter(); if (c == 'A') /* shift cursor left */ return K_SLARROW; if (c == '@') /* shift cursor right */ return K_SRARROW; break; case '?': /* help */ c = GetCharacter(); if (c == '~') return K_HELP; break; } while ((c != '|') && (c != '~')) { if (WaitForChar(raw_in, 500L) == 0) break; c = GetCharacter(); } /* must have been screen resize event */ s_clear(); flushbuf(); if (get_ConUnit(raw_in) != 0) { /* hopefully never exit .... */ emsg("STEVIE: can't get ConUnit info ?!?!?!?\n"); sleep(5); return 0; } Rows = conUnit->cu_YMax + 1; Columns = conUnit->cu_XMax + 1; if (Columns < 5) Columns = 5; if (Columns > MAX_COLUMNS) Columns = MAX_COLUMNS; if (Rows < 2) Rows = 2; P(P_LI) = Rows; screenalloc(); tmp = RedrawingDisabled; RedrawingDisabled = TRUE; S_NOT_VALID; cursupdate(UPDATE_ALL); /* make sure not below Botchar */ RedrawingDisabled = FALSE; s_refresh(NOT_VALID); /* draw it */ RedrawingDisabled = tmp; windgoto(Cursrow, Curscol); flushbuf(); return 0; } /* * inchar() - get a character from the keyboard */ int inchar() { int c; flushbuf(); for (;;) { c = GetCharacter(); if (c == 0x9b) c = getCSIsequence(); if (c != 0) break; } return c; } void beep() { if (RedrawingDisabled) return; outbuf[bpos++] = '\007'; if (bpos >= BSIZE) flushbuf(); } void sleep(n) int n; { void Delay(); if (n > 0) Delay(50L * n); } void delay() { void Delay(); Delay(25L); } void windinit() { raw_in = Input(); if (!IsInteractive(raw_in)) { raw_in = Open("RAW:0/0/480/200/STEVIE", MODE_NEWFILE); if (raw_in == NULL) { fprintf(stderr, "STEVIE: Can't open window ?!?!?!?\n"); exit(2); } raw_out = raw_in; } else { raw_out = Output(); if (raw(raw_in) != 0) { perror("STEVIE: Can't change to raw mode ?!?!?!?"); exit(2); } } if (get_ConUnit(raw_in) != 0) { fprintf(stderr, "STEVIE: can't get ConUnit info ?!?!?!?\n"); windexit(3); } /* get window size */ P(P_LI) = Rows = conUnit->cu_YMax + 1; Columns = conUnit->cu_XMax + 1; outstr("\033[12{"); /* window resize events activated */ flushbuf(); } void windexit(r) int r; { outstr("\033[12}"); /* window resize events de-activated */ flushbuf(); if (raw_in != raw_out) { if (cooked(raw_in) != 0) perror("STEVIE: Can't change to cooked mode ?!?!?!?"); } else { Close(raw_in); } exit(r); } void windgoto(r, c) int c; int r; { r++; c++; outstr("\033["); if (r >= 10) outchar((char) (r / 10 + '0')); outchar((char) (r % 10 + '0')); outchar(';'); if (c >= 10) outchar((char) (c / 10 + '0')); outchar((char) (c % 10 + '0')); outchar('H'); } FILE * fopenb(fname, mode) char *fname; char *mode; { FILE *fopen(); char modestr[16]; sprintf(modestr, "%sb", mode); return fopen(fname, modestr); } /* * raw() & cooked() * * These are routines for setting a given stream to raw or cooked mode on the * Amiga. This is useful when you are using Lattice C to produce programs * that want to read single characters with the "getch()" or "fgetc" call. * * Written : 18-Jun-87 By Chuck McManis. */ /* * Function raw() - Convert the specified File Handle to 'raw' mode. This * only works on TTY's and essentially keeps DOS from translating keys for * you. */ long raw(afh) struct FileHandle *afh; { struct MsgPort *mp; /* The File Handle message port */ long Arg[1], res; mp = ((struct FileHandle *) (BADDR(afh)))->fh_Type; Arg[0] = -1L; res = SendPacket(mp, ACTION_SCREEN_MODE, Arg, 1); if (res == 0) { errno = ENXIO; return (-1); } return (0); } /* * Function - cooked() this function returns the designate file pointer to * it's normal, wait for a mode. This is exactly like raw() except that * it sends a 0 to the console to make it back into a CON: from a RAW: */ long cooked(afh) struct FileHandle *afh; { struct MsgPort *mp; /* The File Handle message port */ long Arg[1], res; mp = ((struct FileHandle *) (BADDR(afh)))->fh_Type; Arg[0] = 0L; res = SendPacket(mp, ACTION_SCREEN_MODE, Arg, 1); if (res == 0) { errno = ENXIO; return (-1); } return (0); } /* * Code for this routine came from the following : * * ConPackets.c - C. Scheppner, A. Finkel, P. Lindsay CBM * DOS packet example * Requires 1.2 * * which I found on Fish Disk 56. */ /* initializes conWindow and conUnit (global vars) */ long get_ConUnit(afh) struct FileHandle *afh; { struct MsgPort *mp; /* The File Handle message port */ struct InfoData *id; long Arg[8], res; if (!IsInteractive((BPTR) afh)) { errno = ENOTTY; return (-1); } mp = ((struct FileHandle *) (BADDR(afh)))->fh_Type; /* Alloc to insure longword alignment */ id = (struct InfoData *) AllocMem(sizeof(struct InfoData), MEMF_PUBLIC | MEMF_CLEAR); if (!id) { errno = ENOMEM; return (-1); } Arg[0] = ((ULONG) id) >> 2; res = SendPacket(mp, ACTION_DISK_INFO, Arg, 1); conWindow = (struct Window *) id->id_VolumeNode; conUnit = (struct ConUnit *) ((struct IOStdReq *) id->id_InUse)->io_Unit; FreeMem(id, sizeof(struct InfoData)); if (res == 0) { errno = ENXIO; return (-1); } return (0); } /* * SendPacket() - written by Phil Lindsay, Carolyn Scheppner, and Andy * Finkel. This function will send a packet of the given type to the Message * Port supplied. */ long SendPacket(pid, action, args, nargs) struct MsgPort *pid; /* process indentifier ... (handlers message * port ) */ long action, /* packet type ... (what you want handler to * do ) */ args[], /* a pointer to a argument list */ nargs; /* number of arguments in list */ { struct MsgPort *replyport; struct StandardPacket *packet; long count, *pargs, res1; replyport = (struct MsgPort *) CreatePort(NULL, 0); if (!replyport) return (0); /* Allocate space for a packet, make it public and clear it */ packet = (struct StandardPacket *) AllocMem((long) sizeof(struct StandardPacket), MEMF_PUBLIC | MEMF_CLEAR); if (!packet) { DeletePort(replyport); return (0); } packet->sp_Msg.mn_Node.ln_Name = (char *) &(packet->sp_Pkt); packet->sp_Pkt.dp_Link = &(packet->sp_Msg); packet->sp_Pkt.dp_Port = replyport; packet->sp_Pkt.dp_Type = action; /* copy the args into the packet */ pargs = &(packet->sp_Pkt.dp_Arg1); /* address of first argument */ for (count = 0; count < nargs; count++) pargs[count] = args[count]; PutMsg(pid, packet); /* send packet */ WaitPort(replyport); GetMsg(replyport); res1 = packet->sp_Pkt.dp_Res1; FreeMem(packet, (long) sizeof(struct StandardPacket)); DeletePort(replyport); return (res1); }