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