
function __fish_umask_parse -d "Internal umask function"
	# Test if already a valid octal mask, and pad it with zeros
	if echo $argv | sgrep -E '^0?[0-7]{1,3}$' >/dev/null
		set -l char_count (echo $argv| wc -c)
		for i in (seq (math 5 - $char_count)); set argv 0$argv; end
		echo $argv
	else
		# Test if argument really is a valid symbolic mask
		if not echo $argv | sgrep -E '^(((u|g|o|a|)(=|\+|-)|)(r|w|x)*)(,(((u|g|o|a|)(=|\+|-)|)(r|w|x)*))*$' >/dev/null
			printf (_ "%s: Invalid mask '%s'\n") umask $argv >&2
			return 1
		end

		set -l implicit_all

		# Insert inverted umask into res variable

		set -l mode
		set -l val
		set -l tmp $umask
		set -l res

		for i in 1 2 3
			set tmp (echo $tmp|cut -c 2-)
			set -l char_count (echo $tmp|cut -c 1)
			set res[$i] (math 7 - $char_count)
		end

		set -l el (echo $argv|tr , \n)
		for i in $el
			switch $i
				case 'u*'
					set idx 1
					set i (echo $i| cut -c 2-)

				case 'g*'
					set idx 2
					set i (echo $i| cut -c 2-)

				case 'o*'
					set idx 3
					set i (echo $i| cut -c 2-)

				case 'a*'
					set idx 1 2 3
					set i (echo $i| cut -c 2-)

				case '*'
					set implicit_all 1
					set idx 1 2 3
			end

			switch $i
				case '=*'
					set mode set
					set i (echo $i| cut -c 2-)

				case '+*'
					set mode add
					set i (echo $i| cut -c 2-)

				case '-*'
					set mode remove
					set i (echo $i| cut -c 2-)

				case '*'
					if not count $implicit_all >/dev/null
						printf (_ "%s: Invalid mask '%s'\n") umask $argv >&2
						return
					end
					set mode set
			end

			if not echo $perm|sgrep -E '^(r|w|x)*$' >/dev/null
				printf (_ "%s: Invalid mask '%s'\n") umask $argv >&2
				return
			end

			set val 0
			if echo $i |sgrep 'r' >/dev/null
				set val 4
			end
			if echo $i |sgrep 'w' >/dev/null
				set val (math $val + 2)
			end
			if echo $i |sgrep 'x' >/dev/null
				set val (math $val + 1)
			end

			for j in $idx
				switch $mode
					case set
						 set res[$j] $val

					case add
						set res[$j] (perl -e 'print( ( '$res[$j]'|'$val[$j]' )."\n" )')

					case remove
						set res[$j] (perl -e 'print( ( (7-'$res[$j]')&'$val[$j]' )."\n" )')
				end
			end
		end

		for i in 1 2 3
			set res[$i] (math 7 - $res[$i])
		end
		echo 0$res[1]$res[2]$res[3]
	end
end

function __fish_umask_print_symbolic
	set -l res ""
	set -l letter a u g o

	for i in 2 3 4
		set res $res,$letter[$i]=
		set val (echo $umask|cut -c $i)

		if contains $val 0 1 2 3
			set res {$res}r
		end

		if contains $val 0 1 4 5
			set res {$res}w
		end

		if contains $val 0 2 4 6
			set res {$res}x
		end

	end

	echo $res|cut -c 2-
end

function umask --description "Set default file permission mask"

	set -l as_command 0
	set -l symbolic 0
	
	set -l options
	set -l shortopt pSh
	if not getopt -T >/dev/null
		# GNU getopt
		set longopt -l as-command,symbolic,help
		set options -o $shortopt $longopt --
		# Verify options
		if not getopt -n umask $options $argv >/dev/null
			return 1
		end
	else
		# Old getopt, used on OS X
		set options $shortopt
		# Verify options
		if not getopt $options $argv >/dev/null
			return 1
		end
	end

	set -l tmp (getopt $options $argv)
	eval set opt $tmp

	while count $opt >/dev/null

		switch $opt[1]
			case -h --help
				__fish_print_help umask
				return 0

			case -p --as-command
				set as_command 1

			case -S --symbolic
				set symbolic 1

			case --
				set -e opt[1]
				break

		end

		set -e opt[1]

	end

	switch (count $opt)

		case 0
			if not set -q umask
				set -g umask 113
			end
			if test $as_command -eq 1
				echo umask $umask
			else
				if test $symbolic -eq 1
					__fish_umask_print_symbolic $umask
				else
					echo $umask
				end
			end

		case 1
			set -l parsed (__fish_umask_parse $opt)
			if test (count $parsed) -eq 1
				set -g umask $parsed
				return 0
			end
			return 1

		case '*'
			printf (_ '%s: Too many arguments\n') umask >&2

	end

end
