# `QuakeC.Progs`
[🔗](https://github.com/jaman/cauldron/blob/v0.2.2/quake_c/lib/quake_c/progs.ex#L1)

A compiled QuakeC program, `progs.dat`, read: Quake's version 6, and FTE's version 7 with
16- or 32-bit statements.

  * `statements` — a tuple of `{op, a, b, c}`; jump distances are signed
  * `functions` — a tuple of `%{first:, parm_start:, locals:, name:, parm_sizes:}`;
    `first` below zero is builtin number `-first`, and 0 a builtin bound by its name
  * `strings` — the string table; a string value is an offset into it
  * `texts` — `%{offset => string}` for every string starting in the table
  * `globals` — the initial global values, a tuple of floats and integers by slot
  * `global_defs`, `field_defs` — `%{name => {type, offset}}`, `type` one of `:void`,
    `:string`, `:float`, `:vector`, `:entity`, `:field`, `:function`, `:pointer`,
    `:integer`
  * `entity_fields` — how many slots an entity's fields take
  * `function_names` — `%{name => index}`
  * `digest` — the SHA-256 of the file, naming the program (and its replacements, `replace/2`)
  * `crc` — the header's check value of the program's global and field layout: 5927
    for Quake's, 54730 for QuakeWorld's

# `t`

```elixir
@type t() :: %QuakeC.Progs{
  crc: term(),
  digest: term(),
  entity_fields: term(),
  field_defs: term(),
  function_names: term(),
  functions: term(),
  global_defs: term(),
  globals: term(),
  statements: term(),
  strings: term(),
  texts: term()
}
```

# `find_function`

```elixir
@spec find_function(t(), String.t()) :: non_neg_integer() | nil
```

The index of function `name` as FTE's `ED_FindFunction` finds it: a name may follow a
program number and `:` (`0:name`), the number read as C's `atoi` reads it; this
program is number 0, so another number finds nothing.

# `function`

```elixir
@spec function(t(), String.t()) :: non_neg_integer() | nil
```

The index of function `name`, or `nil`.

# `parse`

```elixir
@spec parse(binary()) :: {:ok, t()} | {:error, :not_progs | :compressed}
```

The program in `data`, the bytes of a `progs.dat`.

# `replace`

```elixir
@spec replace(t(), [String.t()]) :: t()
```

The program with each function of `names` run by the host in place of its QuakeC body:
the function becomes a builtin bound by its name (`first` 0), so every call of it,
from the program or from `QuakeC.Exec`, runs `builtins.call(host, name, argc)` with the
arguments in the parameter slots. A name the program lacks is passed over. The
program's `digest` names the replacements too, so its compiled code is its own.

    progs = QuakeC.Progs.replace(progs, ["Player::UseDown"])

# `string`

```elixir
@spec string(t(), non_neg_integer()) :: String.t()
```

The string at offset `offset` of the table.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
