Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cf79834870 | |||
| 4171c81bfd | |||
| 09b801c150 | |||
| 1807044977 | |||
|
|
da8080a7de | ||
|
|
ddee2d2702 | ||
|
|
ec5275ab88 | ||
|
|
3b94588d25 | ||
|
|
321731f51f | ||
|
|
dad4175887 | ||
|
|
95834f00ff | ||
|
|
44b2187d76 | ||
|
|
c98e91d810 | ||
|
|
5c693aa638 | ||
|
|
517a9d9605 | ||
|
|
9a084fe0bd | ||
|
|
91e3daf3dc |
22
COPYING
Normal file
22
COPYING
Normal file
@@ -0,0 +1,22 @@
|
||||
COPYRIGHT (C) 2015-2017 by David Baer <david@amyanddavid.net>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -1,2 +1,3 @@
|
||||
SUBDIRS = src data
|
||||
dist_doc_DATA = README.md
|
||||
dist_man1_MANS = sermon.1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
sermon 1.0
|
||||
sermon 1.4
|
||||
==========
|
||||
|
||||
This utility converts text markup into various presentable forms.
|
||||
|
||||
10
configure.ac
10
configure.ac
@@ -2,13 +2,13 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([sermon], [1.1], [david.a.baer@gmail.com])
|
||||
AC_INIT([sermon], [1.5], [david.a.baer@gmail.com])
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
|
||||
AC_CONFIG_SRCDIR([config.h.in])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_C99
|
||||
AC_PROG_LEX
|
||||
AC_PROG_YACC
|
||||
|
||||
@@ -24,16 +24,20 @@ AC_CHECK_HEADERS([inttypes.h libintl.h limits.h malloc.h stddef.h stdint.h stdli
|
||||
AC_C_INLINE
|
||||
AC_TYPE_INT16_T
|
||||
AC_TYPE_INT32_T
|
||||
AC_TYPE_INT64_T
|
||||
AC_TYPE_INT8_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT64_T
|
||||
AC_TYPE_UINT8_T
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_FORK
|
||||
AC_FUNC_MALLOC
|
||||
AC_FUNC_REALLOC
|
||||
AC_CHECK_FUNCS([memset pledge realpath strdup strndup])
|
||||
AC_CHECK_FUNCS([localtime_r pledge memset realpath strcasecmp strdup strndup strrchr])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
data/Makefile
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="ser:p" mode="quote">
|
||||
<text:p text:style-name="Quotations"><text:span text:style-name="T2"><xsl:apply-templates select="*|text()"/></text:span></text:p>
|
||||
<text:p text:style-name="Quotations"><xsl:apply-templates select="*|text()"/></text:p>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="ser:quote" mode="body">
|
||||
|
||||
35
src/format.c
35
src/format.c
@@ -27,6 +27,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "queue.h"
|
||||
#include "stack.h"
|
||||
@@ -45,6 +46,7 @@ typedef enum {
|
||||
TOK_STAR,
|
||||
TOK_REF,
|
||||
TOK_URL,
|
||||
TOK_BREAK,
|
||||
/*
|
||||
TOK_DASH,
|
||||
TOK_OPEN_DOUBLE_QUOTE,
|
||||
@@ -69,35 +71,35 @@ freeTokenizer(utf8iterator* iter) {
|
||||
utf8FreeIterator(iter);
|
||||
}
|
||||
|
||||
inline int
|
||||
int
|
||||
greekChar(uint32_t ch) {
|
||||
return (((0x370 <= ch) && (ch <= 0x3ff)) ||
|
||||
((0x1f00 <= ch) && (ch <= 0x1fff)));
|
||||
}
|
||||
|
||||
inline int
|
||||
int
|
||||
extendedPunctuation(uint32_t ch) {
|
||||
return ((0x2000 <= ch) && (ch <= 0x206f));
|
||||
}
|
||||
|
||||
inline int
|
||||
int
|
||||
latinChar(uint32_t ch) {
|
||||
return (ch <= 0xff) || extendedPunctuation(ch);
|
||||
}
|
||||
|
||||
inline int
|
||||
int
|
||||
httpAt(Tokenizer tokenizer) {
|
||||
return ((tolower(tokenizer->txt[tokenizer->byteIndex]) == 'h') &&
|
||||
(tolower(tokenizer->txt[tokenizer->byteIndex + 1]) == 't') &&
|
||||
(tolower(tokenizer->txt[tokenizer->byteIndex + 2]) == 't') &&
|
||||
(tolower(tokenizer->txt[tokenizer->byteIndex + 3]) == 'p') &&
|
||||
((tokenizer->txt[tokenizer->byteIndex + 4] == ':') &&
|
||||
(tokenizer->txt[tokenizer->byteIndex + 5] == '/') &&
|
||||
(tokenizer->txt[tokenizer->byteIndex + 6] == '/')) ||
|
||||
((tolower(tokenizer->txt[tokenizer->byteIndex + 4]) == 's') &&
|
||||
(tokenizer->txt[tokenizer->byteIndex + 5] == ':') &&
|
||||
(tokenizer->txt[tokenizer->byteIndex + 6] == '/') &&
|
||||
(tokenizer->txt[tokenizer->byteIndex + 7] == '/')));
|
||||
(((tokenizer->txt[tokenizer->byteIndex + 4] == ':') &&
|
||||
(tokenizer->txt[tokenizer->byteIndex + 5] == '/') &&
|
||||
(tokenizer->txt[tokenizer->byteIndex + 6] == '/')) ||
|
||||
((tolower(tokenizer->txt[tokenizer->byteIndex + 4]) == 's') &&
|
||||
(tokenizer->txt[tokenizer->byteIndex + 5] == ':') &&
|
||||
(tokenizer->txt[tokenizer->byteIndex + 6] == '/') &&
|
||||
(tokenizer->txt[tokenizer->byteIndex + 7] == '/'))));
|
||||
}
|
||||
|
||||
static Token
|
||||
@@ -115,6 +117,11 @@ nextToken(Tokenizer tokenizer) {
|
||||
result.toktype = TOK_STAR;
|
||||
result.toktext = NULL;
|
||||
return result;
|
||||
} else if (ch == '\n') {
|
||||
utf8Advance(tokenizer);
|
||||
result.toktype = TOK_BREAK;
|
||||
result.toktext = NULL;
|
||||
return result;
|
||||
} else if (greekChar(ch)) {
|
||||
while ((ch != 0) &&
|
||||
(greekChar(ch) || (ch == ' ') || (ch == ',') || (ch == '.'))) {
|
||||
@@ -158,7 +165,7 @@ nextToken(Tokenizer tokenizer) {
|
||||
result.toktext = strndup(tokenizer->txt + startIndex, endIndex - startIndex);
|
||||
return result;
|
||||
} else if (latinChar(ch)) {
|
||||
while ((ch != 0) && latinChar(ch) && (ch != '*')) {
|
||||
while ((ch != 0) && latinChar(ch) && (ch != '*') && (ch != '\n')) {
|
||||
utf8Advance(tokenizer);
|
||||
ch = utf8CharAt(tokenizer);
|
||||
if (ch == '^') {
|
||||
@@ -206,6 +213,10 @@ int formatText(const char* txt, FormatElement** dst, CitationRecordQueue* citati
|
||||
REINIT_QUEUE(formatElementQ);
|
||||
em = 1;
|
||||
}
|
||||
} else if (tok.toktype == TOK_BREAK) {
|
||||
FormatElement elt = { .elementType = FORMAT_BR, .elementContentLength = 0,
|
||||
.elementContent = { .textContent = NULL } };
|
||||
APPEND_QUEUE(FormatElementQueue, formatElementQ, elt);
|
||||
} else {
|
||||
FormatElementType t;
|
||||
FormatElement elt = { .elementContent = { .textContent = tok.toktext } } ;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
typedef enum {
|
||||
FORMAT_TEXT,
|
||||
FORMAT_EM,
|
||||
FORMAT_BR,
|
||||
FORMAT_STRONG,
|
||||
FORMAT_CITATION,
|
||||
FORMAT_GREEK,
|
||||
|
||||
40
src/odt.c
40
src/odt.c
@@ -31,6 +31,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include "odt.h"
|
||||
#include "options.h"
|
||||
|
||||
@@ -50,7 +51,7 @@ extractTemplateDocument(const char* const templateFilename, const char* const te
|
||||
pid_t child_pid;
|
||||
if ((child_pid = fork()) == 0) {
|
||||
/* you are the child */
|
||||
char* const args[] = { "unzip", "-d", tempDir, templateFilename, NULL };
|
||||
char* const args[] = { "unzip", "-d", (char* const)tempDir, (char* const)templateFilename, NULL };
|
||||
freopen("/dev/null", "w", stdout);
|
||||
execvp("unzip", args);
|
||||
perror("execvp");
|
||||
@@ -72,9 +73,40 @@ createOutputDocument(const char* const outputFilename, const char* const tempDir
|
||||
pid_t child_pid;
|
||||
if ((child_pid = fork()) == 0) {
|
||||
/* you are the child */
|
||||
|
||||
/* In some implementations, realpath will give an error
|
||||
* if the file does not exist, so we need to run it on
|
||||
* the output directory, not the as-yet nonexistent
|
||||
* output filename. That's what all this (below) is for. */
|
||||
char outputDir[FILENAME_MAX];
|
||||
char outputBase[FILENAME_MAX];
|
||||
char outputRealPath[FILENAME_MAX];
|
||||
char* const args[] = { "zip", "-r", outputRealPath, ".", NULL };
|
||||
realpath(outputFilename, outputRealPath);
|
||||
strncpy(outputDir, outputFilename, FILENAME_MAX);
|
||||
char *ptr = strrchr(outputDir, '/');
|
||||
if (ptr) {
|
||||
strncpy(outputBase, ptr + 1, FILENAME_MAX);
|
||||
*(ptr + 1) = '\0';
|
||||
} else {
|
||||
strncpy(outputDir, ".", FILENAME_MAX);
|
||||
strncpy(outputBase, outputFilename, FILENAME_MAX);
|
||||
}
|
||||
|
||||
if (realpath(outputDir, outputRealPath) == NULL) {
|
||||
/* hopefully this doesn't run, but it will give good info
|
||||
* if it does */
|
||||
perror("realpath");
|
||||
fprintf(stderr, "outputFilename was \"%s\"\n", outputFilename);
|
||||
char curdir[FILENAME_MAX];
|
||||
getcwd(curdir, FILENAME_MAX);
|
||||
fprintf(stderr, "curdir was \"%s\"\n", curdir);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Then we append the output filename. */
|
||||
strncat(outputRealPath, "/", FILENAME_MAX);
|
||||
strncat(outputRealPath, outputBase, FILENAME_MAX);
|
||||
|
||||
char* const args[] = { "zip", "-r", outputRealPath, "mimetype", ".", NULL };
|
||||
chdir(tempDir);
|
||||
freopen("/dev/null", "w", stdout);
|
||||
execvp("zip", args);
|
||||
@@ -97,7 +129,7 @@ removeDirectory(const char* const tempDir) {
|
||||
pid_t child_pid;
|
||||
if ((child_pid = fork()) == 0) {
|
||||
/* you are the child */
|
||||
char* const args[] = { "rm", "-rf", tempDir, NULL };
|
||||
char* const args[] = { "rm", "-rf", (char* const)tempDir, NULL };
|
||||
freopen("/dev/null", "w", stdout);
|
||||
execvp("rm", args);
|
||||
perror("execvp");
|
||||
|
||||
@@ -69,7 +69,7 @@ typedef struct { \
|
||||
} N
|
||||
|
||||
#define NEW_QUEUE(T, N) \
|
||||
T N = (T) { .length = 0, .head = NULL, .tail = NULL }
|
||||
T N = { .length = 0, .head = NULL, .tail = NULL }
|
||||
|
||||
/* WARNING: this is probably not what you want -- see DESTROY_QUEUE below */
|
||||
#define REINIT_QUEUE(N) { \
|
||||
|
||||
@@ -38,7 +38,8 @@ typedef struct {
|
||||
|
||||
typedef enum {
|
||||
PARA_DEFAULT,
|
||||
PARA_BLOCKQUOTE
|
||||
PARA_BLOCKQUOTE,
|
||||
PARA_BLOCKPRESERVE
|
||||
} SermonParagraphType;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define LEXPRINT(x...)
|
||||
#endif
|
||||
%}
|
||||
%option noyywrap
|
||||
%s HEADER HEADERVAL REFERENCEINTRO REFERENCENAME REFERENCE BLOCK
|
||||
WHITESPACE [ \t]
|
||||
ID [A-Za-z_][A-Za-z_0-9]*
|
||||
@@ -23,14 +24,23 @@ ID [A-Za-z_][A-Za-z_0-9]*
|
||||
<REFERENCEINTRO>ref { yylloc.first_column = yylloc.last_column + 1; yylloc.last_column = yylloc.first_column + 2; return KW_REF; }
|
||||
<REFERENCEINTRO>: { BEGIN(REFERENCENAME); yylloc.first_column = ++yylloc.last_column; return ':'; }
|
||||
<REFERENCENAME>{ID} { yylloc.first_column = yylloc.last_column + 1; yylloc.last_column = yylloc.first_column + strlen(yytext) + 1; yylval.sval = strdup(yytext); return ID; }
|
||||
<REFERENCENAME>: { BEGIN(REFERENCE); yylloc.first_column = ++yylloc.last_column; return ':'; }
|
||||
<REFERENCE>[^}]* { yylloc.first_column = yylloc.last_column + 1; yylloc.last_column = yylloc.first_column + strlen(yytext) + 1; yylval.sval = strdup(yytext); return REFTEXT; }
|
||||
<REFERENCE>[}] { BEGIN(INITIAL); yylloc.first_column = ++yylloc.last_column; return '}'; }
|
||||
^[^[{>\n].* { yylloc.first_column = ++yylloc.last_column; yylval.sval = strdup(yytext); LEXPRINT("LINE: %s\n", yytext); return LINE; }
|
||||
^>{WHITESPACE}*\n { yylloc.first_column = yylloc.last_column = 0; yylloc.first_line++; yylloc.last_line++; return '\n'; }
|
||||
^>{WHITESPACE}* { BEGIN(BLOCK); yylloc.first_column = yylloc.last_column = 1; return '>'; }
|
||||
<BLOCK>..* { BEGIN(INITIAL); yylloc.first_column = yylloc.last_column + 1; yylloc.last_column = yylloc.first_column + strlen(yytext) - 1; yylval.sval = strdup(yytext); return LINE; }
|
||||
<REFERENCENAME>: { BEGIN(REFERENCE); yylloc.first_column = ++yylloc.last_column; return ':'; }
|
||||
<REFERENCE>[^}]* { yylloc.first_column = yylloc.last_column + 1; yylloc.last_column = yylloc.first_column + strlen(yytext) + 1; yylval.sval = strdup(yytext); return REFTEXT; }
|
||||
<REFERENCE>[}] { BEGIN(INITIAL); yylloc.first_column = ++yylloc.last_column; return '}'; }
|
||||
^[^[{>|\n].* { yylloc.first_column = ++yylloc.last_column; yylval.sval = strdup(yytext); LEXPRINT("LINE: %s\n", yytext); return LINE; }
|
||||
^[>|]{WHITESPACE}*\n { yylloc.first_column = yylloc.last_column = 0; yylloc.first_line++; yylloc.last_line++; return '\n'; }
|
||||
^[>|]{WHITESPACE}* {
|
||||
BEGIN(BLOCK);
|
||||
yylloc.first_column = yylloc.last_column = 1;
|
||||
return yytext[0];
|
||||
}
|
||||
<BLOCK>..* {
|
||||
BEGIN(INITIAL);
|
||||
yylloc.first_column = yylloc.last_column + 1;
|
||||
yylloc.last_column = yylloc.first_column + strlen(yytext) - 1;
|
||||
yylval.sval = strdup(yytext); return LINE;
|
||||
}
|
||||
<INITIAL>\n { yylloc.first_column = yylloc.last_column = 0; yylloc.first_line++; yylloc.last_line++; return '\n'; }
|
||||
<<EOF>> { return 0; }
|
||||
<<EOF>> { return 0; }
|
||||
%%
|
||||
|
||||
|
||||
@@ -37,7 +37,13 @@ char* lineQueueToString(LineQueue* lq) {
|
||||
FOREACH_QUEUE(LineQueue, *lq, ptr) {
|
||||
strncat(dest + idx, ptr->data, paraLength - idx);
|
||||
idx += strlen(ptr->data);
|
||||
if (ptr->next != NULL) dest[idx++] = ' ';
|
||||
if (ptr->next != NULL) {
|
||||
if (dest[idx-1] != '\n')
|
||||
dest[idx++] = ' ';
|
||||
} else {
|
||||
if (dest[idx-1] == '\n')
|
||||
idx--;
|
||||
}
|
||||
free(ptr->data);
|
||||
}
|
||||
FOREACH_QUEUE_END
|
||||
@@ -45,6 +51,14 @@ char* lineQueueToString(LineQueue* lq) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *lineWithBreak(const char *txt) {
|
||||
size_t l = strlen(txt);
|
||||
char* s = (char*)malloc(l+2);
|
||||
strncpy(s, txt, l + 2);
|
||||
s[l] = '\n';
|
||||
return s;
|
||||
}
|
||||
|
||||
void yyerror(Sermon*, const char*);
|
||||
|
||||
%}
|
||||
@@ -126,7 +140,7 @@ block:
|
||||
PARSEPRINT("Parsed paragraph:\n%s\n\n", p.paraText);
|
||||
free(paraText);
|
||||
}
|
||||
| blockquote {
|
||||
| blockquote_or_preserve {
|
||||
SermonParagraph p = { .paraType = PARA_BLOCKQUOTE };
|
||||
char* paraText = lineQueueToString(&lineQ);
|
||||
FormatElement* paraContent = NULL;
|
||||
@@ -142,10 +156,17 @@ para:
|
||||
para LINE '\n' { APPEND_QUEUE(LineQueue, lineQ, $2); }
|
||||
| LINE '\n' { DESTROY_QUEUE(LineQueue, lineQ); APPEND_QUEUE(LineQueue, lineQ, $1); }
|
||||
;
|
||||
blockquote_or_preserve:
|
||||
blockquote
|
||||
| blockpreserve
|
||||
;
|
||||
blockquote:
|
||||
blockquote '>' LINE '\n' { APPEND_QUEUE(LineQueue, lineQ, $3); }
|
||||
| '>' LINE '\n' { DESTROY_QUEUE(LineQueue, lineQ); APPEND_QUEUE(LineQueue, lineQ, $2); }
|
||||
;
|
||||
blockpreserve:
|
||||
blockpreserve '|' LINE '\n' { char* s = lineWithBreak($3); APPEND_QUEUE(LineQueue, lineQ, s); free($3); }
|
||||
| '|' LINE '\n' { char* s = lineWithBreak($2); DESTROY_QUEUE(LineQueue, lineQ); APPEND_QUEUE(LineQueue, lineQ, s); free($2); }
|
||||
references:
|
||||
references reference break
|
||||
| /* empty */
|
||||
|
||||
@@ -83,6 +83,8 @@ formatElementsToXML(
|
||||
xmlNodePtr em = xmlNewNode(sermon_ns, "em");
|
||||
formatElementsToXML(sermon_ns, em, a[i].elementContent.nestedContent, a[i].elementContentLength, numReferences, sermonReferencesPtr);
|
||||
xmlAddChild(parentElement, em);
|
||||
} else if (a[i].elementType == FORMAT_BR) {
|
||||
xmlAddChild(parentElement, xmlNewNode(sermon_ns, "br"));
|
||||
} else if (a[i].elementType == FORMAT_TEXT) {
|
||||
xmlAddChild(parentElement, xmlNewText(a[i].elementContent.textContent));
|
||||
} else if (a[i].elementType == FORMAT_GREEK) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <libxslt/xslt.h>
|
||||
|
||||
Reference in New Issue
Block a user