|
- [CmdletBinding()]
- param(
- [Parameter()]
- [string]$SourcePath = (Join-Path $PSScriptRoot '..\app\src'),
-
- [Parameter()]
- [switch]$ShowFiles
- )
-
- Set-StrictMode -Version Latest
- $ErrorActionPreference = 'Stop'
-
- function Get-CodeLineStatistics {
- param(
- [Parameter(Mandatory)]
- [string]$FilePath
- )
-
- $statistics = [ordered]@{
- TotalLines = 0
- BlankLines = 0
- CommentOnlyLines = 0
- PreprocessorLines = 0
- CodeLines = 0
- }
- $inBlockComment = $false
- $inRawString = $false
- $rawStringTerminator = ''
-
- foreach ($line in [System.IO.File]::ReadLines($FilePath, [System.Text.UTF8Encoding]::new($false))) {
- $statistics.TotalLines++
- $index = 0
- $code = [System.Text.StringBuilder]::new()
- $containsComment = $inBlockComment
-
- while ($index -lt $line.Length) {
- if ($inRawString) {
- $terminatorIndex = $line.IndexOf($rawStringTerminator, $index, [System.StringComparison]::Ordinal)
- if ($terminatorIndex -lt 0) {
- [void]$code.Append($line.Substring($index))
- $index = $line.Length
- continue
- }
-
- [void]$code.Append($line.Substring($index, $terminatorIndex + $rawStringTerminator.Length - $index))
- $index = $terminatorIndex + $rawStringTerminator.Length
- $inRawString = $false
- continue
- }
-
- if ($inBlockComment) {
- $containsComment = $true
- $commentEnd = $line.IndexOf('*/', $index, [System.StringComparison]::Ordinal)
- if ($commentEnd -lt 0) {
- $index = $line.Length
- continue
- }
-
- $index = $commentEnd + 2
- $inBlockComment = $false
- continue
- }
-
- $current = $line[$index]
- $next = if ($index + 1 -lt $line.Length) { $line[$index + 1] } else { [char]0 }
-
- if ($current -eq '/' -and $next -eq '/') {
- $containsComment = $true
- break
- }
-
- if ($current -eq '/' -and $next -eq '*') {
- $containsComment = $true
- $inBlockComment = $true
- $index += 2
- continue
- }
-
- if ($current -eq 'R' -and $next -eq '"') {
- $delimiterStart = $index + 2
- $openParenthesis = $line.IndexOf('(', $delimiterStart)
- if ($openParenthesis -ge 0 -and $openParenthesis - $delimiterStart -le 16) {
- $delimiter = $line.Substring($delimiterStart, $openParenthesis - $delimiterStart)
- if ($delimiter -notmatch '[\s\\()]') {
- $rawStringTerminator = ')' + $delimiter + '"'
- [void]$code.Append($line.Substring($index, $openParenthesis - $index + 1))
- $index = $openParenthesis + 1
- $inRawString = $true
- continue
- }
- }
- }
-
- if ($current -eq '"' -or $current -eq "'") {
- $quote = $current
- [void]$code.Append($quote)
- $index++
- while ($index -lt $line.Length) {
- $stringCharacter = $line[$index]
- [void]$code.Append($stringCharacter)
- $index++
- if ($stringCharacter -eq '\\' -and $index -lt $line.Length) {
- [void]$code.Append($line[$index])
- $index++
- continue
- }
- if ($stringCharacter -eq $quote) {
- break
- }
- }
- continue
- }
-
- [void]$code.Append($current)
- $index++
- }
-
- $remaining = $code.ToString().Trim()
- if ([string]::IsNullOrWhiteSpace($line)) {
- $statistics.BlankLines++
- }
- elseif ($remaining.StartsWith('#')) {
- $statistics.PreprocessorLines++
- }
- elseif (-not [string]::IsNullOrWhiteSpace($remaining)) {
- $statistics.CodeLines++
- }
- elseif ($containsComment) {
- $statistics.CommentOnlyLines++
- }
- else {
- $statistics.BlankLines++
- }
- }
-
- return [pscustomobject]$statistics
- }
-
- $resolvedSourcePath = (Resolve-Path -LiteralPath $SourcePath).Path
- $files = Get-ChildItem -LiteralPath $resolvedSourcePath -Recurse -File -Filter '*.cpp' | Sort-Object FullName
- if ($files.Count -eq 0) {
- throw "未在 '$resolvedSourcePath' 找到 .cpp 文件"
- }
-
- $fileResults = foreach ($file in $files) {
- $statistics = Get-CodeLineStatistics -FilePath $file.FullName
- [pscustomobject]@{
- File = $file.FullName.Substring($resolvedSourcePath.Length).TrimStart('\', '/')
- CodeLines = $statistics.CodeLines
- TotalLines = $statistics.TotalLines
- BlankLines = $statistics.BlankLines
- CommentOnlyLines = $statistics.CommentOnlyLines
- PreprocessorLines = $statistics.PreprocessorLines
- }
- }
-
- $total = [pscustomobject]@{
- File = '合计'
- CodeLines = [int]($fileResults | Measure-Object -Property CodeLines -Sum).Sum
- TotalLines = [int]($fileResults | Measure-Object -Property TotalLines -Sum).Sum
- BlankLines = [int]($fileResults | Measure-Object -Property BlankLines -Sum).Sum
- CommentOnlyLines = [int]($fileResults | Measure-Object -Property CommentOnlyLines -Sum).Sum
- PreprocessorLines = [int]($fileResults | Measure-Object -Property PreprocessorLines -Sum).Sum
- }
-
- Write-Host "扫描目录: $resolvedSourcePath"
- Write-Host "统计范围: $($files.Count) 个 .cpp 文件,不统计 .h;移除注释及 # 预处理指令后统计代码行"
- Write-Host "总行数: $($total.TotalLines)"
- Write-Host "纯 C++ 代码: $($total.CodeLines) 行"
- Write-Host "空白行: $($total.BlankLines) | 纯注释行: $($total.CommentOnlyLines) | 预处理行: $($total.PreprocessorLines)"
-
- if ($ShowFiles) {
- $fileResults | Format-Table File, CodeLines, TotalLines, BlankLines, CommentOnlyLines, PreprocessorLines -AutoSize
- }
|