slweb

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

чување 4ed6157298ad191253c3cf001c2af8028f873858
родитељ 40f313838cc4401e13538737b735e846fedf9ecd
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Tue, 29 Dec 2020 12:46:17 +0100

Determine real pathname in links

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

Diffstat:
MTODO | 2+-
Mdefault.html.do | 2+-
Mdefault.o.do | 2+-
Dexamples/includes/footer.slw | 12------------
Aexamples/includes/inc/copy.slw | 2++
Aexamples/includes/inc/footer.slw | 13+++++++++++++
Rexamples/includes/header.slw -> examples/includes/inc/header.slw | 0
Mexamples/includes/index.slw | 4++--
Mexamples/links/index.slw | 3+++
Mexamples/links/style.css | 32++++++++++++++++++++++++++++++--
Mindex.html | 7++++---
Mindex.slw | 5+++--
Mslweb.c | 200+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mslweb.do | 2+-
измењених датотека: 14, додавања: 215(+), брисања: 71(-)

diff --git a/TODO b/TODO @@ -11,7 +11,7 @@ Migration to C checklist [x] Add {.class} processing [x] Add {#id} processing [x] Convert strncat token processing to individual token-based - [ ] -d support (determine real pathname in links) + [x] -d support (determine real pathname in links) [ ] Add {lsdir} [x] Add title: processing [ ] Update manpage diff --git a/default.html.do b/default.html.do @@ -1,3 +1,3 @@ -redo-ifchange $2.slw +redo-ifchange $2.slw slweb ./slweb $2.slw >$3 diff --git a/default.o.do b/default.o.do @@ -1,3 +1,3 @@ redo-ifchange $2.c -cc -o $3 -c $2.c +cc -g -Wall -o $3 -c $2.c diff --git a/examples/includes/footer.slw b/examples/includes/footer.slw @@ -1,12 +0,0 @@ -{footer} -{.left} -slweb v0.2.2-beta -{/.left} -{.center} -23 Nov 2020 -{/.center} -{.right} -SLWEB(1) -{/.right} -{/footer} - diff --git a/examples/includes/inc/copy.slw b/examples/includes/inc/copy.slw @@ -0,0 +1,2 @@ +{span}([Link to index](../index.html), from include) Copyright &copy; _someguy_{/span} + diff --git a/examples/includes/inc/footer.slw b/examples/includes/inc/footer.slw @@ -0,0 +1,13 @@ +{footer} +{.left} +slweb v0.2.2-beta +{/.left} +{.center} +{include "copy"} +23 Nov 2020 +{/.center} +{.right} +SLWEB(1) +{/.right} +{/footer} + diff --git a/examples/includes/header.slw b/examples/includes/inc/header.slw diff --git a/examples/includes/index.slw b/examples/includes/index.slw @@ -3,7 +3,7 @@ site-name: Includes site-description: Demonstration of the includes stylesheet: index.css --- -{include "header"} +{include "inc/header"} {main} {include "description"} @@ -19,5 +19,5 @@ stylesheet: index.css {include "bugs"} {/main} -{include "footer"} +{include "inc/footer"} diff --git a/examples/links/index.slw b/examples/links/index.slw @@ -14,6 +14,9 @@ Another [link, inline](https://suckless.org). You can also create and style a [=icon (link with icon)][2] +You can also make a [local link][3]. + [1]: https://strahinja.org [2]: https://materialdesignicons.com +[3]: ../../index.html diff --git a/examples/links/style.css b/examples/links/style.css @@ -6,7 +6,8 @@ html, body a { - line-height: 1em; + line-height: 24px; + height: 24px; padding: .5em 1em; border-radius: 10pt; background: #00f; @@ -21,6 +22,33 @@ a:hover a>svg { - vertical-align: middle; + vertical-align: text-bottom; + margin-bottom: -3px; + margin-right: .5ex; +} + +a>span +{ + display: inline-block; + font-family: serif; + transform: skewX(15deg); + font-style: oblique; +} + +a>span::after +{ + content: ' '; + display: block; + width: 0; + height: 2px; + background-color: #fff; + margin: 0 auto; + margin-top: -4px; + transition: all .25s ease; +} + +a:hover>span::after +{ + width: 100%; } diff --git a/index.html b/index.html @@ -17,8 +17,9 @@ transforms custom Markdown-like syntax into HTML.</p> <h2>Prerequisites</h2> -<p>Aside from the obvious (<strong>GCC</strong> and <strong>GNU make</strong>), slweb requires <strong>groff</strong>(1) -and <strong>gzip</strong>(1) to create and compress documentation. <strong>git</strong>(1) is, aside from +<p>Aside from the obvious (<strong>GCC</strong> and <strong>GNU make</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> <h2>Install</h2> @@ -114,7 +115,7 @@ this program. If not, see &lt;<a href="https://www.gnu.org/licenses">https://www <div id="git-log"> Previous commit: -index.slw b16dc97 2020-12-28 19:12:52 +0100 (Страхиња Радић) (HEAD -> redo-instead-of-make, origin/redo-instead-of-make) +index.slw 49a47b4 2020-12-29 12:46:17 +0100 (Страхиња Радић) (HEAD -> redo-instead-of-make) </div><!--git-log--> diff --git a/index.slw b/index.slw @@ -11,8 +11,9 @@ transforms custom Markdown-like syntax into HTML. ## Prerequisites -Aside from the obvious (**GCC** and **GNU make**), slweb requires **groff**(1) -and **gzip**(1) to create and compress documentation. **git**(1) is, aside from +Aside from the obvious (**GCC** and **GNU make**), 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}`. ## Install diff --git a/slweb.c b/slweb.c @@ -18,10 +18,13 @@ */ #include "defs.h" +#include <string.h> static size_t lineno = 0; static size_t colno = 1; -static uint8_t* filename = NULL; +static char* input_filename = NULL; +static char* input_dirname = NULL; +static char* basedir = NULL; static char* arg_zero = NULL; #define CHECKEXITNOMEM(ptr) if (!ptr) exit(error(ENOMEM, \ @@ -75,7 +78,7 @@ warning(int code, uint8_t* fmt, ...) } char* -substr(char* src, int start, int finish) +substr(const char* src, int start, int finish) { int len = strlen(src); if (finish > len) @@ -94,6 +97,12 @@ substr(char* src, int start, int finish) return result; } +BOOL +startswith(const char* s, const char* what) +{ + return s && what && !strcmp(substr(s, 0, strlen(what)), what); +} + uint8_t* get_value(KeyValue* list, size_t list_count, uint8_t* key, BOOL* seen) { @@ -117,6 +126,7 @@ get_value(KeyValue* list, size_t list_count, uint8_t* key, BOOL* seen) int set_basedir(char* arg, char** basedir) { + size_t basedir_len = 0; if (*basedir) free(*basedir); @@ -125,6 +135,9 @@ set_basedir(char* arg, char** basedir) CALLOC(*basedir, char, strlen(arg)+1) strcpy(*basedir, arg); + basedir_len = strlen(*basedir); + if (*(*basedir + basedir_len - 1) == '/') + *(*basedir + basedir_len - 1) = '\0'; return 0; } @@ -153,16 +166,16 @@ process_tag(uint8_t* token, FILE* output, KeyValue** macros, if (!strcmp((char*)token, "git-log") && !read_yaml_macros_and_links) /* {git-log} */ { - if (!filename) + if (!input_filename) return warning(1, (uint8_t*)"Cannot use 'git-log' in stdin\n"); - uint8_t* basename = NULL; - CALLOC(basename, uint8_t, u8_strlen(filename)) - uint8_t* slash = u8_strrchr(filename, (ucs4_t)'/'); + char* basename = NULL; + CALLOC(basename, char, strlen(input_filename)) + char* slash = strrchr(input_filename, '/'); if (slash) - u8_strncpy(basename, slash+1, u8_strlen(slash+1)); + strncpy(basename, slash+1, strlen(slash+1)); else - u8_strncpy(basename, filename, u8_strlen(filename)); + strncpy(basename, input_filename, strlen(input_filename)); fprintf(output, "<div id=\"git-log\">\nPrevious commit:\n"); uint8_t* command = NULL; @@ -217,46 +230,35 @@ process_tag(uint8_t* token, FILE* output, KeyValue** macros, if (!arg_zero) exit(error(EINVAL, (uint8_t*)"Invalid argument zero\n")); - if (!filename) + if (!input_filename) return warning(1, (uint8_t*)"Cannot use 'include' in stdin\n"); uint8_t* command = NULL; - uint8_t* slash = u8_strrchr(filename, (ucs4_t)'/'); uint8_t* ptoken = u8_strchr(token, (ucs4_t)' '); - uint8_t* include_filename = NULL; - uint8_t* pinclude_filename = NULL; - uint8_t* include_dirname = NULL; - uint8_t* pinclude_dirname = NULL; - size_t include_dirname_len = 0; - uint8_t* pfilename = filename; + char* include_filename = NULL; + char* pinclude_filename = NULL; + CALLOC(include_filename, char, BUFSIZE) + pinclude_filename = include_filename; + + *skip_eol = TRUE; if (!ptoken) - { - *skip_eol = TRUE; return warning(1, (uint8_t*)"Directive 'include' requires" " an argument\n"); - } + ptoken++; - CALLOC(include_filename, uint8_t, BUFSIZE) - CALLOC(include_dirname, uint8_t, BUFSIZE) - pinclude_dirname = include_dirname; - if (slash) - while (pfilename && *pfilename && pfilename != slash) - *pinclude_dirname++ = *pfilename++; - else - *pinclude_dirname++ = '.'; - *pinclude_dirname = '\0'; - include_dirname_len = u8_strlen(include_dirname); - u8_strncpy(include_filename, include_dirname, include_dirname_len); - *(include_filename + include_dirname_len) = '/'; - pinclude_filename = include_filename + include_dirname_len + 1; while (ptoken && *ptoken) if (*ptoken != '"') *pinclude_filename++ = *ptoken++; else ptoken++; + CALLOC(command, uint8_t, BUFSIZE) - u8_snprintf(command, BUFSIZE, "%s -b %s.slw", arg_zero, include_filename); + u8_snprintf(command, BUFSIZE, "%s -b -d %s %s/%s.slw", + arg_zero, + !strcmp(basedir, ".") ? input_dirname : basedir, + input_dirname, + include_filename); FILE* cmd_output = popen((char*)command, "r"); if (!cmd_output) @@ -281,9 +283,8 @@ process_tag(uint8_t* token, FILE* output, KeyValue** macros, pclose(cmd_output); free(cmd_output_line); - free(include_dirname); - free(include_filename); free(command); + free(include_filename); } *skip_eol = TRUE; } @@ -417,15 +418,83 @@ process_blockquote(FILE* output, BOOL end_tag) return 0; } +BOOL +url_is_local(char* url) +{ + return !(startswith(url, "http://") + || startswith(url, "https://") + || startswith(url, "ftp://") + || startswith(url, "ftps://") + || startswith(url, "mailto://")); +} + +int +get_realpath(char** realpath, char* relativeto, char* path) +{ + uint8_t* command = NULL; + FILE* cmd_output = NULL; + + CALLOC(command, uint8_t, BUFSIZE) + strcpy(*realpath, "."); + u8_snprintf(command, BUFSIZE, "realpath --relative-to=%s %s", + relativeto, path); + + cmd_output = popen((char*)command, "r"); + if (cmd_output) + { + uint8_t* cmd_output_line = NULL; + CALLOC(cmd_output_line, uint8_t, BUFSIZE) + while (!feof(cmd_output)) + { + if (!fgets((char*)cmd_output_line, BUFSIZE, cmd_output)) + continue; + + char* eol = strchr((char*)cmd_output_line, '\n'); + if (eol) + *eol = '\0'; + + strcpy(*realpath, (char*)cmd_output_line); + } + pclose(cmd_output); + free(cmd_output_line); + } + else + warning(1, (uint8_t*)"get_realpath: Cannot popen\n"); + + free(command); + + return 0; +} + int process_link(uint8_t* link_text, uint8_t* link_macro_body, uint8_t* link_id, KeyValue* links, size_t links_count, FILE* output) { - uint8_t* url = get_value(links, links_count, link_id, NULL); - fprintf(output, "<a href=\"%s\">%s%s</a>", + char* url = (char*)get_value(links, links_count, link_id, NULL); + char* link_dir = NULL; + BOOL local = FALSE; + BOOL dir_is_dot = FALSE; + + if (url) + local = url_is_local(url); + + if (local) + { + CALLOC(link_dir, char, BUFSIZE) + get_realpath(&link_dir, basedir, input_dirname ? input_dirname : "."); + dir_is_dot = !strcmp(link_dir, "."); + } + + fprintf(output, "<a href=\"%s%s%s\">%s%s</a>", + url && local && !dir_is_dot ? link_dir : "", + url && local && !dir_is_dot && url ? "/" : "", url ? (char*)url : "", link_macro_body ? (char*)link_macro_body : "", link_text); + + if (local) + free(link_dir); + return 0; } @@ -433,9 +502,30 @@ int process_inline_link(uint8_t* link_text, uint8_t* link_macro_body, uint8_t* link_url, FILE* output) { - fprintf(output, "<a href=\"%s\">%s%s</a>", - link_url, link_macro_body ? (char*)link_macro_body : "", + char* link_dir = NULL; + BOOL local = FALSE; + BOOL dir_is_dot = FALSE; + + if (link_url) + local = url_is_local((char*)link_url); + + if (local) + { + CALLOC(link_dir, char, BUFSIZE) + get_realpath(&link_dir, basedir, input_dirname ? input_dirname : "."); + dir_is_dot = !strcmp(link_dir, "."); + } + + fprintf(output, "<a href=\"%s%s%s\">%s%s</a>", + link_url && local && !dir_is_dot ? link_dir : "", + link_url && local && !dir_is_dot && link_url ? "/" : "", + link_url ? (char*)link_url : "", + link_macro_body ? (char*)link_macro_body : "", link_text); + + if (local) + free(link_dir); + return 0; } @@ -504,7 +594,6 @@ process_text_token(ULONG* state, int begin_html_and_head(FILE* output, KeyValue* vars, size_t vars_count) { - KeyValue* pvars = vars; uint8_t* site_name = get_value(vars, vars_count, (uint8_t*)"site-name", NULL); uint8_t* site_desc = get_value(vars, vars_count, (uint8_t*)"site-desc", NULL); @@ -612,7 +701,7 @@ slweb_parse(uint8_t* buffer, FILE* output, { uint8_t* eol = u8_strchr(pbuffer, (ucs4_t)'\n'); if (!eol) - continue; + break; pline = line; while (pbuffer != eol) @@ -1542,7 +1631,6 @@ main(int argc, char** argv) char* arg; Command cmd = CMD_NONE; BOOL body_only = FALSE; - char* basedir = NULL; CALLOC(basedir, char, 2) *basedir = '.'; @@ -1615,7 +1703,7 @@ main(int argc, char** argv) return result; } else - filename = (uint8_t*)arg; + input_filename = arg; cmd = CMD_NONE; } } @@ -1629,18 +1717,38 @@ main(int argc, char** argv) FILE* input = NULL; FILE* output = stdout; uint8_t* buffer = NULL; + char* slash = NULL; - if (filename) + if (input_filename) { struct stat fs; - input = fopen((char*)filename, "r"); + input = fopen((char*)input_filename, "r"); if (!input) - return error(ENOENT, (uint8_t*)"No such file: %s\n", filename); + return error(ENOENT, (uint8_t*)"No such file: %s\n", input_filename); fstat(fileno(input), &fs); CALLOC(buffer, uint8_t, fs.st_size) fread((void*)buffer, sizeof(char), fs.st_size, input); + + slash = strrchr(input_filename, '/'); + if (slash) + { + CALLOC(input_dirname, char, BUFSIZE) + char* pinput_dirname = input_dirname; + char* pinput_filename = input_filename; + while (pinput_filename && *pinput_filename + && pinput_filename != slash) + *pinput_dirname++ = *pinput_filename++; + } + else + { + CALLOC(input_dirname, char, 2) + *input_dirname = '.'; + } + + if (!strcmp(basedir, ".")) + strcpy(basedir, input_dirname); } else { diff --git a/slweb.do b/slweb.do @@ -1,3 +1,3 @@ redo-ifchange slweb.o slweb.c defs.h -cc -o $3 slweb.o -Wall -lunistring +cc -g -Wall -o $3 slweb.o -lunistring