11acd27e7Smillert /* parens.c -- Implementation of matching parentheses feature. */
21acd27e7Smillert
31acd27e7Smillert /* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
41acd27e7Smillert
51acd27e7Smillert This file is part of the GNU Readline Library, a library for
61acd27e7Smillert reading lines of text with interactive input and history editing.
71acd27e7Smillert
81acd27e7Smillert The GNU Readline Library is free software; you can redistribute it
91acd27e7Smillert and/or modify it under the terms of the GNU General Public License
101acd27e7Smillert as published by the Free Software Foundation; either version 2, or
111acd27e7Smillert (at your option) any later version.
121acd27e7Smillert
131acd27e7Smillert The GNU Readline Library is distributed in the hope that it will be
141acd27e7Smillert useful, but WITHOUT ANY WARRANTY; without even the implied warranty
151acd27e7Smillert of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
161acd27e7Smillert GNU General Public License for more details.
171acd27e7Smillert
181acd27e7Smillert The GNU General Public License is often shipped with GNU software, and
191acd27e7Smillert is generally kept in a file called COPYING or LICENSE. If you do not
201acd27e7Smillert have a copy of the license, write to the Free Software Foundation,
211acd27e7Smillert 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
221acd27e7Smillert #define READLINE_LIBRARY
231acd27e7Smillert
241acd27e7Smillert #include "rlconf.h"
251acd27e7Smillert
261acd27e7Smillert #if defined (HAVE_CONFIG_H)
271acd27e7Smillert # include <config.h>
281acd27e7Smillert #endif
291acd27e7Smillert
301acd27e7Smillert #include <stdio.h>
311acd27e7Smillert #include <sys/types.h>
321acd27e7Smillert
33*15b117eaSkettenis #if defined (HAVE_UNISTD_H)
34*15b117eaSkettenis # include <unistd.h>
35*15b117eaSkettenis #endif
36*15b117eaSkettenis
371acd27e7Smillert #if defined (FD_SET) && !defined (HAVE_SELECT)
381acd27e7Smillert # define HAVE_SELECT
391acd27e7Smillert #endif
401acd27e7Smillert
411acd27e7Smillert #if defined (HAVE_SELECT)
421acd27e7Smillert # include <sys/time.h>
431acd27e7Smillert #endif /* HAVE_SELECT */
441acd27e7Smillert #if defined (HAVE_SYS_SELECT_H)
451acd27e7Smillert # include <sys/select.h>
461acd27e7Smillert #endif
471acd27e7Smillert
481acd27e7Smillert #if defined (HAVE_STRING_H)
491acd27e7Smillert # include <string.h>
501acd27e7Smillert #else /* !HAVE_STRING_H */
511acd27e7Smillert # include <strings.h>
521acd27e7Smillert #endif /* !HAVE_STRING_H */
531acd27e7Smillert
541acd27e7Smillert #if !defined (strchr) && !defined (__STDC__)
551acd27e7Smillert extern char *strchr (), *strrchr ();
561acd27e7Smillert #endif /* !strchr && !__STDC__ */
571acd27e7Smillert
581acd27e7Smillert #include "readline.h"
591acd27e7Smillert #include "rlprivate.h"
601acd27e7Smillert
61*15b117eaSkettenis static int find_matching_open PARAMS((char *, int, int));
621acd27e7Smillert
631acd27e7Smillert /* Non-zero means try to blink the matching open parenthesis when the
641acd27e7Smillert close parenthesis is inserted. */
651acd27e7Smillert #if defined (HAVE_SELECT)
661acd27e7Smillert int rl_blink_matching_paren = 1;
671acd27e7Smillert #else /* !HAVE_SELECT */
681acd27e7Smillert int rl_blink_matching_paren = 0;
691acd27e7Smillert #endif /* !HAVE_SELECT */
701acd27e7Smillert
71*15b117eaSkettenis static int _paren_blink_usec = 500000;
72*15b117eaSkettenis
731acd27e7Smillert /* Change emacs_standard_keymap to have bindings for paren matching when
741acd27e7Smillert ON_OR_OFF is 1, change them back to self_insert when ON_OR_OFF == 0. */
751acd27e7Smillert void
_rl_enable_paren_matching(on_or_off)761acd27e7Smillert _rl_enable_paren_matching (on_or_off)
771acd27e7Smillert int on_or_off;
781acd27e7Smillert {
791acd27e7Smillert if (on_or_off)
801acd27e7Smillert { /* ([{ */
811acd27e7Smillert rl_bind_key_in_map (')', rl_insert_close, emacs_standard_keymap);
821acd27e7Smillert rl_bind_key_in_map (']', rl_insert_close, emacs_standard_keymap);
831acd27e7Smillert rl_bind_key_in_map ('}', rl_insert_close, emacs_standard_keymap);
841acd27e7Smillert }
851acd27e7Smillert else
861acd27e7Smillert { /* ([{ */
871acd27e7Smillert rl_bind_key_in_map (')', rl_insert, emacs_standard_keymap);
881acd27e7Smillert rl_bind_key_in_map (']', rl_insert, emacs_standard_keymap);
891acd27e7Smillert rl_bind_key_in_map ('}', rl_insert, emacs_standard_keymap);
901acd27e7Smillert }
911acd27e7Smillert }
921acd27e7Smillert
931acd27e7Smillert int
rl_set_paren_blink_timeout(u)94*15b117eaSkettenis rl_set_paren_blink_timeout (u)
95*15b117eaSkettenis int u;
96*15b117eaSkettenis {
97*15b117eaSkettenis int o;
98*15b117eaSkettenis
99*15b117eaSkettenis o = _paren_blink_usec;
100*15b117eaSkettenis if (u > 0)
101*15b117eaSkettenis _paren_blink_usec = u;
102*15b117eaSkettenis return (o);
103*15b117eaSkettenis }
104*15b117eaSkettenis
105*15b117eaSkettenis int
rl_insert_close(count,invoking_key)1061acd27e7Smillert rl_insert_close (count, invoking_key)
1071acd27e7Smillert int count, invoking_key;
1081acd27e7Smillert {
1091acd27e7Smillert if (rl_explicit_arg || !rl_blink_matching_paren)
110*15b117eaSkettenis _rl_insert_char (count, invoking_key);
1111acd27e7Smillert else
1121acd27e7Smillert {
1131acd27e7Smillert #if defined (HAVE_SELECT)
1141acd27e7Smillert int orig_point, match_point, ready;
1151acd27e7Smillert struct timeval timer;
1161acd27e7Smillert fd_set readfds;
1171acd27e7Smillert
118*15b117eaSkettenis _rl_insert_char (1, invoking_key);
1191acd27e7Smillert (*rl_redisplay_function) ();
1201acd27e7Smillert match_point =
1211acd27e7Smillert find_matching_open (rl_line_buffer, rl_point - 2, invoking_key);
1221acd27e7Smillert
1231acd27e7Smillert /* Emacs might message or ring the bell here, but I don't. */
1241acd27e7Smillert if (match_point < 0)
1251acd27e7Smillert return -1;
1261acd27e7Smillert
1271acd27e7Smillert FD_ZERO (&readfds);
1281acd27e7Smillert FD_SET (fileno (rl_instream), &readfds);
1291acd27e7Smillert timer.tv_sec = 0;
130*15b117eaSkettenis timer.tv_usec = _paren_blink_usec;
1311acd27e7Smillert
1321acd27e7Smillert orig_point = rl_point;
1331acd27e7Smillert rl_point = match_point;
1341acd27e7Smillert (*rl_redisplay_function) ();
1351acd27e7Smillert ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer);
1361acd27e7Smillert rl_point = orig_point;
1371acd27e7Smillert #else /* !HAVE_SELECT */
138*15b117eaSkettenis _rl_insert_char (count, invoking_key);
1391acd27e7Smillert #endif /* !HAVE_SELECT */
1401acd27e7Smillert }
1411acd27e7Smillert return 0;
1421acd27e7Smillert }
1431acd27e7Smillert
1441acd27e7Smillert static int
find_matching_open(string,from,closer)1451acd27e7Smillert find_matching_open (string, from, closer)
1461acd27e7Smillert char *string;
1471acd27e7Smillert int from, closer;
1481acd27e7Smillert {
1491acd27e7Smillert register int i;
1501acd27e7Smillert int opener, level, delimiter;
1511acd27e7Smillert
1521acd27e7Smillert switch (closer)
1531acd27e7Smillert {
1541acd27e7Smillert case ']': opener = '['; break;
1551acd27e7Smillert case '}': opener = '{'; break;
1561acd27e7Smillert case ')': opener = '('; break;
1571acd27e7Smillert default:
1581acd27e7Smillert return (-1);
1591acd27e7Smillert }
1601acd27e7Smillert
1611acd27e7Smillert level = 1; /* The closer passed in counts as 1. */
1621acd27e7Smillert delimiter = 0; /* Delimited state unknown. */
1631acd27e7Smillert
1641acd27e7Smillert for (i = from; i > -1; i--)
1651acd27e7Smillert {
1661acd27e7Smillert if (delimiter && (string[i] == delimiter))
1671acd27e7Smillert delimiter = 0;
1681acd27e7Smillert else if (rl_basic_quote_characters && strchr (rl_basic_quote_characters, string[i]))
1691acd27e7Smillert delimiter = string[i];
1701acd27e7Smillert else if (!delimiter && (string[i] == closer))
1711acd27e7Smillert level++;
1721acd27e7Smillert else if (!delimiter && (string[i] == opener))
1731acd27e7Smillert level--;
1741acd27e7Smillert
1751acd27e7Smillert if (!level)
1761acd27e7Smillert break;
1771acd27e7Smillert }
1781acd27e7Smillert return (i);
1791acd27e7Smillert }
180