ncurses 5.6 - patch 20070128
[ncurses.git] / tack / scan.c
1 /*
2 ** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
3 ** 
4 ** This file is part of TACK.
5 ** 
6 ** TACK is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2, or (at your option)
9 ** any later version.
10 ** 
11 ** TACK is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ** GNU General Public License for more details.
15 ** 
16 ** You should have received a copy of the GNU General Public License
17 ** along with TACK; see the file COPYING.  If not, write to
18 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 ** Boston, MA 02110-1301, USA
20 */
21 /* scan mode keyboard support */
22
23 #include <tack.h>
24
25 MODULE_ID("$Id: scan.c,v 1.5 2005/09/17 19:49:16 tom Exp $")
26
27 unsigned scan_max;              /* length of longest scan code */
28 char **scan_up, **scan_down, **scan_name;
29 unsigned *scan_tested, *scan_length;
30 static unsigned *scan_value;
31
32 static int shift_state;
33 static char *str;
34 static int debug_char_count;
35
36 #define SHIFT_KEY   0x100
37 #define CONTROL_KEY 0x200
38 #define META_KEY    0x400
39 #define CAPS_LOCK   0x800
40
41 static const struct {
42         const char *name;
43         unsigned type;
44 }  scan_special[] = {
45         {"<shift>", SHIFT_KEY},
46         {"<left shift>", SHIFT_KEY},
47         {"<right shift>", SHIFT_KEY},
48         {"<control>", CONTROL_KEY},
49         {"<left control>", CONTROL_KEY},
50         {"<right control>", CONTROL_KEY},
51         {"<meta>", META_KEY},
52         {"<left meta>", META_KEY},
53         {"<right meta>", META_KEY},
54         {"<caps lock>", CAPS_LOCK},
55         {"<tab>", '\t'},
56         {"<space>", ' '},
57         {"<return>", '\r'},
58         {"<linefeed>", '\n'},
59         {"<formfeed>", '\f'},
60         {"<backspace>", '\b'},
61         {0, 0}
62 };
63
64 static void
65 scan_blanks(void)
66 {                               /* scan past the white space */
67         while (*str == ' ' || *str == '\t')
68                 str++;
69 }
70
71 static char *
72 smash(void)
73 {                               /* convert a string to hex */
74         char *s, *t;
75         int ch, i, j;
76
77         t = s = str;
78         for (i = 0; (ch = *str); str++) {
79                 if (ch >= '0' && ch <= '9')
80                         j = ch - '0';
81                 else if (ch >= 'a' && ch <= 'f')
82                         j = 10 - 'a' + ch;
83                 else if (ch >= 'A' && ch <= 'F')
84                         j = 10 - 'A' + ch;
85                 else if (ch == ' ' || ch == '\t')
86                         break;
87                 else
88                         continue;
89                 if (i) {
90                         *s |= j;
91                         s++;
92                 } else
93                         *s = j << 4;
94                 i ^= 1;
95         }
96         *s = '\0';
97         return t;
98 }
99
100 void
101 scan_init(char *fn)
102 {                               /* read the scan mode key definitions */
103         char *s, *sl;
104         FILE *fp;
105         int ch, i, j;
106         unsigned len;
107         char home[512];
108
109         if ((str = getenv("HOME")))
110                 strcpy(home, str);
111         else
112                 home[0] = '\0';
113         fp = NULL;
114         if ((str = getenv("KEYBOARD"))) {
115                 if (!(fp = fopen(str, "r")) && home[0]) {
116                         sprintf(temp, "%s/.scan.%s", home, str);
117                         fp = fopen(temp, "r");
118                 }
119         }
120         if (!fp) {
121                 sprintf(temp, ".scan.%s", fn);
122                 fp = fopen(temp, "r");
123         }
124         if (!fp && home[0]) {
125                 sprintf(temp, "%s/.scan.%s", home, fn);
126                 fp = fopen(temp, "r");
127         }
128         if (!fp) {
129                 ptext("Unable to open scanfile: ");
130                 ptextln(temp);
131                 bye_kids(1);
132                 return;
133         }
134         /*
135            scan file format:
136         
137         <down value> <up value> <name>
138         
139         values are in hex. <name> may be any string of characters
140         
141         */
142         scan_up = (char **) malloc(sizeof(char *) * MAX_SCAN);
143         scan_down = (char **) malloc(sizeof(char *) * MAX_SCAN);
144         scan_name = (char **) malloc(sizeof(char *) * MAX_SCAN);
145         scan_tested = (unsigned *) malloc(sizeof(unsigned *) * MAX_SCAN);
146         scan_length = (unsigned *) malloc(sizeof(unsigned *) * MAX_SCAN);
147         scan_value = (unsigned *) malloc(sizeof(unsigned *) * MAX_SCAN);
148         scan_up[0] = scan_down[0] = scan_name[0] = (char *) 0;
149         str = (char *) malloc(4096);    /* buffer space */
150         sl = str + 4000;        /* an upper limit */
151         scan_max = 1;
152         for (i = 0;;) {
153                 for (s = str; (ch = getc(fp)) != EOF;) {
154                         if (ch == '\n' || ch == '\r')
155                                 break;
156                         *s++ = ch;
157                 }
158                 *s++ = '\0';
159                 if (ch == EOF)
160                         break;
161                 if (*str == '#' || *str == '\0')
162                         continue;
163                 scan_down[i] = smash();
164                 scan_blanks();
165                 scan_up[i] = smash();
166                 scan_blanks();
167                 scan_name[i] = str;
168
169                 scan_length[i] = strlen(scan_down[i]);
170                 len = strlen(scan_up[i]) + scan_length[i];
171                 if (len > scan_max)
172                         scan_max = len;
173
174                 scan_value[i] = UChar(scan_name[i][0]);
175                 if (scan_name[i][1])    /* multi-character name */
176                         for (j = 0; scan_special[j].name; j++) {
177                                 if (!strcmp(scan_name[i], scan_special[j].name)) {
178                                         scan_value[i] = scan_special[j].type;
179                                         break;
180                                 }
181                         }
182
183                 i++;
184                 if (str > sl) {
185                         str = (char *) malloc(4096);
186                         sl = str + 4000;
187                 } else
188                         str = s;
189         }
190         fclose(fp);
191 #ifdef notdef
192         for (i = 0; scan_down[i]; i++) {
193                 put_str(hex_expand_to(scan_down[i], 3));
194                 put_str(hex_expand_to(scan_up[i], 3));
195                 put_str("   ");
196                 put_str(scan_name[i]);
197                 put_crlf();
198         }
199         (void) wait_here();
200 #endif
201 }
202
203 int
204 scan_key(void)
205 {                               /* read a key and translate scan mode to
206                                    ASCII */
207         unsigned i;
208         int j, ch;
209         char buf[64];
210
211         for (i = 1;; i++) {
212                 ch = getchar();
213                 if (ch == EOF)
214                         return EOF;
215                 if (debug_fp) {
216                         fprintf(debug_fp, "%02X ", ch);
217                         debug_char_count += 3;
218                         if (debug_char_count > 72) {
219                                 fprintf(debug_fp, "\n");
220                                 debug_char_count = 0;
221                         }
222                 }
223                 buf[i - 1] = ch;
224                 buf[i] = '\0';
225                 if (buf[0] & 0x80) {    /* scan up */
226                         for (j = 0; scan_up[j]; j++) {
227                                 if (i == scan_length[j] &&
228                                         !strcmp(buf, scan_up[j])) {
229                                         i = 0;
230                                         shift_state &= ~scan_value[j];
231                                         break;
232                                 }
233                         }
234                         continue;
235                 }
236                 for (j = 0; scan_down[j]; j++) {
237                         if (i == scan_length[j] && !strcmp(buf, scan_down[j])) {
238                                 i = 0;
239                                 shift_state |= scan_value[j];
240                                 ch = scan_value[j];
241                                 if (ch == CAPS_LOCK)
242                                         shift_state ^= SHIFT_KEY;
243                                 if (ch >= 256)
244                                         break;
245                                 if (shift_state & SHIFT_KEY) {
246                                         if (ch >= 0x60)
247                                                 ch -= 0x20;
248                                         else if (ch >= 0x30 && ch <= 0x3f)
249                                                 ch -= 0x10;
250                                 }
251                                 if (shift_state & CONTROL_KEY) {
252                                         if ((ch | 0x20) >= 0x60 &&
253                                                 (ch | 0x20) <= 0x7f)
254                                                 ch = (ch | 0x20) - 0x60;
255                                 }
256                                 if (shift_state & META_KEY)
257                                         ch |= 0x80;
258                                 return ch;
259                         }
260                 }
261                 if (i > scan_max)
262                         i = 1;
263         }
264 }