slweb

Једноставни генератор статичких веб страна
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување fda452c5bdb273b11a0eb709588d595016cee993
родитељ fdeb0b74d3b269cd9ff3558d1d376f3d4f937a18
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Sat, 16 Jan 2021 23:50:03 +0100

Added lists

Signed-off-by: Страхиња Радић <contact@strahinja.org>

Diffstat:
Mdefs.h | 3++-
Mexamples/includes/reference.slw | 102++++++++++++++++++++++++++++++-------------------------------------------------
Mindex.html | 2+-
Mslweb.1.in | 112++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mslweb.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 `&lt;p&gt;&lt;/p&gt;` tags. -{/li} -{li} -**Headings.** -A line starting with `#` followed by space will be put inside -`&lt;h?&gt;&lt;/h?&gt;`, 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 -`&lt;em&gt;&lt;/em&gt;`. Text inside -`\*\*double asterisks\*\*` will be put inside -`&lt;strong&gt;&lt;/strong&gt;`. -{/li} -{li} -**Backticks.** -Text inside `\`backticks\`` will be put inside -`&lt;code&gt;&lt;/code&gt;` (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 -`&lt;a href="https://example.com"&gt;A link&lt;/a&gt;`. -{/li} -{li} -**Line breaks.** -Space followed by a newline will be turned into `&lt;br /&gt;`. -{/li} -{/ul} +- **Paragraphs.** + Text surrounded by newlines will be put inside `&lt;p&gt;&lt;/p&gt;` tags. +- **Headings.** + A line starting with `#` followed by space will be put inside + `&lt;h?&gt;&lt;/h?&gt;`, where + `?` stands for 1-4, depending on the number of + hashtags. +- **Bold/italic (limited).** + Text inside `\*asterisks\*` or + `\_underlines\_` will be put inside + `&lt;em&gt;&lt;/em&gt;`. Text inside + `\*\*double asterisks\*\*` will be put inside + `&lt;strong&gt;&lt;/strong&gt;`. +- **Backticks.** + Text inside `\`backticks\`` will be put inside + `&lt;code&gt;&lt;/code&gt;` (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 + `&lt;a href="https://example.com"&gt;A link&lt;/a&gt;`. +- **Line breaks.** + Space followed by a newline will be turned into `&lt;br /&gt;`. **Directives** include: -{ul} -{li} -**Class divs.** -Directive `\{.myclass}\{/.myclass}` will be transformed into -`&lt;div class="myclass"&gt;&lt;/div&gt;`. -{/li} -{li} -**Id divs.** -Directive `\{#myid}\{/#myid}` will be transformed into -`&lt;div id="myid"&gt;&lt;/div&gt;`. -{/li} -{li} -**General tags.** -Directive `\{sometag}\{/sometag}` will be transformed into -`&lt;sometag&gt;&lt;/sometag&gt;`. -{/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 &ldquo;watermark&rdquo;.** -Directive `\{made-by}` is converted into a div containing the -&ldquo;watermark&rdquo; text and a link to the **slweb** home page. -{/li} -{/ul} +- **Class divs.** + Directive `\{.myclass}\{/.myclass}` will be transformed into + `&lt;div class="myclass"&gt;&lt;/div&gt;`. +- **Id divs.** + Directive `\{#myid}\{/#myid}` will be transformed into + `&lt;div id="myid"&gt;&lt;/div&gt;`. +- **General tags.** + Directive `\{sometag}\{/sometag}` will be transformed into + `&lt;sometag&gt;&lt;/sometag&gt;`. +- **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 &ldquo;watermark&rdquo;.** + Directive `\{made-by}` is converted into a div containing the + &ldquo;watermark&rdquo; 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 &lt;<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&lt;\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&lt;\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 +![Some title](/path/to/image.png) +.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&lt;\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 -![Some title](/path/to/image.png) +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