Skip to content

Commit 08c88aa

Browse files
Merge branch 'main' into extend_cstring_api
2 parents 47c4da1 + 0261d42 commit 08c88aa

File tree

5 files changed

+909
-4
lines changed

5 files changed

+909
-4
lines changed

code/logic/cstring.c

Lines changed: 329 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@
1616
#include <string.h> // For strlen, strnlen, strncasecmp
1717
#include <strings.h> // For strncasecmp on POSIX
1818
#include <stdlib.h>
19-
#include <unistd.h> // for mkstemp
20-
#include <fcntl.h> // sometimes needed for O_* flags
2119
#include <ctype.h> // For toupper, tolower
22-
20+
#include <time.h>
2321

2422
#ifndef HAVE_STRNLEN
2523
size_t strnlen(const char *s, size_t maxlen) {
@@ -59,11 +57,339 @@ void fossil_io_cstring_free(cstring str) {
5957
}
6058
}
6159

60+
int fossil_io_cstring_silly(const char *input, char *output, size_t size) {
61+
if (!input || !output || size == 0) return -1;
62+
63+
size_t len = strlen(input);
64+
if (len + 1 > size) return -1;
65+
66+
for (size_t i = 0; i < len; i++) {
67+
char c = input[i];
68+
// Random case change
69+
if (isalpha((unsigned char)c)) {
70+
if (rand() % 2) {
71+
c = (char)toupper((unsigned char)c);
72+
} else {
73+
c = (char)tolower((unsigned char)c);
74+
}
75+
}
76+
// Occasionally insert silly symbol
77+
if (rand() % 10 == 0 && (i + 1 < size - 1)) {
78+
output[i++] = '~';
79+
}
80+
output[i] = c;
81+
}
82+
output[len] = '\0';
83+
return 0;
84+
}
85+
86+
int fossil_io_cstring_piglatin(const char *input, char *output, size_t size) {
87+
if (!input || !output || size == 0) return -1;
88+
89+
output[0] = '\0';
90+
const char *delims = " \t\n";
91+
char buffer[256];
92+
char word[128];
93+
94+
// Copy input safely into a working buffer
95+
strncpy(buffer, input, sizeof(buffer) - 1);
96+
buffer[sizeof(buffer) - 1] = '\0';
97+
98+
char *token = strtok(buffer, delims);
99+
while (token) {
100+
size_t word_len = strlen(token);
101+
if (word_len == 0) {
102+
token = strtok(NULL, delims);
103+
continue;
104+
}
105+
106+
// Vowel start → add "yay"
107+
if (strchr("AEIOUaeiou", token[0])) {
108+
strncpy(word, token, sizeof(word) - 4); // leave room for "yay"
109+
word[sizeof(word) - 4] = '\0';
110+
strncat(word, "yay", sizeof(word) - strlen(word) - 1);
111+
}
112+
// Consonant start → move first letter, add "ay"
113+
else {
114+
strncpy(word, token + 1, sizeof(word) - 4); // leave room for "<c>ay"
115+
word[sizeof(word) - 4] = '\0';
116+
117+
size_t len = strlen(word);
118+
if (len < sizeof(word) - 3) {
119+
word[len] = token[0];
120+
word[len + 1] = 'a';
121+
word[len + 2] = 'y';
122+
word[len + 3] = '\0';
123+
} else {
124+
return -1; // truncated
125+
}
126+
}
127+
128+
// Check space in output before appending
129+
if (strlen(output) + strlen(word) + 2 > size) return -1;
130+
strcat(output, word);
131+
strcat(output, " ");
132+
133+
token = strtok(NULL, delims);
134+
}
135+
136+
return 0;
137+
}
138+
139+
int fossil_io_cstring_leetspeak(const char *input, char *output, size_t size) {
140+
if (!input || !output || size == 0) return -1;
141+
142+
size_t out_idx = 0;
143+
for (size_t i = 0; input[i] && out_idx < size - 1; i++) {
144+
char c = input[i];
145+
char repl[3] = {0};
146+
147+
switch (tolower((unsigned char)c)) {
148+
case 'a': strcpy(repl, "4"); break;
149+
case 'e': strcpy(repl, "3"); break;
150+
case 'i': strcpy(repl, "1"); break;
151+
case 'o': strcpy(repl, "0"); break;
152+
case 's': strcpy(repl, "5"); break;
153+
case 't': strcpy(repl, "7"); break;
154+
default: repl[0] = c; repl[1] = '\0'; break;
155+
}
156+
157+
size_t repl_len = strlen(repl);
158+
if (out_idx + repl_len >= size - 1) return -1;
159+
strcpy(&output[out_idx], repl);
160+
out_idx += repl_len;
161+
}
162+
output[out_idx] = '\0';
163+
return 0;
164+
}
165+
166+
// -------------------
167+
// Mocking SpongeBob
168+
// -------------------
169+
char* fossil_io_cstring_mocking(const char *str) {
170+
if (!str) return NULL;
171+
size_t len = strlen(str);
172+
char *out = malloc(len + 1);
173+
if (!out) return NULL;
174+
175+
for (size_t i = 0; i < len; i++) {
176+
if (i % 2 == 0)
177+
out[i] = tolower((unsigned char)str[i]);
178+
else
179+
out[i] = toupper((unsigned char)str[i]);
180+
}
181+
out[len] = '\0';
182+
return out;
183+
}
184+
185+
// -------------------
186+
// ROT13 Cipher
187+
// -------------------
188+
char* fossil_io_cstring_rot13(const char *str) {
189+
if (!str) return NULL;
190+
size_t len = strlen(str);
191+
char *out = malloc(len + 1);
192+
if (!out) return NULL;
193+
194+
for (size_t i = 0; i < len; i++) {
195+
char c = str[i];
196+
if ('a' <= c && c <= 'z')
197+
out[i] = ((c - 'a' + 13) % 26) + 'a';
198+
else if ('A' <= c && c <= 'Z')
199+
out[i] = ((c - 'A' + 13) % 26) + 'A';
200+
else
201+
out[i] = c;
202+
}
203+
out[len] = '\0';
204+
return out;
205+
}
206+
207+
// -------------------
208+
// Shuffle String
209+
// -------------------
210+
char* fossil_io_cstring_shuffle(const char *str) {
211+
if (!str) return NULL;
212+
size_t len = strlen(str);
213+
char *out = malloc(len + 1);
214+
if (!out) return NULL;
215+
216+
strcpy(out, str);
217+
218+
// Seed RNG once per run
219+
static int seeded = 0;
220+
if (!seeded) {
221+
srand((unsigned int)time(NULL));
222+
seeded = 1;
223+
}
224+
225+
for (size_t i = 0; i < len; i++) {
226+
size_t j = rand() % len;
227+
char tmp = out[i];
228+
out[i] = out[j];
229+
out[j] = tmp;
230+
}
231+
232+
return out;
233+
}
234+
235+
// -------------------
236+
// UPPER_SNAKE_CASE
237+
// -------------------
238+
char* fossil_io_cstring_upper_snake(const char *str) {
239+
if (!str) return NULL;
240+
size_t len = strlen(str);
241+
242+
// Worst case: every char becomes "_X"
243+
char *out = malloc(len * 2 + 1);
244+
if (!out) return NULL;
245+
246+
size_t j = 0;
247+
for (size_t i = 0; i < len; i++) {
248+
if (isspace((unsigned char)str[i])) {
249+
out[j++] = '_';
250+
} else if (isalpha((unsigned char)str[i])) {
251+
out[j++] = toupper((unsigned char)str[i]);
252+
} else {
253+
out[j++] = str[i];
254+
}
255+
}
256+
out[j] = '\0';
257+
return out;
258+
}
259+
260+
// -------------------
261+
// Zalgo Text (simplified)
262+
// -------------------
263+
char* fossil_io_cstring_zalgo(const char *str) {
264+
if (!str) return NULL;
265+
size_t len = strlen(str);
266+
267+
// Each char may get up to 3 combining marks
268+
char *out = malloc(len * 10 + 1);
269+
if (!out) return NULL;
270+
271+
static const char *zalgo_marks[] = {
272+
"\u0300", "\u0301", "\u0302", "\u0303", "\u0304",
273+
"\u0306", "\u0307", "\u0308", "\u030A", "\u0315",
274+
"\u0327", "\u0328", "\u0334", "\u033F", "\u0346"
275+
};
276+
static const size_t num_marks = sizeof(zalgo_marks) / sizeof(zalgo_marks[0]);
277+
278+
size_t j = 0;
279+
for (size_t i = 0; i < len; i++) {
280+
j += sprintf(out + j, "%c", str[i]);
281+
282+
int marks = rand() % 3; // 0–2 zalgo marks
283+
for (int m = 0; m < marks; m++) {
284+
const char *mark = zalgo_marks[rand() % num_marks];
285+
j += sprintf(out + j, "%s", mark);
286+
}
287+
}
288+
out[j] = '\0';
289+
return out;
290+
}
291+
62292
cstring fossil_io_cstring_copy(ccstring str) {
63293
if (!str) return NULL;
64294
return fossil_io_cstring_create(str);
65295
}
66296

297+
static const char *units[] = {
298+
"zero", "one", "two", "three", "four", "five",
299+
"six", "seven", "eight", "nine", "ten", "eleven",
300+
"twelve", "thirteen", "fourteen", "fifteen",
301+
"sixteen", "seventeen", "eighteen", "nineteen"
302+
};
303+
304+
static const char *tens[] = {
305+
"", "", "twenty", "thirty", "forty", "fifty",
306+
"sixty", "seventy", "eighty", "ninety"
307+
};
308+
309+
// ---------------- Number -> Words ----------------
310+
int fossil_io_cstring_number_to_words(int num, char *buffer, size_t size) {
311+
if (!buffer || size == 0) return -1;
312+
buffer[0] = '\0';
313+
314+
if (num < 0 || num > 9999) return -1; // Limit to 0..9999
315+
316+
if (num >= 1000) {
317+
int thousands = num / 1000;
318+
if (strlen(buffer) + strlen(units[thousands]) + 10 >= size) return -1;
319+
strcat(buffer, units[thousands]);
320+
strcat(buffer, " thousand");
321+
num %= 1000;
322+
if (num > 0) strcat(buffer, " ");
323+
}
324+
325+
if (num >= 100) {
326+
int hundreds = num / 100;
327+
if (strlen(buffer) + strlen(units[hundreds]) + 10 >= size) return -1;
328+
strcat(buffer, units[hundreds]);
329+
strcat(buffer, " hundred");
330+
num %= 100;
331+
if (num > 0) strcat(buffer, " and ");
332+
}
333+
334+
if (num >= 20) {
335+
int t = num / 10;
336+
if (strlen(buffer) + strlen(tens[t]) + 2 >= size) return -1;
337+
strcat(buffer, tens[t]);
338+
num %= 10;
339+
if (num > 0) {
340+
strcat(buffer, "-");
341+
strcat(buffer, units[num]);
342+
}
343+
} else if (num > 0 || strlen(buffer) == 0) {
344+
if (strlen(buffer) + strlen(units[num]) + 1 >= size) return -1;
345+
strcat(buffer, units[num]);
346+
}
347+
348+
return 0;
349+
}
350+
351+
// ---------------- Words -> Number ----------------
352+
static int fossil_io_word_to_value(const char *word) {
353+
for (int i = 0; i < 20; i++) if (strcmp(word, units[i]) == 0) return i;
354+
for (int i = 2; i < 10; i++) if (strcmp(word, tens[i]) == 0) return i * 10;
355+
if (strcmp(word, "hundred") == 0) return -100; // multiplier
356+
if (strcmp(word, "thousand") == 0) return -1000; // multiplier
357+
return -1; // not found
358+
}
359+
360+
int fossil_io_cstring_number_from_words(const char *str, int *out) {
361+
if (!str || !out) return -1;
362+
363+
int total = 0;
364+
int current = 0;
365+
366+
char buffer[256];
367+
strncpy(buffer, str, sizeof(buffer)-1);
368+
buffer[sizeof(buffer)-1] = '\0';
369+
370+
// lowercase and remove extra characters
371+
for (char *p = buffer; *p; ++p) *p = (char)tolower(*p);
372+
373+
char *token = strtok(buffer, " -");
374+
while (token) {
375+
int val = fossil_io_word_to_value(token);
376+
if (val >= 0) {
377+
current += val;
378+
} else if (val == -100) { // hundred
379+
current *= 100;
380+
} else if (val == -1000) { // thousand
381+
total += current * 1000;
382+
current = 0;
383+
} else {
384+
return -1; // unknown word
385+
}
386+
token = strtok(NULL, " -");
387+
}
388+
389+
*out = total + current;
390+
return 0;
391+
}
392+
67393
cstring fossil_io_cstring_dup(ccstring str) {
68394
if (!str) return NULL;
69395
size_t length = strlen(str);

0 commit comments

Comments
 (0)