* Problem report #60
@ 2006-04-11 15:48 Dan Nicolaescu
2006-04-11 17:54 ` Stuart D. Herring
0 siblings, 1 reply; 6+ messages in thread
From: Dan Nicolaescu @ 2006-04-11 15:48 UTC (permalink / raw
CID: 60
Checker: UNINIT (help)
File: emacs/src/keyboard.c
Function: read_key_sequence
Description: Using uninitialized value "original_uppercase"
Event var_decl: Declared variable "original_uppercase" without initializer
Also see events: [uninit_use]
8608 volatile Lisp_Object original_uppercase;
8609 volatile int original_uppercase_position = -1;
8610
8611 /* Gets around Microsoft compiler limitations. */
8612 int dummyflag = 0;
8613
8614 struct buffer *starting_buffer;
8615
8616 /* List of events for which a fake prefix key has been generated. */
8617 volatile Lisp_Object fake_prefixed_keys = Qnil;
8618
8619 #if defined (GOBBLE_FIRST_EVENT)
8620 int junk;
8621 #endif
8622
8623 struct gcpro gcpro1;
8624
8625 GCPRO1 (fake_prefixed_keys);
8626 raw_keybuf_count = 0;
8627
8628 last_nonmenu_event = Qnil;
8629
8630 delayed_switch_frame = Qnil;
8631 fkey.map = fkey.parent = Vfunction_key_map;
8632 keytran.map = keytran.parent = Vkey_translation_map;
8633 /* If there is no translation-map, turn off scanning. */
8634 fkey.start = fkey.end = KEYMAPP (fkey.map) ? 0 : bufsize + 1;
8635 keytran.start = keytran.end = KEYMAPP (keytran.map) ? 0 : bufsize + 1;
8636
8637 if (INTERACTIVE)
8638 {
8639 if (!NILP (prompt))
8640 echo_prompt (prompt);
8641 else if (cursor_in_echo_area
8642 && (FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
8643 && NILP (Fzerop (Vecho_keystrokes)))
8644 /* This doesn't put in a dash if the echo buffer is empty, so
8645 you don't always see a dash hanging out in the minibuffer. */
8646 echo_dash ();
8647 }
8648
8649 /* Record the initial state of the echo area and this_command_keys;
8650 we will need to restore them if we replay a key sequence. */
8651 if (INTERACTIVE)
8652 echo_start = echo_length ();
8653 keys_start = this_command_key_count;
8654 this_single_command_key_start = keys_start;
8655
8656 #if defined (GOBBLE_FIRST_EVENT)
8657 /* This doesn't quite work, because some of the things that read_char
8658 does cannot safely be bypassed. It seems too risky to try to make
8659 this work right. */
8660
8661 /* Read the first char of the sequence specially, before setting
8662 up any keymaps, in case a filter runs and switches buffers on us. */
8663 first_event = read_char (NILP (prompt), 0, submaps, last_nonmenu_event,
8664 &junk);
8665 #endif /* GOBBLE_FIRST_EVENT */
8666
8667 orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
8668 orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
8669 from_string = Qnil;
8670
8671 /* We jump here when the key sequence has been thoroughly changed, and
8672 we need to rescan it starting from the beginning. When we jump here,
8673 keybuf[0..mock_input] holds the sequence we should reread. */
8674 replay_sequence:
8675
8676 starting_buffer = current_buffer;
8677 first_unbound = bufsize + 1;
8678
8679 /* Build our list of keymaps.
8680 If we recognize a function key and replace its escape sequence in
8681 keybuf with its symbol, or if the sequence starts with a mouse
8682 click and we need to switch buffers, we jump back here to rebuild
8683 the initial keymaps from the current buffer. */
8684 nmaps = 0;
8685
8686 if (!NILP (current_kboard->Voverriding_terminal_local_map)
8687 || !NILP (Voverriding_local_map))
8688 {
8689 if (3 > nmaps_allocated)
8690 {
8691 submaps = (Lisp_Object *) alloca (3 * sizeof (submaps[0]));
8692 defs = (Lisp_Object *) alloca (3 * sizeof (defs[0]));
8693 nmaps_allocated = 3;
8694 }
8695 if (!NILP (current_kboard->Voverriding_terminal_local_map))
8696 submaps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
8697 if (!NILP (Voverriding_local_map))
8698 submaps[nmaps++] = Voverriding_local_map;
8699 }
8700 else
8701 {
8702 int nminor;
8703 int total;
8704 Lisp_Object *maps;
8705
8706 nminor = current_minor_maps (0, &maps);
8707 total = nminor + (!NILP (orig_keymap) ? 3 : 2);
8708
8709 if (total > nmaps_allocated)
8710 {
8711 submaps = (Lisp_Object *) alloca (total * sizeof (submaps[0]));
8712 defs = (Lisp_Object *) alloca (total * sizeof (defs[0]));
8713 nmaps_allocated = total;
8714 }
8715
8716 if (!NILP (orig_keymap))
8717 submaps[nmaps++] = orig_keymap;
8718
8719 bcopy (maps, (void *) (submaps + nmaps),
8720 nminor * sizeof (submaps[0]));
8721
8722 nmaps += nminor;
8723
8724 submaps[nmaps++] = orig_local_map;
8725 }
8726 submaps[nmaps++] = current_global_map;
8727
8728 /* Find an accurate initial value for first_binding. */
8729 for (first_binding = 0; first_binding < nmaps; first_binding++)
8730 if (! NILP (submaps[first_binding]))
8731 break;
8732
8733 /* Start from the beginning in keybuf. */
8734 t = 0;
8735
8736 /* These are no-ops the first time through, but if we restart, they
8737 revert the echo area and this_command_keys to their original state. */
8738 this_command_key_count = keys_start;
8739 if (INTERACTIVE && t < mock_input)
8740 echo_truncate (echo_start);
8741
8742 /* If the best binding for the current key sequence is a keymap, or
8743 we may be looking at a function key's escape sequence, keep on
8744 reading. */
At conditional (1): "((first_binding < nmaps) ? ((*(submaps + (first_binding * 4)) != Qnil) ? 1 : (0)) : ((fkey).start < t || (keytran).start < t)) != 0" taking true path
8745 while (first_binding < nmaps
8746 /* Keep reading as long as there's a prefix binding. */
8747 ? !NILP (submaps[first_binding])
8748 /* Don't return in the middle of a possible function key sequence,
8749 if the only bindings we found were via case conversion.
8750 Thus, if ESC O a has a function-key-map translation
8751 and ESC o has a binding, don't return after ESC O,
8752 so that we can translate ESC O plus the next character. */
8753 : (fkey.start < t || keytran.start < t))
8754 {
8755 Lisp_Object key;
8756 int used_mouse_menu = 0;
8757
8758 /* Where the last real key started. If we need to throw away a
8759 key that has expanded into more than one element of keybuf
8760 (say, a mouse click on the mode line which is being treated
8761 as [mode-line (mouse-...)], then we backtrack to this point
8762 of keybuf. */
8763 volatile int last_real_key_start;
8764
8765 /* These variables are analogous to echo_start and keys_start;
8766 while those allow us to restart the entire key sequence,
8767 echo_local_start and keys_local_start allow us to throw away
8768 just one key. */
8769 volatile int echo_local_start, keys_local_start, local_first_binding;
8770
8771 eassert (fkey.end == t || (fkey.end > t && fkey.end <= mock_input));
8772 eassert (fkey.start <= fkey.end);
8773 eassert (keytran.start <= keytran.end);
8774 /* key-translation-map is applied *after* function-key-map. */
8775 eassert (keytran.end <= fkey.start);
8776
At conditional (2): "first_unbound < (fkey).start" taking true path
At conditional (3): "first_unbound < (keytran).start" taking false path
8777 if (first_unbound < fkey.start && first_unbound < keytran.start)
8778 { /* The prefix upto first_unbound has no binding and has
8779 no translation left to do either, so we know it's unbound.
8780 If we don't stop now, we risk staying here indefinitely
8781 (if the user keeps entering fkey or keytran prefixes
8782 like C-c ESC ESC ESC ESC ...) */
8783 int i;
8784 for (i = first_unbound + 1; i < t; i++)
8785 keybuf[i - first_unbound - 1] = keybuf[i];
8786 mock_input = t - first_unbound - 1;
8787 fkey.end = fkey.start -= first_unbound + 1;
8788 fkey.map = fkey.parent;
8789 keytran.end = keytran.start -= first_unbound + 1;
8790 keytran.map = keytran.parent;
8791 goto replay_sequence;
8792 }
8793
At conditional (4): "t >= bufsize" taking false path
8794 if (t >= bufsize)
8795 error ("Key sequence too long");
8796
At conditional (5): "Vexecuting_kbd_macro == Qnil" taking true path
At conditional (6): "noninteractive == 0" taking true path
8797 if (INTERACTIVE)
8798 echo_local_start = echo_length ();
8799 keys_local_start = this_command_key_count;
8800 local_first_binding = first_binding;
8801
8802 replay_key:
8803 /* These are no-ops, unless we throw away a keystroke below and
8804 jumped back up to replay_key; in that case, these restore the
8805 variables to their original state, allowing us to replay the
8806 loop. */
At conditional (7): "Vexecuting_kbd_macro == Qnil" taking true path
At conditional (8): "noninteractive == 0" taking true path
At conditional (9): "t < mock_input" taking false path
8807 if (INTERACTIVE && t < mock_input)
8808 echo_truncate (echo_local_start);
8809 this_command_key_count = keys_local_start;
8810 first_binding = local_first_binding;
8811
8812 /* By default, assume each event is "real". */
8813 last_real_key_start = t;
8814
8815 /* Does mock_input indicate that we are re-reading a key sequence? */
At conditional (10): "t < mock_input" taking false path
8816 if (t < mock_input)
8817 {
8818 key = keybuf[t];
8819 add_command_key (key);
8820 if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
8821 && NILP (Fzerop (Vecho_keystrokes)))
8822 echo_char (key);
8823 }
8824
8825 /* If not, we should actually read a character. */
8826 else
8827 {
8828 {
8829 #ifdef MULTI_KBOARD
8830 KBOARD *interrupted_kboard = current_kboard;
At conditional (11): "selected_frame & 7 == 4" taking true path
At conditional (12): "((0), (selected_frame & -8))->size & 1073742848 == 1073742848" taking true path
At conditional (13): "(((0), (selected_frame & -8))->output_data).nothing != 0" taking true path
8831 struct frame *interrupted_frame = SELECTED_FRAME ();
At conditional (14): "_setjmp != 0" taking false path
8832 if (setjmp (wrong_kboard_jmpbuf))
8833 {
8834 if (!NILP (delayed_switch_frame))
8835 {
8836 interrupted_kboard->kbd_queue
8837 = Fcons (delayed_switch_frame,
8838 interrupted_kboard->kbd_queue);
8839 delayed_switch_frame = Qnil;
8840 }
8841 while (t > 0)
8842 interrupted_kboard->kbd_queue
8843 = Fcons (keybuf[--t], interrupted_kboard->kbd_queue);
8844
8845 /* If the side queue is non-empty, ensure it begins with a
8846 switch-frame, so we'll replay it in the right context. */
8847 if (CONSP (interrupted_kboard->kbd_queue)
8848 && (key = XCAR (interrupted_kboard->kbd_queue),
8849 !(EVENT_HAS_PARAMETERS (key)
8850 && EQ (EVENT_HEAD_KIND (EVENT_HEAD (key)),
8851 Qswitch_frame))))
8852 {
8853 Lisp_Object frame;
8854 XSETFRAME (frame, interrupted_frame);
8855 interrupted_kboard->kbd_queue
8856 = Fcons (make_lispy_switch_frame (frame),
8857 interrupted_kboard->kbd_queue);
8858 }
8859 mock_input = 0;
8860 orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
8861 orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
8862 goto replay_sequence;
8863 }
8864 #endif
At conditional (15): "prompt == Qnil" taking false path
8865 key = read_char (NILP (prompt), nmaps,
8866 (Lisp_Object *) submaps, last_nonmenu_event,
8867 &used_mouse_menu);
8868 }
8869
8870 /* read_char returns t when it shows a menu and the user rejects it.
8871 Just return -1. */
At conditional (16): "key == Qt" taking false path
8872 if (EQ (key, Qt))
8873 {
8874 unbind_to (count, Qnil);
8875 UNGCPRO;
8876 return -1;
8877 }
8878
8879 /* read_char returns -1 at the end of a macro.
8880 Emacs 18 handles this by returning immediately with a
8881 zero, so that's what we'll do. */
At conditional (17): "key & 7 == 0" taking true path
At conditional (18): "key >> 3 == -1" taking true path
8882 if (INTEGERP (key) && XINT (key) == -1)
8883 {
8884 t = 0;
8885 /* The Microsoft C compiler can't handle the goto that
8886 would go here. */
8887 dummyflag = 1;
8888 break;
8889 }
8890
8891 /* If the current buffer has been changed from under us, the
8892 keymap may have changed, so replay the sequence. */
8893 if (BUFFERP (key))
8894 {
8895 timer_resume_idle ();
8896
8897 mock_input = t;
8898 /* Reset the current buffer from the selected window
8899 in case something changed the former and not the latter.
8900 This is to be more consistent with the behavior
8901 of the command_loop_1. */
8902 if (fix_current_buffer)
8903 {
8904 if (! FRAME_LIVE_P (XFRAME (selected_frame)))
8905 Fkill_emacs (Qnil);
8906 if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
8907 Fset_buffer (XWINDOW (selected_window)->buffer);
8908 }
8909
8910 orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
8911 orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
8912 goto replay_sequence;
8913 }
8914
8915 /* If we have a quit that was typed in another frame, and
8916 quit_throw_to_read_char switched buffers,
8917 replay to get the right keymap. */
8918 if (INTEGERP (key)
8919 && XINT (key) == quit_char
8920 && current_buffer != starting_buffer)
8921 {
8922 GROW_RAW_KEYBUF;
8923 XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
8924 keybuf[t++] = key;
8925 mock_input = t;
8926 Vquit_flag = Qnil;
8927 orig_local_map = get_local_map (PT, current_buffer, Qlocal_map);
8928 orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
8929 goto replay_sequence;
8930 }
8931
8932 Vquit_flag = Qnil;
8933
8934 if (EVENT_HAS_PARAMETERS (key)
8935 /* Either a `switch-frame' or a `select-window' event. */
8936 && EQ (EVENT_HEAD_KIND (EVENT_HEAD (key)), Qswitch_frame))
8937 {
8938 /* If we're at the beginning of a key sequence, and the caller
8939 says it's okay, go ahead and return this event. If we're
8940 in the midst of a key sequence, delay it until the end. */
8941 if (t > 0 || !can_return_switch_frame)
8942 {
8943 delayed_switch_frame = key;
8944 goto replay_key;
8945 }
8946 }
8947
8948 GROW_RAW_KEYBUF;
8949 XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
8950 }
8951
8952 /* Clicks in non-text areas get prefixed by the symbol
8953 in their CHAR-ADDRESS field. For example, a click on
8954 the mode line is prefixed by the symbol `mode-line'.
8955
8956 Furthermore, key sequences beginning with mouse clicks
8957 are read using the keymaps of the buffer clicked on, not
8958 the current buffer. So we may have to switch the buffer
8959 here.
8960
8961 When we turn one event into two events, we must make sure
8962 that neither of the two looks like the original--so that,
8963 if we replay the events, they won't be expanded again.
8964 If not for this, such reexpansion could happen either here
8965 or when user programs play with this-command-keys. */
8966 if (EVENT_HAS_PARAMETERS (key))
8967 {
8968 Lisp_Object kind;
8969 Lisp_Object string;
8970
8971 kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
8972 if (EQ (kind, Qmouse_click))
8973 {
8974 Lisp_Object window, posn;
8975
8976 window = POSN_WINDOW (EVENT_START (key));
8977 posn = POSN_POSN (EVENT_START (key));
8978
8979 if (CONSP (posn)
8980 || (!NILP (fake_prefixed_keys)
8981 && !NILP (Fmemq (key, fake_prefixed_keys))))
8982 {
8983 /* We're looking a second time at an event for which
8984 we generated a fake prefix key. Set
8985 last_real_key_start appropriately. */
8986 if (t > 0)
8987 last_real_key_start = t - 1;
8988 }
8989
8990 /* Key sequences beginning with mouse clicks are
8991 read using the keymaps in the buffer clicked on,
8992 not the current buffer. If we're at the
8993 beginning of a key sequence, switch buffers. */
8994 if (last_real_key_start == 0
8995 && WINDOWP (window)
8996 && BUFFERP (XWINDOW (window)->buffer)
8997 && XBUFFER (XWINDOW (window)->buffer) != current_buffer)
8998 {
8999 XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
9000 keybuf[t] = key;
9001 mock_input = t + 1;
9002
9003 /* Arrange to go back to the original buffer once we're
9004 done reading the key sequence. Note that we can't
9005 use save_excursion_{save,restore} here, because they
9006 save point as well as the current buffer; we don't
9007 want to save point, because redisplay may change it,
9008 to accommodate a Fset_window_start or something. We
9009 don't want to do this at the top of the function,
9010 because we may get input from a subprocess which
9011 wants to change the selected window and stuff (say,
9012 emacsclient). */
9013 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
9014
9015 if (! FRAME_LIVE_P (XFRAME (selected_frame)))
9016 Fkill_emacs (Qnil);
9017 set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
9018 orig_local_map = get_local_map (PT, current_buffer,
9019 Qlocal_map);
9020 orig_keymap = get_local_map (PT, current_buffer, Qkeymap);
9021 goto replay_sequence;
9022 }
9023
9024 /* For a mouse click, get the local text-property keymap
9025 of the place clicked on, rather than point. */
9026 if (last_real_key_start == 0
9027 && CONSP (XCDR (key))
9028 && ! localized_local_map)
9029 {
9030 Lisp_Object map_here, start, pos;
9031
9032 localized_local_map = 1;
9033 start = EVENT_START (key);
9034
9035 if (CONSP (start) && POSN_INBUFFER_P (start))
9036 {
9037 pos = POSN_BUFFER_POSN (start);
9038 if (INTEGERP (pos)
9039 && XINT (pos) >= BEG && XINT (pos) <= Z)
9040 {
9041 map_here = get_local_map (XINT (pos),
9042 current_buffer, Qlocal_map);
9043 if (!EQ (map_here, orig_local_map))
9044 {
9045 orig_local_map = map_here;
9046 keybuf[t] = key;
9047 mock_input = t + 1;
9048
9049 goto replay_sequence;
9050 }
9051 map_here = get_local_map (XINT (pos),
9052 current_buffer, Qkeymap);
9053 if (!EQ (map_here, orig_keymap))
9054 {
9055 orig_keymap = map_here;
9056 keybuf[t] = key;
9057 mock_input = t + 1;
9058
9059 goto replay_sequence;
9060 }
9061 }
9062 }
9063 }
9064
9065 /* Expand mode-line and scroll-bar events into two events:
9066 use posn as a fake prefix key. */
9067 if (SYMBOLP (posn)
9068 && (NILP (fake_prefixed_keys)
9069 || NILP (Fmemq (key, fake_prefixed_keys))))
9070 {
9071 if (t + 1 >= bufsize)
9072 error ("Key sequence too long");
9073
9074 keybuf[t] = posn;
9075 keybuf[t + 1] = key;
9076 mock_input = t + 2;
9077
9078 /* Record that a fake prefix key has been generated
9079 for KEY. Don't modify the event; this would
9080 prevent proper action when the event is pushed
9081 back into unread-command-events. */
9082 fake_prefixed_keys = Fcons (key, fake_prefixed_keys);
9083
9084 /* If on a mode line string with a local keymap,
9085 reconsider the key sequence with that keymap. */
9086 if (string = POSN_STRING (EVENT_START (key)),
9087 (CONSP (string) && STRINGP (XCAR (string))))
9088 {
9089 Lisp_Object pos, map, map2;
9090
9091 pos = XCDR (string);
9092 string = XCAR (string);
9093 if (XINT (pos) >= 0
9094 && XINT (pos) < SCHARS (string))
9095 {
9096 map = Fget_text_property (pos, Qlocal_map, string);
9097 if (!NILP (map))
9098 orig_local_map = map;
9099 map2 = Fget_text_property (pos, Qkeymap, string);
9100 if (!NILP (map2))
9101 orig_keymap = map2;
9102 if (!NILP (map) || !NILP (map2))
9103 goto replay_sequence;
9104 }
9105 }
9106
9107 goto replay_key;
9108 }
9109 else if (NILP (from_string)
9110 && (string = POSN_STRING (EVENT_START (key)),
9111 (CONSP (string) && STRINGP (XCAR (string)))))
9112 {
9113 /* For a click on a string, i.e. overlay string or a
9114 string displayed via the `display' property,
9115 consider `local-map' and `keymap' properties of
9116 that string. */
9117 Lisp_Object pos, map, map2;
9118
9119 pos = XCDR (string);
9120 string = XCAR (string);
9121 if (XINT (pos) >= 0
9122 && XINT (pos) < SCHARS (string))
9123 {
9124 map = Fget_text_property (pos, Qlocal_map, string);
9125 if (!NILP (map))
9126 orig_local_map = map;
9127 map2 = Fget_text_property (pos, Qkeymap, string);
9128 if (!NILP (map2))
9129 orig_keymap = map2;
9130
9131 if (!NILP (map) || !NILP (map2))
9132 {
9133 from_string = string;
9134 goto replay_sequence;
9135 }
9136 }
9137 }
9138 }
9139 else if (CONSP (XCDR (key))
9140 && CONSP (EVENT_START (key))
9141 && CONSP (XCDR (EVENT_START (key))))
9142 {
9143 Lisp_Object posn;
9144
9145 posn = POSN_POSN (EVENT_START (key));
9146 /* Handle menu-bar events:
9147 insert the dummy prefix event `menu-bar'. */
9148 if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
9149 {
9150 if (t + 1 >= bufsize)
9151 error ("Key sequence too long");
9152 keybuf[t] = posn;
9153 keybuf[t+1] = key;
9154
9155 /* Zap the position in key, so we know that we've
9156 expanded it, and don't try to do so again. */
9157 POSN_SET_POSN (EVENT_START (key),
9158 Fcons (posn, Qnil));
9159
9160 mock_input = t + 2;
9161 goto replay_sequence;
9162 }
9163 else if (CONSP (posn))
9164 {
9165 /* We're looking at the second event of a
9166 sequence which we expanded before. Set
9167 last_real_key_start appropriately. */
9168 if (last_real_key_start == t && t > 0)
9169 last_real_key_start = t - 1;
9170 }
9171 }
9172 }
9173
9174 /* We have finally decided that KEY is something we might want
9175 to look up. */
9176 first_binding = (follow_key (key,
9177 nmaps - first_binding,
9178 submaps + first_binding,
9179 defs + first_binding,
9180 submaps + first_binding)
9181 + first_binding);
9182
9183 /* If KEY wasn't bound, we'll try some fallbacks. */
9184 if (first_binding < nmaps)
9185 /* This is needed for the following scenario:
9186 event 0: a down-event that gets dropped by calling replay_key.
9187 event 1: some normal prefix like C-h.
9188 After event 0, first_unbound is 0, after event 1 fkey.start
9189 and keytran.start are both 1, so when we see that C-h is bound,
9190 we need to update first_unbound. */
9191 first_unbound = max (t + 1, first_unbound);
9192 else
9193 {
9194 Lisp_Object head;
9195
9196 /* Remember the position to put an upper bound on fkey.start. */
9197 first_unbound = min (t, first_unbound);
9198
9199 head = EVENT_HEAD (key);
9200 if (help_char_p (head) && t > 0)
9201 {
9202 read_key_sequence_cmd = Vprefix_help_command;
9203 keybuf[t++] = key;
9204 last_nonmenu_event = key;
9205 /* The Microsoft C compiler can't handle the goto that
9206 would go here. */
9207 dummyflag = 1;
9208 break;
9209 }
9210
9211 if (SYMBOLP (head))
9212 {
9213 Lisp_Object breakdown;
9214 int modifiers;
9215
9216 breakdown = parse_modifiers (head);
9217 modifiers = XINT (XCAR (XCDR (breakdown)));
9218 /* Attempt to reduce an unbound mouse event to a simpler
9219 event that is bound:
9220 Drags reduce to clicks.
9221 Double-clicks reduce to clicks.
9222 Triple-clicks reduce to double-clicks, then to clicks.
9223 Down-clicks are eliminated.
9224 Double-downs reduce to downs, then are eliminated.
9225 Triple-downs reduce to double-downs, then to downs,
9226 then are eliminated. */
9227 if (modifiers & (down_modifier | drag_modifier
9228 | double_modifier | triple_modifier))
9229 {
9230 while (modifiers & (down_modifier | drag_modifier
9231 | double_modifier | triple_modifier))
9232 {
9233 Lisp_Object new_head, new_click;
9234 if (modifiers & triple_modifier)
9235 modifiers ^= (double_modifier | triple_modifier);
9236 else if (modifiers & double_modifier)
9237 modifiers &= ~double_modifier;
9238 else if (modifiers & drag_modifier)
9239 modifiers &= ~drag_modifier;
9240 else
9241 {
9242 /* Dispose of this `down' event by simply jumping
9243 back to replay_key, to get another event.
9244
9245 Note that if this event came from mock input,
9246 then just jumping back to replay_key will just
9247 hand it to us again. So we have to wipe out any
9248 mock input.
9249
9250 We could delete keybuf[t] and shift everything
9251 after that to the left by one spot, but we'd also
9252 have to fix up any variable that points into
9253 keybuf, and shifting isn't really necessary
9254 anyway.
9255
9256 Adding prefixes for non-textual mouse clicks
9257 creates two characters of mock input, and both
9258 must be thrown away. If we're only looking at
9259 the prefix now, we can just jump back to
9260 replay_key. On the other hand, if we've already
9261 processed the prefix, and now the actual click
9262 itself is giving us trouble, then we've lost the
9263 state of the keymaps we want to backtrack to, and
9264 we need to replay the whole sequence to rebuild
9265 it.
9266
9267 Beyond that, only function key expansion could
9268 create more than two keys, but that should never
9269 generate mouse events, so it's okay to zero
9270 mock_input in that case too.
9271
9272 FIXME: The above paragraph seems just plain
9273 wrong, if you consider things like
9274 xterm-mouse-mode. -stef
9275
9276 Isn't this just the most wonderful code ever? */
9277
9278 /* If mock_input > t + 1, the above simplification
9279 will actually end up dropping keys on the floor.
9280 This is probably OK for now, but even
9281 if mock_input <= t + 1, we need to adjust fkey
9282 and keytran.
9283 Typical case [header-line down-mouse-N]:
9284 mock_input = 2, t = 1, fkey.end = 1,
9285 last_real_key_start = 0. */
9286 if (fkey.end > last_real_key_start)
9287 {
9288 fkey.end = fkey.start
9289 = min (last_real_key_start, fkey.start);
9290 fkey.map = fkey.parent;
9291 if (keytran.end > last_real_key_start)
9292 {
9293 keytran.end = keytran.start
9294 = min (last_real_key_start, keytran.start);
9295 keytran.map = keytran.parent;
9296 }
9297 }
9298 if (t == last_real_key_start)
9299 {
9300 mock_input = 0;
9301 goto replay_key;
9302 }
9303 else
9304 {
9305 mock_input = last_real_key_start;
9306 goto replay_sequence;
9307 }
9308 }
9309
9310 new_head
9311 = apply_modifiers (modifiers, XCAR (breakdown));
9312 new_click
9313 = Fcons (new_head, Fcons (EVENT_START (key), Qnil));
9314
9315 /* Look for a binding for this new key. follow_key
9316 promises that it didn't munge submaps the
9317 last time we called it, since key was unbound. */
9318 first_binding
9319 = (follow_key (new_click,
9320 nmaps - local_first_binding,
9321 submaps + local_first_binding,
9322 defs + local_first_binding,
9323 submaps + local_first_binding)
9324 + local_first_binding);
9325
9326 /* If that click is bound, go for it. */
9327 if (first_binding < nmaps)
9328 {
9329 key = new_click;
9330 break;
9331 }
9332 /* Otherwise, we'll leave key set to the drag event. */
9333 }
9334 }
9335 }
9336 }
9337
9338 keybuf[t++] = key;
9339 /* Normally, last_nonmenu_event gets the previous key we read.
9340 But when a mouse popup menu is being used,
9341 we don't update last_nonmenu_event; it continues to hold the mouse
9342 event that preceded the first level of menu. */
9343 if (!used_mouse_menu)
9344 last_nonmenu_event = key;
9345
9346 /* Record what part of this_command_keys is the current key sequence. */
9347 this_single_command_key_start = this_command_key_count - t;
9348
9349 if (first_binding < nmaps && NILP (submaps[first_binding]))
9350 /* There is a binding and it's not a prefix.
9351 There is thus no function-key in this sequence.
9352 Moving fkey.start is important in this case to allow keytran.start
9353 to go over the sequence before we return (since we keep the
9354 invariant that keytran.end <= fkey.start). */
9355 {
9356 if (fkey.start < t)
9357 (fkey.start = fkey.end = t, fkey.map = fkey.parent);
9358 }
9359 else
9360 /* If the sequence is unbound, see if we can hang a function key
9361 off the end of it. */
9362 /* Continue scan from fkey.end until we find a bound suffix. */
9363 while (fkey.end < t)
9364 {
9365 struct gcpro gcpro1, gcpro2, gcpro3;
9366 int done, diff;
9367
9368 GCPRO3 (fkey.map, keytran.map, delayed_switch_frame);
9369 done = keyremap_step (keybuf, bufsize, &fkey,
9370 max (t, mock_input),
9371 /* If there's a binding (i.e.
9372 first_binding >= nmaps) we don't want
9373 to apply this function-key-mapping. */
9374 fkey.end + 1 == t && first_binding >= nmaps,
9375 &diff, prompt);
9376 UNGCPRO;
9377 if (done)
9378 {
9379 mock_input = diff + max (t, mock_input);
9380 goto replay_sequence;
9381 }
9382 }
9383
9384 /* Look for this sequence in key-translation-map.
9385 Scan from keytran.end until we find a bound suffix. */
9386 while (keytran.end < fkey.start)
9387 {
9388 struct gcpro gcpro1, gcpro2, gcpro3;
9389 int done, diff;
9390
9391 GCPRO3 (fkey.map, keytran.map, delayed_switch_frame);
9392 done = keyremap_step (keybuf, bufsize, &keytran, max (t, mock_input),
9393 1, &diff, prompt);
9394 UNGCPRO;
9395 if (done)
9396 {
9397 mock_input = diff + max (t, mock_input);
9398 /* Adjust the function-key-map counters. */
9399 fkey.end += diff;
9400 fkey.start += diff;
9401
9402 goto replay_sequence;
9403 }
9404 }
9405
9406 /* If KEY is not defined in any of the keymaps,
9407 and cannot be part of a function key or translation,
9408 and is an upper case letter
9409 use the corresponding lower-case letter instead. */
9410 if (first_binding >= nmaps
9411 && fkey.start >= t && keytran.start >= t
9412 && INTEGERP (key)
9413 && ((((XINT (key) & 0x3ffff)
9414 < XCHAR_TABLE (current_buffer->downcase_table)->size)
9415 && UPPERCASEP (XINT (key) & 0x3ffff))
9416 || (XINT (key) & shift_modifier)))
9417 {
9418 Lisp_Object new_key;
9419
9420 original_uppercase = key;
9421 original_uppercase_position = t - 1;
9422
9423 if (XINT (key) & shift_modifier)
9424 XSETINT (new_key, XINT (key) & ~shift_modifier);
9425 else
9426 XSETINT (new_key, (DOWNCASE (XINT (key) & 0x3ffff)
9427 | (XINT (key) & ~0x3ffff)));
9428
9429 /* We have to do this unconditionally, regardless of whether
9430 the lower-case char is defined in the keymaps, because they
9431 might get translated through function-key-map. */
9432 keybuf[t - 1] = new_key;
9433 mock_input = max (t, mock_input);
9434
9435 goto replay_sequence;
9436 }
9437 /* If KEY is not defined in any of the keymaps,
9438 and cannot be part of a function key or translation,
9439 and is a shifted function key,
9440 use the corresponding unshifted function key instead. */
9441 if (first_binding >= nmaps
9442 && fkey.start >= t && keytran.start >= t
9443 && SYMBOLP (key))
9444 {
9445 Lisp_Object breakdown;
9446 int modifiers;
9447
9448 breakdown = parse_modifiers (key);
9449 modifiers = XINT (XCAR (XCDR (breakdown)));
9450 if (modifiers & shift_modifier)
9451 {
9452 Lisp_Object new_key;
9453
9454 original_uppercase = key;
9455 original_uppercase_position = t - 1;
9456
9457 modifiers &= ~shift_modifier;
9458 new_key = apply_modifiers (modifiers,
9459 XCAR (breakdown));
9460
9461 keybuf[t - 1] = new_key;
9462 mock_input = max (t, mock_input);
9463 fkey.start = fkey.end = KEYMAPP (fkey.map) ? 0 : bufsize + 1;
9464 keytran.start = keytran.end = KEYMAPP (keytran.map) ? 0 : bufsize + 1;
9465
9466 goto replay_sequence;
9467 }
9468 }
9469 }
9470
At conditional (19): "dummyflag == 0" taking false path
9471 if (!dummyflag)
9472 read_key_sequence_cmd = (first_binding < nmaps
9473 ? defs[first_binding]
9474 : Qnil);
9475
9476 unread_switch_frame = delayed_switch_frame;
9477 unbind_to (count, Qnil);
9478
9479 /* Don't downcase the last character if the caller says don't.
9480 Don't downcase it if the result is undefined, either. */
At conditional (20): "dont_downcase_last != 0" taking true path
At conditional (21): "(t - 1) == original_uppercase_position" taking true path
9481 if ((dont_downcase_last || first_binding >= nmaps)
9482 && t - 1 == original_uppercase_position)
Event uninit_use: Using uninitialized value "original_uppercase"
Also see events: [var_decl]
9483 keybuf[t - 1] = original_uppercase;
9484
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Problem report #60
2006-04-11 15:48 Problem report #60 Dan Nicolaescu
@ 2006-04-11 17:54 ` Stuart D. Herring
2006-04-11 18:02 ` David Kastrup
2006-04-12 17:10 ` Richard Stallman
0 siblings, 2 replies; 6+ messages in thread
From: Stuart D. Herring @ 2006-04-11 17:54 UTC (permalink / raw
> 8608 volatile Lisp_Object original_uppercase;
> 8609 volatile int original_uppercase_position = -1;
> [...]
original_uppercase_position remains -1 if original_uppercase is
uninitialized.
> At conditional (20): "dont_downcase_last != 0" taking true path
> At conditional (21): "(t - 1) == original_uppercase_position" taking true
> path
>
> 9481 if ((dont_downcase_last || first_binding >= nmaps)
> 9482 && t - 1 == original_uppercase_position)
Assuming that t!=0, t-1==original_uppercase_position implies that the o_u
variables were set.
> Event uninit_use: Using uninitialized value "original_uppercase"
> Also see events: [var_decl]
>
> 9483 keybuf[t - 1] = original_uppercase;
> 9484
So this is fine. It'd be a big bug if t were 0, though, indexing at -1
like that. Looking back up, it seems that if the while loop iterates even
once, t is > 0, but what if the while test fails the first time? It looks
like t would be 0, and original_uppercase_position would still be -1, and
uninitialized data would be stored outside of an array. Nasty, if it can
happen. Otherwise, no bug.
Davis
--
This product is sold by volume, not by mass. If it appears too dense or
too sparse, it is because mass-energy conversion has occurred during
shipping.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Problem report #60
2006-04-11 17:54 ` Stuart D. Herring
@ 2006-04-11 18:02 ` David Kastrup
2006-04-12 17:10 ` Richard Stallman
1 sibling, 0 replies; 6+ messages in thread
From: David Kastrup @ 2006-04-11 18:02 UTC (permalink / raw
Cc: emacs-devel
"Stuart D. Herring" <herring@lanl.gov> writes:
>> 8608 volatile Lisp_Object original_uppercase;
>> 8609 volatile int original_uppercase_position = -1;
>> [...]
>
> original_uppercase_position remains -1 if original_uppercase is
> uninitialized.
>
>> At conditional (20): "dont_downcase_last != 0" taking true path
>> At conditional (21): "(t - 1) == original_uppercase_position" taking true
>> path
>>
>> 9481 if ((dont_downcase_last || first_binding >= nmaps)
>> 9482 && t - 1 == original_uppercase_position)
>
> Assuming that t!=0, t-1==original_uppercase_position implies that the o_u
> variables were set.
>
>> Event uninit_use: Using uninitialized value "original_uppercase"
>> Also see events: [var_decl]
>>
>> 9483 keybuf[t - 1] = original_uppercase;
>> 9484
>
> So this is fine. It'd be a big bug if t were 0, though, indexing at -1
> like that. Looking back up, it seems that if the while loop iterates even
> once, t is > 0, but what if the while test fails the first time? It looks
> like t would be 0, and original_uppercase_position would still be -1, and
> uninitialized data would be stored outside of an array. Nasty, if it can
> happen. Otherwise, no bug.
Then this should not be written as
while (condition)
{ body
}
but rather
assert(condition);
do { body
} while (condition);
--
David Kastrup, Kriemhildstr. 15, 44793 Bochum
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Problem report #60
2006-04-11 17:54 ` Stuart D. Herring
2006-04-11 18:02 ` David Kastrup
@ 2006-04-12 17:10 ` Richard Stallman
2006-04-12 17:29 ` Stuart D. Herring
1 sibling, 1 reply; 6+ messages in thread
From: Richard Stallman @ 2006-04-12 17:10 UTC (permalink / raw
Cc: emacs-devel
So this is fine. It'd be a big bug if t were 0, though, indexing at -1
like that. Looking back up, it seems that if the while loop iterates even
once, t is > 0, but what if the while test fails the first time?
Which while test is that? Which line number?
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Problem report #60
2006-04-12 17:10 ` Richard Stallman
@ 2006-04-12 17:29 ` Stuart D. Herring
2006-04-13 3:20 ` Richard Stallman
0 siblings, 1 reply; 6+ messages in thread
From: Stuart D. Herring @ 2006-04-12 17:29 UTC (permalink / raw
Cc: emacs-devel
> So this is fine. It'd be a big bug if t were 0, though, indexing at
> -1
> like that. Looking back up, it seems that if the while loop iterates
> even
> once, t is > 0, but what if the while test fails the first time?
>
> Which while test is that? Which line number?
The while test starts at like 8745 in the problem report (the loop ends at
line 9469). t is incremented unconditionally at line 9338, and the
dangerous indexing/use is at line 9483.
Davis
--
This product is sold by volume, not by mass. If it appears too dense or
too sparse, it is because mass-energy conversion has occurred during
shipping.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Problem report #60
2006-04-12 17:29 ` Stuart D. Herring
@ 2006-04-13 3:20 ` Richard Stallman
0 siblings, 0 replies; 6+ messages in thread
From: Richard Stallman @ 2006-04-13 3:20 UTC (permalink / raw
Cc: emacs-devel
I concluded this bug can really happen, and added a simple
conditional to fix it.
Thanks.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2006-04-13 3:20 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-04-11 15:48 Problem report #60 Dan Nicolaescu
2006-04-11 17:54 ` Stuart D. Herring
2006-04-11 18:02 ` David Kastrup
2006-04-12 17:10 ` Richard Stallman
2006-04-12 17:29 ` Stuart D. Herring
2006-04-13 3:20 ` Richard Stallman
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).