Skip to content

Instantly share code, notes, and snippets.

@sartimo
Last active February 16, 2024 08:54
Show Gist options
  • Save sartimo/6bf2e103cbb0c9a73945de5918ddfc92 to your computer and use it in GitHub Desktop.
Save sartimo/6bf2e103cbb0c9a73945de5918ddfc92 to your computer and use it in GitHub Desktop.
Markdown to ToC
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define TOP 1
#define MAX 10
typedef struct {
char *source_file;
int top;
int max;
int count;
char *level;
char *header;
char *start;
char *anchor;
char **seen;
int seen_count;
} ToCWriter;
void initialize_ToCWriter(ToCWriter *writer, char *source_file, int top, int max) {
writer->source_file = source_file;
writer->top = top;
writer->max = max;
writer->count = 1;
writer->level = malloc(256);
writer->header = malloc(256);
writer->start = malloc(256);
writer->anchor = malloc(256);
writer->seen = malloc(256 * sizeof(char*));
writer->seen_count = 0;
}
void free_ToCWriter(ToCWriter *writer) {
free(writer->level);
free(writer->header);
free(writer->start);
free(writer->anchor);
for (int i = 0; i < writer->seen_count; i++) {
free(writer->seen[i]);
}
free(writer->seen);
}
int ignore_this_header(ToCWriter *writer) {
return (strcmp(writer->header, "Table of contents") == 0) ||
(strlen(writer->level) < writer->top) ||
(strlen(writer->level) > writer->max);
}
void set_anchor(ToCWriter *writer) {
strcpy(writer->anchor, writer->header);
for (int i = 0; writer->anchor[i]; i++) {
writer->anchor[i] = tolower(writer->anchor[i]);
if (!isalnum(writer->anchor[i]) && writer->anchor[i] != '_' && writer->anchor[i] != '-' && writer->anchor[i] != ' ') {
writer->anchor[i] = '\0';
}
}
char *ptr = writer->anchor;
while (*ptr) {
if (*ptr == ' ') *ptr = '-';
ptr++;
}
}
void update_if_seen(ToCWriter *writer) {
int inc = 2;
int found;
do {
found = 0;
for (int i = 0; i < writer->seen_count; i++) {
if (strcmp(writer->seen[i], writer->anchor) == 0) {
found = 1;
break;
}
}
if (found) {
char suffix[10];
sprintf(suffix, "-%d", inc++);
strcat(writer->anchor, suffix);
}
} while (found);
writer->seen[writer->seen_count] = strdup(writer->anchor);
writer->seen_count++;
}
void set_start(ToCWriter *writer) {
int len = strlen(writer->level);
if (len == writer->top) {
sprintf(writer->start, "%d.", writer->count++);
} else {
char bullet = len % 2 == 0 ? '-' : '*';
memset(writer->start, ' ', 256);
for (int i = 0; i < (len - writer->top) * 4; i++) {
writer->start[i] = ' ';
}
writer->start[(len - writer->top) * 4] = bullet;
writer->start[(len - writer->top) * 4 + 1] = '\0';
}
}
void write_ToC(ToCWriter *writer) {
printf("#### Table of contents\n\n");
FILE *file = fopen(writer->source_file, "r");
char line[256];
int line_number = 0;
while (fgets(line, sizeof(line), file)) {
line_number++;
if (line_number == 1) continue;
if (line[0] != '#') continue;
sscanf(line, "%s %[^\n]", writer->level, writer->header);
if (ignore_this_header(writer)) continue;
set_anchor(writer);
update_if_seen(writer);
set_start(writer);
printf("%s [%s](#%s)\n", writer->start, writer->header, writer->anchor);
}
fclose(file);
}
int main() {
// Define the filename directly
char filename[] = "example.md";
// Define the default TOP and MAX values
int top = TOP;
int max = MAX;
ToCWriter writer;
initialize_ToCWriter(&writer, filename, top, max);
write_ToC(&writer);
free_ToCWriter(&writer);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment