1 /*
2  * $Id: key.c,v 1.8 2001/02/13 23:38:06 danny Exp $
3  *
4  * Copyright � 1993, 2001 Free Software Foundation, Inc.
5  *
6  * This program 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  * This program 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 this software; see the file COPYING.  If not, write to
18  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #ifdef	WITH_DMALLOC
25 #include <dmalloc.h>
26 #endif
27 
28 #include <ctype.h>
29 
30 #include "key.h"
31 #include "cmd.h"
32 #include "io-abstract.h"
33 #include "io-generic.h"
34 #include "io-utils.h"
35 #include "io-term.h"
36 
37 struct keymap **the_maps;
38 char **map_names;
39 char **map_prompts;
40 int num_maps;
41 struct cmd_func **the_funcs;
42 int num_funcs;
43 
44 
45 int
search_map_for_cmd(struct line * line,int map,int vec,int code)46 search_map_for_cmd (struct line * line, int map, int vec, int code)
47 {
48   int len = strlen (line->buf);
49   struct keymap * this_map;
50   int x;
51   char used[OLEO_NUM_KEYS];
52   int try_prefix;
53 
54   for (try_prefix = 0; try_prefix < 2; ++try_prefix)
55     {
56       bzero (used, sizeof (used));
57 
58       for (this_map = the_maps[map]; this_map; this_map = this_map->map_next)
59 	{
60 	  for (x = 128; x >= 0; --x)
61 	    if (!used[x])
62 	      {
63 		int found_it = ((this_map->keys[x].vector == vec)
64 				&& this_map->keys[x].code == code);
65 		int prefix_key = ((this_map->keys[x].vector == -1)
66 				  && (this_map->keys[x].code != -1));
67 		if (!(   (this_map->keys[x].vector == -1)
68 		      && (this_map->keys[x].code == -1)))
69 		  used[x] = 1;
70 		if (found_it || (try_prefix && prefix_key))
71 		  {
72 		    char * c = char_to_string (x);
73 		    catn_line (line, " ", 1);
74 		    catn_line (line, c, strlen (c));
75 		    if (found_it
76 			|| (try_prefix
77 			    && search_map_for_cmd (line,
78 						   this_map->keys[x].code,
79 						   vec, code)))
80 		      return 1;
81 		    line->buf[len] = 0;
82 		  }
83 	      }
84 	}
85     }
86   return 0;
87 }
88 
89 static void
do_bind_key(struct keymap * m,int key,int vector,int code)90 do_bind_key (struct keymap *m, int key, int vector, int code)
91 {
92   m->keys[key].vector = (short)vector;
93   m->keys[key].code = (short)code;
94 }
95 
96 
97 void
bind_key(char * keymap,char * function,int ch)98 bind_key (char * keymap, char * function, int ch)
99 {
100   struct cmd_func * tmpfunc;
101   int map = map_id (keymap);
102   int vec;
103   int code;
104   struct rng rng;
105   struct cmd_func * cmd;
106 
107   if (map < 0)
108     {
109       io_error_msg ("bind_key: bad keymap.");
110       return;
111     }
112 
113   if (!find_func (&vec, &cmd, function))
114     {
115       code = (cmd - the_funcs[vec]);
116       goto fini;
117     }
118 
119   for (code = 0; code < num_maps; code++)
120     {
121       if (!strcmp (function, map_names[code]))
122 	{
123 	  vec = -1;
124 	  goto fini;
125 	}
126     }
127   if (get_abs_rng (&function, &rng))
128     {
129       io_error_msg ("Unknown command '%s'", function);
130       return;
131     }
132 
133   for (code = 0; code < n_bound_macros; code++)
134     {
135       if (!bcmp (&bound_macros[code], &rng, sizeof (struct rng)))
136 	  goto fini;
137     }
138 
139   function = range_name (&rng);
140   if (!bound_macro_vec)
141     {
142       bound_macros = ck_malloc (sizeof (struct rng));
143       n_bound_macros = 1;
144       tmpfunc = (struct cmd_func *)ck_malloc (2 * sizeof (struct cmd_func));
145       bzero (tmpfunc + 1, sizeof (*tmpfunc));
146       bound_macro_vec = add_usr_cmds (tmpfunc);
147     }
148   else
149     {
150       n_bound_macros++;
151       bound_macros = ck_realloc (bound_macros,
152 				 n_bound_macros * sizeof (struct rng));
153       the_funcs[bound_macro_vec]
154 	= ck_realloc (the_funcs[bound_macro_vec],
155 		      (1 + n_bound_macros) * sizeof (struct cmd_func));
156       tmpfunc = &the_funcs[bound_macro_vec][n_bound_macros - 1];
157       bzero (tmpfunc + 1, sizeof (*tmpfunc));
158     }
159   vec = bound_macro_vec;
160   bound_macros[n_bound_macros - 1] = rng;
161   tmpfunc->func_args = (char **)ck_malloc (2 * sizeof (char *));
162   tmpfunc->func_args[0] = mk_sprintf ("#%d", n_bound_macros - 1);
163   tmpfunc->func_args[1] = 0;
164   tmpfunc->init_code = 0;
165   tmpfunc->func_doc = 0;
166   tmpfunc->func_name = ck_savestr (function);
167   tmpfunc->func_func = bound_macro;
168 fini:
169   do_bind_key (the_maps[map], ch, vec, code);
170 }
171 
172 void
unbind_key(char * keymap,int ch)173 unbind_key (char * keymap, int ch)
174 {
175   int map = map_id (keymap);
176   struct keymap *m;
177   m = the_maps[map];
178   m->keys[ch].vector = -1;
179   m->keys[ch].code = -1;
180 }
181 
182 void
bind_or_unbind_set(char * keymap,char * command,char * keyset)183 bind_or_unbind_set (char * keymap, char * command, char * keyset)
184 {
185   int first;
186   int last;
187   first = string_to_char (&keyset);
188   if (first < 0)
189     {
190       io_error_msg ("Invalid character set.");
191       return;
192     }
193   while (isspace (*keyset))
194     ++keyset;
195   if (*keyset == '-')
196     {
197       ++keyset;
198       last = string_to_char (&keyset);
199       if (last < 0)
200 	{
201 	  io_error_msg ("Unterminated character set.");
202 	  return;
203 	}
204     }
205   else if (*keyset)
206     {
207       io_error_msg ("Extra characters in keyset: `%s'.",
208 		    keyset);
209       return;
210     }
211   else
212     last = first;
213 
214   while (first <= last)
215     {
216       if (command != "0")
217         bind_key (keymap, command, first);
218       else
219         unbind_key (keymap, first);
220       ++first;
221     }
222 }
223 
unbind_set(char * keymap,char * keyset)224 void unbind_set (char *keymap, char *keyset)
225 {
226   char *command = "0";
227   bind_or_unbind_set (keymap, command, keyset);
228 }
229 
230 void
bind_all_keys(char * keymap,char * function)231 bind_all_keys (char * keymap, char * function)
232 {
233   struct cmd_func * tmpfunc;
234   int map = map_id (keymap);
235   int vec;
236   int code;
237   struct rng rng;
238   struct cmd_func * cmd;
239 
240   if (map < 0)
241     {
242       io_error_msg ("bind_key: bad keymap.");
243       return;
244     }
245 
246   if (!find_func (&vec, &cmd, function))
247     {
248       code = (cmd - the_funcs[vec]);
249       goto fini;
250     }
251 
252   for (code = 0; code < num_maps; code++)
253     {
254       if (!strcmp (function, map_names[code]))
255 	{
256 	  vec = -1;
257 	  goto fini;
258 	}
259     }
260   if (get_abs_rng (&function, &rng))
261     {
262       io_error_msg ("Unknown command '%s'", function);
263       return;
264     }
265 
266   vec = bound_macro_vec;
267   for (code = 0; code < n_bound_macros; code++)
268     {
269       if (!bcmp (&bound_macros[code], &rng, sizeof (struct rng)))
270 	  goto fini;
271     }
272 
273   function = range_name (&rng);
274   if (!bound_macro_vec)
275     {
276       bound_macros = ck_malloc (sizeof (struct rng));
277       n_bound_macros = 1;
278       tmpfunc = (struct cmd_func *)ck_malloc (2 * sizeof (struct cmd_func));
279       bzero (tmpfunc + 1, sizeof (*tmpfunc));
280       bound_macro_vec = add_usr_cmds (tmpfunc);
281     }
282   else
283     {
284       n_bound_macros++;
285       bound_macros = ck_realloc (bound_macros,
286 				 n_bound_macros * sizeof (struct rng));
287       the_funcs[bound_macro_vec]
288 	= ck_realloc (the_funcs[bound_macro_vec],
289 		      (1 + n_bound_macros) * sizeof (struct cmd_func));
290       tmpfunc = &the_funcs[bound_macro_vec][n_bound_macros - 1];
291       bzero (tmpfunc + 1, sizeof (*tmpfunc));
292     }
293   bound_macros[n_bound_macros - 1] = rng;
294   tmpfunc->func_args = (char **)ck_malloc (2 * sizeof (char *));
295   tmpfunc->func_args[0] = mk_sprintf ("#%d", n_bound_macros - 1);
296   tmpfunc->func_args[1] = 0;
297   tmpfunc->func_doc = 0;
298   tmpfunc->func_name = ck_savestr (function);
299   tmpfunc->func_func = bound_macro;
300 fini:
301   {
302     int ch;
303     for (ch = 0; ch < OLEO_NUM_KEYS; ++ch)
304       do_bind_key (the_maps[map], ch, vec, code);
305   }
306 }
307 
308 
309 void
write_keys_cmd(FILE * fp)310 write_keys_cmd (FILE *fp)
311 {
312   struct keymap *map;
313   int n;
314   int key;
315   int vec;
316   int code;
317 
318   for (n = 0; n < num_maps; n++)
319     {
320       char *def;
321       map = the_maps[n];
322       def = 0;
323       if (map && map->map_next)
324 	{
325 	  for (key = 0; key < num_maps; key++)
326 	    if (the_maps[key] == map->map_next)
327 	      {
328 		def = map_names[key];
329 		break;
330 	      }
331 	}
332       if (def)
333 	fprintf (fp, "create-keymap %s %s\n", map_names[n], def);
334       else
335 	fprintf (fp, "create-keymap %s\n", map_names[n]);
336     }
337   for (n = 0; n < num_maps; n++)
338     {
339       map = the_maps[n];
340       for (key = 0; key < OLEO_NUM_KEYS; key++)
341 	{
342 	  vec = map->keys[key].vector;
343 	  code = map->keys[key].code;
344 	  if (vec < 0 && code >= 0)
345 	    fprintf (fp, "bind-key %s %s %s\n",
346 		     map_names[n],
347 		     map_names[code],
348 		     char_to_string (key));
349 	  else if (vec >= 0)
350 	    fprintf (fp, "bind-key %s %s %s\n",
351 		     map_names[n],
352 		     the_funcs[vec][code].func_name,
353 		     char_to_string (key));
354 	}
355     }
356 }
357 
358 
359 
360 void
clear_keymap(struct keymap * m)361 clear_keymap (struct keymap *m)
362 {
363   int n;
364   for (n = 0; n < OLEO_NUM_KEYS; n++)
365     {
366       m->keys[n].vector = -1;
367       m->keys[n].code = -1;
368     }
369 }
370 
371 int
map_idn(const char * name,int n)372 map_idn (const char *name, int n)
373 {
374   int x;
375   for (x = 0; x < num_maps; ++x)
376     if (!strincmp (name, map_names[x], n))
377       return x;
378   return -1;
379 }
380 
381 int
map_id(const char * name)382 map_id(const char *name)
383 {
384     return map_idn(name, strlen(name));
385 }
386 
387 void
create_keymap(char * mapname,char * parentname)388 create_keymap (char * mapname, char * parentname)
389 {
390   int map = map_id (mapname);
391   int parent = parentname ? map_id (parentname) : -1;
392 
393   if (map >= 0)
394     {
395       io_info_msg ("Map %s already exists.",  mapname);
396       return;
397     }
398   if (parentname && (parent < 0))
399     {
400       io_error_msg ("Map %s does not exist.", parentname);
401       return;
402     }
403   the_maps = ck_realloc (the_maps, (num_maps + 1) * sizeof (struct keymap *));
404   the_maps[num_maps] = ck_malloc (sizeof (struct keymap));
405   the_maps[num_maps]->id = num_maps;
406   the_maps[num_maps]->map_next = ((parent >= 0)
407 				  ? the_maps[parent]
408 				  : 0);
409   {
410     int c;
411     for (c = 0; c < OLEO_NUM_KEYS; ++c)
412       {
413 	the_maps[num_maps]->keys[c].vector = -1;
414 	the_maps[num_maps]->keys[c].code = -1;
415       }
416   }
417   map_names = ck_realloc (map_names, (num_maps + 1) * sizeof (char *));
418   map_prompts = ck_realloc (map_prompts, (num_maps + 1) * sizeof (char *));
419   map_names[num_maps] = ck_savestr (mapname);
420   map_prompts[num_maps] = 0;
421   num_maps++;
422 }
423 
424 
425 void
set_map_prompt(char * map,char * str)426 set_map_prompt (char * map, char * str)
427 {
428   int id = map_id (map);
429   if (id < 0)
430     io_error_msg ("No such keymap as %s.", map); /* No return. */
431   if (map_prompts[id])
432     free (map_prompts [id]);
433   map_prompts[id] = ck_savestr (str);
434 }
435