Markdown Table Generator — C source
Turn pipe, CSV, tab, semicolon, or space-separated data into a clean GitHub-Flavored Markdown table. Auto-detects the delimiter, pads columns, escapes pipes, and supports per-column alignment - all in your browser.
This is the C implementation — the same logic the interactive tool runs, in a shareable, citable form.
/* markdown-table — C (C11) port: split delimiter-separated rows and render a padded GFM table, ported from src/lib/markdown-table.ts. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum { NONE, LEFT, CENTER, RIGHT } Align;
static char *trim(char *s) {
while (*s == ' ' || *s == '\t' || *s == '\r') s++;
size_t n = strlen(s);
while (n > 0 && (s[n - 1] == ' ' || s[n - 1] == '\t' || s[n - 1] == '\r')) s[--n] = '\0';
return s;
}
/* splitLine: literal-delimiter split (',', '\t', ';'); cells point into `line`. */
static int split_line(char *line, char delim, char **cells) {
int n = 0;
char *start = line;
for (char *p = line;; p++) {
if (*p == delim || *p == '\0') {
int end = *p == '\0';
*p = '\0';
cells[n++] = trim(start);
if (end) return n;
start = p + 1;
}
}
}
/* escapeCell: newlines collapse to spaces, a literal '|' renders as '\|'
* (heap-allocated — escaping can grow the cell). */
static char *escape_cell(const char *cell) {
char *out = malloc(2 * strlen(cell) + 1), *w = out;
for (; *cell; cell++) {
if (*cell == '\n' || *cell == '\r') *w++ = ' ';
else {
if (*cell == '|') *w++ = '\\';
*w++ = *cell;
}
}
*w = '\0';
return out;
}
/* sepCell: the ---, :--, --:, :-: separator cell, min width 3. */
static void print_sep_cell(Align a, int width) {
int w = width < 3 ? 3 : width, d = w;
if (a == LEFT || a == RIGHT) d = w - 1;
else if (a == CENTER) d = w - 2;
if (a == LEFT || a == CENTER) putchar(':');
for (int i = 0; i < d; i++) putchar('-');
if (a == RIGHT || a == CENTER) putchar(':');
}
/* toMarkdown: '| ' + padded cells joined ' | ' + ' |', separator under the
* header row (the demo fixes header = true). */
int main(void) {
char input[3][64] = { "Name,Price,Qty", "Wire | cable,2 m,1", "LED,3 mm,25" };
enum { R = 3, C = 8 };
char *grid[R][C];
int ncols[R], cols = 0, widths[C];
Align aligns[C] = { NONE, RIGHT, CENTER };
for (int r = 0; r < R; r++) {
ncols[r] = split_line(input[r], ',', grid[r]);
for (int c = 0; c < ncols[r]; c++) grid[r][c] = escape_cell(grid[r][c]);
if (ncols[r] > cols) cols = ncols[r];
}
for (int c = 0; c < cols; c++) {
widths[c] = 3;
for (int r = 0; r < R; r++)
if (c < ncols[r] && (int)strlen(grid[r][c]) > widths[c])
widths[c] = (int)strlen(grid[r][c]);
}
for (int r = 0; r < R; r++) {
fputs("| ", stdout);
for (int c = 0; c < cols; c++) {
const char *cell = c < ncols[r] ? grid[r][c] : "";
int diff = widths[c] - (int)strlen(cell);
if (c > 0) fputs(" | ", stdout);
if (diff <= 0) fputs(cell, stdout); /* pad: already at width */
else if (aligns[c] == RIGHT) printf("%*s%s", diff, "", cell);
else if (aligns[c] == CENTER) printf("%*s%s%*s", diff / 2, "", cell, diff - diff / 2, "");
else printf("%s%*s", cell, diff, ""); /* LEFT, NONE -> left-aligned */
}
fputs(" |\n", stdout);
if (r == 0) { /* the separator row sits directly under the header */
fputs("| ", stdout);
for (int c = 0; c < cols; c++) {
if (c > 0) fputs(" | ", stdout);
print_sep_cell(aligns[c], widths[c]);
}
fputs(" |\n", stdout);
}
}
for (int r = 0; r < R; r++)
for (int c = 0; c < ncols[r]; c++) free(grid[r][c]);
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 →