xref: /openbsd-src/gnu/lib/libreadline/parens.c (revision 15b117eae8ea0caffec2fbd5cbd366a5ccee20ab)
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