Skip to content

Fix plotting correctness, memory safety, and terminal sizing - #3

Merged
sofuture merged 6 commits into
masterfrom
cursor/fix-plot-correctness-1655
Oct 11, 2026
Merged

sofuture merged 6 commits into
masterfrom
cursor/fix-plot-correctness-1655

Conversation

@sofuture

@sofuture sofuture commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Summary

tfig was dropping points, overflowing a heap allocation on every run, and crashing on bad dimensions. This makes the scatter plot match the data it is given and fail cleanly on bad input.

  • Autoscaling fits the actual samples exactly. Bounds are stored as double, so fractional data spreads across the chart instead of collapsing into a [0, 1] window, and large values such as 1e20 plot instead of failing. The largest point stays on the chart, and a cluster far from zero is no longer pinned to the origin. Bounds the user omits are fitted independently. The old defaults copied the screen height into xmax and the width into ymax. A zero-length axis, including a single sample, is drawn in the middle cell.
  • -x, -X, -y, and -Y accept fractional values. Ranges are inclusive, so a point on the maximum edge lands in the last cell. An inverted explicit range is rejected, and so is a range whose span overflows. If only one bound is given and all the data is on the wrong side of it, the window extends one unit from that bound and the plot is empty instead of failing. A trailing unpaired number no longer moves the window. Non-numeric and non-finite input exits with an error.
  • -w and -h must be integers from 1 to 10000. The raster is allocated on the heap, so a zero, negative, or huge size is an error instead of a stack overflow.
  • -s takes one character that occupies one terminal column. UTF-8 scalars such as • are accepted. Wide characters, emoji, combining marks, and line separators are rejected, so the axis stays aligned with the marks.
  • ll_new allocated sizeof(pointer) because a variable named list hid the type. Points are now a growable array sized with sizeof(list). Allocation failure exits instead of dereferencing NULL.
  • SIGPIPE is ignored, and output errors are detected when a row is written or stdout is flushed, so a closed pipe and tfig > /dev/full both exit with a write error. A read error on stdin is reported as one instead of as non-numeric input.
  • Window size comes from ioctl on a tty or /dev/tty, then COLUMNS and LINES. The stty fallback, which printed errors on Linux, is gone. Each plot row is written in one shot.

Test plan

  • make test checks the README figure, autoscaled integers, fractional data and bounds, huge coordinates, a centered single sample, a vertical line on a zero-width axis, negative values, a far cluster, partial bounds (including one that excludes all the data), inclusive edges, odd input, a one-column UTF-8 symbol, and rejected wide, combining, and separator symbols, dimensions, ranges, and non-numeric input. It also checks writing to /dev/full, a closed stdout pipe, and reading from an unreadable stdin.
  • make is clean with -Wall -Wextra -pedantic.
  • The same suite passes under AddressSanitizer and UndefinedBehaviorSanitizer.
Open in Web Open in Cursor 

cursoragent and others added 6 commits October 11, 2026 14:21
Fit autoscaled bounds to the data so extreme points stay visible, and
let omitted bounds follow the samples instead of a swapped terminal
size. Store points in a growable array, draw from a heap raster, reject
invalid dimensions and input, and read the window size with ioctl.

Co-authored-by: Jeff Zellner <sofuture@users.noreply.github.com>
Co-authored-by: jeff.zellner <jeff.zellner@gmail.com>
Co-authored-by: jeff.zellner <jeff.zellner@gmail.com>
Co-authored-by: jeff.zellner <jeff.zellner@gmail.com>
Co-authored-by: jeff.zellner <jeff.zellner@gmail.com>
Reject UTF-8 symbols whose terminal width is not 1, draw a zero-length
axis in the middle cell, and ignore SIGPIPE so a closed stdout reports
a write error.

Co-authored-by: Jeff Zellner <sofuture@users.noreply.github.com>
@sofuture
sofuture marked this pull request as ready for review October 11, 2026 14:45
@sofuture
sofuture merged commit 5c1850f into master Oct 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants