Removes the "-unix" element and with it any trademark exposure to The
Open Group.
The split follows the ecosystem layout: SchOS is the system, and the
kernel has its own name. Kernel-identity strings are the only places
that take SchIFT -- uname(2) sysname, /proc/version, and the two licence
sentences that say "kernel" outright. That is what every Unix does here:
`uname -s` on Linux reports the kernel, not the distribution. Everything
a user reads as the product -- panic screen, boot menu, error prefixes,
docs, LICENSE, NOTICE -- is SchOS.
schunix.img is schos.img, the logo assets and the musl TLS patch are
renamed, and __SCHUNIX__ is __SCHOS__ (the define and the patch that
consumes it moved together).
Two things the rename broke, both found by the bootcheck suite:
- shmtest wrote "SCHUNIX-MMAP-OK" with a hardcoded length of 15 and
compared it back by hand-counted offsets (m[3]=='U', m[14]=='K').
The shorter marker left the write running two bytes past the literal
and the compare reading past the data, failing a file-backed mmap
that was working correctly. Now written and compared through one
constant with sizeof.
- bootcheck asserted a 31-byte file after appending to
"hello-from-schunix"; the shorter string makes it 29.
Both are the same mistake: a string literal whose length is written out
somewhere else. Full suite green -- base, Tty, Ps, Sock, Fb, Usb, Evdev.
200 lines
8.8 KiB
PowerShell
200 lines
8.8 KiB
PowerShell
# How much of SchOS is actually SchOS.
|
|
#
|
|
# `wc -l` over the whole tree answers a question nobody asked: it counts musl,
|
|
# toybox, mksh and a NetBSD checkout, which between them are
|
|
# two orders of magnitude larger than this project and none of them ours. This
|
|
# counts only first-party code, and separates the code from the comments so the
|
|
# number means something.
|
|
#
|
|
# tools\loc.ps1 the summary table
|
|
# tools\loc.ps1 -PerFile every file, largest first
|
|
# tools\loc.ps1 -All include third-party trees, for comparison
|
|
#
|
|
# Comment detection is deliberately simple: it handles // and /* */ for C and
|
|
# # for scripts, and does not try to understand a // inside a string literal.
|
|
# That is worth being honest about -- the comment ratio is indicative, not
|
|
# exact. The line and byte counts are exact.
|
|
|
|
param(
|
|
[switch]$PerFile,
|
|
[switch]$All,
|
|
[int]$Top = 30
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$root = Split-Path $PSScriptRoot -Parent
|
|
|
|
# What counts as ours. Everything else in the tree is either somebody else's
|
|
# source or generated output, and mixing either in makes the total meaningless.
|
|
$areas = [ordered]@{
|
|
'kernel' = 'kernel'
|
|
'include' = 'include'
|
|
'boot' = 'boot'
|
|
'lib' = 'lib'
|
|
'cmd' = 'cmd'
|
|
'tools' = 'tools'
|
|
'docs' = 'docs'
|
|
'projects' = 'projects'
|
|
}
|
|
if ($All) {
|
|
$areas['ports (3rd party)'] = 'ports'
|
|
$areas['src-trunk (NetBSD)'] = 'src-trunk'
|
|
}
|
|
|
|
# Source only. Images, fonts-as-data and upstream tarballs are not code.
|
|
$exts = @('.c', '.h', '.S', '.s', '.ld', '.inc', '.ps1', '.sh', '.pl', '.py', '.md', '.mk')
|
|
|
|
function Measure-Area([string]$rel) {
|
|
$dir = Join-Path $root $rel
|
|
$res = [PSCustomObject]@{
|
|
Area = $rel; Files = 0; Lines = 0; Code = 0; Comment = 0; Blank = 0
|
|
Bytes = 0; NonWs = 0; Alpha = 0; Digit = 0; Files_ = @()
|
|
}
|
|
if (-not (Test-Path $dir)) { return $res }
|
|
|
|
Get-ChildItem -Path $dir -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object {
|
|
$f = $_
|
|
if ($exts -notcontains $f.Extension.ToLower()) { return }
|
|
# Makefiles have no extension; picked up separately below.
|
|
$text = [System.IO.File]::ReadAllText($f.FullName)
|
|
$lines = $text -split "`r?`n"
|
|
# A trailing newline produces one empty element; do not count it.
|
|
if ($lines.Length -gt 0 -and $lines[-1] -eq '') { $lines = $lines[0..($lines.Length-2)] }
|
|
|
|
$code = 0; $comment = 0; $blank = 0
|
|
$inBlock = $false
|
|
$isC = @('.c','.h','.s','.ld','.inc') -contains $f.Extension.ToLower()
|
|
foreach ($l in $lines) {
|
|
$t = $l.Trim()
|
|
if ($t -eq '') { $blank++; continue }
|
|
if ($inBlock) {
|
|
$comment++
|
|
if ($t -match '\*/') { $inBlock = $false }
|
|
continue
|
|
}
|
|
if ($isC) {
|
|
if ($t.StartsWith('//')) { $comment++; continue }
|
|
if ($t.StartsWith('/*')) {
|
|
$comment++
|
|
if ($t -notmatch '\*/') { $inBlock = $true }
|
|
continue
|
|
}
|
|
} elseif ($t.StartsWith('#') -and $f.Extension -ne '.md') {
|
|
$comment++; continue
|
|
}
|
|
$code++
|
|
}
|
|
|
|
$nonWs = ($text.ToCharArray() | Where-Object { -not [char]::IsWhiteSpace($_) }).Count
|
|
$alpha = ($text.ToCharArray() | Where-Object { [char]::IsLetter($_) }).Count
|
|
$digit = ($text.ToCharArray() | Where-Object { [char]::IsDigit($_) }).Count
|
|
|
|
$res.Files++
|
|
$res.Lines += $lines.Length
|
|
$res.Code += $code
|
|
$res.Comment += $comment
|
|
$res.Blank += $blank
|
|
$res.Bytes += $f.Length
|
|
$res.NonWs += $nonWs
|
|
$res.Alpha += $alpha
|
|
$res.Digit += $digit
|
|
$res.Files_ += [PSCustomObject]@{
|
|
Path = $f.FullName.Substring($root.Length + 1)
|
|
Lines = $lines.Length; Code = $code; Comment = $comment
|
|
}
|
|
}
|
|
return $res
|
|
}
|
|
|
|
$results = @()
|
|
foreach ($k in $areas.Keys) { $results += (Measure-Area $areas[$k]) }
|
|
|
|
# The top-level Makefile has no extension, so it is added by hand rather than
|
|
# widening the extension list and dragging in every stray file in the tree.
|
|
$mk = Join-Path $root 'Makefile'
|
|
if (Test-Path $mk) {
|
|
$mkLines = ([System.IO.File]::ReadAllText($mk) -split "`r?`n")
|
|
$r = $results | Where-Object { $_.Area -eq 'tools' } | Select-Object -First 1
|
|
if ($r) {
|
|
$r.Files++; $r.Lines += $mkLines.Length; $r.Bytes += (Get-Item $mk).Length
|
|
$r.Code += ($mkLines | Where-Object { $_.Trim() -ne '' -and -not $_.Trim().StartsWith('#') }).Count
|
|
$r.Comment += ($mkLines | Where-Object { $_.Trim().StartsWith('#') }).Count
|
|
$r.Blank += ($mkLines | Where-Object { $_.Trim() -eq '' }).Count
|
|
}
|
|
}
|
|
|
|
$fmt = @(
|
|
@{ N='Area'; E={$_.Area} }
|
|
@{ N='Files'; E={$_.Files}; A='right' }
|
|
@{ N='Lines'; E={'{0:N0}' -f $_.Lines}; A='right' }
|
|
@{ N='Code'; E={'{0:N0}' -f $_.Code}; A='right' }
|
|
@{ N='Comment'; E={'{0:N0}' -f $_.Comment}; A='right' }
|
|
@{ N='Blank'; E={'{0:N0}' -f $_.Blank}; A='right' }
|
|
@{ N='Cmt%'; E={ if ($_.Code + $_.Comment) { '{0:N0}%' -f (100 * $_.Comment / ($_.Code + $_.Comment)) } else { '-' } }; A='right' }
|
|
@{ N='Ln/File'; E={ if ($_.Files) { '{0:N0}' -f ($_.Lines / $_.Files) } else { '-' } }; A='right' }
|
|
@{ N='KiB'; E={'{0:N0}' -f ($_.Bytes / 1KB)}; A='right' }
|
|
)
|
|
|
|
Write-Host ''
|
|
Write-Host ' SchOS — first-party source' -ForegroundColor Cyan
|
|
Write-Host ''
|
|
Write-Host (($results | Where-Object { $_.Files -gt 0 } | Sort-Object Lines -Descending | Format-Table $fmt -AutoSize | Out-String))
|
|
|
|
# Two totals, because they answer different questions and conflating them
|
|
# flatters the number. "The OS" is what boots and runs on the machine; docs,
|
|
# host-side tools and the projects/ stubs are first-party but are not SchOS
|
|
# running on hardware. Linux 0.01's 10,239 lines were kernel, headers and boot
|
|
# -- no documentation and no build tooling -- so only the first total is a fair
|
|
# comparison.
|
|
$osAreas = @('kernel','include','boot','lib','cmd')
|
|
$own = $results | Where-Object { $_.Area -notin @('ports','src-trunk') }
|
|
$os = $results | Where-Object { $_.Area -in $osAreas }
|
|
$T = ($own | Measure-Object -Property Lines -Sum).Sum
|
|
$C = ($own | Measure-Object -Property Code -Sum).Sum
|
|
$M = ($own | Measure-Object -Property Comment -Sum).Sum
|
|
$B = ($own | Measure-Object -Property Blank -Sum).Sum
|
|
$F = ($own | Measure-Object -Property Files -Sum).Sum
|
|
$By = ($own | Measure-Object -Property Bytes -Sum).Sum
|
|
$NW = ($own | Measure-Object -Property NonWs -Sum).Sum
|
|
$AL = ($own | Measure-Object -Property Alpha -Sum).Sum
|
|
$DG = ($own | Measure-Object -Property Digit -Sum).Sum
|
|
|
|
Write-Host (' {0,-22} {1,12:N0}' -f 'Files', $F)
|
|
Write-Host (' {0,-22} {1,12:N0}' -f 'Lines total', $T)
|
|
Write-Host (' {0,-22} {1,12:N0} {2:N0}%' -f ' of which code', $C, (100 * $C / [Math]::Max($T,1)))
|
|
Write-Host (' {0,-22} {1,12:N0} {2:N0}%' -f ' of which comment', $M, (100 * $M / [Math]::Max($T,1)))
|
|
Write-Host (' {0,-22} {1,12:N0} {2:N0}%' -f ' of which blank', $B, (100 * $B / [Math]::Max($T,1)))
|
|
Write-Host (' {0,-22} {1,12:N0}' -f 'Lines per file', ($T / [Math]::Max($F,1)))
|
|
Write-Host ''
|
|
$osT = ($os | Measure-Object -Property Lines -Sum).Sum
|
|
$osC = ($os | Measure-Object -Property Code -Sum).Sum
|
|
$osF = ($os | Measure-Object -Property Files -Sum).Sum
|
|
Write-Host (' {0,-22} {1,12:N0} ({2:N0} code, {3} files)' -f 'THE OS ITSELF', $osT, $osC, $osF) -ForegroundColor Green
|
|
Write-Host (' {0,-22}' -f ' kernel+include+boot+lib+cmd') -ForegroundColor DarkGray
|
|
Write-Host ''
|
|
Write-Host (' {0,-22} {1,12:N0}' -f 'Bytes', $By)
|
|
Write-Host (' {0,-22} {1,12:N0}' -f 'Non-whitespace chars', $NW)
|
|
Write-Host (' {0,-22} {1,12:N0}' -f ' letters', $AL)
|
|
Write-Host (' {0,-22} {1,12:N0}' -f ' digits', $DG)
|
|
Write-Host ''
|
|
|
|
# For scale. Linux 0.01 (September 1991) is 10,239 lines by the same crude
|
|
# measure -- every line of every file in the tarball, comments included.
|
|
$lin = 10239
|
|
Write-Host (' For scale: Linux 0.01 was {0:N0} lines (kernel, headers, boot -- the' -f $lin) -ForegroundColor DarkGray
|
|
Write-Host (' same things counted above as THE OS ITSELF). SchOS is {0:N1}x that.' -f ($osT / $lin)) -ForegroundColor DarkGray
|
|
Write-Host ''
|
|
|
|
if ($PerFile) {
|
|
Write-Host ' Largest files' -ForegroundColor Cyan
|
|
# Out-String, not a bare Format-Table: two Format-Table calls writing to
|
|
# the same output stream interleave their grouping records and PowerShell
|
|
# rejects the second one outright.
|
|
$rows = ($own | ForEach-Object { $_.Files_ }) |
|
|
Sort-Object Lines -Descending | Select-Object -First $Top |
|
|
Format-Table @{N='Lines';E={'{0:N0}' -f $_.Lines};A='right'},
|
|
@{N='Code'; E={'{0:N0}' -f $_.Code};A='right'},
|
|
@{N='Cmt'; E={'{0:N0}' -f $_.Comment};A='right'},
|
|
Path -AutoSize | Out-String
|
|
Write-Host $rows
|
|
}
|