/* * STIO.C * These functions negotiate with various flavors atariST TOS/MiNT * system for characters and write characters in a barely buffered fashion * to the display. * Signals are also handled for MiNT only. * * Most of this code cribbed from unixio.c and pcio.c * ++jrb bammi@cadence.com * Public Domain */ #include #include "me2.h" #include "term.h" #include "config.h" /***************************************************************************/ /***** The top section of this file is for TOS, the bottom for MiNT *******/ /***************************************************************************/ #ifndef __MINT__ /***************************************************************************/ /***** TOS section *******/ /***************************************************************************/ #include #include /* ******************************************************************** */ /* ******** Opening and closing the terminal ************************** */ /* ******************************************************************** */ /* * This function is called once to set up the terminal device streams. */ ttopen() { } /* * This function gets called just before we exit ME. */ ttclose() { } /* ******************************************************************** */ /* ************** Terminal I/O *************************************** */ /* ******************************************************************** */ /* * Write a character to the display. * Use the rawest console output routine that handles backspace, \r and \n. */ t_putchar(c) int c; { Bconout(2, c); } /* * Flush terminal buffer. Does real work when the terminal output is * buffered up. */ t_flush() { } /* * Read a character from the terminal, performing no editing and doing no * echo at all. * Map terminal dependent things (like softkeys and other things ME doesn't * or can't know about) to ME keys. Do *NOT* map control keys. * In general, try just to read a character and return it. */ KeyCode t_getchar() { unsigned long kee = Bconin(2); short *key = (short *)&kee; int scancode = *key; int c = *(key+1); KeyCode keycode; if(c == 0 && scancode != 0 && map_key(scancode, &keycode)) return keycode; else return (KeyCode)c; } /* Ask the window/screen size how big it is. * Input: * row: Pointer to a int * col: Pointer to a int * Munges: * row: The number of rows on the window or screen is put here. * col: The number of columns on the window or screen is put here. * Returns: * TRUE: If I know how to do this and row,col updated. * FALSE: Not supported or got bogus data. row, col not changed. */ int get_size_from_window(row, col) int *row, *col; { return FALSE; } /* ******************************************************************** */ /* *********** Key waiting? ******************************************* */ /* ******************************************************************** */ /* Wait for a key to be pressed for no more than sec seconds. * Use 0 seconds to check to see if a key is in the input que. */ wait_for_key(sec) { long waitUntil = get_sysvar(_hz_200) + (((long)sec) << 8); do { if(Bconstat(2)) return TRUE; } while (get_sysvar(_hz_200) < waitUntil); return FALSE; } /* keywaiting: * Check to see if any characters are already in the keyboard buffer. */ keywaiting() { return Bconstat(2); } #else /* __MINT__ */ /***************************************************************************/ /***** MiNT section *******/ /***************************************************************************/ #include /* for stty/gtty functions */ #include /* to get at the typeahead */ struct sgttyb ostate; /* saved tty state */ struct sgttyb nstate; /* values for editor mode */ struct tchars otchars; /* Saved terminal special character set */ struct tchars ntchars = /* A lot of nothing */ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* ******************************************************************** */ /* ******** Opening and closing the terminal ************************** */ /* ******************************************************************** */ /* * This function is called once to set up the terminal device streams. */ ttopen() { gtty(0,&ostate); /* save old state */ gtty(0,&nstate); /* get base of new state */ nstate.sg_flags |= RAW; /* nstate.sg_flags &= ~(ECHO | CRMOD); /* no echo for now... */ nstate.sg_flags &= ~(ECHO | CRMOD | TANDEM); /* no echo for now... */ stty(0, &nstate); /* set mode */ ioctl(0, TIOCGETC, &otchars); /* Save old characters */ ioctl(0, TIOCSETC, &ntchars); /* Place new character into K */ set_signals(); } /* * This function gets called just before we exit ME. */ ttclose() { stty(0,&ostate); ioctl(0,TIOCSETC,&otchars); /* Place old character into K */ } /* ******************************************************************** */ /* ************** Terminal I/O *************************************** */ /* ******************************************************************** */ /* * Write a character to the display. * Use the rawest console output routine that handles backspace, \r and \n. */ t_putchar(c) unsigned char c; { fputc(c,stdout); } /* * Flush terminal buffer. Does real work when the terminal output is * buffered up. */ t_flush() { fflush(stdout); } /* * Read a character from the terminal, performing no editing and doing no * echo at all. * Map terminal dependent things (like softkeys and other things ME doesn't * or can't know about) to ME keys. Do *NOT* map control keys. * In general, try just to read a character and return it. * Note: * On Unix systems, system calls (like read()) can be interrupted. In * this case, read() will return -1 and errno will be set to EINTR. */ KeyCode t_getchar() { extern int errno; unsigned char c; int n; KeyCode keycode; while (TRUE) { n = read(0,&c,1); if (0 < n) return (KeyCode)c; /* the expected case */ /* Nothing read, error or (most likely) a signal. * Since it might be a signal that something needs to be done and we * aren't anything else right now, try to process any hooks. * Note: On some OSs, read() is automatically restarted so we will * never get this case. */ process_hooks(); } } /* Ask the window/screen size how big it is. * Input: * row: Pointer to a int * col: Pointer to a int * Munges: * row: The number of rows on the window or screen is put here. * col: The number of columns on the window or screen is put here. * Returns: * TRUE: If I know how to do this and row,col updated. * FALSE: Not supported or got bogus data. row, col not changed. * Notes: * According to the BSD tty(4) man page: If, for some unknown (to me) * reason, the terminal has bogus data, the winsize structure is * zeroed. On Apollo, this happens in special cases. ws_xpixel and * ws_ypixel always seem to be zero (probably something to do with * my terminal windows). */ int get_size_from_window(row, col) int *row, *col; { #ifdef TIOCGWINSZ struct winsize term_stats; /* */ /* Get the terminal size */ if (-1 == ioctl(0, TIOCGWINSZ, &term_stats) || 0 == term_stats.ws_row) return FALSE; /* something bad happened */ *row = term_stats.ws_row; *col = term_stats.ws_col; return TRUE; #else return FALSE; #endif } /* ******************************************************************** */ /* *********** Key waiting? ******************************************* */ /* ******************************************************************** */ /* Note: need 1 or 2 routines to check to see if a key is in the input que. * One routine is needed if it is reliable and fast or you need a fast * routine (for HP escape sequence parsing) and one thats fast (for * interrupting a display update). * Sync these up with config.h. */ #include /* Wait for a key to be pressed for no more than sec seconds. * Use 0 seconds to check to see if a key is in the input que. */ wait_for_key(sec) { int x = 1; /* stdin */ struct timeval timeout; timeout.tv_sec = sec; timeout.tv_usec = 0; return select(1, &x, 0, 0, &timeout); } /* keywaiting: * Check to see if any characters are already in the keyboard buffer. * This is reliable but slows things down if called much. * This HAS to work. Sometimes used to parse (HP like) keyboard generated * escape sequences. * Note: FIONREAD is no good on HPUX. */ keywaiting() { long int x; return((ioctl(0,FIONREAD,&x) < 0) ? 0 : x); } /* ******************************************************************** */ /* ******************* Signals **************************************** */ /* ******************************************************************** */ #include #ifdef SIGWINCH /* The screen has been resized. * WARNING: Should NOT actually resize the display in a signal handler * because ME could be in the middle of doing all kinds of things and * this could really mess things up (I don't know for sure but I don't * want to have to debug that case!) or the signal might arrive before * the display system has been properly initialized. * Result: * Tell the main loop to call us when it can. */ static void sig_resize(dummy) { void sig_do_the_resize(); call_me_sometime(RESIZE_HOOK,sig_do_the_resize); } static void sig_do_the_resize() { int row, col; if (get_size_from_window(&row, &col)) { display_resized(row,col); update(); /* force the screen to be redrawn */ } } #endif /* An external process has told ME that it has some info. */ static void sig_expro(foo) { extern void process_talks(); signal(SIGUSR1, SIG_IGN); call_me_sometime(PROCESS_HOOK,process_talks); signal(SIGUSR1, sig_expro); /* reset the signal */ } /* Somebody, somewhere, told me to bite the big one. Well, I can take a * hint. * If there are any modified buffers, too bad. I suppose I could have a * ME-quit-hook. */ static void sig_die(dummy) { mlwrite("ME2 terminated via signal.\r\n"); quit(TRUE,1); } /* Put ME into the background. This can be invoked via signal or called * from ME. This means I gotta be careful when I send myself a signal. */ void sig_pause(dummy) { close_display(TRUE); /* restore terminal for normal user interface */ kill(getpid(),SIGSTOP); /* hello background. Can't catch SIGSTOP. */ open_display(); /* set up terminal for editor */ /* ME might not be in the keywait loop when this is called (because of * an external signal) and so might not redraw the screen until a key * is pressed. */ update(); /* force the screen to be redrawn */ } /* Setup the signals I'm going to catch: * Signal Action * SIGTSTP Put ME into the background. * SIGTERM Clean up and exit. * SIGHUP Clean up and exit. * SIGINT Clean up and exit. * SIGUSR1 Unused. * SIGUSR2 Unused. * SIGWINCH Resize the screen. * Ignore these signals: * SIGCONT sig_pause() will take care of everything it would do. */ static void set_signals() { signal(SIGTSTP,sig_pause); signal(SIGCONT,SIG_IGN); signal(SIGTERM,sig_die); signal(SIGHUP, sig_die); signal(SIGINT, sig_die); #ifdef SIGWINCH signal(SIGWINCH, sig_resize); #endif signal(SIGUSR1, sig_expro); signal(SIGUSR2, SIG_IGN); } #endif /* MiNT */