/* * Commodore 64 Spoof Emulator (C) Eddy Carroll, 1st April 1988 * * Module: MAIN.C * * This module is the mainline - it handles the input loop and command * interpretation logic. * */ #include #include #include #include #include #include #include "screen.h" #include "commands.h" #define DEL '\177' /* * Defining the following functions here stops them from being pulled into * the program from the Lattice library when we link. */ int chkabort() {return(0);} void MemCleanup() {} /* * Global references */ extern struct Menu mymenus; extern struct IntuiText mytext[]; extern struct commandlist command[]; /* Commands & Responses */ extern char *errormsg[]; /* List of error msgs */ extern int MAXCOMMANDS; /* Number of commands */ extern int MAXERRORS; /* Number of messages */ extern char *STARTUP; /* Startup message */ extern char *ABOUT; /* "About..." message */ extern char *READY; /* Ready prompt */ /* * Executes one of the menu commands * */ void domenu(opt) int opt; { CURSOROFF; switch (opt) { case M_ABOUT: clearscreen(); if (titlebar) printchar('\r'); /* Skip past title bar if on */ printmess(ABOUT); printmess(READY); break; case M_TITLE: titlebar = !titlebar; ClearMenuStrip(mywin); mytext[1].IText = titlebar ? " Hide Title" : " Show Title"; SetMenuStrip(mywin,&mymenus); ShowTitle(myscreen, titlebar); break; case M_QUIT: cleanup(0); break; } } /* * Returns a random number in range 0..range-1. * */ int random(range) int range; { LONG seconds,micros; CurrentTime(&seconds,µs); return (micros % range); } /* * Reads current line from screen into string, stripping off any extra * leading or trailing spaces. * */ void getcommand(s) char *s; { int i = 0, j = 39; char *p; p = screen[cursory]; while (p[i] == ' ' && i < 40) i++; if (i == 40) { *s = '\0'; return; } while (p[j] == ' ') j--; while (i <= j) { *s++ = toupper(p[i]); i++; } *s = '\0'; } /* * Returns TRUE if the first n chars of the two strings are equal, else * returns FALSE * */ int match(s1,s2,n) char *s1,*s2; int n; { while (*s1++ == *s2++ && n) n--; return (!n); } /* * Initialises error messages to be in random order. * */ void initerror() { int i, x, y; char *p; for (i = 0; i < MAXERRORS; i++) { x = random(MAXERRORS); y = MAXERRORS - 1 - random(MAXERRORS); p = errormsg[x]; errormsg[x] = errormsg[y]; errormsg[y] = p; } } /* * Prints a suitable response for command in string s. If a match is found * in the command list, then a reponse appropriate to that command is * printed, else one of the standard error messages is printed. * */ void docommand(s) char *s; { static int curerr = 0; int i = 1, k = -1, x, y; char *p; struct commandlist *com; if (*s >= '0' && *s <= '9') k = 0; else { while (i < MAXCOMMANDS && k < 0) { if (match(command[i].asc,s,command[i].len)) k = i; i++; } } printchar('\r'); if (k >= 0) { com = &command[k]; do { com->num++; /* If we have printed all three messages once each, re-arrange */ /* the order of them before we print them again to make it */ /* seem random. */ if (com->num >= MAXRESPONSE) { com->num = 0; x = random(MAXRESPONSE); y = random(MAXRESPONSE); p = com->response[x]; com->response[x] = com->response[y]; com->response[y] = p; } } while ((p = com->response[com->num]) == NULL); printmess(p); } else { printmess(errormsg[curerr]); curerr++; if (curerr >= MAXERRORS) { curerr = 0; initerror(); } } printmess(READY); } /* * Initialises the message headers to point to random messages * */ void initmess() { int i; for (i = 0; i < MAXCOMMANDS; i++) command[i].num = random(3); } /* * Returns code for function key n, where n = 0..20 * Returns 0 if no char equivalent. Also binds otherwise undefined * function keys to common commands recognised. */ char fkey(n) int n; { register char ch = 0; switch (n) { case 9: ch = C_HOME; break; case 19: ch = C_CLEAR; break; case 20: printmess("HELP"); break; default: if (n >= 0 & n <= 19) printmess(command[n].asc); /* Get command & print it */ break; } return (ch); } /* * Converts code (an escape character) into one of the internal codes * (or 0 if no corresponding code) * */ char convert(ch) char ch; { switch (ch) { case 'A': ch = C_UP; break; case 'B': ch = C_DOWN; break; case 'C': ch = C_RIGHT; break; case 'D': ch = C_LEFT; break; default: ch = 0; } return(ch); } /* * Mainline * */ void _main() { LONG MenuNumber; struct MenuItem *item; register struct IntuiMessage *message; register struct Message *conmessage; int escape = 0; LONG class; USHORT code; int time = 3, curstate = 0, fkeynum; char s[50], ch; titlebar = 0; /* Initially hidden */ initscreen(); initmess(); initerror(); printmess(STARTUP); printmess(READY); CURSORON; /* Main loop */ #define INTUIBITS (1 << mywin->UserPort->mp_SigBit) #define CONSOLEBITS (1 << ConReadPort->mp_SigBit) while (1) { /* Reset message pointers, just in case 2nd part of conditional */ /* && isn't executed. */ message = NULL; conmessage = NULL; while ((message = (struct IntuiMessage *) GetMsg(mywin->UserPort)) == NULL && (conmessage = (struct Message *) GetMsg(ConReadPort)) == NULL) Wait ( INTUIBITS | CONSOLEBITS); if (message) { /* Got an IntuiMessage */ class = message->Class; code = message->Code; ReplyMsg((struct Message *)message); switch (class) { case MENUPICK: MenuNumber = code; while (MenuNumber != MENUNULL) { item = (struct MenuItem *)ItemAddress(&mymenus,MenuNumber); code = item->Command; MenuNumber = item->NextSelect; } domenu(code); break; case INTUITICKS: if (time == 0) { curstate = 1 - curstate; if (curstate) CURSORON; else CURSOROFF; time = 3; } else --time; break; } } if (conmessage) { /* Character from console */ ch = *constring; /* Retrieve char, then line up request for next char */ QueueRead(ConReadReq,constring); if (ch == CSI) escape = 1, fkeynum = 0; else { if (escape) { if (isdigit(ch)) fkeynum = fkeynum * 10 + ch - '0', ch = 0; else if (ch == '?') fkeynum = 20, ch = 0; else if (ch == ' ') escape = 2, ch = 0; else { escape = 0; if (ch == '~') ch = fkey(fkeynum); else if (escape != 2) ch = convert(ch); } } CURSOROFF; if (ch == '\r') { getcommand(s); /* Read command from screen */ printchar(ch); if (*s) docommand(s); } else { if (ch == DEL) /* If delete key (Ascii #127) */ ch = C_INSERT; /* Make it act as insert */ printchar(ch); } CURSORON; time = 3; curstate = 1; } } } }