# File Access

`filesystem.h`/`filesystem.cpp` hold a small set of free functions for resolving netlist source file paths and for pulling one specific line out of a file or an in-memory string. They back the [parser](dflparser.md)'s `include` handling and [source location](sourceloc.md) formatting's "show me the offending line."

## Finding files: `findFile()`

Three overloads encode the resolution order `include "name"` actually uses, layered by the [file stack](filestack.md)'s `addFile()`:

1. **Absolute-path overload**: only succeeds if `fileName` is already an absolute path that exists; a relative name is rejected outright (returns `false`) rather than being resolved against the current directory - callers combine this with the next overload to get "absolute path always wins, ignoring any directory" behavior.
2. **Directory overload**: for a relative `fileName`, resolves it against a given directory (or the current directory, if the directory string is empty).
3. **Path-list overload**: tries the directory overload against each entry of a search path in turn, first match wins.

`findFileInSystemPath()` layers the platform's installed-file search path (`LibPlatform::systemPath()`) on top of the path-list overload, for locating files that ship with the simulator rather than files named by the netlist.

Every overload can canonicalize the resolved path (`makeCanonical`, used as the stable key stored in a [`FileStack`](filestack.md) entry) and checks the file's size against `SourceColumnNumber`'s maximum (`checkSize`) before accepting it - a byte offset into a source file is stored in that type ([Source Location Tracking](sourceloc.md)), so a file too large to address by it would silently corrupt location tracking; oversized files are rejected up front with `std::length_error` instead.

## Reading a specific line

`getLine()` (both the stream and C-string overloads) is marked "No longer used" in the source - dead code, superseded by `getLineByOffset()` below.

`getLineByOffset()` (stream and C-string overloads) takes a byte *offset* rather than a line number, and returns the line containing it plus a 1-based column. This matches how locations are actually recorded: a [`Loc`](sourceloc.md) stores an offset, not a line number, so finding "which line is this" happens lazily, on demand, only when an error is actually formatted for display - `Loc::toString()` is the caller. The stream overload searches backward from the offset for the preceding newline with an exponentially growing window (`back *= 2` each attempt that doesn't find one) rather than scanning forward from the start of the file, since the offset alone gives no line number to seek by. Column counting works in bytes and is documented as not correct for UTF-8 - an accepted simplification, not an oversight.
