Last active
February 16, 2024 08:54
-
-
Save sartimo/6bf2e103cbb0c9a73945de5918ddfc92 to your computer and use it in GitHub Desktop.
Markdown to ToC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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