1 /* $OpenBSD: re.c,v 1.19 2018/06/19 12:36:18 martijn Exp $ */
2 /* $NetBSD: re.c,v 1.14 1995/03/21 09:04:48 cgd Exp $ */
3
4 /* re.c: This file contains the regular expression interface routines for
5 the ed line editor. */
6 /*-
7 * Copyright (c) 1993 Andrew Moore, Talke Studio.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <regex.h>
33 #include <signal.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "ed.h"
39
40 static char *extract_pattern(int);
41 static char *parse_char_class(char *);
42
43 extern int patlock;
44
45
46 /* get_compiled_pattern: return pointer to compiled pattern from command
47 buffer */
48 regex_t *
get_compiled_pattern(void)49 get_compiled_pattern(void)
50 {
51 static regex_t *exp = NULL;
52 char errbuf[128] = "";
53
54 char *exps;
55 char delimiter;
56 int n;
57
58 if ((delimiter = *ibufp) == ' ') {
59 seterrmsg("invalid pattern delimiter");
60 return NULL;
61 } else if (delimiter == '\n' || *++ibufp == '\n' || *ibufp == delimiter) {
62 if (!exp)
63 seterrmsg("no previous pattern");
64 return exp;
65 } else if ((exps = extract_pattern(delimiter)) == NULL)
66 return NULL;
67 /* buffer alloc'd && not reserved */
68 if (exp && !patlock)
69 regfree(exp);
70 else if ((exp = malloc(sizeof(regex_t))) == NULL) {
71 perror(NULL);
72 seterrmsg("out of memory");
73 return NULL;
74 }
75 patlock = 0;
76 if ((n = regcomp(exp, exps, 0)) != 0) {
77 regerror(n, exp, errbuf, sizeof errbuf);
78 seterrmsg(errbuf);
79 free(exp);
80 return exp = NULL;
81 }
82 return exp;
83 }
84
85
86 /* extract_pattern: copy a pattern string from the command buffer; return
87 pointer to the copy */
88 static char *
extract_pattern(int delimiter)89 extract_pattern(int delimiter)
90 {
91 static char *lhbuf = NULL; /* buffer */
92 static int lhbufsz = 0; /* buffer size */
93
94 char *nd;
95 int len;
96
97 for (nd = ibufp; *nd != delimiter && *nd != '\n'; nd++)
98 switch (*nd) {
99 default:
100 break;
101 case '[':
102 if ((nd = parse_char_class(++nd)) == NULL) {
103 seterrmsg("unbalanced brackets ([])");
104 return NULL;
105 }
106 break;
107 case '\\':
108 if (*++nd == '\n') {
109 seterrmsg("trailing backslash (\\)");
110 return NULL;
111 }
112 break;
113 }
114 len = nd - ibufp;
115 REALLOC(lhbuf, lhbufsz, len + 1, NULL);
116 memcpy(lhbuf, ibufp, len);
117 lhbuf[len] = '\0';
118 ibufp = nd;
119 return (isbinary) ? NUL_TO_NEWLINE(lhbuf, len) : lhbuf;
120 }
121
122
123 /* parse_char_class: expand a POSIX character class */
124 static char *
parse_char_class(char * s)125 parse_char_class(char *s)
126 {
127 int c, d;
128
129 if (*s == '^')
130 s++;
131 if (*s == ']')
132 s++;
133 for (; *s != ']' && *s != '\n'; s++)
134 if (*s == '[' && ((d = *(s+1)) == '.' || d == ':' || d == '='))
135 for (s++, c = *++s; *s != ']' || c != d; s++)
136 if ((c = *s) == '\n')
137 return NULL;
138 return (*s == ']') ? s : NULL;
139 }
140