Scripted sim runs and screenshots (t47 / c47): A short rundown of practical examples.

Build:  make simc47 t47
        (exactly that; a bare "make t47" builds the R47-based t47 instead)
        Alternate legal build, for R47 use: make simr47 t47
        (the alternateive R47 build has a different key layout so the usage of the press command must be reviewed from this document, which is C47 flavoured)

t47 and c47 are one build, two front ends: t47 forces headless (no GTK), c47 is the GTK twin. Same DSL except press, which needs GTK: c47 only.
c47 chdirs to its own folder and reads res/ from there; Gdk-CRITICAL/XPC noise at start is harmless.

The legal and only accepted way to control, is to use commands, not item numbers. Bare commands are registered lowercase (m.dim 00, 42dim#, scatr), and xeq takes
the catalog's own case (xeq SCATR). item <n> is the fallback ONLY, not the first choice, for a name that cannot be typed. A constant is not one: reach it with CNST
<n>, e.g.  cnst 4  = c. PLT f is the case in point: its gap is no space at all but a U+2005 four-per-em, so the name must be copied out of the --dslcommands list, the
reason that list exists. Pasted, it is one Jim word: xeq PLT f resolves, as do braces and double quotes; single quotes are not Jim quoting and fail.
Without the paste item 2734 does the same job, at the clear cost of code nobody can read.
A name carrying a bracket or a quote is not a fallback case either. It is missing from --dslcommands because either one breaks Jim parsing, so it is never registered
as a bare command, and xeq and catfn still reach it by its catalog name. Braces protect it:  xeq {f'} vv  and  xeq {f"} vv  differentiate against the variable vv.

WARNING: no item whose name is written >NNNN< is free to use. Those are legacy entries, kept only so an old program still decodes, and they must not be used for
anything: not in a script, not in a program, not as a stand-in for a name you cannot type. If you meet one in the catalogue or the --dslcommands list, look for the
current name instead.

CAUTION, calculator state: the sim starts from backup.cfg (t47) or backupR47.cfg (R47-based t47) in the working folder.
DSP, HIDE, grouping and profile change how numbers render in stack, menus and graph text, so bmp comparisons hold only against the same setup.
--reset = factory defaults, cfg not loaded: produce reference bmps from a --reset run and they reproduce on any machine.
A profile switch like --jm is not factory defaults (JM HIDE=31 renders below 1E-31 as 0).
  ./t47 --reset --exec '...'

Normal screen (stack, menus, status bar):
  ./t47 --exec 'nim 2; nim 3; xeq +; snap'

Graphic screen (PIXEL / POINT / plot), keep the drawn pixels:
  ./t47 --snapskiprefresh --exec 'cllcd; nim 240; chs; nim 300; pixel; snap'

Stat graph (SCATR / HISTOX / HISTOY): Σ+ the data, then plot. Plots render at once, so either snap mode captures them:
  ./t47 --snapskiprefresh --exec 'clΣ; nim 1; nim 1; xeq Σ+; nim 4; nim 2; xeq Σ+; nim 9; nim 3; xeq Σ+; nim 16; nim 4; xeq Σ+; nim 25; nim 5; xeq Σ+; xeq SCATR; snap'

Plot test suite examples:
  ./t47 --exec 'readp ./docs/appnotes/sources/AN0022/func.p47; xeq PLTROOT'
  ./t47 -e 'readp ./res/PROGRAMS/FFX.p47; pgmplt FFX; nim 1e-50; nim 2e-50; xeq "PLT f" "xx"; snap'
  (PLTf from the --exec line captures the graph with a trailing snap, but the axis operand must be a fresh variable name, here "xx": give PLTf the function's MVAR name
   and nothing plots, so the snap grabs the stack instead. Wrapping PLTf and SNAP in a program, the way PLTROOT does, works too.)
  ./c47 --reset --headless --snapskiprefresh -e 'readp ./res/PROGRAMS/FFX.p47; pgmplt FFX; nim 1e-50; nim 2e-50; xeq "PLT f" "xx"; snap'
  ./t47 --reset -e 'readp ./res/PROGRAMS/FFX.p47; pgmplt FFX; nim 1e-50; nim 2e-50; xeq "PLT f" "x"; snap'

Programmed EQN solve and draw (cpxSlv and Draw as program steps; single-variable formulas only, the solve variable is picked up).
Encode the listing with  ./rejig listing.txt -o eqndemo.p47 :
    LBL 'CSLV'
      'x^2+4' X.EDIT
      1 5
      cpxSlvˣʸ
    RTN
    LBL 'DRW'
      'x^2-4' X.EDIT
      -5 5
      Draw_y^x
    RTN
  (X.EDIT loads the string in X as the formula and drops it; X.SWAP exchanges. cpxSlvˣʸ takes the two guesses from Y and X; Drawˣʸ the plot range.)
  ./t47 --reset --exec 'readp eqndemo.p47; xeq CSLV; puts "X=[reg X]"'   (root 0-i2)
  ./t47 --reset --exec 'readp eqndemo.p47; xeq DRW; snap'                (parabola, roots -2 and 2)

Loading a formula from the command line, with no program at all:
  Put the text in X as a string, make an empty formula with EQ.NEW, then swap the two: ./t47 --reset --exec 'reg X "aa+bb+cc+dd"; eq.new; x.swap; enter; openm EQN; snap'
  The swap leaves the old formula in X, an empty string for a formula just created, which is why the line ends with a fresh ENTER. From there the engines are reachable by
  name or by menu: menu {f'} opens the derivative on that formula, and its softkeys are the formula's variables. Without the EQ.NEW, X.EDIT stores into whichever
  formula happens to be current, or into none at all.
  Multiply is × and never *. A star is stored and displayed as typed, no error, but the parser stops there and the rest is dropped:  f' on  aa*3  answers 1, the
  slope of aa alone, while  aa×3  answers 3. Suspect the glyph whenever a formula answers for a shorter formula than the one on the screen.

Named variable as a program operand:
  To store to or recall from a named variable, put the name in quotes:  STO 'cva'  or  RCL 'cva'.  rejig accepts plain quotes ('cva') or curly quotes (‘cva’) and always
  stores the curly form, so when you decode the program again the line reads back as  STO ‘cva’.  Without quotes it is no longer a variable:  a bare  STO cva  does not
  encode, rejig reads the word as a register name and rejects it (invalid register: cva);  STO A  is the lettered register A, never a variable of that name.
  Reserved variables follow the same quoting rule:  STO '↓Lim'  and  RCL '↓Lim'  reach the integration lower limit (↑Lim, ACC and the rest likewise), while a bare
  STO ↓Lim  fails like any bare name. This is how to set the ∫f d limits from a program:  2 STO '↑Lim'  0 STO '↓Lim'  then  ∫fd 'x'  integrates the named variable x.
  ACC has no other route: as a command it is not programmable and a program carrying it stops at that step with "non-programmable function ACC", so the quoted store is
  how the integration accuracy is set from a program:  1E-4 STO 'ACC'.  A loose accuracy is what makes a nested integral finish in a usable time.
  There is no plain command to delete a variable. CLV (also spelt DELITM) needs a TAM argument, so it only works as a program step, not on the --exec line. Delete one
  from inside a short program, the step being  CLV 'cvb'  between an  LBL 'DEL'  and its  RTN.
  Unsure how an operand should be written? Decode a shipped program and copy the glyphs it prints:  ./rejig docs/appnotes/sources/AN0022/func.p47 -o out.txt  (look for
  lines such as  RCL ‘x’).

A plain space finds a built-in command name that displays with a fancy gap:
  Some built-in command names carry a narrow gap that is not a plain space: PLT f has a four-per-em (U+2005). Type a plain space and it is found anyway, so you never
  need an exotic space. The plain space and the em, three-per-em, four-per-em, six-per-em, figure, punctuation and hair spaces all count as one space, but only when a
  built-in command name is matched. A name you create yourself is untouched: a label or variable is matched exactly as written, so one stored with a four-per-em is a
  different name from one with a plain space. Example, PLT f driven with a plain space:
  ./t47 --reset --exec 'readp res/PROGRAMS/FFX.p47; pgmplt FFX; nim 1e-50; nim 2e-50; xeq "PLT f" xx; snap'

Export a loaded program to RTF (GUI XPORTP needs a file chooser, the DSL does not):
  ./t47 --reset --exec 'readp res/PROGRAMS/GudrmPL.p47; xportp GudrmPL res/PROGRAMS/GudrmPL.rtf'
  (xportp <global label> <filename>.)

Export / import a register data file (.d47) (GUI EXPreg / IMPORTr need a file chooser):
  ./t47 --reset --exec 'nim 3; nim 4; ÷; expreg X quot.d47'   (export register X)
  ./t47 --reset --exec 'impreg quot.d47; puts "X=[reg X]"'          (import, then read X)
  ./t47 --reset --exec 'nim 7; sto 00; expnrg 100 regs.d47'       (export the block R00..R99, EXPnrg)
  (expnrg <n> <file> exports R00..R(n-1), n up to 126; same filename-override rules as expreg.)
  (expreg <reg> <file>; impreg <file>; reg name as for reg, e.g. X, 00, A. The filename is verbatim, so the folder must exist; the GUI keeps .d47 in DATA/.)
  (Headless there is no chooser to open, so a file function reached without a filename stops with a cannot-read/write error and a note on stderr. Always name the file.)

Write your own TSV from a running program (🖨xy, flag 🖨ACT clear):
  With the system flag  🖨ACT  clear,  🖨xy  writes one tab separated line to a dated  DATA\*.REGS.TSV  instead of printing it: register X in the first column, register Y in
  the second. Push the value first and the label second, so the label lands in X:  RCL 00 'MY CASE' 🖨xy DROPX DROPX.  A running program can therefore log a row per
  step of a long test and you read the file afterwards.
  The file is opened, written and closed for each line, so a row already written survives whatever a later step does. Nothing is written while the calculator is on the
  graph screen, so a program that has just plotted needs  CLSTK  first, which leaves the graph without stopping the run (CLRMOD and EXIT leave it too but both stop the
  program, and EXITALL only closes menus).
  A real is written through the display format, which can shorten 7080 to 7.08E+3 even under FIX 00. Store a count as a long integer and it is written as its digits.

Stat graph at 1E-50 (both axes scaled):
  ./t47 --snapskiprefresh --exec 'clΣ; nim 1e-50; nim 1e-50; xeq Σ+; nim 4e-50; nim 2e-50; xeq Σ+; nim 9e-50; nim 3e-50; xeq Σ+; nim 16e-50; nim 4e-50; xeq Σ+; nim 25e-50; nim 5e-50; xeq Σ+; xeq SCATR; snap'

Jim Tcl scripting (the DSL is Jim: set/expr/while/if/puts all work; incr is a NO-OP, step with expr):
  ./t47 --reset --exec 'set s 0; set n 0; while {$n < 5} {set n [expr {$n + 1}]; set s [expr {$s + $n}]}; puts "sum=$s"'   (sum=15)

Register / named variable / flag write and read (complex values in braces; strings and more forms in values.t47):
  ./t47 --reset --exec 'reg 05 3.5; var myv 2.5; flag SPCRES 1; puts "R05=[reg 05] myv=[var myv] SPCRES=[flag SPCRES]"'
  ./t47 --reset --exec 'reg 10 {1 + ix2}; puts "R10=[reg 10]"'
  A one-letter name given to var is the lettered register, not a variable of that name:  var x 5  writes stack register X, the same rule as  STO A  in a program. Name
  a variable with two letters or more and it is unambiguous. The single letter reads as the named variable on the solver and integrator operands only, so  xeq SOLVE x
  and  ∫f d x  do reach a variable called x.

Distribution functions take their parameters from the stat registers, not from the stack:
  Only the value goes in X. The Weibull pdf reads the shape from Q and the scale from S, so a scripted call writes those two with reg and keys in the value alone.
  The normal pdf reads the mean from M and the standard deviation from S. Which registers a distribution uses differs from one distribution to the next.
  ./t47 --reset --exec 'reg S 1.5; reg Q 2.5; nim 2; weibl⒫; puts "f=[reg X]"'      (0.3294099600746249339120285341074746)
  ./t47 --reset --exec 'reg S 1; reg Q 0.5; nim 1e-30; weibl⒫; puts "f=[reg X]"'    (499999999999999.5000000000000002500)
  ./t47 --reset --exec 'reg M 10; reg S 2; nim 12; norml⒫; puts "f=[reg X]"'        (0.1209853622595716748989150964677803)
  The p in Weibl⒫ is a parenthesised letter that no keyboard types, so copy the name out of --dslcommands the way PLT f is copied; typed with a subscript p the run stops
  at invalid command name. reg X returns all 34 digits of the result, which is what a comparison against an independently computed value needs.

Progress-monitor paths (MONIT) under a multi-second load, with a marker telling "ran and returned" from "hung" (markers: see Notes):
  ./t47 --reset --exec 'flag MONIT 1; reg 01 -1; nim 2000000000000095000000000000777; xeq FACTORS; reg 01 1; puts "R01=[reg 01]"'
  (the 31-digit semiprime = 1000000000000037 x 2000000000000021 runs tens of seconds in the sim, so the 1.024 s monitor tick fires throughout; R01=1 proves
   FACTORS returned, and the factor matrix prints as ReMa rows on stdout. Two ~15-digit primes give seconds of load; small factors finish in microseconds.)

Range screening examples (error text appears on stdout):
  NaN/inf STO rejected:  ./t47 --exec 'flag SPCRES 1; nim 1; nim 0; ÷; sto "↓Y"'
  equal limits rejected: ./t47 --exec 'readp ./res/PROGRAMS/FFX.p47; pgmplt FFX; nim 5; nim 5; xeq "PLT f" "xx"'
  out-of-domain range:   ./t47 --reset -e 'readp ./res/PROGRAMS/FFX.p47; pgmplt FFX; nim 1; nim 10; xeq "PLT f" "xx"'
                         (every sample infinite -> "no plottable sample in the plot range")
  (↑Y and ↓Y are the plot y-limit reserved vars, set by quoted STO such as  sto "↓Y";  ÷ is divide.)

State save/load and register assertions (savest/loadst take a filename):
  save a state:    ./t47 --reset --exec 'nim 2; nim 2; m.dim 00; savest good.sav'
  load and check:  ./t47 --reset --exec 'loadst good.sav; rcl 00; 42dim#; puts "rows=[reg Y] cols=[reg X]"'
  (m.dim dims a register to Y x X reals, rcl recalls it, 42dim# drops the X-matrix dimensions to Y=rows, X=cols.
   reg <name> reads a register's display string but returns <unsupported> for a matrix, so assert dimensions via 42DIM#.
   Register data also moves through hand-written .d47 files; format in AN0025.)

A function a softmenu starts, headless (the equation derivative):
  menu <name> is the real showSoftmenu, so a menu that acts as it opens acts headless too. Braces because an apostrophe is not Jim quoting, and a script file because
  that same apostrophe would close an --exec wrapper. Running the item behind the menu without opening the menu first skips the menu state and reads "In function
  regInRange: generic is not defined!".
  Encode the formula loader with  ./rejig listing.txt -o eqr.p47 :
    LBL 'EQR'
      '1/vv' X.EDIT
    RTN
  and the script, run as  ./t47 --reset --script deriv.t47 :
    readp eqr.p47
    xeq EQR
    menu {f'}
    var vv 1
    item 2377
    puts "deriv=[reg X]"
  (d/dvv of 1/vv at vv = 1 is -1. Opening the menu selects the single variable and stops there, so put the point in that variable and then run the Calc f' softkey.
   That key is item 2377 and has no name xeq will take, which is what item <n> is the fallback for.)
  A PROGRAM derivative is driven like SOLVE and ∫f d: PGMDRV names the program, then f' or f" names the variable. The point comes off the stack and the answer
  replaces it, MVAR or no MVAR:  nim 3; xeq PGMDRV FX; xeq {f'} zz. The legacy >f'(x)< and >f"(x)< take a program label there instead.
  A script cannot open a program's MVAR menu: f' takes a variable, so a program name given to it becomes a variable and the run stops with "No program specified".
  That prompt is on the keyboard only. The equation form does open its menu headless, which is the menu {f'} example above.

Keyboard path (press; c47 only): F1..F6 softkeys, @f/@g shifts, @k NN physical key (NN = 00..36), single ASCII, ENTER, R/S. Bare commands and xeq call the function direct,
so TAM and softmenu decode need press. Matrix editor, cursor to 2;2:

press never reaches the key release code. F1..F6 and @k NN call the button press handler direct, and R/S, ENTER and a single ASCII char go in as Gtk key events, which
the sim answers on the press alone. Only a mouse click on an on-screen button raises a release, so anything a key does when it is let go cannot be scripted: check it by
hand in the GUI. SHOW paging runs on the press and scripts fine; the R/S fault that blanked SHOW's top line (issue #560) ran on the release and does not.

  A name taking a TAM argument (e.g. M.EDITN) is not scriptable at all: reach it with press.

  ./c47 --reset --exec 'nim 3; nim 3; m.dim 00; rcl 00; m.edit; press F6; press @f; press F6; snap'
  (m.edit; M_EDIT F5/F6 = left/right, f-shifted = up/down; snap shows "2;2=".)
  M.EDIT indexes X, so a later nim pushes the matrix out of X: index a numbered register instead where the test needs the stack. A program stops at M.EDIT.

  A program derivative's MVAR menu is not scriptable: f' asks for the program at a TAM prompt. By hand it is f', the program name, ENTER, then the variable key to
  store the point and the same key again to differentiate. F1..F6 are the variables in declaration order and the last softkey is the step.

  XEQ a function by name from the keyboard: press XEQ, then alpha, type the letters, Enter. Alpha is f-shift on the XEQ key and raises the ' name prompt.
  ./c47 --reset --exec 'nim 30; press "@k 05"; press @f; press "@k 05"; press "@k 21"; press "@k 08"; press "@k 14"; press ENTER; snap'
  (@k 05 = XEQ; @f @k 05 = alpha; then @k NN types that key's letter, here 21 8 14 = S I N = SIN, so 30deg -> 0.5. Lowercase = @f first.)

  A name with a special glyph takes it from an alpha softmenu. i ℂ (set complex input) needs ℂ off the αMath number-sets page:
  ./c47 --reset --exec 'press "@k 05"; press @f; press "@k 05"; press @f; press "@k 08"; press " "; press F2; press "@k 22"; press "@k 22"; press "@k 22"; press @g; press F1; press ENTER; press 1; press ENTER'
  (lowercase i = @f @k 08; F2 opens αMath, @k 22 x3 pages to the ℂ ℐ ℕ ℚ ℝ ℤ row, @g F1 = ℂ. After i ℂ a typed 1 is complex; ℝ = @g F5 for i ℝ.)

SHOW (all-digit view). snap clears it, so headless run show TWICE (the 2nd call's refresh paints the 1st) and always --snapskiprefresh; one page per run:
  long int, big font:    ./t47 --reset --snapskiprefresh --exec 'nim 123456789012345678901234567890; show; show; snap'
  long int, small font:  ./t47 --reset --snapskiprefresh --exec 'nim 2; nim 1500; yˣ; show; show; snap'   (over 170 glyphs)
  real, 34 digits:       ./t47 --reset --snapskiprefresh --exec 'nim 1; nim 3; ÷; show; show; snap'
  XY+Z exact (XFN):      ./t47 --reset --snapskiprefresh --exec 'nim 1; nim 3; ÷; nim 7; nim 11; ÷; nim 13; nim 17; ÷; menu XFCNS; show; show; snap'
  page 2 (c47):          ./c47 --reset --snapskiprefresh --exec 'nim 2; nim 1500; yˣ; show; press R/S; snap'
  tiny font (c47):       ./c47 --reset --snapskiprefresh --exec 'nim 2; nim 1500; yˣ; show; press R/S; press R/S; snap'
  other register (c47):  ./c47 --reset --snapskiprefresh --exec 'nim 7; nim 9; show; press "@k 17"; snap'   (up: Y, Z..; down "@k 22": numbered regs)
  (R/S cycles small-font pages of 10 lines, then tiny, then back to page 1; a page count over 2 needs a longer number.)

Temporary information screens (WHO, VERS, STO/RCL and the rest of the TI_ set): fnSNAP clears temporaryInformation before it refreshes, so a plain snap never captures
one, it saves the stack instead. Use --snapskiprefresh and put one more command after the one under test: that next command's refresh paints the screen, and snap
then saves it as-is. The extra command can be anything harmless.
  ./t47 --reset --snapskiprefresh --exec 'who; nim 1; snap'
  (drop the trailing nim and the capture holds the start-up splash, because nothing ever painted. --snapskiprefresh does not clear either, so splash text stays visible
   under a TI screen shorter than the one it replaced; read the capture with that in mind.)

Power cycle (backup.cfg; savest above is a SAVE file, no calcMode in it):
  ./c47 --reset --exec '<setup>; off'   (off: writes backup.cfg, exits)
  ./c47 --exec 'snap'                         (no --reset: restores it)
  Writes the exe folder's backup.cfg: to spare your own, copy c47 to a scratch dir and symlink res/ beside it.

Output: newest ./YYYYMMDD-HHMMSS.bmp in cwd (time is the sim clock).

Notes:
  ;              separates commands.
  negative num   type the value then  chs   (nim 240; chs -> -240).
  stack order    first nim -> Y, second nim -> X.
  script file    ./t47 --headless --script file.t47   (instead of --exec).
  snap           saves a screenshot; default redraws the whole screen first.
  --snapskiprefresh  snap saves the screen as-is, so drawn PIXEL/POINT/plot pixels are not wiped by the redraw.
  item <n>       fallback only, see the top note.
  --dslcommands  ./t47 --dslcommands writes t47-op-commands.txt: item number, command name, catalog name. Copy untypable names from it.
  markers        set a register before the run (reg 01 -1) and read it after, to tell "the step ran and did nothing" from "the step never ran".
  snap <name>    writes <name>.bmp plus <name>.REGS.TSV.T47.TSV (stack as TSV) instead of the timestamp name.
  menu <name>    opens the real softmenu headless, so menu-open side effects fire without keys (e.g. menu XFCNS above).
  error mid-run  a calculator error no-ops every later step: put the step under test last, or markers lie.
  tsvfn <file>   redirects TSV output; it APPENDS, delete the old .T47.TSV first.
