humanReadable <- function(x,
                          units="auto",
                          standard=c("IEC", "SI", "Unix"),
                          digits=1,
                          width=NULL,
                          sep=" ",
                          justify = c("right", "left")
                          )
{
  ## --- Setup ---

  suffix.SI   <- c("B",  "kB",  "MB",  "GB",  "TB",  "PB",  "EB",  "ZB",  "YB")
  suffix.IEC  <- c("B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB")
  suffix.Unix <- c("B" ,  "K",   "M",   "G",   "T",   "P",   "E",   "Z",   "Y")

  standard <- match.arg(standard)
  if(length(justify)==1) justify <- c(justify, justify)

  ## --- Functions ---

  .applyHuman <- function(x, base, suffix, digits, width, sep)
  {
    ## Which suffix should we use?
    n <- length(suffix)
    i <- pmax(pmin(floor(log(x, base)), n-1),0)
    if(!is.finite(i)) i <- 0
    x <- x / base^i
    ## Formatting
    if(is.null(width))
        ## the same formatting for all
        x <- format(round(x=x, digits=digits), nsmall=digits)
    else
        {
            ## similar to ls, du, and df
            lenX <- nchar(x)
            if(lenX > width) {
                digits <- pmax( width - nchar(round(x)) - 1, 0)
            }
            if(i == 0) digits <- 0
            x <- round(x, digits=digits)
        }
    c(x, suffix[i+1])
  }

  ## -- Work

  if(any(x < 0)) stop("'x' must be positive")
  if(standard == "SI")
      {
          suffix <- suffix.SI
          base <- 10^3
      }
  else if (standard=="IEC")
      {
          suffix <- suffix.IEC
          base <- 2^10
      }
  else # (standard=="Unix)
      {
          suffix <- suffix.Unix
          base <- 2^10
      }

  if(!missing(units) && units=="bytes")
      {
          retval <- rbind(x, "bytes")
      }
  else if(!missing(units) && units!="auto")
      {
          units <- suffix[match( toupper(units), toupper(suffix) )]
          power <- match(units, suffix ) -1
          X <- x/(base^power)
          X <- format.default(x=X, digits=digits, nsmall=digits)
          retval <- rbind(X, rep(units, length(X)))
      }
  else
      retval <- sapply(X=x, FUN=".applyHuman", base=base, suffix=suffix,
                       digits=digits, width=width, sep=sep)

  if(all(justify == "none"))
      paste(trim(retval[1,]), trim(retval[2,]), sep=sep)
  else
      paste(format(trim(retval[1,]), justify=justify[1]),
            format(trim(retval[2,]), justify=justify[2]),
            sep=sep)

}

