aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/boxes.c
diff options
context:
space:
mode:
authorDavid Walter Seikel2014-01-29 21:55:43 +1000
committerDavid Walter Seikel2014-01-29 21:55:43 +1000
commitf883185e52bbcb9fbc8ab070b03681e9250bef38 (patch)
tree6e86f751900c9d69d74a72a7915726a55b2e2477 /boxes.c
parentAdd a CSI parser. We need one for terminal sizing and mouse reports. (diff)
downloadopensim-SC-f883185e52bbcb9fbc8ab070b03681e9250bef38.zip
opensim-SC-f883185e52bbcb9fbc8ab070b03681e9250bef38.tar.gz
opensim-SC-f883185e52bbcb9fbc8ab070b03681e9250bef38.tar.bz2
opensim-SC-f883185e52bbcb9fbc8ab070b03681e9250bef38.tar.xz
Signal catcher to catch those signals sent on keystrokes.
Actually found a better way while researching this, and this all gets deleted. I wanted to save this version in the git history though.
Diffstat (limited to 'boxes.c')
-rw-r--r--boxes.c78
1 files changed, 77 insertions, 1 deletions
diff --git a/boxes.c b/boxes.c
index 79b412d..8c9f7f6 100644
--- a/boxes.c
+++ b/boxes.c
@@ -32,6 +32,13 @@ config BOXES
32 Stick chars means to use ASCII for the boxes instead of "graphics" characters. 32 Stick chars means to use ASCII for the boxes instead of "graphics" characters.
33*/ 33*/
34 34
35
36/* We need to catch some signals, coz some key strokes used by some editors trigger signals.
37If we use poll or select, we get the race condition from the signals.
38Poll is preferable over select in general. So I was using poll originally.
39However, ppoll is Linux specific, and worse, needs to define the following swear words...
40*/
41#define _GNU_SOURCE
35#include "toys.h" 42#include "toys.h"
36 43
37GLOBALS( 44GLOBALS(
@@ -659,6 +666,7 @@ static box *rootBox; // Parent of the rest of the boxes, or the only box. Alway
659static box *currentBox; 666static box *currentBox;
660static view *commandLine; 667static view *commandLine;
661static int commandMode; 668static int commandMode;
669static /*sigatomic_t*/ volatile int signalPipe[2];
662 670
663 671
664#define MEM_SIZE 128 // Chunk size for line memory allocation. 672#define MEM_SIZE 128 // Chunk size for line memory allocation.
@@ -1857,7 +1865,9 @@ struct CSI CSI_terminators[] =
1857 1865
1858void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct keyCommand * (*lineCommand)(long extra, char *command)) 1866void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct keyCommand * (*lineCommand)(long extra, char *command))
1859{ 1867{
1860 struct pollfd pollfds[1]; 1868 struct pollfd pollfds[2];
1869 struct timespec timeout = {0, 100000000}; // Timeout of one tenth of a second.
1870 sigset_t signalMask;
1861 // Get the initial command set. 1871 // Get the initial command set.
1862 struct keyCommand *ourKeys = lineCommand(extra, ""); 1872 struct keyCommand *ourKeys = lineCommand(extra, "");
1863 char buffer[20], command[20], csFinal[8]; 1873 char buffer[20], command[20], csFinal[8];
@@ -1869,6 +1879,14 @@ void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct key
1869 buffer[0] = 0; 1879 buffer[0] = 0;
1870 command[0] = 0; 1880 command[0] = 0;
1871 1881
1882 sigemptyset(&signalMask);
1883 sigaddset(&signalMask, SIGINT);
1884 sigaddset(&signalMask, SIGCONT);
1885// sigaddset(&signalMask, SIGSTOP);
1886// sigaddset(&signalMask, SIGINFO);
1887 sigaddset(&signalMask, SIGTSTP);
1888 sigaddset(&signalMask, SIGQUIT);
1889
1872 // TODO - OS buffered keys might be a problem, but we can't do the usual timestamp filter for now. 1890 // TODO - OS buffered keys might be a problem, but we can't do the usual timestamp filter for now.
1873 TT.stillRunning = 1; 1891 TT.stillRunning = 1;
1874 while (TT.stillRunning) 1892 while (TT.stillRunning)
@@ -1888,11 +1906,15 @@ void editLine(long extra, void (*lineChar)(long extra, char *buffer), struct key
1888 memset(pollfds, 0, pollcount * sizeof(struct pollfd)); 1906 memset(pollfds, 0, pollcount * sizeof(struct pollfd));
1889 pollfds[0].events = POLLIN; 1907 pollfds[0].events = POLLIN;
1890 pollfds[0].fd = 0; 1908 pollfds[0].fd = 0;
1909 pollfds[0].events = POLLIN;
1910 pollfds[0].fd = signalPipe[0];
1891 1911
1892// TODO - A bit unstable at the moment, something makes it go into a horrid CPU eating edit line flicker mode sometimes. And / or vi mode can crash on exit (stack smash). 1912// TODO - A bit unstable at the moment, something makes it go into a horrid CPU eating edit line flicker mode sometimes. And / or vi mode can crash on exit (stack smash).
1893// This might be fixed now. 1913// This might be fixed now.
1894 1914
1895 // TODO - Should only ask for a time out after we get an Escape. 1915 // TODO - Should only ask for a time out after we get an Escape.
1916 p = ppoll(pollfds, pollcount, &timeout, &signalMask);
1917// p = poll(pollfds, pollcount, 100);
1896 p = poll(pollfds, pollcount, 100); // Timeout of one tenth of a second (100). 1918 p = poll(pollfds, pollcount, 100); // Timeout of one tenth of a second (100).
1897 if (0 > p) perror_exit("poll"); 1919 if (0 > p) perror_exit("poll");
1898 if (0 == p) // A timeout, trigger a time event. 1920 if (0 == p) // A timeout, trigger a time event.
@@ -2756,6 +2778,35 @@ struct context simpleVi =
2756// TODO - have any unrecognised escape key sequence start up a new box (split one) to show the "show keys" content. 2778// TODO - have any unrecognised escape key sequence start up a new box (split one) to show the "show keys" content.
2757// That just adds each "Key is X" to the end of the content, and allows scrolling, as well as switching between other boxes. 2779// That just adds each "Key is X" to the end of the content, and allows scrolling, as well as switching between other boxes.
2758 2780
2781struct signalTranslate
2782{
2783 int sig;
2784 char key;
2785};
2786
2787struct signalTranslate translate[] =
2788{
2789 {SIGINT, '\x03'}, // ^C
2790 {SIGCONT, '\x11'}, // ^Q
2791 {SIGSTOP, '\x13'}, // ^S
2792// {SIGINFO, '\x14'}, // ^T
2793 {SIGTSTP, '\x1A'}, // ^Z
2794 {SIGQUIT, '\x1C'} // "^\"
2795};
2796
2797static void handleSignals(int signo)
2798{
2799 int j;
2800
2801 for (j = 0; j < (sizeof(translate) / sizeof(*translate)); j++)
2802 {
2803 if (translate[j].sig == signo)
2804 {
2805 write(signalPipe[1], &translate[j].key, 1);
2806 break;
2807 }
2808 }
2809}
2759 2810
2760void boxes_main(void) 2811void boxes_main(void)
2761{ 2812{
@@ -2763,6 +2814,23 @@ void boxes_main(void)
2763 struct termios termio, oldtermio; 2814 struct termios termio, oldtermio;
2764 char *prompt = "Enter a command : "; 2815 char *prompt = "Enter a command : ";
2765 unsigned W = 80, H = 24; 2816 unsigned W = 80, H = 24;
2817 int signalPipe[2];
2818 struct sigaction sigAction, oldSigActions[6];
2819
2820 // Set up pipes and signal handlers for catching keys that are normally signals.
2821 if (pipe(signalPipe)) perror_exit("can't open a pipe");
2822 fcntl(signalPipe[0], F_SETFL, O_NONBLOCK);
2823 fcntl(signalPipe[1], F_SETFL, O_NONBLOCK);
2824 // Assumes that sigAction is not messed with by sigaction().
2825 memset(&sigAction, 0, sizeof(sigAction));
2826 sigAction.sa_handler = handleSignals;
2827 sigAction.sa_flags = SA_RESTART; // Useless since we are using poll.
2828 if (sigaction(SIGINT, &sigAction, &oldSigActions[0])) perror_exit("can't set signal handler SIGINT"); // Crashes with "poll: Interrupted system call"
2829 if (sigaction(SIGCONT, &sigAction, &oldSigActions[1])) perror_exit("can't set signal handler SIGCONT"); // Not needed it seems.
2830// if (sigaction(SIGSTOP, &sigAction, &oldSigActions[2])) perror_exit("can't set signal handler SIGSTOP"); // Can't be done, screw emacs and vi. "can't set signal handler SIGSTOP: Invalid argument"
2831// if (sigaction(SIGINFO, &sigAction, &oldSigActions[3])) perror_exit("can't set signal handler SIGINFO"); // No such thing as SIGINFO without special foo.
2832 if (sigaction(SIGTSTP, &sigAction, &oldSigActions[4])) perror_exit("can't set signal handler SIGTSTP"); // Crashes with "poll: Interrupted system call"
2833 if (sigaction(SIGQUIT, &sigAction, &oldSigActions[5])) perror_exit("can't set signal handler SIGQUIT"); // Crashes with "poll: Interrupted system call" if using "^\"
2766 2834
2767 // For testing purposes, figure out which context we use. When this gets real, the toybox multiplexer will sort this out for us instead. 2835 // For testing purposes, figure out which context we use. When this gets real, the toybox multiplexer will sort this out for us instead.
2768 if (toys.optflags & FLAG_m) 2836 if (toys.optflags & FLAG_m)
@@ -2866,6 +2934,14 @@ void boxes_main(void)
2866 // Restore the old terminal settings. 2934 // Restore the old terminal settings.
2867 tcsetattr(0, TCSANOW, &oldtermio); 2935 tcsetattr(0, TCSANOW, &oldtermio);
2868 2936
2937 // Probaly don't need to restore these before quitting, but including this in the example.
2938 sigaction(SIGINT, &oldSigActions[0], NULL);
2939 sigaction(SIGCONT, &oldSigActions[1], NULL);
2940// sigaction(SIGSTOP, &oldSigActions[2], NULL);
2941// sigaction(SIGINFO, &oldSigActions[3], NULL);
2942 sigaction(SIGTSTP, &oldSigActions[4], NULL);
2943 sigaction(SIGQUIT, &oldSigActions[5], NULL);
2944
2869 puts("\n"); 2945 puts("\n");
2870 fflush(stdout); 2946 fflush(stdout);
2871} 2947}