1/*	$NetBSD: regsub.cc,v 1.1 2023/08/01 06:04:42 mrg Exp $	*/
2
3/*-
4 * Copyright (c) 2015 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32extern "C" {
33
34#include <sys/param.h>
35#include <ctype.h>
36#include <stdlib.h>
37#include <string.h>
38#include <regex.h>
39
40struct str {
41	char *s_ptr;
42	size_t s_max;
43	size_t s_len;
44	int s_fixed;
45};
46
47#define	REINCR	64
48
49static int
50addspace(struct str *s, size_t len)
51{
52	void *v;
53
54	if (s->s_max - s->s_len > len)
55		return 0;
56
57	if (s->s_fixed)
58		return -1;
59
60	s->s_max += len + REINCR;
61
62	v = realloc(s->s_ptr, s->s_max);
63	if (v == NULL)
64		return -1;
65	s->s_ptr = (char *)v;
66
67	return 0;
68}
69
70static void
71addchar(struct str *s, int c)
72{
73	if (addspace(s, 1) == -1)
74		s->s_len++;
75	else
76		s->s_ptr[s->s_len++] = c;
77	if (c == 0) {
78		--s->s_len;
79		s->s_ptr[s->s_max - 1] = c;
80	}
81}
82
83static void
84addnstr(struct str *s, const char *buf, size_t len)
85{
86	if (addspace(s, len) != -1)
87		memcpy(s->s_ptr + s->s_len, buf, len);
88	s->s_len += len;
89}
90
91static int
92initstr(struct str *s, char *buf, size_t len)
93{
94	s->s_max = len;
95	s->s_ptr = (char *)(buf == NULL ? malloc(len) : buf);
96	s->s_fixed = buf != NULL;
97	s->s_len = 0;
98	return s->s_ptr == NULL ? -1 : 0;
99}
100
101static ssize_t
102regsub1(char **buf, size_t len, const char *sub,
103    const regmatch_t *rm, const char *str)
104{
105        ssize_t i;
106        char c;
107	struct str s;
108
109	if (initstr(&s, *buf, len) == -1)
110		return -1;
111
112        while ((c = *sub++) != '\0') {
113
114		switch (c) {
115		case '&':
116			i = 0;
117			break;
118		case '\\':
119			if (isdigit((unsigned char)*sub))
120				i = *sub++ - '0';
121			else
122				i = -1;
123			break;
124		default:
125			i = -1;
126			break;
127		}
128
129                if (i == -1) {
130                        if (c == '\\' && (*sub == '\\' || *sub == '&'))
131                                c = *sub++;
132			addchar(&s, c);
133                } else if (rm[i].rm_so != -1 && rm[i].rm_eo != -1) {
134                        size_t l = (size_t)(rm[i].rm_eo - rm[i].rm_so);
135			addnstr(&s, str + rm[i].rm_so, l);
136                }
137        }
138
139	addchar(&s, '\0');
140	if (!s.s_fixed) {
141		if (s.s_len >= s.s_max) {
142			free(s.s_ptr);
143			return -1;
144		}
145		*buf = s.s_ptr;
146	}
147	return s.s_len;
148}
149
150ssize_t
151regnsub(char *buf, size_t len, const char *sub, const regmatch_t *rm,
152    const char *str)
153{
154	return regsub1(&buf, len, sub, rm, str);
155}
156
157ssize_t
158regasub(char **buf, const char *sub, const regmatch_t *rm, const char *str)
159{
160	*buf = NULL;
161	return regsub1(buf, REINCR, sub, rm, str);
162}
163
164}
165