Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Cygwin zsh and command availability



Posting this in the hope that it might prove useful to others.

Under Windows, commands run by ShellExecute() look in multiple places,
including doing a registry key lookup under:
 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\

According to MSDN, the priority ordering of ShellExecute() varies by
Windows version, but as of WinXP SP1 the App Path items come before
%PATH%.

This is how you can do things like Start->Run "firefox" and get a
web-browser, despite Firefox not being in %PATH%.

This zsh solution is not perfectly robust but it appears to work for me.
It does not favour conciseness.  Because I wanted to keep everything
safe, the script generates zsh command-lines.  Rather than re-work it,
I've decided that I'm happy with:

function load_win32_registry_paths {
	local t
	/cygdrive/X/path/to/win32_registry_paths | while read t
		do eval $t; done
}

Comments & improvements welcome.

Command dependency is "reg", which I think is a standard Windows
component; it says:
 Console Registry Tool for Windows - version 3.0
 Copyright (C) Microsoft Corp. 1981-2001.  All rights reserved

-----------------------------< cut here >-------------------------------
#!/usr/bin/zsh -f
setopt extended_glob
typeset -a regout

oIFS="$IFS"
IFS=$'\n'
regout=($(reg query \
	"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths" /s | \
	sed 's/\\/\\\\/g'))
IFS="$oIFS"

function path_convert_backslash
{
	local loc="$1"

	loc=${(Q)loc}
	loc=${loc:gs,\\,/}
# for some reason, that results in // in the result, so:
#	loc=${loc:gs,//,/}
	print -r -- ${(q)loc}
}

function path_convert_drive
{
	local loc="$1"
	loc=${(Q)loc}
	if [[ $loc == ?:* ]]
	then
		drive=${loc%%:*}
		loc="/cygdrive/${drive}${loc#?:}"
	fi
	print -r -- ${(q)loc}
}

function path_expand_var
{
# %ProgramFiles% -> $PROGRAMFILES
	local t="$1"

	while [[ $t == *%*%* ]]
	do
		local prefix suffix var
		prefix=${t%%\%*}
		var=${t#${prefix}\%}
		suffix=${var#*%}
		var=${var%%\%*}
		t="$(path_convert_backslash "${(qP)${(U)var}}")"
		t="$(path_convert_drive "$t")"
		t="${prefix}${t}${suffix}"
	done
	print -r -- $t
	return 0
}

function get_path_expanded
{
	#local src="${(p)1:gs/\t/ /}"
	local src="$1" # we actually can just split on a tab, at present
	local p t what drive
	typeset -a list newlist

	# Get the type and the rest
	list=(${(ps:\t:)src})
	what=$list[1]
	list[1]=()
	t="$(path_convert_backslash "${list[*]}")"

	# expand out <drive-letter>: for each element in the ;-list
	list=(${(s:;:)t})
	newlist=()
	for p in $list
	do
		newlist+=("$(path_convert_drive $p)")
	done
	t="${(j:;:)newlist[*]}"

	case $what in
	(REG_SZ)
		print $t
		return 0
		;;
	(REG_EXPAND_SZ)
# XXX: this probably doesn't deal well with variables whose value contains %,
# which shouldn't happen but we should protect against it anyway.
		list=()
		for p in $newlist
		do
			list+=("$(path_expand_var $p)")
		done
		print "${(j:;:)list}"
		return 0
		;;
	(*)
		print -u2 "Unhandled registry type: $what"
		;;
	esac
	return 1
}

print "zmodload -i zsh/parameter"

typeset -A state
local rest n t
for ((i=0; i < ${#regout}; i++))
do
	case ":${regout[$i]}:" in
	(:HKEY*)
		if [[ -n $state[name] && -n $state[cmd] ]]
	       	then
			n="${${(L)state[name]}%.exe}"
			if [[ -n $state[path_add] ]]
			then
				t="\"${(j:" ":)${(qs:;:)state[path_add]}}\""
				print "function $n { ( path=($t \$path); \"${state[cmd]}\" \\\"\$@\\\" ) }"
			else
				print "commands[$n]=\"${state[cmd]}\""
			fi
		fi

		state=()
		state[name]=${regout[$i]:t}
#		print "NAME: $state[name]"
		;;
	(:[[:blank:]]##\<NO NAME\>*)
		rest="${regout[$i]##[[:blank:]]##<NO NAME>}"
		state[cmd]=$(get_path_expanded $rest)
#		print " cmd: $state[cmd]"
		;;
	(:[[:blank:]]##Path[[:blank:]]*)
		rest="${regout[$i]##[[:blank:]]##Path}"
		state[path_add]=$(get_path_expanded $rest)
#		print "path: $state[path_add]"
		;;

# Alas, we lost the blank lines, so accumulate in HKEY
#	(:[[:blank:]]#:)
#		;;

	(*)
# Oooh, look at all those undocumented fields:
#   print -u2 "Unhandled registry item for ${state[name]}: $regout[$i]"
		;;
	esac
done



Messages sorted by: Reverse Date, Date, Thread, Author