Giter Club home page Giter Club logo

libfort's Introduction

libfort (Library to create FORmatted Tables)

Build Status Build Status Build status Build Status Coverage Status Try online Documentation Doc License: MIT

libfort is a simple crossplatform library to create formatted text tables.

TableSample

Features:

  • Easy to integrate (only 2 files)
  • Customization of appearance (various border styles and row/column/cell properties for indentation, alignment, padding)
  • A number of functions to fill the table (add content by adding separate cells, rows or use printf like functions)
  • Support of multiple lines in cells
  • Support of UTF-8 and wide characters

Design goals

  • Portability. All main OSes (Linux, Windows, macOS, FreeBSD) and compilers are supported.
  • Maintainability and robustness. libfort is written in C because it is much less complicated than C++ and it can be used in both C and C++ projects and even on platforms without C++ compiler.
  • Trivial integration. Therefore all source code files are amalgamed in only 2 files.
  • Heavy testing. The goal is to cover 100% of the code (it is not reached yet) and to run tests on all major compilers and platforms.

Integration

Add 2 files ( fort.c and fort.h from lib directory) to your C or C++ project and include

#include "fort.h"

in your source code where you will use libfort functions.

For C++ projects that use compiler with C++11 support (and later) there are also availabe convenient C++ wrappers around C functions (see fort.hpp in lib direrctory). In that case instead of fort.h you will need to include

#include "fort.hpp"

Integration with cmake

In case libfort is installed on the host system it should be sufficient to use find_package:

find_package(libfort)
target_link_libraries(your_target PRIVATE libfort::fort)

In case you downloaded libfort sources and embedded them in your project (e.g. put all sources in directory third-party/libfort) you can use add_subdirectory:

# Disable building tests and examples in libfort project
set(FORT_ENABLE_TESTING OFF CACHE INTERNAL "")

add_subdirectory(third-party/libfort)
target_link_libraries(your_target PRIVATE fort)

Documentation

See guide in tutorial of the library and doxygen API documentation.

Getting Started

The common libfort usage pattern (C API):

  • create a table (ft_create_table);
  • fill it with data (ft_write_ln, fr_ptrintf_ln, ft_row_write, ...);
  • modify basic table appearance (ft_set_cell_prop, ft_set_border_style ...)
  • convert table to string representation (ft_to_string);
  • destroy the table (ft_destroy_table)

Here are some examples:

Basic example

/* C API */
#include <stdio.h>
#include "fort.h"
int main(void)
{
    ft_table_t *table = ft_create_table();
    /* Set "header" type for the first row */
    ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);

    ft_write_ln(table, "N", "Driver", "Time", "Avg Speed");

    ft_write_ln(table, "1", "Ricciardo", "1:25.945", "222.128");
    ft_write_ln(table, "2", "Hamilton", "1:26.373", "221.027");
    ft_write_ln(table, "3", "Verstappen", "1:26.469", "220.782");

    printf("%s\n", ft_to_string(table));
    ft_destroy_table(table);
}
/* C++ API */
#include <iostream>
#include "fort.hpp"
int main(void)
{
    fort::char_table table;
    table << fort::header
        << "N" << "Driver" << "Time" << "Avg Speed" << fort::endr
        << "1" << "Ricciardo" << "1:25.945" << "47.362" << fort::endr
        << "2" << "Hamilton" << "1:26.373" << "35.02" << fort::endr
        << "3" << "Verstappen" << "1:26.469" << "29.78" << fort::endr;

    std::cout << table.to_string() << std::endl;
}

Output:

+---+------------+----------+-----------+
| N | Driver     | Time     | Avg Speed |
+---+------------+----------+-----------+
| 1 | Ricciardo  | 1:25.945 | 47.362    |
| 2 | Hamilton   | 1:26.373 | 35.02     |
| 3 | Verstappen | 1:26.469 | 29.78     |
+---+------------+----------+-----------+

Customize table appearance

/* C API */
#include <stdio.h>
#include "fort.h"
int main(void)
{
    ft_table_t *table = ft_create_table();
    /* Change border style */
    ft_set_border_style(table, FT_DOUBLE2_STYLE);

    /* Set "header" type for the first row */
    ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
    ft_write_ln(table, "Movie title", "Director", "Year", "Rating");

    ft_write_ln(table, "The Shawshank Redemption", "Frank Darabont", "1994", "9.5");
    ft_write_ln(table, "The Godfather", "Francis Ford Coppola", "1972", "9.2");
    ft_write_ln(table, "2001: A Space Odyssey", "Stanley Kubrick", "1968", "8.5");

    /* Set center alignment for the 1st and 3rd columns */
    ft_set_cell_prop(table, FT_ANY_ROW, 1, FT_CPROP_TEXT_ALIGN, FT_ALIGNED_CENTER);
    ft_set_cell_prop(table, FT_ANY_ROW, 3, FT_CPROP_TEXT_ALIGN, FT_ALIGNED_CENTER);

    printf("%s\n", ft_to_string(table));
    ft_destroy_table(table);
}
/* C++ API */
#include <iostream>
#include "fort.hpp"
int main(void)
{
    fort::char_table table;
    /* Change border style */
    table.set_border_style(FT_DOUBLE2_STYLE);

    table << fort::header
        << "Movie title" << "Director" << "Year" << "Rating" << fort::endr
        << "The Shawshank Redemption" << "Frank Darabont" << "1994" << "9.5" << fort::endr
        << "The Godfather" << "Francis Ford Coppola" << "1972" << "9.2" << fort::endr
        << "2001: A Space Odyssey" << "Stanley Kubrick" << "1968" << "8.5" << fort::endr;

    /* Set center alignment for the 1st and 3rd columns */
    table.column(1).set_cell_text_align(fort::text_align::center);
    table.column(3).set_cell_text_align(fort::text_align::center);

    std::cout << table.to_string() << std::endl;
}

Output:

╔══════════════════════════╤══════════════════════╤══════╤════════╗
║ Movie title              │       Director       │ Year │ Rating ║
╠══════════════════════════╪══════════════════════╪══════╪════════╣
║ The Shawshank Redemption │    Frank Darabont    │ 1994 │  9.5   ║
╟──────────────────────────┼──────────────────────┼──────┼────────╢
║ The Godfather            │ Francis Ford Coppola │ 1972 │  9.2   ║
╟──────────────────────────┼──────────────────────┼──────┼────────╢
║ 2001: A Space Odyssey    │   Stanley Kubrick    │ 1968 │  8.5   ║
╚══════════════════════════╧══════════════════════╧══════╧════════╝

Different ways to fill table with data

/* C API */
#include <stdio.h>
#include "fort.h"
int main(void)
{
    ft_table_t *table = ft_create_table();
    /* Set "header" type for the first row */
    ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
    ft_write_ln(table, "N", "Planet", "Speed, km/s", "Temperature, K");

    /* Fill row with printf like function */
    ft_printf_ln(table, "1|%s|%6.3f|%d", "Mercury", 47.362, 340);

    /* Fill row explicitly with strings */
    ft_write_ln(table, "2", "Venus", "35.02", "737");

    /* Fill row with the array of strings */
    const char *arr[4] = {"3", "Earth", "29.78", "288"};
    ft_row_write_ln(table, 4, arr);

    printf("%s\n", ft_to_string(table));
    ft_destroy_table(table);
}
/* C++ API */
#include <iostream>
#include "fort.hpp"
int main(void)
{
    fort::char_table table;
    table << fort::header;
    /* Fill each cell with operator[] */
    table [0][0] = "N";
    table [0][1] = "Planet";
    table [0][2] = "Speed, km/s";
    table [0][3] = "Temperature, K";
    table << fort::endr;

    /* Fill with iostream operator<< */
    table << 1 << "Mercury" << 47.362 << 340 << fort::endr;

    /* Fill row explicitly with strings */
    table.write_ln("2", "Venus", "35.02", "737");

    /* Fill row with data from the container */
    std::vector<std::string> arr = {"3", "Earth", "29.78", "288"};
    table.range_write_ln(std::begin(arr), std::end(arr));

    std::cout << table.to_string() << std::endl;
}

Output:

+---+---------+-------------+----------------+
| N | Planet  | Speed, km/s | Temperature, K |
+---+---------+-------------+----------------+
| 1 | Mercury | 47.362      | 340            |
| 2 | Venus   | 35.02       | 737            |
| 3 | Earth   | 29.78       | 288            |
+---+---------+-------------+----------------+

Working with multibyte-character-strings

libfort supports wchar_t and utf-8 strings. Here are simple examples of working with utf-8 strings:

/* C API */
#include <stdio.h>
#include "fort.h"
int main(void)
{
    ft_table_t *table = ft_create_table();
    ft_set_border_style(table, FT_NICE_STYLE);
    ft_set_cell_prop(table, FT_ANY_ROW, 0, FT_CPROP_TEXT_ALIGN, FT_ALIGNED_CENTER);
    ft_set_cell_prop(table, FT_ANY_ROW, 1, FT_CPROP_TEXT_ALIGN, FT_ALIGNED_LEFT);
    ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);

    ft_u8write_ln(table, "Ранг", "Название", "Год", "Рейтинг");
    ft_u8write_ln(table, "1", "Побег из Шоушенка", "1994", "9.5");
    ft_u8write_ln(table, "2", "12 разгневанных мужчин", "1957", "8.8");
    ft_u8write_ln(table, "3", "Космическая одиссея 2001 года", "1968", "8.5");
    ft_u8write_ln(table, "4", "Бегущий по лезвию", "1982", "8.1");

    printf("%s\n", (const char *)ft_to_u8string(table));
    ft_destroy_table(table);
}
/* C++ API */
#include <iostream>
#include "fort.hpp"
int main(void)
{
    fort::utf8_table table;
    table.set_border_style(FT_NICE_STYLE);
    table.column(0).set_cell_text_align(fort::text_align::center);
    table.column(1).set_cell_text_align(fort::text_align::center);

    table << fort::header
          << "Ранг" << "Название" << "Год" << "Рейтинг" << fort::endr
          << "1" << "Побег из Шоушенка" << "1994" << "9.5"<< fort::endr
          << "2" << "12 разгневанных мужчин" << "1957" << "8.8" << fort::endr
          << "3" << "Космическая одиссея 2001 года" << "1968" << "8.5" << fort::endr
          << "4" << "Бегущий по лезвию" << "1982" << "8.1" << fort::endr;
    std::cout << table.to_string() << std::endl;
}

Output:

╔══════╦═══════════════════════════════╦══════╦═════════╗
║ Ранг ║           Название            ║ Год  ║ Рейтинг ║
╠══════╬═══════════════════════════════╬══════╬═════════╣
║  1   ║       Побег из Шоушенка       ║ 1994 ║ 9.5     ║
║  2   ║    12 разгневанных мужчин     ║ 1957 ║ 8.8     ║
║  3   ║ Космическая одиссея 2001 года ║ 1968 ║ 8.5     ║
║  4   ║       Бегущий по лезвию       ║ 1982 ║ 8.1     ║
╚══════╩═══════════════════════════════╩══════╩═════════╝

Please note:

  • libfort internally has a very simple logic to compute visible width of utf-8 strings. It considers that each codepoint will occupy one position on the terminal in case of monowidth font (some east asians wide and fullwidth characters (see http://www.unicode.org/reports/tr11/tr11-33.html) will occupy 2 positions). This logic is very simple and covers wide range of cases. But obviously there a lot of cases when it is not sufficient. In such cases user should use some external libraries and provide an appropriate function to libfort via ft_set_u8strwid_func function.

Supported platforms and compilers

The following compilers are currently used in continuous integration at Travis, AppVeyor and Cirrus:

Compiler Operating System
GCC 5.5.0 Ubuntu 16.04.11
GCC 4.9.4 Ubuntu 16.04.11
GCC 5.5.0 Ubuntu 16.04.11
GCC 6.5.0 Ubuntu 16.04.11
GCC 7.5.0 Ubuntu 16.04.11
GCC 8.4.0 Ubuntu 16.04.11
GCC 9.3.0 Ubuntu 16.04.11
Clang 5.0.0 Ubuntu 16.04.11
AppleClang 7.3.0 Darwin Kernel Version 15.6.0
AppleClang 8.1.0 Darwin Kernel Version 16.7.0
AppleClang 9.1.0 Darwin Kernel Version 17.4.0
Clang 8.0.1 FreeBSD 12.1
Clang 11.0.1 FreeBSD 13.0
Visual Studio 2017 Windows Server 2016

Please note:

  • In case of clang on OS X before using libfort with wchar_t with real unicode symbols it may be necessary to set setlocale(LC_CTYPE, ""); because otherwise standard function swprintf, that libfort uses internally, may fail and ft_to_string will return error.

Contributing to libfort

See the contribution guidelines for more information.

License

The class is licensed under the MIT License:

Copyright © 2017 - 2020 Seleznev Anton

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

libfort's People

Contributors

alessandro-gentilini avatar brlcad avatar eriklax avatar jakobwenzel avatar pdietl avatar seleznevae avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libfort's Issues

Integration as package into Alpine Linux

Hey there. I love the library! And so I would like to know if you would be okay with me packaging it as a dev package for Alpine Linux.

To do this, I probably need to package fort.h, fort.hpp, and fort.a into a dev package.
If you are interested in adding support for generating a .so file, then I could potentially also make a regular library package just containing that.

Finally, it would be helpful if you could make a release so that I can make a URL directly to your repo to grab the source tarball for packaging and pointing others to your great library.

Thought on this?

How to set decimal precision in a column?

First, thanks for this great lib. I'm filling a table with data from a double array. However, I can't manage to print the table with exactly two digits after decimal point without generating extra columns.

Here's the code to generate the table:

double data[3][3] = {
  {3.4403, 5.1802, 0.0071},
  {18.931, 22.004, 0.0000},
  {  74.5, 100.01, 9.1110}
};

fort::char_table t1;

t1 << fort::header << "#" << "arrival time" << "departure time" << "waiting time" << fort::endr;

t1.column(0).set_cell_text_align(fort::text_align::center);
t1.column(1).set_cell_text_align(fort::text_align::right);
t1.column(2).set_cell_text_align(fort::text_align::right);
t1.column(3).set_cell_text_align(fort::text_align::right);

// Fill with data
for (int i = 0; i < 3; i++) {
  t1 << i;
  for (int j = 0; j < 3; j++)
    t1 << data[i][j];

  t1 << fort::endr;
}

std::cout << t1.to_string() << std::endl;

Output:

+---+--------------+----------------+--------------+
| # | arrival time | departure time | waiting time |
+---+--------------+----------------+--------------+
| 0 |       3.4403 |         5.1802 |       0.0071 |
| 1 |       18.931 |         22.004 |            0 |
| 2 |         74.5 |         100.01 |        9.111 |
+---+--------------+----------------+--------------+

I tried using std::setprecision and std::fixed from <iomanip> to print every cell with two digits after decimal point, but it did not work.

My attempts:

  1. Adding std::cout << std::fixed << std::setprecision(2); before the line std::cout << t1.to_string() << std::endl;. Output is the same as before.

  2. Replacing t1 << data[i][j]; by t1 << std::fixed << std::setprecision(2) << data[i][j];. Output:

+---+--------------+----------------+--------------+--+--+--------+--+--+------+
| # | arrival time | departure time | waiting time |  |  |        |  |  |      |
+---+--------------+----------------+--------------+--+--+--------+--+--+------+
| 0 |              |                |         3.44 |  |  | 5.18   |  |  | 0.01 |
| 1 |              |                |        18.93 |  |  | 22.00  |  |  | 0.00 |
| 2 |              |                |        74.50 |  |  | 100.01 |  |  | 9.11 |
+---+--------------+----------------+--------------+--+--+--------+--+--+------+

As you can see, it actually prints the values as expected, but it generates empty columns and disarranges the table.

  1. Adding t1 << std::fixed << std::setprecision(2); before the first for loop. Output has issues similar to 2nd attempt:
+---+--------------+----------------+--------------+------+------+
| # | arrival time | departure time | waiting time |      |      |
+---+--------------+----------------+--------------+------+------+
|   |              |              0 |         3.44 | 5.18 | 0.01 |
| 1 |        18.93 |          22.00 |         0.00 |      |      |
| 2 |        74.50 |         100.01 |         9.11 |      |      |
+---+--------------+----------------+--------------+------+------+

Other attempts also did not produce the expected output. I'm sorry, but I did not find in the tutorials something related to this issue. What am I missing here? Thanks in advance.

CMake build does not generate .lib

Hi,

I am trying to integrate libfort as part of a project built using CMake. I would like to link to it either statically by using a .lib file, or dynamically but with exports linked through a .lib file also.

I can't figure out how to build libfort one way or the other using CMake. All I've managed is to generate a .dll file alone.

Any pointers ?

Thanks !

2 tests fail on FreeBSD

Test project /disk-samsung/freebsd-ports/devel/libfort/work/.build
      Start  1: libfort_test_dev
 1/18 Test  #1: libfort_test_dev .................Subprocess aborted***Exception:   0.01 sec
      Start  2: libfort_test_cpp
 2/18 Test  #2: libfort_test_cpp .................   Passed    0.01 sec
      Start  3: libfort_test
 3/18 Test  #3: libfort_test .....................Subprocess aborted***Exception:   0.01 sec
      Start  4: libfort_simple_table
 4/18 Test  #4: libfort_simple_table .............   Passed    0.00 sec
      Start  5: libfort_custom_table
 5/18 Test  #5: libfort_custom_table .............   Passed    0.00 sec
      Start  6: libfort_fill_table
 6/18 Test  #6: libfort_fill_table ...............   Passed    0.00 sec
      Start  7: libfort_custom_border_style
 7/18 Test  #7: libfort_custom_border_style ......   Passed    0.00 sec
      Start  8: libfort_print_styles
 8/18 Test  #8: libfort_print_styles .............   Passed    0.01 sec
      Start  9: libfort_math_table
 9/18 Test  #9: libfort_math_table ...............   Passed    0.00 sec
      Start 10: libfort_beautiful_table
10/18 Test #10: libfort_beautiful_table ..........   Passed    0.00 sec
      Start 11: libfort_complex_layout
11/18 Test #11: libfort_complex_layout ...........   Passed    0.00 sec
      Start 12: libfort_non_ascii_table
12/18 Test #12: libfort_non_ascii_table ..........   Passed    0.00 sec
      Start 13: libfort_simple_table_cpp
13/18 Test #13: libfort_simple_table_cpp .........   Passed    0.00 sec
      Start 14: libfort_custom_table_cpp
14/18 Test #14: libfort_custom_table_cpp .........   Passed    0.00 sec
      Start 15: libfort_complex_layout_cpp
15/18 Test #15: libfort_complex_layout_cpp .......   Passed    0.00 sec
      Start 16: libfort_fill_table_cpp
16/18 Test #16: libfort_fill_table_cpp ...........   Passed    0.00 sec
      Start 17: libfort_beautiful_table_cpp
17/18 Test #17: libfort_beautiful_table_cpp ......   Passed    0.00 sec
      Start 18: libfort_non_ascii_table_cpp
18/18 Test #18: libfort_non_ascii_table_cpp ......   Passed    0.00 sec

89% tests passed, 2 tests failed out of 18

Total Test time (real) =   0.07 sec

The following tests FAILED:
	  1 - libfort_test_dev (Subprocess aborted)
	  3 - libfort_test (Subprocess aborted)
Errors while running CTest
Output from these tests are in: /disk-samsung/freebsd-ports/devel/libfort/work/.build/Testing/Temporary/LastTest.log
Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely.
FAILED: CMakeFiles/test.util 
cd /disk-samsung/freebsd-ports/devel/libfort/work/.build && /usr/local/bin/ctest --force-new-ctest-process
ninja: build stopped: subcommand failed.
*** Error code 1

libfort_test, when run alone, succeeds:

$ ./work/.build/tests/libfort_test
 ==  RUNNING BLACK BOX TEST SUITE ==
[==========] Running 15 test(s).
[ RUN      ] test_bug_fixes
[       OK ] test_bug_fixes
[ RUN      ] test_table_basic
[       OK ] test_table_basic
[ RUN      ] test_wcs_table_boundaries
[       OK ] test_wcs_table_boundaries
[ RUN      ] test_utf8_table
[       OK ] test_utf8_table
[ RUN      ] test_table_write
[       OK ] test_table_write
[ RUN      ] test_table_insert_strategy
[       OK ] test_table_insert_strategy
[ RUN      ] test_table_changing_cell
[       OK ] test_table_changing_cell
[ RUN      ] test_table_erase
[       OK ] test_table_erase
[ RUN      ] test_table_border_style
[       OK ] test_table_border_style
[ RUN      ] test_table_builtin_border_styles
[       OK ] test_table_builtin_border_styles
[ RUN      ] test_table_cell_properties
[       OK ] test_table_cell_properties
[ RUN      ] test_table_tbl_properties
[       OK ] test_table_tbl_properties
[ RUN      ] test_table_text_styles
[       OK ] test_table_text_styles
[ RUN      ] test_memory_errors
[       OK ] test_memory_errors
[ RUN      ] test_error_codes
[       OK ] test_error_codes
[==========] 15 test(s) run.
[  PASSED  ] 15 test(s).

something wrong about decoding chars in windows shell

Hello,
I followed the instruction in README.md
But I get something wrong using FT_DOUBLE2_STYLE.
In windows like bash (cmd and powershell), I got something like this.
image
But when I use Unix like bash (git bash) it went right.
image

I use clang v8.0.0 and msvc 2017 for compiling.
Thanks for the lib, it helped me a lot.

Compilation warnings on esp32 platform

I get the following warnings when I try to compile libfort as a component for the esp32 platform with esp-idf:

[2/7] Building C object esp-idf/libfort/CMakeFiles/idf_component_libfort.dir/fort.c.obj
FAILED: esp-idf/libfort/CMakeFiles/idf_component_libfort.dir/fort.c.obj 
ccache /home/bruno/dev/esp/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc -DESP_PLATFORM -DGCC_NOT_5_2_0=0 -DHAVE_CONFIG_H -DIDF_VER=\"v3.3-71-g46b12a560\" -I../components/libfort -Iconfig -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/esp32/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/driver/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/esp_ringbuf/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/tcpip_adapter/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/lwip/include/apps -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/lwip/lwip/src/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/lwip/port/esp32/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/lwip/port/esp32/include/arch -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/lwip/include_compat -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/vfs/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/esp_event/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/log/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/efuse/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/efuse/esp32/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/newlib/platform_include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/newlib/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/freertos/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/app_trace/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/heap/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/soc/esp32/include -I/home/bruno/dev/esp/esp-mdf/esp-idf/components/soc/include -mlongcalls   -mlongcalls -Og -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -nostdlib -Wall -Werror=all -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wextra -Wno-unused-parameter -Wno-sign-compare -ggdb -std=gnu99 -Wno-old-style-declaration -MD -MT esp-idf/libfort/CMakeFiles/idf_component_libfort.dir/fort.c.obj -MF esp-idf/libfort/CMakeFiles/idf_component_libfort.dir/fort.c.obj.d -o esp-idf/libfort/CMakeFiles/idf_component_libfort.dir/fort.c.obj   -c ../components/libfort/fort.c
In file included from ../components/libfort/fort.c:2585:0:
../components/libfort/fort.c: In function 'print_row_separator_impl':
/home/bruno/dev/esp/esp-mdf/esp-idf/components/newlib/include/ctype.h:57:54: error: array subscript has type 'char' [-Werror=char-subscripts]
 #define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)])
                                                      ^
/home/bruno/dev/esp/esp-mdf/esp-idf/components/newlib/include/ctype.h:67:23: note: in expansion of macro '__ctype_lookup'
 #define isprint(__c) (__ctype_lookup(__c)&(_P|_U|_L|_N|_B))
                       ^
../components/libfort/fort.c:5419:50: note: in expansion of macro 'isprint'
     if ((strlen(*L) == 0 || (strlen(*L) == 1 && !isprint(**L)))
                                                  ^
/home/bruno/dev/esp/esp-mdf/esp-idf/components/newlib/include/ctype.h:57:54: error: array subscript has type 'char' [-Werror=char-subscripts]
 #define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)])
                                                      ^
/home/bruno/dev/esp/esp-mdf/esp-idf/components/newlib/include/ctype.h:67:23: note: in expansion of macro '__ctype_lookup'
 #define isprint(__c) (__ctype_lookup(__c)&(_P|_U|_L|_N|_B))
                       ^
../components/libfort/fort.c:5420:53: note: in expansion of macro 'isprint'
         && (strlen(*I) == 0 || (strlen(*I) == 1 && !isprint(**I)))
                                                     ^
/home/bruno/dev/esp/esp-mdf/esp-idf/components/newlib/include/ctype.h:57:54: error: array subscript has type 'char' [-Werror=char-subscripts]
 #define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)])
                                                      ^
/home/bruno/dev/esp/esp-mdf/esp-idf/components/newlib/include/ctype.h:67:23: note: in expansion of macro '__ctype_lookup'
 #define isprint(__c) (__ctype_lookup(__c)&(_P|_U|_L|_N|_B))
                       ^
../components/libfort/fort.c:5421:55: note: in expansion of macro 'isprint'
         && (strlen(*IV) == 0 || (strlen(*IV) == 1 && !isprint(**IV)))
                                                       ^
/home/bruno/dev/esp/esp-mdf/esp-idf/components/newlib/include/ctype.h:57:54: error: array subscript has type 'char' [-Werror=char-subscripts]
 #define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)])
                                                      ^
/home/bruno/dev/esp/esp-mdf/esp-idf/components/newlib/include/ctype.h:67:23: note: in expansion of macro '__ctype_lookup'
 #define isprint(__c) (__ctype_lookup(__c)&(_P|_U|_L|_N|_B))
                       ^
../components/libfort/fort.c:5422:53: note: in expansion of macro 'isprint'
         && (strlen(*R) == 0 || (strlen(*R) == 1 && !isprint(**R)))) {
                                                     ^
../components/libfort/fort.c: In function 'mk_wcwidth':
../components/libfort/fort.c:7282:11: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
           ^
../components/libfort/fort.c:7282:20: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
                    ^
../components/libfort/fort.c:7282:33: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
                                 ^
../components/libfort/fort.c:7282:42: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
                                          ^
../components/libfort/fort.c:7282:55: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
                                                       ^
../components/libfort/fort.c:7282:64: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
                                                                ^
../components/libfort/fort.c:7283:11: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
           ^
../components/libfort/fort.c:7283:20: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
                    ^
../components/libfort/fort.c:7283:33: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
                                 ^
../components/libfort/fort.c:7283:42: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
                                          ^
../components/libfort/fort.c:7283:55: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
                                                       ^
../components/libfort/fort.c:7283:64: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
                                                                ^
../components/libfort/fort.c:7284:11: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
           ^
../components/libfort/fort.c:7284:20: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
                    ^
../components/libfort/fort.c:7284:33: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
                                 ^
../components/libfort/fort.c:7284:42: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
                                          ^
../components/libfort/fort.c:7284:55: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
                                                       ^
../components/libfort/fort.c:7284:64: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
                                                                ^
../components/libfort/fort.c:7285:11: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
           ^
../components/libfort/fort.c:7285:20: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
                    ^
../components/libfort/fort.c:7285:33: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
                                 ^
../components/libfort/fort.c:7285:42: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
                                          ^
../components/libfort/fort.c:7285:55: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
                                                       ^
../components/libfort/fort.c:7285:64: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
                                                                ^
../components/libfort/fort.c:7286:11: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0xE0100, 0xE01EF }
           ^
../components/libfort/fort.c:7286:20: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         { 0xE0100, 0xE01EF }
                    ^
../components/libfort/fort.c:7314:19: warning: comparison is always false due to limited range of data type [-Wtype-limits]
              (ucs >= 0x20000 && ucs <= 0x2fffd) ||
                   ^
../components/libfort/fort.c:7314:37: warning: comparison is always true due to limited range of data type [-Wtype-limits]
              (ucs >= 0x20000 && ucs <= 0x2fffd) ||
                                     ^
../components/libfort/fort.c:7315:19: warning: comparison is always false due to limited range of data type [-Wtype-limits]
              (ucs >= 0x30000 && ucs <= 0x3fffd)));
                   ^
../components/libfort/fort.c:7315:37: warning: comparison is always true due to limited range of data type [-Wtype-limits]
              (ucs >= 0x30000 && ucs <= 0x3fffd)));
                                     ^
cc1: some warnings being treated as errors
ninja: build stopped: subcommand failed.
ninja failed with exit code 1

undefined reference to `ft_create_table'

Any Fix?

[atta@atta-pc APP]$ g++ app.cpp -std=c++11
/usr/bin/ld: /tmp/ccgEbx1a.o: in function fort::table<(fort::table_type)0>::table()': app.cpp:(.text._ZN4fort5tableILNS_10table_typeE0EEC2Ev[_ZN4fort5tableILNS_10table_typeE0EEC5Ev]+0x33): undefined reference to ft_create_table'
/usr/bin/ld: /tmp/ccgEbx1a.o: in function fort::table<(fort::table_type)0>::~table()': app.cpp:(.text._ZN4fort5tableILNS_10table_typeE0EED2Ev[_ZN4fort5tableILNS_10table_typeE0EED5Ev]+0x18): undefined reference to ft_destroy_table'
/usr/bin/ld: /tmp/ccgEbx1a.o: in function fort::table<(fort::table_type)0>::operator<<(fort::table_manipulator const&)': app.cpp:(.text._ZN4fort5tableILNS_10table_typeE0EElsERKNS_17table_manipulatorE[_ZN4fort5tableILNS_10table_typeE0EElsERKNS_17table_manipulatorE]+0x41): undefined reference to ft_set_cell_prop'
/usr/bin/ld: app.cpp:(.text._ZN4fort5tableILNS_10table_typeE0EElsERKNS_17table_manipulatorE[_ZN4fort5tableILNS_10table_typeE0EElsERKNS_17table_manipulatorE]+0x63): undefined reference to ft_ln' /usr/bin/ld: app.cpp:(.text._ZN4fort5tableILNS_10table_typeE0EElsERKNS_17table_manipulatorE[_ZN4fort5tableILNS_10table_typeE0EElsERKNS_17table_manipulatorE]+0x85): undefined reference to ft_add_separator'
/usr/bin/ld: /tmp/ccgEbx1a.o: in function fort::table<(fort::table_type)0>& fort::table<(fort::table_type)0>::operator<< <char [2]>(char const (&) [2])': app.cpp:(.text._ZN4fort5tableILNS_10table_typeE0EElsIA2_cEERS2_RKT_[_ZN4fort5tableILNS_10table_typeE0EElsIA2_cEERS2_RKT_]+0xa2): undefined reference to ft_nwrite'
/usr/bin/ld: /tmp/ccgEbx1a.o: in function fort::table<(fort::table_type)0>& fort::table<(fort::table_type)0>::operator<< <char [7]>(char const (&) [7])': app.cpp:(.text._ZN4fort5tableILNS_10table_typeE0EElsIA7_cEERS2_RKT_[_ZN4fort5tableILNS_10table_typeE0EElsIA7_cEERS2_RKT_]+0xa2): undefined reference to ft_nwrite'
/usr/bin/ld: /tmp/ccgEbx1a.o: in function fort::table<(fort::table_type)0>& fort::table<(fort::table_type)0>::operator<< <char [5]>(char const (&) [5])': app.cpp:(.text._ZN4fort5tableILNS_10table_typeE0EElsIA5_cEERS2_RKT_[_ZN4fort5tableILNS_10table_typeE0EElsIA5_cEERS2_RKT_]+0xa2): undefined reference to ft_nwrite'
/usr/bin/ld: /tmp/ccgEbx1a.o: in function fort::table<(fort::table_type)0>& fort::table<(fort::table_type)0>::operator<< <char [10]>(char const (&) [10])': app.cpp:(.text._ZN4fort5tableILNS_10table_typeE0EElsIA10_cEERS2_RKT_[_ZN4fort5tableILNS_10table_typeE0EElsIA10_cEERS2_RKT_]+0xa2): undefined reference to ft_nwrite'
/usr/bin/ld: /tmp/ccgEbx1a.o: in function fort::table<(fort::table_type)0>& fort::table<(fort::table_type)0>::operator<< <char [9]>(char const (&) [9])': app.cpp:(.text._ZN4fort5tableILNS_10table_typeE0EElsIA9_cEERS2_RKT_[_ZN4fort5tableILNS_10table_typeE0EElsIA9_cEERS2_RKT_]+0xa2): undefined reference to ft_nwrite'
/usr/bin/ld: /tmp/ccgEbx1a.o:app.cpp:(.text.ZN4fort5tableILNS_10table_typeE0EElsIA6_cEERS2_RKT[ZN4fort5tableILNS_10table_typeE0EElsIA6_cEERS2_RKT]+0xa2): more undefined references to ft_nwrite' follow /usr/bin/ld: /tmp/ccgEbx1a.o: in function fort::table<(fort::table_type)0>::c_str() const':
app.cpp:(.text._ZNK4fort5tableILNS_10table_typeE0EE5c_strEv[_ZNK4fort5tableILNS_10table_typeE0EE5c_strEv]+0x18): undefined reference to `ft_to_string'
collect2: error: ld returned 1 exit status

Built-in style for RST (reStructuredText Markup) table

+------------------------+------------+----------+----------+
| Header row, column 1   | Header 2   | Header 3 | Header 4 |
| (header rows optional) |            |          |          |
+========================+============+==========+==========+
| body row 1, column 1   | column 2   | column 3 | column 4 |
+------------------------+------------+----------+----------+
| body row 2             | ...        | ...      |          |
+------------------------+------------+----------+----------+

an RST table looks like this, see https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#grid-tables

Do we have a build-in table style in libfort that gives result like above? If not can we add one (please name it RST_STYLE)

Feature request: reduce RAM consumption

The library has a relatively high RAM footprint, making it difficult to use on low-spec embedded systems. Printing a table with 4 or 5 rows easly allocates several kB of RAM.
Jumping in the code, I noticed that in the background buffers are allocated for each cell of the table, before printing starts.
Would it be possible to selectively draw the table in lines? For example, something like this:

    for (size_t i = 0; i != ft_get_number_of_rows_to_print(table); ++i)
    {
        memset(buffer, 0, 128);
        if (0 == ft_print_single_row(table, i, buffer, 256))
        {
            printf(buffer);
        }
    }

So that in the background, only the necessary allocations are done for a single row, and the buffers are freed after printing out.
Judging from the code, this would mean major code changes regarding the cell buffer handling.

Support exported targets

I have a C++ project using the CMake build system. I tried to link to libfort with
add_subdirectory(…) + target_link_libraries(mylib libfort) but cmake complains as it does not export targets. Indeed, there is no install(export ) for targets with CMake configuration files.
It would be possible to support also exported targets for use in an external project?
Thanks in advance for any help!

Is it possible to erase table data and add new data, but keep the header

We have a command line utility that uses this library to show the output in a tabular form, which is fetched from a running application. The header row of this output does not change between 2 invocations of the tool, but the data might change (as it has time stamps etc). Currently we create a table from scratch every time the tool is run. But the tool is run quite frequently (in fact with watch command), so I was wondering if we can create the header added just once and the data can be repopulated every time.. Is it possible?

Is it possible to code the header at the end?

I am dynamically populating a table in a function which returns ta string by calling to_string() in the end. My logic is such that I may end up in not adding any data at all to the table. In such cases I don't want to add any header to the table, so that to_string() returns an empty string.

Hence a feature to add the header at the end after knowing the number of rows (or whenever we wish) will be helpful. Currently I use workarounds to return an empty string from my function, as adding the header afterwards adds it after all the data added till then.

Feature request: raw CSV output

In my application, I pretty-print the data, but save them in a CSV as well. This would relieve me from having to manually write to the CSV stream myself (though the C++ syntax is similar).

Crash observed in v0.1.5

The following code crashes on commit bb6002ec0b0cf04a528d434944b617f5816dd633 (tag: v0.1.5) - this is the version we are using.

int main()
{
  // the pipe character appears occasionally in our strings
  // we use \n to wrap long strings
  std::string s =
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||||||||||||||||||||||||||\n"
      "||||||";

  fort::table table;
  table.set_border_style(FT_PLAIN_STYLE);

  table << fort::header << "hdr1"
        << "hdr2"
        << "xxx" << fort::endr;
  table << "3"
        << "" << s << fort::endr;

  // some of the rows in our table are rendered in red colour, 
  // while rest are in default colour.
  table.row(1).set_cell_content_fg_color(fort::color::red);
  std::cout << table.to_string() << std::endl;
}
$ ./a.out 
terminate called after throwing an instance of 'std::runtime_error'
  what():  Libfort runtime error
Aborted (core dumped)

I am not seeing this problem on tip of develop. Would you happen to know if this was ever found and fixed and which commit fixes this? We want to be sure that this has been fixed before updating libfort.

line at bottom of the table for FT_PLAIN_STYLE

#include <iostream>
#include "../src/fort.hpp"

int main(int argc, char** argv) {
  fort::table table;
  table.set_border_style(FT_PLAIN_STYLE);
  table << fort::header << "A"
        << "B" << fort::endr;

  int n_rows = argc > 1 ? std::stoi(argv[1]) : 5;
  for (int i = 0; i < n_rows; i++) {
    table << 3.14 << 12345 << fort::endr;
  }
  std::cout << table.to_string() << std::endl;
  return 0;
}

Can you build and run this code (accepts number of rows to be rendered as an argument):

~/libfort$ ./a.out 3
 -------------- 
  A      B      
 -------------- 
  3.14   12345  
  3.14   12345  
  3.14   12345  
                

~/libfort$ ./a.out 2
 -------------- 
  A      B      
 -------------- 
  3.14   12345  
  3.14   12345  
                

~/libfort$ ./a.out 1
 -------------- 
  A      B      
 -------------- 
  3.14   12345  
 -------------- 

Note the dashed line at the bottom of the table when there is only one row (other than the header). This line vanishes if I have more than one row in the table (other than the header). Isn't this a bug?

ft_color skips one number, produces an assert if bg white

diff --git a/src/fort.h b/src/fort.h
index 11c35a2..39f7b8d 100644
--- a/src/fort.h
+++ b/src/fort.h
@@ -820,9 +820,9 @@ enum ft_color {
     FT_COLOR_LIGHT_GREEN    = 11, /**< Light green color */
     FT_COLOR_LIGHT_YELLOW   = 12, /**< Light yellow color */
     FT_COLOR_LIGHT_BLUE     = 13, /**< Light blue color */
-    FT_COLOR_LIGHT_MAGENTA  = 15, /**< Light magenta color */
-    FT_COLOR_LIGHT_CYAN     = 16, /**< Light cyan color */
-    FT_COLOR_LIGHT_WHYTE    = 17  /**< Light whyte color */
+    FT_COLOR_LIGHT_MAGENTA  = 14, /**< Light magenta color */
+    FT_COLOR_LIGHT_CYAN     = 15, /**< Light cyan color */
+    FT_COLOR_LIGHT_WHITE    = 16  /**< Light white color */
 };
 
 /**

Invalid type cast

In

return (((unsigned long)buffer->str.data) & (sizeof(wchar_t) - 1)) == 0;
contains a cast from pointer to integer of different size according to CLang warnings

This may attract side effects for x64 ¯_(ツ)_/¯

Undefined reference while building shared library that uses libfort

Everything works file is the library is static. But when SHARED is added to add_library then it gives linker error.

project(fortapp)

add_subdirectory(libfort)
add_library(fortapplib SHARED lib.cpp)
target_link_libraries(fortapplib fort)

add_executable(fortapp main.cpp)
target_link_libraries(fortapp fortapplib)

With the above CMake configuration I get

[1/3] Building CXX object CMakeFiles/fortapplib.dir/lib.cpp.o
[2/3] Linking CXX shared library libfortapplib.so
FAILED: libfortapplib.so 
: && /usr/bin/c++ -fPIC    -shared -Wl,-soname,libfortapplib.so -o libfortapplib.so CMakeFiles/fortapplib.dir/lib.cpp.o  libfort/lib/libfort.a && :
/usr/bin/ld: libfort/lib/libfort.a(fort.c.o): relocation R_X86_64_PC32 against symbol `fort_calloc' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
*** Failure: Exit code 1 ***

segfault in ft_to_string()

I'm still working on getting a backtrace and simplified code that reproduces, but encountered a segfault/crash if one tries to set the current cell position to an empty/non-existent cell. For example, code filling in what will ultimately be a 2-row, 6-col table out of order like this:

ft_printf(t, "%s|%.2lf|%d|%c", "testing", 21.0/7.0, 12, 'X');
ft_ln(t);
ft_printf(t, "123|321|abc|def|hij|klm");
ft_set_cur_cell(t, 0, 4); // causes badness, but not yet observed
ft_printf(t, "1|2");
ft_to_string(t); // crash

Are unicode characters supported?

I tried the following code on latest libfort code

int main() {
    fort::char_table table;
    table << fort::header << "N"
          << "Driver"
          << "Time"
          << "Avg Speed" << fort::endr;
    table << "α"  // unicode!
          << "Hamilton"
          << "1:26.373"
          << "35.02" << fort::endr;
    std::cout << table.to_string() << std::endl;
}

Here is the output, note how the formatting has gone bad!

+----+----------+----------+-----------+
| N  | Driver   | Time     | Avg Speed |
+----+----------+----------+-----------+
| α | Hamilton | 1:26.373 | 35.02     |
+----+----------+----------+-----------+

Looks like string length calculations go haywire if we try to put unicode characters in a table.

Escape sequences break the formatting of tables

Is there a possibility to ignore escape sequences when calculating table layout? I've found that escape sequences are processed as regular text which lead to improper table layout calculations. Can I propose to add such support?

I think the simple solution would be to implement a function like ft_set_u8strwid_func for char buffers. Separate concept of string length from string width. Implement two different functions: one for calculating string length and another for calculating string visible width.

Remove trailing whitespace for FT_PLAIN_STYLE (& other similar styles)

If you look at the output of a table using this style:

------------
 Key   Value 
-------------
 Key1  true  
 Key2  2000  
-------------

Every line of string that is generated has the same length, some of them have been appended with whitespaces for achieving same length. This is required for styles that use table borders, but not for styles like FT_PLAIN_STYLE which do not have table borders.

Can such trailing whitespaces be removed? It would be good enhancement, the resulting test when copied from a terminal and pasted at other places, won't have these unnecessary trailing whitespace

It's not possible to build (or rather use) libfort as .dll on windows

Because of following externs:

libfort/src/fort.h

Lines 716 to 730 in 51910b1

extern const struct ft_border_style *const FT_BASIC_STYLE;
extern const struct ft_border_style *const FT_BASIC2_STYLE;
extern const struct ft_border_style *const FT_SIMPLE_STYLE;
extern const struct ft_border_style *const FT_PLAIN_STYLE;
extern const struct ft_border_style *const FT_DOT_STYLE;
extern const struct ft_border_style *const FT_EMPTY_STYLE;
extern const struct ft_border_style *const FT_EMPTY2_STYLE;
extern const struct ft_border_style *const FT_SOLID_STYLE;
extern const struct ft_border_style *const FT_SOLID_ROUND_STYLE;
extern const struct ft_border_style *const FT_NICE_STYLE;
extern const struct ft_border_style *const FT_DOUBLE_STYLE;
extern const struct ft_border_style *const FT_DOUBLE2_STYLE;
extern const struct ft_border_style *const FT_BOLD_STYLE;
extern const struct ft_border_style *const FT_BOLD2_STYLE;
extern const struct ft_border_style *const FT_FRAME_STYLE;

it's not possible to use library as a .dll

please add corresponding macros for windows with __declspec(dllimport)/__declspec(dllexport).

IMHO it would be better to use enum and resolve it internally into a pointer to a built in style.

Not more than 15 columns supported

I am not able to add more than 15 columns as it throws compiler warning and segmentation fault on running it.

warning: passing argument 2 of ‘ft_u8nwrite_ln’ makes integer from pointer without a cast [-Wint-conversion]
 Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг", "Ранг", "Название", "s","x");
                                                                                                                                                                             ^
util/libfort/fort.h:187:23: note: in definition of macro ‘FT_EXPAND_’
 #define FT_EXPAND_(x) x
                       ^
util/libfort/fort.h:189:16: note: in expansion of macro ‘FT_NARGS_IMPL_’
     FT_EXPAND_(FT_NARGS_IMPL_(__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))
                ^~~~~~~~~~~~~~
util/libfort/fort.h:1011:28: note: in expansion of macro ‘FT_PP_NARG_’
     (ft_u8nwrite_ln(table, FT_PP_NARG_(__VA_ARGS__), __VA_ARGS__))
                            ^~~~~~~~~~~
testprogram.c:72:5: note: in expansion of macro ‘ft_u8write_ln’
     ft_u8write_ln(table, "Ранг", "Название", "Год", "Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг", "Ранг", "Название", "s","x");
     ^~~~~~~~~~~~~
In file included from testprogram.c:12:0:
util/libfort/fort.c:3680:5: note: expected ‘size_t {aka long unsigned int}’ but argument is of type ‘char *’
 int ft_u8nwrite_ln(ft_table_t *table, size_t n, const void *cell_content, ...)warning: passing argument 2 of ‘ft_u8nwrite_ln’ makes integer from pointer without a cast [-Wint-conversion]
 Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг", "Ранг", "Название", "s","x");
                                                                                                                                                                             ^
util/libfort/fort.h:187:23: note: in definition of macro ‘FT_EXPAND_’
 #define FT_EXPAND_(x) x
                       ^
util/libfort/fort.h:189:16: note: in expansion of macro ‘FT_NARGS_IMPL_’
     FT_EXPAND_(FT_NARGS_IMPL_(__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))
                ^~~~~~~~~~~~~~
util/libfort/fort.h:1011:28: note: in expansion of macro ‘FT_PP_NARG_’
     (ft_u8nwrite_ln(table, FT_PP_NARG_(__VA_ARGS__), __VA_ARGS__))
                            ^~~~~~~~~~~
testprogram.c:72:5: note: in expansion of macro ‘ft_u8write_ln’
     ft_u8write_ln(table, "Ранг", "Название", "Год", "Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг","Рейтинг", "Ранг", "Название", "s","x");
     ^~~~~~~~~~~~~
In file included from testprogram.c:12:0:
util/libfort/fort.c:3680:5: note: expected ‘size_t {aka long unsigned int}’ but argument is of type ‘char *’
 int ft_u8nwrite_ln(ft_table_t *table, size_t n, const void *cell_content, ...)

make the header bold?

I need a table with only the header (row[0]) in bold:

fort::table table;
table << fort::header << "A" << "B" << fort::endr;
table << 3.14 << 12345 << fort::endr;
table << 3.14 << 12345 << fort::endr;
table << 3.14 << 12345 << fort::endr;
table.row(0).set_cell_content_text_style(fort::text_style::bold);
table.row(0).set_cell_content_fg_color(fort::color::red);
std::cout << table.to_string() << std::endl;

This is making the whole table bold, in fact everything I type in the terminal is bold after running this code. Guess the closing tag for bold text encoding is missing.
However text color for the header row is red as expected.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.