From: Fletcher T. Penney Date: Tue, 7 Aug 2018 00:10:35 +0000 (-0500) Subject: ADDED: Add opml option to read for MultiMarkdown OPML files X-Git-Tag: 6.4.0^2~7 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a45c0051d0c8ff0f4d65beb9a700b0f658c7fc1d;p=multimarkdown ADDED: Add opml option to read for MultiMarkdown OPML files --- diff --git a/CMakeLists.txt b/CMakeLists.txt index d0baeff..7ff61ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,6 +194,9 @@ set(src_files 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 @@ -227,6 +230,9 @@ set(header_files 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 @@ -672,6 +678,20 @@ ADD_MMD_TEST(mmd-6-critic-accept "-a" CriticMarkup htmla) 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) diff --git a/Sources/libMultiMarkdown/include/libMultiMarkdown.h b/Sources/libMultiMarkdown/include/libMultiMarkdown.h index 20fcbd7..cbeefee 100644 --- a/Sources/libMultiMarkdown/include/libMultiMarkdown.h +++ b/Sources/libMultiMarkdown/include/libMultiMarkdown.h @@ -555,6 +555,7 @@ enum parser_extensions { 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 }; diff --git a/Sources/libMultiMarkdown/mmd.c b/Sources/libMultiMarkdown/mmd.c index 6a42c46..b4b38d6 100644 --- a/Sources/libMultiMarkdown/mmd.c +++ b/Sources/libMultiMarkdown/mmd.c @@ -65,6 +65,7 @@ #include "mmd.h" #include "object_pool.h" #include "opendocument.h" +#include "opml-reader.h" #include "parser.h" #include "scanners.h" #include "stack.h" @@ -2187,6 +2188,10 @@ token * mmd_engine_parse_substring(mmd_engine * e, size_t byte_start, size_t byt 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); @@ -2759,6 +2764,11 @@ DString * mmd_engine_convert_to_data(mmd_engine * e, short format, const char * 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); diff --git a/Sources/libMultiMarkdown/opml-lexer.c b/Sources/libMultiMarkdown/opml-lexer.c new file mode 100644 index 0000000..4aa2f69 --- /dev/null +++ b/Sources/libMultiMarkdown/opml-lexer.c @@ -0,0 +1,1264 @@ +/* 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 + + 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 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 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 + +#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 ); } +} + +} diff --git a/Sources/libMultiMarkdown/opml-lexer.h b/Sources/libMultiMarkdown/opml-lexer.h new file mode 100644 index 0000000..482d67e --- /dev/null +++ b/Sources/libMultiMarkdown/opml-lexer.h @@ -0,0 +1,153 @@ +/** + + 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 + + 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 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 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 diff --git a/Sources/libMultiMarkdown/opml-lexer.re b/Sources/libMultiMarkdown/opml-lexer.re new file mode 100644 index 0000000..3146a2d --- /dev/null +++ b/Sources/libMultiMarkdown/opml-lexer.re @@ -0,0 +1,214 @@ +/** + + 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 + + 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 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 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 + +#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*; + + '\x00]* '>' { return OPML_XML; } + + '\x00]* '>' { return OPML_OPML_OPEN; } + '' { return OPML_OPML_CLOSE; } + + '\x00]* '>' { return OPML_HEAD_OPEN; } + '' { return OPML_HEAD_CLOSE; } + + '\x00]* '>' { return OPML_TITLE_OPEN; } + '' { return OPML_TITLE_CLOSE; } + + '\x00]* '>' { return OPML_BODY_OPEN; } + '' { return OPML_BODY_CLOSE; } + + '' { return OPML_OUTLINE_PREAMBLE; } + '' { return OPML_OUTLINE_METADATA; } + + + '\x00]* '/>' { return OPML_OUTLINE_SELF_CLOSE; } + '\x00]* '>' { return OPML_OUTLINE_OPEN; } + '' { 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; } +*/ +} diff --git a/Sources/libMultiMarkdown/opml-parser.c b/Sources/libMultiMarkdown/opml-parser.c new file mode 100644 index 0000000..f356bc6 --- /dev/null +++ b/Sources/libMultiMarkdown/opml-parser.c @@ -0,0 +1,1081 @@ +/* +** 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 +/************ Begin %include sections from the grammar ************************/ + + #include + #include + #include + + #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 +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: +**
    +**
  • A FILE* to which trace output should be written. +** If NULL, then tracing is turned off. +**
  • A prefix string written at the beginning of every +** line of trace output. If NULL, then tracing is +** turned off. +**
+** +** 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 %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 + j0 + ){ +#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 && iyytos--; +#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( yyNewStateyytos->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 + ** { ... } // User supplied code + ** #line + ** 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( yyrulenoYY_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: +**
    +**
  • A pointer to the parser (an opaque structure.) +**
  • The major token number. +**
  • The minor token number. +**
  • An option argument of a grammar-specified type. +**
+** +** 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; +} diff --git a/Sources/libMultiMarkdown/opml-parser.h b/Sources/libMultiMarkdown/opml-parser.h new file mode 100644 index 0000000..d974765 --- /dev/null +++ b/Sources/libMultiMarkdown/opml-parser.h @@ -0,0 +1,15 @@ +#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 diff --git a/Sources/libMultiMarkdown/opml-parser.out b/Sources/libMultiMarkdown/opml-parser.out new file mode 100644 index 0000000..7ce1075 --- /dev/null +++ b/Sources/libMultiMarkdown/opml-parser.out @@ -0,0 +1,215 @@ +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 diff --git a/Sources/libMultiMarkdown/opml-parser.y b/Sources/libMultiMarkdown/opml-parser.y new file mode 100644 index 0000000..ddd1165 --- /dev/null +++ b/Sources/libMultiMarkdown/opml-parser.y @@ -0,0 +1,185 @@ +/** + + 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 + + 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 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 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 + #include + #include + + #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"); +} diff --git a/Sources/libMultiMarkdown/opml-reader.c b/Sources/libMultiMarkdown/opml-reader.c new file mode 100644 index 0000000..db1385c --- /dev/null +++ b/Sources/libMultiMarkdown/opml-reader.c @@ -0,0 +1,418 @@ +/** + + 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 + + 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 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 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 +#include + +#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 `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); +} diff --git a/Sources/libMultiMarkdown/opml-reader.h b/Sources/libMultiMarkdown/opml-reader.h new file mode 100644 index 0000000..f867efa --- /dev/null +++ b/Sources/libMultiMarkdown/opml-reader.h @@ -0,0 +1,111 @@ +/** + + 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 + + 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 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 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 diff --git a/Sources/libMultiMarkdown/parser.c b/Sources/libMultiMarkdown/parser.c index cc5a01a..db335c5 100644 --- a/Sources/libMultiMarkdown/parser.c +++ b/Sources/libMultiMarkdown/parser.c @@ -1579,6 +1579,8 @@ static void yy_accept( /* 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 */ } diff --git a/Sources/libMultiMarkdown/parser.y b/Sources/libMultiMarkdown/parser.y index 870c01a..4bdf0e3 100644 --- a/Sources/libMultiMarkdown/parser.y +++ b/Sources/libMultiMarkdown/parser.y @@ -406,6 +406,10 @@ para ::= defs. #endif } +%parse_accept { +// printf("parsing completed successfully!\n"); +} + %parse_failure { fprintf(stderr, "Parser failed to successfully parse.\n"); } diff --git a/Sources/libMultiMarkdown/update b/Sources/libMultiMarkdown/update index 65a0d98..ec5482f 100755 --- a/Sources/libMultiMarkdown/update +++ b/Sources/libMultiMarkdown/update @@ -8,7 +8,10 @@ re2c -i -8 lexer.re > lexer.c 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 diff --git a/Sources/multimarkdown/main.c b/Sources/multimarkdown/main.c index 962814a..e6d2022 100644 --- a/Sources/multimarkdown/main.c +++ b/Sources/multimarkdown/main.c @@ -76,7 +76,7 @@ // 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; @@ -150,6 +150,7 @@ int main(int argc, char** argv) { 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("", ""), @@ -235,6 +236,11 @@ int main(int argc, char** argv) { 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; diff --git a/tests/MarkdownTest.pl b/tests/MarkdownTest.pl index fd4c87c..36b25d7 100755 --- a/tests/MarkdownTest.pl +++ b/tests/MarkdownTest.pl @@ -24,6 +24,8 @@ my $flags = ""; my $file_ext = "html"; my $trail = ""; +my $source_ext = "text"; + GetOptions ( "script=s" => \$script, "testdir=s" => \$test_dir, @@ -32,6 +34,7 @@ GetOptions ( "flags=s" => \$flags, "ext=s" => \$file_ext, "trailflags=s" => \$trail, + "source_ext=s" => \$source_ext, ); if($flag_version) { @@ -57,14 +60,14 @@ my $tests_failed = 0; 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++;