# ___
# _/ oo\ An evil idea:
# ( \ -/__ the Evil nested file expander
# \ \__)
# / \ (c) 2009 by Tim Menzies, GPL 3.0
# / _\ http://www.gnu.org/licenses/gpl.txt
# `"""""`` jgs
#
#use X : recurses into X
#SHOW X : recuses into X, showing the contents
#show X : recuses into X, showing the contents, except para1
#list X : includes file X, wrapped in "pre"
#
# -R = root directory (where to look for files)
# -p = print contents
# -s = skip para one
# -i = explore contents of included print files
# -u = explore contents of included used files
# -f = print file name
BEGIN { options("R,.,p,,i,,u,,f,,S,1",Opt) }
{ xpand(1,opt("S")) }
END { if (opt("f")) print " " FILENAME }
function xpand(n,skippingPara1, skipped,i) {
if (opt("i") && ($1 ~ "^#SHOW"))
xpands(n+1,$2)
else if (opt("i") && ($1 ~ "^#show"))
xpands(n+1,$2,opt("S"))
else if (opt("i") && ($1 ~ "^#list")) {
print "
"
xpands(n+1,$2)
print "
"
}
else if (opt("u") && ($1 ~ "^#use"))
xpands(n+1,$2)
else if (opt("p")) {
if (skippingPara1) {
if (skipped) print $0
} else print $0
}
}
function xpands(n,f,skippingPara1, skipped, missing) {
gsub(/"/,"",f)
if (newFile(f,Seen)) {
f = opt("R") "/" f
Stack[++Stack[0]]= f
missing = 1
while((getline 0) {
missing = 0
if (!skipped && ($0 ~ /^[\t ]*$/))
skipped = 1
xpand(n+1,skippingPara1,skipped)
}
close(f)
if (missing)
warn("?? [" Stack[Stack[0]-1] \
"] references missing file [" f \
"].")
else { if (opt("f"))
print chars(n*3," ") f }
Stack[0]--
}
}
# standard one-liners
function opt(x) {
return (x in Opt) ? Opt[x] : warn("option ["x"] unknown")
}
function newFile(f,seen) { return (++seen[f])==1 }
function chars(n,c, str) { while((n--)> 0) str=str c ; return str }
function saya(str,a, i) { for(i in a) print str "[" i "]=" a[i]}
function barph(s) { warn(s); exit }
function warn(s) { print s >"/dev/stderr"; return 0 }
function s2a(str,a, tmp,i,n) {
n=split(str,tmp,/,/)
for(i=1;i<=n;i += 2) a[tmp[i]]=tmp[i+1]
return n
}
#begin world's simplest command-line parser.
#Upper case flags have parameters
#After grabbing all the command-line flags,
#ARGV/ARGC is set to the remaining command-line vars
function options(str,opt, key,i,j,k,n,tmp1,tmp2) {
# first: split "str" to initialize "opt"
n=split(str,tmp1,/,/)
for(i=1;i<=n;i += 2)
opt[tmp1[i]]=tmp1[i+1]
# second: explore the arguments till no more flags
for(i=1;i<=ARGC;i++) {
key = ARGV[i]
if (sub(/^-/,"",key)) { # we have a new flag
if (key in opt) # if flag is legal, change its value
# if flag begins with upper case,
# then take value from command line
opt[key] = (key ~ /^[A-Z]/) ? ARGV[++i] : 1
else print "? unknown key ["key"]" >"/dev/stderr"
} else { i--; break }
}
# third: clear the flags from ARGC, ARGV
for(j=i+1;j<=ARGC;j++)
tmp2[j-i]=ARGV[j]
split("",ARGV,"")
for(k in tmp2)
ARGV[k] = tmp2[k]
ARGC -= i
return ARGC
}