zsh-users
 help / color / mirror / code / Atom feed
From: Phil Pennock <phil.pennock@globnix.org>
To: zsh-users@sunsite.dk
Subject: Cygwin zsh and command availability
Date: Sat, 4 Mar 2006 20:37:33 +0100	[thread overview]
Message-ID: <20060304193733.GA22944@parhelion.globnix.org> (raw)

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


                 reply	other threads:[~2006-03-04 19:37 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20060304193733.GA22944@parhelion.globnix.org \
    --to=phil.pennock@globnix.org \
    --cc=zsh-users@sunsite.dk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).