1#! /usr/bin/env modernish
2#! use safe -k
3#! use sys/cmd/harden
4#! use var/loop/find -B
5#! use sys/base/mktemp
6harden cat
7harden -e '>1' cmp
8harden paste
9harden LC_ALL=C sed
10harden LC_ALL=C sort
11
12# This is a helper script I use to maintain the 'unalias' commands at the top
13# of every lib/modernish/mdl/**/*.mm module file. They are mainly inserted for
14# the benefit of interactive shell users, where aliases are not unlikely to
15# interfere with function definitions, causing spurious syntax errors.
16# Ref.: https://github.com/modernish/modernish/issues/5
17#
18# This script greps function names in module files, sorts them, and combines
19# them on one line. Without options, it adds or updates unalias commands on the
20# second line of each module file, only updating the file if something actually
21# changed. With the -r option, it removes these unalias commands.
22#
23# It is a nice demonstration of the use of the 'find' loop, as well as the
24# auto-cleanup option of modernish 'mktemp'.
25
26# --- Parse options ---
27showusage() { putln "Usage: $ME [ -r ]" "See comments in script for info."; }
28unset -v opt_r
29while getopts 'r' opt; do
30	case $opt in
31	( r )	opt_r= ;;
32	( * )	exit -u 1 ;;
33	esac
34done
35shift $((OPTIND-1))
36let $# && exit -u 1 'Excess arguments.'
37
38# --- Make sure we're in a modernish tree ---
39mdl_reldir=${MSH_MDL#"$MSH_PREFIX/"}
40is dir $mdl_reldir || chdir $MSH_PREFIX
41putln "Updating unalias for modules in $PWD/$mdl_reldir"
42
43# --- Prepare temp file ---
44mktemp -sCCt unalias_update	# 2x -C = auto-cleanup even on Ctrl+C
45mytempfile=$REPLY
46
47# --- Main loop ---
48changed=0 total=0
49LOOP find modulefile in $mdl_reldir -type f -name *.mm; DO
50	let "total += 1"
51	# Eliminate comments, get function names from lines like "funcname() {",
52	# as well as alias names from lines like 'alias name=...',
53	# and make make "_" sort last (change to "~").
54	fn_al_names=$(
55		export LC_ALL=C
56		sed -n 's/#.*//
57			/[[:alpha:]_][[:alnum:]_]*()[[:blank:]]*[{(]/ {
58				h
59				s/().*//
60				s/^.*[^[:alnum:]_]//
61				s/^_/~/
62				p
63				g
64			}
65			/alias[[:blank:]]\{1,\}[[:alnum:]_!%,@]\{1,\}=/ {
66				s/^.*alias //
67				s/=.*//
68				s/^_/~/
69				p
70			}' $modulefile |
71		sort -u |
72		sed 's/^~/_/' |
73		paste -s -d ' ' -	# combine on one line
74	)
75	str empty $fn_al_names && continue
76	if isset opt_r; then
77		message="- Removing unalias from $PWD/$modulefile"
78		script="2 { /^\\\\command unalias/ d; }"
79	else
80		message="- Updating $PWD/$modulefile:${CCn}  $fn_al_names"
81		script="2 i\\${CCn}\\\\command unalias $fn_al_names 2>/dev/null
82			2 { /^\\\\command unalias/ d; }"
83	fi
84	# (The >| operator bypasses the safe mode's noclobber check: we *want*
85	# to overwrite. Redirections cannot be covered by 'harden', so check.)
86	sed $script $modulefile >| $mytempfile || die
87	if ! cmp -s $modulefile $mytempfile; then
88		putln $message
89		cat $mytempfile >| $modulefile || die
90		let "changed += 1"
91	fi
92DONE
93putln "$changed out of $total modules updated."
94