Utils/pathchk.ps1

Register-GnuUtil @{
    Name        = 'pathchk'
    Category    = 'Paths and names'
    Synopsis    = 'Check whether file names are valid or portable.'
    Usage       = @('pathchk [OPTION]... NAME...')
    Description = @('Diagnose invalid or non-portable file names.')
    Options     = @(
        @{ Short = 'p'; Key = 'posix'; Help = 'check for most POSIX systems' }
        @{ Short = 'P'; Key = 'extra'; Help = 'check for empty names and leading "-"' }
        @{ Long = 'portability'; Sets = @{ posix = 1; extra = 1 }; Help = 'check for all POSIX systems (equivalent to -p -P)' }
    )
    Notes       = @('PowerShell note: without -p the limits are 255 bytes per component and 4096 bytes per name.')
}



function script:Test-GnuPathName {
    <#
    .SYNOPSIS
    Returns the first problem of a file name as a GNU message, or nothing if the name is fine.
    #>

    param(
        [Parameter(Mandatory)][AllowEmptyString()][string]$Name,
        [switch]$Posix,
        [switch]$Extra
    )

    if ($Extra) {
        if ($Name.Length -eq 0) { return 'empty file name' }
        foreach ($component in $Name.Split('/')) {
            if ($component.StartsWith('-', [System.StringComparison]::Ordinal)) { return "leading '-' in a component of file name '$Name'" }
        }
    }
    elseif ($Name.Length -eq 0) {
        # GNU without -P: an empty name does not exist, like "pathchk ''" -> No such file or directory
        return "'': No such file or directory"
    }

    if ($Posix) {
        foreach ($char in $Name.ToCharArray()) {
            if ($char -cnotmatch '[A-Za-z0-9._/-]') { return "nonportable character '$char' in file name '$Name'" }
        }
    }

    $nameLimit = 4096
    $componentLimit = 255
    if ($Posix) {
        $nameLimit = 256
        $componentLimit = 14
    }
    $nameLength = $script:GnuUtf8.GetByteCount($Name)
    if ($nameLength -gt $nameLimit) { return "limit $nameLimit exceeded by length $nameLength of file name '$Name'" }
    foreach ($component in $Name.Split('/')) {
        $length = $script:GnuUtf8.GetByteCount($component)
        if ($length -gt $componentLimit) { return "limit $componentLimit exceeded by length $length of file name component '$component'" }
    }
}