Fun 0.41.5
The programming language that makes you have fun!
Loading...
Searching...
No Matches
str_utils.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
10/**
11 * @file str_utils.c
12 * @brief Helpers for manipulating C strings and bridging with Value arrays.
13 *
14 * Functions here return newly allocated C strings or construct Value arrays
15 * from strings. Callers own returned allocations and must free them using
16 * free()/free_value() as appropriate.
17 */
18#include "value.h"
19#include <stdlib.h>
20#include <string.h>
21
22/* string helpers returning newly allocated C strings or arrays */
23
24/**
25 * @brief Create a newly allocated substring of s.
26 *
27 * Indices are clamped into valid range. If s is NULL, an empty string is
28 * returned. The caller owns the returned buffer and must free() it.
29 *
30 * @param s Source C string (may be NULL).
31 * @param start Zero-based start index; clamped to [0, strlen(s)].
32 * @param len Maximum number of characters to copy; negative treated as 0.
33 * @return Newly allocated NUL-terminated substring; never NULL.
34 */
35char *string_substr(const char *s, int start, int len) {
36 if (!s) return strdup("");
37 int n = (int)strlen(s);
38 if (start < 0) start = 0;
39 if (start > n) start = n;
40 if (len < 0) len = 0;
41 if (start + len > n) len = n - start;
42 char *out = (char *)malloc((size_t)len + 1);
43 if (!out) return strdup("");
44 memcpy(out, s + start, (size_t)len);
45 out[len] = '\0';
46 return out;
47}
48
49/**
50 * @brief Find first occurrence of needle in hay.
51 *
52 * @param hay Haystack C string (may be NULL).
53 * @param needle Needle C string (may be NULL).
54 * @return Zero-based index or -1 if not found/invalid input.
55 */
56int string_find(const char *hay, const char *needle) {
57 if (!hay || !needle) return -1;
58 const char *p = strstr(hay, needle);
59 if (!p) return -1;
60 return (int)(p - hay);
61}
62
63/**
64 * @brief Split a C string by separator into a Value array of strings.
65 *
66 * When sep is empty, splits into individual UTF-8 bytes (characters). Uses
67 * make_string/make_array_from_values; the returned Value owns internal memory
68 * per Value semantics. NULL inputs are treated as empty strings.
69 *
70 * @param s Source C string (may be NULL).
71 * @param sep Separator C string (may be NULL). Empty means split into chars.
72 * @return Value of type VAL_ARRAY with string elements.
73 */
74Value string_split_to_array(const char *s, const char *sep) {
75 if (!s) s = "";
76 if (!sep) sep = "";
77 int seplen = (int)strlen(sep);
78 if (seplen == 0) {
79 /* split into characters */
80 int n = (int)strlen(s);
81 if (n <= 0) return make_array_from_values(NULL, 0);
82 Value *tmp = (Value *)malloc(sizeof(Value) * n);
83 if (!tmp) return make_array_from_values(NULL, 0);
84 for (int i = 0; i < n; ++i) {
85 char ch[2] = {s[i], 0};
86 tmp[i] = make_string(ch);
87 }
89 for (int i = 0; i < n; ++i)
90 free_value(tmp[i]);
91 free(tmp);
92 return arr;
93 }
94 /* split by separator */
95 Value *parts = NULL;
96 int count = 0;
97 int cap = 0;
98 const char *cur = s;
99 const char *pos = NULL;
100 while ((pos = strstr(cur, sep)) != NULL) {
101 int len = (int)(pos - cur);
102 char *piece = (char *)malloc((size_t)len + 1);
103 if (!piece) break;
104 memcpy(piece, cur, (size_t)len);
105 piece[len] = '\0';
106 if (count >= cap) {
107 cap = cap == 0 ? 4 : cap * 2;
108 parts = (Value *)realloc(parts, sizeof(Value) * cap);
109 }
110 parts[count++] = make_string(piece);
111 free(piece);
112 cur = pos + seplen;
113 }
114 /* tail */
115 char *tail = strdup(cur ? cur : "");
116 if (count >= cap) {
117 cap = cap == 0 ? 1 : cap + 1;
118 parts = (Value *)realloc(parts, sizeof(Value) * cap);
119 }
120 parts[count++] = make_string(tail ? tail : "");
121 free(tail);
122
124 for (int i = 0; i < count; ++i)
125 free_value(parts[i]);
126 free(parts);
127 return arr;
128}
129
130/**
131 * @brief Join the elements of a Value array into a single newly allocated C string.
132 *
133 * Each array element is converted to a string via value_to_string_alloc.
134 * NULL/invalid inputs yield an empty string. The caller owns the returned
135 * buffer and must free() it.
136 *
137 * @param v Pointer to Value (expected VAL_ARRAY).
138 * @param sep Separator C string inserted between items (may be NULL).
139 * @return Newly allocated joined string; never NULL.
140 */
141char *array_join_with_sep(const Value *v, const char *sep) {
142 if (!v || v->type != VAL_ARRAY || !v->arr) return strdup("");
143 if (!sep) sep = "";
144 /* Array is defined in value.c; we only need safe public access. */
145 const int n = array_length(v);
146 if (n <= 0) return strdup("");
147
148 char **parts = (char **)malloc(sizeof(char *) * n);
149 if (!parts) return strdup("");
150
151 size_t total = 0;
152 for (int i = 0; i < n; ++i) {
153 Value item;
154 if (!array_get_copy(v, i, &item)) {
155 parts[i] = strdup("");
156 } else {
157 parts[i] = value_to_string_alloc(&item);
158 free_value(item);
159 }
160 total += strlen(parts[i]);
161 if (i + 1 < n) total += strlen(sep);
162 }
163
164 char *out = (char *)malloc(total + 1);
165 if (!out) {
166 for (int i = 0; i < n; ++i)
167 free(parts[i]);
168 free(parts);
169 return strdup("");
170 }
171
172 size_t off = 0;
173 for (int i = 0; i < n; ++i) {
174 size_t li = strlen(parts[i]);
175 memcpy(out + off, parts[i], li);
176 off += li;
177 if (i + 1 < n) {
178 size_t ls = strlen(sep);
179 memcpy(out + off, sep, ls);
180 off += ls;
181 }
182 free(parts[i]);
183 }
184 free(parts);
185 out[off] = '\0';
186 return out;
187}
Value out
Definition apop.c:38
Value v
Definition cast.c:22
array_clear & arr
Definition clear.c:38
Value hay
Definition find.c:34
int ch
Definition input_line.c:111
size_t len
Definition input_line.c:102
size_t cap
Definition input_line.c:101
int n
Definition insert.c:41
free(vals)
int count
Definition parser.c:263
const char * p
Definition read_file.c:37
uint32_t s
Definition rol.c:31
Value start
Definition slice.c:34
char * string_substr(const char *s, int start, int len)
Create a newly allocated substring of s.
Definition str_utils.c:35
char * array_join_with_sep(const Value *v, const char *sep)
Join the elements of a Value array into a single newly allocated C string.
Definition str_utils.c:141
int string_find(const char *hay, const char *needle)
Find first occurrence of needle in hay.
Definition str_utils.c:56
Value string_split_to_array(const char *s, const char *sep)
Split a C string by separator into a Value array of strings.
Definition str_utils.c:74
Tagged union representing a Fun value.
Definition value.h:68
Value make_string(const char *s)
Construct a string Value by duplicating the given C string.
Definition value.c:95
int array_length(const Value *v)
Get the element count of an array Value.
Definition value.c:176
void free_value(Value v)
Free dynamic storage owned by a Value.
Definition value.c:517
char * value_to_string_alloc(const Value *v)
Allocate a printable C string for a Value.
Definition value.c:641
int array_get_copy(const Value *v, int index, Value *out)
Copy an array element into out.
Definition value.c:192
Value make_array_from_values(const Value *vals, int count)
Create an array Value by copying items from an input span.
Definition value.c:142
Defines the Value type and associated functions for the Fun VM.
@ VAL_ARRAY
Definition value.h:55