чување fda452c5bdb273b11a0eb709588d595016cee993
родитељ fdeb0b74d3b269cd9ff3558d1d376f3d4f937a18
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Sat, 16 Jan 2021 23:50:03 +0100
Added lists
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | defs.h | | | 3 | ++- |
| M | examples/includes/reference.slw | | | 102 | ++++++++++++++++++++++++++++++------------------------------------------------- |
| M | index.html | | | 2 | +- |
| M | slweb.1.in | | | 112 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------- |
| M | slweb.c | | | 199 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------- |
измењених датотека: 5, додавања: 289(+), брисања: 129(-)
diff --git a/defs.h b/defs.h
@@ -38,7 +38,7 @@
#include <uniwidth.h>
#define PROGRAMNAME "slweb"
-#define VERSION "0.3.4"
+#define VERSION "0.3.5"
#define COPYRIGHTYEAR "2020, 2021"
#define BUFSIZE 1024
@@ -100,6 +100,7 @@ const ULONG ST_MACRO_BODY = 1 << 16;
const ULONG ST_CSV_BODY = 1 << 17;
const ULONG ST_HTML_TAG = 1 << 18;
const ULONG ST_KBD = 1 << 19;
+const ULONG ST_LIST = 1 << 20;
const UBYTE ST_CS_NONE = 0;
const UBYTE ST_CS_HEADER = 1;
diff --git a/examples/includes/reference.slw b/examples/includes/reference.slw
@@ -3,72 +3,46 @@
Files processed by **slweb** are using a minimal subset of Markdown with added
directives. Supported **Markdown features** are:
-{ul}
-{li}
-**Paragraphs.**
-Text surrounded by newlines will be put inside `<p></p>` tags.
-{/li}
-{li}
-**Headings.**
-A line starting with `#` followed by space will be put inside
-`<h?></h?>`, where
-`?` stands for 1-4, depending on the number of
-hashtags.
-{/li}
-{li}
-**Bold/italic (limited).**
-Text inside `\*asterisks\*` or
-`\_underlines\_` will be put inside
-`<em></em>`. Text inside
-`\*\*double asterisks\*\*` will be put inside
-`<strong></strong>`.
-{/li}
-{li}
-**Backticks.**
-Text inside `\`backticks\`` will be put inside
-`<code></code>` (one per line, both backticks need to be on the same line).
-{/li}
-{li}
-**Links (limited).**
-The construct `\[A link](https://example.com)` will be converted into
-`<a href="https://example.com">A link</a>`.
-{/li}
-{li}
-**Line breaks.**
-Space followed by a newline will be turned into `<br />`.
-{/li}
-{/ul}
+- **Paragraphs.**
+ Text surrounded by newlines will be put inside `<p></p>` tags.
+- **Headings.**
+ A line starting with `#` followed by space will be put inside
+ `<h?></h?>`, where
+ `?` stands for 1-4, depending on the number of
+ hashtags.
+- **Bold/italic (limited).**
+ Text inside `\*asterisks\*` or
+ `\_underlines\_` will be put inside
+ `<em></em>`. Text inside
+ `\*\*double asterisks\*\*` will be put inside
+ `<strong></strong>`.
+- **Backticks.**
+ Text inside `\`backticks\`` will be put inside
+ `<code></code>` (one per line, both backticks need to be on the same line).
+- **Links (limited).**
+ The construct `\[A link](https://example.com)` will be converted into
+ `<a href="https://example.com">A link</a>`.
+- **Line breaks.**
+ Space followed by a newline will be turned into `<br />`.
**Directives** include:
-{ul}
-{li}
-**Class divs.**
-Directive `\{.myclass}\{/.myclass}` will be transformed into
-`<div class="myclass"></div>`.
-{/li}
-{li}
-**Id divs.**
-Directive `\{#myid}\{/#myid}` will be transformed into
-`<div id="myid"></div>`.
-{/li}
-{li}
-**General tags.**
-Directive `\{sometag}\{/sometag}` will be transformed into
-`<sometag></sometag>`.
-{/li}
-{li}
-**Includes.**
-Directive `\{include "somefile"}` will run
-`slweb -b` on _somefile.slw_ (related
-to the directory containing the file containing the directive) and include the
-resulting {abbr}HTML{/abbr}. Directive needs to start at the beginning of the line.
-{/li}
-{li}
-**Brand “watermark”.**
-Directive `\{made-by}` is converted into a div containing the
-“watermark” text and a link to the **slweb** home page.
-{/li}
-{/ul}
+- **Class divs.**
+ Directive `\{.myclass}\{/.myclass}` will be transformed into
+ `<div class="myclass"></div>`.
+- **Id divs.**
+ Directive `\{#myid}\{/#myid}` will be transformed into
+ `<div id="myid"></div>`.
+- **General tags.**
+ Directive `\{sometag}\{/sometag}` will be transformed into
+ `<sometag></sometag>`.
+- **Includes.**
+ Directive `\{include "somefile"}` will run
+ `slweb -b` on _somefile.slw_ (related
+ to the directory containing the file containing the directive) and include the
+ resulting {abbr}HTML{/abbr}. Directive needs to start at the beginning of the line.
+- **Brand “watermark”.**
+ Directive `\{made-by}` is converted into a div containing the
+ “watermark” text and a link to the **slweb** home page.
diff --git a/index.html b/index.html
@@ -123,7 +123,7 @@ this program. If not, see <<a href="https://www.gnu.org/licenses">https://www
<div id="git-log">
Previous commit:
-index.slw 1aeac69 2021-01-15 17:12:58 +0100 (Страхиња Радић) (HEAD -> master, origin/master, origin/HEAD)
+index.slw 1d57278 2021-01-16 23:50:45 +0100 (Страхиња Радић) (HEAD -> master, tag: v0.3.5)
</div><!--git-log-->
diff --git a/slweb.1.in b/slweb.1.in
@@ -91,15 +91,16 @@ are using a minimal subset of Markdown with added directives.
.
.SS Supported Markdown features
.
-.IP \[bu] 4
-.BR Paragraphs .
-Text surrounded by newlines will be put inside \fC<p></p>\fP tags.
+.IP \[bu]
+.BR Backticks .
+Text inside \fC`backticks`\fP will be put inside \fC<code></code>\fP. Text
+inside triple backticks (\fC```\fP) will be put inside \fC<pre></pre>\fP. Any
+\[lq]less-than\[rq] character will be converted to \fC<\fP.
.
.IP \[bu]
-.BR Headings .
-A line starting with \fC#\fP followed by space will be put inside
-\fC<h?></h?>\fP, where \fC?\fP stands for 1-4, depending on the number of
-hash signs.
+.BR Blockquotes .
+Starting the line with \fC>\fP will surround it with a \fC<blockquote>\fP tag.
+Multiple lines are supported.
.
.IP \[bu]
.BR Bold/italic .
@@ -109,10 +110,34 @@ underlines__\fP will be put inside \fC<strong></strong>\fP. \fC***More than
two*** of the ___same symbol___\fP should be avoided.
.
.IP \[bu]
-.BR Backticks .
-Text inside \fC`backticks`\fP will be put inside \fC<code></code>\fP. Text
-inside triple backticks (\fC```\fP) will be put inside \fC<pre></pre>\fP. Any
-\[lq]less-than\[rq] character will be converted to \fC<\fP.
+.BR Headings .
+A line starting with \fC#\fP followed by space will be put inside
+\fC<h?></h?>\fP, where \fC?\fP stands for 1-4, depending on the number of
+hash signs.
+.
+.IP \[bu]
+.BR Images .
+Similar to links (see
+.BR Links ),
+images can be added by using:
+.
+.CDS 8
+
+.CDE
+.
+.IP
+Which will produce:
+.
+.CDS 8
+<a href="/path/to/image.png" title="Some title"
+ class="image" target="_blank"><img src="/path/to/image.png"
+ alt="Some title" /></a>
+.CDE
+.
+.IP
+If the additional link is not desirable, it can be turned off by setting
+.B add-image-links
+to \[lq]0\[rq].
.
.IP \[bu]
.BR "Keyboard tags" .
@@ -121,9 +146,8 @@ with backticks, any \[lq]less-than\[rq] character will be converted to
\fC<\fP.
.
.IP \[bu]
-.BR Blockquotes .
-Starting the line with \fC>\fP will surround it with a \fC<blockquote>\fP tag.
-Multiple lines are supported.
+.BR "Line breaks" .
+Two spaces followed by a newline will become \fC<br />\fP.
.
.IP \[bu]
.BR Links .
@@ -176,30 +200,64 @@ outside of the \fC<span></span>\fP:
.CDE
.
.IP \[bu]
-.BR Images .
-Similar to links, images can be added by using:
+.BR Lists .
+Lines starting with a dash (\fC\-\fP) will start an unordered list (if used for
+the first time) and start a list item. Input:
.
.CDS 8
-
+Colors are:
+
+- Red
+- Green
+- Blue
+
+and so on.
.CDE
.
.IP
-Which will produce:
+will produce:
.
.CDS 8
-<a href="/path/to/image.png" title="Some title"
- class="image" target="_blank"><img src="/path/to/image.png"
- alt="Some title" /></a>
+<p>Colors are:</p>
+
+<ul>
+<li><p>Red
+</p></li>
+<li><p>Green
+</p></li>
+<li><p>Blue</p>
+</li></ul>
+<p>And so on.</p>
.CDE
.
.IP
-If the additional link is not desirable, it can be turned off by setting
-.B add-image-links
-to \[lq]0\[rq].
+Indenting a line after a blank line with four spaces will create a paragraph
+within the list item, otherwise it will end the list:
.
-.IP \[bu]
-.BR "Line breaks" .
-Two spaces followed by a newline will become \fC<br />\fP.
+.CDS 8
+- This is a text inside a list item.
+
+ Remarkably, this paragraph is as well.
+- This is already a second item.
+
+This is after the list.
+.CDE
+.
+.IP
+will produce:
+.
+.CDS 8
+<ul>
+<li><p>This is a text inside a list item.</p>
+<p>Remarkably, this paragraph is as well.
+</p></li>
+<li><p>This is already a second item.</p></li></ul>
+<p>This is after the list.</p>
+.CDE
+.
+.IP \[bu] 4
+.BR Paragraphs .
+Text surrounded by newlines will be put inside \fC<p></p>\fP tags.
.
.SS Directives
.
diff --git a/slweb.c b/slweb.c
@@ -165,7 +165,7 @@ set_basedir(char* arg, char** basedir, size_t* basedir_size)
REALLOC(*basedir, *basedir_size)
}
strncpy(*basedir, arg, *basedir_size-1);
- *(basedir + arg_len) = 0;
+ *(*basedir + arg_len) = 0;
basedir_len = strlen(*basedir);
if (*(*basedir + basedir_len - 1) == '/')
*(*basedir + basedir_len - 1) = 0;
@@ -670,6 +670,40 @@ process_include(uint8_t* token, FILE* output, BOOL read_yaml_macros_and_links)
}
int
+process_list_start(FILE* output)
+{
+ fprintf(output, "<ul>");
+ return 0;
+}
+
+int
+process_list_item_start(FILE* output)
+{
+ fprintf(output, "\n<li><p>");
+ state |= ST_PARA_OPEN;
+ return 0;
+}
+
+int
+process_list_item_end(FILE* output)
+{
+ if (state & ST_PARA_OPEN)
+ {
+ state &= ~ST_PARA_OPEN;
+ fprintf(output, "</p>");
+ }
+ fprintf(output, "</li>");
+ return 0;
+}
+
+int
+process_list_end(FILE* output)
+{
+ fprintf(output, "</ul>\n");
+ return 0;
+}
+
+int
filter_subdirs(const struct dirent* node)
{
if (!node || !strcmp(node->d_name, ".") || !strcmp(node->d_name, ".."))
@@ -1223,16 +1257,29 @@ process_image(uint8_t* image_text, uint8_t* image_id, FILE* output, BOOL add_lin
}
int
-process_line_start(BOOL first_line_in_doc,
+process_line_start(uint8_t* line, BOOL first_line_in_doc,
BOOL previous_line_blank, BOOL processed_start_of_line,
- BOOL read_yaml_macros_and_links, FILE* output,
+ BOOL read_yaml_macros_and_links, BOOL list_para,
+ BOOL list_item, FILE* output,
uint8_t** token,
uint8_t** ptoken)
{
if ((first_line_in_doc || previous_line_blank)
&& !processed_start_of_line
- && !(state & (ST_PRE | ST_BLOCKQUOTE)))
+ && !(state & (ST_BLOCKQUOTE | ST_PRE)))
{
+ if (state & ST_LIST)
+ {
+ if (!list_para)
+ {
+ state &= ~ST_LIST;
+ if (!read_yaml_macros_and_links)
+ {
+ process_list_item_end(output);
+ process_list_end(output);
+ }
+ }
+ }
if (!read_yaml_macros_and_links)
print_output(output, "<p>");
state |= ST_PARA_OPEN;
@@ -1241,23 +1288,25 @@ process_line_start(BOOL first_line_in_doc,
}
int
-process_text_token(BOOL first_line_in_doc,
+process_text_token(uint8_t* line, BOOL first_line_in_doc,
BOOL previous_line_blank,
BOOL processed_start_of_line,
- BOOL read_yaml_macros_and_links,
+ BOOL read_yaml_macros_and_links, BOOL list_para,
+ BOOL list_item,
FILE* output,
uint8_t** token,
uint8_t** ptoken,
BOOL add_enclosing_paragraph)
{
- if (!read_yaml_macros_and_links && !(state & ST_YAML))
+ if (!(state & ST_YAML))
{
if (add_enclosing_paragraph)
- process_line_start(first_line_in_doc, previous_line_blank,
+ process_line_start(line, first_line_in_doc, previous_line_blank,
processed_start_of_line, read_yaml_macros_and_links,
- output, token, ptoken);
+ list_para, list_item, output, token, ptoken);
**ptoken = 0;
- if (**token && !(state & ST_MACRO_BODY))
+ if (**token && !read_yaml_macros_and_links
+ && !(state & ST_MACRO_BODY))
print_output(output, "%s", *token);
}
**token = 0;
@@ -1353,6 +1402,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
BOOL previous_line_blank = FALSE;
BOOL processed_start_of_line = FALSE;
BOOL add_links = TRUE;
+ BOOL list_para = FALSE;
+ BOOL list_item = FALSE;
if (!buffer)
exit(error(1, (uint8_t*)"Empty buffer"));
@@ -1446,15 +1497,21 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
colno = 1;
processed_start_of_line = FALSE;
skip_eol = FALSE;
+ /*list_item = FALSE;*/
+ list_para = FALSE;
while (pline && *pline)
{
switch (*pline)
{
case '-':
- if (colno == 1
- && !(state & (ST_CODE | ST_MACRO_BODY | ST_PRE
- | ST_YAML_VAL ))
+ if (state & (ST_CODE | ST_MACRO_BODY | ST_PRE
+ | ST_YAML_VAL))
+ {
+ *ptoken++ = *pline++;
+ colno++;
+ }
+ else if (colno == 1
&& u8_strlen(pline) > 2
&& startswith((char*)pline, "---"))
{
@@ -1466,6 +1523,27 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
pline += 3;
colno += 3;
}
+ else if (colno == 1
+ && u8_strlen(pline) > 1
+ && *(pline+1) == ' ')
+ {
+ if (!read_yaml_macros_and_links)
+ {
+ if (!(state & ST_LIST))
+ process_list_start(output);
+ else
+ process_list_item_end(output);
+ process_list_item_start(output);
+ }
+
+ processed_start_of_line = TRUE;
+ skip_eol = FALSE;
+
+ state |= ST_LIST;
+
+ pline += 2;
+ colno += 2;
+ }
else
{
*ptoken++ = *pline++;
@@ -1558,10 +1636,11 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
else
{
/* Output existing text up to ` */
- process_text_token(first_line_in_doc,
+ process_text_token(line, first_line_in_doc,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
+ list_para, list_item,
output,
&token,
&ptoken,
@@ -1641,10 +1720,11 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
else
{
/* Output existing text up to __ */
- process_text_token(first_line_in_doc,
+ process_text_token(line, first_line_in_doc,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
+ list_para, list_item,
output,
&token,
&ptoken,
@@ -1683,10 +1763,11 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
else
{
/* Output existing text up to _ */
- process_text_token(first_line_in_doc,
+ process_text_token(line, first_line_in_doc,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
+ list_para, list_item,
output,
&token,
&ptoken,
@@ -1743,10 +1824,11 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
else
{
/* Output existing text up to * */
- process_text_token(first_line_in_doc,
+ process_text_token(line, first_line_in_doc,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
+ list_para, list_item,
output,
&token,
&ptoken,
@@ -1785,10 +1867,11 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
else
{
/* Output existing text up to * */
- process_text_token(first_line_in_doc,
+ process_text_token(line, first_line_in_doc,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
+ list_para, list_item,
output,
&token,
&ptoken,
@@ -1807,13 +1890,34 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
break;
case ' ':
- if (state & ST_MACRO_BODY)
+ if (state & (ST_CODE | ST_MACRO_BODY | ST_PRE
+ | ST_YAML_VAL))
{
*ptoken++ = *pline++;
colno++;
break;
}
+ if (colno == 1
+ && u8_strlen(pline) > 1
+ && startswith((char*)pline, " "))
+ {
+ list_para = TRUE;
+ process_text_token(line, first_line_in_doc,
+ previous_line_blank,
+ processed_start_of_line,
+ read_yaml_macros_and_links,
+ list_para, list_item,
+ output,
+ &token,
+ &ptoken,
+ TRUE);
+ processed_start_of_line = TRUE;
+ pline += 4;
+ colno += 4;
+ break;
+ }
+
if (u8_strlen(pline) == 2
&& *(pline+1) == ' ')
{
@@ -1879,10 +1983,11 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
else
{
/* Output existing text up to { */
- process_text_token(first_line_in_doc,
+ process_text_token(line, first_line_in_doc,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
+ list_para, list_item,
output,
&token,
&ptoken,
@@ -1916,22 +2021,26 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
break;
case '}':
- if (state & (ST_CODE | ST_PRE | ST_HEADING | ST_YAML_VAL))
+ if (state & (ST_CODE | ST_PRE | ST_HEADING | ST_YAML
+ | ST_YAML_VAL))
{
*ptoken++ = *pline++;
colno++;
break;
}
- state &= ~ST_TAG;
- *ptoken = 0;
+ if (state & ST_TAG)
+ {
+ state &= ~ST_TAG;
+ *ptoken = 0;
- process_tag(token, output, read_yaml_macros_and_links,
- &skip_eol, end_tag);
+ process_tag(token, output, read_yaml_macros_and_links,
+ &skip_eol, end_tag);
- *token = 0;
- ptoken = token;
- end_tag = FALSE;
+ *token = 0;
+ ptoken = token;
+ end_tag = FALSE;
+ }
pline++;
colno++;
@@ -1970,10 +2079,11 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
else
{
/* Output existing text up to || */
- process_text_token(first_line_in_doc,
+ process_text_token(line, first_line_in_doc,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
+ list_para, list_item,
output,
&token,
&ptoken,
@@ -2118,10 +2228,11 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
if (*token)
/* Output existing text up to [ */
- process_text_token(first_line_in_doc,
+ process_text_token(line, first_line_in_doc,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
+ list_para, list_item,
output,
&token,
&ptoken,
@@ -2390,23 +2501,39 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only,
heading_level = 0;
}
else
- process_text_token(first_line_in_doc,
+ process_text_token(line, first_line_in_doc,
previous_line_blank,
processed_start_of_line,
read_yaml_macros_and_links,
+ list_para, list_item,
output,
&token,
&ptoken,
TRUE);
}
- if ((state & ST_PARA_OPEN)
- && !(state & (ST_PRE | ST_LINK_SECOND_ARG))
+ if (!(state & (ST_PRE | ST_LINK_SECOND_ARG))
&& (!*pbuffer || *pbuffer == '\n'))
{
- if (!read_yaml_macros_and_links)
- print_output(output, "</p>");
- state &= ~ST_PARA_OPEN;
+ if (state & ST_PARA_OPEN)
+ {
+ if (!read_yaml_macros_and_links)
+ print_output(output, "</p>");
+ if (state & ST_LIST)
+ skip_eol = TRUE;
+ state &= ~ST_PARA_OPEN;
+ }
+
+ if (!*pbuffer && (state & ST_LIST))
+ {
+ if (!read_yaml_macros_and_links)
+ {
+ process_list_item_end(output);
+ process_list_end(output);
+ }
+ state &= ~ST_LIST;
+ }
+
}
if (state & ST_BLOCKQUOTE