solidc
Robust collection of general-purpose cross-platform C libraries and data structures designed for rapid and safe development in C
Loading...
Searching...
No Matches
prettytable.c
Go to the documentation of this file.
1
6#include "../include/prettytable.h"
7
8#include <stdlib.h>
9#include <string.h>
10
11// Predefined styles
13 .top_left = "┌",
14 .top_mid = "┬",
15 .top_right = "┐",
16 .mid_left = "├",
17 .mid_mid = "┼",
18 .mid_right = "┤",
19 .bottom_left = "└",
20 .bottom_mid = "┴",
21 .bottom_right = "┘",
22 .horizontal = "─",
23 .vertical = "│",
24};
25
26const prettytable_style PRETTYTABLE_STYLE_ASCII = {
27 .top_left = "+",
28 .top_mid = "+",
29 .top_right = "+",
30 .mid_left = "+",
31 .mid_mid = "+",
32 .mid_right = "+",
33 .bottom_left = "+",
34 .bottom_mid = "+",
35 .bottom_right = "+",
36 .horizontal = "-",
37 .vertical = "|",
38};
39
40const prettytable_style PRETTYTABLE_STYLE_MINIMAL = {
41 .top_left = "",
42 .top_mid = "",
43 .top_right = "",
44 .mid_left = "",
45 .mid_mid = " ",
46 .mid_right = "",
47 .bottom_left = "",
48 .bottom_mid = "",
49 .bottom_right = "",
50 .horizontal = "",
51 .vertical = " ",
52};
53
54const prettytable_style PRETTYTABLE_STYLE_DOUBLE = {
55 .top_left = "╔",
56 .top_mid = "╦",
57 .top_right = "╗",
58 .mid_left = "╠",
59 .mid_mid = "╬",
60 .mid_right = "╣",
61 .bottom_left = "╚",
62 .bottom_mid = "╩",
63 .bottom_right = "╝",
64 .horizontal = "═",
65 .vertical = "║",
66};
67
69 config->num_rows = 0;
70 config->num_cols = 0;
71 config->get_header = NULL;
72 config->get_cell = NULL;
73 config->get_length = NULL;
74 config->user_data = NULL;
75 config->style = &PRETTYTABLE_STYLE_BOX;
76 config->show_header = true;
77 config->show_row_count = true;
78 config->output = stdout;
79}
80
84static inline int get_text_length(const prettytable_config* cfg, const char* text) {
85 if (cfg->get_length) {
86 return cfg->get_length(cfg->user_data, text);
87 }
88 return (int)strlen(text);
89}
90
94static void calculate_column_widths(const prettytable_config* cfg, int* widths) {
95 // Initialize with header lengths if showing headers
96 if (cfg->show_header && cfg->get_header) {
97 for (int col = 0; col < cfg->num_cols; col++) {
98 const char* header = cfg->get_header(cfg->user_data, col);
99 widths[col] = get_text_length(cfg, header);
100 }
101 } else {
102 for (int col = 0; col < cfg->num_cols; col++) {
103 widths[col] = 0;
104 }
105 }
106
107 // Check each row for maximum width
108 for (int row = 0; row < cfg->num_rows; row++) {
109 for (int col = 0; col < cfg->num_cols; col++) {
110 const char* value = cfg->get_cell(cfg->user_data, row, col);
111 int len = get_text_length(cfg, value);
112 if (len > widths[col]) {
113 widths[col] = len;
114 }
115 }
116 }
117}
118
122static inline void print_separator(const prettytable_config* cfg, const int* widths, const char* left, const char* mid,
123 const char* right) {
124 const prettytable_style* style = cfg->style;
125 FILE* out = cfg->output;
126
127 fputs(left, out);
128 for (int col = 0; col < cfg->num_cols; col++) {
129 // Print horizontal line for column (with padding)
130 for (int i = 0; i < widths[col] + 2; i++) {
131 fputs(style->horizontal, out);
132 }
133
134 if (col < cfg->num_cols - 1) {
135 fputs(mid, out);
136 }
137 }
138 fputs(right, out);
139 fputc('\n', out);
140}
141
145static inline void print_row(const prettytable_config* cfg, const int* widths, const char** values) {
146 const prettytable_style* style = cfg->style;
147 FILE* out = cfg->output;
148
149 fputs(style->vertical, out);
150
151 for (int col = 0; col < cfg->num_cols; col++) {
152 fprintf(out, " %-*s ", widths[col], values[col]);
153 fputs(style->vertical, out);
154 }
155 fputc('\n', out);
156}
157
159 if (!config || !config->get_cell) {
160 return -1;
161 }
162
163 if (config->num_cols <= 0) {
164 fprintf(config->output ? config->output : stderr, "(No columns)\n");
165 return 0;
166 }
167
168 const prettytable_config* cfg = config;
169 const prettytable_style* style = cfg->style ? cfg->style : &PRETTYTABLE_STYLE_BOX;
170
171 // Allocate single block for widths and row data
172 void* block = malloc(sizeof(int) * (size_t)cfg->num_cols + sizeof(char*) * (size_t)cfg->num_cols);
173 if (!block) {
174 fprintf(stderr, "Memory allocation failed\n");
175 return -1;
176 }
177
178 int* widths = (int*)block;
179 const char** row_data = (const char**)((char*)block + sizeof(int) * (size_t)cfg->num_cols);
180
181 // Calculate column widths
182 calculate_column_widths(cfg, widths);
183
184 // Print top border
185 print_separator(cfg, widths, style->top_left, style->top_mid, style->top_right);
186
187 // Print header if requested
188 if (cfg->show_header && cfg->get_header) {
189 for (int col = 0; col < cfg->num_cols; col++) {
190 row_data[col] = cfg->get_header(cfg->user_data, col);
191 }
192 print_row(cfg, widths, row_data);
193
194 // Print header separator
195 print_separator(cfg, widths, style->mid_left, style->mid_mid, style->mid_right);
196 }
197
198 // Print data rows
199 for (int row = 0; row < cfg->num_rows; row++) {
200 for (int col = 0; col < cfg->num_cols; col++) {
201 row_data[col] = cfg->get_cell(cfg->user_data, row, col);
202 }
203 print_row(cfg, widths, row_data);
204 }
205
206 // Print bottom border
207 print_separator(cfg, widths, style->bottom_left, style->bottom_mid, style->bottom_right);
208
209 // Print row count if requested
210 if (cfg->show_row_count) {
211 fprintf(cfg->output, "(%d row%s)\n", cfg->num_rows, cfg->num_rows == 1 ? "" : "s");
212 }
213
214 free(block);
215 return 0;
216}
const prettytable_style PRETTYTABLE_STYLE_BOX
Definition prettytable.c:12
int prettytable_print(const prettytable_config *config)
void prettytable_config_init(prettytable_config *config)
Definition prettytable.c:68