121308Sache/* parens.c -- Implementation of matching parentheses feature. */
221308Sache
321308Sache/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
421308Sache
521308Sache   This file is part of the GNU Readline Library, a library for
621308Sache   reading lines of text with interactive input and history editing.
721308Sache
821308Sache   The GNU Readline Library is free software; you can redistribute it
921308Sache   and/or modify it under the terms of the GNU General Public License
1058310Sache   as published by the Free Software Foundation; either version 2, or
1121308Sache   (at your option) any later version.
1221308Sache
1321308Sache   The GNU Readline Library is distributed in the hope that it will be
1421308Sache   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
1521308Sache   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1621308Sache   GNU General Public License for more details.
1721308Sache
1821308Sache   The GNU General Public License is often shipped with GNU software, and
1921308Sache   is generally kept in a file called COPYING or LICENSE.  If you do not
2021308Sache   have a copy of the license, write to the Free Software Foundation,
2158310Sache   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
2221308Sache#define READLINE_LIBRARY
2321308Sache
24136644Sache#if defined (__TANDEM)
25136644Sache#  include <floss.h>
26136644Sache#endif
27136644Sache
2821308Sache#include "rlconf.h"
2921308Sache
3021308Sache#if defined (HAVE_CONFIG_H)
3121308Sache#  include <config.h>
3221308Sache#endif
3321308Sache
3421308Sache#include <stdio.h>
3521308Sache#include <sys/types.h>
3621308Sache
37119610Sache#if defined (HAVE_UNISTD_H)
38119610Sache#  include <unistd.h>
39119610Sache#endif
40119610Sache
4121308Sache#if defined (FD_SET) && !defined (HAVE_SELECT)
4221308Sache#  define HAVE_SELECT
4321308Sache#endif
4421308Sache
4521308Sache#if defined (HAVE_SELECT)
4621308Sache#  include <sys/time.h>
4721308Sache#endif /* HAVE_SELECT */
4821308Sache#if defined (HAVE_SYS_SELECT_H)
4921308Sache#  include <sys/select.h>
5021308Sache#endif
5121308Sache
5221308Sache#if defined (HAVE_STRING_H)
5321308Sache#  include <string.h>
5421308Sache#else /* !HAVE_STRING_H */
5521308Sache#  include <strings.h>
5621308Sache#endif /* !HAVE_STRING_H */
5721308Sache
5821308Sache#if !defined (strchr) && !defined (__STDC__)
5921308Sacheextern char *strchr (), *strrchr ();
6021308Sache#endif /* !strchr && !__STDC__ */
6121308Sache
6221308Sache#include "readline.h"
6358310Sache#include "rlprivate.h"
6421308Sache
65119610Sachestatic int find_matching_open PARAMS((char *, int, int));
6621308Sache
6721308Sache/* Non-zero means try to blink the matching open parenthesis when the
6821308Sache   close parenthesis is inserted. */
6921308Sache#if defined (HAVE_SELECT)
7021308Sacheint rl_blink_matching_paren = 1;
7121308Sache#else /* !HAVE_SELECT */
7221308Sacheint rl_blink_matching_paren = 0;
7321308Sache#endif /* !HAVE_SELECT */
7421308Sache
7575406Sachestatic int _paren_blink_usec = 500000;
7675406Sache
7758310Sache/* Change emacs_standard_keymap to have bindings for paren matching when
7858310Sache   ON_OR_OFF is 1, change them back to self_insert when ON_OR_OFF == 0. */
7958310Sachevoid
8058310Sache_rl_enable_paren_matching (on_or_off)
8158310Sache     int on_or_off;
8258310Sache{
8358310Sache  if (on_or_off)
8458310Sache    {	/* ([{ */
8558310Sache      rl_bind_key_in_map (')', rl_insert_close, emacs_standard_keymap);
8658310Sache      rl_bind_key_in_map (']', rl_insert_close, emacs_standard_keymap);
8758310Sache      rl_bind_key_in_map ('}', rl_insert_close, emacs_standard_keymap);
8858310Sache    }
8958310Sache  else
9058310Sache    {	/* ([{ */
9158310Sache      rl_bind_key_in_map (')', rl_insert, emacs_standard_keymap);
9258310Sache      rl_bind_key_in_map (']', rl_insert, emacs_standard_keymap);
9358310Sache      rl_bind_key_in_map ('}', rl_insert, emacs_standard_keymap);
9458310Sache    }
9558310Sache}
9621308Sache
9721308Sacheint
9875406Sacherl_set_paren_blink_timeout (u)
9975406Sache     int u;
10075406Sache{
10175406Sache  int o;
10275406Sache
10375406Sache  o = _paren_blink_usec;
10475406Sache  if (u > 0)
10575406Sache    _paren_blink_usec = u;
10675406Sache  return (o);
10775406Sache}
10875406Sache
10975406Sacheint
11021308Sacherl_insert_close (count, invoking_key)
11121308Sache     int count, invoking_key;
11221308Sache{
11321308Sache  if (rl_explicit_arg || !rl_blink_matching_paren)
114119610Sache    _rl_insert_char (count, invoking_key);
11521308Sache  else
11621308Sache    {
11721308Sache#if defined (HAVE_SELECT)
11821308Sache      int orig_point, match_point, ready;
11921308Sache      struct timeval timer;
12021308Sache      fd_set readfds;
12121308Sache
122119610Sache      _rl_insert_char (1, invoking_key);
12321308Sache      (*rl_redisplay_function) ();
12421308Sache      match_point =
12521308Sache	find_matching_open (rl_line_buffer, rl_point - 2, invoking_key);
12621308Sache
12721308Sache      /* Emacs might message or ring the bell here, but I don't. */
12821308Sache      if (match_point < 0)
12921308Sache	return -1;
13021308Sache
13121308Sache      FD_ZERO (&readfds);
13221308Sache      FD_SET (fileno (rl_instream), &readfds);
13335486Sache      timer.tv_sec = 0;
13475406Sache      timer.tv_usec = _paren_blink_usec;
13521308Sache
13621308Sache      orig_point = rl_point;
13721308Sache      rl_point = match_point;
13821308Sache      (*rl_redisplay_function) ();
13921308Sache      ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer);
14021308Sache      rl_point = orig_point;
14121308Sache#else /* !HAVE_SELECT */
142119610Sache      _rl_insert_char (count, invoking_key);
14321308Sache#endif /* !HAVE_SELECT */
14421308Sache    }
14521308Sache  return 0;
14621308Sache}
14721308Sache
14821308Sachestatic int
14921308Sachefind_matching_open (string, from, closer)
15021308Sache     char *string;
15121308Sache     int from, closer;
15221308Sache{
15321308Sache  register int i;
15421308Sache  int opener, level, delimiter;
15521308Sache
15621308Sache  switch (closer)
15721308Sache    {
15821308Sache    case ']': opener = '['; break;
15921308Sache    case '}': opener = '{'; break;
16021308Sache    case ')': opener = '('; break;
16121308Sache    default:
16221308Sache      return (-1);
16321308Sache    }
16421308Sache
16521308Sache  level = 1;			/* The closer passed in counts as 1. */
16621308Sache  delimiter = 0;		/* Delimited state unknown. */
16721308Sache
16821308Sache  for (i = from; i > -1; i--)
16921308Sache    {
17021308Sache      if (delimiter && (string[i] == delimiter))
17121308Sache	delimiter = 0;
17221308Sache      else if (rl_basic_quote_characters && strchr (rl_basic_quote_characters, string[i]))
17321308Sache	delimiter = string[i];
17421308Sache      else if (!delimiter && (string[i] == closer))
17521308Sache	level++;
17621308Sache      else if (!delimiter && (string[i] == opener))
17721308Sache	level--;
17821308Sache
17921308Sache      if (!level)
18021308Sache	break;
18121308Sache    }
18221308Sache  return (i);
18321308Sache}
184