1 /* parens.c -- implementation of matching parentheses feature. */ 2 3 /* Copyright (C) 1987, 1989, 1992-2009 Free Software Foundation, Inc. 4 5 This file is part of the GNU Readline Library (Readline), a library 6 for reading lines of text with interactive input and history editing. 7 8 Readline is free software: you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation, either version 3 of the License, or 11 (at your option) any later version. 12 13 Readline is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with Readline. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 #define READLINE_LIBRARY 23 24 #if defined (__TANDEM) 25 # include <floss.h> 26 #endif 27 28 #include "rlconf.h" 29 30 #if defined (HAVE_CONFIG_H) 31 # include <config.h> 32 #endif 33 34 #include <stdio.h> 35 #include <sys/types.h> 36 37 #if defined (HAVE_UNISTD_H) 38 # include <unistd.h> 39 #endif 40 41 #include "posixselect.h" 42 43 #if defined (HAVE_STRING_H) 44 # include <string.h> 45 #else /* !HAVE_STRING_H */ 46 # include <strings.h> 47 #endif /* !HAVE_STRING_H */ 48 49 #if !defined (strchr) && !defined (__STDC__) 50 extern char *strchr (), *strrchr (); 51 #endif /* !strchr && !__STDC__ */ 52 53 #include "readline.h" 54 #include "rlprivate.h" 55 56 static int find_matching_open PARAMS((char *, int, int)); 57 58 /* Non-zero means try to blink the matching open parenthesis when the 59 close parenthesis is inserted. */ 60 #if defined (HAVE_SELECT) 61 int rl_blink_matching_paren = 1; 62 #else /* !HAVE_SELECT */ 63 int rl_blink_matching_paren = 0; 64 #endif /* !HAVE_SELECT */ 65 66 static int _paren_blink_usec = 500000; 67 68 /* Change emacs_standard_keymap to have bindings for paren matching when 69 ON_OR_OFF is 1, change them back to self_insert when ON_OR_OFF == 0. */ 70 void 71 _rl_enable_paren_matching (on_or_off) 72 int on_or_off; 73 { 74 if (on_or_off) 75 { /* ([{ */ 76 rl_bind_key_in_map (')', rl_insert_close, emacs_standard_keymap); 77 rl_bind_key_in_map (']', rl_insert_close, emacs_standard_keymap); 78 rl_bind_key_in_map ('}', rl_insert_close, emacs_standard_keymap); 79 } 80 else 81 { /* ([{ */ 82 rl_bind_key_in_map (')', rl_insert, emacs_standard_keymap); 83 rl_bind_key_in_map (']', rl_insert, emacs_standard_keymap); 84 rl_bind_key_in_map ('}', rl_insert, emacs_standard_keymap); 85 } 86 } 87 88 int 89 rl_set_paren_blink_timeout (u) 90 int u; 91 { 92 int o; 93 94 o = _paren_blink_usec; 95 if (u > 0) 96 _paren_blink_usec = u; 97 return (o); 98 } 99 100 int 101 rl_insert_close (count, invoking_key) 102 int count, invoking_key; 103 { 104 if (rl_explicit_arg || !rl_blink_matching_paren) 105 _rl_insert_char (count, invoking_key); 106 else 107 { 108 #if defined (HAVE_SELECT) 109 int orig_point, match_point, ready; 110 struct timeval timer; 111 fd_set readfds; 112 113 _rl_insert_char (1, invoking_key); 114 (*rl_redisplay_function) (); 115 match_point = 116 find_matching_open (rl_line_buffer, rl_point - 2, invoking_key); 117 118 /* Emacs might message or ring the bell here, but I don't. */ 119 if (match_point < 0) 120 return -1; 121 122 FD_ZERO (&readfds); 123 FD_SET (fileno (rl_instream), &readfds); 124 USEC_TO_TIMEVAL (_paren_blink_usec, timer); 125 126 orig_point = rl_point; 127 rl_point = match_point; 128 (*rl_redisplay_function) (); 129 ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer); 130 rl_point = orig_point; 131 #else /* !HAVE_SELECT */ 132 _rl_insert_char (count, invoking_key); 133 #endif /* !HAVE_SELECT */ 134 } 135 return 0; 136 } 137 138 static int 139 find_matching_open (string, from, closer) 140 char *string; 141 int from, closer; 142 { 143 register int i; 144 int opener, level, delimiter; 145 146 switch (closer) 147 { 148 case ']': opener = '['; break; 149 case '}': opener = '{'; break; 150 case ')': opener = '('; break; 151 default: 152 return (-1); 153 } 154 155 level = 1; /* The closer passed in counts as 1. */ 156 delimiter = 0; /* Delimited state unknown. */ 157 158 for (i = from; i > -1; i--) 159 { 160 if (delimiter && (string[i] == delimiter)) 161 delimiter = 0; 162 else if (rl_basic_quote_characters && strchr (rl_basic_quote_characters, string[i])) 163 delimiter = string[i]; 164 else if (!delimiter && (string[i] == closer)) 165 level++; 166 else if (!delimiter && (string[i] == opener)) 167 level--; 168 169 if (!level) 170 break; 171 } 172 return (i); 173 } 174