Fun 0.41.5
The programming language that makes You have fun
Loading...
Searching...
No Matches
regex_replace.c
Go to the documentation of this file.
1/*
2 * This file is part of the Fun programming language.
3 * https://fun-lang.xyz/
4 *
5 * Copyright 2025 Johannes Findeisen <you@hanez.org>
6 * Licensed under the terms of the Apache-2.0 license.
7 * https://opensource.org/license/apache-2-0
8 */
9
34/* Regex global replace opcode using POSIX regex */
35#ifdef __unix__
36#include <regex.h>
37#include <stdlib.h>
38#include <string.h>
39#endif
40
42 Value repl = pop_value(vm);
43 Value pattern = pop_value(vm);
44 Value str = pop_value(vm);
45 if (str.type != VAL_STRING || pattern.type != VAL_STRING || repl.type != VAL_STRING) {
46 fprintf(stderr, "Runtime type error: REGEX_REPLACE expects (string, string, string)\n");
47 exit(1);
48 }
49#ifndef __unix__
50 /* Not supported: return original string */
51 Value out = make_string(str.s ? str.s : "");
52 free_value(repl);
56 break;
57#else
58 regex_t rx;
59 int rc = regcomp(&rx, pattern.s ? pattern.s : "", REG_EXTENDED);
60 if (rc != 0) {
61 /* invalid regex -> return original */
62 Value out = make_string(str.s ? str.s : "");
63 free_value(repl);
66 push_value(vm, out);
67 break;
68 }
69
70 const char *s = str.s ? str.s : "";
71 const char *r = repl.s ? repl.s : "";
72
73 size_t out_cap = strlen(s) + 1;
74 char *outbuf = (char *)malloc(out_cap);
75 size_t out_len = 0;
76 size_t pos = 0;
77
78 enum { MAX_CAP = 16 };
79 regmatch_t caps[MAX_CAP];
80
81 while (1) {
82 if (regexec(&rx, s + pos, MAX_CAP, caps, 0) != 0) {
83 /* no more matches: append the rest */
84 size_t rest = strlen(s + pos);
85 if (out_len + rest + 1 > out_cap) {
86 out_cap = out_len + rest + 1;
87 outbuf = (char *)realloc(outbuf, out_cap);
88 }
89 memcpy(outbuf + out_len, s + pos, rest + 1);
90 out_len += rest;
91 break;
92 }
93 int mstart = (int)caps[0].rm_so;
94 int mend = (int)caps[0].rm_eo;
95 if (mstart < 0 || mend < mstart) {
96 /* Shouldn't happen, avoid infinite loop */
97 break;
98 }
99 /* append prefix */
100 size_t pre_len = (size_t)mstart;
101 if (out_len + pre_len + 1 > out_cap) {
102 out_cap = (out_len + pre_len + 1) * 2;
103 outbuf = (char *)realloc(outbuf, out_cap);
104 }
105 memcpy(outbuf + out_len, s + pos, pre_len);
106 out_len += pre_len;
107
108 /* append replacement (no backref expansion for simplicity) */
109 size_t rlen = strlen(r);
110 if (out_len + rlen + 1 > out_cap) {
111 out_cap = (out_len + rlen + 1) * 2;
112 outbuf = (char *)realloc(outbuf, out_cap);
113 }
114 memcpy(outbuf + out_len, r, rlen);
115 out_len += rlen;
116
117 /* advance */
118 pos += (size_t)mend;
119 if (mend == 0) { /* prevent zero-length match infinite loop */
120 if (pos < strlen(s)) {
121 if (out_len + 1 > out_cap) {
122 out_cap = out_len + 2;
123 outbuf = (char *)realloc(outbuf, out_cap);
124 }
125 outbuf[out_len++] = s[pos++];
126 } else {
127 break;
128 }
129 }
130 }
131
132 Value out = make_string(outbuf ? outbuf : "");
133 if (outbuf) free(outbuf);
134 regfree(&rx);
135 free_value(repl);
138 push_value(vm, out);
139 break;
140#endif
141}
Value out
Definition apop.c:38
uint32_t r
Definition band.c:33
@ OP_REGEX_REPLACE
Definition bytecode.h:109
int rc
free(vals)
Value str
Definition regex_match.c:41
free_value(repl)
Value pattern
push_value(vm, out)
uint32_t s
Definition rol.c:31
Tagged union representing a Fun value.
Definition value.h:68
ValueType type
Definition value.h:69
char * s
Definition value.h:73
Value make_string(const char *s)
Construct a string Value by duplicating the given C string.
Definition value.c:95
@ VAL_STRING
Definition value.h:53
#define fprintf
Definition vm.c:200
#define exit(code)
Definition vm.c:230