Browse Source

Initial commit

Frans Bergman 6 months ago
commit
8c06fdfb1e

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+sites/tankernn.eu

+ 18 - 0
LICENSE

@@ -0,0 +1,18 @@
+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.
+

+ 4 - 0
README.md

@@ -0,0 +1,4 @@
+wesh
+====
+
+POSIX shell web framework loosely based on [werc](http://werc.cat-v.org/).

+ 9 - 0
bin/conf.sh

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+export SITE="${HTTP_HOST:-wesh.tankernn.eu}"
+export SITE_DIR="sites/$SITE"
+
+forbidden_uri_chars='[^a-zA-Z0-9_+\-\/\.,:]'
+export DIR_FILTER="s/\*$//; s,/+\./+,/,g; s,^\./,,; /\/[._][^\/]/d; /$forbidden_uri_chars/d; /index\.(md|html|txt|tpl)$/d; /(robots|sitemap)\.(txt|xml|gz)$/d; /_wesh\/?$/d; "
+export DIR_CLEAN=" s/\.(md|html|txt)$//; /^$/d; "
+

+ 56 - 0
bin/corehandlers.sh

@@ -0,0 +1,56 @@
+#!/bin/sh
+
+handler() {
+    case "$1" in
+        **.md)
+            bin/md2html.awk "$1"
+            ;;
+        **.tpl)
+            eval "$(bin/template.awk "$1")"
+            ;;
+        **)
+            cat "$1"
+            ;;
+    esac
+}
+
+handler_body_main() {
+    if [ -d "$SITE_DIR/$REQUEST_URI" ]; then
+        handler "$SITE_DIR/$REQUEST_URI/index.md"
+    elif [ -f "$SITE_DIR/$REQUEST_URI.md" ]; then
+            handler "$SITE_DIR/$REQUEST_URI.md"
+    fi
+}
+
+nav_tree() {
+    find "$SITE_DIR" |
+        sed -E -e "$DIR_FILTER s!^$SITE_DIR!!; $DIR_CLEAN" 2>&1 |
+        sort -u | awk -v req_path="$REQUEST_URI" -F/ '
+    function p(x, y, s) { for(i=0; i < x-y; i+=1) print s }
+    BEGIN { lNF=2; print "<ul>" }
+    {
+        d = ""
+        if(match($0, "/$"))
+            d = "/"
+        sub("/$", "") # Strip trailing / for dirs so NF is consistent
+
+        p(NF, lNF, "<li><ul>")
+        p(lNF, NF, "</ul></li>")
+        lNF = NF
+
+        bname = $NF d
+        path = $0 d
+        gsub(/[\-_]/, " ", bname)
+
+        # To avoid false matches add trailing / even for plain files to act as delimiter
+        pa = path
+        gsub(/[^\/]$/, "&/", pa)
+
+        if(index(req_path "/", pa) == 1)
+            print "<li><a href=\"" path "\" class=\"thisPage\">&raquo;<i> " bname "</i></a></li>"
+        else
+            print "<li><a href=\"" path "\">&rsaquo; " bname "</a></li>"
+    }
+    END { p(lNF, 2, "</ul></li>"); print "</ul>" }'
+}
+

+ 45 - 0
bin/lib.sh

@@ -0,0 +1,45 @@
+#!/bin/sh
+
+get_lib_file() {
+    if [ -f "sites/$SITE/_wesh/lib/$1" ]; then
+        echo "sites/$SITE/_wesh/lib/$1"
+    else
+        echo "lib/$1"
+    fi
+}
+
+static_file() {
+    printf "Content-Type: "
+    select_mime "$1"
+    echo
+    cat "$1"
+}
+
+select_mime() {
+    m='text/plain'
+    case "$1" in
+    *.css)
+        m='text/css'
+        ;;
+    *.ico)
+        m='image/x-icon'
+        ;;
+    *.png)
+        m='image/png'
+        ;;
+    *.jpg)
+        m='image/jpeg'
+        ;;
+    *.jpeg)
+        m='image/jpeg'
+        ;;
+    *.gif)
+        m='image/gif'
+        ;;
+    *.pdf)
+        m='application/pdf'
+        ;;
+    esac
+    echo $m
+}
+

+ 427 - 0
bin/md2html.awk

@@ -0,0 +1,427 @@
+#!/usr/bin/mawk -f
+#
+# by: Jesus Galan (yiyus) 2009
+#
+# Usage: md2html.awk file.md > file.html
+# See: http://4l77.com/src/md2html.awk
+
+function eschtml(t) {
+	gsub("&", "\\&amp;", t);
+	gsub("<", "\\&lt;", t);
+	return t;
+}
+
+function oprint(t){
+	if(nr == 0)
+		print t;
+	else
+		otext = otext "\n" t;
+}
+
+function subref(id){
+	for(; nr > 0 && sub("<<" id, ref[id], otext); nr--);
+	if(nr == 0 && otext) {
+		print otext;
+		otext = "";
+	}
+}
+
+function nextil(t) {
+	if(!match(t, /[`<&\[*_\\-]|(\!\[)/))
+		return t;
+	t1 = substr(t, 1, RSTART - 1);
+	tag = substr(t, RSTART, RLENGTH);
+	t2 = substr(t, RSTART + RLENGTH);
+	if(ilcode && tag != "`")
+		return eschtml(t1 tag) nextil(t2);
+	# Backslash escaping
+	if(tag == "\\"){
+		if(match(t2, /^[\\`*_{}\[\]()#+\-\.!]/)){
+			tag = substr(t2, 1, 1);
+			t2 = substr(t2, 2);
+		}
+		return t1 tag nextil(t2);
+	}
+	# Dashes
+	if(tag == "-"){
+		if(sub(/^-/, "", t2))
+			tag = "&#8212;";
+		return t1 tag nextil(t2);
+	}
+	# Inline Code
+	if(tag == "`"){
+		if(sub(/^`/, "", t2)){
+			if(!match(t2, /``/))
+				return t1 "&#8221;" nextil(t2);
+			ilcode2 = !ilcode2;
+		}
+		else if(ilcode2)
+			return t1 tag nextil(t2);
+		tag = "<code>";
+		if(ilcode){
+			t1 = eschtml(t1);
+			tag = "</code>";
+		}
+		ilcode = !ilcode;
+		return t1 tag nextil(t2);
+	}
+	if(tag == "<"){
+	# Autolinks
+		if(match(t2, /^[^ 	]+[\.@][^ 	]+>/)){
+			url = eschtml(substr(t2, 1, RLENGTH - 1));
+			t2 = substr(t2, RLENGTH + 1);
+			linktext = url;
+			if(match(url, /@/) && !match(url, /^mailto:/))
+				url = "mailto:" url;
+			return t1 "<a href=\"" url "\">" linktext "</a>" nextil(t2);
+		}
+	# Html tags
+		if(match(t2, /^[A-Za-z\/!][^>]*>/)){
+			tag = tag substr(t2, RSTART, RLENGTH);
+			t2 = substr(t2, RLENGTH + 1);
+			return t1 tag nextil(t2);
+		}
+		return t1 "&lt;" nextil(t2);
+	}
+	# Html special entities
+	if(tag == "&"){
+		if(match(t2, /^#?[A-Za-z0-9]+;/)){
+			tag = tag substr(t2, RSTART, RLENGTH);
+			t2 = substr(t2, RLENGTH + 1);
+			return t1 tag nextil(t2);
+		}
+		return t1 "&amp;" nextil(t2);
+	}
+	# Images
+	if(tag == "!["){
+		if(!match(t2, /(\[.*\])|(\(.*\))/))
+			return t1 tag nextil(t2);
+		match(t2, /^[^\]]*/);
+		alt = substr(t2, 1, RLENGTH);
+		t2 = substr(t2, RLENGTH + 2);
+		if(match(t2, /^\(/)){
+			# Inline
+			sub(/^\(/, "", t2);
+			match(t2, /^[^\)]+/);
+			url = eschtml(substr(t2, 1, RLENGTH));
+			t2 = substr(t2, RLENGTH + 2);
+			title = "";
+			if(match(url, /[ 	]+\".*\"[ 	]*$/)) {
+				title = substr(url, RSTART, RLENGTH);
+				url = substr(url, 1, RSTART - 1);
+				match(title, /\".*\"/);
+				title = " title=\"" substr(title, RSTART + 1, RLENGTH - 2) "\"";
+			}
+			if(match(url, /^<.*>$/))
+				url = substr(url, 2, RLENGTH - 2);
+			return t1 "<img src=\"" url "\" alt=\"" alt "\"" title " />" nextil(t2);
+		}
+		else{
+			# Referenced
+			sub(/^ ?\[/, "", t2);
+			id = alt;
+			if(match(t2, /^[^\]]+/))
+				id = substr(t2, 1, RLENGTH);
+			t2 = substr(t2, RLENGTH + 2);
+			if(ref[id])
+				r = ref[id];
+			else{
+				r = "<<" id;
+				nr++;
+			}
+			return t1 "<img src=\"" r "\" alt=\"" alt "\" />" nextil(t2);
+		}
+	}
+	# Links
+	if(tag == "["){
+		if(!match(t2, /(\[.*\])|(\(.*\))/))
+			return t1 tag nextil(t2);
+		match(t2, /^[^\]]*(\[[^\]]*\][^\]]*)*/);
+		linktext = substr(t2, 1, RLENGTH);
+		t2 = substr(t2, RLENGTH + 2);
+		if(match(t2, /^\(/)){
+			# Inline
+			match(t2, /^[^\)]+(\([^\)]+\)[^\)]*)*/);
+			url = substr(t2, 2, RLENGTH - 1);
+			pt2 = substr(t2, RLENGTH + 2);
+			title = "";
+			if(match(url, /[ 	]+\".*\"[ 	]*$/)) {
+				title = substr(url, RSTART, RLENGTH);
+				url = substr(url, 1, RSTART - 1);
+				match(title, /\".*\"/);
+				title = " title=\"" substr(title, RSTART + 1, RLENGTH - 2) "\"";
+			}
+			if(match(url, /^<.*>$/))
+				url = substr(url, 2, RLENGTH - 2);
+			url = eschtml(url);
+			return t1 "<a href=\"" url "\"" title ">" nextil(linktext) "</a>" nextil(pt2);
+		}
+		else{
+			# Referenced
+			sub(/^ ?\[/, "", t2);
+			id = linktext;
+			if(match(t2, /^[^\]]+/))
+				id = substr(t2, 1, RLENGTH);
+			t2 = substr(t2, RLENGTH + 2);
+			if(ref[id])
+				r = ref[id];
+			else{
+				r = "<<" id;
+				nr++;
+			}
+			pt2 = t2;
+			return t1 "<a href=\"" r "\" />" nextil(linktext) "</a>" nextil(pt2);
+		}
+	}
+	# Emphasis
+	if(match(tag, /[*_]/)){
+		ntag = tag;
+		if(sub("^" tag, "", t2)){
+			if(stag[ns] == tag && match(t2, "^" tag))
+				t2 = tag t2;
+			else
+				ntag = tag tag
+		}
+		n = length(ntag);
+		tag = (n == 2) ? "strong" : "em";
+		if(match(t1, / $/) && match(t2, /^ /))
+			return t1 tag nextil(t2);
+		if(stag[ns] == ntag){
+			tag = "/" tag;
+			ns--;
+		}
+		else
+			stag[++ns] = ntag;
+		tag = "<" tag ">";
+		return t1 tag nextil(t2);
+	}
+}
+
+function inline(t) {
+	ilcode = 0;
+	ilcode2 = 0;
+	ns = 0;
+	
+	return nextil(t);
+}
+
+function printp(tag) {
+	if(!match(text, /^[ 	]*$/)){
+		text = inline(text);
+		if(tag != "")
+			oprint("<" tag ">" text "</" tag ">");
+		else
+			oprint(text);
+	}
+	text = "";
+}
+
+BEGIN {
+	blank = 0;
+	code = 0;
+	hr = 0;
+	html = 0;
+	nl = 0;
+	nr = 0;
+	otext = "";
+	text = "";
+	par = "p";
+}
+
+# References
+!code && /^ *\[[^\]]*\]:[ 	]+/ {
+	sub(/^ *\[/, "");
+	match($0, /\]/);
+	id = substr($0, 1, RSTART - 1);
+	sub(id "\\]:[ 	]+", "");
+	title = "";
+	if(match($0, /\".*\"$/))
+		title = "\" title=\"" substr($0, RSTART + 1, RLENGTH - 2);
+	sub(/[ 	]+\".*\"$/, "");
+	url = eschtml($0);
+	ref[id] = url title;
+
+	subref(id);
+	next;
+}
+
+# html
+!html && /^<(address|blockquote|center|dir|div|dl|fieldset|form|h[1-6r]|\
+isindex|menu|noframes|noscript|ol|p|pre|table|ul|!--)/ {
+	if(code)
+		oprint("</pre></code>");
+	for(; !text && block[nl] == "blockquote"; nl--)
+		oprint("</blockquote>");
+	match($0, /^<(address|blockquote|center|dir|div|dl|fieldset|form|h[1-6r]|\
+	isindex|menu|noframes|noscript|ol|p|pre|table|ul|!--)/);
+	htag = substr($0, 2, RLENGTH - 1);
+	if(!match($0, "(<\\/" htag ">)|((^<hr ?\\/?)|(--)>$)"))
+		html = 1;
+	if(html && match($0, /^<hr/))
+		hr = 1;
+	oprint($0);
+	next;
+}
+
+html && (/(^<\/(address|blockquote|center|dir|div|dl|fieldset|form|h[1-6r]|\
+isindex|menu|noframes|noscript|ol|p|pre|table|ul).*)|(--)>$/ ||
+(hr && />$/)) {
+	html = 0;
+	hr = 0;
+	oprint($0);
+	next;
+}
+
+html {
+	oprint($0);
+	next;
+}
+
+# List and quote blocks
+
+#   Remove indentation
+{
+	for(nnl = 0; nnl < nl; nnl++)
+		if((match(block[nnl + 1], /[ou]l/) && !sub(/^(    |	)/, "")) || \
+		(block[nnl + 1] == "blockquote" && !sub(/^> ?/, "")))
+			break;
+}
+nnl < nl && !blank && text && ! /^ ? ? ?([*+-]|([0-9]+\.)+)( +|	)/ { nnl = nl; }
+#   Quote blocks
+{ 
+	while(sub(/^> /, ""))
+		nblock[++nnl] = "blockquote";
+}
+#   Horizontal rules
+{ hr = 0; }
+(blank || (!text && !code)) && /^ ? ? ?([-*_][ 	]*)([-*_][ 	]*)([-*_][ 	]*)+$/ {
+	if(code){
+		oprint("</pre></code>");
+		code = 0;
+	}
+	blank = 0;
+	nnl = 0;
+	hr = 1;
+}
+#   List items
+block[nl] ~ /[ou]l/ && /^$/ {
+	blank = 1;
+	next;
+}
+{ newli = 0; }
+!hr && (nnl != nl || !text || block[nl] ~ /[ou]l/) && /^ ? ? ?[*+-]( +|	)/ {
+	sub(/^ ? ? ?[*+-]( +|	)/, "");
+	nnl++;
+	nblock[nnl] = "ul";
+	newli = 1;
+}
+(nnl != nl || !text || block[nl] ~ /[ou]l/) && /^ ? ? ?([0-9]+\.)+( +|	)/ {
+	sub(/^ ? ? ?([0-9]+\.)+( +|	)/, "");
+	nnl++;
+	nblock[nnl] = "ol";
+	newli = 1;
+}
+newli { 
+	if(blank && nnl == nl && !par)
+		par = "p";
+	blank = 0;
+	printp(par);
+	if(nnl == nl && block[nl] == nblock[nl])
+		oprint("</li><li>");
+}
+blank && ! /^$/ {
+	if(match(block[nnl], /[ou]l/) && !par)
+		par = "p";
+	printp(par);
+	par = "p";
+	blank = 0;
+}
+		
+# Close old blocks and open new ones
+nnl != nl || nblock[nl] != block[nl] {
+	if(code){
+		oprint("</pre></code>");
+		code = 0;
+	}
+	printp(par);
+	b = (nnl > nl) ? nblock[nnl] : block[nnl];
+	par = (match(b, /[ou]l/)) ? "" : "p";
+}
+nnl < nl || (nnl == nl && nblock[nl] != block[nl]) {
+	for(; nl > nnl || (nnl == nl && pblock[nl] != block[nl]); nl--){
+		if(match(block[nl], /[ou]l/))
+			oprint("</li>");
+		oprint("</" block[nl] ">");
+	}
+}
+nnl > nl {
+	for(; nl < nnl; nl++){
+		block[nl + 1] = nblock[nl + 1];
+		oprint("<" block[nl + 1] ">");
+		if(match(block[nl + 1], /[ou]l/))
+			oprint("<li>");
+	}
+}
+hr {
+	oprint("<hr>");
+	next;
+}
+
+# Code blocks
+code && /^$/ { 
+	if(blanK)
+		oprint("");
+	blank = 1;
+	next;
+}
+!text && sub(/^(	|    )/, "") {
+	if(blanK)
+		oprint("");
+	blank = 0;
+	if(!code)
+		oprint("<code><pre>");
+	code = 1;
+	$0 = eschtml($0);
+	oprint($0);
+	next;
+}
+code {
+	oprint("</pre></code>");
+	code = 0;
+}
+
+# Setex-style Headers
+text && /^=+$/ {printp("h1"); next;}
+text && /^-+$/ {printp("h2"); next;} 
+
+# Atx-Style headers
+/^#+/ && (!newli || par=="p" || /^##/) {
+	for(n = 0; n < 6 && sub(/^# */, ""); n++)
+		sub(/#$/, "");
+	par = "h" n;
+}
+
+# Paragraph	
+/^$/ {
+	printp(par);
+	par = "p";
+	next;
+}
+
+# Add text
+{ text = (text ? text " " : "") $0; }
+
+END {
+	if(code){
+		oprint("</pre></code>");
+		code = 0;
+	}
+	printp(par);
+	for(; nl > 0; nl--){
+		if(match(block[nl], /[ou]l/))
+			oprint("</li>");
+		oprint("</" block[nl] ">");
+	}
+	gsub(/<<[^\"]*/, "", otext);
+	print(otext);
+}

+ 55 - 0
bin/template.awk

@@ -0,0 +1,55 @@
+#!/usr/bin/awk -f
+function pr(str) {
+	if(lastc !~ "[{(]")
+		gsub(/'/, "''", str)
+	printf "%s", str
+}
+function trans(c) {
+	printf "%s", end
+
+	lastc = c
+	end = "\n"
+	if(c == "%")
+		end = ""
+	else if(c == "(")
+		printf "echo -n "
+	else if(c ~ "[})]") {
+		end = "'\n"
+		printf "echo -n '"
+	}
+}
+
+BEGIN {
+	lastc = "{"
+	trans("}")
+}
+END {
+	print end
+}
+
+/^%/ && $0 !~ /^%[{()}%]/ && lastc !~ /[({]/ {
+	trans("%")
+	print substr($0, 2)
+	next
+}
+{
+	if(lastc == "%")
+		trans("}")
+	n = split($0, a, "%")
+	pr(a[1])
+	for(i=2; i<=n; i++) {
+		c = substr(a[i], 1, 1)
+		rest = substr(a[i], 2)
+
+		if((lastc !~ "[({]" && c ~ "[({]") ||
+		   (lastc == "{" && c == "}") ||
+		   (lastc == "(" && c == ")"))
+			trans(c)
+		else if(c == "%")
+			pr("%")
+		else
+			pr("%" c)
+		pr(rest)
+	}
+	pr("\n")
+}

+ 39 - 0
bin/urldecode.awk

@@ -0,0 +1,39 @@
+#!/bin/awk -f
+BEGIN {
+	hextab ["0"] = 0; hextab ["8"] = 8;
+	hextab ["1"] = 1; hextab ["9"] = 9;
+	hextab ["2"] = 2; hextab ["A"] = hextab ["a"] = 10
+	hextab ["3"] = 3; hextab ["B"] = hextab ["b"] = 11;
+	hextab ["4"] = 4; hextab ["C"] = hextab ["c"] = 12;
+	hextab ["5"] = 5; hextab ["D"] = hextab ["d"] = 13;
+	hextab ["6"] = 6; hextab ["E"] = hextab ["e"] = 14;
+	hextab ["7"] = 7; hextab ["F"] = hextab ["f"] = 15;
+}
+{
+	decoded = ""
+	i   = 1
+	len = length ($0)
+	while ( i <= len ) {
+		c = substr ($0, i, 1)
+		if ( c == "%" ) {
+			if ( i+2 <= len ) {
+				c1 = substr ($0, i+1, 1)
+				c2 = substr ($0, i+2, 1)
+				if ( hextab [c1] == "" || hextab [c2] == "" ) {
+					print "WARNING: invalid hex encoding: %" c1 c2 | "cat >&2"
+				} else {
+					code = 0 + hextab [c1] * 16 + hextab [c2] + 0
+					c = sprintf ("%c", code)
+					i = i + 2
+				}
+			} else {
+				print "WARNING: invalid % encoding: " substr ($0, i, len - i)
+			}
+		} else if ( c == "+" ) {
+			c = " "
+		}
+		decoded = decoded c
+		++i
+	}
+	print decoded
+}

+ 126 - 0
bin/urlencode.awk

@@ -0,0 +1,126 @@
+# Taken from http://www.shelldorado.com/scripts/cmds/urlencode
+##########################################################################
+# Title      :  urlencode - encode URL data
+# Author     :  Heiner Steven (heiner.steven@odn.de)
+# Date       :  2000-03-15
+# Requires   :  awk
+# Categories :  File Conversion, WWW, CGI
+# SCCS-Id.   :  @(#) urlencode  1.4 06/10/29
+##########################################################################
+# Description
+#   Encode data according to
+#       RFC 1738: "Uniform Resource Locators (URL)" and
+#       RFC 1866: "Hypertext Markup Language - 2.0" (HTML)
+#
+#   This encoding is used i.e. for the MIME type
+#   "application/x-www-form-urlencoded"
+#
+# Notes
+#    o  The default behaviour is not to encode the line endings. This
+#   may not be what was intended, because the result will be
+#   multiple lines of output (which cannot be used in an URL or a
+#   HTTP "POST" request). If the desired output should be one
+#   line, use the "-l" option.
+#
+#    o  The "-l" option assumes, that the end-of-line is denoted by
+#   the character LF (ASCII 10). This is not true for Windows or
+#   Mac systems, where the end of a line is denoted by the two
+#   characters CR LF (ASCII 13 10).
+#   We use this for symmetry; data processed in the following way:
+#       cat | urlencode -l | urldecode -l
+#   should (and will) result in the original data
+#
+#    o  Large lines (or binary files) will break many AWK
+#       implementations. If you get the message
+#       awk: record `...' too long
+#        record number xxx
+#   consider using GNU AWK (gawk).
+#
+#    o  urlencode will always terminate it's output with an EOL
+#       character
+#
+# Thanks to Stefan Brozinski for pointing out a bug related to non-standard
+# locales.
+#
+# See also
+#   urldecode
+##########################################################################
+
+PN=`basename "$0"`          # Program name
+VER='1.4'
+
+: ${AWK=awk}
+
+Usage () {
+    echo >&2 "$PN - encode URL data, $VER
+usage: $PN [-l] [file ...]
+    -l:  encode line endings (result will be one line of output)
+
+The default is to encode each input line on its own."
+    exit 1
+}
+
+Msg () {
+    for MsgLine
+    do echo "$PN: $MsgLine" >&2
+    done
+}
+
+Fatal () { Msg "$@"; exit 1; }
+
+set -- `getopt hl "$@" 2>/dev/null` || Usage
+[ $# -lt 1 ] && Usage           # "getopt" detected an error
+
+EncodeEOL=no
+while [ $# -gt 0 ]
+do
+    case "$1" in
+        -l) EncodeEOL=yes;;
+    --) shift; break;;
+    -h) Usage;;
+    -*) Usage;;
+    *)  break;;         # First file name
+    esac
+    shift
+done
+
+LANG=C  export LANG
+$AWK '
+    BEGIN {
+    # We assume an awk implementation that is just plain dumb.
+    # We will convert an character to its ASCII value with the
+    # table ord[], and produce two-digit hexadecimal output
+    # without the printf("%02X") feature.
+
+    EOL = "%0A"     # "end of line" string (encoded)
+    split ("1 2 3 4 5 6 7 8 9 A B C D E F", hextab, " ")
+    hextab [0] = 0
+    for ( i=1; i<=255; ++i ) ord [ sprintf ("%c", i) "" ] = i + 0
+    if ("'"$EncodeEOL"'" == "yes") EncodeEOL = 1; else EncodeEOL = 0
+    }
+    {
+    encoded = ""
+    for ( i=1; i<=length ($0); ++i ) {
+        c = substr ($0, i, 1)
+        if ( c ~ /[a-zA-Z0-9.-]/ ) {
+        encoded = encoded c     # safe character
+        } else if ( c == " " ) {
+        encoded = encoded "+"   # special handling
+        } else {
+        # unsafe character, encode it as a two-digit hex-number
+        lo = ord [c] % 16
+        hi = int (ord [c] / 16);
+        encoded = encoded "%" hextab [hi] hextab [lo]
+        }
+    }
+    if ( EncodeEOL ) {
+        printf ("%s", encoded EOL)
+    } else {
+        print encoded
+    }
+    }
+    END {
+        #if ( EncodeEOL ) print ""
+    }
+' "$@"
+

+ 14 - 0
bin/wesh.sh

@@ -0,0 +1,14 @@
+#!/bin/sh
+
+. conf.sh
+. lib.sh
+. corehandlers.sh
+cd ..
+
+. "$SITE_DIR/_wesh/config"
+
+printf "Content-Type: text/html\n"
+printf "\n"
+
+handler lib/headers.tpl
+handler lib/default_master.tpl

+ 12 - 0
lib/404.tpl

@@ -0,0 +1,12 @@
+<h1>The requested document at '<i>%($base_url$"req_path%)</i>' doesn't exist</h1>
+
+% # Google Enhanced 404 pages: http://www.google.com/support/webmasters/bin/answer.py?answer=93644
+<script type="text/javascript">
+  var GOOG_FIXURL_LANG = 'en';
+  var GOOG_FIXURL_SITE = '%($base_url%)/';
+</script>
+<script type="text/javascript" 
+    src="http://linkhelp.clients.google.com/tbproxy/lh/wm/fixurl.js"></script>
+
+<h4>Or take a look at the <a href="/sitemap">sitemap</a>.</h4>
+<hr>

+ 27 - 0
lib/default_master.tpl

@@ -0,0 +1,27 @@
+<div id="header">
+    <div class="superHeader">
+% cat $(get_lib_file top_bar.inc)
+    </div>
+
+    <div class="midHeader">
+    <h1 class="headerTitle"><a href="/">%($siteTitle%) <span id="headerSubTitle">%($siteSubTitle%)</span></a></h1>
+    </div>
+
+    <div class="subHeader"><br></div>
+</div>
+
+<div id="side-bar">
+    <div>
+%       nav_tree
+    </div>
+</div>
+
+<div id="main-copy">
+
+% handler_body_main
+
+</div>
+
+<div id="footer">
+% cat $(get_lib_file footer.inc)
+</div>

+ 5 - 0
lib/footer.inc

@@ -0,0 +1,5 @@
+<div class="left"><a href="https://gogs.tankernn.eu/Tankernn/wesh">Powered by wesh</a></div>
+<div class="right"><!--<a href="/_users/login">User Login</a>--></div>
+
+<br>
+<br class="doNotDisplay doNotPrint">

+ 33 - 0
lib/headers.tpl

@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+
+    <title>%($pageTitle%)</title>
+
+    <link rel="stylesheet" href="/pub/style/style.css" type="text/css" media="screen, handheld" title="default">
+    <link rel="shortcut icon" href="/favicon.ico" type="image/vnd.microsoft.icon">
+% if [ -f $sitedir/_werc/pub/style.css ]; then
+    <link rel="stylesheet" href="/_werc/pub/style.css" type="text/css" media="screen" title="default">'
+% fi
+
+    <meta charset="UTF-8">
+% # Legacy charset declaration for backards compatibility with non-html5 browsers.
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
+
+% if [ -z $meta_description ]; then
+    <meta name="description" content="%($meta_description%)">
+% fi
+% if [ -z $meta_keywords ]; then
+    <meta name="keywords" content="%($meta_keywords%)">
+% fi
+
+% h="$(get_lib_file headers.inc)"
+% if [ -z "$h" ]; then
+%   cat "$h"
+% fi
+
+    %($extraHeaders%)
+
+</head>
+<body>
+

+ 16 - 0
lib/top_bar.inc

@@ -0,0 +1,16 @@
+    <div class="left">
+      <a href="http://gsoc.cat-v.org">gsoc</a> |
+      <a href="http://doc.cat-v.org">doc archive</a> |
+      <a href="http://repo.cat-v.org">software repo</a> |
+      <a href="http://ninetimes.cat-v.org">ninetimes</a> |
+      <a href="http://harmful.cat-v.org">harmful</a> |
+      <a href="http://9p.cat-v.org/">9P</a> |
+      <a href="http://cat-v.org">cat-v.org</a>
+    </div>
+
+    <div class="right">
+      <span class="doNotDisplay">Related sites:</span>
+      | <a href="http://cat-v.org/update_log">site updates</a>
+      | <a href="/sitemap">site map</a>
+    </div>
+

BIN
pub/default_favicon.ico


+ 329 - 0
pub/style/style.css

@@ -0,0 +1,329 @@
+/* Default werc style */
+
+body {
+  color: black;
+  background-color: white;
+  font-family: Helvetica, Verdana, Arial, 'Liberation Sans', FreeSans, sans-serif;
+  font-size: 84%;  /* Enables font size scaling in MSIE */
+  margin: 0;
+  padding: 0;
+}
+
+
+/* # Header # */
+.superHeader {
+  color: white;
+  background-color: #337AB7;
+  height: 1.6em;
+}
+
+.superHeader img { vertical-align: bottom; }
+
+.superHeader a {
+  color: white;
+  background-color: transparent;
+  font-size: 91%;
+  margin: 0;
+  padding: 0 0.5ex 0 0.25ex;
+}
+
+a { text-decoration: none; }
+a:hover { text-decoration: underline; }
+
+.superHeader div {
+  position: absolute;
+  top: 0.40ex;
+}
+
+.superHeader .left { left: 0.4em; }
+.superHeader .right { right: 0.4em; }
+
+.midHeader {
+  color: rgb(39,78,144);
+  background-color: #00a4e1;
+  /*border: solid 0 black;*/
+  border-width: 2px 0;
+}
+
+.headerTitle {
+  color: white;
+  font-size: 233%;
+  font-weight: normal;
+  margin: 0 0 0 4mm;
+  padding: 0.25ex 0;
+}
+#headerSubTitle {
+  font-size: 50%;
+  font-style: italic;
+  margin-left: 1em;
+}
+
+.headerTitle a { color: white; }
+.headerTitle a:hover { text-decoration: none; }
+
+.subHeader {
+  display: none;
+  color: white;
+  background-color: rgb(0,51,153);
+  margin: 0;
+  padding: 1ex 1ex 1ex 1.5mm;
+}
+
+.subHeader a {
+  color: white;
+  background-color: transparent;
+  font-weight: bold;
+  margin: 0;
+  padding: 0 0.75ex 0 0.5ex;
+}  
+
+.superHeader .highlight, .subHeader .highlight {
+  color: rgb(253,160,91);
+  background-color: transparent;
+}
+
+
+/* # Side # */
+#side-bar {
+  width: 16em;
+  float: left;
+  clear: left;
+  border-right: 1px solid #ddd;
+}
+
+#side-bar div {
+  border-bottom: 1px solid #ddd;
+}
+
+.sideBarTitle {
+  font-weight: bold;
+  margin: 0 0 0.5em 2mm;
+  padding: 1em 0 0 0;
+}
+
+#side-bar ul {
+  list-style-type: none;
+  list-style-position: outside;
+  margin: 0;
+  padding: 0 0 0.3em 0;
+}
+
+li ul {
+  padding-left: 0.6em !important;
+}
+
+#side-bar li {
+  margin: 0;
+  padding: 0.1ex 0;  /* Circumvents a rendering bug (?) in MSIE 6.0  XXX should move to iehacks.css, this causes an ugly gap */
+}
+
+#side-bar a {
+  color: rgb(0,102,204);
+  background-color: transparent;
+  margin: 0;
+  padding: 0.25em 1ex 0.25em 2mm;
+  display: block;
+  text-transform: capitalize;
+  font-weight: bold!important;
+  font-size: 102%;
+  border-left: white solid 0.2em;
+}
+
+.thisPage, .thisPage a {
+  color: black!important;
+  background-color: white;
+  padding-left: 5mm;
+}
+
+#side-bar a:hover {
+  color: white;
+  background-color: rgb(100,135,220);
+  border-left: black solid 0.2em;
+  text-decoration: none;
+}
+
+.sideBarText {
+  line-height: 1.5em;
+  margin: 0 0 1em 0;
+  padding: 0 1.5ex 0 2.5mm;
+  display: block;
+}
+
+#side-bar .sideBarText a {
+  margin: 0;
+  padding: 0;
+  display: inline;
+}
+
+#side-bar .sideBarText a:hover {
+  color: rgb(0,102,204);
+  background-color: transparent;
+  text-decoration: none;
+}
+
+
+/* # Main Copy # */
+#main-copy {
+  max-width: 70em;
+  color: black;
+  background-color: transparent;
+  text-align: justify;
+  line-height: 1.5em;
+  margin: 0em 0 0 16em;
+  padding: 0.5mm 5mm 5mm 5mm;
+  border-left: 1px solid #ddd;
+}
+
+#bodyText {
+  margin: 0 0 0 15.5em;
+  padding: 2mm 5mm 2mm 5mm;
+}
+
+#main-copy p {
+  margin: 1em 1ex 1em 1ex !important; /* Need !important so troff-generated pages don't look totally squezed */
+  padding: 0;
+}
+
+#main-copy a {
+  color: rgb(0,102,204);
+  background-color: transparent;
+}
+
+#main-copy a:hover {
+  color:  rgb(100,135,220);
+}
+
+#main-copy h1, #main-copy h2 {
+  color: rgb(0,102,204);
+  background-color: transparent;
+  font-size: 145.5%;
+  font-weight: bold;
+  margin: 2em 0 0 0;
+  padding: 0.5ex 0 0.5ex 0.6ex;
+  border-bottom: 2px solid rgb(0,102,204);
+}
+
+#main-copy h2 {
+  font-size: 115.5%;
+  border-bottom: 1px solid rgb(0,102,204);
+}
+
+#main-copy .topOfPage {
+  color: rgb(0,102,204);
+  background-color: transparent;
+  font-size: 91%;
+  font-weight: bold;
+  text-decoration: none;
+  margin: 3ex 1ex 0 0;
+  padding: 0;
+  float: right;
+}
+
+dl {
+  margin: 1em 1ex 2em 1ex;
+  padding: 0;
+}
+
+dt {
+  font-weight: bold;
+  margin: 0 0 0 0;
+  padding: 0;
+}
+
+dd {
+  margin: 0 0 2em 2em;
+  padding: 0;
+}
+
+
+/* # Footer # */
+#footer {
+  color: white;
+  background-color: #337AB7;
+  padding: 1em;
+  clear: both;
+}
+
+#footer .left {
+  text-align: left;
+  line-height: 1.55em;
+  float: left;
+  clear: left;
+}
+
+#footer .right {
+  text-align: right;
+  line-height: 1.45em;
+}
+
+#footer a {
+  color: white;
+  background-color: transparent;
+}
+
+
+/* GENERAL */
+
+table {
+  border: solid 1px black;
+}
+th {
+  background-color: #abc;
+  border: solid 1px black;
+   text-align: center;
+}
+td {
+  background-color: #def;
+  border: solid 1px black;
+}
+
+hr {
+  border-width: 0px 0px 0.1em 0px;
+  border-color: black;
+}
+
+acronym, .titleTip {
+  border-bottom: 1px solid #ddd;
+  cursor: help;
+  margin: 0;
+  padding: 0 0 0.4px 0;
+}
+
+pre {
+  margin-left: 2em; 
+  font-size: 1.2em;
+}
+
+blockquote {
+  border-left: 1px solid blue;
+  font-style: italic;
+}
+
+.smallCaps {
+  font-size: 110%;
+  font-variant: small-caps;
+}
+
+.doNotDisplay { display: none; }
+
+
+.notify_errors,
+.notify_notes,
+.notify_success { padding: .8em; margin-bottom: 1em; border: 2px solid #ddd; }
+ 
+.notify_errors { background: #FBE3E4; color: #8a1f11; border-color: #FBC2C4; }
+.notify_notes { background: #FFF6BF; color: #514721; border-color: #FFD324; }
+.notify_success { background: #E6EFC2; color: #264409; border-color: #C6D880; }
+.notify_errors a { color: #8a1f11; }
+.notify_notes a { color: #514721; }
+.notify_success a { color: #264409; }
+
+
+/* # Page/Handler specific # */
+h1.dir-list-head, ul.dir-list {
+  text-transform: capitalize;
+  font-weight: bold;
+}
+ul.sitemap-list a {
+  text-transform: capitalize;
+}

+ 0 - 0
sites/CREATE-SITE-DIRECTORIES-HERE


+ 4 - 0
sites/wesh.tankernn.eu/_wesh/config

@@ -0,0 +1,4 @@
+masterSite=wesh.tankernn.eu
+siteTitle='wesh'
+siteSubTitle='POSIX web framework based on werc'
+

+ 0 - 0
sites/wesh.tankernn.eu/_wesh/lib/OVERRIDE_LIB_FILES_HERE


+ 6 - 0
sites/wesh.tankernn.eu/about/FAQ.md

@@ -0,0 +1,6 @@
+FAQ
+===
+
+Q: Why not werc?
+
+A: [Plan 9](https://9fans.github.io/plan9port/), which is required for werc, does not compile with [musl](https://www.musl-libc.org/).

+ 4 - 0
sites/wesh.tankernn.eu/about/index.md

@@ -0,0 +1,4 @@
+About wesh
+==========
+
+wesh was inspired by a similar project, [werc](http://werc.cat-v.org/), written in the rc shell.

+ 4 - 0
sites/wesh.tankernn.eu/index.md

@@ -0,0 +1,4 @@
+Web Extensible SHell
+====================
+
+This website is an example of [wesh](https://gogs.tankernn.eu/Tankernn/wesh), the POSIX shell web framework.