1#!/usr/local/bin/zsh
2#
3# NAME:
4#	reporter
5#
6# SYNOPSIS:
7#	reporter [all | aliases | bindings | completion | functions |
8#			limits | options | variables | zstyles]
9#
10# DESCRIPTION:
11#	"reporter" prints your current environment variables, shell
12#	variables, limits, completion settings, and option settings to
13#	stdout in the form of a script.
14#
15#	If you run into a zsh bug, someone can source the output script to
16#	recreate most of the environment under which you were working.
17#
18#	IMPORTANT:	"source" this script, don't try to run it directly.
19#			Otherwise it won't report the settings for your
20#			current shell session.
21#
22# OPTIONS:
23#	All command-line options can be abbreviated.
24#
25#	"aliases"	prints only aliases.
26#	"bindings"	prints only "bindkey" commands.
27#	"completion"	prints only "compctl" commands.
28#	"functions"	prints "autoload" commands or actual functions.
29#	"limits"	prints "limit" commands for things like cputime, etc.
30#	"modules"	prints "zmodload" commands.
31#	"options"	prints "setopt" commands.
32#	"variables"	prints both shell and environment variables.
33#	"zstyles"	prints "zstyle" commands
34#
35#	"all"		tries to find every useful setting under your shell.
36#			This is the default, and it's the same as typing all
37#			of the above options on the command line.
38#
39# CAVEATS:
40#	Assumes that you have the following programs in your search path:
41#		awk, cut, echo, grep, sed, sort
42#	Assumes that your C preprocessor lives in /lib/cpp or /usr/ccs/lib/cpp.
43#	Uses (and unsets) variables beginning with "reporter_".
44#	Won't work for versions of zsh that are older than 3.1.3 or so.
45#
46# RESTRICTIONS:
47#	DON'T:	pretend you wrote it, sell it, or blame me if it breaks.
48#	DO:	as ye will an' ye harm none.
49#					--Wiccan saying, I think
50#
51# BUGS:
52#	I'm sure there are more than a few.  To be safe, run "zsh -f" before
53#	sourcing the output from this script.  If you have "screen", you may
54#	want to use that, too; I hammered my terminal settings beyond repair
55#	when using an early version, and "screen" saved me from having to
56#	login on another terminal.
57#
58# HISTORY:
59#	The name was ripped off from the Emacs "reporter.el" function.
60#	The idea came from a mail message to the ZSH mailing list:
61#
62# Begin Configuration Section
63#
64
65reporter_OSVersion="`uname -s`_`uname -r`"
66
67#
68# Solaris 2.x
69#
70case ${reporter_OSVersion} in
71	SunOS_5.*)
72		CPP=${CPP:-/usr/ccs/lib/cpp}
73		AWK=${AWK:-nawk}	# GNU AWK doesn't come standard :-(
74		;;
75esac
76
77#
78# Default Values 
79#
80
81CPP=${CPP:-/lib/cpp}
82AWK=${AWK:-awk}
83
84#
85# End Configuration Section
86#
87
88reporter_do_all=yes
89
90for reporter_each
91do
92	case "$reporter_each"
93	in
94		ali*)	reporter_do_aliases=yes; reporter_do_all=no ;;
95		b*)	reporter_do_bindings=yes; reporter_do_all=no ;;
96		c*)	reporter_do_compctl=yes; reporter_do_all=no ;;
97		f*)	reporter_do_fun=yes; reporter_do_all=no ;;
98		l*)	reporter_do_lim=yes; reporter_do_all=no ;;
99		m*)	reporter_do_mod=yes; reporter_do_all=no ;;
100		o*)	reporter_do_setopt=yes; reporter_do_all=no ;;
101		v*)	reporter_do_vars=yes; reporter_do_all=no ;;
102		zs*|s*)	reporter_do_zstyle=yes; reporter_do_all=no ;;
103		*)	;;
104	esac
105done
106
107#
108#	The "cshjunkiequotes" option can break some of the commands
109#	used in the remainder of this script, so we check for that first
110#	and disable it.  Similarly "shwordsplit" and "kshoptionprint".
111#	We'll re-enable them later.
112#
113
114reporter_junkiequotes="no"
115reporter_shwordsplit="no"
116reporter_kshoptprint="no"
117reporter_nounset="no"
118
119if [[ -o cshjunkiequotes ]]
120then
121	reporter_junkiequotes="yes"
122	unsetopt cshjunkiequotes
123fi
124if [[ -o shwordsplit ]]
125then
126	reporter_shwordsplit="yes"
127	unsetopt shwordsplit
128fi
129if [[ -o kshoptionprint ]]
130then
131	reporter_kshoptprint="yes"
132	unsetopt kshoptionprint
133fi
134if [[ -o nounset ]]
135then
136	reporter_nounset="yes"
137	unsetopt nounset
138fi
139
140#
141#	UNAME
142#
143#	This shows your system name.  It's extremely system-dependent, so
144#	we need a way to find out what system you're on.  The easiest
145#	way to do this is by using "uname", but not everyone has that,
146#	so first we go through the search path.
147#
148#	If we don't find it, then the only thing I can think of is to
149#	check what's defined in your C compiler, and code in some exceptions
150#	for the location of "uname" or an equivalent.  For example, Pyramid
151#	has "uname" only in the ATT universe.  This code assumes that
152#	the "-a" switch is valid for "uname".
153#
154#	This section of code sees what is defined by "cpp".  It was
155#	originally written by brandy@tramp.Colorado.EDU (Carl Brandauer).
156#	Additional error checking and sed hacking added by Ken Phelps.
157#
158
159reporter_cppdef=(`strings -3 ${CPP} |
160	sed -n '
161	/^[a-zA-Z_][a-zA-Z0-9_]*$/{
162	s/.*/#ifdef &/p
163	s/.* \(.*\)/"\1";/p
164	s/.*/#endif/p
165	}
166	' | ${CPP} |sed '
167	/^[	 ]*$/d
168	/^#/d
169	s/.*"\(.*\)".*/\1/'`)
170
171reporter_uname=""
172
173for reporter_each in `echo $PATH | sed -e 's/:/ /g'`
174do
175	if [[ -x $reporter_each/uname ]]
176	then
177		reporter_uname="$reporter_each/uname"
178		break
179	fi
180done
181
182case "$reporter_uname"
183in
184	"")	reporter_uname="echo not found on this system" ;;
185	*)	;;
186esac
187
188for reporter_each in $reporter_cppdef
189do
190	case "$reporter_each"
191	in
192		pyr)	reporter_uname="/bin/att uname" ;;
193		*)	;;
194	esac
195done
196
197echo '# START zsh saveset'
198echo '# uname: ' `eval $reporter_uname -a`
199echo
200
201unset reporter_cppdef
202unset reporter_uname
203unset reporter_each
204
205#
206#	ALIASES
207#
208#	Use "alias -L" to get a listing of the aliases in the form we want.
209#
210
211if [[ "$reporter_do_all" = "yes" || "$reporter_do_aliases" = "yes" ]]
212then
213	echo '# Aliases.'
214	echo
215
216	alias -L
217fi
218
219#
220#	KEY BINDINGS
221#
222#	The -L option does most of the work.  The subshell is used to
223#	avoid modifying things that will be recorded later.
224#
225
226if [[ "$reporter_do_all" = "yes" || "$reporter_do_bindings" = "yes" ]]
227then
228	echo
229	echo "# Key bindings."
230	echo
231	bindkey -lL | grep -v ' \.safe$'
232	(
233		alias bindkey=bindkey
234		bindkey () {
235			[[ "$1" == "-N" ]] || return
236			[[ "$2" == "--" ]] && shift
237			[[ "$2" == ".safe" ]] && return
238			echo
239			builtin bindkey -L -M -- "$2"
240		}
241		eval "`builtin bindkey -lL`"
242	)
243fi
244
245#
246#	COMPLETION COMMANDS
247#	Warning:  this won't work for zsh-2.5.03.
248#
249
250if [[ "$reporter_do_all" = "yes" || "$reporter_do_compctl" = "yes" ]]
251then
252	echo
253	echo "# Completions."
254	echo
255
256	compctl -L
257fi
258
259#
260#	FUNCTIONS
261#
262
263if [[ "$reporter_do_all" = "yes" || "$reporter_do_fun" = "yes" ]]
264then
265	echo 
266	echo "# Undefined functions."
267	echo
268
269	autoload + | ${AWK} '{print "autoload " $1}'
270
271	echo 
272	echo "# Defined functions."
273	echo
274
275	(
276		unfunction `autoload +` 2>/dev/null
277		functions
278	)
279fi
280
281#
282#	LIMITS
283#
284#	"cputime" has to be handled specially, because you can specify
285#	the time as just hours, or "minutes:seconds".
286#
287
288if [[ "$reporter_do_all" = "yes" || "$reporter_do_lim" = "yes" ]]
289then
290	echo
291	echo '# Limits.'
292	echo
293
294	(
295		set X `limit | grep "cputime" | grep -v "unlimited" |
296			sed -e 's/:/ /g'`
297
298		if test "$#" -gt 1
299		then
300			hr=$3
301			min=$4
302			sec=$5
303
304			if test "$hr" -gt 0
305			then
306				echo "limit cputime ${hr}h"
307			else
308				echo "limit cputime $min:$sec"
309			fi
310		fi
311	)
312
313	limit | grep -v "cputime" | grep -v "unlimited" |
314		sed -e 's/Mb/m/' -e 's/Kb/k/' |
315		${AWK} 'NF > 1 {print "limit " $0}'
316fi
317
318#
319#	MODULE LOADING COMMANDS
320#
321
322if [[ "$reporter_do_all" = "yes" || "$reporter_do_mod" = "yes" ]]
323then
324	echo
325	if ( zmodload ) >& /dev/null; then
326		echo "# Modules."
327		echo
328		zmodload -d -L
329		echo
330		zmodload -ab -L
331		echo
332		zmodload -ac -L
333		echo
334		zmodload -ap -L
335		echo
336		zmodload -L
337	else
338		echo "# Modules: zmodload not available."
339	fi
340fi
341
342#
343#	NON-ARRAY VARIABLES
344#
345#	We run this in a subshell to preserve the parameter module state
346#	in the current shell.  Also, reset the prompt to show you're now
347#	in a test shell.
348#
349
350if [[ "$reporter_do_all" = "yes" || "$reporter_do_vars" = "yes" ]]
351then
352	echo
353	echo "# Non-array variables."
354	echo
355
356	(
357		zmodload -u `zmodload | grep parameter` 2>/dev/null
358
359		echo "ARGC=0"
360		eval `typeset + |
361			grep -v 'array ' |
362			grep -v 'association ' |
363			grep -v 'undefined ' |
364			grep -v ' ARGC$' |
365			grep -v '^reporter_' |
366			grep -wv '[!#$*0?@_-]$' |
367			sed -e 's/.* \(.*\)/print -r -- \1=${(qq)\1};/' \
368			    -e 's/^\([^ ]*\)$/print -r -- \1=${(qq)\1};/'`
369		echo "prompt='test%'"
370	)
371
372#
373#	ARRAY VARIABLES
374#
375#	Run this in a subshell to preserve the parameter module state in
376#	the current shell.
377#
378
379	echo
380	echo "# Array variables."
381	echo
382
383	(
384		zmodload -u `zmodload | grep parameter` 2>/dev/null
385
386		echo "argv=()"
387		eval `{ typeset + | grep 'array ' ;
388				typeset + | grep 'association ' } |
389			grep -v 'undefined ' |
390			grep -v ' argv$' |
391			grep -v ' reporter_' |
392			grep -v ' [!#$*0?@_-]$' |
393			sed 's/.* \(.*\)/print -r -- \1=\\\(${(qq)\1}\\\);/'`
394	)
395
396#
397#	EXPORTED VARIABLES
398#
399#	Run this in a subshell to preserve the parameter module state in
400#	the current shell.
401#
402
403	echo
404	echo "# Exported variables."
405	echo
406
407	(
408		zmodload -u `zmodload | grep parameter` 2>/dev/null
409
410		export | grep -v "^'*"'[!#$*0?@_-]'"'*=" |
411			${AWK} -F'=' '{print "export " $1}'
412	)
413fi
414
415#
416#	SETOPT
417#
418#	We exclude interactive because "setopt interactive" has no effect.
419#	A few special options are dealt with separately; see the comments
420#	near the start of the script.
421#
422
423if [[ "$reporter_do_all" = "yes" || "$reporter_do_setopt" = "yes" ]]
424then
425	echo
426	echo '# Setopt.'
427	echo
428
429	(
430		setopt | grep -v 'interactive' | ${AWK} '{print "setopt " $0}'
431
432		case "$reporter_junkiequotes"
433		in
434			yes)	echo "setopt cshjunkiequotes" ;;
435			*)	;;
436		esac
437		case "$reporter_shwordsplit"
438		in
439			yes)	echo "setopt shwordsplit" ;;
440			*)	;;
441		esac
442		case "$reporter_kshoptprint"
443		in
444			yes)	echo "setopt kshoptionprint" ;;
445			*)	;;
446		esac
447		case "$reporter_nounset"
448		in
449			yes)	echo "setopt nounset" ;;
450			*)	;;
451		esac
452	) | sort
453fi
454
455#
456#	STYLES
457#
458
459if [[ "$reporter_do_all" = "yes" || "$reporter_do_zstyle" = "yes" ]]
460then
461	echo
462	echo '# Styles.'
463	echo
464
465	zstyle -L
466fi
467
468echo
469echo '# END zsh saveset'
470
471#
472#	Don't put an exit here, or you'll get a nasty surprise when you
473#	source this thing.  Get rid of variables created when processing
474#	command line.
475#
476
477unset reporter_do_all
478unset reporter_do_aliases
479unset reporter_do_bindings
480unset reporter_do_compctl
481unset reporter_do_fun
482unset reporter_do_lim
483unset reporter_do_setopt
484unset reporter_do_vars
485
486#
487#	Turn various options back on if necessary, in case run via ".".
488#
489
490case "$reporter_junkiequotes"
491in
492	yes)	setopt cshjunkiequotes ;;
493	*)	;;
494esac
495case "$reporter_shwordsplit"
496in
497	yes)	setopt shwordsplit ;;
498	*)	;;
499esac
500case "$reporter_kshoptprint"
501in
502	yes)	setopt kshoptionprint ;;
503	*)	;;
504esac
505case "$reporter_nounset"
506in
507	yes)	setopt nounset ;;
508	*)	;;
509esac
510
511unset reporter_junkiequotes
512unset reporter_shwordsplit
513unset reporter_kshoptprint
514unset reporter_nounset
515
516unset reporter_OSVersion
517