Implement incoming links

This commit is contained in:
Nat 2023-01-20 09:23:19 -08:00
parent c7e413c6e5
commit 046e31f91e
Signed by: nat
GPG Key ID: B53AB05285D710D6
2 changed files with 110 additions and 14 deletions

View File

@ -12,7 +12,7 @@ over explain every line of code.
## Features ## Features
- [x] Rendering wikilinks - [x] Rendering wikilinks
- [ ] Ability to keep track of incoming links - [x] Ability to keep track of incoming links
- [ ] Named wikilinks (i.e. `[[link title|actual page]]`) - [ ] Named wikilinks (i.e. `[[link title|actual page]]`)
## installation ## installation

View File

@ -11,6 +11,7 @@ struct Page {
char title[80]; char title[80];
char *permalink; char *permalink;
struct Page *next; struct Page *next;
struct PageList *incoming;
char *content; char *content;
}; };
@ -93,14 +94,52 @@ struct Page * map_get(struct Page **map, int mapSize, char title[]) {
return page; return page;
} }
/*** Dynamic Array Implementation ***/
struct PageList {
struct Page **pages;
int length;
int capacity;
};
struct PageList * page_list(int capacity) {
struct PageList *pageList = malloc(sizeof(struct PageList));
pageList->pages = malloc(sizeof(struct Page *) * capacity);
pageList->capacity = capacity;
pageList->length = 0;
return pageList;
}
void page_list_insert(struct PageList *list, struct Page *page) {
// If the page is already present in the list, we don't bother adding it again
for (int i = 0; i < list->length; i++) {
if (page == list->pages[i]) {
return;
}
}
// Increase the length of the array if necessary
if (list->length >= list->capacity) {
list->pages = realloc(list->pages, (list->capacity + 1)*sizeof(struct Page *));
}
list->pages[list->length] = page;
list->length++;
}
void page_list_free(struct PageList *list) {
free(list->pages);
free(list);
}
/*** Templating ***/ /*** Templating ***/
char * substitute_string(char dest[], char sub[], char *start, char *end) { char * substitute_string(char dest[], char sub[], char *start, char *end) {
int startIndex = start - dest; int startIndex = start - dest;
int newLength = strlen(dest) - (end - start) + strlen(sub) + 1; int newLength = strlen(dest) - (end - start) + strlen(sub) + 1;
char * compiled = malloc(newLength * sizeof(char)); char *compiled = malloc(newLength * sizeof(char));
compiled[0] = 0; memset(compiled, 0, newLength * sizeof(char));
strncpy(compiled, dest, startIndex); strncpy(compiled, dest, startIndex);
strcat(compiled, sub); strcat(compiled, sub);
strcat(compiled, end); strcat(compiled, end);
@ -111,6 +150,7 @@ char * substitute_string(char dest[], char sub[], char *start, char *end) {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
char pagesLocation[256] = "./pages"; char pagesLocation[256] = "./pages";
int mapSize = 1000; int mapSize = 1000;
int initialInboundCapacity = 2;
char templateFileName[256] = "./template.html"; char templateFileName[256] = "./template.html";
char outputDirectoryName[256] = "./build"; char outputDirectoryName[256] = "./build";
@ -137,6 +177,11 @@ int main(int argc, char *argv[]) {
i++; i++;
strcpy(outputDirectoryName, argv[i]); strcpy(outputDirectoryName, argv[i]);
} }
} else if (strcmp(argv[i], "--incoming-cap") == 0) {
if (i + 1 < argc) {
i++;
initialInboundCapacity = atoi(argv[i]);
}
} else { } else {
printf("Unknown argument: %s\n", argv[i]); printf("Unknown argument: %s\n", argv[i]);
} }
@ -194,6 +239,8 @@ int main(int argc, char *argv[]) {
} }
} }
currentPage->incoming = page_list(initialInboundCapacity);
// Build the page's permalink // Build the page's permalink
currentPage->permalink = malloc(strlen(fileBasename) + 6); currentPage->permalink = malloc(strlen(fileBasename) + 6);
@ -274,7 +321,7 @@ int main(int argc, char *argv[]) {
free(createOutputDir); free(createOutputDir);
/*** Page Processing ***/ /*** Link Processing ***/
currentPage = firstPage; currentPage = firstPage;
while (currentPage != NULL) { while (currentPage != NULL) {
// Scan the file for links // Scan the file for links
@ -298,6 +345,7 @@ int main(int argc, char *argv[]) {
title[linkLength - 2] = 0; title[linkLength - 2] = 0;
struct Page *linkedPage = map_get(pageMap, mapSize, title); struct Page *linkedPage = map_get(pageMap, mapSize, title);
char *compiledLink; char *compiledLink;
if (linkedPage == NULL) { if (linkedPage == NULL) {
@ -307,6 +355,7 @@ int main(int argc, char *argv[]) {
strcat(compiledLink, title); strcat(compiledLink, title);
strcat(compiledLink, "</a>\0"); strcat(compiledLink, "</a>\0");
} else { } else {
page_list_insert(linkedPage->incoming, currentPage);
compiledLink = malloc(strlen(title) + strlen(linkedPage->permalink) + 5); compiledLink = malloc(strlen(title) + strlen(linkedPage->permalink) + 5);
strcpy(compiledLink, "["); strcpy(compiledLink, "[");
strcat(compiledLink, title); strcat(compiledLink, title);
@ -331,6 +380,12 @@ int main(int argc, char *argv[]) {
nextLinkStart = strstr(currentPage->content, "[["); nextLinkStart = strstr(currentPage->content, "[[");
} }
currentPage = currentPage->next;
}
/*** Rendering ***/
currentPage = firstPage;
while (currentPage != NULL) {
// Compile the markdown // Compile the markdown
currentPage->content = cmark_markdown_to_html( currentPage->content = cmark_markdown_to_html(
currentPage->content, currentPage->content,
@ -338,19 +393,58 @@ int main(int argc, char *argv[]) {
(1 << 17) // Disables safe mode, allowing raw HTML (1 << 17) // Disables safe mode, allowing raw HTML
); );
// Insert the content into the template
char *renderedPage = NULL;
char *templateTagStart = strstr(templateContent, "{{content}}"); char *templateTagStart = strstr(templateContent, "{{content}}");
char *renderedPageContent = substitute_string( char *renderedWithContent = substitute_string(
templateContent, templateContent,
currentPage->content, currentPage->content,
templateTagStart, templateTagStart,
templateTagStart + 11 templateTagStart + 11
); );
renderedPage = renderedWithContent;
char *incomingTagStart = strstr(renderedPage, "{{incoming}}");
if (incomingTagStart != NULL) {
// Build the incoming links list
int incomingListSize = 37; // <ul class="calathea-incoming">\n</ul>\n
for (int i = 0; i < currentPage->incoming->length; i++) {
// ` <li><a href=\"[permalink]\">[title]</a></li>\n`
struct Page *page = currentPage->incoming->pages[i];
incomingListSize += 27 + strlen(page->title) + strlen(page->permalink);
}
char *incomingLinksList = malloc((incomingListSize + 1) * sizeof(char));
memset(incomingLinksList, 0, (incomingListSize + 1) * sizeof(char));
strcpy(incomingLinksList, "<ul class=\"calathea-incoming\">\n");
for (int i = 0; i < currentPage->incoming->length; i++) {
struct Page *page = currentPage->incoming->pages[i];
strcat(incomingLinksList, " <li><a href=\"");
strcat(incomingLinksList, page->permalink);
strcat(incomingLinksList, "\">");
strcat(incomingLinksList, page->title);
strcat(incomingLinksList, "</a></li>\n");
}
strcat(incomingLinksList, "</ul>\n");
char *renderedWithInbound = substitute_string(
renderedPage,
incomingLinksList,
incomingTagStart,
incomingTagStart + 12
);
renderedPage = renderedWithInbound;
free(renderedWithContent);
}
// Output the page to the file // Output the page to the file
char *outputFileName = malloc( char *outputFileName = malloc(
(strlen(outputDirectoryName) (strlen(outputDirectoryName)
+ strlen(currentPage->permalink) + strlen(currentPage->permalink)
+ 2)); + 2));
strcpy(outputFileName, outputDirectoryName); strcpy(outputFileName, outputDirectoryName);
strcat(outputFileName, "/\0"); strcat(outputFileName, "/\0");
strcat(outputFileName, currentPage->permalink); strcat(outputFileName, currentPage->permalink);
@ -358,23 +452,25 @@ int main(int argc, char *argv[]) {
FILE *outputFile = fopen(outputFileName, "w"); FILE *outputFile = fopen(outputFileName, "w");
if (outputFile != NULL) { if (outputFile != NULL) {
fputs(renderedPageContent, outputFile); fputs(renderedPage, outputFile);
fclose(outputFile); fclose(outputFile);
} else { } else {
printf("Warning: failed to create %s\n", outputFileName); printf("Warning: failed to create %s\n", outputFileName);
} }
free(outputFileName); free(outputFileName);
free(renderedPageContent); free(renderedPage);
currentPage = currentPage->next; currentPage = currentPage->next;
} }
/*** Deallocation and whatnot ***/ /*** Deallocation and whatnot ***/
currentPage = firstPage; currentPage = firstPage;
while (currentPage != NULL) { while (currentPage != NULL) {
free(currentPage->content); free(currentPage->content);
free(currentPage->permalink); free(currentPage->permalink);
page_list_free(currentPage->incoming);
struct Page *next = currentPage->next; struct Page *next = currentPage->next;
free(currentPage); free(currentPage);
currentPage = next; currentPage = next;