Under development — the help is being filled in plugin by plugin.
Plugin reference

csv

Parse and build CSV data, field by field.

17 functionsnamespace csvsource plugins/csv/CsvPlugin.c

Written from a line-by-line source review; every example output is from a real run.

Introduction

The csv plugin is a self-contained, dependency-free CSV/TSV reader and writer. It parses CSV text into a table from which you can read by row and column (cell) or by column name, or you can build a table from scratch and serialize it to RFC 4180 CSV text. Both the parser and the serializer are implemented inside the plugin.

A handle-based model

Like the JSON plugin, this plugin is handle-based: Parse / ParseEx / NewTable return an integer identifier (a handle) that refers to an internal table. Every further operation takes this handle as its first argument. When you are done, release it with Free. At most 64 tables can be open at once.

Header rows and name-based access

Multi-row headers are first-class: the headerRows parameter of ParseEx says how many rows are header (0 = no header, 1 = classic, 2+ = stacked headers, such as a group row plus a unit row). RowCount counts ONLY the data rows (after the header rows). Name-based access (GetByName / ColIndex / HeaderName) uses one designated “name row”; by default that is the LAST header row (usually the most specific column label), but SetNameRow can change it.

RFC 4180 quoting

On input, fields may be wrapped in double quotes; inside a quoted field a doubled quote ("") is a single literal quote, and the delimiter and newlines are literal. On output, a field is quoted only if it contains the delimiter, a quote, CR or LF. Both line endings (\n and \r\n) are accepted on input; the output uses \n.

Loading the plugin

plugin "../plugins/print/PrintPlugin";
plugin "../plugins/csv/CsvPlugin";

A typical flow — reading

i32 $h;
$h = csv.ParseEx("name;age\nAda;36", ";", 1);
printf("%s\n", csv.GetByName($h, 0, "age"));
csv.Free($h);

What to know about every function (the basics)

  • The row index is 0-based and refers to DATA rows: data row 0 is the first non-header row. The column index is also 0-based.

  • An out-of-range cell read is not an error: Get / GetByName / HeaderCell / HeaderName return an empty string, and ColIndex returns -1 for an unknown name. So the script need not guard every read.

  • An invalid handle, however, is an error: if you pass the handle of a non-existent or already-freed table, the script stops with a runtime error. So do not reuse a handle after Free.

  • Ragged (unequal-length) rows are padded by the parser to the widest row: the missing cells read as empty strings.

  • On writing, NewTable fixes the column count; SetCell writes only to an existing data row and a valid column (otherwise it returns 0 rather than failing).

How to read the signatures

handle is always the table's identifier. The type after the -> arrow is the return type. For example, csv.Get(handle, row, col) -> string takes three arguments and returns a string.

Parsing

Loading CSV text into a table. Both functions return a handle.

csv.Parse

csv.Parse(text) -> int

Parses CSV text with a comma delimiter and no header row (every row is a data row).

Parameters
Parameter Type Description
text string The CSV text (rows separated by \n or \r\n).
Return value

The table handle (a positive integer). Out of memory or more than 64 open tables causes a runtime error.

Example
i32 $h;
$h = csv.Parse("a,b,c\n1,2,3\n4,5,6");
printf("%d\n", csv.RowCount($h));
printf("%s\n", csv.Get($h, 1, 2));
csv.Free($h);
Output after running
3
3
When to use

For simple, header-less, comma-separated data. If you need a header or a different delimiter, use ParseEx.

csv.ParseEx

csv.ParseEx(text, delim, headerRows) -> int

Parses CSV text with any single-character delimiter and a given number of header rows.

Parameters
Parameter Type Description
text string The CSV/TSV text.
delim string The delimiter — exactly one character (for example ",", ";" or a tab).
headerRows int The number of header rows (0 = none, 1 = classic, 2+ = stacked). A negative value is clamped to 0.
Return value

The table handle. If the delimiter is not exactly one character, a runtime error.

Example
i32 $h;
$h = csv.ParseEx("name;age\nAda;36\nBob;41", ";", 1);
printf("%d\n", csv.RowCount($h));
printf("%s\n", csv.GetByName($h, 1, "age"));
csv.Free($h);
Output after running
2
41
When to use

For TSV (delim = tab), European semicolon CSV, or wherever you want to refer to columns by their header. RowCount here counts only the data rows.

Lifecycle

Releasing the table when you no longer need it.

csv.Free

csv.Free(handle) -> int

Frees the table and its memory; the handle becomes invalid afterwards.

Parameters
Parameter Type Description
handle int The handle of the table to free.
Return value

1 if it was freed; 0 if the handle is invalid or was already freed.

Example
i32 $h;
$h = csv.Parse("a,b\n1,2");
printf("%d\n", csv.Free($h));
printf("%d\n", csv.Free($h));
Output after running
1
0
When to use

Always call it when you are done with a table — otherwise you may hit the limit of 64. Free is the forgiving operation: it does not fail on an invalid handle, it just returns 0.

Inspection (dimensions)

Querying the table's dimensions.

csv.RowCount

csv.RowCount(handle) -> int

Returns the number of DATA rows (excluding the header rows).

Parameters
Parameter Type Description
handle int The table handle.
Return value

The number of data rows.

Example
i32 $h;
// 1 header row + 2 data rows
$h = csv.ParseEx("name;age\nAda;36\nBob;41", ";", 1);
printf("%d\n", csv.RowCount($h));
csv.Free($h);
Output after running
2
When to use

For iterating over the data rows: from 0 to RowCount-1. The header does not count.

csv.ColCount

csv.ColCount(handle) -> int

Returns the number of columns.

Parameters
Parameter Type Description
handle int The table handle.
Return value

The number of columns.

Example
i32 $h;
$h = csv.Parse("a,b,c\n1,2,3");
printf("%d\n", csv.ColCount($h));
csv.Free($h);
Output after running
3
When to use

For iterating over columns, or for checking the shape of the table after parsing.

csv.HeaderRowCount

csv.HeaderRowCount(handle) -> int

Returns the number of header rows (as you gave it to ParseEx).

Parameters
Parameter Type Description
handle int The table handle.
Return value

The number of header rows (0 if there is no header).

Example
i32 $h;
$h = csv.ParseEx("Sales,Sales\nQ1,Q2\n10,20", ",", 2);
printf("%d\n", csv.HeaderRowCount($h));
csv.Free($h);
Output after running
2
When to use

When you want to check whether a table of unknown origin has a header before trying to read by name.

Setting the name row

Choosing which header row supplies the column names for name-based access.

csv.SetNameRow

csv.SetNameRow(handle, headerRow) -> int

Sets which header row provides the column names for name-based access (GetByName / ColIndex / HeaderName). The default is the last header row.

Parameters
Parameter Type Description
handle int The table handle.
headerRow int The 0-based index of the header row to use as the name row.
Return value

1 if it was set; 0 if headerRow is out of range (in which case nothing changes).

Example
i32 $h;
$h = csv.ParseEx("Sales,Sales,HR\nQ1,Q2,Q1\n10,20,5", ",", 2);
// by default the last header row is the name row (Q1/Q2)
printf("%s\n", csv.HeaderName($h, 1));
csv.SetNameRow($h, 0);
printf("%s\n", csv.HeaderName($h, 1));
csv.Free($h);
Output after running
Q2
Sales
When to use

For stacked headers, when you want to refer to columns by the upper group row rather than the lowest (most specific) row.

Reading

Reading cells by index or by column name. An out-of-range / unknown reference returns an empty string (or -1 for ColIndex).

csv.Get

csv.Get(handle, row, col) -> string

Returns the value of a data cell by row and column index.

Parameters
Parameter Type Description
handle int The table handle.
row int The 0-based data-row index (counted without the header).
col int The 0-based column index.
Return value

The cell's text; an empty string if the row or column is out of range.

Example
i32 $h;
$h = csv.Parse("a,b,c\n1,2,3\n4,5,6");
printf("%s\n", csv.Get($h, 0, 0));
printf("%s\n", csv.Get($h, 1, 2));
printf("[%s]\n", csv.Get($h, 9, 9));
csv.Free($h);
Output after running
a
3
[]
When to use

For reading by position, when there is no header, or for a fast index-based walk over the table.

csv.GetByName

csv.GetByName(handle, row, col) -> string

Returns the value of a data cell by row index and COLUMN NAME (per the name row).

Parameters
Parameter Type Description
handle int The table handle.
row int The 0-based data-row index.
col string The column's name in the name row.
Return value

The cell's text; an empty string if the name is unknown or the row is out of range.

Example
i32 $h;
$h = csv.ParseEx("name;age\nAda;36\nBob;41", ";", 1);
printf("%s\n", csv.GetByName($h, 0, "name"));
printf("%s\n", csv.GetByName($h, 1, "age"));
printf("[%s]\n", csv.GetByName($h, 0, "nope"));
csv.Free($h);
Output after running
Ada
41
[]
When to use

The most readable choice for tables with a header: you refer to a column by name regardless of column order. If you read from the same column often, fetch its index once with ColIndex, then read with Get.

csv.HeaderCell

csv.HeaderCell(handle, headerRow, col) -> string

Returns the value of a header cell by header-row and column index.

Parameters
Parameter Type Description
handle int The table handle.
headerRow int The 0-based header-row index.
col int The 0-based column index.
Return value

The header cell's text; an empty string if the header row or column is out of range.

Example
i32 $h;
$h = csv.ParseEx("Sales,Sales,HR\nQ1,Q2,Q1\n10,20,5", ",", 2);
printf("%s\n", csv.HeaderCell($h, 0, 0));
printf("%s\n", csv.HeaderCell($h, 1, 1));
csv.Free($h);
Output after running
Sales
Q2
When to use

For stacked headers, where you can reach any cell of any header row (for example to print the upper group row and the lower unit row together).

csv.HeaderName

csv.HeaderName(handle, col) -> string

Returns a column's name from the designated name row.

Parameters
Parameter Type Description
handle int The table handle.
col int The 0-based column index.
Return value

The column's name in the name row; an empty string if there is no header or the column is out of range.

Example
i32 $h;
$h = csv.ParseEx("name;age\nAda;36", ";", 1);
printf("%s\n", csv.HeaderName($h, 0));
printf("%s\n", csv.HeaderName($h, 1));
csv.Free($h);
Output after running
name
age
When to use

For printing column headers, or when you walk columns by index but also want to show their names.

csv.ColIndex

csv.ColIndex(handle, col) -> int

Gives which column corresponds to the given name (per the name row).

Parameters
Parameter Type Description
handle int The table handle.
col string The column name to look for.
Return value

The column's 0-based index, or -1 if there is no column with that name.

Example
i32 $h;
$h = csv.ParseEx("name;age\nAda;36", ";", 1);
printf("%d\n", csv.ColIndex($h, "age"));
printf("%d\n", csv.ColIndex($h, "nope"));
csv.Free($h);
Output after running
1
-1
When to use

Fetch a column's index once, then read with the faster Get inside the loop — so you do not resolve the name for every cell. The -1 signals a missing column.

Writing

Building a table from scratch, cell by cell, then serializing it to CSV text.

csv.NewTable

csv.NewTable(colCount, headerRows) -> int

Creates a new, empty table with a fixed column count and a given number of (pre-created, empty) header rows.

Parameters
Parameter Type Description
colCount int The number of columns (at least 1).
headerRows int The number of header rows (0 or more). A negative value is clamped to 0.
Return value

The new table's handle. If colCount is invalid (0 or too large), a runtime error.

Example
i32 $h;
$h = csv.NewTable(2, 1);
printf("%d\n", csv.ColCount($h));
printf("%d\n", csv.HeaderRowCount($h));
csv.Free($h);
Output after running
2
1
When to use

The first step of building output CSV. The header rows are created with empty cells; fill them with SetHeaderCell.

csv.SetHeaderCell

csv.SetHeaderCell(handle, headerRow, col, name) -> int

Sets a header cell at a given header row and column.

Parameters
Parameter Type Description
handle int The table handle.
headerRow int The 0-based header-row index.
col int The 0-based column index.
name string The header text to write.
Return value

1 if it was written; 0 if the header row or column is out of range.

Example
i32 $h;
$h = csv.NewTable(2, 1);
printf("%d\n", csv.SetHeaderCell($h, 0, 0, "name"));
printf("%s\n", csv.HeaderName($h, 0));
csv.Free($h);
Output after running
1
name
When to use

For setting the column titles of the output table. For stacked headers, fill each header row separately.

csv.AddRow

csv.AddRow(handle) -> int

Appends a new, empty data row to the end of the table.

Parameters
Parameter Type Description
handle int The table handle.
Return value

The new data row's 0-based index (excluding the header rows).

Example
i32 $h;
i32 $r;
$h = csv.NewTable(2, 1);
$r = csv.AddRow($h);
printf("%d\n", $r);
csv.Free($h);
Output after running
0
When to use

Call it before each new record; use the returned index to write the cells with SetCell. The first data row's index is always 0, regardless of the header rows.

csv.SetCell

csv.SetCell(handle, row, col, value) -> int

Sets a data cell by row and column index.

Parameters
Parameter Type Description
handle int The table handle.
row int The 0-based data-row index.
col int The 0-based column index.
value string The value to write.
Return value

1 if it was written; 0 if the row or column is out of range (the row must already exist — call AddRow first).

Example
i32 $h;
$h = csv.NewTable(2, 0);
csv.AddRow($h);
printf("%d\n", csv.SetCell($h, 0, 0, "Ada"));
printf("%d\n", csv.SetCell($h, 9, 9, "x"));
csv.Free($h);
Output after running
1
0
When to use

For filling a row's cells after AddRow. It does not write to a non-existent row (returns 0), so always create the row first.

csv.Serialize

csv.Serialize(handle) -> string

Serializes the whole table (header + data rows) to RFC 4180 CSV text with a comma delimiter.

Parameters
Parameter Type Description
handle int The table handle.
Return value

The CSV text. A field is quoted only if it contains a comma, a quote, CR or LF.

Example
i32 $h;
$h = csv.NewTable(2, 1);
csv.SetHeaderCell($h, 0, 0, "name");
csv.SetHeaderCell($h, 0, 1, "note");
csv.AddRow($h);
csv.SetCell($h, 0, 0, "Ada");
// quoted because of the comma
csv.SetCell($h, 0, 1, "hi, there");
printf("%s", csv.Serialize($h));
csv.Free($h);
Output after running
name,note
Ada,"hi, there"
When to use

For emitting the built table (before saving to a file or sending over the network). Quoting is handled automatically; you only supply the raw values.

Practical notes

What the csv plugin is good for

  • Reading and processing tabular data (exported reports, measurement logs, configuration lists).

  • Name-based access to data with a header, so the code is independent of column order.

  • Producing output CSV that you can then save to a file or hand to another tool (such as a spreadsheet).

  • Handling TSV and semicolon CSV, by specifying the delimiter.

Efficient patterns

  • For repeated column reads, fetch ColIndex once, then read with the faster Get inside the loop — not GetByName for every cell.

  • Fetch RowCount/ColCount once before the loop, not on every iteration.

  • Always close handles with Free; because of the limit of 64, releasing is especially important in long-running scripts.

Common pitfalls

  • Row indexing: RowCount and Get count DATA rows; the header is not row 0. For header cells use HeaderCell/HeaderName.

  • Invalid handle: after Free (or with a wrong handle) the dimension and read operations raise a runtime error — unlike an out-of-range cell read, which only returns an empty string.

  • Single-character delimiter: the delim parameter of ParseEx must be exactly one character; a multi- or zero-character delimiter is a runtime error.

  • SetCell order: AddRow first, then SetCell; SetCell on a non-existent row returns 0 and writes nothing.

Error handling

A wrong argument count or type, an invalid handle, a bad delimiter, and out of memory are reported by the runtime as a runtime error, and the script stops. Content-level cases (an out-of-range cell, an unknown column name), however, are handled by the plugin with a neutral return value: an empty string, or ColIndex's -1. So the usual reads need no extra guard checks.

The queue message-queue plugin

Thread-safe FIFO queue — complete function reference