145 lines
3.9 KiB
C
145 lines
3.9 KiB
C
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
/* compile with `clang metagen.c -std=c89 -I/usr/include/libxml2 -lxml2' */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <libxml2/libxml/tree.h>
|
|
#include <libxml2/libxml/parser.h>
|
|
#define SMALL 512 /* 0.5KiB */
|
|
#define BIG 524288 /* 512KiB */
|
|
|
|
/*
|
|
This program generates a HTML list of user sites. It was made for Midgard, but
|
|
you can feel free to use it for your own projects and modify it to fit your
|
|
needs (following GNU GPLv3).
|
|
*/
|
|
|
|
void help(char program[]) {
|
|
fprintf(stderr, "Usage: %s /path/to/xml\n", program);
|
|
fprintf(stderr, "For example, %s /srv/http/users/*/site-meta.xml\n", program);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
char* get_child(const char *parent, const char *tag, xmlDocPtr doc, xmlNodePtr node) {
|
|
/* get the content of a nested element */
|
|
static char out[BIG];
|
|
xmlNodePtr child_node = NULL;
|
|
while (node != NULL) {
|
|
if (!xmlStrcmp(node->name, (const xmlChar *)parent)) {
|
|
child_node = node->children;
|
|
break;
|
|
} else {
|
|
node = node->next;
|
|
}
|
|
}
|
|
|
|
while (child_node != NULL) {
|
|
if (!xmlStrcmp(child_node->name, (const xmlChar *)tag)) {
|
|
sprintf(out, "%s", xmlNodeListGetString(doc, child_node->xmlChildrenNode, 1));
|
|
return out;
|
|
}
|
|
child_node = child_node->next;
|
|
}
|
|
|
|
return "NOT_FOUND";
|
|
}
|
|
|
|
char* get_tag(const char* tag, xmlDocPtr doc, xmlNodePtr node) {
|
|
/* get the content of an element */
|
|
static char out[BIG];
|
|
while (node != NULL) {
|
|
if (!xmlStrcmp(node->name, (const xmlChar *)tag)) {
|
|
sprintf(out, "%s", xmlNodeListGetString(doc, node->xmlChildrenNode, 1));
|
|
return out;
|
|
}
|
|
node = node->next;
|
|
}
|
|
return "NOT_FOUND";
|
|
}
|
|
|
|
const char* gen_html(const char* filename) {
|
|
/* This function is more close to being the actual main one,
|
|
it's where the HTML is generated.
|
|
What it generates _should_ be valid XHTML verifiable on https://validator.w3.org,
|
|
if you care about that. */
|
|
xmlDocPtr source = xmlReadFile(filename, NULL, 0);
|
|
xmlNodePtr cur = NULL;
|
|
static char out[BIG];
|
|
|
|
/* these just check if the file is really messed up */
|
|
if (source == NULL) {
|
|
fprintf(stderr, "failed to parse file\n");
|
|
xmlFreeDoc(source);
|
|
} else {
|
|
cur = xmlDocGetRootElement(source);
|
|
}
|
|
|
|
if (cur == NULL) {
|
|
fprintf(stderr, "empty\n");
|
|
xmlFreeDoc(source);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (xmlStrcmp(cur->name, (const xmlChar *) "site")) {
|
|
fprintf(stderr, "root tag must be <site>");
|
|
xmlFreeDoc(source);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
cur = cur->xmlChildrenNode;
|
|
|
|
/* these are for iterating over later */
|
|
char protocols[4][SMALL] = {"gemini", "gopher", "nex", "web"};
|
|
char networks[5][SMALL] = {"i2p_b32", "i2p_ah", "tor", "ygg", "alfis"};
|
|
|
|
/* you're supposed to put the output here into a <dl> */
|
|
/* it's messy, but it works (kind of) */
|
|
printf(" <dt><span class=\"site-title\">%s</span>", get_tag("title", source, cur));
|
|
printf(" <sub>%s</sub></dt>\n", get_tag("lang", source, cur));
|
|
printf(" <dd>\n");
|
|
printf(" <p>\n");
|
|
printf(" %s\n", get_tag("description", source, cur));
|
|
printf(" </p>\n");
|
|
|
|
const char *error = "NOT_FOUND"; /* whatever is in here, if a tag is equal to that it will be discarded */
|
|
|
|
printf(" <p>\n");
|
|
|
|
int i;
|
|
for (i = 0; i < (sizeof(protocols) / sizeof(protocols[0])); i++) {
|
|
char *tag = get_tag(protocols[i], source, cur);
|
|
|
|
if (tag != error) {
|
|
printf(" %s: ", protocols[i]);
|
|
|
|
int j = 0;
|
|
for (j = 0; j < (sizeof(networks) / sizeof(networks[0])); j++) {
|
|
char *tag = get_child(protocols[i], networks[j], source, cur);
|
|
|
|
if (!strcmp(networks[j], "alfis") && tag != error) {
|
|
printf("<a href=\"%s\">ygg (alfis)</a> ", tag);
|
|
} else if (tag != error) {
|
|
printf("<a href=\"%s\">%s</a> ", tag, networks[j]);
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
printf(" </p>\n");
|
|
printf(" </dd>\n");
|
|
|
|
return out;
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
if (argc == 1) {
|
|
help(argv[0]);
|
|
}
|
|
|
|
int i;
|
|
for (i = 1; i < argc; i++) {
|
|
printf("%s", gen_html(argv[i]));
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|