#!/bin/awk -f #!/opt/busybox/awk -f # Copyright 2022 - 2023 Paul Hänsch # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR # IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. function sh_escape(arg){ return "'" gensub(/'/, "'\"'\"'", "g", arg) "'"; } function argsplit(line, args, LOCAL, c, n, ctx) { ctx="space"; n=0; while ( length(line) > 0 ) { c = substr(line, 1, 1); line = substr(line, 2); if (ctx == "space" ) if (c ~ /[ \t]/) ctx = "space"; else if (c ~ /\\/) { n++; ctx = "escbare"; } else if (c ~ /"/) { n++; ctx = "dquot"; } else if (c ~ /'/) { n++; ctx = "squot"; } else { n++; args[n] = c; ctx = "bare"; } else if (ctx == "bare") if (c ~ /[ \t]/) ctx = "space"; else if (c ~ /\\/) ctx = "escbare"; else if (c ~ /"/) ctx = "dquot"; else if (c ~ /'/) ctx = "squot"; else args[n] = args[n] c; else if (ctx == "dquot") if (c ~ /"/) ctx = "bare"; else if (c ~ /\\/) ctx = "escdquot"; else args[n] = args[n] c; else if (ctx == "squot") if (c ~ /'/) ctx = "bare"; else args[n] = args[n] c; else if (ctx == "escbare") { args[n] = args[n] c; ctx = "bare"; } else if (ctx == "escdquot") { args[n] = args[n] c; ctx = "dquot"; } } } function HTML ( text ) { gsub( /&/, "\\&", text ); gsub( //, "\\>", text ); gsub( /"/, "\\"", text ); gsub( /'/, "\\'", text ); gsub( /\\/, "\\\", text ); return text; } function macro(call, LOCAL, line, args) { argsplit(call, args); call=""; for (n = 1; n in args; n++) call = call sh_escape(args[n]) " "; if (args[1] in MACROS) { printf "%s", file | sh_escape(ENVIRON["MD_MACROS"]) "/" call; close(sh_escape(ENVIRON["MD_MACROS"]) "/" call); } else { printf "%s", HTML("<<" call ">>"); } } function unhtml ( text ) { gsub( /</, "<", text); gsub( />/, ">", text); gsub( /"/, "\"", text); gsub( /'/, "'", text); gsub( /\/, "\\", text); gsub( /&/, "\\&", text); return text; } function findmacro(line, LOCAL, st, len, pre, post) { if ( match(line, /[^\n]*<\/code>/) ) { match(line, //); pre = substr( line, 1, RSTART - 1 ); line = substr( line, RSTART + RLENGTH); match( line, /<\/code>/); post = substr(line, RSTART + RLENGTH); line = substr(line, 1, RSTART - 1); printf "%s", pre; macro( unhtml(line) ); findmacro( post ); } else { printf "%s", line; } } BEGIN { if (ENVIRON["MD_MACROS"]) { AllowMacros = "true"; "cd " sh_escape(ENVIRON["MD_MACROS"]) "; printf '%s/' *" |getline macro_list; split(macro_list, MACROS, "/"); for (n in MACROS) { MACROS[MACROS[n]] = ""; delete MACROS[n]; } delete MACROS[""]; file = ""; while ( getline ) { file = file $0 "\n"; } findmacro( file ); } }