чување ee901138a0309940b74aaa60bb2f5d3760ddb2cc
родитељ 08b316044f620561ce493b73d18a8daa92ae8b52
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Sun, 24 Jan 2021 22:08:49 +0100
Added math mode
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
измењених датотека: 7, додавања: 353(+), брисања: 177(-)
diff --git a/defs.h b/defs.h
@@ -38,7 +38,7 @@
#include <uniwidth.h>
#define PROGRAMNAME "slweb"
-#define VERSION "0.3.5"
+#define VERSION "0.3.6"
#define COPYRIGHTYEAR "2020, 2021"
#define BUFSIZE 1024
@@ -105,6 +105,8 @@ typedef struct
#define ST_FOOTNOTE (1 << 22)
#define ST_FOOTNOTE_TEXT (1 << 23)
#define ST_INLINE_FOOTNOTE (1 << 24)
+#define ST_FORMULA (1 << 25)
+#define ST_DISPLAY_FORMULA (1 << 26)
#define ST_CS_NONE 0
#define ST_CS_HEADER 1
diff --git a/examples/math/all.do b/examples/math/all.do
@@ -0,0 +1,2 @@
+redo-ifchange index.html
+
diff --git a/examples/math/index.slw b/examples/math/index.slw
@@ -0,0 +1,14 @@
+---
+stylesheet: https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css
+---
+
+This is an inline formula: $\sum_{i=1}^n\frac1n\rightarrow0$.
+
+A display formula:
+$$\int_{j=0}^n\frac{(n-1)^3}{n^2}\,{\rm d}x.$$
+
+Some more:
+$$\begin{aligned}(a-b)(a+b)
+&=a^2-ab+ab-b^2\\
+&=a^2-b^2\end{aligned}$$
+
diff --git a/index.html b/index.html
@@ -8,6 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="generator" content="slweb" />
<link rel="stylesheet" href="index.css" />
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css" />
</head>
<body>
<main>
@@ -21,7 +22,8 @@ transforms custom Markdown-like syntax into HTML.</p>
<p>Aside from the obvious (a C compiler, by default <strong>GNU C</strong>), slweb requires
<strong>realpath</strong>(1) to determine paths in local links and <strong>groff</strong>(1) and
<strong>gzip</strong>(1) to create and compress documentation. <strong>git</strong>(1) is, aside from
-cloning the repository, required to use the directive <code>{git-log}</code>.</p>
+cloning the repository, required to use the directive <code>{git-log}</code>. <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>KaTeX</mtext></mrow><annotation encoding="application/x-tex">\KaTeX</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.89883em;vertical-align:-0.2155em;"></span><span class="mord text"><span class="mord textrm">K</span><span class="mspace" style="margin-right:-0.17em;"></span><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.68333em;"><span style="top:-2.904999em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord"><span class="mord textrm mtight sizing reset-size6 size3">A</span></span></span></span></span></span><span class="mspace" style="margin-right:-0.15em;"></span><span class="mord text"><span class="mord textrm">T</span><span class="mspace" style="margin-right:-0.1667em;"></span><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.46782999999999997em;"><span style="top:-2.7845em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord textrm">E</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.2155em;"><span></span></span></span></span><span class="mspace" style="margin-right:-0.125em;"></span><span class="mord textrm">X</span></span></span></span></span></span>
+(<a href="https://katex.org">https://katex.org</a>) is optionally used for math mode.</p>
<h2>Install</h2>
@@ -111,13 +113,13 @@ $ slweb index.slw > index.html
<h2>Bugs and limitations</h2>
-<p>Bugs can be reported using the <a href="https://github.com/Strahinja/slweb/issues">Github issue tracker</a>. See the manpage (<code>man
-slweb</code>) after installing <strong>slweb</strong> for more information.</p>
+<p>Bugs can be reported using the <a href="https://github.com/Strahinja/slweb/issues">Github issue tracker</a>. See the manpage
+(<code>man slweb</code>) after installing <strong>slweb</strong> for more information.</p>
<h2>License</h2>
-<p>slweb - Simple static website generator.<br />
+<p>slweb - Simple static website generator.<br />
Copyright (C) 2020, 2021 Страхиња Радић</p>
<p>This program is free software: you can redistribute it and/or modify it under
@@ -134,7 +136,7 @@ this program. If not, see <<a href="https://www.gnu.org/licenses">https://www
<div id="git-log">
Previous commit:
-index.slw 2062af3 2021-01-23 13:21:37 +0100 (Страхиња Радић) (HEAD -> master, origin/master, origin/HEAD)
+index.slw 5144730 2021-01-24 22:09:25 +0100 (Страхиња Радић) (HEAD -> master, tag: v0.3.6, origin/master, origin/HEAD)
</div><!--git-log-->
diff --git a/index.slw b/index.slw
@@ -2,6 +2,7 @@
site-name: slweb - Simple static website generator.
site-desc: Simple static website generator
stylesheet: index.css
+stylesheet: https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css
favicon-url: /slweb/favicon.ico
---
{main}
@@ -15,7 +16,8 @@ transforms custom Markdown-like syntax into HTML.
Aside from the obvious (a C compiler, by default **GNU C**), slweb requires
**realpath**(1) to determine paths in local links and **groff**(1) and
**gzip**(1) to create and compress documentation. **git**(1) is, aside from
-cloning the repository, required to use the directive `{git-log}`.
+cloning the repository, required to use the directive `{git-log}`. $\KaTeX$
+([https://katex.org][katex]) is optionally used for math mode.
## Install
@@ -25,7 +27,7 @@ $ cd slweb
$ su
```
-Then, if you have [apenwarr/redo][5]:
+Then, if you have [apenwarr/redo][aredo]:
```
# redo install
@@ -50,7 +52,7 @@ compared to **gcc**, but the compilation time is significantly shorter.
## Examples
-See the [`examples/`][1] directory in this repository.
+See the [`examples/`][examp] directory in this repository.
Given the file `index.slw` in the current directory:
@@ -100,13 +102,13 @@ file `index.html` contains:
## TODO (checklist)
-See the file [`TODO`][2] for more information.
+See the file [`TODO`][mtodo] for more information.
## Bugs and limitations
-Bugs can be reported using the [Github issue tracker][3]. See the manpage (`man
-slweb`) after installing **slweb** for more information.
+Bugs can be reported using the [Github issue tracker][issue]. See the manpage
+(`man slweb`) after installing **slweb** for more information.
## License
@@ -124,16 +126,17 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
-this program. If not, see <[https://www.gnu.org/licenses/][4]>.
+this program. If not, see <[https://www.gnu.org/licenses/][licen]>.
{git-log}
{made-by}
{/main}
-[1]: https://github.com/Strahinja/slweb/tree/master/examples
-[2]: https://github.com/Strahinja/slweb/tree/master/TODO
-[3]: https://github.com/Strahinja/slweb/issues
-[4]: https://www.gnu.org/licenses
-[5]: https://github.com/apenwarr/redo
+[examp]: https://github.com/Strahinja/slweb/tree/master/examples
+[mtodo]: https://github.com/Strahinja/slweb/tree/master/TODO
+[issue]: https://github.com/Strahinja/slweb/issues
+[licen]: https://www.gnu.org/licenses
+[aredo]: https://github.com/apenwarr/redo
+[katex]: https://katex.org
diff --git a/slweb.1.in b/slweb.1.in
@@ -403,6 +403,25 @@ will produce:
Text surrounded by newlines will be put inside \fC<p></p>\fP tags. See
.SM "KNOWN LIMITATIONS."
.
+.SS Math mode
+.
+.LP
+Math mode is supported through KaTeX. With
+.BR katex
+installed, anything between dollar signs (\fC$\fP) will be transformed into
+MathML and
+.SM HTML
+markup. To generate display math, use double dollar signs (\fC$$\fP). The text
+between the dollar signs in both cases should be LaTeX source code, and is
+passed to
+.BR katex .
+The KaTeX stylesheet is not included, and needs to be included separately
+through the
+.B stylesheet
+.SM YAML
+variable (see
+.BR stylesheet ).
+.
.SS Directives
.
.IP \[bu] 4
diff --git a/slweb.c b/slweb.c
@@ -18,6 +18,7 @@
*/
#include "defs.h"
+#include <stdint.h>
static size_t lineno = 0;
static size_t colno = 1;
@@ -59,6 +60,19 @@ static ULONG state = ST_NONE;
#define REALLOCARRAY(ptr, membtype, newcount) { ptr = realloc(ptr, \
newcount * sizeof(membtype)); CHECKEXITNOMEM(ptr) }
+#define CHECKCOPY(token, ptoken, token_size, pline) { \
+ if (ptoken - token + 1 > token_size) \
+ { \
+ token_size += BUFSIZE; \
+ REALLOC(token, token_size) \
+ } \
+ *ptoken++ = *pline++; }
+
+#define RESET_TOKEN(token, ptoken, token_size) { \
+ token_size = BUFSIZE; \
+ REALLOC(token, token_size) \
+ *token = 0; ptoken = token; }
+
int
version()
{
@@ -82,7 +96,8 @@ error(int code, uint8_t* fmt, ...)
va_start(args, fmt);
u8_vsnprintf(buf, sizeof(buf), (const char*)fmt, args);
va_end(args);
- fprintf(stderr, "%s:%s:%lu:%lu: %s\n", PROGRAMNAME, input_filename,
+ fprintf(stderr, "%s:%s:%lu:%lu: %s\n", PROGRAMNAME,
+ input_filename ? input_filename : "(stdin)",
lineno, colno, buf);
return code;
}
@@ -238,7 +253,7 @@ print_output(FILE* output, char* fmt, ...)
}
int
-print_command(uint8_t* command, FILE* output)
+print_command(uint8_t* command, FILE* output, BOOL strip_newlines)
{
if (!command)
exit(error(EINVAL, (uint8_t*)"print_command: Invalid argument"));
@@ -262,7 +277,8 @@ print_command(uint8_t* command, FILE* output)
if (eol)
*eol = 0;
- print_output(output, "%s\n", cmd_output_line);
+ print_output(output, "%s%s", cmd_output_line,
+ strip_newlines ? "" : "\n");
}
free(cmd_output_line);
pclose(cmd_output);
@@ -351,7 +367,7 @@ process_git_log(FILE* output)
"git log -1 --pretty=format:\"%s %%h %%ci (%%cn) %%d\""
" || echo \"(Not in a Git repository)\"",
basename);
- if (print_command(command, output))
+ if (print_command(command, output, FALSE))
{
print_output(output, "</div><!--git-log-->\n");
return error(1, (uint8_t*)"git-log: Cannot run git");
@@ -368,8 +384,8 @@ int
print_csv_row(FILE* output, uint8_t** csv_header, uint8_t** csv_register)
{
uint8_t* pcsv_template = csv_template;
- UBYTE csv_state = ST_CS_NONE;
- UBYTE num = 0;
+ UBYTE csv_state = ST_CS_NONE;
+ UBYTE num = 0;
while (*pcsv_template)
{
@@ -433,7 +449,7 @@ print_csv_row(FILE* output, uint8_t** csv_header, uint8_t** csv_register)
}
int
-process_csv(uint8_t* token, FILE* output, BOOL read_yaml_macros_and_links,
+process_csv(uint8_t* arg_token, FILE* output, BOOL read_yaml_macros_and_links,
BOOL end_tag)
{
if (read_yaml_macros_and_links)
@@ -443,24 +459,27 @@ process_csv(uint8_t* token, FILE* output, BOOL read_yaml_macros_and_links,
{
state &= ~ST_CSV_BODY;
- FILE* csv = fopen(csv_filename, "rt");
- size_t csv_lineno = 0;
- uint8_t* bufline = NULL;
- uint8_t* pbufline = NULL;
- uint8_t* token = NULL;
- uint8_t* ptoken = NULL;
- UBYTE csv_state = ST_CS_NONE;
+ FILE* csv = fopen(csv_filename, "rt");
+ size_t csv_lineno = 0;
+ uint8_t* bufline = NULL;
+ uint8_t* pbufline = NULL;
+ uint8_t* token = NULL;
+ uint8_t* ptoken = NULL;
+ size_t token_size = 0;
+ UBYTE csv_state = ST_CS_NONE;
uint8_t* csv_header[MAX_CSV_REGISTERS];
- UBYTE current_header = 0;
+ UBYTE current_header = 0;
uint8_t* csv_register[MAX_CSV_REGISTERS];
- UBYTE current_register = 0;
- uint8_t* csv_delimiter = get_value(vars, vars_count, (uint8_t*)"csv-delimiter", NULL);
+ UBYTE current_register = 0;
+ uint8_t* csv_delimiter = get_value(vars, vars_count,
+ (uint8_t*)"csv-delimiter", NULL);
if (!csv)
exit(error(ENOENT, (uint8_t*)"csv: No such file: %s", csv_filename));
CALLOC(bufline, uint8_t, BUFSIZE)
- CALLOC(token, uint8_t, BUFSIZE)
+ token_size = BUFSIZE;
+ CALLOC(token, uint8_t, token_size)
for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
CALLOC(csv_header[i], uint8_t, BUFSIZE)
for (UBYTE i = 0; i < MAX_CSV_REGISTERS; i++)
@@ -476,8 +495,7 @@ process_csv(uint8_t* token, FILE* output, BOOL read_yaml_macros_and_links,
*eol = 0;
pbufline = bufline;
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
current_register = 0;
while (*pbufline)
{
@@ -493,7 +511,7 @@ process_csv(uint8_t* token, FILE* output, BOOL read_yaml_macros_and_links,
case ';':
case ',':
if (csv_state & ST_CS_QUOTE)
- *ptoken++ = *pbufline;
+ CHECKCOPY(token, ptoken, token_size, pbufline)
else
{
*ptoken = 0;
@@ -509,14 +527,13 @@ process_csv(uint8_t* token, FILE* output, BOOL read_yaml_macros_and_links,
u8_strncpy(csv_header[current_header++], token,
BUFSIZE-1);
}
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
+ pbufline++;
}
- pbufline++;
break;
default:
if (csv_state & ST_CS_QUOTE)
- *ptoken++ = *pbufline++;
+ CHECKCOPY(token, ptoken, token_size, pbufline)
else
{
if (csv_delimiter && *pbufline == *csv_delimiter)
@@ -534,12 +551,11 @@ process_csv(uint8_t* token, FILE* output, BOOL read_yaml_macros_and_links,
u8_strncpy(csv_header[current_header++], token,
BUFSIZE-1);
}
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
pbufline++;
}
else
- *ptoken++ = *pbufline++;
+ CHECKCOPY(token, ptoken, token_size, pbufline)
}
}
}
@@ -555,8 +571,7 @@ process_csv(uint8_t* token, FILE* output, BOOL read_yaml_macros_and_links,
if (current_header < MAX_CSV_REGISTERS)
u8_strncpy(csv_header[current_header++], token, BUFSIZE-1);
}
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
if (csv_lineno > 0 && pbufline != bufline)
print_csv_row(output, csv_header, csv_register);
@@ -584,7 +599,7 @@ process_csv(uint8_t* token, FILE* output, BOOL read_yaml_macros_and_links,
state |= ST_CSV_BODY;
uint8_t* saveptr = NULL;
- uint8_t* args = u8_strtok(token, (uint8_t*)" ", &saveptr);
+ uint8_t* args = u8_strtok(arg_token, (uint8_t*)" ", &saveptr);
args = u8_strtok(NULL, (uint8_t*)" ", &saveptr);
if (!args)
exit(error(EINVAL, (uint8_t*)"csv: Arguments required"));
@@ -1430,7 +1445,7 @@ process_text_token(uint8_t* line, BOOL first_line_in_doc,
BOOL processed_start_of_line,
BOOL read_yaml_macros_and_links, BOOL list_para,
FILE* output, uint8_t** token,
- uint8_t** ptoken,
+ uint8_t** ptoken, size_t* token_size,
BOOL add_enclosing_paragraph)
{
if (!(state & ST_YAML))
@@ -1444,8 +1459,22 @@ process_text_token(uint8_t* line, BOOL first_line_in_doc,
&& !(state & ST_MACRO_BODY))
print_output(output, "%s", *token);
}
- **token = 0;
- *ptoken = *token;
+ RESET_TOKEN(*token, *ptoken, *token_size)
+ return 0;
+}
+
+int
+process_formula(FILE* output, uint8_t* token, BOOL display_formula)
+{
+ uint8_t* command = NULL;
+ CALLOC(command, uint8_t, BUFSIZE)
+
+ u8_snprintf(command, BUFSIZE-1, "katex <<<'%s%s'",
+ display_formula ? "\\displaystyle " : "",
+ token);
+ print_command(command, output, TRUE);
+
+ free(command);
return 0;
}
@@ -1567,6 +1596,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
size_t line_len = 0;
uint8_t* token = NULL;
uint8_t* ptoken = NULL;
+ size_t token_size = 0;
uint8_t* link_text = NULL;
size_t link_size = 0;
uint8_t* link_macro = NULL;
@@ -1575,6 +1605,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
BOOL first_line_in_doc = TRUE;
BOOL skip_change_first_line_in_doc = FALSE;
BOOL skip_eol = FALSE;
+ BOOL reset_token = TRUE;
BOOL previous_line_blank = FALSE;
BOOL processed_start_of_line = FALSE;
BOOL add_image_links = TRUE;
@@ -1607,6 +1638,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
add_footnote_div = var_add_footnote_div && *var_add_footnote_div == '1';
CALLOC(line, uint8_t, BUFSIZE)
+ token_size = BUFSIZE;
CALLOC(token, uint8_t, BUFSIZE)
CALLOC(link_macro, uint8_t, BUFSIZE)
@@ -1658,6 +1690,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
free(link);
}
+ RESET_TOKEN(token, ptoken, token_size)
+
do
{
uint8_t* eol = u8_strchr(pbuffer, (ucs4_t)'\n');
@@ -1671,8 +1705,6 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
*pline = 0;
pline = line;
line_len = u8_strlen(line);
- *token = 0;
- ptoken = token;
lineno++;
colno = 1;
@@ -1686,10 +1718,10 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
switch (*pline)
{
case '-':
- if (state & (ST_CODE | ST_MACRO_BODY | ST_PRE
- | ST_YAML_VAL))
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_MACRO_BODY | ST_PRE | ST_YAML_VAL))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
}
else if (colno == 1
@@ -1738,14 +1770,15 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
}
else
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
}
break;
case ':':
if (state & ST_YAML
- && !(state & (ST_CODE | ST_HEADING | ST_MACRO_BODY
- | ST_PRE | ST_TAG | ST_YAML_VAL))
+ && !(state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_HEADING | ST_MACRO_BODY | ST_PRE | ST_TAG
+ | ST_YAML_VAL))
&& read_yaml_macros_and_links)
{
*ptoken = 0;
@@ -1763,8 +1796,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
pvars->value_size = 0;
state |= ST_YAML_VAL;
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
pline++;
colno++;
@@ -1775,15 +1807,15 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
}
}
else {
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
}
break;
case '`':
- if (state & ST_MACRO_BODY)
+ if (state & (ST_DISPLAY_FORMULA | ST_FORMULA | ST_MACRO_BODY))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -1833,7 +1865,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
- list_para, output, &token, &ptoken, TRUE);
+ list_para, output, &token, &ptoken,
+ &token_size, TRUE);
processed_start_of_line = TRUE;
if (!read_yaml_macros_and_links
@@ -1848,14 +1881,15 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
}
else
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
}
break;
case '#':
if (colno == 1
- && !(state & (ST_CODE | ST_MACRO_BODY | ST_PRE | ST_YAML)))
+ && !(state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_MACRO_BODY | ST_PRE | ST_YAML)))
{
state |= ST_HEADING;
heading_level = 1;
@@ -1871,16 +1905,17 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
}
else
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
}
break;
case '_':
- if (state & (ST_CODE | ST_HTML_TAG
- | ST_MACRO_BODY | ST_PRE | ST_TAG | ST_YAML))
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_HTML_TAG | ST_MACRO_BODY | ST_PRE | ST_TAG
+ | ST_YAML))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -1913,7 +1948,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
- list_para, output, &token, &ptoken, TRUE);
+ list_para, output, &token, &ptoken,
+ &token_size, TRUE);
processed_start_of_line = TRUE;
if (!read_yaml_macros_and_links
@@ -1953,7 +1989,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
- list_para, output, &token, &ptoken, TRUE);
+ list_para, output, &token, &ptoken,
+ &token_size, TRUE);
processed_start_of_line = TRUE;
if (!read_yaml_macros_and_links
@@ -1968,10 +2005,10 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
break;
case '*':
- if (state & (ST_CODE | ST_HTML_TAG
- | ST_MACRO_BODY | ST_PRE | ST_YAML))
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_HTML_TAG | ST_MACRO_BODY | ST_PRE | ST_YAML))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2023,7 +2060,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
- list_para, output, &token, &ptoken, TRUE);
+ list_para, output, &token, &ptoken,
+ &token_size, TRUE);
processed_start_of_line = TRUE;
if (!read_yaml_macros_and_links
@@ -2064,7 +2102,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
- list_para, output, &token, &ptoken, TRUE);
+ list_para, output, &token, &ptoken,
+ &token_size, TRUE);
processed_start_of_line = TRUE;
if (!read_yaml_macros_and_links
@@ -2079,10 +2118,10 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
break;
case ' ':
- if (state & (ST_CODE | ST_MACRO_BODY | ST_PRE
- | ST_YAML_VAL))
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_MACRO_BODY | ST_PRE | ST_YAML_VAL))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2106,7 +2145,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
- list_para, output, &token, &ptoken, TRUE);
+ list_para, output, &token, &ptoken,
+ &token_size, TRUE);
processed_start_of_line = TRUE;
pline += 4;
colno += 4;
@@ -2128,21 +2168,20 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
*ptoken = 0;
u8_strncpy(link_macro, token, BUFSIZE-1);
*(link_macro + u8_strlen(token)) = 0;
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
state &= ~ST_LINK_MACRO;
}
else if (!(state & ST_HEADING
&& *(pline-1) == '#'))
- *ptoken++ = *pline;
- pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
case '{':
- if (state & (ST_CODE | ST_PRE | ST_YAML | ST_YAML_VAL))
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_HTML_TAG | ST_PRE | ST_YAML | ST_YAML_VAL))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2180,39 +2219,42 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
process_text_token(line, first_line_in_doc,
previous_line_blank, processed_start_of_line,
read_yaml_macros_and_links, list_para, output,
- &token, &ptoken, FALSE);
+ &token, &ptoken, &token_size, FALSE);
processed_start_of_line = TRUE;
}
state |= ST_TAG;
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
pline++;
colno++;
break;
case '/':
- if (state & (ST_CODE | ST_PRE | ST_HEADING | ST_YAML_VAL))
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_PRE | ST_HEADING | ST_YAML_VAL))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
if ((state & ST_TAG) && pline-1 && *(pline-1) == '{')
+ {
end_tag = TRUE;
+ pline++;
+ }
else
- *ptoken++ = *pline;
+ CHECKCOPY(token, ptoken, token_size, pline)
- pline++;
colno++;
break;
case '}':
- if (state & (ST_CODE | ST_PRE | ST_YAML | ST_YAML_VAL))
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_PRE | ST_YAML | ST_YAML_VAL))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2225,8 +2267,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
process_tag(token, output, read_yaml_macros_and_links,
&skip_eol, end_tag);
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
end_tag = FALSE;
}
@@ -2235,10 +2276,10 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
break;
case '|':
- if (state & (ST_CODE | ST_HTML_TAG
- | ST_PRE | ST_TAG | ST_YAML))
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_HTML_TAG | ST_PRE | ST_TAG | ST_YAML))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2271,7 +2312,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
- list_para, output, &token, &ptoken, TRUE);
+ list_para, output, &token, &ptoken,
+ &token_size, TRUE);
processed_start_of_line = TRUE;
if (!read_yaml_macros_and_links
@@ -2287,15 +2329,16 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
}
else
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
}
break;
case '<':
- if (read_yaml_macros_and_links)
+ if (read_yaml_macros_and_links
+ || (state & (ST_DISPLAY_FORMULA | ST_FORMULA)))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2313,19 +2356,17 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
}
state |= ST_HTML_TAG;
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
case '>':
if (state & ST_HTML_TAG)
- {
state &= ~ST_HTML_TAG;
- }
- if (state & ST_MACRO_BODY)
+ if (state & (ST_DISPLAY_FORMULA | ST_FORMULA | ST_MACRO_BODY))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2345,17 +2386,18 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
}
else
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
}
break;
case '!':
- if (state & (ST_CODE | ST_FOOTNOTE_TEXT | ST_HEADING
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_FOOTNOTE_TEXT | ST_HEADING
| ST_INLINE_FOOTNOTE | ST_LINK | ST_MACRO_BODY
| ST_PRE))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2367,11 +2409,10 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
process_text_token(line, first_line_in_doc,
previous_line_blank, processed_start_of_line,
read_yaml_macros_and_links, list_para, output,
- &token, &ptoken, FALSE);
+ &token, &ptoken, &token_size, FALSE);
processed_start_of_line = TRUE;
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
state |= ST_IMAGE;
pline += 2;
@@ -2379,16 +2420,17 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
}
else
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
}
break;
case '=':
- if (state & (ST_CODE | ST_MACRO_BODY | ST_PRE | ST_TAG))
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_MACRO_BODY | ST_PRE | ST_TAG))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2401,7 +2443,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
}
else
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
}
break;
@@ -2409,9 +2451,10 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
case '[':
pline_len = u8_strlen(pline);
- if (state & (ST_CODE | ST_HEADING | ST_MACRO_BODY | ST_PRE))
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_HEADING | ST_MACRO_BODY | ST_PRE))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2423,11 +2466,10 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
process_text_token(line, first_line_in_doc,
previous_line_blank, processed_start_of_line,
read_yaml_macros_and_links, list_para, output,
- &token, &ptoken, FALSE);
+ &token, &ptoken, &token_size, TRUE);
processed_start_of_line = TRUE;
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
state |= ST_FOOTNOTE;
pline += 2;
colno += 2;
@@ -2440,11 +2482,11 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
- list_para, output, &token, &ptoken, TRUE);
+ list_para, output, &token, &ptoken, &token_size,
+ TRUE);
processed_start_of_line = TRUE;
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
state |= ST_LINK;
*link_macro = 0;
@@ -2454,9 +2496,10 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
break;
case '(':
- if (state & (ST_CODE | ST_FOOTNOTE_TEXT | ST_HEADING
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_FOOTNOTE_TEXT | ST_HEADING
| ST_INLINE_FOOTNOTE | ST_MACRO_BODY | ST_PRE))
- *ptoken++ = *pline;
+ CHECKCOPY(token, ptoken, token_size, pline)
else if (state & ST_LINK)
{
uint8_t* tag = (uint8_t*)"<span>";
@@ -2473,14 +2516,21 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
}
state |= ST_LINK_SPAN;
+ pline++;
}
else
- *ptoken++ = *pline;
- pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
case ')':
+ if (state & (ST_DISPLAY_FORMULA | ST_FORMULA))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline)
+ colno++;
+ break;
+ }
+
if (state & ST_LINK_SPAN)
{
if (u8_strlen(pline) > 1
@@ -2500,6 +2550,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
}
state &= ~ST_LINK_SPAN;
}
+ pline++;
}
else if (state & (ST_LINK_SECOND_ARG | ST_IMAGE_SECOND_ARG))
{
@@ -2515,21 +2566,21 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
process_inline_image(link_text, token, output,
add_image_links);
}
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
state &= ~(ST_LINK | ST_LINK_SECOND_ARG
| ST_IMAGE | ST_IMAGE_SECOND_ARG);
+ pline++;
}
else
- *ptoken++ = *pline;
- pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
case ']':
- if (state & (ST_CODE | ST_HEADING | ST_MACRO_BODY | ST_PRE))
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_HEADING | ST_MACRO_BODY | ST_PRE))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2540,8 +2591,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
process_inline_footnote(token, read_yaml_macros_and_links,
output);
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
state &= ~ST_INLINE_FOOTNOTE;
pline++;
colno++;
@@ -2556,8 +2606,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
!footnote_definition && !read_yaml_macros_and_links,
output);
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
state &= ~ST_FOOTNOTE;
if (footnote_definition)
{
@@ -2575,8 +2624,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
get_value(macros, macros_count,
link_macro, NULL),
token, output);
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
state &= ~(ST_LINK | ST_LINK_SECOND_ARG);
pline++;
colno++;
@@ -2585,8 +2633,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
{
if (!read_yaml_macros_and_links)
process_image(link_text, token, output, add_image_links);
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
state &= ~(ST_IMAGE | ST_IMAGE_SECOND_ARG);
pline++;
colno++;
@@ -2615,8 +2662,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
pline++;
colno++;
}
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
state |= ST_LINK_SECOND_ARG;
break;
@@ -2640,15 +2686,14 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
*(link_text + token_len) = 0;
pline += 2;
colno += 2;
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
if (state & ST_LINK)
state |= ST_LINK_SECOND_ARG;
else
state |= ST_IMAGE_SECOND_ARG;
break;
default:
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
state &= ~(ST_LINK | ST_IMAGE);
break;
@@ -2657,10 +2702,11 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
break;
case '^':
- if (state & (ST_CODE | ST_FOOTNOTE_TEXT | ST_INLINE_FOOTNOTE
- | ST_PRE | ST_YAML))
+ if (state & (ST_CODE | ST_DISPLAY_FORMULA | ST_FORMULA
+ | ST_FOOTNOTE_TEXT | ST_INLINE_FOOTNOTE | ST_PRE
+ | ST_YAML))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2672,25 +2718,25 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
process_text_token(line, first_line_in_doc,
previous_line_blank, processed_start_of_line,
read_yaml_macros_and_links, list_para, output,
- &token, &ptoken, FALSE);
+ &token, &ptoken, &token_size, TRUE);
processed_start_of_line = TRUE;
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
state |= ST_INLINE_FOOTNOTE;
pline += 2;
colno += 2;
break;
}
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
case '\\':
- if (state & ST_MACRO_BODY)
+ if (state & (ST_DISPLAY_FORMULA | ST_FORMULA | ST_HTML_TAG
+ | ST_MACRO_BODY))
{
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
break;
}
@@ -2700,20 +2746,108 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
pline++;
colno++;
- *ptoken++ = *pline;
+ CHECKCOPY(token, ptoken, token_size, pline)
+ }
+ else
+ {
+ pline = NULL;
+ break;
}
- /* TODO: Cases? */
- pline++;
colno++;
break;
+ case '$':
+ if (state & (ST_CODE | ST_CSV_BODY | ST_PRE | ST_YAML))
+ {
+ CHECKCOPY(token, ptoken, token_size, pline)
+ colno++;
+ break;
+ }
+
+ if (u8_strlen(pline) > 1
+ && *(pline+1) == '$')
+ {
+ if (state & ST_FORMULA)
+ exit(error(1, (uint8_t*)"Display formula within an"
+ " open formula"));
+
+ if (!(state & ST_DISPLAY_FORMULA))
+ {
+ /* Output existing text up to $$ */
+ process_text_token(line, first_line_in_doc,
+ previous_line_blank,
+ processed_start_of_line,
+ read_yaml_macros_and_links,
+ list_para, output, &token, &ptoken, &token_size,
+ TRUE);
+ processed_start_of_line = TRUE;
+ }
+
+ state ^= ST_DISPLAY_FORMULA;
+
+ if (state & ST_DISPLAY_FORMULA)
+ reset_token = FALSE;
+ else
+ {
+ *ptoken = 0;
+
+ if (!read_yaml_macros_and_links)
+ process_formula(output, token, TRUE);
+
+ RESET_TOKEN(token, ptoken, token_size)
+ reset_token = TRUE;
+ }
+
+ pline += 2;
+ colno += 2;
+ }
+ else
+ {
+ if (state & ST_DISPLAY_FORMULA)
+ exit(error(1, (uint8_t*)"Formula within an open"
+ " display formula"));
+
+ if (!(state & ST_FORMULA))
+ {
+ /* Output existing text up to $ */
+ process_text_token(line, first_line_in_doc,
+ previous_line_blank,
+ processed_start_of_line,
+ read_yaml_macros_and_links,
+ list_para, output, &token, &ptoken, &token_size,
+ TRUE);
+ processed_start_of_line = TRUE;
+ }
+
+ state ^= ST_FORMULA;
+
+ if (state & ST_FORMULA)
+ reset_token = FALSE;
+ else
+ {
+ *ptoken = 0;
+
+ if (!read_yaml_macros_and_links)
+ process_formula(output, token, FALSE);
+
+ RESET_TOKEN(token, ptoken, token_size)
+ reset_token = TRUE;
+ }
+
+ pline++;
+ colno++;
+ }
+ break;
+
default:
- *ptoken++ = *pline++;
+ CHECKCOPY(token, ptoken, token_size, pline)
colno++;
}
}
+ *ptoken = 0;
+
if (*token && read_yaml_macros_and_links
&& (state & ST_YAML_VAL))
{
@@ -2722,7 +2856,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
CALLOC(pvars->value, uint8_t, pvars->value_size)
u8_strncpy(pvars->value, token, pvars->value_size-1);
}
- else
+ else if (!(state & (ST_DISPLAY_FORMULA | ST_FORMULA)))
{
if (*token)
{
@@ -2801,8 +2935,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
if (!read_yaml_macros_and_links)
process_heading(token, output, heading_level);
first_line_in_doc = FALSE;
- *token = 0;
- ptoken = token;
+ RESET_TOKEN(token, ptoken, token_size)
heading_level = 0;
}
else
@@ -2810,7 +2943,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
- list_para, output, &token, &ptoken, TRUE);
+ list_para, output, &token, &ptoken, &token_size,
+ TRUE);
}
if (!(state & (ST_PRE | ST_LINK_SECOND_ARG))
@@ -2883,8 +3017,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
| ST_LINK_SECOND_ARG)))
print_output(output, "\n");
- *token = 0;
- ptoken = token;
+ if (reset_token)
+ RESET_TOKEN(token, ptoken, token_size)
if (!skip_change_first_line_in_doc
&& !(state & ST_YAML))
@@ -3004,17 +3138,17 @@ main(int argc, char** argv)
if (cmd == CMD_VERSION)
return version();
- FILE* input = NULL;
- FILE* output = stdout;
- uint8_t* buffer = NULL;
+ FILE* input = NULL;
+ FILE* output = stdout;
+ uint8_t* buffer = NULL;
size_t buffer_size = 0;
if (input_filename)
read_file_into_buffer(&buffer, &buffer_size, input_filename, &input_dirname, &input);
else
{
- uint8_t* bufline = NULL;
- size_t buffer_len = 0;
+ uint8_t* bufline = NULL;
+ size_t buffer_len = 0;
size_t buffer_size = 0;
size_t bufline_len = 0;