Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cf79834870 | |||
| 4171c81bfd | |||
| 09b801c150 | |||
| 1807044977 | |||
|
|
da8080a7de | ||
|
|
ddee2d2702 | ||
|
|
ec5275ab88 | ||
|
|
3b94588d25 | ||
|
|
321731f51f | ||
|
|
dad4175887 | ||
|
|
95834f00ff | ||
|
|
44b2187d76 | ||
|
|
c98e91d810 | ||
|
|
5c693aa638 | ||
|
|
517a9d9605 | ||
|
|
9a084fe0bd | ||
|
|
91e3daf3dc | ||
|
|
9abc0f159c | ||
|
|
eb62727ff9 | ||
|
|
549a6cbab7 | ||
|
|
af79834d89 | ||
|
|
501d6c87c2 | ||
|
|
cbd16b6ab1 | ||
|
|
0f69fd7a8e |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,6 +2,7 @@ Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
compile
|
||||
config.h
|
||||
config.h.in
|
||||
config.h.in~
|
||||
@@ -22,3 +23,4 @@ stamp-h1
|
||||
ylwrap
|
||||
*.o
|
||||
*.core
|
||||
*.tar.gz
|
||||
|
||||
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.
|
||||
@@ -46,4 +46,4 @@ The markup syntax is very simple:
|
||||
> This paragraph will be
|
||||
> a block quote.
|
||||
|
||||
- Text enclosed between `[* starred braces *]` will be ignored as a comment.
|
||||
- Text enclosed between `[* starred braces *]` will be ignored as a comment.
|
||||
|
||||
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.0], [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">
|
||||
|
||||
48
sermon.1
Normal file
48
sermon.1
Normal file
@@ -0,0 +1,48 @@
|
||||
.Dd $Mdocdate: July 7 2016$
|
||||
.Dt SERMON 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm sermon
|
||||
.Nd converts sermon text markup to a variety of formats
|
||||
.Sh SYNOPSIS
|
||||
.Nm sermon
|
||||
.Op Fl hv
|
||||
.Op Fl a Ar author
|
||||
.Op Fl s Ar stylename
|
||||
.Op Fl o Ar output
|
||||
.Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility converts sermon markup text into a variety of useful formats,
|
||||
including
|
||||
.Em HTML Ns
|
||||
,
|
||||
.Em ODT Ns
|
||||
, and
|
||||
.Em XSL-FO No Ns .
|
||||
.\" .Sh CONTEXT
|
||||
.\" For section 9 functions only.
|
||||
.\" .Sh IMPLEMENTATION NOTES
|
||||
.\" Not used in OpenBSD.
|
||||
.\" .Sh RETURN VALUES
|
||||
.\" For sections 2, 3, and 9 function return values only.
|
||||
.\" .Sh ENVIRONMENT
|
||||
.\" For sections 1, 6, 7, and 8 only.
|
||||
.\" .Sh FILES
|
||||
.\" .Sh EXIT STATUS
|
||||
.\" For sections 1, 6, and 8 only.
|
||||
.\" .Sh EXAMPLES
|
||||
.\" .Sh DIAGNOSTICS
|
||||
.\" For sections 1, 4, 6, 7, 8, and 9 printf/stderr messages only.
|
||||
.\" .Sh ERRORS
|
||||
.\" For sections 2, 3, 4, and 9 errno settings only.
|
||||
.\" .Sh SEE ALSO
|
||||
.\" .Xr foobar 1
|
||||
.\" .Sh STANDARDS
|
||||
.\" .Sh HISTORY
|
||||
.\" .Sh AUTHORS
|
||||
.\" .Sh CAVEATS
|
||||
.\" .Sh BUGS
|
||||
.\" .Sh SECURITY CONSIDERATIONS
|
||||
.\" Not used in OpenBSD.
|
||||
67
src/format.c
67
src/format.c
@@ -27,6 +27,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "queue.h"
|
||||
#include "stack.h"
|
||||
@@ -44,6 +45,8 @@ typedef enum {
|
||||
TOK_UNICODE,
|
||||
TOK_STAR,
|
||||
TOK_REF,
|
||||
TOK_URL,
|
||||
TOK_BREAK,
|
||||
/*
|
||||
TOK_DASH,
|
||||
TOK_OPEN_DOUBLE_QUOTE,
|
||||
@@ -68,22 +71,37 @@ 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);
|
||||
}
|
||||
|
||||
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] == '/'))));
|
||||
}
|
||||
|
||||
static Token
|
||||
nextToken(Tokenizer tokenizer) {
|
||||
int startIndex = tokenizer->byteIndex;
|
||||
@@ -99,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 == '.'))) {
|
||||
@@ -125,12 +148,30 @@ nextToken(Tokenizer tokenizer) {
|
||||
result.toktype = TOK_REF;
|
||||
result.toktext = strndup(tokenizer->txt + idStart, idEnd - idStart);
|
||||
return result;
|
||||
} else if (httpAt(tokenizer)) {
|
||||
int endIndex = 0;
|
||||
while ((ch != 0) && (ch != ' ') && (ch != '\r') && (ch != '\n')) {
|
||||
utf8Advance(tokenizer);
|
||||
ch = utf8CharAt(tokenizer);
|
||||
}
|
||||
if (tokenizer->txt[tokenizer->byteIndex - 1] == '.') {
|
||||
/* heuristic: url doesn't end in . */
|
||||
endIndex = --tokenizer->byteIndex;
|
||||
} else {
|
||||
endIndex = tokenizer->byteIndex;
|
||||
}
|
||||
|
||||
result.toktype = TOK_URL;
|
||||
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 == '^') {
|
||||
if (tokenizer->txt[tokenizer->byteIndex + 1] == '{') break;
|
||||
} else if (httpAt(tokenizer)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result.toktype = TOK_TEXT;
|
||||
@@ -172,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 } } ;
|
||||
@@ -181,6 +226,8 @@ int formatText(const char* txt, FormatElement** dst, CitationRecordQueue* citati
|
||||
t = FORMAT_GREEK;
|
||||
} else if (tok.toktype == TOK_UNICODE) {
|
||||
t = FORMAT_UNICODE;
|
||||
} else if (tok.toktype == TOK_URL) {
|
||||
t = FORMAT_URL;
|
||||
} else if (tok.toktype == TOK_REF) {
|
||||
t = FORMAT_CITATION;
|
||||
if (citationQPtr && !lookupCitation(*citationQPtr, tok.toktext)) {
|
||||
@@ -223,15 +270,3 @@ void freeFormatElementArray(FormatElement* a, int length) {
|
||||
free(a);
|
||||
}
|
||||
|
||||
#ifdef FORMATTER_TEST
|
||||
#include <stdio.h>
|
||||
|
||||
const char* str = "My name in Chinese is \xe7\x86\x8a\xe5\xa4\xa7\xe8\xa1\x9b, or *xiong da wei*. My favorite Greek passage is \xe1\xbc\x90\xce\xbd \xe1\xbc\x80\xcf\x81\xcf\x87\xe1\xbf\x87 \xe1\xbc\xa6\xce\xbd \xe1\xbd\x81 \xce\xbb\xe1\xbd\xb9\xce\xb3\xce\xbf\xcf\x82.^{cite}";
|
||||
|
||||
int
|
||||
main() {
|
||||
FormatElement* lst;
|
||||
int l = formatText(str, &lst, NULL);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -34,10 +34,12 @@
|
||||
typedef enum {
|
||||
FORMAT_TEXT,
|
||||
FORMAT_EM,
|
||||
FORMAT_BR,
|
||||
FORMAT_STRONG,
|
||||
FORMAT_CITATION,
|
||||
FORMAT_GREEK,
|
||||
FORMAT_UNICODE
|
||||
FORMAT_UNICODE,
|
||||
FORMAT_URL
|
||||
} FormatElementType;
|
||||
|
||||
typedef struct FormatElement FormatElement;
|
||||
|
||||
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 */
|
||||
|
||||
@@ -73,7 +73,7 @@ uint32_t utf8CharAt(const utf8iterator* iter) {
|
||||
((uint32_t)(iter->txt[byteIndex] & 0x03) << 24);
|
||||
|
||||
} else if (((iter->txt[byteIndex] & 0xf7) == 0xfc) &&
|
||||
((iter->txt[byteIndex + 1]) & 0xc0 == 0x80) &&
|
||||
((iter->txt[byteIndex + 1] & 0xc0) == 0x80) &&
|
||||
((iter->txt[byteIndex + 2] & 0xc0) == 0x80) &&
|
||||
((iter->txt[byteIndex + 3] & 0xc0) == 0x80) &&
|
||||
((iter->txt[byteIndex + 4] & 0xc0) == 0x80) &&
|
||||
@@ -112,7 +112,7 @@ _next_offset(const utf8iterator* iter) {
|
||||
((iter->txt[byteIndex + 4] & 0xc0) == 0x80)) {
|
||||
return 5;
|
||||
} else if (((iter->txt[byteIndex] & 0xf7) == 0xfc) &&
|
||||
((iter->txt[byteIndex + 1]) & 0xc0 == 0x80) &&
|
||||
((iter->txt[byteIndex + 1] & 0xc0) == 0x80) &&
|
||||
((iter->txt[byteIndex + 2] & 0xc0) == 0x80) &&
|
||||
((iter->txt[byteIndex + 3] & 0xc0) == 0x80) &&
|
||||
((iter->txt[byteIndex + 4] & 0xc0) == 0x80) &&
|
||||
|
||||
35
src/xml.c
35
src/xml.c
@@ -1,3 +1,31 @@
|
||||
/*
|
||||
* xml.c - Create XML representation of sermon document
|
||||
* Copyright © 2017 David A. Baer
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
* 3. Neither the name of the organization nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY David A. Baer ''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 David A. Baer 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.
|
||||
*
|
||||
*/
|
||||
#include <libxml/tree.h>
|
||||
#include <string.h>
|
||||
#include "options.h"
|
||||
@@ -55,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) {
|
||||
@@ -65,6 +95,11 @@ formatElementsToXML(
|
||||
xmlNodePtr unicode = xmlNewNode(sermon_ns, "unicode");
|
||||
xmlAddChild(unicode, xmlNewText(a[i].elementContent.textContent));
|
||||
xmlAddChild(parentElement, unicode);
|
||||
} else if (a[i].elementType == FORMAT_URL) {
|
||||
xmlNodePtr link = xmlNewNode(sermon_ns, "link");
|
||||
xmlSetProp(link, "href", a[i].elementContent.textContent);
|
||||
xmlAddChild(link, xmlNewText(a[i].elementContent.textContent));
|
||||
xmlAddChild(parentElement, link);
|
||||
} else if (a[i].elementType == FORMAT_CITATION) {
|
||||
xmlNodePtr cite = xmlNewNode(sermon_ns, "cite");
|
||||
int num = findReferenceNumber(numReferences, sermonReferencesPtr, a[i].elementContent.textContent);
|
||||
|
||||
28
src/xml.h
28
src/xml.h
@@ -1,3 +1,31 @@
|
||||
/*
|
||||
* xml.h - create XML representation of sermon document
|
||||
* Copyright © 2017 David A. Baer
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
* 3. Neither the name of the organization nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY David A. Baer ''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 David A. Baer 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.
|
||||
*
|
||||
*/
|
||||
#ifndef _XML_H
|
||||
#define _XML_H
|
||||
|
||||
|
||||
@@ -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