---
name: "libttyrec"
section: "3"
platform: "linux"
package: "libtty-dev"
version: "0.19-2"
release: "Debian 12 (Bookworm)"
platforms: ["linux"]
url: "https://new.carta.tech/libttyrec"
---

# libttyrec(3)

a library for handling ttyrec files

## NAME

libttyrec - a library for handling ttyrec files

## SYNOPSIS

**#include \<ttyrec.h\>**

Link with *-ltty*.

## DESCRIPTION

### Helper stream function:

- **int open\_stream(int** *fd***, const char\*** *url***, int** *mode***, const char \*\****error***);**

  This function opens a stream designated by the *url*.  If the given url ends in ".gz", ".xz", ".bz2" or ".zst"), the stream is assumed to be compressed and gets passed through the appropriate \[un\]packer.  If the *fd* is not -1, it is the descriptor you already opened; if it is -1, the file is opened.  The *mode* can be:

  - SM\_READ

    - SM\_WRITE

    - SM\_REPREAD

    - SM\_APPEND

    On error, -1 is returned.  If you want the message, pass a non-null pointer *error*, it will be filled in.

### Format encoders:

- **const char\* ttyrec\_w\_find\_format(const char \****format***, const char \****filename***, const char \****fallback***);**

  This function searches for a format that would fit the *filename* provided -- that is, abc.ttyrec.gz returns "ttyrec".  If no known extension is found, the function returns whatever you gave as *fallback*.  You can force a *format* yourself, in this case, it is only validated and if invalid, 0 is returned regardless of the other two arguments.

- **recorder ttyrec\_w\_open(int** *fd***, const char \****format***, const char \****filename***, const struct timeval \****ts***);**

  A recorder is opened, writing to the file *fd*; if it's not given (=-1), the function calls **open\_stream()**. Recording is done in the given *format*, if not provided, the format is guessed based on the *filename*. If you provide a timestamp *ts*, it becomes date of the recording.

- **int ttyrec\_w\_write(recorder** *r***, const struct timeval \*tm, const char \****data***, int** *len***);**

  A chunk of data of length *len* is written to recorder *r*, with timestamp *tm*. Returns 1 if some sort of write error happened.

- **int ttyrec\_w\_close(recorder** *r***);**

  All pending data is flushed, recorder closed and its memory freed. Returns 1 if there's some kind of failure.

- **const char\* ttyrec\_w\_get\_format\_name(int** *i***);**

  You can use this function to enumerate known write formats by calling it with *i* being subsequent numbers starting at 0.  An invalid *i* will return a null pointer.

- **const char\* ttyrec\_w\_get\_format\_ext(const char \****format***);**

  If the given write *format* is associated with a file extension, it is returned.

### Format decoders:

- **const char\* ttyrec\_r\_find\_format(const char \****format***, const char \****filename***, const char \****fallback***);**

  See the \_w\_ function, except that read formats are searched instead.

- **const char\* ttyrec\_r\_get\_format\_name(int** *i***);**

  ditto

- **const char\* ttyrec\_r\_get\_format\_ext(const char \****format***);**

  ditto

- **int ttyrec\_r\_play(int** *fd***, const char \****format***, const char \****filename***, void (\****synch\_init\_wait***)(const struct timeval \*ts, void \****arg***), void (\****synch\_wait***)(const struct timeval \****delay***, void \****arg***), void (\****synch\_print***)(const char \****data***, int** *len***, void \****arg***), void \****arg***);**

  This function decodes the file *fd* (opening *filename* if *fd*=-1).  If its contents contain the date of the recording, you'll receive it through the callback *synch\_init\_wait*.  Between frames, the delay is passed through *synch\_wait*.  The actual frame data goes through *synch\_print*.  Note that in some formats, two or more consecutive delays or two consecutive frames can happen one after another.  If you provide an arbitrary *arg*, it will be passed to all callbacks.

  The function doesn't return until the end of input data.  Returns 1 on success, 0 on failure.

### The following functions deal with in-memory ttyrecs:

- **ttyrec ttyrec\_init(tty** *vt***);**

  An empty one is allocated.  If a *vt* is provided, it becomes the screen that the ttyrec is internally played on; otherwise, a blank 80x25 one is allocated.  The *vt* is consumed.

- **ttyrec ttyrec\_load(int** *fd***, const char \****format***, const char \****filename***, tty** *vt***);**

  This function will load a ttyrec from the file designated with *fd*.  If it's not open yet (*fd*=-1), it will be opened with **open\_stream**.  The ttyrec is played on the *vt* you provide -- or on a new 80x25 one.

- **void ttyrec\_free(ttyrec** *tr***);**

  Destroys the in-memory ttyrec, freeing its memory.

You can read the ttyrec's data while it's being read; all functions are thread-safe with regard to reading.  The frames are stored in structures like this:

typedef struct {\
     struct timeval t;\
     int len;\
     char \*data; } \*ttyrec\_frame;

- **ttyrec\_frame ttyrec\_seek(ttyrec** *tr***, const struct timeval \****t***, tty \****vt***);**

  Finds the frame that should be shown at time *\*t*, or the first frame if *t* is null. If *vt* is not-null, it will receive a terminal containing the screen at that frame.

- **ttyrec\_frame ttyrec\_next\_frame(ttyrec** *tr***, ttyrec\_frame** *tfv***);**

  Returns the next frame after frame *tfv*, or null if *tfv* was the last.

- **void ttyrec\_add\_frame(ttyrec** *tr***, const struct timeval \****delay***, const char \****data***, int** *len***);**

  Creates a new frame and appends it to ttyrec *tr*.

- **int ttyrec\_save(ttyrec** *tr***, int** *fd***, const char \****format***, const char \****filename***, const struct timeval \****selstart***, const struct timeval \****selend***);**

  Exports the ttyrec to a new file.  If *selstart* and/or *selend* are given, they designate the part that should be exported -- if not, the whole is.

### struct timeval arithmetics:

A handful of macros for operating on timeval values:

- **tadd(t, d)**

  t+=d;

- **tsub(t, d)**

  t-=d;

- **tmul1000(t, m)**

  t\*=m/1000;

- **tdiv1000(t, m)**

  t/=m/1000;

- **tcmp(t1, t2)**

  If t1\<t2, -1.  If t1\>t2, +1.  0 otherwise.

## SEE ALSO

[**libtty**(3)](/libtty/3.md)
