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