Skip to content

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 →