RTBL(3)
π RTBL(3) β the roken library's little table queen π
okay bestie, sit DOWN, because we're about to talk about rtbl, aka the function family that lets you build cute lil text tables without losing your entire mind. it lives in the roken library (libroken, link it with -lroken) and honestly? it's giving spreadsheet but make it Unix. π¦
β¨ NAME β¨
rtbl_create, rtbl_destroy, rtbl_set_flags, rtbl_get_flags, rtbl_set_prefix, rtbl_set_separator, rtbl_set_column_prefix, rtbl_set_column_affix_by_id, rtbl_add_column, rtbl_add_column_by_id, rtbl_add_column_entry, rtbl_add_column_entry_by_id, rtbl_new_row, rtbl_format β format data in simple tables π
π LIBRARY π
The roken library (libroken, -lroken). yes bestie that's the whole vibe. π
πΈ SYNOPSIS πΈ
#include <rtbl.h>
int
rtbl_add_column(rtbl_t table, const char *column_name,
unsigned int flags);
int
rtbl_add_column_by_id(rtbl_t table, unsigned int column_id,
const char *column_header, unsigned int flags);
int
rtbl_add_column_entry(rtbl_t table, const char *column_name,
const char *cell_entry);
int
rtbl_add_column_entry_by_id(rtbl_t table, unsigned int column_id,
const char *cell_entry);
rtbl_t
rtbl_create(void);
void
rtbl_destroy(rtbl_t table);
int
rtbl_new_row(rtbl_t table);
int
rtbl_set_column_affix_by_id(rtbl_t table, unsigned int column_id, const,
char, *prefix", const char *suffix);
int
rtbl_set_column_prefix(rtbl_t table, const char *column_name,
const char *prefix);
unsigned int
rtbl_get_flags(rtbl_t table);
void
rtbl_set_flags(rtbl_t table, unsigned int flags);
int
rtbl_set_prefix(rtbl_t table, const char *prefix);
int
rtbl_set_separator(rtbl_t table, const char *separator);
int
rtbl_format(rtbl_t table, FILE, *file");
yes, a couple of those lines in the original are a lil cursed (look atrtbl_set_column_affix_by_idandrtbl_format). we do NOT fix them, we reproduce them, because facts are facts and I do not edit the ancestors' code. π
π DESCRIPTION π
So. This lil set of functions assembles a simple table made of rows and columns, and then lets you print it with certain options. the classic use case? output from tools like ls(1) or netstat(1), where you know how many columns you want but you literally cannot know the column widths ahead of time. iconic problem, iconic solution. β¨
A table gets created with rtbl_create() and destroyed with rtbl_destroy(). that's the whole life cycle, birth to glow-down, no cap. π«Ά
Global flags on the table get set with rtbl_set_flags and retrieved with rtbl_get_flags. right now the only defined flag is RTBL_HEADER_STYLE_NONE, which suppresses printing the header. bye bye header. π
Before you can add data, you need one or more columns. normally you'd do this with rtbl_add_column_by_id(): column_id is any number you want (it exists purely to identify the column, it's not that deep), column_header is the header printed at the top of the column, and flags are flags specific to this column. currently the only defined flag is RTBL_ALIGN_RIGHT, which aligns the column entries to the right. columns print in the order you added them, periodt. π
There's also rtbl_add_column(), which adds columns by column name, but it's less flexible (your header names have to be unique) and it's considered deprecated. so likeβ¦ it exists, it works, but it's not the main character anymore. π
To add data to a column, use rtbl_add_column_entry_by_id(). the column_id has to be the same one you used when the column was added β and adding data to a non-existent column is undefined, which is fancy speak for "we will not be responsible for what happens, bestie". π cell_entry is whatever string you want in that cell, and it should not include newlines. and if your column was added with rtbl_add_column(), you must use rtbl_add_column_entry() instead. no mixing, no matching, pick a lane. πΈ
rtbl_new_row() fills all columns with blank entries until they all have the same number of rows. it's the lil equalizer, the vibe balancer, the "everyone gets a seat" of this whole thing. π§
Every column can have its own prefix and suffix, set with rtbl_set_column_affix_by_id. and rtbl_set_column_prefix lets you set the prefix only, by column name. on top of that, columns can be separated by a string you set with rtbl_set_separator β and by default, columns are not separated by anything (not a typo in spirit, the original says "seprated", I said it nicer, the meaning is identical π).
The finished table gets printed to file with rtbl_format.
π¦ EXAMPLES π¦
okay this program, look at her:
#include <stdio.h>
#include <rtbl.h>
int
main(int argc, char **argv)
{
rtbl_t table;
table = rtbl_create();
rtbl_set_separator(table, " ");
rtbl_add_column_by_id(table, 0, "Column A", 0);
rtbl_add_column_by_id(table, 1, "Column B", RTBL_ALIGN_RIGHT);
rtbl_add_column_by_id(table, 2, "Column C", 0);
rtbl_add_column_entry_by_id(table, 0, "A-1");
rtbl_add_column_entry_by_id(table, 0, "A-2");
rtbl_add_column_entry_by_id(table, 0, "A-3");
rtbl_add_column_entry_by_id(table, 1, "B-1");
rtbl_add_column_entry_by_id(table, 2, "C-1");
rtbl_add_column_entry_by_id(table, 2, "C-2");
rtbl_add_column_entry_by_id(table, 1, "B-2");
rtbl_add_column_entry_by_id(table, 1, "B-3");
rtbl_add_column_entry_by_id(table, 2, "C-3");
rtbl_add_column_entry_by_id(table, 0, "A-4");
rtbl_new_row(table);
rtbl_add_column_entry_by_id(table, 1, "B-4");
rtbl_new_row(table);
rtbl_add_column_entry_by_id(table, 2, "C-4");
rtbl_new_row(table);
rtbl_format(table, stdout);
rtbl_destroy(table);
return 0;
}
and she will output the following:
Column A Column B Column C
A-1 B-1 C-1
A-2 B-2 C-2
A-3 B-3 C-3
A-4
B-4
C-4
likeβ¦ the RTBL_ALIGN_RIGHT on Column B is doing exactly what it promised, and rtbl_new_row is out here keeping the blank cells blank so the columns line up. we love a tidy queen. ππ₯
π SEE ALSO π
that's the whole page bestie, no cross-refs here, only vibes.
this page came from HEIMDAL, dated June 26, 2004 β and it's still serving RTBL(3) energy to this very day. mwah, take care of your tables, they take care of you. πβ¨π
π¦ where this page comes from
- alpine 3.22: heimdal-doc 7.8.0-r4 Β· BSD-3-Clause
- alpine 3.23: heimdal-doc 7.8.0-r5 Β· BSD-3-Clause
- alpine 3.24: heimdal-doc 7.8.0-r5 Β· BSD-3-Clause
- debian bookworm: heimdal-dev 7.8.git20221117.28daf24+dfsg-2 Β· BSD-3-Clause
- debian trixie: heimdal-dev 7.8.git20221117.28daf24+dfsg-9+deb13u1 Β· BSD-3-Clause
- epel 10: heimdal-devel 7.8.0-26.el10_2 Β· BSD-2-Clause AND BSD-3-Clause AND HPND-export-US AND HPND-export2-US AND LicenseRef-Fedora-Public-Domain
- epel 9: heimdal-devel 7.8.0-5.el9 Β· BSD and MIT
- fedora 43: heimdal-devel 7.8.0-26.fc43 Β· BSD-2-Clause AND BSD-3-Clause AND HPND-export-US AND HPND-export2-US AND LicenseRef-Fedora-Public-Domain
- fedora 43: heimdal-devel 7.8.0-26.fc43 Β· BSD-2-Clause AND BSD-3-Clause AND HPND-export-US AND HPND-export2-US AND LicenseRef-Fedora-Public-Domain
- fedora 44: heimdal-devel 7.8.0-26.fc43 Β· BSD-2-Clause AND BSD-3-Clause AND HPND-export-US AND HPND-export2-US AND LicenseRef-Fedora-Public-Domain
- fedora 44: heimdal-devel 7.8.0-26.fc43 Β· BSD-2-Clause AND BSD-3-Clause AND HPND-export-US AND HPND-export2-US AND LicenseRef-Fedora-Public-Domain
- fedora 44: heimdal-devel 7.8.0-28.fc44 Β· BSD-2-Clause AND BSD-3-Clause AND HPND-export-US AND HPND-export2-US AND LicenseRef-Fedora-Public-Domain
- fedora 44: heimdal-devel 7.8.0-28.fc44 Β· BSD-2-Clause AND BSD-3-Clause AND HPND-export-US AND HPND-export2-US AND LicenseRef-Fedora-Public-Domain
- nixpkgs unstable: heimdal 7.8.0-unstable-2024-09-10
- ubuntu jammy: heimdal-dev 7.7.0+dfsg-3ubuntu1 Β· BSD-3-Clause
- ubuntu noble: heimdal-dev 7.8.git20221117.28daf24+dfsg-5ubuntu3 Β· BSD-3-Clause
- ubuntu questing: heimdal-dev 7.8.git20221117.28daf24+dfsg-9ubuntu1
- ubuntu resolute: heimdal-dev 7.8.git20221117.28daf24+dfsg-11ubuntu1 Β· BSD-3-Clause
- ubuntu stonking: heimdal-dev 7.8.git20240113.1b4565a+dfsg-2ubuntu1 Β· BSD-3-Clause
- Copyright (c) 2004 Kungliga Tekniska HΓΆgskolan
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms