Last active
August 28, 2025 12:13
-
-
Save darkuranium/4f4f571f9e50240436ab to your computer and use it in GitHub Desktop.
Macro language processor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/awk -f | |
# Usage: ./mproc.awk \ | |
# KEY1=VAL1 KEY2=VAL2 ... \ | |
# /path/to/config1.conf.in /path/to/config2.conf.in > /path/to/output.conf | |
function logCOLOR(col, action, str) { | |
printf "\033[%sm> %s\033[0m %s\n", col, action, str > "/dev/stderr"; | |
} | |
function logVERBOSE(col, action, str) { | |
#logCOLOR(col, action, str); | |
} | |
function errFATAL(str) { | |
logCOLOR("31", "ERROR", str); | |
exit 1; | |
} | |
BEGIN { | |
# BRANCH STATE | |
btop = 0; | |
bstack_p[btop] = 1; # should we print the contents? | |
bstack_h[btop] = 1; # did we print at any point in the past? | |
for(i = 1; i < ARGC; i++) | |
{ | |
eq = index(ARGV[i], "="); | |
if(eq) | |
{ | |
key = substr(ARGV[i], 1, eq - 1); | |
val = substr(ARGV[i], eq + 1); | |
vars[key] = val; | |
ARGV[i] = ""; | |
} | |
else | |
process_file(ARGV[i]); | |
} | |
# don't process anything else | |
ARGC = 1; | |
} | |
function includefile(fname, raw, line) { | |
logVERBOSE("32", "INCLUDE" (raw ? " RAW" : ""), fname); | |
if(raw) | |
{ | |
while((getline line < fname) > 0) | |
printf "%s\n", line; | |
} | |
else | |
process_file(fname); | |
} | |
function isfalse(str) { | |
return (tolower(str) ~ /^(0|no|off|false)?$/); | |
} | |
function istrue(str) { | |
return !isfalse(str); | |
} | |
function istrue_var(var) { | |
return (var ~ /^\!/) ? isfalse(vars[var]) : istrue(vars[var]); | |
} | |
function err_stray(kw) { | |
errFATAL(sprintf("Stray `%s` in input (missing `@if`?)", kw)); | |
} | |
function expand_vars(src, dst, end, pattern, var, rstart, rlength) { | |
end = 1; | |
dst = ""; | |
while (match(src, /@[[:alpha:]_][[:alnum:]_]*@/)) { | |
rstart = RSTART; | |
rlength = RLENGTH; | |
pattern = substr(src, rstart + 1, rlength - 2); | |
if(!(pattern in vars)) | |
printf "Warning: Variable `%s` not set!\n", pattern > "/dev/stderr"; | |
var = vars[pattern]; | |
if(macros[pattern]) | |
var = expand_vars(var); | |
dst = dst substr(src, 1, rstart - 1) var; | |
end = rstart + rlength; | |
src = substr(src, end); | |
} | |
dst = dst src; | |
return dst; | |
} | |
function cmd_get_name(cmd) { | |
match(cmd, /^[[:space:]]*@[[:alpha:]_.][[:alnum:]_.]*[[:space:]]/); | |
return substr(cmd, RSTART + 1, RLENGTH - 2); | |
} | |
function cmd_get_body(cmd, ret) { | |
# trim leading spaces | |
match(cmd, /^[[:space:]]*@[[:alpha:]_.][[:alnum:]_.]*[[:space:]]+/); | |
ret = substr(cmd, RSTART + RLENGTH); | |
#trim trailing spaces | |
match(ret, /[[:space:]]*$/); | |
return substr(ret, 0, RSTART); | |
} | |
# we have to use a separate function because of recursion! | |
function process_file(fname, pname) | |
{ | |
logVERBOSE("36", "PROCESS BEGIN", fname); | |
pname = vars["MP_SRC_FILENAME"]; | |
vars["MP_SRC_FILENAME"] = fname; | |
while((getline < fname) > 0) | |
{ | |
if($0 ~ /^[[:space:]]*@include(\.raw)?[[:space:]]+.+$/) { | |
cmd = cmd_get_name($0); | |
file = cmd_get_body($0); | |
includefile(file, cmd == "include.raw"); | |
continue; | |
} | |
if($0 ~ /^[[:space:]]*@#.*$/) { # comments | |
continue; | |
} | |
if($0 ~ /^[[:space:]]*@[[:space:]]*$/) { # blank `@` lines | |
continue; | |
} | |
if($0 ~ /^[[:space:]]*@define[[:space:]]+[[:alpha:]_][[:alnum:]_]*[:?]?=.*?$/) { | |
if(!bstack_p[btop]) continue; | |
eq = index($0, "="); | |
split($2, spl, "="); | |
key = spl[1]; | |
val = substr($0, eq+1); | |
end = substr(key, length(key)); | |
nkey = substr(key, 1, length(key)-1); | |
if(end == "?") # ignore if set | |
{ | |
key = nkey; | |
if(key in vars) | |
continue; | |
} | |
else if(end == ":") # expand now | |
{ | |
key = nkey; | |
val = expand_vars(val); | |
macros[key] = 0; | |
} | |
else | |
macros[key] = 1; | |
vars[key] = val; | |
#printf "DEFINE %s => %s %s\n", key, val, end; | |
continue; | |
} | |
if($0 ~ /^[[:space:]]*@undef[[:space:]]+[[:alpha:]_][[:alnum:]_]*[[:space:]]*$/) { | |
if(!bstack_p[btop]) continue; | |
key = $2; | |
delete vars[$2]; | |
delete macros[$2]; | |
#printf "UNDEF %s\n", $2; | |
continue; | |
} | |
if($0 ~ /^[[:space:]]*@if[[:space:]]+\!?[[:alpha:]_][[:alnum:]_]*[[:space:]]*$/) { | |
btop++; | |
bstack_p[btop] = istrue_var($2); | |
bstack_h[btop] = bstack_p[btop]; | |
#printf "IF %s => bstack_p[%s] = %s\n", $2, btop, bstack_p[btop]; | |
continue; | |
} | |
if($0 ~ /^[[:space:]]*@elif[[:space:]]+\!?[[:alpha:]_][[:alnum:]_]*[[:space:]]*$/) { | |
if(!btop) | |
err_stray($1); | |
if(bstack_h[btop] == 2) | |
printf "Warning: `@elif` after `@else`!\n" > "/dev/stderr"; | |
if(bstack_h[btop]) | |
bstack_p[btop] = 0; | |
else | |
{ | |
bstack_p[btop] = istrue_var($2); | |
bstack_h[btop] = bstack_p[btop]; | |
} | |
#printf "ELIF %s => bstack_p[%s] = %s\n", $2, btop, bstack_p[btop]; | |
continue; | |
} | |
if($0 ~ /^[[:space:]]*@else[[:space:]]*$/) { | |
if(!btop) | |
err_stray($1); | |
bstack_p[btop] = !bstack_h[btop]; | |
bstack_h[btop] = 2; | |
#printf "ELSE %s\n", btop; | |
continue; | |
} | |
if($0 ~ /^[[:space:]]*@endif[[:space:]]*$/) { | |
if(!btop) | |
err_stray($1); | |
btop--; | |
#printf "ENDIF %s\n", btop; | |
continue; | |
} | |
if($0 ~ /^[[:space:]]*@/) { | |
errFATAL(sprintf("Unknown command `%s`", $0)); | |
} | |
if(!bstack_p[btop]) continue; | |
print expand_vars($0); | |
} | |
close(fname); | |
vars["MP_SRC_FILENAME"] = pname; | |
logVERBOSE("36", "PROCESS END", fname); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@# output a warning into output | |
# !!! AUTOGENERATED FILE - DO NOT EDIT !!! | |
# Generated from @MP_SRC_FILENAME@ | |
@include other.conf.in | |
@include.raw other.conf.in | |
@define INDEXES?=index.html index.htm | |
@if ENABLE_PHP | |
@define INDEXES:=@INDEXES@ index.php | |
@endif | |
server { | |
root /home/@USER@/public_html; | |
server_name @DOMAIN@ @[email protected]; | |
index @INDEXES@; | |
@if ENABLE_PHP | |
location ~ \.php$ { | |
fastcgi_pass /var/run/php5/@[email protected]; | |
fastcgi_index index.php; | |
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; | |
include fastcgi_params; | |
} | |
@endif | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# this is included from `other.conf.in` for @USER@! | |
@define DOMAIN:=@DOMAIN@ whatever.com |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment