List Converter — C source
Transform a list between separators (newline, comma, space, pipe, semicolon, tab) with trim, dedupe, sort, and empty-removal options. Runs entirely in your browser, with a shareable link.
This is the C implementation — the same logic the interactive tool runs, in a shareable, citable form.
/* List Converter — split/trim/dedup/sort/join between separators — C (C11) port of the list-converter tool. */
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct { int trim, remove_empty, unique, sort, case_insensitive; } Opts;
static const char *SEP_NAMES[] = { "newline", "comma", "space", "pipe", "semicolon", "tab" };
static const char SEP_CHARS[] = { '\n', ',', ' ', '|', ';', '\t' };
/* Separators are all single characters, so one char is the whole glue.
* NULL falls back to the TS default (from '\n', to ','). */
static char sep_char(const char *name, char fallback) {
if (name == NULL) return fallback;
for (int i = 0; i < 6; i++)
if (strcmp(name, SEP_NAMES[i]) == 0) return SEP_CHARS[i];
return name[0]; /* a literal custom separator */
}
/* strcmp over optionally-lowercased bytes; the unique/sort comparison key. */
static int key_cmp(const char *a, const char *b, int ci) {
while (*a != '\0' && *b != '\0') {
int ca = ci ? tolower((unsigned char)*a) : (unsigned char)*a;
int cb = ci ? tolower((unsigned char)*b) : (unsigned char)*b;
if (ca != cb) return ca - cb;
a++;
b++;
}
return (unsigned char)*a - (unsigned char)*b;
}
/* Convert a list between separators: split -> (trim) -> (drop empties) ->
* (dedup, first occurrence wins) -> (stable sort) -> join. malloc'd result. */
static char *convert(const char *input, const char *from, const char *to, Opts o) {
char fs = sep_char(from, '\n'), ts = sep_char(to, ',');
size_t len = strlen(input), n = 0;
char *buf = malloc(len + 1);
char **items = malloc((len + 2) * sizeof *items); /* at most one item per byte */
memcpy(buf, input, len + 1);
for (char *p = buf, *start = buf;;) { /* split in place: sep -> '\0' */
if (*p == fs || *p == '\0') {
int last = (*p == '\0');
*p = '\0';
char *s = start;
if (o.trim) { /* strip both ends */
while (*s != '\0' && isspace((unsigned char)*s)) s++;
char *e = s + strlen(s);
while (e > s && isspace((unsigned char)e[-1])) *--e = '\0';
}
if (!(o.remove_empty && *s == '\0')) items[n++] = s;
if (last) break;
start = p + 1;
}
p++;
}
if (o.unique) { /* keep the first occurrence of each key */
size_t m = 0;
for (size_t i = 0; i < n; i++) {
size_t j = 0;
while (j < m && key_cmp(items[i], items[j], o.case_insensitive) != 0) j++;
if (j == m) items[m++] = items[i];
}
n = m;
}
if (o.sort) /* insertion sort: stable, plenty for list-sized inputs */
for (size_t i = 1; i < n; i++) {
char *key = items[i];
size_t j = i;
while (j > 0 && key_cmp(items[j - 1], key, o.case_insensitive) > 0) {
items[j] = items[j - 1];
j--;
}
items[j] = key;
}
size_t total = 1;
for (size_t i = 0; i < n; i++) total += strlen(items[i]) + 1;
char *out = malloc(total), *w = out;
for (size_t i = 0; i < n; i++) {
if (i != 0) *w++ = ts;
size_t l = strlen(items[i]);
memcpy(w, items[i], l);
w += l;
}
*w = '\0';
free(items);
free(buf);
return out;
}
int main(void) {
/* "b\n a \nB\na\n\nc" -> trim, drop empties, case-insensitive dedup+sort
* -> "a,b,c" (default from=newline, to=comma). */
Opts all = { 1, 1, 1, 1, 1 };
char *out = convert("b\n a \nB\na\n\nc", NULL, NULL, all);
printf("%s\n", out);
free(out);
return 0;
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →