#compdef truncate

local curcontext=$curcontext variant rs ret=1
local -a state state_descr line specs optA
typeset -A opt_args

_pick_variant -r variant gnu='(GNU|uutils)' $OSTYPE --version
[[ $variant != gnu ]] && rs='-r -s' # -r/-s mutually exclusive

# common specs
specs=(
  '(hv -c --no-create)'{-c,--no-create}'[do not create any files]'
  "(hv $rs -r --reference)"{-r+,--reference=}'[base size on the specified file]:reference file:_files'
  "(hv $rs -s --size)"{-s+,--size=}'[set or adjust the file size by specified bytes]:size:->size'
  '(hv)*: :_files'
)

case $variant in
  gnu) # GNU coreutils 8.32
    specs+=(
      '(hv -o --io-blocks)'{-o,--io-blocks}'[treat the specified size as number of IO blocks instead of bytes]'
      + 'hv'
      '(- *)--help[display help and exit]'
      '(- *)--version[output version information and exit]'
    )
    ;;
  *) # FreeBSD/DragonFly
    specs=( ${specs:#(|*\))--*} )    # remove long options
    optA=( -A '-*' )
    ;;
esac

_arguments -C -s -S : $specs && ret=0

case $state in
  size)
    local unit=bytes
    (( ${#opt_args[(I)(-o|--io-blocks)]} )) && unit=blocks
    local -a suffix=( K:1024 M G T )
    local -a prefix=( '+:extend by' '-:reduce by' )
    local prefix_char='[-+]'
    case $variant in
      gnu|freebsd*)
	prefix+=( '/:round down to multiple of' '%:round up to multiple of' )
	;|
      gnu)
	suffix=( K:1024 KB:1000 {M,G,T,P,E,Z,Y}{,B} )
	prefix+=( '<:at most' '>:at least' )
	prefix_char='([-+/%]|\\[<>])'
	;;
      freebsd*)
	prefix_char='[-+/%]'
	;;
    esac
    local -a numbers=( _numbers -u $unit size $suffix )

    if compset -P "$prefix_char"; then
      $numbers && ret=0
    elif (( ${#opt_args[(I)(-r|--reference)]} )); then
      # prefix is required if the reference file is given
      _describe -t 'prefixes' 'prefix' prefix && ret=0
    else
      _alternative "prefixes:prefix:((${(@q)prefix}))" \
      		   "sizes: :$numbers" && ret=0
    fi
  ;;
esac

return ret
