Sources/libMultiMarkdown/opendocument.c
Sources/libMultiMarkdown/opendocument-content.c
Sources/libMultiMarkdown/opml.c
+ Sources/libMultiMarkdown/opml-lexer.c
+ Sources/libMultiMarkdown/opml-parser.c
+ Sources/libMultiMarkdown/opml-reader.c
Sources/libMultiMarkdown/parser.c
Sources/libMultiMarkdown/rng.c
Sources/libMultiMarkdown/scanners.c
Sources/libMultiMarkdown/opendocument.h
Sources/libMultiMarkdown/opendocument-content.h
Sources/libMultiMarkdown/opml.h
+ Sources/libMultiMarkdown/opml-lexer.h
+ Sources/libMultiMarkdown/opml-parser.h
+ Sources/libMultiMarkdown/opml-reader.h
Sources/libMultiMarkdown/scanners.h
Sources/libMultiMarkdown/stack.h
Sources/libMultiMarkdown/textbundle.c
ADD_MMD_TEST(mmd-6-critic-reject "-r" CriticMarkup htmlr)
+# Some of these will (properly) fail.
+# But it's useful to run manually at times to verify that
+# round-tripping through OPML generally works
+
+# add_test ( mmd-6-opml-parse
+# ${PROJECT_SOURCE_DIR}/tests/MarkdownTest.pl
+# --Script="${CMAKE_CURRENT_BINARY_DIR}/multimarkdown"
+# --testdir=${PROJECT_SOURCE_DIR}/tests/MMD6Tests
+# "--Flags=--opml -t mmd"
+# --ext=text
+# --source_ext=opml
+# )
+
+
ADD_MMD_TEST(pathologic-compat "-c" ../build html)
ADD_MMD_TEST(pathologic "" ../build html)
EXT_CRITIC_REJECT = 1 << 11, //!< Reject all proposed changes
EXT_RANDOM_FOOT = 1 << 12, //!< Use random numbers for footnote links
EXT_TRANSCLUDE = 1 << 13, //!< Perform transclusion(s)
+ EXT_PARSE_OPML = 1 << 14, //!< Convert from OPML before processing source text
EXT_FAKE = 1 << 31, //!< 31 is highest number allowed
};
#include "mmd.h"
#include "object_pool.h"
#include "opendocument.h"
+#include "opml-reader.h"
#include "parser.h"
#include "scanners.h"
#include "stack.h"
e->extensions |= EXT_NO_METADATA;
}
+ if (e->extensions & EXT_PARSE_OPML) {
+ // Convert from OPML first (if not done earlier)
+ mmd_convert_opml_string(e, byte_start, byte_len);
+ }
// Tokenize the string
token * doc = mmd_tokenize_string(e, byte_start, byte_len, false);
DString * result = NULL;
if (format == FORMAT_MMD) {
+ if (e->extensions & EXT_PARSE_OPML) {
+ // Convert from OPML first (if not done earlier)
+ mmd_convert_opml_string(e, 0, e->dstr->currentStringLength);
+ }
+
// Simply return text (transclusion is handled externally)
d_string_append_c_array(output, e->dstr->str, e->dstr->currentStringLength);
--- /dev/null
+/* Generated by re2c 1.0.3 on Mon Aug 6 17:50:40 2018 */
+/**
+
+ MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+ @file opml-lexer.c
+
+ @brief Tokenize OPML file for parsing
+
+
+ @author Fletcher T. Penney
+ @bug
+
+**/
+
+/*
+
+ Copyright © 2016 - 2018 Fletcher T. Penney.
+
+
+ The `MultiMarkdown 6` project is released under the MIT License..
+
+ GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+
+ https://github.com/fletcher/MultiMarkdown-4/
+
+ MMD 4 is released under both the MIT License and GPL.
+
+
+ CuTest is released under the zlib/libpng license. See CuTest.c for the
+ text of the license.
+
+ uthash library:
+ Copyright (c) 2005-2016, Troy D. Hanson
+
+ Licensed under Revised BSD license
+
+ miniz library:
+ Copyright 2013-2014 RAD Game Tools and Valve Software
+ Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+
+ Licensed under the MIT license
+
+ argtable3 library:
+ Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ <sheitmann@users.sourceforge.net>
+ All rights reserved.
+
+ Licensed under the Revised BSD License
+
+
+ ## The MIT License ##
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+ ## Revised BSD License ##
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "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 <COPYRIGHT
+ HOLDER> 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 <stdlib.h>
+
+#include "opml-lexer.h"
+#include "opml-parser.h"
+
+
+// Basic scanner struct
+
+#define YYCTYPE unsigned char
+#define YYCURSOR s->cur
+#define YYMARKER s->ptr
+#define YYCTXMARKER s->ctx
+
+int opml_scan(Scanner * s, const char * stop) {
+
+ scan:
+
+ if (s->cur >= stop) {
+ return 0;
+ }
+
+ s->start = s->cur;
+
+
+{
+ YYCTYPE yych;
+ unsigned int yyaccept = 0;
+ yych = *YYCURSOR;
+ switch (yych) {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy4;
+ case '<': goto yy7;
+ default: goto yy2;
+ }
+yy2:
+ ++YYCURSOR;
+yy3:
+ { goto scan; }
+yy4:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy4;
+ default: goto yy6;
+ }
+yy6:
+ { return OPML_WSNL; }
+yy7:
+ yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ switch (yych) {
+ case '/': goto yy8;
+ case '?': goto yy10;
+ case 'B':
+ case 'b': goto yy11;
+ case 'H':
+ case 'h': goto yy12;
+ case 'O':
+ case 'o': goto yy13;
+ case 'T':
+ case 't': goto yy14;
+ default: goto yy3;
+ }
+yy8:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'B':
+ case 'b': goto yy15;
+ case 'H':
+ case 'h': goto yy16;
+ case 'O':
+ case 'o': goto yy17;
+ case 'T':
+ case 't': goto yy18;
+ default: goto yy9;
+ }
+yy9:
+ YYCURSOR = YYMARKER;
+ switch (yyaccept) {
+ case 0: goto yy3;
+ case 1: goto yy89;
+ default: goto yy94;
+ }
+yy10:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'X':
+ case 'x': goto yy19;
+ default: goto yy9;
+ }
+yy11:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'O':
+ case 'o': goto yy20;
+ default: goto yy9;
+ }
+yy12:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy21;
+ default: goto yy9;
+ }
+yy13:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'P':
+ case 'p': goto yy22;
+ case 'U':
+ case 'u': goto yy23;
+ default: goto yy9;
+ }
+yy14:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'I':
+ case 'i': goto yy24;
+ default: goto yy9;
+ }
+yy15:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'O':
+ case 'o': goto yy25;
+ default: goto yy9;
+ }
+yy16:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy26;
+ default: goto yy9;
+ }
+yy17:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'P':
+ case 'p': goto yy27;
+ case 'U':
+ case 'u': goto yy28;
+ default: goto yy9;
+ }
+yy18:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'I':
+ case 'i': goto yy29;
+ default: goto yy9;
+ }
+yy19:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'M':
+ case 'm': goto yy30;
+ default: goto yy9;
+ }
+yy20:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'D':
+ case 'd': goto yy31;
+ default: goto yy9;
+ }
+yy21:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'A':
+ case 'a': goto yy32;
+ default: goto yy9;
+ }
+yy22:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'M':
+ case 'm': goto yy33;
+ default: goto yy9;
+ }
+yy23:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'T':
+ case 't': goto yy34;
+ default: goto yy9;
+ }
+yy24:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'T':
+ case 't': goto yy35;
+ default: goto yy9;
+ }
+yy25:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'D':
+ case 'd': goto yy36;
+ default: goto yy9;
+ }
+yy26:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'A':
+ case 'a': goto yy37;
+ default: goto yy9;
+ }
+yy27:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'M':
+ case 'm': goto yy38;
+ default: goto yy9;
+ }
+yy28:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'T':
+ case 't': goto yy39;
+ default: goto yy9;
+ }
+yy29:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'T':
+ case 't': goto yy40;
+ default: goto yy9;
+ }
+yy30:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'L':
+ case 'l': goto yy41;
+ default: goto yy9;
+ }
+yy31:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'Y':
+ case 'y': goto yy43;
+ default: goto yy9;
+ }
+yy32:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'D':
+ case 'd': goto yy45;
+ default: goto yy9;
+ }
+yy33:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'L':
+ case 'l': goto yy47;
+ default: goto yy9;
+ }
+yy34:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'L':
+ case 'l': goto yy49;
+ default: goto yy9;
+ }
+yy35:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'L':
+ case 'l': goto yy50;
+ default: goto yy9;
+ }
+yy36:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'Y':
+ case 'y': goto yy51;
+ default: goto yy9;
+ }
+yy37:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'D':
+ case 'd': goto yy52;
+ default: goto yy9;
+ }
+yy38:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'L':
+ case 'l': goto yy53;
+ default: goto yy9;
+ }
+yy39:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'L':
+ case 'l': goto yy54;
+ default: goto yy9;
+ }
+yy40:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'L':
+ case 'l': goto yy55;
+ default: goto yy9;
+ }
+yy41:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '>': goto yy56;
+ default: goto yy41;
+ }
+yy43:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '>': goto yy58;
+ default: goto yy43;
+ }
+yy45:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '>': goto yy60;
+ default: goto yy45;
+ }
+yy47:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '>': goto yy62;
+ default: goto yy47;
+ }
+yy49:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'I':
+ case 'i': goto yy64;
+ default: goto yy9;
+ }
+yy50:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy65;
+ default: goto yy9;
+ }
+yy51:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case '>': goto yy67;
+ default: goto yy9;
+ }
+yy52:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case '>': goto yy69;
+ default: goto yy9;
+ }
+yy53:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case '>': goto yy71;
+ default: goto yy9;
+ }
+yy54:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'I':
+ case 'i': goto yy73;
+ default: goto yy9;
+ }
+yy55:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy74;
+ default: goto yy9;
+ }
+yy56:
+ ++YYCURSOR;
+ { return OPML_XML; }
+yy58:
+ ++YYCURSOR;
+ { return OPML_BODY_OPEN; }
+yy60:
+ ++YYCURSOR;
+ { return OPML_HEAD_OPEN; }
+yy62:
+ ++YYCURSOR;
+ { return OPML_OPML_OPEN; }
+yy64:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'N':
+ case 'n': goto yy75;
+ default: goto yy9;
+ }
+yy65:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '>': goto yy76;
+ default: goto yy65;
+ }
+yy67:
+ ++YYCURSOR;
+ { return OPML_BODY_CLOSE; }
+yy69:
+ ++YYCURSOR;
+ { return OPML_HEAD_CLOSE; }
+yy71:
+ ++YYCURSOR;
+ { return OPML_OPML_CLOSE; }
+yy73:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'N':
+ case 'n': goto yy78;
+ default: goto yy9;
+ }
+yy74:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case '>': goto yy79;
+ default: goto yy9;
+ }
+yy75:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy81;
+ default: goto yy9;
+ }
+yy76:
+ ++YYCURSOR;
+ { return OPML_TITLE_OPEN; }
+yy78:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy83;
+ default: goto yy9;
+ }
+yy79:
+ ++YYCURSOR;
+ { return OPML_TITLE_CLOSE; }
+yy81:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy81;
+ case '/': goto yy86;
+ case '>': goto yy88;
+ case 'T':
+ case 't': goto yy90;
+ default: goto yy84;
+ }
+yy83:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case '>': goto yy91;
+ default: goto yy9;
+ }
+yy84:
+ yych = *++YYCURSOR;
+yy85:
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '/': goto yy86;
+ case '>': goto yy88;
+ default: goto yy84;
+ }
+yy86:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '/': goto yy86;
+ case '>': goto yy93;
+ default: goto yy84;
+ }
+yy88:
+ ++YYCURSOR;
+yy89:
+ { return OPML_OUTLINE_OPEN; }
+yy90:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy95;
+ default: goto yy85;
+ }
+yy91:
+ ++YYCURSOR;
+ { return OPML_OUTLINE_CLOSE; }
+yy93:
+ ++YYCURSOR;
+yy94:
+ { return OPML_OUTLINE_SELF_CLOSE; }
+yy95:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'X':
+ case 'x': goto yy96;
+ default: goto yy85;
+ }
+yy96:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'T':
+ case 't': goto yy97;
+ default: goto yy85;
+ }
+yy97:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy97;
+ case '/': goto yy86;
+ case '=': goto yy99;
+ case '>': goto yy88;
+ default: goto yy84;
+ }
+yy99:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy99;
+ case '"': goto yy101;
+ case '/': goto yy86;
+ case '>': goto yy88;
+ default: goto yy84;
+ }
+yy101:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case '(': goto yy102;
+ case 'M':
+ case 'm': goto yy103;
+ default: goto yy85;
+ }
+yy102:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'U':
+ case 'u': goto yy104;
+ default: goto yy85;
+ }
+yy103:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy105;
+ default: goto yy85;
+ }
+yy104:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'N':
+ case 'n': goto yy106;
+ default: goto yy85;
+ }
+yy105:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'T':
+ case 't': goto yy107;
+ default: goto yy85;
+ }
+yy106:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'T':
+ case 't': goto yy108;
+ default: goto yy85;
+ }
+yy107:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'A':
+ case 'a': goto yy109;
+ default: goto yy85;
+ }
+yy108:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'I':
+ case 'i': goto yy110;
+ default: goto yy85;
+ }
+yy109:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'D':
+ case 'd': goto yy111;
+ default: goto yy85;
+ }
+yy110:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'T':
+ case 't': goto yy112;
+ default: goto yy85;
+ }
+yy111:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'A':
+ case 'a': goto yy113;
+ default: goto yy85;
+ }
+yy112:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'L':
+ case 'l': goto yy114;
+ default: goto yy85;
+ }
+yy113:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'T':
+ case 't': goto yy115;
+ default: goto yy85;
+ }
+yy114:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy116;
+ default: goto yy85;
+ }
+yy115:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'A':
+ case 'a': goto yy117;
+ default: goto yy85;
+ }
+yy116:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'D':
+ case 'd': goto yy118;
+ default: goto yy85;
+ }
+yy117:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case '"': goto yy119;
+ default: goto yy85;
+ }
+yy118:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case ' ': goto yy121;
+ default: goto yy85;
+ }
+yy119:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy119;
+ case '/': goto yy86;
+ case '>': goto yy122;
+ default: goto yy84;
+ }
+yy121:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'P':
+ case 'p': goto yy124;
+ default: goto yy85;
+ }
+yy122:
+ ++YYCURSOR;
+ { return OPML_OUTLINE_METADATA; }
+yy124:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'R':
+ case 'r': goto yy125;
+ default: goto yy85;
+ }
+yy125:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy126;
+ default: goto yy85;
+ }
+yy126:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'A':
+ case 'a': goto yy127;
+ default: goto yy85;
+ }
+yy127:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'M':
+ case 'm': goto yy128;
+ default: goto yy85;
+ }
+yy128:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'B':
+ case 'b': goto yy129;
+ default: goto yy85;
+ }
+yy129:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'L':
+ case 'l': goto yy130;
+ default: goto yy85;
+ }
+yy130:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy131;
+ default: goto yy85;
+ }
+yy131:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case ')': goto yy132;
+ default: goto yy85;
+ }
+yy132:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case '"': goto yy133;
+ default: goto yy85;
+ }
+yy133:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy133;
+ case '/': goto yy86;
+ case '>': goto yy88;
+ case '_': goto yy135;
+ default: goto yy84;
+ }
+yy135:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'N':
+ case 'n': goto yy136;
+ default: goto yy85;
+ }
+yy136:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'O':
+ case 'o': goto yy137;
+ default: goto yy85;
+ }
+yy137:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'T':
+ case 't': goto yy138;
+ default: goto yy85;
+ }
+yy138:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy139;
+ default: goto yy85;
+ }
+yy139:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy139;
+ case '/': goto yy86;
+ case '=': goto yy141;
+ case '>': goto yy88;
+ default: goto yy84;
+ }
+yy141:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy141;
+ case '"': goto yy143;
+ case '/': goto yy86;
+ case '>': goto yy88;
+ default: goto yy84;
+ }
+yy143:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '"': goto yy145;
+ case '/': goto yy147;
+ case '>': goto yy149;
+ default: goto yy143;
+ }
+yy145:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy145;
+ case '/': goto yy86;
+ case '>': goto yy150;
+ default: goto yy84;
+ }
+yy147:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '"': goto yy145;
+ case '/': goto yy147;
+ case '>': goto yy152;
+ default: goto yy143;
+ }
+yy149:
+ yyaccept = 1;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= 0x00) goto yy89;
+ goto yy154;
+yy150:
+ ++YYCURSOR;
+ { return OPML_OUTLINE_PREAMBLE; }
+yy152:
+ yyaccept = 2;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if (yych <= 0x00) goto yy94;
+ goto yy154;
+yy153:
+ yych = *++YYCURSOR;
+yy154:
+ switch (yych) {
+ case 0x00: goto yy9;
+ case '"': goto yy155;
+ default: goto yy153;
+ }
+yy155:
+ yych = *++YYCURSOR;
+ switch (yych) {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy155;
+ case '>': goto yy150;
+ default: goto yy9;
+ }
+}
+
+}
+
+
+
+
+/// skip through text attribute to find value
+size_t scan_text(const char * c) {
+ const char * marker = NULL;
+ const char * start = c;
+
+
+{
+ unsigned char yych;
+ yych = *(marker = c);
+ switch (yych) {
+ case '\t':
+ case '\r':
+ case ' ': goto yy161;
+ case '\n': goto yy162;
+ case 'T':
+ case 't': goto yy165;
+ default: goto yy160;
+ }
+yy159:
+ { return 0; }
+yy160:
+ ++c;
+ goto yy159;
+yy161:
+ yych = *(marker = ++c);
+ switch (yych) {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy162;
+ case 'T':
+ case 't': goto yy166;
+ default: goto yy159;
+ }
+yy162:
+ yych = *++c;
+ switch (yych) {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy162;
+ case 'T':
+ case 't': goto yy166;
+ default: goto yy164;
+ }
+yy164:
+ c = marker;
+ goto yy159;
+yy165:
+ yych = *(marker = ++c);
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy167;
+ default: goto yy159;
+ }
+yy166:
+ yych = *++c;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy167;
+ default: goto yy164;
+ }
+yy167:
+ yych = *++c;
+ switch (yych) {
+ case 'X':
+ case 'x': goto yy168;
+ default: goto yy164;
+ }
+yy168:
+ yych = *++c;
+ switch (yych) {
+ case 'T':
+ case 't': goto yy169;
+ default: goto yy164;
+ }
+yy169:
+ yych = *++c;
+ switch (yych) {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy169;
+ case '=': goto yy171;
+ default: goto yy164;
+ }
+yy171:
+ yych = *++c;
+ switch (yych) {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy171;
+ case '"':
+ marker = c;
+ goto yy173;
+ default: goto yy164;
+ }
+yy173:
+ yych = *++c;
+ switch (yych) {
+ case 0x00: goto yy164;
+ case '"': goto yy175;
+ default: goto yy173;
+ }
+yy175:
+ ++c;
+ c = marker;
+ { return (size_t)( c - start ); }
+}
+
+}
+
+
+/// skip through _note attribute to find value
+size_t scan_note(const char * c) {
+ const char * marker = NULL;
+ const char * start = c;
+
+
+{
+ unsigned char yych;
+ yych = *(marker = c);
+ switch (yych) {
+ case '\t':
+ case '\r':
+ case ' ': goto yy181;
+ case '\n': goto yy182;
+ case '_': goto yy185;
+ default: goto yy180;
+ }
+yy179:
+ { return 0; }
+yy180:
+ ++c;
+ goto yy179;
+yy181:
+ yych = *(marker = ++c);
+ switch (yych) {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy182;
+ case '_': goto yy186;
+ default: goto yy179;
+ }
+yy182:
+ yych = *++c;
+ switch (yych) {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy182;
+ case '_': goto yy186;
+ default: goto yy184;
+ }
+yy184:
+ c = marker;
+ goto yy179;
+yy185:
+ yych = *(marker = ++c);
+ switch (yych) {
+ case 'N':
+ case 'n': goto yy187;
+ default: goto yy179;
+ }
+yy186:
+ yych = *++c;
+ switch (yych) {
+ case 'N':
+ case 'n': goto yy187;
+ default: goto yy184;
+ }
+yy187:
+ yych = *++c;
+ switch (yych) {
+ case 'O':
+ case 'o': goto yy188;
+ default: goto yy184;
+ }
+yy188:
+ yych = *++c;
+ switch (yych) {
+ case 'T':
+ case 't': goto yy189;
+ default: goto yy184;
+ }
+yy189:
+ yych = *++c;
+ switch (yych) {
+ case 'E':
+ case 'e': goto yy190;
+ default: goto yy184;
+ }
+yy190:
+ yych = *++c;
+ switch (yych) {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy190;
+ case '=': goto yy192;
+ default: goto yy184;
+ }
+yy192:
+ yych = *++c;
+ switch (yych) {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ': goto yy192;
+ case '"':
+ marker = c;
+ goto yy194;
+ default: goto yy184;
+ }
+yy194:
+ yych = *++c;
+ switch (yych) {
+ case 0x00: goto yy184;
+ case '"': goto yy196;
+ default: goto yy194;
+ }
+yy196:
+ ++c;
+ c = marker;
+ { return (size_t)( c - start ); }
+}
+
+}
+
+
+/// find end of double quoted value
+size_t scan_double_quoted(const char * c) {
+ const char * marker = NULL;
+ const char * start = c;
+
+
+{
+ unsigned char yych;
+ yych = *c;
+ switch (yych) {
+ case '\n': goto yy200;
+ case '"': goto yy202;
+ default: goto yy201;
+ }
+yy200:
+ { return 0; }
+yy201:
+ ++c;
+ goto yy200;
+yy202:
+ yych = *(marker = ++c);
+ if (yych <= 0x00) goto yy200;
+ goto yy204;
+yy203:
+ yych = *++c;
+yy204:
+ switch (yych) {
+ case 0x00: goto yy205;
+ case '"': goto yy206;
+ default: goto yy203;
+ }
+yy205:
+ c = marker;
+ goto yy200;
+yy206:
+ ++c;
+ { return (size_t)( c - start ); }
+}
+
+}
--- /dev/null
+/**
+
+ MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+ @file opml-lexer.h
+
+ @brief
+
+
+ @author Fletcher T. Penney
+ @bug
+
+**/
+
+/*
+
+ Copyright © 2016 - 2018 Fletcher T. Penney.
+
+
+ The `MultiMarkdown 6` project is released under the MIT License..
+
+ GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+
+ https://github.com/fletcher/MultiMarkdown-4/
+
+ MMD 4 is released under both the MIT License and GPL.
+
+
+ CuTest is released under the zlib/libpng license. See CuTest.c for the
+ text of the license.
+
+ uthash library:
+ Copyright (c) 2005-2016, Troy D. Hanson
+
+ Licensed under Revised BSD license
+
+ miniz library:
+ Copyright 2013-2014 RAD Game Tools and Valve Software
+ Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+
+ Licensed under the MIT license
+
+ argtable3 library:
+ Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ <sheitmann@users.sourceforge.net>
+ All rights reserved.
+
+ Licensed under the Revised BSD License
+
+
+ ## The MIT License ##
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+ ## Revised BSD License ##
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "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 <COPYRIGHT
+ HOLDER> 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 OPML_LEXER_MULTIMARKDOWN_H
+#define OPML_LEXER_MULTIMARKDOWN_H
+
+enum opml_tokens {
+ OPML_XML,
+ OPML_OPML_OPEN,
+ OPML_OPML_CLOSE,
+ OPML_HEAD_OPEN,
+ OPML_HEAD_CLOSE,
+ OPML_TITLE_OPEN,
+ OPML_TITLE_CLOSE,
+ OPML_BODY_OPEN,
+ OPML_BODY_CLOSE,
+ OPML_WSNL,
+};
+
+/// Re2c scanner data -- this structure is used by the re2c
+/// lexer to track progress and offsets within the source
+/// string. They can be used to create "tokens" that match
+/// sections of the text with an abstract syntax tree.
+struct Scanner {
+ const char * start; //!< Start of current token
+ const char * cur; //!< Character currently being matched
+ const char * ptr; //!< Used for backtracking by re2c
+ const char * ctx;
+};
+
+typedef struct Scanner Scanner;
+
+
+/// Scan for the next opml token
+int opml_scan(
+ Scanner * s, //!< Pointer to Scanner state structure
+ const char * stop //!< Pointer to position in string at which to stop parsing
+);
+
+
+/// skip through text attribute to find value
+size_t scan_text(const char * c);
+
+
+/// skip through _note attribute to find value
+size_t scan_note(const char * c);
+
+
+/// find end of double quoted value
+size_t scan_double_quoted(const char * c);
+
+#endif
--- /dev/null
+/**
+
+ MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+ @file opml-lexer.c
+
+ @brief Tokenize OPML file for parsing
+
+
+ @author Fletcher T. Penney
+ @bug
+
+**/
+
+/*
+
+ Copyright © 2016 - 2018 Fletcher T. Penney.
+
+
+ The `MultiMarkdown 6` project is released under the MIT License..
+
+ GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+
+ https://github.com/fletcher/MultiMarkdown-4/
+
+ MMD 4 is released under both the MIT License and GPL.
+
+
+ CuTest is released under the zlib/libpng license. See CuTest.c for the
+ text of the license.
+
+ uthash library:
+ Copyright (c) 2005-2016, Troy D. Hanson
+
+ Licensed under Revised BSD license
+
+ miniz library:
+ Copyright 2013-2014 RAD Game Tools and Valve Software
+ Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+
+ Licensed under the MIT license
+
+ argtable3 library:
+ Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ <sheitmann@users.sourceforge.net>
+ All rights reserved.
+
+ Licensed under the Revised BSD License
+
+
+ ## The MIT License ##
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+ ## Revised BSD License ##
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "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 <COPYRIGHT
+ HOLDER> 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 <stdlib.h>
+
+#include "opml-lexer.h"
+#include "opml-parser.h"
+
+
+// Basic scanner struct
+
+#define YYCTYPE unsigned char
+#define YYCURSOR s->cur
+#define YYMARKER s->ptr
+#define YYCTXMARKER s->ctx
+
+int opml_scan(Scanner * s, const char * stop) {
+
+ scan:
+
+ if (s->cur >= stop) {
+ return 0;
+ }
+
+ s->start = s->cur;
+
+ /*!re2c
+ re2c:yyfill:enable = 0;
+
+ NL = "\r\n" | '\n' | '\r';
+ WS = [ \t]+;
+ WSNL = (NL | WS)+;
+
+ EQUAL = '=';
+
+ double_quoted = '"' [^"\x00]* '"';
+
+ text_attribute = WSNL* 'text' WSNL* EQUAL WSNL*;
+ note_attribute = WSNL* '_note' WSNL* EQUAL WSNL*;
+
+ '<?xml' [^>\x00]* '>' { return OPML_XML; }
+
+ '<opml' [^>\x00]* '>' { return OPML_OPML_OPEN; }
+ '</opml>' { return OPML_OPML_CLOSE; }
+
+ '<head' [^>\x00]* '>' { return OPML_HEAD_OPEN; }
+ '</head>' { return OPML_HEAD_CLOSE; }
+
+ '<title' [^>\x00]* '>' { return OPML_TITLE_OPEN; }
+ '</title>' { return OPML_TITLE_CLOSE; }
+
+ '<body' [^>\x00]* '>' { return OPML_BODY_OPEN; }
+ '</body>' { return OPML_BODY_CLOSE; }
+
+ '<outline' text_attribute '"(Untitled Preamble)"' note_attribute double_quoted WSNL* '>' { return OPML_OUTLINE_PREAMBLE; }
+ '<outline' text_attribute '"Metadata"' WSNL* '>' { return OPML_OUTLINE_METADATA; }
+
+
+ '<outline' [^>\x00]* '/>' { return OPML_OUTLINE_SELF_CLOSE; }
+ '<outline' [^>\x00]* '>' { return OPML_OUTLINE_OPEN; }
+ '</outline>' { return OPML_OUTLINE_CLOSE; }
+
+ WSNL { return OPML_WSNL; }
+
+ // Skip over anything else - '.' does not include '\n'
+ . { goto scan; }
+ */
+}
+
+
+/*!re2c
+
+ re2c:define:YYCTYPE = "unsigned char";
+ re2c:define:YYCURSOR = c;
+ re2c:define:YYMARKER = marker;
+ re2c:define:YYCTXMARKER = marker;
+ re2c:yyfill:enable = 0;
+
+*/
+
+/// skip through text attribute to find value
+size_t scan_text(const char * c) {
+ const char * marker = NULL;
+ const char * start = c;
+
+/*!re2c
+ text_attribute / double_quoted { return (size_t)( c - start ); }
+ .? { return 0; }
+*/
+}
+
+
+/// skip through _note attribute to find value
+size_t scan_note(const char * c) {
+ const char * marker = NULL;
+ const char * start = c;
+
+/*!re2c
+ note_attribute / double_quoted { return (size_t)( c - start ); }
+ .? { return 0; }
+*/
+}
+
+
+/// find end of double quoted value
+size_t scan_double_quoted(const char * c) {
+ const char * marker = NULL;
+ const char * start = c;
+
+/*!re2c
+ double_quoted { return (size_t)( c - start ); }
+ .? { return 0; }
+*/
+}
--- /dev/null
+/*
+** 2000-05-29
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** Driver template for the LEMON parser generator.
+**
+** The "lemon" program processes an LALR(1) input grammar file, then uses
+** this template to construct a parser. The "lemon" program inserts text
+** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the
+** interstitial "-" characters) contained in this template is changed into
+** the value of the %name directive from the grammar. Otherwise, the content
+** of this template is copied straight through into the generate parser
+** source file.
+**
+** The following is the concatenation of all %include directives from the
+** input grammar file:
+*/
+#include <stdio.h>
+/************ Begin %include sections from the grammar ************************/
+
+ #include <assert.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ #include "libMultiMarkdown.h"
+ #include "mmd.h"
+ #include "parser.h"
+ #include "token.h"
+/**************** End of %include directives **********************************/
+/* These constants specify the various numeric values for terminal symbols
+** in a format understandable to "makeheaders". This section is blank unless
+** "lemon" is run with the "-m" command-line option.
+***************** Begin makeheaders token definitions *************************/
+/**************** End makeheaders token definitions ***************************/
+
+/* The next sections is a series of control #defines.
+** various aspects of the generated parser.
+** YYCODETYPE is the data type used to store the integer codes
+** that represent terminal and non-terminal symbols.
+** "unsigned char" is used if there are fewer than
+** 256 symbols. Larger types otherwise.
+** YYNOCODE is a number of type YYCODETYPE that is not used for
+** any terminal or nonterminal symbol.
+** YYFALLBACK If defined, this indicates that one or more tokens
+** (also known as: "terminal symbols") have fall-back
+** values which should be used if the original symbol
+** would not parse. This permits keywords to sometimes
+** be used as identifiers, for example.
+** YYACTIONTYPE is the data type used for "action codes" - numbers
+** that indicate what to do in response to the next
+** token.
+** OPMLTOKENTYPE is the data type used for minor type for terminal
+** symbols. Background: A "minor type" is a semantic
+** value associated with a terminal or non-terminal
+** symbols. For example, for an "ID" terminal symbol,
+** the minor type might be the name of the identifier.
+** Each non-terminal can have a different minor type.
+** Terminal symbols all have the same minor type, though.
+** This macros defines the minor type for terminal
+** symbols.
+** YYMINORTYPE is the data type used for all minor types.
+** This is typically a union of many types, one of
+** which is OPMLTOKENTYPE. The entry in the union
+** for terminal symbols is called "yy0".
+** YYSTACKDEPTH is the maximum depth of the parser's stack. If
+** zero the stack is dynamically sized using realloc()
+** OPMLARG_SDECL A static variable declaration for the %extra_argument
+** OPMLARG_PDECL A parameter declaration for the %extra_argument
+** OPMLARG_STORE Code to store %extra_argument into yypParser
+** OPMLARG_FETCH Code to extract %extra_argument from yypParser
+** YYERRORSYMBOL is the code number of the error symbol. If not
+** defined, then do no error processing.
+** YYNSTATE the combined number of states.
+** YYNRULE the number of rules in the grammar
+** YY_MAX_SHIFT Maximum value for shift actions
+** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
+** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
+** YY_MIN_REDUCE Maximum value for reduce actions
+** YY_ERROR_ACTION The yy_action[] code for syntax error
+** YY_ACCEPT_ACTION The yy_action[] code for accept
+** YY_NO_ACTION The yy_action[] code for no-op
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/************* Begin control #defines *****************************************/
+#define YYCODETYPE unsigned char
+#define YYNOCODE 26
+#define YYACTIONTYPE unsigned char
+#define OPMLTOKENTYPE token *
+typedef union {
+ int yyinit;
+ OPMLTOKENTYPE yy0;
+} YYMINORTYPE;
+#ifndef YYSTACKDEPTH
+#define YYSTACKDEPTH 100
+#endif
+#define OPMLARG_SDECL mmd_engine * engine ;
+#define OPMLARG_PDECL , mmd_engine * engine
+#define OPMLARG_FETCH mmd_engine * engine = yypParser->engine
+#define OPMLARG_STORE yypParser->engine = engine
+#define YYNSTATE 18
+#define YYNRULE 17
+#define YY_MAX_SHIFT 17
+#define YY_MIN_SHIFTREDUCE 33
+#define YY_MAX_SHIFTREDUCE 49
+#define YY_MIN_REDUCE 50
+#define YY_MAX_REDUCE 66
+#define YY_ERROR_ACTION 67
+#define YY_ACCEPT_ACTION 68
+#define YY_NO_ACTION 69
+/************* End control #defines *******************************************/
+
+/* Define the yytestcase() macro to be a no-op if is not already defined
+** otherwise.
+**
+** Applications can choose to define yytestcase() in the %include section
+** to a macro that can assist in verifying code coverage. For production
+** code the yytestcase() macro should be turned off. But it is useful
+** for testing.
+*/
+#ifndef yytestcase
+# define yytestcase(X)
+#endif
+
+
+/* Next are the tables used to determine what action to take based on the
+** current state and lookahead token. These tables are used to implement
+** functions that take a state number and lookahead value and return an
+** action integer.
+**
+** Suppose the action integer is N. Then the action is determined as
+** follows
+**
+** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead
+** token onto the stack and goto state N.
+**
+** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then
+** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE.
+**
+** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE
+** and YY_MAX_REDUCE
+**
+** N == YY_ERROR_ACTION A syntax error has occurred.
+**
+** N == YY_ACCEPT_ACTION The parser accepts its input.
+**
+** N == YY_NO_ACTION No such action. Denotes unused
+** slots in the yy_action[] table.
+**
+** The action table is constructed as a single large table named yy_action[].
+** Given state S and lookahead X, the action is computed as either:
+**
+** (A) N = yy_action[ yy_shift_ofst[S] + X ]
+** (B) N = yy_default[S]
+**
+** The (A) formula is preferred. The B formula is used instead if:
+** (1) The yy_shift_ofst[S]+X value is out of range, or
+** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or
+** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT.
+** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that
+** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X.
+** Hence only tests (1) and (2) need to be evaluated.)
+**
+** The formulas above are for computing the action when the lookahead is
+** a terminal symbol. If the lookahead is a non-terminal (as occurs after
+** a reduce action) then the yy_reduce_ofst[] array is used in place of
+** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
+** YY_SHIFT_USE_DFLT.
+**
+** The following are the tables generated in this section:
+**
+** yy_action[] A single table containing all actions.
+** yy_lookahead[] A table containing the lookahead for each entry in
+** yy_action. Used to detect hash collisions.
+** yy_shift_ofst[] For each state, the offset into yy_action for
+** shifting terminals.
+** yy_reduce_ofst[] For each state, the offset into yy_action for
+** shifting non-terminals after a reduce.
+** yy_default[] Default action for each state.
+**
+*********** Begin parsing tables **********************************************/
+#define YY_ACTTAB_COUNT (57)
+static const YYACTIONTYPE yy_action[] = {
+ /* 0 */ 1, 45, 14, 3, 49, 42, 1, 10, 14, 3,
+ /* 10 */ 49, 1, 48, 14, 3, 49, 1, 47, 14, 3,
+ /* 20 */ 49, 41, 1, 43, 14, 3, 49, 1, 2, 14,
+ /* 30 */ 3, 49, 68, 17, 15, 6, 6, 7, 7, 8,
+ /* 40 */ 5, 5, 12, 2, 40, 9, 13, 39, 11, 4,
+ /* 50 */ 16, 38, 37, 36, 46, 35, 50,
+};
+static const YYCODETYPE yy_lookahead[] = {
+ /* 0 */ 11, 12, 13, 14, 15, 10, 11, 1, 13, 14,
+ /* 10 */ 15, 11, 12, 13, 14, 15, 11, 12, 13, 14,
+ /* 20 */ 15, 10, 11, 24, 13, 14, 15, 11, 9, 13,
+ /* 30 */ 14, 15, 17, 18, 21, 23, 24, 23, 24, 5,
+ /* 40 */ 23, 24, 22, 9, 8, 20, 21, 6, 7, 3,
+ /* 50 */ 19, 6, 4, 4, 12, 2, 0,
+};
+#define YY_SHIFT_USE_DFLT (57)
+#define YY_SHIFT_COUNT (17)
+#define YY_SHIFT_MIN (-11)
+#define YY_SHIFT_MAX (56)
+static const signed char yy_shift_ofst[] = {
+ /* 0 */ 6, -11, -5, 16, 34, 0, 5, 11, 41, 19,
+ /* 10 */ 46, 36, 45, 48, 42, 49, 53, 56,
+};
+#define YY_REDUCE_USE_DFLT (-2)
+#define YY_REDUCE_COUNT (10)
+#define YY_REDUCE_MIN (-1)
+#define YY_REDUCE_MAX (31)
+static const signed char yy_reduce_ofst[] = {
+ /* 0 */ 15, 12, 14, 17, 25, -1, -1, -1, 20, 13,
+ /* 10 */ 31,
+};
+static const YYACTIONTYPE yy_default[] = {
+ /* 0 */ 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+ /* 10 */ 67, 67, 67, 67, 67, 67, 51, 67,
+};
+/********** End of lemon-generated parsing tables *****************************/
+
+/* The next table maps tokens (terminal symbols) into fallback tokens.
+** If a construct like the following:
+**
+** %fallback ID X Y Z.
+**
+** appears in the grammar, then ID becomes a fallback token for X, Y,
+** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
+** but it does not parse, the type of the token is changed to ID and
+** the parse is retried before an error is thrown.
+**
+** This feature can be used, for example, to cause some keywords in a language
+** to revert to identifiers if they keyword does not apply in the context where
+** it appears.
+*/
+#ifdef YYFALLBACK
+static const YYCODETYPE yyFallback[] = {
+};
+#endif /* YYFALLBACK */
+
+/* The following structure represents a single element of the
+** parser's stack. Information stored includes:
+**
+** + The state number for the parser at this level of the stack.
+**
+** + The value of the token stored at this level of the stack.
+** (In other words, the "major" token.)
+**
+** + The semantic value stored at this level of the stack. This is
+** the information used by the action routines in the grammar.
+** It is sometimes called the "minor" token.
+**
+** After the "shift" half of a SHIFTREDUCE action, the stateno field
+** actually contains the reduce action for the second half of the
+** SHIFTREDUCE.
+*/
+struct yyStackEntry {
+ YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */
+ YYCODETYPE major; /* The major token value. This is the code
+ ** number for the token at this stack level */
+ YYMINORTYPE minor; /* The user-supplied minor token value. This
+ ** is the value of the token */
+};
+typedef struct yyStackEntry yyStackEntry;
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct yyParser {
+ yyStackEntry *yytos; /* Pointer to top element of the stack */
+#ifdef YYTRACKMAXSTACKDEPTH
+ int yyhwm; /* High-water mark of the stack */
+#endif
+#ifndef YYNOERRORRECOVERY
+ int yyerrcnt; /* Shifts left before out of the error */
+#endif
+ OPMLARG_SDECL /* A place to hold %extra_argument */
+#if YYSTACKDEPTH<=0
+ int yystksz; /* Current side of the stack */
+ yyStackEntry *yystack; /* The parser's stack */
+ yyStackEntry yystk0; /* First stack entry */
+#else
+ yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+#endif
+};
+typedef struct yyParser yyParser;
+
+#ifndef NDEBUG
+#include <stdio.h>
+static FILE *yyTraceFILE = 0;
+static char *yyTracePrompt = 0;
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/*
+** Turn parser tracing on by giving a stream to which to write the trace
+** and a prompt to preface each trace message. Tracing is turned off
+** by making either argument NULL
+**
+** Inputs:
+** <ul>
+** <li> A FILE* to which trace output should be written.
+** If NULL, then tracing is turned off.
+** <li> A prefix string written at the beginning of every
+** line of trace output. If NULL, then tracing is
+** turned off.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void OPMLTrace(FILE *TraceFILE, char *zTracePrompt){
+ yyTraceFILE = TraceFILE;
+ yyTracePrompt = zTracePrompt;
+ if( yyTraceFILE==0 ) yyTracePrompt = 0;
+ else if( yyTracePrompt==0 ) yyTraceFILE = 0;
+}
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required. The following table supplies these names */
+static const char *const yyTokenName[] = {
+ "$", "OPML_XML", "OPML_WSNL", "OPML_OPML_OPEN",
+ "OPML_OPML_CLOSE", "OPML_HEAD_OPEN", "OPML_HEAD_CLOSE", "OPML_TITLE_OPEN",
+ "OPML_TITLE_CLOSE", "OPML_BODY_OPEN", "OPML_BODY_CLOSE", "OPML_OUTLINE_OPEN",
+ "OPML_OUTLINE_CLOSE", "OPML_OUTLINE_PREAMBLE", "OPML_OUTLINE_METADATA", "OPML_OUTLINE_SELF_CLOSE",
+ "error", "doc", "doc_xml", "doc_opml",
+ "opml_header", "opml_body", "opml_title", "opml_outlines",
+ "opml_outline",
+};
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing reduce actions, the names of all rules are required.
+*/
+static const char *const yyRuleName[] = {
+ /* 0 */ "doc ::= doc_xml",
+ /* 1 */ "doc_xml ::= OPML_XML doc_opml",
+ /* 2 */ "doc_xml ::= OPML_XML doc_opml OPML_WSNL",
+ /* 3 */ "doc_opml ::= OPML_OPML_OPEN opml_header opml_body OPML_OPML_CLOSE",
+ /* 4 */ "doc_opml ::= OPML_OPML_OPEN opml_body OPML_OPML_CLOSE",
+ /* 5 */ "opml_header ::= OPML_HEAD_OPEN opml_title OPML_HEAD_CLOSE",
+ /* 6 */ "opml_header ::= OPML_HEAD_OPEN OPML_HEAD_CLOSE",
+ /* 7 */ "opml_title ::= OPML_TITLE_OPEN OPML_TITLE_CLOSE",
+ /* 8 */ "opml_body ::= OPML_BODY_OPEN opml_outlines OPML_BODY_CLOSE",
+ /* 9 */ "opml_body ::= OPML_BODY_OPEN OPML_BODY_CLOSE",
+ /* 10 */ "opml_outlines ::= opml_outlines opml_outline",
+ /* 11 */ "opml_outlines ::= opml_outline",
+ /* 12 */ "opml_outline ::= OPML_OUTLINE_OPEN OPML_OUTLINE_CLOSE",
+ /* 13 */ "opml_outline ::= OPML_OUTLINE_PREAMBLE OPML_OUTLINE_CLOSE",
+ /* 14 */ "opml_outline ::= OPML_OUTLINE_OPEN opml_outlines OPML_OUTLINE_CLOSE",
+ /* 15 */ "opml_outline ::= OPML_OUTLINE_METADATA opml_outlines OPML_OUTLINE_CLOSE",
+ /* 16 */ "opml_outline ::= OPML_OUTLINE_SELF_CLOSE",
+};
+#endif /* NDEBUG */
+
+
+#if YYSTACKDEPTH<=0
+/*
+** Try to increase the size of the parser stack. Return the number
+** of errors. Return 0 on success.
+*/
+static int yyGrowStack(yyParser *p){
+ int newSize;
+ int idx;
+ yyStackEntry *pNew;
+
+ newSize = p->yystksz*2 + 100;
+ idx = p->yytos ? (int)(p->yytos - p->yystack) : 0;
+ if( p->yystack==&p->yystk0 ){
+ pNew = malloc(newSize*sizeof(pNew[0]));
+ if( pNew ) pNew[0] = p->yystk0;
+ }else{
+ pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ }
+ if( pNew ){
+ p->yystack = pNew;
+ p->yytos = &p->yystack[idx];
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
+ yyTracePrompt, p->yystksz, newSize);
+ }
+#endif
+ p->yystksz = newSize;
+ }
+ return pNew==0;
+}
+#endif
+
+/* Datatype of the argument to the memory allocated passed as the
+** second argument to OPMLAlloc() below. This can be changed by
+** putting an appropriate #define in the %include section of the input
+** grammar.
+*/
+#ifndef YYMALLOCARGTYPE
+# define YYMALLOCARGTYPE size_t
+#endif
+
+/*
+** This function allocates a new parser.
+** The only argument is a pointer to a function which works like
+** malloc.
+**
+** Inputs:
+** A pointer to the function used to allocate memory.
+**
+** Outputs:
+** A pointer to a parser. This pointer is used in subsequent calls
+** to OPML and OPMLFree.
+*/
+void *OPMLAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){
+ yyParser *pParser;
+ pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
+ if( pParser ){
+#ifdef YYTRACKMAXSTACKDEPTH
+ pParser->yyhwm = 0;
+#endif
+#if YYSTACKDEPTH<=0
+ pParser->yytos = NULL;
+ pParser->yystack = NULL;
+ pParser->yystksz = 0;
+ if( yyGrowStack(pParser) ){
+ pParser->yystack = &pParser->yystk0;
+ pParser->yystksz = 1;
+ }
+#endif
+#ifndef YYNOERRORRECOVERY
+ pParser->yyerrcnt = -1;
+#endif
+ pParser->yytos = pParser->yystack;
+ pParser->yystack[0].stateno = 0;
+ pParser->yystack[0].major = 0;
+ }
+ return pParser;
+}
+
+/* The following function deletes the "minor type" or semantic value
+** associated with a symbol. The symbol can be either a terminal
+** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
+** a pointer to the value to be deleted. The code used to do the
+** deletions is derived from the %destructor and/or %token_destructor
+** directives of the input grammar.
+*/
+static void yy_destructor(
+ yyParser *yypParser, /* The parser */
+ YYCODETYPE yymajor, /* Type code for object to destroy */
+ YYMINORTYPE *yypminor /* The object to be destroyed */
+){
+ OPMLARG_FETCH;
+ switch( yymajor ){
+ /* Here is inserted the actions which take place when a
+ ** terminal or non-terminal is destroyed. This can happen
+ ** when the symbol is popped from the stack during a
+ ** reduce or during error processing or when a parser is
+ ** being destroyed before it is finished parsing.
+ **
+ ** Note: during a reduce, the only symbols destroyed are those
+ ** which appear on the RHS of the rule, but which are *not* used
+ ** inside the C code.
+ */
+/********* Begin destructor definitions ***************************************/
+/********* End destructor definitions *****************************************/
+ default: break; /* If no destructor action specified: do nothing */
+ }
+}
+
+/*
+** Pop the parser's stack once.
+**
+** If there is a destructor routine associated with the token which
+** is popped from the stack, then call it.
+*/
+static void yy_pop_parser_stack(yyParser *pParser){
+ yyStackEntry *yytos;
+ assert( pParser->yytos!=0 );
+ assert( pParser->yytos > pParser->yystack );
+ yytos = pParser->yytos--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sPopping %s\n",
+ yyTracePrompt,
+ yyTokenName[yytos->major]);
+ }
+#endif
+ yy_destructor(pParser, yytos->major, &yytos->minor);
+}
+
+/*
+** Deallocate and destroy a parser. Destructors are called for
+** all stack elements before shutting the parser down.
+**
+** If the YYPARSEFREENEVERNULL macro exists (for example because it
+** is defined in a %include section of the input grammar) then it is
+** assumed that the input pointer is never NULL.
+*/
+void OPMLFree(
+ void *p, /* The parser to be deleted */
+ void (*freeProc)(void*) /* Function used to reclaim memory */
+){
+ yyParser *pParser = (yyParser*)p;
+#ifndef YYPARSEFREENEVERNULL
+ if( pParser==0 ) return;
+#endif
+ while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+ if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
+#endif
+ (*freeProc)((void*)pParser);
+}
+
+/*
+** Return the peak depth of the stack for a parser.
+*/
+#ifdef YYTRACKMAXSTACKDEPTH
+int OPMLStackPeak(void *p){
+ yyParser *pParser = (yyParser*)p;
+ return pParser->yyhwm;
+}
+#endif
+
+/*
+** Find the appropriate action for a parser given the terminal
+** look-ahead token iLookAhead.
+*/
+static unsigned int yy_find_shift_action(
+ yyParser *pParser, /* The parser */
+ YYCODETYPE iLookAhead /* The look-ahead token */
+){
+ int i;
+ int stateno = pParser->yytos->stateno;
+
+ if( stateno>=YY_MIN_REDUCE ) return stateno;
+ assert( stateno <= YY_SHIFT_COUNT );
+ do{
+ i = yy_shift_ofst[stateno];
+ assert( iLookAhead!=YYNOCODE );
+ i += iLookAhead;
+ if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+#ifdef YYFALLBACK
+ YYCODETYPE iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+ && (iFallback = yyFallback[iLookAhead])!=0 ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+ }
+#endif
+ assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
+ iLookAhead = iFallback;
+ continue;
+ }
+#endif
+#ifdef YYWILDCARD
+ {
+ int j = i - iLookAhead + YYWILDCARD;
+ if(
+#if YY_SHIFT_MIN+YYWILDCARD<0
+ j>=0 &&
+#endif
+#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
+ j<YY_ACTTAB_COUNT &&
+#endif
+ yy_lookahead[j]==YYWILDCARD && iLookAhead>0
+ ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead],
+ yyTokenName[YYWILDCARD]);
+ }
+#endif /* NDEBUG */
+ return yy_action[j];
+ }
+ }
+#endif /* YYWILDCARD */
+ return yy_default[stateno];
+ }else{
+ return yy_action[i];
+ }
+ }while(1);
+}
+
+/*
+** Find the appropriate action for a parser given the non-terminal
+** look-ahead token iLookAhead.
+*/
+static int yy_find_reduce_action(
+ int stateno, /* Current state number */
+ YYCODETYPE iLookAhead /* The look-ahead token */
+){
+ int i;
+#ifdef YYERRORSYMBOL
+ if( stateno>YY_REDUCE_COUNT ){
+ return yy_default[stateno];
+ }
+#else
+ assert( stateno<=YY_REDUCE_COUNT );
+#endif
+ i = yy_reduce_ofst[stateno];
+ assert( i!=YY_REDUCE_USE_DFLT );
+ assert( iLookAhead!=YYNOCODE );
+ i += iLookAhead;
+#ifdef YYERRORSYMBOL
+ if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+ return yy_default[stateno];
+ }
+#else
+ assert( i>=0 && i<YY_ACTTAB_COUNT );
+ assert( yy_lookahead[i]==iLookAhead );
+#endif
+ return yy_action[i];
+}
+
+/*
+** The following routine is called if the stack overflows.
+*/
+static void yyStackOverflow(yyParser *yypParser){
+ OPMLARG_FETCH;
+ yypParser->yytos--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will execute if the parser
+ ** stack every overflows */
+/******** Begin %stack_overflow code ******************************************/
+/******** End %stack_overflow code ********************************************/
+ OPMLARG_STORE; /* Suppress warning about unused %extra_argument var */
+}
+
+/*
+** Print tracing information for a SHIFT action
+*/
+#ifndef NDEBUG
+static void yyTraceShift(yyParser *yypParser, int yyNewState){
+ if( yyTraceFILE ){
+ if( yyNewState<YYNSTATE ){
+ fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n",
+ yyTracePrompt,yyTokenName[yypParser->yytos->major],
+ yyNewState);
+ }else{
+ fprintf(yyTraceFILE,"%sShift '%s'\n",
+ yyTracePrompt,yyTokenName[yypParser->yytos->major]);
+ }
+ }
+}
+#else
+# define yyTraceShift(X,Y)
+#endif
+
+/*
+** Perform a shift action.
+*/
+static void yy_shift(
+ yyParser *yypParser, /* The parser to be shifted */
+ int yyNewState, /* The new state to shift in */
+ int yyMajor, /* The major token to shift in */
+ OPMLTOKENTYPE yyMinor /* The minor token to shift in */
+){
+ yyStackEntry *yytos;
+ yypParser->yytos++;
+#ifdef YYTRACKMAXSTACKDEPTH
+ if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
+ yypParser->yyhwm++;
+ assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
+ }
+#endif
+#if YYSTACKDEPTH>0
+ if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){
+ yyStackOverflow(yypParser);
+ return;
+ }
+#else
+ if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
+ if( yyGrowStack(yypParser) ){
+ yyStackOverflow(yypParser);
+ return;
+ }
+ }
+#endif
+ if( yyNewState > YY_MAX_SHIFT ){
+ yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
+ }
+ yytos = yypParser->yytos;
+ yytos->stateno = (YYACTIONTYPE)yyNewState;
+ yytos->major = (YYCODETYPE)yyMajor;
+ yytos->minor.yy0 = yyMinor;
+ yyTraceShift(yypParser, yyNewState);
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static const struct {
+ YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
+ unsigned char nrhs; /* Number of right-hand side symbols in the rule */
+} yyRuleInfo[] = {
+ { 17, 1 },
+ { 18, 2 },
+ { 18, 3 },
+ { 19, 4 },
+ { 19, 3 },
+ { 20, 3 },
+ { 20, 2 },
+ { 22, 2 },
+ { 21, 3 },
+ { 21, 2 },
+ { 23, 2 },
+ { 23, 1 },
+ { 24, 2 },
+ { 24, 2 },
+ { 24, 3 },
+ { 24, 3 },
+ { 24, 1 },
+};
+
+static void yy_accept(yyParser*); /* Forward Declaration */
+
+/*
+** Perform a reduce action and the shift that must immediately
+** follow the reduce.
+*/
+static void yy_reduce(
+ yyParser *yypParser, /* The parser */
+ unsigned int yyruleno /* Number of the rule by which to reduce */
+){
+ int yygoto; /* The next state */
+ int yyact; /* The next action */
+ yyStackEntry *yymsp; /* The top of the parser's stack */
+ int yysize; /* Amount to pop the stack */
+ OPMLARG_FETCH;
+ yymsp = yypParser->yytos;
+#ifndef NDEBUG
+ if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
+ yysize = yyRuleInfo[yyruleno].nrhs;
+ fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt,
+ yyRuleName[yyruleno], yymsp[-yysize].stateno);
+ }
+#endif /* NDEBUG */
+
+ /* Check that the stack is large enough to grow by a single entry
+ ** if the RHS of the rule is empty. This ensures that there is room
+ ** enough on the stack to push the LHS value */
+ if( yyRuleInfo[yyruleno].nrhs==0 ){
+#ifdef YYTRACKMAXSTACKDEPTH
+ if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
+ yypParser->yyhwm++;
+ assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack));
+ }
+#endif
+#if YYSTACKDEPTH>0
+ if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){
+ yyStackOverflow(yypParser);
+ return;
+ }
+#else
+ if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
+ if( yyGrowStack(yypParser) ){
+ yyStackOverflow(yypParser);
+ return;
+ }
+ yymsp = yypParser->yytos;
+ }
+#endif
+ }
+
+ switch( yyruleno ){
+ /* Beginning here are the reduction cases. A typical example
+ ** follows:
+ ** case 0:
+ ** #line <lineno> <grammarfile>
+ ** { ... } // User supplied code
+ ** #line <lineno> <thisfile>
+ ** break;
+ */
+/********** Begin reduce actions **********************************************/
+ case 0: /* doc ::= doc_xml */
+{ engine->root = yymsp[0].minor.yy0; }
+ break;
+ default:
+ /* (1) doc_xml ::= OPML_XML doc_opml */ yytestcase(yyruleno==1);
+ /* (2) doc_xml ::= OPML_XML doc_opml OPML_WSNL */ yytestcase(yyruleno==2);
+ /* (3) doc_opml ::= OPML_OPML_OPEN opml_header opml_body OPML_OPML_CLOSE */ yytestcase(yyruleno==3);
+ /* (4) doc_opml ::= OPML_OPML_OPEN opml_body OPML_OPML_CLOSE */ yytestcase(yyruleno==4);
+ /* (5) opml_header ::= OPML_HEAD_OPEN opml_title OPML_HEAD_CLOSE */ yytestcase(yyruleno==5);
+ /* (6) opml_header ::= OPML_HEAD_OPEN OPML_HEAD_CLOSE */ yytestcase(yyruleno==6);
+ /* (7) opml_title ::= OPML_TITLE_OPEN OPML_TITLE_CLOSE */ yytestcase(yyruleno==7);
+ /* (8) opml_body ::= OPML_BODY_OPEN opml_outlines OPML_BODY_CLOSE */ yytestcase(yyruleno==8);
+ /* (9) opml_body ::= OPML_BODY_OPEN OPML_BODY_CLOSE */ yytestcase(yyruleno==9);
+ /* (10) opml_outlines ::= opml_outlines opml_outline */ yytestcase(yyruleno==10);
+ /* (11) opml_outlines ::= opml_outline (OPTIMIZED OUT) */ assert(yyruleno!=11);
+ /* (12) opml_outline ::= OPML_OUTLINE_OPEN OPML_OUTLINE_CLOSE */ yytestcase(yyruleno==12);
+ /* (13) opml_outline ::= OPML_OUTLINE_PREAMBLE OPML_OUTLINE_CLOSE */ yytestcase(yyruleno==13);
+ /* (14) opml_outline ::= OPML_OUTLINE_OPEN opml_outlines OPML_OUTLINE_CLOSE */ yytestcase(yyruleno==14);
+ /* (15) opml_outline ::= OPML_OUTLINE_METADATA opml_outlines OPML_OUTLINE_CLOSE */ yytestcase(yyruleno==15);
+ /* (16) opml_outline ::= OPML_OUTLINE_SELF_CLOSE */ yytestcase(yyruleno==16);
+ break;
+/********** End reduce actions ************************************************/
+ };
+ assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
+ yygoto = yyRuleInfo[yyruleno].lhs;
+ yysize = yyRuleInfo[yyruleno].nrhs;
+ yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
+ if( yyact <= YY_MAX_SHIFTREDUCE ){
+ if( yyact>YY_MAX_SHIFT ){
+ yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
+ }
+ yymsp -= yysize-1;
+ yypParser->yytos = yymsp;
+ yymsp->stateno = (YYACTIONTYPE)yyact;
+ yymsp->major = (YYCODETYPE)yygoto;
+ yyTraceShift(yypParser, yyact);
+ }else{
+ assert( yyact == YY_ACCEPT_ACTION );
+ yypParser->yytos -= yysize;
+ yy_accept(yypParser);
+ }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+#ifndef YYNOERRORRECOVERY
+static void yy_parse_failed(
+ yyParser *yypParser /* The parser */
+){
+ OPMLARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser fails */
+/************ Begin %parse_failure code ***************************************/
+
+ fprintf(stderr, "Parser failed to successfully parse.\n");
+/************ End %parse_failure code *****************************************/
+ OPMLARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+#endif /* YYNOERRORRECOVERY */
+
+/*
+** The following code executes when a syntax error first occurs.
+*/
+static void yy_syntax_error(
+ yyParser *yypParser, /* The parser */
+ int yymajor, /* The major type of the error token */
+ OPMLTOKENTYPE yyminor /* The minor type of the error token */
+){
+ OPMLARG_FETCH;
+#define TOKEN yyminor
+/************ Begin %syntax_error code ****************************************/
+
+ fprintf(stderr,"Parser syntax error.\n");
+#ifndef NDEBUG
+ fprintf(stderr,"Parser syntax error.\n");
+ int n = sizeof(yyTokenName) / sizeof(yyTokenName[0]);
+ for (int i = 0; i < n; ++i) {
+ int a = yy_find_shift_action(yypParser, (YYCODETYPE)i);
+ if (a < YYNSTATE + YYNRULE) {
+ fprintf(stderr,"expected token: %s\n", yyTokenName[i]);
+ }
+ }
+#endif
+/************ End %syntax_error code ******************************************/
+ OPMLARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void yy_accept(
+ yyParser *yypParser /* The parser */
+){
+ OPMLARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
+ }
+#endif
+#ifndef YYNOERRORRECOVERY
+ yypParser->yyerrcnt = -1;
+#endif
+ assert( yypParser->yytos==yypParser->yystack );
+ /* Here code is inserted which will be executed whenever the
+ ** parser accepts */
+/*********** Begin %parse_accept code *****************************************/
+
+// printf("parsing completed successfully!\n");
+/*********** End %parse_accept code *******************************************/
+ OPMLARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/* The main parser program.
+** The first argument is a pointer to a structure obtained from
+** "OPMLAlloc" which describes the current state of the parser.
+** The second argument is the major token number. The third is
+** the minor token. The fourth optional argument is whatever the
+** user wants (and specified in the grammar) and is available for
+** use by the action routines.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser (an opaque structure.)
+** <li> The major token number.
+** <li> The minor token number.
+** <li> An option argument of a grammar-specified type.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void OPML(
+ void *yyp, /* The parser */
+ int yymajor, /* The major token code number */
+ OPMLTOKENTYPE yyminor /* The value for the token */
+ OPMLARG_PDECL /* Optional %extra_argument parameter */
+){
+ YYMINORTYPE yyminorunion;
+ unsigned int yyact; /* The parser action. */
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+ int yyendofinput; /* True if we are at the end of input */
+#endif
+#ifdef YYERRORSYMBOL
+ int yyerrorhit = 0; /* True if yymajor has invoked an error */
+#endif
+ yyParser *yypParser; /* The parser */
+
+ yypParser = (yyParser*)yyp;
+ assert( yypParser->yytos!=0 );
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+ yyendofinput = (yymajor==0);
+#endif
+ OPMLARG_STORE;
+
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+
+ do{
+ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
+ if( yyact <= YY_MAX_SHIFTREDUCE ){
+ yy_shift(yypParser,yyact,yymajor,yyminor);
+#ifndef YYNOERRORRECOVERY
+ yypParser->yyerrcnt--;
+#endif
+ yymajor = YYNOCODE;
+ }else if( yyact <= YY_MAX_REDUCE ){
+ yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
+ }else{
+ assert( yyact == YY_ERROR_ACTION );
+ yyminorunion.yy0 = yyminor;
+#ifdef YYERRORSYMBOL
+ int yymx;
+#endif
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
+ }
+#endif
+#ifdef YYERRORSYMBOL
+ /* A syntax error has occurred.
+ ** The response to an error depends upon whether or not the
+ ** grammar defines an error token "ERROR".
+ **
+ ** This is what we do if the grammar does define ERROR:
+ **
+ ** * Call the %syntax_error function.
+ **
+ ** * Begin popping the stack until we enter a state where
+ ** it is legal to shift the error symbol, then shift
+ ** the error symbol.
+ **
+ ** * Set the error count to three.
+ **
+ ** * Begin accepting and shifting new tokens. No new error
+ ** processing will occur until three tokens have been
+ ** shifted successfully.
+ **
+ */
+ if( yypParser->yyerrcnt<0 ){
+ yy_syntax_error(yypParser,yymajor,yyminor);
+ }
+ yymx = yypParser->yytos->major;
+ if( yymx==YYERRORSYMBOL || yyerrorhit ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sDiscard input token %s\n",
+ yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+ yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
+ yymajor = YYNOCODE;
+ }else{
+ while( yypParser->yytos >= yypParser->yystack
+ && yymx != YYERRORSYMBOL
+ && (yyact = yy_find_reduce_action(
+ yypParser->yytos->stateno,
+ YYERRORSYMBOL)) >= YY_MIN_REDUCE
+ ){
+ yy_pop_parser_stack(yypParser);
+ }
+ if( yypParser->yytos < yypParser->yystack || yymajor==0 ){
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ yy_parse_failed(yypParser);
+#ifndef YYNOERRORRECOVERY
+ yypParser->yyerrcnt = -1;
+#endif
+ yymajor = YYNOCODE;
+ }else if( yymx!=YYERRORSYMBOL ){
+ yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
+ }
+ }
+ yypParser->yyerrcnt = 3;
+ yyerrorhit = 1;
+#elif defined(YYNOERRORRECOVERY)
+ /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
+ ** do any kind of error recovery. Instead, simply invoke the syntax
+ ** error routine and continue going as if nothing had happened.
+ **
+ ** Applications can set this macro (for example inside %include) if
+ ** they intend to abandon the parse upon the first syntax error seen.
+ */
+ yy_syntax_error(yypParser,yymajor, yyminor);
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ yymajor = YYNOCODE;
+
+#else /* YYERRORSYMBOL is not defined */
+ /* This is what we do if the grammar does not define ERROR:
+ **
+ ** * Report an error message, and throw away the input token.
+ **
+ ** * If the input token is $, then fail the parse.
+ **
+ ** As before, subsequent error messages are suppressed until
+ ** three input tokens have been successfully shifted.
+ */
+ if( yypParser->yyerrcnt<=0 ){
+ yy_syntax_error(yypParser,yymajor, yyminor);
+ }
+ yypParser->yyerrcnt = 3;
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ if( yyendofinput ){
+ yy_parse_failed(yypParser);
+#ifndef YYNOERRORRECOVERY
+ yypParser->yyerrcnt = -1;
+#endif
+ }
+ yymajor = YYNOCODE;
+#endif
+ }
+ }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack );
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ yyStackEntry *i;
+ char cDiv = '[';
+ fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
+ for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){
+ fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]);
+ cDiv = ' ';
+ }
+ fprintf(yyTraceFILE,"]\n");
+ }
+#endif
+ return;
+}
--- /dev/null
+#define OPML_XML 1
+#define OPML_WSNL 2
+#define OPML_OPML_OPEN 3
+#define OPML_OPML_CLOSE 4
+#define OPML_HEAD_OPEN 5
+#define OPML_HEAD_CLOSE 6
+#define OPML_TITLE_OPEN 7
+#define OPML_TITLE_CLOSE 8
+#define OPML_BODY_OPEN 9
+#define OPML_BODY_CLOSE 10
+#define OPML_OUTLINE_OPEN 11
+#define OPML_OUTLINE_CLOSE 12
+#define OPML_OUTLINE_PREAMBLE 13
+#define OPML_OUTLINE_METADATA 14
+#define OPML_OUTLINE_SELF_CLOSE 15
--- /dev/null
+State 0:
+ doc ::= * doc_xml
+ doc_xml ::= * OPML_XML doc_opml
+ doc_xml ::= * OPML_XML doc_opml OPML_WSNL
+
+ OPML_XML shift 10
+ doc accept
+ doc_xml shift 17
+
+State 1:
+ opml_outlines ::= * opml_outlines opml_outline
+ opml_outlines ::= * opml_outline
+ opml_outline ::= * OPML_OUTLINE_OPEN OPML_OUTLINE_CLOSE
+ opml_outline ::= OPML_OUTLINE_OPEN * OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_PREAMBLE OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_OPEN opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= OPML_OUTLINE_OPEN * opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_METADATA opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_SELF_CLOSE
+
+ OPML_OUTLINE_OPEN shift 1
+ OPML_OUTLINE_CLOSE shift-reduce 12 opml_outline ::= OPML_OUTLINE_OPEN OPML_OUTLINE_CLOSE
+ OPML_OUTLINE_PREAMBLE shift 14
+ OPML_OUTLINE_METADATA shift 3
+ OPML_OUTLINE_SELF_CLOSE shift-reduce 16 opml_outline ::= OPML_OUTLINE_SELF_CLOSE
+ opml_outlines shift 6
+ opml_outline shift 6 /* because opml_outline==opml_outlines */
+
+State 2:
+ opml_body ::= OPML_BODY_OPEN * opml_outlines OPML_BODY_CLOSE
+ opml_body ::= OPML_BODY_OPEN * OPML_BODY_CLOSE
+ opml_outlines ::= * opml_outlines opml_outline
+ opml_outlines ::= * opml_outline
+ opml_outline ::= * OPML_OUTLINE_OPEN OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_PREAMBLE OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_OPEN opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_METADATA opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_SELF_CLOSE
+
+ OPML_BODY_CLOSE shift-reduce 9 opml_body ::= OPML_BODY_OPEN OPML_BODY_CLOSE
+ OPML_OUTLINE_OPEN shift 1
+ OPML_OUTLINE_PREAMBLE shift 14
+ OPML_OUTLINE_METADATA shift 3
+ OPML_OUTLINE_SELF_CLOSE shift-reduce 16 opml_outline ::= OPML_OUTLINE_SELF_CLOSE
+ opml_outlines shift 7
+ opml_outline shift 7 /* because opml_outline==opml_outlines */
+
+State 3:
+ opml_outlines ::= * opml_outlines opml_outline
+ opml_outlines ::= * opml_outline
+ opml_outline ::= * OPML_OUTLINE_OPEN OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_PREAMBLE OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_OPEN opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_METADATA opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= OPML_OUTLINE_METADATA * opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_SELF_CLOSE
+
+ OPML_OUTLINE_OPEN shift 1
+ OPML_OUTLINE_PREAMBLE shift 14
+ OPML_OUTLINE_METADATA shift 3
+ OPML_OUTLINE_SELF_CLOSE shift-reduce 16 opml_outline ::= OPML_OUTLINE_SELF_CLOSE
+ opml_outlines shift 5
+ opml_outline shift 5 /* because opml_outline==opml_outlines */
+
+State 4:
+ doc_opml ::= OPML_OPML_OPEN * opml_header opml_body OPML_OPML_CLOSE
+ doc_opml ::= OPML_OPML_OPEN * opml_body OPML_OPML_CLOSE
+ opml_header ::= * OPML_HEAD_OPEN opml_title OPML_HEAD_CLOSE
+ opml_header ::= * OPML_HEAD_OPEN OPML_HEAD_CLOSE
+ opml_body ::= * OPML_BODY_OPEN opml_outlines OPML_BODY_CLOSE
+ opml_body ::= * OPML_BODY_OPEN OPML_BODY_CLOSE
+
+ OPML_HEAD_OPEN shift 8
+ OPML_BODY_OPEN shift 2
+ opml_header shift 9
+ opml_body shift 13
+
+State 5:
+ opml_outlines ::= opml_outlines * opml_outline
+ opml_outline ::= * OPML_OUTLINE_OPEN OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_PREAMBLE OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_OPEN opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_METADATA opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= OPML_OUTLINE_METADATA opml_outlines * OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_SELF_CLOSE
+
+ OPML_OUTLINE_OPEN shift 1
+ OPML_OUTLINE_CLOSE shift-reduce 15 opml_outline ::= OPML_OUTLINE_METADATA opml_outlines OPML_OUTLINE_CLOSE
+ OPML_OUTLINE_PREAMBLE shift 14
+ OPML_OUTLINE_METADATA shift 3
+ OPML_OUTLINE_SELF_CLOSE shift-reduce 16 opml_outline ::= OPML_OUTLINE_SELF_CLOSE
+ opml_outline shift-reduce 10 opml_outlines ::= opml_outlines opml_outline
+
+State 6:
+ opml_outlines ::= opml_outlines * opml_outline
+ opml_outline ::= * OPML_OUTLINE_OPEN OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_PREAMBLE OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_OPEN opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= OPML_OUTLINE_OPEN opml_outlines * OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_METADATA opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_SELF_CLOSE
+
+ OPML_OUTLINE_OPEN shift 1
+ OPML_OUTLINE_CLOSE shift-reduce 14 opml_outline ::= OPML_OUTLINE_OPEN opml_outlines OPML_OUTLINE_CLOSE
+ OPML_OUTLINE_PREAMBLE shift 14
+ OPML_OUTLINE_METADATA shift 3
+ OPML_OUTLINE_SELF_CLOSE shift-reduce 16 opml_outline ::= OPML_OUTLINE_SELF_CLOSE
+ opml_outline shift-reduce 10 opml_outlines ::= opml_outlines opml_outline
+
+State 7:
+ opml_body ::= OPML_BODY_OPEN opml_outlines * OPML_BODY_CLOSE
+ opml_outlines ::= opml_outlines * opml_outline
+ opml_outline ::= * OPML_OUTLINE_OPEN OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_PREAMBLE OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_OPEN opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_METADATA opml_outlines OPML_OUTLINE_CLOSE
+ opml_outline ::= * OPML_OUTLINE_SELF_CLOSE
+
+ OPML_BODY_CLOSE shift-reduce 8 opml_body ::= OPML_BODY_OPEN opml_outlines OPML_BODY_CLOSE
+ OPML_OUTLINE_OPEN shift 1
+ OPML_OUTLINE_PREAMBLE shift 14
+ OPML_OUTLINE_METADATA shift 3
+ OPML_OUTLINE_SELF_CLOSE shift-reduce 16 opml_outline ::= OPML_OUTLINE_SELF_CLOSE
+ opml_outline shift-reduce 10 opml_outlines ::= opml_outlines opml_outline
+
+State 8:
+ opml_header ::= OPML_HEAD_OPEN * opml_title OPML_HEAD_CLOSE
+ opml_header ::= OPML_HEAD_OPEN * OPML_HEAD_CLOSE
+ opml_title ::= * OPML_TITLE_OPEN OPML_TITLE_CLOSE
+
+ OPML_HEAD_CLOSE shift-reduce 6 opml_header ::= OPML_HEAD_OPEN OPML_HEAD_CLOSE
+ OPML_TITLE_OPEN shift 11
+ opml_title shift 12
+
+State 9:
+ doc_opml ::= OPML_OPML_OPEN opml_header * opml_body OPML_OPML_CLOSE
+ opml_body ::= * OPML_BODY_OPEN opml_outlines OPML_BODY_CLOSE
+ opml_body ::= * OPML_BODY_OPEN OPML_BODY_CLOSE
+
+ OPML_BODY_OPEN shift 2
+ opml_body shift 15
+
+State 10:
+ doc_xml ::= OPML_XML * doc_opml
+ doc_xml ::= OPML_XML * doc_opml OPML_WSNL
+ doc_opml ::= * OPML_OPML_OPEN opml_header opml_body OPML_OPML_CLOSE
+ doc_opml ::= * OPML_OPML_OPEN opml_body OPML_OPML_CLOSE
+
+ OPML_OPML_OPEN shift 4
+ doc_opml shift 16
+
+State 11:
+ opml_title ::= OPML_TITLE_OPEN * OPML_TITLE_CLOSE
+
+ OPML_TITLE_CLOSE shift-reduce 7 opml_title ::= OPML_TITLE_OPEN OPML_TITLE_CLOSE
+
+State 12:
+ opml_header ::= OPML_HEAD_OPEN opml_title * OPML_HEAD_CLOSE
+
+ OPML_HEAD_CLOSE shift-reduce 5 opml_header ::= OPML_HEAD_OPEN opml_title OPML_HEAD_CLOSE
+
+State 13:
+ doc_opml ::= OPML_OPML_OPEN opml_body * OPML_OPML_CLOSE
+
+ OPML_OPML_CLOSE shift-reduce 4 doc_opml ::= OPML_OPML_OPEN opml_body OPML_OPML_CLOSE
+
+State 14:
+ opml_outline ::= OPML_OUTLINE_PREAMBLE * OPML_OUTLINE_CLOSE
+
+ OPML_OUTLINE_CLOSE shift-reduce 13 opml_outline ::= OPML_OUTLINE_PREAMBLE OPML_OUTLINE_CLOSE
+
+State 15:
+ doc_opml ::= OPML_OPML_OPEN opml_header opml_body * OPML_OPML_CLOSE
+
+ OPML_OPML_CLOSE shift-reduce 3 doc_opml ::= OPML_OPML_OPEN opml_header opml_body OPML_OPML_CLOSE
+
+State 16:
+ (1) doc_xml ::= OPML_XML doc_opml *
+ doc_xml ::= OPML_XML doc_opml * OPML_WSNL
+
+ OPML_WSNL shift-reduce 2 doc_xml ::= OPML_XML doc_opml OPML_WSNL
+ {default} reduce 1 doc_xml ::= OPML_XML doc_opml
+
+State 17:
+ (0) doc ::= doc_xml *
+
+ $ reduce 0 doc ::= doc_xml
+
+----------------------------------------------------
+Symbols:
+ 0: $:
+ 1: OPML_XML
+ 2: OPML_WSNL
+ 3: OPML_OPML_OPEN
+ 4: OPML_OPML_CLOSE
+ 5: OPML_HEAD_OPEN
+ 6: OPML_HEAD_CLOSE
+ 7: OPML_TITLE_OPEN
+ 8: OPML_TITLE_CLOSE
+ 9: OPML_BODY_OPEN
+ 10: OPML_BODY_CLOSE
+ 11: OPML_OUTLINE_OPEN
+ 12: OPML_OUTLINE_CLOSE
+ 13: OPML_OUTLINE_PREAMBLE
+ 14: OPML_OUTLINE_METADATA
+ 15: OPML_OUTLINE_SELF_CLOSE
+ 16: error:
+ 17: doc: OPML_XML
+ 18: doc_xml: OPML_XML
+ 19: doc_opml: OPML_OPML_OPEN
+ 20: opml_header: OPML_HEAD_OPEN
+ 21: opml_body: OPML_BODY_OPEN
+ 22: opml_title: OPML_TITLE_OPEN
+ 23: opml_outlines: OPML_OUTLINE_OPEN OPML_OUTLINE_PREAMBLE OPML_OUTLINE_METADATA OPML_OUTLINE_SELF_CLOSE
+ 24: opml_outline: OPML_OUTLINE_OPEN OPML_OUTLINE_PREAMBLE OPML_OUTLINE_METADATA OPML_OUTLINE_SELF_CLOSE
--- /dev/null
+/**
+
+ MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+ @file opml-parser.c
+
+ @brief
+
+
+ @author Fletcher T. Penney
+ @bug
+
+**/
+
+/*
+
+ Copyright © 2016 - 2018 Fletcher T. Penney.
+
+
+ The `MultiMarkdown 6` project is released under the MIT License..
+
+ GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+
+ https://github.com/fletcher/MultiMarkdown-4/
+
+ MMD 4 is released under both the MIT License and GPL.
+
+
+ CuTest is released under the zlib/libpng license. See CuTest.c for the
+ text of the license.
+
+ uthash library:
+ Copyright (c) 2005-2016, Troy D. Hanson
+
+ Licensed under Revised BSD license
+
+ miniz library:
+ Copyright 2013-2014 RAD Game Tools and Valve Software
+ Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+
+ Licensed under the MIT license
+
+ argtable3 library:
+ Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ <sheitmann@users.sourceforge.net>
+ All rights reserved.
+
+ Licensed under the Revised BSD License
+
+
+ ## The MIT License ##
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+ ## Revised BSD License ##
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "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 <COPYRIGHT
+ HOLDER> 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.
+
+
+*/
+
+
+//
+// Language grammar here
+//
+
+%token_type { token * }
+
+%extra_argument { mmd_engine * engine }
+
+%name OPML
+
+
+// Start symbol
+doc ::= doc_xml(B). { engine->root = B; }
+
+doc_xml ::= OPML_XML doc_opml.
+doc_xml ::= OPML_XML doc_opml OPML_WSNL.
+
+doc_opml ::= OPML_OPML_OPEN opml_header opml_body OPML_OPML_CLOSE.
+doc_opml ::= OPML_OPML_OPEN opml_body OPML_OPML_CLOSE.
+
+opml_header ::= OPML_HEAD_OPEN opml_title OPML_HEAD_CLOSE.
+opml_header ::= OPML_HEAD_OPEN OPML_HEAD_CLOSE.
+
+opml_title ::= OPML_TITLE_OPEN OPML_TITLE_CLOSE.
+
+opml_body ::= OPML_BODY_OPEN opml_outlines OPML_BODY_CLOSE.
+opml_body ::= OPML_BODY_OPEN OPML_BODY_CLOSE.
+
+opml_outlines ::= opml_outlines opml_outline.
+opml_outlines ::= opml_outline.
+
+opml_outline ::= OPML_OUTLINE_OPEN OPML_OUTLINE_CLOSE.
+opml_outline ::= OPML_OUTLINE_PREAMBLE OPML_OUTLINE_CLOSE.
+
+opml_outline ::= OPML_OUTLINE_OPEN opml_outlines OPML_OUTLINE_CLOSE.
+opml_outline ::= OPML_OUTLINE_METADATA opml_outlines OPML_OUTLINE_CLOSE.
+
+opml_outline ::= OPML_OUTLINE_SELF_CLOSE.
+
+
+
+//
+// Additional Configuration
+//
+
+%include {
+ #include <assert.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ #include "libMultiMarkdown.h"
+ #include "mmd.h"
+ #include "parser.h"
+ #include "token.h"
+}
+
+
+// Improved error messages for debugging:
+// http://stackoverflow.com/questions/11705737/expected-token-using-lemon-parser-generator
+
+%syntax_error {
+ fprintf(stderr,"Parser syntax error.\n");
+#ifndef NDEBUG
+ fprintf(stderr,"Parser syntax error.\n");
+ int n = sizeof(yyTokenName) / sizeof(yyTokenName[0]);
+ for (int i = 0; i < n; ++i) {
+ int a = yy_find_shift_action(yypParser, (YYCODETYPE)i);
+ if (a < YYNSTATE + YYNRULE) {
+ fprintf(stderr,"expected token: %s\n", yyTokenName[i]);
+ }
+ }
+#endif
+}
+
+%parse_accept {
+// printf("parsing completed successfully!\n");
+}
+
+%parse_failure {
+ fprintf(stderr, "Parser failed to successfully parse.\n");
+}
--- /dev/null
+/**
+
+ MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+ @file opml-reader.c
+
+ @brief
+
+
+ @author Fletcher T. Penney
+ @bug
+
+**/
+
+/*
+
+ Copyright © 2016 - 2018 Fletcher T. Penney.
+
+
+ The `MultiMarkdown 6` project is released under the MIT License..
+
+ GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+
+ https://github.com/fletcher/MultiMarkdown-4/
+
+ MMD 4 is released under both the MIT License and GPL.
+
+
+ CuTest is released under the zlib/libpng license. See CuTest.c for the
+ text of the license.
+
+ uthash library:
+ Copyright (c) 2005-2016, Troy D. Hanson
+
+ Licensed under Revised BSD license
+
+ miniz library:
+ Copyright 2013-2014 RAD Game Tools and Valve Software
+ Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+
+ Licensed under the MIT license
+
+ argtable3 library:
+ Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ <sheitmann@users.sourceforge.net>
+ All rights reserved.
+
+ Licensed under the Revised BSD License
+
+
+ ## The MIT License ##
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+ ## Revised BSD License ##
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "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 <COPYRIGHT
+ HOLDER> 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 "mmd.h"
+#include "opml-reader.h"
+#include "opml-lexer.h"
+#include "opml-parser.h"
+#include "token.h"
+
+
+// Basic parser function declarations
+void * OPMLAlloc();
+void OPML();
+void OPMLFree();
+void OPMLTrace();
+
+
+#define print(x) d_string_append(out, x)
+#define print_const(x) d_string_append_c_array(out, x, sizeof(x) - 1)
+#define print_char(x) d_string_append_c(out, x)
+#define printf(...) d_string_append_printf(out, __VA_ARGS__)
+
+
+/// Create a token chain from source OPML string
+token * tokenize_opml_string(mmd_engine * e, size_t start, size_t len) {
+
+ // Create a scanner (for re2c)
+ Scanner s;
+ s.start = &e->dstr->str[start];
+ s.cur = s.start;
+
+ // Where do we stop parsing?
+ const char * stop = &e->dstr->str[start] + len;
+
+ int type; // TOKEN type
+ token * t; // Create tokens for incorporation
+
+ token * root = token_new(0, start, 0); // Store the final parse tree here
+
+ const char * last_stop = &e->dstr->str[start]; // Remember where last token ended
+
+ do {
+ // Scan for next token (type of 0 means there is nothing left);
+ type = opml_scan(&s, stop);
+
+ //if (type && s.start != last_stop) {
+ if (s.start != last_stop) {
+ // We skipped characters between tokens
+
+ if (type) {
+ // Create a default token type for the skipped characters
+ // t = token_new(TEXT_PLAIN, (size_t)(last_stop - e->dstr->str), (size_t)(s.start - last_stop));
+ } else {
+ if (stop > last_stop) {
+ // Source text ends without newline
+ // t = token_new(TEXT_PLAIN, (size_t)(last_stop - e->dstr->str), (size_t)(stop - last_stop));
+ }
+ }
+ } else if (type == 0 && stop > last_stop) {
+ // Source text ends without newline
+ // t = token_new(TEXT_PLAIN, (size_t)(last_stop - e->dstr->str), (size_t)(stop - last_stop));
+ }
+
+
+ switch (type) {
+ case 0:
+ // 0 means we finished with input
+ break;
+
+ case OPML_WSNL:
+ // Ignore for now
+ break;
+
+ default:
+ t = token_new(type, (size_t)(s.start - e->dstr->str), (size_t)(s.cur - s.start));
+ token_chain_append(root, t);
+ break;
+ }
+
+ // Remember where token ends to detect skipped characters
+ last_stop = s.cur;
+ } while (type != 0);
+
+ return root;
+}
+
+
+void print_opml_text(DString * out, const char * source, size_t start, size_t len) {
+ const char * s_start = &source[start];
+ const char * s_stop = &source[start + len];
+
+ char * c = (char *) s_start;
+
+ while (c < s_stop) {
+ switch (*c) {
+ case '&':
+ switch (*++c) {
+ case '#':
+ if (strncmp(c, "#10;", 4) == 0) {
+ print_char('\n');
+ c += 4;
+ continue;
+ }
+
+ if (strncmp(c, "#9;", 3) == 0) {
+ print_char('\t');
+ c += 3;
+ continue;
+ }
+
+ if (strncmp(c, "#13;", 4) == 0) {
+ print_char('\r');
+ c += 4;
+ continue;
+ }
+
+ break;
+
+ case 'a':
+ if (strncmp(c, "amp;", 4) == 0) {
+ print_char('&');
+ c += 4;
+ continue;
+ }
+
+ if (strncmp(c, "apos;", 5) == 0) {
+ print_char('\'');
+ c += 5;
+ continue;
+ }
+
+ break;
+
+ case 'l':
+ if (strncmp(c, "lt;", 3) == 0) {
+ print_char('<');
+ c += 3;
+ continue;
+ }
+
+ break;
+
+ case 'g':
+ if (strncmp(c, "gt;", 3) == 0) {
+ print_char('>');
+ c += 3;
+ continue;
+ }
+
+ break;
+
+ case 'q':
+ if (strncmp(c, "quot;", 5) == 0) {
+ print_char('"');
+ c += 5;
+ continue;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ print_char('&');
+ continue;
+ break;
+
+ default:
+ print_char(*c);
+ break;
+ }
+
+ c++;
+ }
+}
+
+
+
+void parse_opml_token_chain(mmd_engine * e, token * chain) {
+
+ void* pParser = OPMLAlloc (malloc); // Create a parser (for lemon)
+ token * walker = chain->next; // Walk the existing tree
+ token * remainder; // Hold unparsed tail of chain
+
+ #ifndef NDEBUG
+ OPMLTrace(stderr, "parser >>");
+ #endif
+
+ // Remove existing token tree
+ e->root = NULL;
+
+ while (walker != NULL) {
+ remainder = walker->next;
+
+ OPML(pParser, walker->type, walker, e);
+
+ walker = remainder;
+ }
+
+ // Signal finish to parser
+ #ifndef NDEBUG
+ fprintf(stderr, "\nFinish parse\n");
+ #endif
+ OPML(pParser, 0, NULL, e);
+
+ if (e->root) {
+ // Successful parse -- process to new source document
+ DString * final = d_string_new("");
+ DString * metadata = d_string_new("");
+ DString * out = final;
+
+ size_t header_level = 0;
+ size_t start, len;
+
+ walker = chain->next;
+
+ while (walker) {
+ switch (walker->type) {
+ case OPML_OUTLINE_PREAMBLE:
+ case OPML_OUTLINE_OPEN:
+ case OPML_OUTLINE_SELF_CLOSE:
+ header_level++;
+
+ // Advance over `<outline`
+ start = walker->start + 8;
+
+ start += scan_text(&(e->dstr->str[start]));
+ len = scan_double_quoted(&(e->dstr->str[start]));
+
+ if (strncmp(&(e->dstr->str[start + 1]), "(Untitled Preamble)", 19) != 0) {
+ if (out == metadata) {
+ print_opml_text(out, e->dstr->str, start + 1, len - 2);
+ print_const(":\t");
+ } else {
+ // Print header
+ for (int i = 0; i < header_level; ++i) {
+ print_char('#');
+ }
+
+ print_char(' ');
+
+ print_opml_text(out, e->dstr->str, start + 1, len - 2);
+
+ print_char(' ');
+
+ for (int i = 0; i < header_level; ++i) {
+ print_char('#');
+ }
+
+ print_const("\n");
+ }
+ }
+
+ // Print contents
+ start += len;
+ start += scan_note(&(e->dstr->str[start]));
+ len = scan_double_quoted(&(e->dstr->str[start]));
+
+ print_opml_text(out, e->dstr->str, start + 1, len - 2);
+
+ if (out == metadata) {
+ print_char('\n');
+ }
+
+ if (walker->type == OPML_OUTLINE_SELF_CLOSE) {
+ header_level--;
+ }
+
+ break;
+
+ case OPML_OUTLINE_METADATA:
+ // Now handle metadata
+ out = metadata;
+ header_level++;
+ break;
+
+ case OPML_OUTLINE_CLOSE:
+ header_level--;
+ break;
+
+ default:
+ break;
+ }
+
+ walker = walker->next;
+ }
+
+ // Append body to metadata
+ d_string_append_c_array(metadata, final->str, final->currentStringLength);
+
+ // TODO: How to safely swap the new text, given that we might not own e->dstr->str?
+
+ free(e->dstr->str);
+ e->dstr->str = metadata->str;
+ e->dstr->currentStringLength = metadata->currentStringLength;
+
+ d_string_free(metadata, false);
+ d_string_free(final, true);
+ } else {
+ // Unsuccessful parse -- free token chain
+ }
+
+ // Clean up token chain
+ token_tree_free(chain);
+
+ OPMLFree(pParser, free);
+}
+
+
+/// Create a token chain from source OPML string
+void mmd_convert_opml_string(mmd_engine * e, size_t start, size_t len) {
+ token * chain = tokenize_opml_string(e, start, len);
+ parse_opml_token_chain(e, chain);
+}
--- /dev/null
+/**
+
+ MultiMarkdown -- Lightweight markup processor to produce HTML, LaTeX, and more.
+
+ @file opml-reader.h
+
+ @brief
+
+
+ @author Fletcher T. Penney
+ @bug
+
+**/
+
+/*
+
+ Copyright © 2016 - 2018 Fletcher T. Penney.
+
+
+ The `MultiMarkdown 6` project is released under the MIT License..
+
+ GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
+
+ https://github.com/fletcher/MultiMarkdown-4/
+
+ MMD 4 is released under both the MIT License and GPL.
+
+
+ CuTest is released under the zlib/libpng license. See CuTest.c for the
+ text of the license.
+
+ uthash library:
+ Copyright (c) 2005-2016, Troy D. Hanson
+
+ Licensed under Revised BSD license
+
+ miniz library:
+ Copyright 2013-2014 RAD Game Tools and Valve Software
+ Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+
+ Licensed under the MIT license
+
+ argtable3 library:
+ Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
+ <sheitmann@users.sourceforge.net>
+ All rights reserved.
+
+ Licensed under the Revised BSD License
+
+
+ ## The MIT License ##
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+ ## Revised BSD License ##
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "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 <COPYRIGHT
+ HOLDER> 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 OPML_READER_MULTIMARKDOWN_H
+#define OPML_READER_MULTIMARKDOWN_H
+
+/// Create a token chain from source OPML string
+void mmd_convert_opml_string(mmd_engine * e, size_t start, size_t len);
+
+#endif
/* Here code is inserted which will be executed whenever the
** parser accepts */
/*********** Begin %parse_accept code *****************************************/
+
+// printf("parsing completed successfully!\n");
/*********** End %parse_accept code *******************************************/
ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
#endif
}
+%parse_accept {
+// printf("parsing completed successfully!\n");
+}
+
%parse_failure {
fprintf(stderr, "Parser failed to successfully parse.\n");
}
re2c -i -8 scanners.re > scanners.c
+re2c -i opml-lexer.re > opml-lexer.c
+
# It seems that some other versions of lemon don't create valid
# parsers?? Using the version included here works
# lemon -l parser.y
../../lemon/build/lemon -l parser.y
+../../lemon/build/lemon -l opml-parser.y
// argtable structs
struct arg_lit *a_help, *a_version, *a_compatibility, *a_nolabels, *a_batch,
*a_accept, *a_reject, *a_full, *a_snippet, *a_random, *a_meta,
- *a_notransclude, *a_nosmart;
+ *a_notransclude, *a_nosmart, *a_opml;
struct arg_str *a_format, *a_lang, *a_extract;
struct arg_file *a_file, *a_o;
struct arg_end *a_end;
a_nosmart = arg_lit0(NULL, "nosmart", "Disable smart typography"),
a_nolabels = arg_lit0(NULL, "nolabels", "Disable id attributes for headers"),
a_notransclude = arg_lit0(NULL, "notransclude", "Disable file transclusion"),
+ a_opml = arg_lit0(NULL, "opml", "Convert OPML source to plain text before processing"),
a_rem2 = arg_rem("", ""),
extensions &= ~EXT_TRANSCLUDE;
}
+ if (a_opml->count > 0) {
+ // Attempt to convert from OPML
+ extensions |= EXT_PARSE_OPML;
+ }
+
if (a_accept->count > 0) {
// Accept CriticMarkup changes
extensions |= EXT_CRITIC_ACCEPT | EXT_CRITIC;
my $file_ext = "html";
my $trail = "";
+my $source_ext = "text";
+
GetOptions (
"script=s" => \$script,
"testdir=s" => \$test_dir,
"flags=s" => \$flags,
"ext=s" => \$file_ext,
"trailflags=s" => \$trail,
+ "source_ext=s" => \$source_ext,
);
if($flag_version) {
TEST:
$test_dir =~ s/ /\\ /g;
-foreach my $testfile (glob "$test_dir/*.text") {
+foreach my $testfile (glob "$test_dir/*.$source_ext") {
my $testname = $testfile;
- $testname =~ s{.*/(.+)\.text$}{$1}i;
+ $testname =~ s{.*/(.+)\.$source_ext$}{$1}i;
print "$testname ... ";
# Look for a corresponding .html file for each .text file:
my $resultfile = $testfile;
- $resultfile =~ s{\.text$}{\.$file_ext}i;
+ $resultfile =~ s{\.$source_ext$}{\.$file_ext}i;
unless (-f $resultfile) {
print "'$resultfile' does not exist.\n\n";
$tests_failed++;