Enable writing ODT files with correct metadata
This commit is contained in:
@@ -7,6 +7,7 @@ AM_YFLAGS = -d --location
|
||||
sermon_SOURCES = citations.c \
|
||||
format.c \
|
||||
main.c \
|
||||
odt.c \
|
||||
options.c \
|
||||
sermon_lexer.l \
|
||||
sermon_parser.y \
|
||||
|
||||
74
src/main.c
74
src/main.c
@@ -31,6 +31,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <err.h>
|
||||
#include "meta.h"
|
||||
#include "odt.h"
|
||||
#include "options.h"
|
||||
#include "sermon.h"
|
||||
#include "xml.h"
|
||||
@@ -39,10 +42,31 @@
|
||||
extern int yyparse(Sermon *);
|
||||
extern FILE* yyin;
|
||||
|
||||
char*
|
||||
constructMetaXml(const char* sermonTitle, const char* timestamp,
|
||||
const char* sermonAuthor) {
|
||||
size_t sz = sizeof(META_XML_TEMPLATE) - 13 + 2 * strlen(sermonTitle)
|
||||
+ 3 * strlen(timestamp) + 2 * strlen(sermonAuthor);
|
||||
char* result = malloc(sz);
|
||||
if (!result) {
|
||||
perror("malloc");
|
||||
exit(1);
|
||||
}
|
||||
snprintf(result, sz, META_XML_TEMPLATE, sermonTitle, timestamp,
|
||||
sermonAuthor, timestamp, sermonAuthor, sermonTitle, timestamp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
Sermon sermon;
|
||||
xmlDocPtr document, transformed;
|
||||
int i = 0, block = 0, normal = 0;
|
||||
#ifdef HAVE_PLEDGE
|
||||
if (-1 == pledge("stdio rpath wpath tmppath proc exec", NULL)) {
|
||||
err(1, "pledge");
|
||||
}
|
||||
#endif /* !def(HAVE_PLEDGE) */
|
||||
InitOptions(argc, (const char**)argv);
|
||||
InitSermon(&sermon);
|
||||
|
||||
@@ -53,17 +77,61 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
yyparse(&sermon);
|
||||
|
||||
#if 0
|
||||
#ifdef HAVE_PLEDGE
|
||||
if (-1 == pledge("stdio", NULL)) {
|
||||
err(1, "pledge");
|
||||
}
|
||||
#endif /* !def(HAVE_PLEDGE) */
|
||||
#endif
|
||||
|
||||
document = sermonToXmlDoc(&sermon);
|
||||
transformed = applyStyleSheet(document, options.styleSheetName);
|
||||
printXML(transformed);
|
||||
if (strcmp(options.styleSheetName, "none") != 0) {
|
||||
transformed = applyStyleSheet(document, options.styleSheetName);
|
||||
} else {
|
||||
transformed = document;
|
||||
}
|
||||
if (strcmp(options.outputFileName, "-") == 0) {
|
||||
printXML(transformed);
|
||||
} else {
|
||||
if ((strcmp(options.styleSheetName, "odt") == 0) ||
|
||||
(strcmp(options.styleSheetName, "ms_odt") == 0)) {
|
||||
ODTFileEntry entry[2];
|
||||
int sz;
|
||||
xmlChar* doc;
|
||||
char templateFileName[FILENAME_MAX];
|
||||
char timestamp[20];
|
||||
time_t tm;
|
||||
|
||||
/* get timestamp */
|
||||
time(&tm);
|
||||
strftime(timestamp, 20, "%Y-%m-%dT%H:%M:%S", localtime(&tm));
|
||||
|
||||
xmlDocDumpMemoryEnc(transformed, &doc, &sz, "utf-8");
|
||||
entry[0].path = "content.xml";
|
||||
entry[0].content = doc;
|
||||
entry[1].path = "meta.xml";
|
||||
entry[1].content = constructMetaXml(sermon.sermonTitle, timestamp, sermon.sermonAuthor ? sermon.sermonAuthor : options.authorName);
|
||||
snprintf(templateFileName, FILENAME_MAX, "%s.odt", options.styleSheetName);
|
||||
constructODT(options.outputFileName, OptionsDataFile(templateFileName), 2, entry);
|
||||
free(doc);
|
||||
free(entry[1].content);
|
||||
} else {
|
||||
xmlSaveFileEnc(options.outputFileName, transformed, "utf-8");
|
||||
}
|
||||
}
|
||||
|
||||
/* clean up, clean up, everybody, everywhere! */
|
||||
VERBOSE_PRINTF("Cleaning up\n");
|
||||
xmlFreeDoc(document);
|
||||
xmlFreeDoc(transformed);
|
||||
if (strcmp(options.styleSheetName, "none") != 0) {
|
||||
xmlFreeDoc(transformed);
|
||||
}
|
||||
FreeSermon(&sermon);
|
||||
if (strcmp(options.inputFileName, "-") != 0) {
|
||||
fclose(yyin);
|
||||
}
|
||||
FreeOptions();
|
||||
VERBOSE_PRINTF("Cleanup done\n");
|
||||
}
|
||||
|
||||
|
||||
55
src/meta.h
Normal file
55
src/meta.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* meta.h
|
||||
* Copyright © 2016 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 _META_H
|
||||
#define _META_H
|
||||
|
||||
#define META_XML_TEMPLATE \
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" \
|
||||
"<office:document-meta xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:ooo=\"http://openoffice.org/2004/office\" office:version=\"1.2\">\n" \
|
||||
" <office:meta>\n" \
|
||||
" <meta:generator>OpenOffice.org/3.1$Unix OpenOffice.org_project/310m19$Build-9420</meta:generator>\n" \
|
||||
" <dc:title>%s</dc:title>\n" \
|
||||
" <meta:creation-date>%s</meta:creation-date>\n" \
|
||||
" <dc:language>en-US</dc:language>\n" \
|
||||
" <meta:editing-cycles>4</meta:editing-cycles>\n" \
|
||||
" <meta:editing-duration>PT00H11M59S</meta:editing-duration>\n" \
|
||||
" <meta:initial-creator>%s</meta:initial-creator>\n" \
|
||||
" <dc:date>%s</dc:date>\n" \
|
||||
" <dc:creator>%s</dc:creator>\n" \
|
||||
" <meta:document-statistic meta:table-count=\"0\" meta:image-count=\"0\" meta:object-count=\"0\" meta:page-count=\"3\" meta:paragraph-count=\"18\" meta:word-count=\"1420\" meta:character-count=\"7596\"/>\n" \
|
||||
" <meta:user-defined meta:name=\"Info 1\"/>\n" \
|
||||
" <meta:user-defined meta:name=\"Info 2\"/>\n" \
|
||||
" <meta:user-defined meta:name=\"Info 3\"/>\n" \
|
||||
" <meta:user-defined meta:name=\"Info 4\"/>\n" \
|
||||
" <meta:template xlink:type=\"simple\" xlink:actuate=\"onRequest\" xlink:title=\"%s\" xlink:href=\"../../.openoffice.org/3/user/template/default.ott\" meta:date=\"%s\"/>\n" \
|
||||
" </office:meta>\n" \
|
||||
"</office:document-meta>\n"
|
||||
|
||||
#endif /* !def(_META_H) */
|
||||
151
src/odt.c
Normal file
151
src/odt.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* odt.c
|
||||
* Copyright © 2016 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "odt.h"
|
||||
#include "options.h"
|
||||
|
||||
void
|
||||
saveEntry(const char* rootPath, const ODTFileEntry entry) {
|
||||
char* fullpath = malloc(FILENAME_MAX);
|
||||
FILE* ptr;
|
||||
snprintf(fullpath, FILENAME_MAX, "%s/%s", rootPath, entry.path);
|
||||
ptr = fopen(fullpath, "w");
|
||||
fwrite(entry.content, 1, strlen(entry.content), ptr);
|
||||
fclose(ptr);
|
||||
free(fullpath);
|
||||
}
|
||||
|
||||
static void
|
||||
extractTemplateDocument(const char* const templateFilename, const char* const tempDir) {
|
||||
pid_t child_pid;
|
||||
if ((child_pid = fork()) == 0) {
|
||||
/* you are the child */
|
||||
char* const args[] = { "unzip", "-d", tempDir, templateFilename, NULL };
|
||||
freopen("/dev/null", "w", stdout);
|
||||
execvp("unzip", args);
|
||||
perror("execvp");
|
||||
exit(1);
|
||||
} else {
|
||||
/* you are the parent */
|
||||
int status;
|
||||
|
||||
waitpid(child_pid, &status, 0);
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "unzip exited with status %d.\n", status);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
createOutputDocument(const char* const outputFilename, const char* const tempDir) {
|
||||
pid_t child_pid;
|
||||
if ((child_pid = fork()) == 0) {
|
||||
/* you are the child */
|
||||
char outputRealPath[FILENAME_MAX];
|
||||
char* const args[] = { "zip", "-r", outputRealPath, ".", NULL };
|
||||
realpath(outputFilename, outputRealPath);
|
||||
chdir(tempDir);
|
||||
freopen("/dev/null", "w", stdout);
|
||||
execvp("zip", args);
|
||||
perror("execvp");
|
||||
exit(1);
|
||||
} else {
|
||||
/* you are the parent */
|
||||
int status;
|
||||
|
||||
waitpid(child_pid, &status, 0);
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "zip exited with status %d.\n", status);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
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 };
|
||||
freopen("/dev/null", "w", stdout);
|
||||
execvp("rm", args);
|
||||
perror("execvp");
|
||||
exit(1);
|
||||
} else {
|
||||
/* you are the parent */
|
||||
int status;
|
||||
|
||||
waitpid(child_pid, &status, 0);
|
||||
if (status != 0) {
|
||||
fprintf(stderr, "rm exited with status %d.\n", status);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
constructODT(const char* const outputFilename, const char* const templateFilename,
|
||||
unsigned int numEntries, const ODTFileEntry* entries) {
|
||||
char tempDir[23];
|
||||
int i;
|
||||
|
||||
/* create temporary workspace */
|
||||
strlcpy(tempDir, "/tmp/sermon.XXXXXXXXXX", sizeof(tempDir));
|
||||
if (mkdtemp(tempDir) == NULL) {
|
||||
perror("mkdtemp");
|
||||
exit(1);
|
||||
}
|
||||
VERBOSE_PRINTF("Making temporary directory %s\n", tempDir);
|
||||
|
||||
/* extract template document to workspace */
|
||||
VERBOSE_PRINTF("Extracting template %s to temporary directory\n", templateFilename);
|
||||
extractTemplateDocument(templateFilename, tempDir);
|
||||
|
||||
/* replace/add entries */
|
||||
for (i = 0; i < numEntries; i++) {
|
||||
VERBOSE_PRINTF("Adding %s\n", entries[i].path);
|
||||
saveEntry(tempDir, entries[i]);
|
||||
}
|
||||
|
||||
/* create output file */
|
||||
VERBOSE_PRINTF("Creating output file %s\n", outputFilename);
|
||||
createOutputDocument(outputFilename, tempDir);
|
||||
|
||||
/* clean up */
|
||||
VERBOSE_PRINTF("Removing %s\n", tempDir);
|
||||
removeDirectory(tempDir);
|
||||
|
||||
VERBOSE_PRINTF("ODT output successfully created\n");
|
||||
return 0;
|
||||
}
|
||||
45
src/odt.h
Normal file
45
src/odt.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* odt.h
|
||||
* Copyright © 2016 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 _ODT_H
|
||||
#define _ODT_H 1
|
||||
|
||||
typedef struct {
|
||||
char* path;
|
||||
char* content;
|
||||
} ODTFileEntry;
|
||||
|
||||
int
|
||||
constructODT(
|
||||
const char* const outputFilename, const char* const templateFilename,
|
||||
unsigned int numEntries, const ODTFileEntry* entries
|
||||
);
|
||||
|
||||
|
||||
#endif /* !def(_ODT_H) */
|
||||
@@ -35,7 +35,8 @@
|
||||
|
||||
int odttemplate(const char* template_fn, const char* output_fn, struct dict* substitutions_dict) {
|
||||
|
||||
struct archive* arch_in = archive_read_new();
|
||||
struct archive* arch_in = archive_read_new(),
|
||||
*arch_out = archive_write_new();
|
||||
struct archive_entry* ent;
|
||||
struct dict_iter* i;
|
||||
char ftype;
|
||||
@@ -43,41 +44,24 @@ int odttemplate(const char* template_fn, const char* output_fn, struct dict* sub
|
||||
if (archive_read_support_format_zip(arch_in) != ARCHIVE_OK) {
|
||||
return ODTTEMPLATE_FATAL;
|
||||
}
|
||||
if (archive_write_set_format_zip(arch_out) != ARCHIVE_OK) {
|
||||
return ODTTEMPLATE_FATAL;
|
||||
}
|
||||
if (archive_write_zip_set_compression_deflate(arch_out) != ARCHIVE_OK) {
|
||||
return ODTTEMPLATE_FATAL;
|
||||
}
|
||||
if (archive_read_open_filename(arch_in, template_fn, ODTTEMPLATE_BLOCK_SIZE) != ARCHIVE_OK) {
|
||||
return ODTTEMPLATE_FATAL;
|
||||
}
|
||||
if (archive_write_open_filename(arch_out, output_fn) != ARCHIVE_OK) {
|
||||
return ODTTEMPLATE_FATAL;
|
||||
}
|
||||
while (archive_read_next_header(arch_in, &ent) != ARCHIVE_EOF) {
|
||||
switch (archive_entry_filetype(ent)) {
|
||||
case AE_IFREG:
|
||||
ftype = 'F';
|
||||
break;
|
||||
case AE_IFLNK:
|
||||
ftype = 'L';
|
||||
break;
|
||||
case AE_IFSOCK:
|
||||
ftype = 'S';
|
||||
break;
|
||||
case AE_IFCHR:
|
||||
ftype = 'C';
|
||||
break;
|
||||
case AE_IFBLK:
|
||||
ftype = 'B';
|
||||
break;
|
||||
case AE_IFDIR:
|
||||
ftype = 'D';
|
||||
break;
|
||||
case AE_IFIFO:
|
||||
ftype = 'P';
|
||||
break;
|
||||
default:
|
||||
ftype = '?';
|
||||
if ((archive_entry_filetype(ent) == AE_IFREG) &&
|
||||
(dict_find(substitutions_dict, archive_entry_pathname(ent), NULL)
|
||||
== DICT_OK)) {
|
||||
} else {
|
||||
}
|
||||
fn = archive_entry_pathname(ent);
|
||||
printf("%s [%c]", fn, ftype);
|
||||
if (substitutions_dict && (dict_find(substitutions_dict, fn, NULL) == DICT_OK)) {
|
||||
printf(" - in dictionary, skip");
|
||||
}
|
||||
printf("\n");
|
||||
archive_read_data_skip(arch_in);
|
||||
}
|
||||
archive_read_close(arch_in);
|
||||
|
||||
@@ -36,7 +36,9 @@
|
||||
#include "options.h"
|
||||
|
||||
Options options = {
|
||||
.progname = NULL, .datadir = DATADIR, .styleSheetName = "html5"
|
||||
.progname = NULL, .datadir = DATADIR, .styleSheetName = NULL,
|
||||
.outputFileName = "-", .placeName = "Highlands Presbyterian Church",
|
||||
.authorName = "David A. Baer", .verbose = 0
|
||||
};
|
||||
|
||||
char*
|
||||
@@ -70,10 +72,14 @@ datadir(const char* progname) {
|
||||
}
|
||||
|
||||
static void usage(const char* progname) {
|
||||
fprintf(stderr, "Usage: %s [-h] [-s STYLESHEET] FILE\n"
|
||||
fprintf(stderr, "Usage: %s [options] FILE\n"
|
||||
"\n"
|
||||
" -h Display help message\n"
|
||||
" -s STYLESHEET Apply stylesheet (default \"html5\")\n"
|
||||
"Options:\n"
|
||||
" -h|--help Display this help message\n"
|
||||
" -a|--author AUTHOR Author name\n"
|
||||
" -o|--output OUTPUT Output file name\n"
|
||||
" -s|--stylesheet STYLESHEET Apply stylesheet (default \"html5\")\n"
|
||||
" -v|--verbose Verbose output\n"
|
||||
"\n"
|
||||
" FILE sermon file to scan (\"-\" for stdin)\n", progname);
|
||||
}
|
||||
@@ -83,13 +89,35 @@ void InitOptions(int argc, const char* argv[]) {
|
||||
options.progname = argv[0];
|
||||
options.datadir = datadir(options.progname);
|
||||
while (++i < argc) {
|
||||
if (strcmp(argv[i], "-h") == 0) { usage(options.progname); exit(0); }
|
||||
else if (strcmp(argv[i], "-") == 0) {
|
||||
if ((strcmp(argv[i], "-h") == 0) ||
|
||||
(strcmp(argv[i], "--help") == 0)) {
|
||||
usage(options.progname);
|
||||
exit(0);
|
||||
} else if (strcmp(argv[i], "-") == 0) {
|
||||
options.inputFileName = argv[i];
|
||||
} else if (strcmp(argv[i], "-s") == 0) {
|
||||
} else if ((strcmp(argv[i], "-s") == 0) ||
|
||||
(strcmp(argv[i], "--stylesheet") == 0)) {
|
||||
options.styleSheetName = argv[++i];
|
||||
} else if (strncmp(argv[i], "-s", 2) == 0) {
|
||||
options.styleSheetName = argv[i] + 2;
|
||||
} else if ((strcmp(argv[i], "-o") == 0) ||
|
||||
(strcmp(argv[i], "--output") == 0)) {
|
||||
options.outputFileName = argv[++i];
|
||||
} else if (strncmp(argv[i], "-o", 2) == 0) {
|
||||
options.outputFileName = argv[i] + 2;
|
||||
} else if ((strcmp(argv[i], "-a") == 0) ||
|
||||
(strcmp(argv[i], "--author") == 0)) {
|
||||
options.authorName = argv[++i];
|
||||
} else if (strncmp(argv[i], "-a", 2) == 0) {
|
||||
options.authorName = argv[i] + 2;
|
||||
} else if ((strcmp(argv[i], "-p") == 0) ||
|
||||
(strcmp(argv[i], "--place") == 0)) {
|
||||
options.placeName = argv[++i];
|
||||
} else if (strncmp(argv[i], "-p", 2) == 0) {
|
||||
options.placeName = argv[i] + 2;
|
||||
} else if ((strcmp(argv[i], "-v") == 0) ||
|
||||
(strcmp(argv[i], "--verbose") == 0)) {
|
||||
options.verbose = 1;
|
||||
} else if (argv[i][0] == '-') {
|
||||
fprintf(stderr, "Unknown option: %s\n", argv[i]);
|
||||
} else {
|
||||
@@ -102,6 +130,23 @@ void InitOptions(int argc, const char* argv[]) {
|
||||
usage(options.progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* set stylesheet based on output file name */
|
||||
if (!options.styleSheetName && options.outputFileName) {
|
||||
char* outputExten = strrchr(options.outputFileName, '.');
|
||||
if (outputExten) {
|
||||
if (strcasecmp(outputExten, ".odt") == 0) {
|
||||
options.styleSheetName = "odt";
|
||||
} else if (strcasecmp(outputExten, ".html") == 0) {
|
||||
options.styleSheetName = "html5";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* default stylesheet is html5 */
|
||||
if (!options.styleSheetName) {
|
||||
options.styleSheetName = "html5";
|
||||
}
|
||||
}
|
||||
|
||||
char*
|
||||
|
||||
@@ -34,7 +34,11 @@ typedef struct {
|
||||
const char* progname;
|
||||
char* datadir;
|
||||
const char* inputFileName;
|
||||
const char* outputFileName;
|
||||
const char* styleSheetName;
|
||||
const char* authorName;
|
||||
const char* placeName;
|
||||
int verbose;
|
||||
} Options;
|
||||
|
||||
extern Options options;
|
||||
@@ -43,4 +47,6 @@ void InitOptions(int argc, const char* argv[]);
|
||||
char* OptionsDataFile(const char* fname);
|
||||
void FreeOptions();
|
||||
|
||||
#define VERBOSE_PRINTF(x...) { if (options.verbose) printf(x); }
|
||||
|
||||
#endif /* !def _OPTIONS_H */
|
||||
|
||||
@@ -58,6 +58,7 @@ typedef struct {
|
||||
char* sermonAuthor;
|
||||
char* sermonDate;
|
||||
char* sermonOccasion;
|
||||
char* sermonPlace;
|
||||
char* sermonText;
|
||||
|
||||
int numParagraphs;
|
||||
|
||||
@@ -105,6 +105,7 @@ header:
|
||||
else if (strcmp($2, "text") == 0) { sermon->sermonText = $4; }
|
||||
else if (strcmp($2, "occasion") == 0) { sermon->sermonOccasion = $4; }
|
||||
else if (strcmp($2, "date") == 0) { sermon->sermonDate = $4; }
|
||||
else if (strcmp($2, "place") == 0) { sermon->sermonPlace = $4; }
|
||||
else { free($4); }
|
||||
free($2);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <libxml/tree.h>
|
||||
#include <string.h>
|
||||
#include "options.h"
|
||||
#include "sermon.h"
|
||||
|
||||
static xmlNsPtr srmNs = NULL;
|
||||
@@ -18,8 +19,9 @@ xmlNodePtr
|
||||
sermonHeader(xmlNsPtr sermon_ns, const Sermon* srm) {
|
||||
xmlNodePtr header = xmlNewNode(sermon_ns, "header");
|
||||
appendHeaderNode(sermon_ns, header, "title", srm->sermonTitle);
|
||||
appendHeaderNode(sermon_ns, header, "author", srm->sermonAuthor);
|
||||
appendHeaderNode(sermon_ns, header, "author", srm->sermonAuthor ? srm->sermonAuthor : options.authorName);
|
||||
appendHeaderNode(sermon_ns, header, "occasion", srm->sermonOccasion);
|
||||
appendHeaderNode(sermon_ns, header, "place", srm->sermonPlace ? srm->sermonPlace : options.placeName);
|
||||
appendHeaderNode(sermon_ns, header, "date", srm->sermonDate);
|
||||
appendHeaderNode(sermon_ns, header, "text", srm->sermonText);
|
||||
return header;
|
||||
@@ -166,3 +168,4 @@ printXML(xmlDocPtr document) {
|
||||
xmlOutputBufferPtr output = xmlOutputBufferCreateFd(1, encoding);
|
||||
xmlSaveFileTo(output, document, "utf-8");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#ifndef _XML_H
|
||||
#define _XML_H
|
||||
|
||||
xmlDocPtr sermonToXmlDoc(const Sermon*);
|
||||
void printXML(xmlDocPtr);
|
||||
#include <stdio.h>
|
||||
|
||||
xmlDocPtr
|
||||
sermonToXmlDoc(const Sermon*);
|
||||
|
||||
void
|
||||
printXML(xmlDocPtr);
|
||||
|
||||
#endif /* !def _XML_H */
|
||||
|
||||
@@ -15,7 +15,7 @@ applyStyleSheet(xmlDocPtr document, const char* styleSheetName) {
|
||||
snprintf(t, l, "%s.xsl", styleSheetName);
|
||||
styleSheetFileName = OptionsDataFile(t);
|
||||
free(t);
|
||||
fprintf(stderr, "Loading stylesheet %s ...\n", styleSheetFileName);
|
||||
/*fprintf(stderr, "Loading stylesheet %s ...\n", styleSheetFileName);*/
|
||||
|
||||
xmlSubstituteEntitiesDefault(1);
|
||||
xmlLoadExtDtdDefaultValue = 1;
|
||||
|
||||
Reference in New Issue
Block a user