root/trunk/src/util.c

Revision 877, 65.8 kB (checked in by takkaria, 2 weeks ago)

Add some more colour names for the edit files.

Line 
1 /*
2  * File: util.c
3  * Purpose: Macro code, gamma correction, some high-level UI functions, inkey()
4  *
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6  *
7  * This work is free software; you can redistribute it and/or modify it
8  * under the terms of either:
9  *
10  * a) the GNU General Public License as published by the Free Software
11  *    Foundation, version 2, or
12  *
13  * b) the "Angband licence":
14  *    This software may be copied and distributed for educational, research,
15  *    and not for profit purposes provided that this copyright and statement
16  *    are included in all such copies.  Other copyrights may also apply.
17  */
18 #include "angband.h"
19 #include "randname.h"
20
21
22
23 /*
24  * Convert a decimal to a single digit hex number
25  */
26 static char hexify(int i)
27 {
28         return (hexsym[i % 16]);
29 }
30
31 /*
32  * Convert a hexidecimal-digit into a decimal
33  */
34 static int dehex(char c)
35 {
36         if (isdigit((unsigned char)c)) return (D2I(c));
37         if (isalpha((unsigned char)c)) return (A2I(tolower((unsigned char)c)) + 10);
38         return (0);
39 }
40
41
42 /*
43  * Transform macro trigger name ('\[alt-D]' etc..)
44  * into macro trigger key code ('^_O_64\r' or etc..)
45  */
46 static size_t trigger_text_to_ascii(char *buf, size_t max, cptr *strptr)
47 {
48         cptr str = *strptr;
49         bool mod_status[MAX_MACRO_MOD];
50
51         int i, len = 0;
52         int shiftstatus = 0;
53         cptr key_code;
54        
55         size_t current_len = strlen(buf);
56
57         /* No definition of trigger names */
58         if (macro_template == NULL) return 0;
59
60         /* Initialize modifier key status */   
61         for (i = 0; macro_modifier_chr[i]; i++)
62                 mod_status[i] = FALSE;
63
64         str++;
65
66         /* Examine modifier keys */
67         while (1)
68         {
69                 /* Look for modifier key name */
70                 for (i = 0; macro_modifier_chr[i]; i++)
71                 {
72                         len = strlen(macro_modifier_name[i]);
73
74                         if (!my_strnicmp(str, macro_modifier_name[i], len))
75                                 break;
76                 }
77
78                 /* None found? */
79                 if (!macro_modifier_chr[i]) break;
80
81                 /* Proceed */
82                 str += len;
83
84                 /* This modifier key is pressed */
85                 mod_status[i] = TRUE;
86
87                 /* Shift key might be going to change keycode */
88                 if (macro_modifier_chr[i] == 'S')
89                         shiftstatus = 1;
90         }
91
92         /* Look for trigger name */
93         for (i = 0; i < max_macrotrigger; i++)
94         {
95                 len = strlen(macro_trigger_name[i]);
96
97                 /* Found it and it is ending with ']' */
98                 if (!my_strnicmp(str, macro_trigger_name[i], len) && (']' == str[len]))
99                         break;
100         }
101
102         /* Invalid trigger name? */
103         if (i == max_macrotrigger)
104         {
105                 /*
106                  * If this invalid trigger name is ending with ']',
107                  * skip whole of it to avoid defining strange macro trigger
108                  */
109                 str = strchr(str, ']');
110
111                 if (str)
112                 {
113                         strnfcat(buf, max, &current_len, "\x1F\r");
114
115                         *strptr = str; /* where **strptr == ']' */
116                 }
117
118                 return current_len;
119         }
120
121         /* Get keycode for this trigger name */
122         key_code = macro_trigger_keycode[shiftstatus][i];
123
124         /* Proceed */
125         str += len;
126
127         /* Begin with '^_' */
128         strnfcat(buf, max, &current_len, "\x1F");
129
130         /* Write key code style trigger using template */
131         for (i = 0; macro_template[i]; i++)
132         {
133                 char ch = macro_template[i];
134
135                 switch (ch)
136                 {
137                         /* Modifier key character */
138                         case '&':
139                         {
140                                 size_t j;
141                                 for (j = 0; macro_modifier_chr[j]; j++)
142                                 {
143                                         if (mod_status[j])
144                                                 strnfcat(buf, max, &current_len, "%c", macro_modifier_chr[j]);
145                                 }
146                                 break;
147                         }
148
149                         /* Key code */
150                         case '#':
151                         {
152                                 strnfcat(buf, max, &current_len, "%s", key_code);
153                                 break;
154                         }
155
156                         /* Fixed string */
157                         default:
158                         {
159                                 strnfcat(buf, max, &current_len, "%c", ch);
160                                 break;
161                         }
162                 }
163         }
164
165         /* End with '\r' */
166         strnfcat(buf, max, &current_len, "\r");
167
168         /* Succeed */
169         *strptr = str; /* where **strptr == ']' */
170        
171         return current_len;
172 }
173
174
175 /*
176  * Hack -- convert a printable string into real ascii
177  *
178  * This function will not work on non-ascii systems.
179  *
180  * To be safe, "buf" should be at least as large as "str".
181  */
182 void text_to_ascii(char *buf, size_t len, cptr str)
183 {
184         char *s = buf;
185
186         /* Analyze the "ascii" string */
187         while (*str)
188         {
189                 /* Check if the buffer is long enough */
190                 if (s >= buf + len - 1) break;
191
192                 /* Backslash codes */
193                 if (*str == '\\')
194                 {
195                         str++;
196                         if (*str == '\0') break;
197
198                         switch (*str)
199                         {
200                                 /* Macro trigger */
201                                 case '[':
202                                 {
203                                         /* Terminate before appending the trigger */
204                                         *s = '\0';
205                                         s += trigger_text_to_ascii(buf, len, &str);
206                                         break;
207                                 }
208
209                                 /* Hex-mode */
210                                 case 'x':
211                                 {
212                                         if (isxdigit((unsigned char)(*(str + 1))) &&
213                                             isxdigit((unsigned char)(*(str + 2))))
214                                         {
215                                                 *s = 16 * dehex(*++str);
216                                                 *s++ += dehex(*++str);
217                                         }
218                                         else
219                                         {
220                                                 /* HACK - Invalid hex number */
221                                                 *s++ = '?';
222                                         }
223                                         break;
224                                 }
225
226                                 case 'e':
227                                         *s++ = ESCAPE;
228                                         break;
229                                 case 's':
230                                         *s++ = ' ';
231                                         break;
232                                 case 'b':
233                                         *s++ = '\b';
234                                         break;
235                                 case 'n':
236                                         *s++ = '\n';
237                                         break;
238                                 case 'r':
239                                         *s++ = '\r';
240                                         break;
241                                 case 't':
242                                         *s++ = '\t';
243                                         break;
244                                 case 'a':
245                                         *s++ = '\a';
246                                         break;
247                                 case '\\':
248                                         *s++ = '\\';
249                                         break;
250                                 case '^':
251                                         *s++ = '^';
252                                         break;
253
254                                 default:
255                                         *s = *str;
256                                         break;
257                         }
258
259                         /* Skip the final char */
260                         str++;
261                 }
262
263                 /* Normal Control codes */
264                 else if (*str == '^')
265                 {
266                         str++;
267                         if (*str == '\0') break;
268
269                         *s++ = KTRL(*str);
270                         str++;
271                 }
272
273                 /* Normal chars */
274                 else
275                 {
276                         *s++ = *str++;
277                 }
278         }
279
280         /* Terminate */
281         *s = '\0';
282 }
283
284
285 /*
286  * Transform macro trigger key code ('^_O_64\r' or etc..)
287  * into macro trigger name ('\[alt-D]' etc..)
288  */
289 static size_t trigger_ascii_to_text(char *buf, size_t max, cptr *strptr)
290 {
291         cptr str = *strptr;
292         char key_code[100];
293         int i;
294         cptr tmp;
295         size_t current_len = strlen(buf);
296        
297
298         /* No definition of trigger names */
299         if (macro_template == NULL) return 0;
300
301         /* Trigger name will be written as '\[name]' */
302         strnfcat(buf, max, &current_len, "\\[");
303
304         /* Use template to read key-code style trigger */
305         for (i = 0; macro_template[i]; i++)
306         {
307                 char ch = macro_template[i];
308
309                 switch (ch)
310                 {
311                         /* Read modifier */
312                         case '&':
313                         {
314                                 size_t j;
315                                 while ((tmp = strchr(macro_modifier_chr, *str)) != 0)
316                                 {
317                                         j = tmp - macro_modifier_chr;
318                                         strnfcat(buf, max, &current_len, "%s", macro_modifier_name[j]);
319                                         str++;
320                                 }
321                                 break;
322                         }
323
324                         /* Read key code */
325                         case '#':
326                         {
327                                 size_t j;
328                                 for (j = 0; *str && (*str != '\r') && (j < sizeof(key_code) - 1); j++)
329                                         key_code[j] = *str++;
330                                 key_code[j] = '\0';
331                                 break;
332                         }
333
334                         /* Skip fixed strings */
335                         default:
336                         {
337                                 if (ch != *str) return 0;
338                                 str++;
339                         }
340                 }
341         }
342
343         /* Key code style triggers always end with '\r' */
344         if (*str++ != '\r') return 0;
345
346         /* Look for trigger name with given keycode (normal or shifted keycode) */
347         for (i = 0; i < max_macrotrigger; i++)
348         {
349                 if (!my_stricmp(key_code, macro_trigger_keycode[0][i]) ||
350                     !my_stricmp(key_code, macro_trigger_keycode[1][i]))
351                         break;
352         }
353
354         /* Not found? */
355         if (i == max_macrotrigger) return 0;
356
357         /* Write trigger name + "]" */
358         strnfcat(buf, max, &current_len, "%s]", macro_trigger_name[i]);
359
360         /* Succeed */
361         *strptr = str;
362         return current_len;
363 }
364
365
366 /*
367  * Hack -- convert a string into a printable form
368  *
369  * This function will not work on non-ascii systems.
370  */
371 void ascii_to_text(char *buf, size_t len, cptr str)
372 {
373         char *s = buf;
374
375         /* Analyze the "ascii" string */
376         while (*str)
377         {
378                 byte i = (byte)(*str++);
379
380                 /* Check if the buffer is long enough */
381                 /* HACK - always assume worst case (hex-value + '\0') */
382                 if (s >= buf + len - 5) break;
383
384                 if (i == ESCAPE)
385                 {
386                         *s++ = '\\';
387                         *s++ = 'e';
388                 }
389                 else if (i == ' ')
390                 {
391                         *s++ = '\\';
392                         *s++ = 's';
393                 }
394                 else if (i == '\b')
395                 {
396                         *s++ = '\\';
397                         *s++ = 'b';
398                 }
399                 else if (i == '\t')
400                 {
401                         *s++ = '\\';
402                         *s++ = 't';
403                 }
404                 else if (i == '\a')
405                 {
406                         *s++ = '\\';
407                         *s++ = 'a';
408                 }
409                 else if (i == '\n')
410                 {
411                         *s++ = '\\';
412                         *s++ = 'n';
413                 }
414                 else if (i == '\r')
415                 {
416                         *s++ = '\\';
417                         *s++ = 'r';
418                 }
419                 else if (i == '\\')
420                 {
421                         *s++ = '\\';
422                         *s++ = '\\';
423                 }
424                 else if (i == '^')
425                 {
426                         *s++ = '\\';
427                         *s++ = '^';
428                 }
429                 /* Macro Trigger */
430                 else if (i == 31)
431                 {
432                         size_t offset;
433
434                         /* Terminate before appending the trigger */
435                         *s = '\0';
436
437                         offset = trigger_ascii_to_text(buf, len, &str);
438                        
439                         if (offset == 0)
440                         {
441                                 /* No trigger found */
442                                 *s++ = '^';
443                                 *s++ = '_';
444                         }
445                         else
446                                 s += offset;
447                 }
448                 else if (i < 32)
449                 {
450                         *s++ = '^';
451                         *s++ = UN_KTRL(i);
452                 }
453                 else if (i < 127)
454                 {
455                         *s++ = i;
456                 }
457                 else
458                 {
459                         *s++ = '\\';
460                         *s++ = 'x';
461                         *s++ = hexify((int)i / 16);
462                         *s++ = hexify((int)i % 16);
463                 }
464         }
465
466         /* Terminate */
467         *s = '\0';
468 }
469
470
471
472 /*
473  * The "macro" package
474  *
475  * Functions are provided to manipulate a collection of macros, each
476  * of which has a trigger pattern string and a resulting action string
477  * and a small set of flags.
478  */
479
480
481
482 /*
483  * Determine if any macros have ever started with a given character.
484  */
485 static bool macro__use[256];
486
487
488 /*
489  * Find the macro (if any) which exactly matches the given pattern
490  */
491 int macro_find_exact(cptr pat)
492 {
493         int i;
494
495         /* Nothing possible */
496         if (!macro__use[(byte)(pat[0])])
497                 return -1;
498
499         /* Scan the macros */
500         for (i = 0; i < macro__num; ++i)
501         {
502                 if (streq(macro__pat[i], pat))
503                         return i;
504         }
505
506         /* No matches */
507         return -1;
508 }
509
510
511 /*
512  * Find the first macro (if any) which contains the given pattern
513  */
514 static int macro_find_check(cptr pat)
515 {
516         int i;
517
518         /* Nothing possible */
519         if (!macro__use[(byte)(pat[0])])
520                 return -1;
521
522         /* Scan the macros */
523         for (i = 0; i < macro__num; ++i)
524         {
525                 if (prefix(macro__pat[i], pat))
526                         return i;
527         }
528
529         /* Nothing */
530         return -1;
531 }
532
533
534 /*
535  * Find the first macro (if any) which contains the given pattern and more
536  */
537 static int macro_find_maybe(cptr pat)
538 {
539         int i;
540
541         /* Nothing possible */
542         if (!macro__use[(byte)(pat[0])])
543                 return -1;
544
545         /* Scan the macros */
546         for (i = 0; i < macro__num; ++i)
547         {
548                 if (prefix(macro__pat[i], pat) && !streq(macro__pat[i], pat))
549                         return i;
550         }
551
552         /* Nothing */
553         return -1;
554 }
555
556
557
558 /*
559  * Find the longest macro (if any) which starts with the given pattern
560  */
561 static int macro_find_ready(cptr pat)
562 {
563         int i, t, n = -1, s = -1;
564
565         /* Nothing possible */
566         if (!macro__use[(byte)(pat[0])])
567                 return -1;
568
569         /* Scan the macros */
570         for (i = 0; i < macro__num; ++i)
571         {
572                 /* Skip macros which are not contained by the pattern */
573                 if (!prefix(pat, macro__pat[i])) continue;
574
575                 /* Obtain the length of this macro */
576                 t = strlen(macro__pat[i]);
577
578                 /* Only track the "longest" pattern */
579                 if ((n >= 0) && (s > t)) continue;
580
581                 /* Track the entry */
582                 n = i;
583                 s = t;
584         }
585
586         /* Result */
587         return n;
588 }
589
590
591 /*
592  * Add a macro definition (or redefinition).
593  *
594  * We should use "act == NULL" to "remove" a macro, but this might make it
595  * impossible to save the "removal" of a macro definition.  XXX XXX XXX
596  *
597  * We should consider refusing to allow macros which contain existing macros,
598  * or which are contained in existing macros, because this would simplify the
599  * macro analysis code.  XXX XXX XXX
600  *
601  * We should consider removing the "command macro" crap, and replacing it
602  * with some kind of "powerful keymap" ability, but this might make it hard
603  * to change the "roguelike" option from inside the game.  XXX XXX XXX
604  */
605 errr macro_add(cptr pat, cptr act)
606 {
607         int n;
608
609         if (!pat || !act) return (-1);
610
611
612         /* Look for any existing macro */
613         n = macro_find_exact(pat);
614
615         /* Replace existing macro */
616         if (n >= 0)
617         {
618                 string_free(macro__act[n]);
619         }
620
621         /* Create a new macro */
622         else
623         {
624                 /* Get a new index */
625                 n = macro__num++;
626                 if (macro__num >= MACRO_MAX) quit("Too many macros!");
627
628                 /* Save the pattern */
629                 macro__pat[n] = string_make(pat);
630         }
631
632         /* Save the action */
633         macro__act[n] = string_make(act);
634
635         /* Efficiency */
636         macro__use[(byte)(pat[0])] = TRUE;
637
638         /* Success */
639         return (0);
640 }
641
642
643
644 /*
645  * Initialize the "macro" package
646  */
647 errr macro_init(void)
648 {
649         /* Macro patterns */
650         macro__pat = C_ZNEW(MACRO_MAX, cptr);
651
652         /* Macro actions */
653         macro__act = C_ZNEW(MACRO_MAX, cptr);
654
655         /* Success */
656         return (0);
657 }
658
659
660 /*
661  * Free the macro package
662  */
663 errr macro_free(void)
664 {
665         int i;
666         size_t j;
667
668         /* Free the macros */
669         for (i = 0; i < macro__num; ++i)
670         {
671                 string_free(macro__pat[i]);
672                 string_free(macro__act[i]);
673         }
674
675         FREE(macro__pat);
676         FREE(macro__act);
677
678         /* Free the keymaps */
679         for (i = 0; i < KEYMAP_MODES; ++i)
680         {
681                 for (j = 0; j < N_ELEMENTS(keymap_act[i]); ++j)
682                 {
683                         string_free(keymap_act[i][j]);
684                         keymap_act[i][j] = NULL;
685                 }
686         }
687
688         /* Success */
689         return (0);
690 }
691
692
693 /*
694  * Free the macro trigger package
695  */
696 errr macro_trigger_free(void)
697 {
698         int i;
699         int num;
700
701         if (macro_template != NULL)
702         {
703                 /* Free the template */
704                 string_free(macro_template);
705                 macro_template = NULL;
706
707                 /* Free the trigger names and keycodes */
708                 for (i = 0; i < max_macrotrigger; i++)
709                 {
710                         string_free(macro_trigger_name[i]);
711
712                         string_free(macro_trigger_keycode[0][i]);
713                         string_free(macro_trigger_keycode[1][i]);
714                 }
715
716                 /* No more macro triggers */
717                 max_macrotrigger = 0;
718
719                 /* Count modifier-characters */
720                 num = strlen(macro_modifier_chr);
721
722                 /* Free modifier names */
723                 for (i = 0; i < num; i++)
724                         string_free(macro_modifier_name[i]);
725
726                 /* Free modifier chars */
727                 string_free(macro_modifier_chr);
728         }
729
730         /* Success */
731         return (0);
732 }
733
734
735 /*
736  * Flush all pending input.
737  *
738  * Actually, remember the flush, using the "inkey_xtra" flag, and in the
739  * next call to "inkey()", perform the actual flushing, for efficiency,
740  * and correctness of the "inkey()" function.
741  */
742 void flush(void)
743 {
744         /* Do it later */
745         inkey_xtra = TRUE;
746 }
747
748
749 /*
750  * Flush all pending input if the flush_failure option is set.
751  */
752 void flush_fail(void)
753 {
754         if (flush_failure) flush();
755 }
756
757
758 /*
759  * Local variable -- we are inside a "macro action"
760  *
761  * Do not match any macros until "ascii 30" is found.
762  */
763 static bool parse_macro = FALSE;
764
765
766 /*
767  * Local variable -- we are inside a "macro trigger"
768  *
769  * Strip all keypresses until a low ascii value is found.
770  */
771 static bool parse_under = FALSE;
772
773
774
775 /*
776  * Helper function called only from "inkey()"
777  *
778  * This function does almost all of the "macro" processing.
779  *
780  * We use the "Term_key_push()" function to handle "failed" macros, as well
781  * as "extra" keys read in while choosing the proper macro, and also to hold
782  * the action for the macro, plus a special "ascii 30" character indicating
783  * that any macro action in progress is complete.  Embedded macros are thus
784  * illegal, unless a macro action includes an explicit "ascii 30" character,
785  * which would probably be a massive hack, and might break things.
786  *
787  * Only 500 (0+1+2+...+29+30) milliseconds may elapse between each key in
788  * the macro trigger sequence.  If a key sequence forms the "prefix" of a
789  * macro trigger, 500 milliseconds must pass before the key sequence is
790  * known not to be that macro trigger.  XXX XXX XXX
791  */
792 static ui_event_data inkey_aux(int scan_cutoff)
793 {
794         int k = 0, n, p = 0, w = 0;
795        
796         ui_event_data ke, ke0;
797         char ch;
798        
799         cptr pat, act;
800        
801         char buf[1024];
802
803         /* Initialize the no return */
804         ke0.type = EVT_NONE;
805         ke0.key = 0;
806         ke0.index = 0; /* To fix GCC warnings on X11 */
807         ke0.mousey = 0;
808         ke0.mousex = 0;
809  
810         /* Wait for a keypress */
811         if (scan_cutoff == SCAN_OFF)
812         {
813                 (void)(Term_inkey(&ke, TRUE, TRUE));
814                 ch = ke.key;
815         }
816         else
817         {
818                 w = 0;
819
820                 /* Wait only as long as macro activation would wait*/
821                 while (Term_inkey(&ke, FALSE, TRUE) != 0)
822                 {
823                         /* Increase "wait" */
824                         w++;
825
826                         /* Excessive delay */
827                         if (w >= scan_cutoff)
828                         {
829                                 ke0.type = EVT_KBRD;
830                                 return ke0;
831                         }
832
833                         /* Delay */
834                         Term_xtra(TERM_XTRA_DELAY, 10);
835                 }
836                 ch = ke.key;
837         }
838
839        
840         /* End "macro action" */
841         if ((ch == 30) || (ch == '\xff'))
842         {
843                 parse_macro = FALSE;
844                 return (ke);
845         }
846        
847         /* Inside "macro action" */
848         if (parse_macro) return (ke);
849        
850         /* Inside "macro trigger" */
851         if (parse_under) return (ke);
852        
853
854         /* Save the first key, advance */
855         buf[p++] = ch;
856         buf[p] = '\0';
857        
858        
859         /* Check for possible macro */
860         k = macro_find_check(buf);
861        
862         /* No macro pending */
863         if (k < 0) return (ke);
864        
865        
866         /* Wait for a macro, or a timeout */
867         while (TRUE)
868         {
869                 /* Check for pending macro */
870                 k = macro_find_maybe(buf);
871                
872                 /* No macro pending */
873                 if (k < 0) break;
874                
875                 /* Check for (and remove) a pending key */
876                 if (0 == Term_inkey(&ke, FALSE, TRUE))
877                 {
878                         /* Append the key */
879                         buf[p++] = ke.key;
880                         buf[p] = '\0';
881                
882                         /* Resta