1/* Copyright (C) 2003 Free Software Foundation, Inc.
2
3   This file is part of GNU Bash, the Bourne Again SHell.
4
5   Bash is free software; you can redistribute it and/or modify it under
6   the terms of the GNU General Public License as published by the Free
7   Software Foundation; either version 2, or (at your option) any later
8   version.
9
10   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
11   WARRANTY; without even the implied warranty of MERCHANTABILITY or
12   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13   for more details.
14
15   You should have received a copy of the GNU General Public License along
16   with Bash; see the file COPYING.  If not, write to the Free Software
17   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
18
19/*
20 * shmatch.c -- shell interface to posix regular expression matching.
21 */
22
23#ifdef HAVE_CONFIG_H
24#  include <config.h>
25#endif
26
27#if defined (HAVE_POSIX_REGEXP)
28
29#ifdef HAVE_UNISTD_H
30#  include <unistd.h>
31#endif
32
33#include "bashansi.h"
34
35#include <stdio.h>
36#include <regex.h>
37
38#include "shell.h"
39#include "variables.h"
40#include "externs.h"
41
42extern int glob_ignore_case, match_ignore_case;
43
44int
45sh_regmatch (string, pattern, flags)
46     const char *string;
47     const char *pattern;
48     int flags;
49{
50  regex_t regex = { 0 };
51  regmatch_t *matches;
52  int rflags;
53#if defined (ARRAY_VARS)
54  SHELL_VAR *rematch;
55  ARRAY *amatch;
56  int subexp_ind;
57  char *subexp_str;
58  int subexp_len;
59#endif
60  int result;
61
62#if defined (ARRAY_VARS)
63  rematch = (SHELL_VAR *)NULL;
64#endif
65
66  rflags = REG_EXTENDED;
67  if (glob_ignore_case || match_ignore_case)
68    rflags |= REG_ICASE;
69#if !defined (ARRAY_VARS)
70  rflags |= REG_NOSUB;
71#endif
72
73  if (regcomp (&regex, pattern, rflags))
74    return 2;		/* flag for printing a warning here. */
75
76#if defined (ARRAY_VARS)
77  matches = (regmatch_t *)malloc (sizeof (regmatch_t) * (regex.re_nsub + 1));
78#else
79  matches = NULL;
80#endif
81
82  if (regexec (&regex, string, regex.re_nsub + 1, matches, 0))
83    result = EXECUTION_FAILURE;
84  else
85    result = EXECUTION_SUCCESS;		/* match */
86
87#if defined (ARRAY_VARS)
88  subexp_len = strlen (string) + 10;
89  subexp_str = malloc (subexp_len + 1);
90
91  /* Store the parenthesized subexpressions in the array BASH_REMATCH.
92     Element 0 is the portion that matched the entire regexp.  Element 1
93     is the part that matched the first subexpression, and so on. */
94  unbind_variable ("BASH_REMATCH");
95  rematch = make_new_array_variable ("BASH_REMATCH");
96  amatch = array_cell (rematch);
97
98  if ((flags & SHMAT_SUBEXP) && result == EXECUTION_SUCCESS && subexp_str)
99    {
100      for (subexp_ind = 0; subexp_ind <= regex.re_nsub; subexp_ind++)
101	{
102	  memset (subexp_str, 0, subexp_len);
103	  strncpy (subexp_str, string + matches[subexp_ind].rm_so,
104		     matches[subexp_ind].rm_eo - matches[subexp_ind].rm_so);
105	  array_insert (amatch, subexp_ind, subexp_str);
106	}
107    }
108
109  VSETATTR (rematch, att_readonly);
110
111  free (subexp_str);
112  free (matches);
113#endif /* ARRAY_VARS */
114
115  regfree (&regex);
116
117  return result;
118}
119
120#endif /* HAVE_POSIX_REGEXP */
121