Initial commit
This commit is contained in:
56
src/html.c
Normal file
56
src/html.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
ncdg - A program to help generate natechoe.dev
|
||||
Copyright (C) 2022 Nate Choe (natechoe9@gmail.com)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <html.h>
|
||||
|
||||
/* truncates groups of whitespace into a single space, removes all whitespace
|
||||
* immediately before and after <> characters.
|
||||
*
|
||||
* Example: " < text in html> " -> "<text in html>"
|
||||
* */
|
||||
int copyhtml(FILE *in, FILE *out) {
|
||||
int c;
|
||||
int addspace;
|
||||
for (;;) {
|
||||
addspace = 0;
|
||||
c = fgetc(in);
|
||||
if (c == EOF)
|
||||
return 0;
|
||||
if (isspace(c)) {
|
||||
addspace = 1;
|
||||
while (isspace(c)) {
|
||||
c = fgetc(in);
|
||||
if (c == EOF)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (c == '<' || c == '>') {
|
||||
fputc(c, out);
|
||||
while (isspace(c = fgetc(in))) ;
|
||||
ungetc(c, in);
|
||||
}
|
||||
else {
|
||||
if (addspace)
|
||||
fputc(' ', out);
|
||||
fputc(c, out);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
26
src/include/html.h
Normal file
26
src/include/html.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
ncdg - A program to help generate natechoe.dev
|
||||
Copyright (C) 2022 Nate Choe (natechoe9@gmail.com)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef HAVE_HTML
|
||||
#define HAVE_HTML
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int copyhtml(FILE *in, FILE *out);
|
||||
/* Copies the contents of in to out, minimizing html along the way. */
|
||||
|
||||
#endif
|
||||
25
src/include/template.h
Normal file
25
src/include/template.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
ncdg - A program to help generate natechoe.dev
|
||||
Copyright (C) 2022 Nate Choe (natechoe9@gmail.com)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef HAVE_TEMPLATE
|
||||
#define HAVE_TEMPLATE
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int parsetemplate(FILE *infile, FILE *outfile);
|
||||
|
||||
#endif
|
||||
101
src/main.c
Normal file
101
src/main.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
ncdg - A program to help generate natechoe.dev
|
||||
Copyright (C) 2022 Nate Choe (natechoe9@gmail.com)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define _POSIX_C_SOURCE 2
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <html.h>
|
||||
#include <template.h>
|
||||
|
||||
static void printhelp(FILE *file, char *name);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *header, *template, *footer, *out;
|
||||
FILE *outfile;
|
||||
int c;
|
||||
|
||||
header = template = footer = out = NULL;
|
||||
|
||||
while ((c = getopt(argc, argv, "b:t:e:o:h")) >= 0) {
|
||||
switch (c) {
|
||||
case 'b':
|
||||
header = optarg;
|
||||
break;
|
||||
case 't':
|
||||
template = optarg;
|
||||
break;
|
||||
case 'e':
|
||||
footer = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
out = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
printhelp(stdout, argv[0]);
|
||||
return 0;
|
||||
default:
|
||||
printhelp(stderr, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (out == NULL)
|
||||
outfile = stdout;
|
||||
else
|
||||
outfile = fopen(out, "w");
|
||||
|
||||
if (header != NULL) {
|
||||
FILE *headerfile;
|
||||
headerfile = fopen(header, "r");
|
||||
if (copyhtml(headerfile, outfile)) {
|
||||
fputs("Failed to copy header\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
fclose(headerfile);
|
||||
}
|
||||
if (template != NULL) {
|
||||
FILE *templatefile;
|
||||
templatefile = fopen(template, "r");
|
||||
if (parsetemplate(templatefile, outfile))
|
||||
return 1;
|
||||
fclose(templatefile);
|
||||
}
|
||||
if (footer != NULL) {
|
||||
FILE *footerfile;
|
||||
footerfile = fopen(footer, "r");
|
||||
if (copyhtml(footerfile, outfile)) {
|
||||
fputs("Failed to copy footer\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
fclose(footerfile);
|
||||
}
|
||||
if (outfile != stdout)
|
||||
fclose(outfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void printhelp(FILE *file, char *name) {
|
||||
fprintf(file,
|
||||
"Usage: %s -b [header] -t [template] -e [footer] -o [output]", name);
|
||||
fputs(
|
||||
"This program is free software. You can redistribute and/or modify it under\n"
|
||||
"the terms of the GNU General Public License as published by the Free\n"
|
||||
"Software Foundation, either version 3 of the License, or (at your option)\n"
|
||||
"any later version.\n", file);
|
||||
}
|
||||
371
src/template.c
Normal file
371
src/template.c
Normal file
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
ncdg - A program to help generate natechoe.dev
|
||||
Copyright (C) 2022 Nate Choe (natechoe9@gmail.com)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <template.h>
|
||||
|
||||
struct linefile {
|
||||
char *prevline;
|
||||
FILE *file;
|
||||
};
|
||||
|
||||
enum paratype {
|
||||
NORMAL,
|
||||
EMPTY,
|
||||
H1, H2, H3, H4, H5, H6,
|
||||
BLOCKQUOTE,
|
||||
CODESPACE, CODEBACK,
|
||||
UL, OL,
|
||||
HL
|
||||
};
|
||||
|
||||
static int parsepara(struct linefile *infile, FILE *outfile);
|
||||
static enum paratype identifypara(char *line, char **contentret);
|
||||
|
||||
static char *untrail(char *line);
|
||||
static size_t reallen(char *line);
|
||||
static int islinebreak(char *line);
|
||||
|
||||
static int paraeasycase(struct linefile *infile, FILE *outfile,
|
||||
char *line, char *buff,
|
||||
char *tag, enum paratype type);
|
||||
static int parahardcase(struct linefile *infile, FILE *outfile,
|
||||
char *line, char *buff,
|
||||
char *vars, char *linetag, char *tag, enum paratype type);
|
||||
static int paracodecase(struct linefile *infile, FILE *outfile,
|
||||
char *line, char *buff,
|
||||
char *vars, enum paratype type);
|
||||
|
||||
static void ungetline(struct linefile *file, char *line);
|
||||
static char *getline(struct linefile *file);
|
||||
|
||||
int parsetemplate(FILE *infile, FILE *outfile) {
|
||||
struct linefile realin;
|
||||
realin.prevline = NULL;
|
||||
realin.file = infile;
|
||||
while (parsepara(&realin, outfile) == 0) ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parsepara(struct linefile *infile, FILE *outfile) {
|
||||
for (;;) {
|
||||
char *line, *buff;
|
||||
/* line exists for the explicit purpose of being freed later */
|
||||
enum paratype type;
|
||||
|
||||
line = getline(infile);
|
||||
if (line == NULL)
|
||||
return 1;
|
||||
type = identifypara(line, &buff);
|
||||
|
||||
buff = untrail(buff);
|
||||
|
||||
if (buff[0] == '\0') {
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
#define EASY_CASE(enumtype, tag) \
|
||||
case enumtype: \
|
||||
paraeasycase(infile, outfile, line, buff, \
|
||||
tag, enumtype); \
|
||||
return 0;
|
||||
#define HARD_CASE(enumtype, tag, linetag, vars) \
|
||||
case enumtype: \
|
||||
parahardcase(infile, outfile, line, buff, \
|
||||
vars, linetag, tag, enumtype); \
|
||||
return 0;
|
||||
#define CODE_CASE(enumtype, vars) \
|
||||
case enumtype: \
|
||||
paracodecase(infile, outfile, line, buff, \
|
||||
vars, enumtype); \
|
||||
return 0;
|
||||
EASY_CASE(H1, "h1");
|
||||
EASY_CASE(H2, "h2");
|
||||
EASY_CASE(H3, "h3");
|
||||
EASY_CASE(H4, "h4");
|
||||
EASY_CASE(H5, "h5");
|
||||
EASY_CASE(H6, "h6");
|
||||
HARD_CASE(NORMAL, "p", NULL, NULL);
|
||||
HARD_CASE(BLOCKQUOTE, "blockquote", NULL, NULL);
|
||||
HARD_CASE(UL, "ul", "li", NULL);
|
||||
HARD_CASE(OL, "ol", "li", NULL);
|
||||
CODE_CASE(CODESPACE, "class='block'");
|
||||
CODE_CASE(CODEBACK, "class='block'");
|
||||
case HL:
|
||||
fputs("<hr />", outfile);
|
||||
free(line);
|
||||
return 0;
|
||||
case EMPTY:
|
||||
free(line);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static enum paratype identifypara(char *line, char **contentret) {
|
||||
int i, count;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
if (line[i] == ' ')
|
||||
continue;
|
||||
if (line[i] == '\0')
|
||||
return EMPTY;
|
||||
goto whitegone;
|
||||
}
|
||||
|
||||
*contentret = line + i;
|
||||
return CODESPACE;
|
||||
|
||||
whitegone:
|
||||
line += i;
|
||||
/* At this point, line has no extraneous trailing whitespace */
|
||||
switch (line[0]) {
|
||||
case '\0':
|
||||
return EMPTY;
|
||||
case '#':
|
||||
for (i = 0; i < 6 && line[i] == '#'; ++i) ;
|
||||
*contentret = line + i;
|
||||
return H1 + i - 1;
|
||||
case '>':
|
||||
*contentret = line + 1;
|
||||
return BLOCKQUOTE;
|
||||
case '-':
|
||||
count = 0;
|
||||
for (i = 0; line[i] != '\0'; ++i) {
|
||||
if (line[i] == '-')
|
||||
++count;
|
||||
if (count == 3)
|
||||
return HL;
|
||||
}
|
||||
case '*':
|
||||
*contentret = line + 1;
|
||||
return UL;
|
||||
case '`':
|
||||
for (i = 0; i < 3; ++i)
|
||||
if (line[i] != '`')
|
||||
return NORMAL;
|
||||
return CODEBACK;
|
||||
default:
|
||||
if (isdigit(line[0])) {
|
||||
for (i = 0; isdigit(line[i]); ++i) ;
|
||||
if (line[i] == '.' || line[i] == ')') {
|
||||
*contentret = line + i + 1;
|
||||
return OL;
|
||||
}
|
||||
}
|
||||
*contentret = line;
|
||||
return NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
static char *untrail(char *line) {
|
||||
while (isspace(line[0]))
|
||||
++line;
|
||||
return line;
|
||||
}
|
||||
|
||||
static size_t reallen(char *line) {
|
||||
size_t fakelen;
|
||||
fakelen = strlen(line);
|
||||
if (line[fakelen - 1] == '\\')
|
||||
--fakelen;
|
||||
while (isspace(line[fakelen]))
|
||||
--fakelen;
|
||||
return fakelen;
|
||||
}
|
||||
|
||||
static int islinebreak(char *line) {
|
||||
size_t len;
|
||||
int i;
|
||||
len = strlen(line);
|
||||
if (line[len - 1] == '\\')
|
||||
return 1;
|
||||
if (len < 2)
|
||||
return 0;
|
||||
for (i = 0; i < 2; ++i)
|
||||
if (!isspace(line[len - i - 1]))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int paraeasycase(struct linefile *infile, FILE *outfile,
|
||||
char *line, char *buff,
|
||||
char *tag, enum paratype type) {
|
||||
size_t writelen;
|
||||
|
||||
writelen = reallen(buff);
|
||||
|
||||
fprintf(outfile, "<%s>", tag);
|
||||
for (;;) {
|
||||
fwrite(buff, sizeof(*buff), writelen, outfile);
|
||||
free(line);
|
||||
line = getline(infile);
|
||||
if (line == NULL)
|
||||
break;
|
||||
if (identifypara(line, &buff) != type) {
|
||||
ungetline(infile, line);
|
||||
line = NULL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
buff = untrail(buff);
|
||||
}
|
||||
fprintf(outfile, "</%s>", tag);
|
||||
|
||||
free(line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parahardcase(struct linefile *infile, FILE *outfile,
|
||||
char *line, char *buff,
|
||||
char *vars, char *linetag, char *tag, enum paratype type) {
|
||||
size_t writelen;
|
||||
|
||||
if (vars == NULL)
|
||||
fprintf(outfile, "<%s>", tag);
|
||||
else
|
||||
fprintf(outfile, "<%s %s>", tag, vars);
|
||||
for (;;) {
|
||||
writelen = reallen(buff);
|
||||
|
||||
if (linetag != NULL)
|
||||
fprintf(outfile, "<%s>", linetag);
|
||||
fwrite(buff, sizeof(*buff), writelen, outfile);
|
||||
if (islinebreak(line))
|
||||
fputs("<br />", outfile);
|
||||
if (linetag != NULL)
|
||||
fprintf(outfile, "</%s>", linetag);
|
||||
|
||||
free(line);
|
||||
line = getline(infile);
|
||||
if (line == NULL)
|
||||
break;
|
||||
if (identifypara(line, &buff) != type) {
|
||||
buff = untrail(line);
|
||||
if (buff[0] == '\0') {
|
||||
free(line);
|
||||
line = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
buff = untrail(buff);
|
||||
}
|
||||
fprintf(outfile, "</%s>", tag);
|
||||
|
||||
free(line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int paracodecase(struct linefile *infile, FILE *outfile,
|
||||
char *line, char *buff,
|
||||
char *vars, enum paratype type) {
|
||||
int seenfirst;
|
||||
enum paratype newtype;
|
||||
|
||||
if (type != CODESPACE && type != CODEBACK)
|
||||
return 1;
|
||||
|
||||
if (vars == NULL)
|
||||
fputs("<code>", outfile);
|
||||
else
|
||||
fprintf(outfile, "<code %s>", vars);
|
||||
seenfirst = 0;
|
||||
newtype = type;
|
||||
for (;;) {
|
||||
if ((type == CODEBACK && type != newtype) ||
|
||||
newtype == CODESPACE) {
|
||||
if (seenfirst)
|
||||
fputs("<br />", outfile);
|
||||
seenfirst = 1;
|
||||
}
|
||||
|
||||
if (newtype != CODEBACK)
|
||||
fputs(buff, outfile);
|
||||
|
||||
free(line);
|
||||
line = getline(infile);
|
||||
if (line == NULL)
|
||||
return 1;
|
||||
|
||||
newtype = identifypara(line, &buff);
|
||||
if (type == CODEBACK && newtype == CODEBACK)
|
||||
break;
|
||||
if (type == CODESPACE && newtype != type) {
|
||||
ungetline(infile, line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fputs("</code>", outfile);
|
||||
|
||||
if (type == CODEBACK)
|
||||
free(line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ungetline(struct linefile *file, char *line) {
|
||||
file->prevline = line;
|
||||
}
|
||||
|
||||
static char *getline(struct linefile *file) {
|
||||
size_t alloc;
|
||||
size_t len;
|
||||
char *ret;
|
||||
int c;
|
||||
|
||||
if (file->prevline != NULL) {
|
||||
ret = file->prevline;
|
||||
file->prevline = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
c = fgetc(file->file);
|
||||
if (c == EOF)
|
||||
return NULL;
|
||||
ungetc(c, file->file);
|
||||
|
||||
alloc = 80;
|
||||
len = 0;
|
||||
ret = malloc(alloc);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
|
||||
for (;;) {
|
||||
if (len >= alloc) {
|
||||
char *newret;
|
||||
alloc *= 2;
|
||||
newret = realloc(ret, alloc);
|
||||
if (newret == NULL) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret = newret;
|
||||
}
|
||||
c = fgetc(file->file);
|
||||
if (c == '\n') {
|
||||
ret[len] = '\0';
|
||||
return ret;
|
||||
}
|
||||
ret[len++] = c;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user