Arcadia Sanitizer
The Arcadia Sanitizer is a native C tool and library for checking and normalizing source-file whitespace on Windows and Linux. It uses Arcadia's own FileSystem, FilePath, DirectoryIterator, FileHandle, and byte-buffer APIs.
Introduction
Use --check before committing to detect whitespace differences
without modifying files. Use --fix to apply the supported
normalization. Both modes accept a file or a directory; the path defaults
to the current working directory.
Build
Configure and build Arcadia with the usual CMake workflow, then build the sanitizer executable and its regression tests:
cmake -S . -B build
cmake --build build --target Arcadia.Sanitizer.Tool
cmake --build build --target Arcadia.Sanitizer.Tests
ctest --test-dir build -R Sanitizer --output-on-failure
The executable location depends on the selected CMake generator and
configuration. For Visual Studio or other multi-configuration generators,
select the appropriate build/test configuration (for example, with
--config Debug and ctest -C Debug).
Examples
Arcadia.Sanitizer.Tool --check .
Arcadia.Sanitizer.Tool --check Runtime/FileSystem
Arcadia.Sanitizer.Tool --fix Runtime/FileSystem
Arcadia.Sanitizer.Tool --check CMakeLists.txt
Run the executable by its actual filesystem path, or place its directory
on PATH. The examples assume it is available on PATH.
After a fix, inspect the changes using git diff and
git diff --check. Do not use --fix on files that
cannot be restored if an interruption occurs.
Typical workflow
- Run
--checkfor the module being changed. - If differences are expected, run
--fixon that module. - Review the changed files and run
--checkagain. - Run the native sanitizer CTest regression suite.
Concepts and Terms
- Check mode
- Read-only traversal which reports differing whitespace and exits with status 1 when at least one inspected text file is nonconforming.
- Fix mode
- Traversal which writes normalized bytes back to each affected text file. Files whose content is already conforming are not rewritten.
- Root
- The explicitly supplied file or directory; if omitted, the working directory. Root directories are traversed recursively.
- Eligible source file
- A regular file with an allowed extension discovered during directory traversal. An explicitly provided regular file is eligible regardless of its filename extension.
- Normalized bytes
- The original byte sequence after converting CRLF and lone CR line endings to LF and removing spaces/tabs at the ends of lines.
- Binary input
- Any inspected file containing a NUL byte. Such files are reported and skipped without modification.
The scanner operates on bytes rather than decoding text. It does not infer a character encoding or interpret language syntax. See the Specification for its exact boundaries.
Specification
Command line and exit statuses
Arcadia.Sanitizer.Tool (--check|--fix) [file-or-directory]
Exactly one mode is required. The optional path is interpreted as a
native filesystem path and defaults to .. Invalid arguments,
a missing or inaccessible root, and filesystem/runtime errors produce
exit status 2. The following exit statuses are part of the CLI contract:
| Status | Meaning |
|---|---|
0 | Check found no whitespace differences, or fix completed successfully. |
1 | Check found at least one whitespace difference. |
2 | Argument, filesystem, or runtime error. |
Skipped binary and linked files are not counted as formatting violations; a check can therefore return zero even when such files were skipped.
Normalization
The transform is byte-oriented and performs these operations:
- Replace each CRLF pair with one LF byte.
- Replace each remaining CR byte with one LF byte.
- Remove each run of ASCII space or tab bytes immediately before a line ending or at the end of the file.
All other bytes are copied unchanged. In particular, interior spaces, byte order marks, encoded non-ASCII bytes, and the presence or absence of a final line ending are preserved. The transform is idempotent. It does not add a final LF, decode encodings, reorder text, or format C, PDL, or ADL syntax.
File selection
Directory traversal processes regular files with these case-sensitive suffixes:
.txt, .c, .h, .i,
.tl, .te, .pdl,
.adl, .ddl, .md,
.cmake, .c.g, .h.g.
Directory scans exclude child directories named .,
.., .git, .vs,
.venv, .Dependencies, build,
.build, CMakeFiles,
node_modules, and __pycache__. These
exclusions apply to encountered child directories, not to a root directory
explicitly selected by the caller. Hidden files are not otherwise ignored.
This is not a Git tracked-file-only scan.
Symbolic links and special files
The sanitizer skips discovered symbolic links and never follows them when descending directories. The filesystem test also treats Windows reparse points, including junctions, as links. Explicitly selecting a symbolic-link or reparse-point root is rejected with status 2. Special file types not recognized as regular files or directories are not processed. See Arcadia FileSystem for the underlying API.
Reporting and writes
A changed file produces one report for its first affected line, for example:
Runtime/FileSystem/Example.c:17: whitespace differs
In fix mode the suffix is fixed whitespace instead. Binary
inputs are reported as skipped binary: path; nested links
as skipped link: path. File-level reporting is not a report
of every offending line, nor a JSON or machine-readable diagnostics format.
Directory enumeration order is filesystem-dependent.
Fix mode writes affected files in place using
Arcadia_FileSystem_setFileContents. This is not an atomic
replacement and does not guarantee preservation of modification times
for changed files. Interrupted writes can leave partial output. Use
version control or backups, and review the diff before committing.
Non-goals and future checks
This release checks whitespace only. It does not check header guards, C prototypes, C function layouts, PDL/ADL/DDL grammar, documentation structure, or generated-code ownership. Future validators should expose distinct named checks, deterministic diagnostic locations, independent regression tests, and a documented severity/exit-status policy rather than silently changing the meaning of this whitespace pass.
Module Interface
The native public library interface is defined in
Tools/Sanitizer/Library/Sources/Arcadia/Sanitizer/Sanitizer.h.
It depends on Arcadia FileSystem and Ring2. The executable is implemented
separately in Tools/Sanitizer/Tool.
Arcadia_Sanitizer_normalize
Arcadia_BooleanValue
Arcadia_Sanitizer_normalize
(
Arcadia_Thread* thread,
Arcadia_ByteArrayBuilder* input,
Arcadia_ByteArrayBuilder* output,
Arcadia_SizeValue* firstAffectedLine
);
Normalizes the input byte sequence into a distinct output builder.
Returns true if any byte would change; otherwise returns false.
firstAffectedLine receives the 1-based first affected line
number or zero when unchanged. The input and output builders must be
different objects. The caller owns the supplied builders and output
parameter.
Arcadia_Sanitizer_Statistics
typedef struct Arcadia_Sanitizer_Statistics {
Arcadia_SizeValue inspected;
Arcadia_SizeValue changed;
Arcadia_SizeValue skippedBinary;
Arcadia_SizeValue skippedLinks;
} Arcadia_Sanitizer_Statistics;
inspected counts regular files read for normalization,
including binary files. changed counts files whose
normalized bytes differ, including files fixed in fix mode.
skippedBinary and skippedLinks count
ignored binary inputs and links respectively. Initialize this structure
to zero before a scan.
Arcadia_Sanitizer_scan
void
Arcadia_Sanitizer_scan
(
Arcadia_Thread* thread,
Arcadia_FileSystem* fileSystem,
Arcadia_FilePath* path,
Arcadia_FileHandle* output,
Arcadia_BooleanValue fix,
Arcadia_Sanitizer_Statistics* statistics
);
Scans a file or directory recursively, writes diagnostics to the
supplied open file handle, and updates the provided statistics. When
fix is false, no files are rewritten. When true, only
files with differing normalized bytes are rewritten. This library
function does not return a CLI exit status; the command-line wrapper
maps the statistics and failures to statuses 0, 1, and 2.
The library uses Arcadia's normal thread error/status and jump-target conventions. Its caller must establish the required Arcadia process and thread environment, and manage errors according to those conventions.
Build targets and tests
| Target | Purpose |
|---|---|
Arcadia.Sanitizer | Reusable native C library. |
Arcadia.Sanitizer.Tool | Command-line executable. |
Arcadia.Sanitizer.Tests | Native regression suite, registered with CTest. |
Arcadia.Sanitizer.BuildDocs | Generate this documentation with the Arcadia Template Engine. |
The documentation source resides in Tools/Sanitizer/Documentation.
The generated site is .Website/Arcadia/Sanitizer/index.html.
Treat generated files as output, not as the primary editing surface.