💾 Archived View for gmi.noulin.net › gitRepositories › csvFmt › file › fort.c.gmi captured on 2024-08-18 at 17:54:07. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
fort.c (227773B)
1 /* 2 libfort 3 4 MIT License 5 6 Copyright (c) 2017 - 2020 Seleznev Anton 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in all 16 copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 SOFTWARE. 25 */ 26 27 /* The file was GENERATED by an amalgamation script.*/ 28 /* DO NOT EDIT BY HAND!!! */ 29 30 31 #define FT_AMALGAMED_SOURCE /* Macros to make internal libfort functions static */ 32 33 34 /******************************************************** 35 Begin of file "fort_utils.h" 36 ********************************************************/ 37 38 #ifndef FORT_IMPL_H 39 #define FORT_IMPL_H 40 41 #if defined(_MSC_VER) 42 #define _CRT_SECURE_NO_WARNINGS /* To disable warnings for unsafe functions */ 43 #endif 44 45 #include <stddef.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <assert.h> 49 #include <stdio.h> 50 #include <stdbool.h> 51 #include "fort.h" 52 53 /* Define FT_INTERNAL to make internal libfort functions static 54 * in the result amalgamed source file. 55 */ 56 #ifdef FT_AMALGAMED_SOURCE 57 #define FT_INTERNAL static 58 #else 59 #define FT_INTERNAL 60 #endif /* FT_AMALGAMED_SORCE */ 61 62 63 #define FORT_DEFAULT_COL_SEPARATOR '|' 64 extern char g_col_separator; 65 66 #define FORT_COL_SEPARATOR_LENGTH 1 67 68 #define FORT_UNUSED __attribute__((unused)) 69 70 #define F_MALLOC fort_malloc 71 #define F_FREE fort_free 72 #define F_CALLOC fort_calloc 73 #define F_REALLOC fort_realloc 74 #define F_STRDUP fort_strdup 75 #define F_WCSDUP fort_wcsdup 76 /* @todo: replace with custom impl !!!*/ 77 #define F_UTF8DUP utf8dup 78 79 #define F_CREATE(type) ((type *)F_CALLOC(sizeof(type), 1)) 80 81 #define MAX(a,b) ((a) > (b) ? (a) : (b)) 82 #define MIN(a,b) ((a) < (b) ? (a) : (b)) 83 84 #define FT_NEWLINE "\n" 85 #define FT_SPACE " " 86 87 /***************************************************************************** 88 * DEFAULT_SIZES 89 * ***************************************************************************/ 90 #define DEFAULT_STR_BUF_SIZE 1024 91 #define DEFAULT_VECTOR_CAPACITY 10 92 93 /***************************************************************************** 94 * DATA TYPES 95 * ***************************************************************************/ 96 97 enum f_get_policy { 98 CREATE_ON_NULL, 99 DONT_CREATE_ON_NULL 100 }; 101 102 enum f_bool { 103 F_FALSE = 0, 104 F_TRUE = 1 105 }; 106 107 enum f_cell_type { 108 COMMON_CELL, 109 GROUP_MASTER_CELL, 110 GROUP_SLAVE_CELL 111 }; 112 113 enum f_geometry_type { 114 VISIBLE_GEOMETRY, 115 INTERN_REPR_GEOMETRY 116 }; 117 118 enum f_string_type { 119 CHAR_BUF, 120 #ifdef FT_HAVE_WCHAR 121 W_CHAR_BUF, 122 #endif /* FT_HAVE_WCHAR */ 123 #ifdef FT_HAVE_UTF8 124 UTF8_BUF, 125 #endif /* FT_HAVE_WCHAR */ 126 }; 127 128 struct f_string_view { 129 union { 130 const char *cstr; 131 #ifdef FT_HAVE_WCHAR 132 const wchar_t *wstr; 133 #endif 134 #ifdef FT_HAVE_UTF8 135 const void *u8str; 136 #endif 137 const void *data; 138 } u; 139 enum f_string_type type; 140 }; 141 typedef struct f_string_view f_string_view_t; 142 143 144 #define FT_STR_2_CAT_(arg1, arg2) \ 145 arg1##arg2 146 #define FT_STR_2_CAT(arg1, arg2) \ 147 FT_STR_2_CAT_(arg1, arg2) 148 149 #define UNIQUE_NAME_(prefix) \ 150 FT_STR_2_CAT(prefix,__COUNTER__) 151 #define UNIQUE_NAME(prefix) \ 152 UNIQUE_NAME_(prefix) 153 154 typedef int f_status; 155 156 157 158 159 struct f_table_properties; 160 struct f_row; 161 struct f_vector; 162 struct f_cell; 163 struct f_string_buffer; 164 struct f_separator { 165 int enabled; 166 }; 167 168 typedef struct f_table_properties f_table_properties_t; 169 typedef struct f_vector f_vector_t; 170 typedef struct f_cell f_cell_t; 171 typedef struct f_string_buffer f_string_buffer_t; 172 typedef struct f_row f_row_t; 173 typedef struct f_separator f_separator_t; 174 175 struct f_context { 176 f_table_properties_t *table_properties; 177 size_t row; 178 size_t column; 179 }; 180 typedef struct f_context f_context_t; 181 182 struct f_conv_context { 183 union { 184 char *buf; 185 #ifdef FT_HAVE_WCHAR 186 wchar_t *wbuf; 187 #endif 188 #ifdef FT_HAVE_UTF8 189 const void *u8str; 190 #endif 191 } u; 192 size_t raw_avail; 193 struct f_context *cntx; 194 enum f_string_type b_type; 195 }; 196 typedef struct f_conv_context f_conv_context_t; 197 198 199 /***************************************************************************** 200 * LIBFORT helpers 201 *****************************************************************************/ 202 203 extern void *(*fort_malloc)(size_t size); 204 extern void (*fort_free)(void *ptr); 205 extern void *(*fort_calloc)(size_t nmemb, size_t size); 206 extern void *(*fort_realloc)(void *ptr, size_t size); 207 208 FT_INTERNAL 209 void set_memory_funcs(void *(*f_malloc)(size_t size), void (*f_free)(void *ptr)); 210 211 FT_INTERNAL 212 char *fort_strdup(const char *str); 213 214 215 216 FT_INTERNAL 217 size_t number_of_columns_in_format_string(const f_string_view_t *fmt); 218 219 FT_INTERNAL 220 size_t number_of_columns_in_format_buffer(const f_string_buffer_t *fmt); 221 222 #if defined(FT_HAVE_WCHAR) 223 FT_INTERNAL 224 wchar_t *fort_wcsdup(const wchar_t *str); 225 #endif 226 227 228 229 FT_INTERNAL 230 int print_n_strings(f_conv_context_t *cntx, size_t n, const char *str); 231 232 233 FT_INTERNAL 234 int ft_nprint(f_conv_context_t *cntx, const char *str, size_t strlen); 235 #ifdef FT_HAVE_WCHAR 236 FT_INTERNAL 237 int ft_nwprint(f_conv_context_t *cntx, const wchar_t *str, size_t strlen); 238 #endif /* FT_HAVE_WCHAR */ 239 #ifdef FT_HAVE_UTF8 240 FT_INTERNAL 241 int ft_nu8print(f_conv_context_t *cntx, const void *beg, const void *end); 242 #endif /* FT_HAVE_UTF8 */ 243 244 245 /*#define PRINT_DEBUG_INFO fprintf(stderr, "error in %s(%s:%d)\n", __FUNCTION__, __FILE__, __LINE__);*/ 246 #define PRINT_DEBUG_INFO 247 248 #define FT_CHECK(statement) \ 249 do { \ 250 tmp = statement; \ 251 if (tmp < 0) {\ 252 PRINT_DEBUG_INFO \ 253 goto clear; \ 254 } \ 255 } while(0) 256 257 #define CHCK_RSLT_ADD_TO_WRITTEN(statement) \ 258 do { \ 259 tmp = statement; \ 260 if (tmp < 0) {\ 261 PRINT_DEBUG_INFO \ 262 goto clear; \ 263 } \ 264 written += (size_t)tmp; \ 265 } while(0) 266 267 #define CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(statement) \ 268 do { \ 269 tmp = statement; \ 270 if (tmp < 0) {\ 271 PRINT_DEBUG_INFO \ 272 goto clear; \ 273 } \ 274 invisible_written += (size_t)tmp; \ 275 } while(0) 276 277 278 #define CHECK_NOT_NEGATIVE(x) \ 279 do { if ((x) < 0) goto fort_fail; } while (0) 280 281 #endif /* FORT_IMPL_H */ 282 283 /******************************************************** 284 End of file "fort_utils.h" 285 ********************************************************/ 286 287 288 /******************************************************** 289 Begin of file "vector.h" 290 ********************************************************/ 291 292 #ifndef VECTOR_H 293 #define VECTOR_H 294 295 /* #include "fort_utils.h" */ /* Commented by amalgamation script */ 296 297 298 #define INVALID_VEC_INDEX ((size_t) -1) 299 300 FT_INTERNAL 301 f_vector_t *create_vector(size_t item_size, size_t capacity); 302 303 FT_INTERNAL 304 void destroy_vector(f_vector_t *); 305 306 FT_INTERNAL 307 size_t vector_size(const f_vector_t *); 308 309 FT_INTERNAL 310 size_t vector_capacity(const f_vector_t *); 311 312 FT_INTERNAL 313 int vector_push(f_vector_t *, const void *item); 314 315 FT_INTERNAL 316 int vector_insert(f_vector_t *, const void *item, size_t pos); 317 318 FT_INTERNAL 319 f_vector_t *vector_split(f_vector_t *, size_t pos); 320 321 FT_INTERNAL 322 const void *vector_at_c(const f_vector_t *vector, size_t index); 323 324 FT_INTERNAL 325 void *vector_at(f_vector_t *, size_t index); 326 327 FT_INTERNAL 328 f_status vector_swap(f_vector_t *cur_vec, f_vector_t *mv_vec, size_t pos); 329 330 FT_INTERNAL 331 void vector_clear(f_vector_t *); 332 333 FT_INTERNAL 334 int vector_erase(f_vector_t *, size_t index); 335 336 #ifdef FT_TEST_BUILD 337 f_vector_t *copy_vector(f_vector_t *); 338 size_t vector_index_of(const f_vector_t *, const void *item); 339 #endif 340 341 #define VECTOR_AT(vector, pos, data_type) \ 342 *(data_type *)vector_at((vector), (pos)) 343 344 #define VECTOR_AT_C(vector, pos, const_data_type) \ 345 *(const_data_type *)vector_at_c((vector), (pos)) 346 347 #endif /* VECTOR_H */ 348 349 /******************************************************** 350 End of file "vector.h" 351 ********************************************************/ 352 353 354 /******************************************************** 355 Begin of file "wcwidth.h" 356 ********************************************************/ 357 358 #ifndef WCWIDTH_H 359 #define WCWIDTH_H 360 361 /* #include "fort_utils.h" */ /* Commented by amalgamation script */ 362 363 #ifdef FT_HAVE_WCHAR 364 #include <wchar.h> 365 366 FT_INTERNAL 367 int mk_wcswidth(const wchar_t *pwcs, size_t n); 368 369 #endif /* FT_HAVE_WCHAR */ 370 371 #endif /* WCWIDTH_H */ 372 373 /******************************************************** 374 End of file "wcwidth.h" 375 ********************************************************/ 376 377 378 /******************************************************** 379 Begin of file "utf8.h" 380 ********************************************************/ 381 382 // The latest version of this library is available on GitHub; 383 // https://github.com/sheredom/utf8.h 384 385 // This is free and unencumbered software released into the public domain. 386 // 387 // Anyone is free to copy, modify, publish, use, compile, sell, or 388 // distribute this software, either in source code form or as a compiled 389 // binary, for any purpose, commercial or non-commercial, and by any 390 // means. 391 // 392 // In jurisdictions that recognize copyright laws, the author or authors 393 // of this software dedicate any and all copyright interest in the 394 // software to the public domain. We make this dedication for the benefit 395 // of the public at large and to the detriment of our heirs and 396 // successors. We intend this dedication to be an overt act of 397 // relinquishment in perpetuity of all present and future rights to this 398 // software under copyright law. 399 // 400 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 401 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 402 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 403 // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 404 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 405 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 406 // OTHER DEALINGS IN THE SOFTWARE. 407 // 408 // For more information, please refer to <http://unlicense.org/> 409 410 #ifndef SHEREDOM_UTF8_H_INCLUDED 411 #define SHEREDOM_UTF8_H_INCLUDED 412 413 #if defined(_MSC_VER) 414 #pragma warning(push) 415 416 // disable 'bytes padding added after construct' warning 417 #pragma warning(disable : 4820) 418 #endif 419 420 #include <stddef.h> 421 #include <stdlib.h> 422 423 #if defined(_MSC_VER) 424 #pragma warning(pop) 425 #endif 426 427 #if defined(_MSC_VER) 428 typedef __int32 utf8_int32_t; 429 #else 430 #include <stdint.h> 431 typedef int32_t utf8_int32_t; 432 #endif 433 434 #if defined(__clang__) 435 #pragma clang diagnostic push 436 #pragma clang diagnostic ignored "-Wold-style-cast" 437 #pragma clang diagnostic ignored "-Wcast-qual" 438 #endif 439 440 #ifdef __cplusplus 441 extern "C" { 442 #endif 443 444 #if defined(__clang__) || defined(__GNUC__) 445 #define utf8_nonnull __attribute__((nonnull)) 446 #define utf8_pure __attribute__((pure)) 447 #define utf8_restrict __restrict__ 448 #define utf8_weak __attribute__((weak)) 449 #elif defined(_MSC_VER) 450 #define utf8_nonnull 451 #define utf8_pure 452 #define utf8_restrict __restrict 453 #define utf8_weak __inline 454 #else 455 #define utf8_nonnull 456 #define utf8_pure 457 #define utf8_restrict 458 #define utf8_weak inline 459 #endif 460 461 #ifdef __cplusplus 462 #define utf8_null NULL 463 #else 464 #define utf8_null 0 465 #endif 466 467 // Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > 468 // src2 respectively, case insensitive. 469 utf8_nonnull utf8_pure utf8_weak int utf8casecmp(const void *src1, 470 const void *src2); 471 472 // Append the utf8 string src onto the utf8 string dst. 473 utf8_nonnull utf8_weak void *utf8cat(void *utf8_restrict dst, 474 const void *utf8_restrict src); 475 476 // Find the first match of the utf8 codepoint chr in the utf8 string src. 477 utf8_nonnull utf8_pure utf8_weak void *utf8chr(const void *src, 478 utf8_int32_t chr); 479 480 // Return less than 0, 0, greater than 0 if src1 < src2, 481 // src1 == src2, src1 > src2 respectively. 482 utf8_nonnull utf8_pure utf8_weak int utf8cmp(const void *src1, 483 const void *src2); 484 485 // Copy the utf8 string src onto the memory allocated in dst. 486 utf8_nonnull utf8_weak void *utf8cpy(void *utf8_restrict dst, 487 const void *utf8_restrict src); 488 489 // Number of utf8 codepoints in the utf8 string src that consists entirely 490 // of utf8 codepoints not from the utf8 string reject. 491 utf8_nonnull utf8_pure utf8_weak size_t utf8cspn(const void *src, 492 const void *reject); 493 494 // Duplicate the utf8 string src by getting its size, malloc'ing a new buffer 495 // copying over the data, and returning that. Or 0 if malloc failed. 496 utf8_nonnull utf8_weak void *utf8dup(const void *src); 497 498 // Number of utf8 codepoints in the utf8 string str, 499 // excluding the null terminating byte. 500 utf8_nonnull utf8_pure utf8_weak size_t utf8len(const void *str); 501 502 // Visible width of utf8string. 503 utf8_nonnull utf8_pure utf8_weak size_t utf8width(const void *str); 504 505 // Visible width of codepoint. 506 utf8_nonnull utf8_pure utf8_weak int utf8cwidth(utf8_int32_t c); 507 508 // Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > 509 // src2 respectively, case insensitive. Checking at most n bytes of each utf8 510 // string. 511 utf8_nonnull utf8_pure utf8_weak int utf8ncasecmp(const void *src1, 512 const void *src2, size_t n); 513 514 // Append the utf8 string src onto the utf8 string dst, 515 // writing at most n+1 bytes. Can produce an invalid utf8 516 // string if n falls partway through a utf8 codepoint. 517 utf8_nonnull utf8_weak void *utf8ncat(void *utf8_restrict dst, 518 const void *utf8_restrict src, size_t n); 519 520 // Return less than 0, 0, greater than 0 if src1 < src2, 521 // src1 == src2, src1 > src2 respectively. Checking at most n 522 // bytes of each utf8 string. 523 utf8_nonnull utf8_pure utf8_weak int utf8ncmp(const void *src1, 524 const void *src2, size_t n); 525 526 // Copy the utf8 string src onto the memory allocated in dst. 527 // Copies at most n bytes. If there is no terminating null byte in 528 // the first n bytes of src, the string placed into dst will not be 529 // null-terminated. If the size (in bytes) of src is less than n, 530 // extra null terminating bytes are appended to dst such that at 531 // total of n bytes are written. Can produce an invalid utf8 532 // string if n falls partway through a utf8 codepoint. 533 utf8_nonnull utf8_weak void *utf8ncpy(void *utf8_restrict dst, 534 const void *utf8_restrict src, size_t n); 535 536 // Similar to utf8dup, except that at most n bytes of src are copied. If src is 537 // longer than n, only n bytes are copied and a null byte is added. 538 // 539 // Returns a new string if successful, 0 otherwise 540 utf8_nonnull utf8_weak void *utf8ndup(const void *src, size_t n); 541 542 // Locates the first occurence in the utf8 string str of any byte in the 543 // utf8 string accept, or 0 if no match was found. 544 utf8_nonnull utf8_pure utf8_weak void *utf8pbrk(const void *str, 545 const void *accept); 546 547 // Find the last match of the utf8 codepoint chr in the utf8 string src. 548 utf8_nonnull utf8_pure utf8_weak void *utf8rchr(const void *src, int chr); 549 550 // Number of bytes in the utf8 string str, 551 // including the null terminating byte. 552 utf8_nonnull utf8_pure utf8_weak size_t utf8size(const void *str); 553 554 // Number of utf8 codepoints in the utf8 string src that consists entirely 555 // of utf8 codepoints from the utf8 string accept. 556 utf8_nonnull utf8_pure utf8_weak size_t utf8spn(const void *src, 557 const void *accept); 558 559 // The position of the utf8 string needle in the utf8 string haystack. 560 utf8_nonnull utf8_pure utf8_weak void *utf8str(const void *haystack, 561 const void *needle); 562 563 // The position of the utf8 string needle in the utf8 string haystack, case 564 // insensitive. 565 utf8_nonnull utf8_pure utf8_weak void *utf8casestr(const void *haystack, 566 const void *needle); 567 568 // Return 0 on success, or the position of the invalid 569 // utf8 codepoint on failure. 570 utf8_nonnull utf8_pure utf8_weak void *utf8valid(const void *str); 571 572 // Sets out_codepoint to the next utf8 codepoint in str, and returns the address 573 // of the utf8 codepoint after the current one in str. 574 utf8_nonnull utf8_weak void * 575 utf8codepoint(const void *utf8_restrict str, 576 utf8_int32_t *utf8_restrict out_codepoint); 577 578 // Returns the size of the given codepoint in bytes. 579 utf8_weak size_t utf8codepointsize(utf8_int32_t chr); 580 581 // Write a codepoint to the given string, and return the address to the next 582 // place after the written codepoint. Pass how many bytes left in the buffer to 583 // n. If there is not enough space for the codepoint, this function returns 584 // null. 585 utf8_nonnull utf8_weak void *utf8catcodepoint(void *utf8_restrict str, 586 utf8_int32_t chr, size_t n); 587 588 // Returns 1 if the given character is lowercase, or 0 if it is not. 589 utf8_weak int utf8islower(utf8_int32_t chr); 590 591 // Returns 1 if the given character is uppercase, or 0 if it is not. 592 utf8_weak int utf8isupper(utf8_int32_t chr); 593 594 // Transform the given string into all lowercase codepoints. 595 utf8_nonnull utf8_weak void utf8lwr(void *utf8_restrict str); 596 597 // Transform the given string into all uppercase codepoints. 598 utf8_nonnull utf8_weak void utf8upr(void *utf8_restrict str); 599 600 // Make a codepoint lower case if possible. 601 utf8_weak utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp); 602 603 // Make a codepoint upper case if possible. 604 utf8_weak utf8_int32_t utf8uprcodepoint(utf8_int32_t cp); 605 606 #undef utf8_weak 607 #undef utf8_pure 608 #undef utf8_nonnull 609 610 int utf8casecmp(const void *src1, const void *src2) 611 { 612 utf8_int32_t src1_cp, src2_cp, src1_orig_cp, src2_orig_cp; 613 614 for (;;) { 615 src1 = utf8codepoint(src1, &src1_cp); 616 src2 = utf8codepoint(src2, &src2_cp); 617 618 // Take a copy of src1 & src2 619 src1_orig_cp = src1_cp; 620 src2_orig_cp = src2_cp; 621 622 // Lower the srcs if required 623 src1_cp = utf8lwrcodepoint(src1_cp); 624 src2_cp = utf8lwrcodepoint(src2_cp); 625 626 // Check if the lowered codepoints match 627 if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) { 628 return 0; 629 } else if (src1_cp == src2_cp) { 630 continue; 631 } 632 633 // If they don't match, then we return which of the original's are less 634 if (src1_orig_cp < src2_orig_cp) { 635 return -1; 636 } else if (src1_orig_cp > src2_orig_cp) { 637 return 1; 638 } 639 } 640 } 641 642 void *utf8cat(void *utf8_restrict dst, const void *utf8_restrict src) 643 { 644 char *d = (char *)dst; 645 const char *s = (const char *)src; 646 647 // find the null terminating byte in dst 648 while ('\0' != *d) { 649 d++; 650 } 651 652 // overwriting the null terminating byte in dst, append src byte-by-byte 653 while ('\0' != *s) { 654 *d++ = *s++; 655 } 656 657 // write out a new null terminating byte into dst 658 *d = '\0'; 659 660 return dst; 661 } 662 663 void *utf8chr(const void *src, utf8_int32_t chr) 664 { 665 char c[5] = {'\0', '\0', '\0', '\0', '\0'}; 666 667 if (0 == chr) { 668 // being asked to return position of null terminating byte, so 669 // just run s to the end, and return! 670 const char *s = (const char *)src; 671 while ('\0' != *s) { 672 s++; 673 } 674 return (void *)s; 675 } else if (0 == ((utf8_int32_t)0xffffff80 & chr)) { 676 // 1-byte/7-bit ascii 677 // (0b0xxxxxxx) 678 c[0] = (char)chr; 679 } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { 680 // 2-byte/11-bit utf8 code point 681 // (0b110xxxxx 0b10xxxxxx) 682 c[0] = 0xc0 | (char)(chr >> 6); 683 c[1] = 0x80 | (char)(chr & 0x3f); 684 } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { 685 // 3-byte/16-bit utf8 code point 686 // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) 687 c[0] = 0xe0 | (char)(chr >> 12); 688 c[1] = 0x80 | (char)((chr >> 6) & 0x3f); 689 c[2] = 0x80 | (char)(chr & 0x3f); 690 } else { // if (0 == ((int)0xffe00000 & chr)) { 691 // 4-byte/21-bit utf8 code point 692 // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) 693 c[0] = 0xf0 | (char)(chr >> 18); 694 c[1] = 0x80 | (char)((chr >> 12) & 0x3f); 695 c[2] = 0x80 | (char)((chr >> 6) & 0x3f); 696 c[3] = 0x80 | (char)(chr & 0x3f); 697 } 698 699 // we've made c into a 2 utf8 codepoint string, one for the chr we are 700 // seeking, another for the null terminating byte. Now use utf8str to 701 // search 702 return utf8str(src, c); 703 } 704 705 int utf8cmp(const void *src1, const void *src2) 706 { 707 const unsigned char *s1 = (const unsigned char *)src1; 708 const unsigned char *s2 = (const unsigned char *)src2; 709 710 while (('\0' != *s1) || ('\0' != *s2)) { 711 if (*s1 < *s2) { 712 return -1; 713 } else if (*s1 > *s2) { 714 return 1; 715 } 716 717 s1++; 718 s2++; 719 } 720 721 // both utf8 strings matched 722 return 0; 723 } 724 725 int utf8coll(const void *src1, const void *src2); 726 727 void *utf8cpy(void *utf8_restrict dst, const void *utf8_restrict src) 728 { 729 char *d = (char *)dst; 730 const char *s = (const char *)src; 731 732 // overwriting anything previously in dst, write byte-by-byte 733 // from src 734 while ('\0' != *s) { 735 *d++ = *s++; 736 } 737 738 // append null terminating byte 739 *d = '\0'; 740 741 return dst; 742 } 743 744 size_t utf8cspn(const void *src, const void *reject) 745 { 746 const char *s = (const char *)src; 747 size_t chars = 0; 748 749 while ('\0' != *s) { 750 const char *r = (const char *)reject; 751 size_t offset = 0; 752 753 while ('\0' != *r) { 754 // checking that if *r is the start of a utf8 codepoint 755 // (it is not 0b10xxxxxx) and we have successfully matched 756 // a previous character (0 < offset) - we found a match 757 if ((0x80 != (0xc0 & *r)) && (0 < offset)) { 758 return chars; 759 } else { 760 if (*r == s[offset]) { 761 // part of a utf8 codepoint matched, so move our checking 762 // onwards to the next byte 763 offset++; 764 r++; 765 } else { 766 // r could be in the middle of an unmatching utf8 code point, 767 // so we need to march it on to the next character beginning, 768 769 do { 770 r++; 771 } while (0x80 == (0xc0 & *r)); 772 773 // reset offset too as we found a mismatch 774 offset = 0; 775 } 776 } 777 } 778 779 // the current utf8 codepoint in src did not match reject, but src 780 // could have been partway through a utf8 codepoint, so we need to 781 // march it onto the next utf8 codepoint starting byte 782 do { 783 s++; 784 } while ((0x80 == (0xc0 & *s))); 785 chars++; 786 } 787 788 return chars; 789 } 790 791 size_t utf8size(const void *str); 792 793 void *utf8dup(const void *src) 794 { 795 const char *s = (const char *)src; 796 char *n = utf8_null; 797 798 // figure out how many bytes (including the terminator) we need to copy first 799 size_t bytes = utf8size(src); 800 801 n = (char *)malloc(bytes); 802 803 if (utf8_null == n) { 804 // out of memory so we bail 805 return utf8_null; 806 } else { 807 bytes = 0; 808 809 // copy src byte-by-byte into our new utf8 string 810 while ('\0' != s[bytes]) { 811 n[bytes] = s[bytes]; 812 bytes++; 813 } 814 815 // append null terminating byte 816 n[bytes] = '\0'; 817 return n; 818 } 819 } 820 821 void *utf8fry(const void *str); 822 823 size_t utf8len(const void *str) 824 { 825 const unsigned char *s = (const unsigned char *)str; 826 size_t length = 0; 827 828 while ('\0' != *s) { 829 if (0xf0 == (0xf8 & *s)) { 830 // 4-byte utf8 code point (began with 0b11110xxx) 831 s += 4; 832 } else if (0xe0 == (0xf0 & *s)) { 833 // 3-byte utf8 code point (began with 0b1110xxxx) 834 s += 3; 835 } else if (0xc0 == (0xe0 & *s)) { 836 // 2-byte utf8 code point (began with 0b110xxxxx) 837 s += 2; 838 } else { // if (0x00 == (0x80 & *s)) { 839 // 1-byte ascii (began with 0b0xxxxxxx) 840 s += 1; 841 } 842 843 // no matter the bytes we marched s forward by, it was 844 // only 1 utf8 codepoint 845 length++; 846 } 847 848 return length; 849 } 850 851 // See 852 // https://unicode.org/Public/UNIDATA/EastAsianWidth.txt 853 // http://www.unicode.org/reports/tr11/tr11-33.html 854 int utf8cwidth(utf8_int32_t c) 855 { 856 // TODO: add non printable characters check 857 if (c == 0) 858 return 0; 859 860 if (c < 0x1100) 861 return 1; 862 863 // Fullwidth 864 if ((0x3000 == c) || 865 (0xFF01 <= c && c <= 0xFF60) || 866 (0xFFE0 <= c && c <= 0xFFE6)) { 867 return 2; 868 } 869 870 // Wide 871 if ((0x1100 <= c && c <= 0x115F) || 872 (0x11A3 <= c && c <= 0x11A7) || 873 (0x11FA <= c && c <= 0x11FF) || 874 (0x2329 <= c && c <= 0x232A) || 875 (0x2E80 <= c && c <= 0x2E99) || 876 (0x2E9B <= c && c <= 0x2EF3) || 877 (0x2F00 <= c && c <= 0x2FD5) || 878 (0x2FF0 <= c && c <= 0x2FFB) || 879 (0x3001 <= c && c <= 0x303E) || 880 (0x3041 <= c && c <= 0x3096) || 881 (0x3099 <= c && c <= 0x30FF) || 882 (0x3105 <= c && c <= 0x312D) || 883 (0x3131 <= c && c <= 0x318E) || 884 (0x3190 <= c && c <= 0x31BA) || 885 (0x31C0 <= c && c <= 0x31E3) || 886 (0x31F0 <= c && c <= 0x321E) || 887 (0x3220 <= c && c <= 0x3247) || 888 (0x3250 <= c && c <= 0x32FE) || 889 (0x3300 <= c && c <= 0x4DBF) || 890 (0x4E00 <= c && c <= 0xA48C) || 891 (0xA490 <= c && c <= 0xA4C6) || 892 (0xA960 <= c && c <= 0xA97C) || 893 (0xAC00 <= c && c <= 0xD7A3) || 894 (0xD7B0 <= c && c <= 0xD7C6) || 895 (0xD7CB <= c && c <= 0xD7FB) || 896 (0xF900 <= c && c <= 0xFAFF) || 897 (0xFE10 <= c && c <= 0xFE19) || 898 (0xFE30 <= c && c <= 0xFE52) || 899 (0xFE54 <= c && c <= 0xFE66) || 900 (0xFE68 <= c && c <= 0xFE6B) || 901 (0x1B000 <= c && c <= 0x1B001) || 902 (0x1F200 <= c && c <= 0x1F202) || 903 (0x1F210 <= c && c <= 0x1F23A) || 904 (0x1F240 <= c && c <= 0x1F248) || 905 (0x1F250 <= c && c <= 0x1F251) || 906 (0x20000 <= c && c <= 0x2F73F) || 907 (0x2B740 <= c && c <= 0x2FFFD) || 908 (0x30000 <= c && c <= 0x3FFFD)) { 909 return 2; 910 } 911 912 return 1; 913 } 914 915 size_t utf8width(const void *str) 916 { 917 size_t length = 0; 918 utf8_int32_t c = 0; 919 920 str = utf8codepoint(str, &c); 921 while (c != 0) { 922 length += utf8cwidth(c); 923 str = utf8codepoint(str, &c); 924 } 925 return length; 926 } 927 928 int utf8ncasecmp(const void *src1, const void *src2, size_t n) 929 { 930 utf8_int32_t src1_cp, src2_cp, src1_orig_cp, src2_orig_cp; 931 932 do { 933 const unsigned char *const s1 = (const unsigned char *)src1; 934 const unsigned char *const s2 = (const unsigned char *)src2; 935 936 // first check that we have enough bytes left in n to contain an entire 937 // codepoint 938 if (0 == n) { 939 return 0; 940 } 941 942 if ((1 == n) && ((0xc0 == (0xe0 & *s1)) || (0xc0 == (0xe0 & *s2)))) { 943 const utf8_int32_t c1 = (0xe0 & *s1); 944 const utf8_int32_t c2 = (0xe0 & *s2); 945 946 if (c1 < c2) { 947 return -1; 948 } else if (c1 > c2) { 949 return 1; 950 } else { 951 return 0; 952 } 953 } 954 955 if ((2 >= n) && ((0xe0 == (0xf0 & *s1)) || (0xe0 == (0xf0 & *s2)))) { 956 const utf8_int32_t c1 = (0xf0 & *s1); 957 const utf8_int32_t c2 = (0xf0 & *s2); 958 959 if (c1 < c2) { 960 return -1; 961 } else if (c1 > c2) { 962 return 1; 963 } else { 964 return 0; 965 } 966 } 967 968 if ((3 >= n) && ((0xf0 == (0xf8 & *s1)) || (0xf0 == (0xf8 & *s2)))) { 969 const utf8_int32_t c1 = (0xf8 & *s1); 970 const utf8_int32_t c2 = (0xf8 & *s2); 971 972 if (c1 < c2) { 973 return -1; 974 } else if (c1 > c2) { 975 return 1; 976 } else { 977 return 0; 978 } 979 } 980 981 src1 = utf8codepoint(src1, &src1_cp); 982 src2 = utf8codepoint(src2, &src2_cp); 983 n -= utf8codepointsize(src1_cp); 984 985 // Take a copy of src1 & src2 986 src1_orig_cp = src1_cp; 987 src2_orig_cp = src2_cp; 988 989 // Lower srcs if required 990 src1_cp = utf8lwrcodepoint(src1_cp); 991 src2_cp = utf8lwrcodepoint(src2_cp); 992 993 // Check if the lowered codepoints match 994 if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) { 995 return 0; 996 } else if (src1_cp == src2_cp) { 997 continue; 998 } 999 1000 // If they don't match, then we return which of the original's are less 1001 if (src1_orig_cp < src2_orig_cp) { 1002 return -1; 1003 } else if (src1_orig_cp > src2_orig_cp) { 1004 return 1; 1005 } 1006 } while (0 < n); 1007 1008 // both utf8 strings matched 1009 return 0; 1010 } 1011 1012 void *utf8ncat(void *utf8_restrict dst, const void *utf8_restrict src, 1013 size_t n) 1014 { 1015 char *d = (char *)dst; 1016 const char *s = (const char *)src; 1017 1018 // find the null terminating byte in dst 1019 while ('\0' != *d) { 1020 d++; 1021 } 1022 1023 // overwriting the null terminating byte in dst, append src byte-by-byte 1024 // stopping if we run out of space 1025 do { 1026 *d++ = *s++; 1027 } while (('\0' != *s) && (0 != --n)); 1028 1029 // write out a new null terminating byte into dst 1030 *d = '\0'; 1031 1032 return dst; 1033 } 1034 1035 int utf8ncmp(const void *src1, const void *src2, size_t n) 1036 { 1037 const unsigned char *s1 = (const unsigned char *)src1; 1038 const unsigned char *s2 = (const unsigned char *)src2; 1039 1040 while ((0 != n--) && (('\0' != *s1) || ('\0' != *s2))) { 1041 if (*s1 < *s2) { 1042 return -1; 1043 } else if (*s1 > *s2) { 1044 return 1; 1045 } 1046 1047 s1++; 1048 s2++; 1049 } 1050 1051 // both utf8 strings matched 1052 return 0; 1053 } 1054 1055 void *utf8ncpy(void *utf8_restrict dst, const void *utf8_restrict src, 1056 size_t n) 1057 { 1058 char *d = (char *)dst; 1059 const char *s = (const char *)src; 1060 size_t index; 1061 1062 // overwriting anything previously in dst, write byte-by-byte 1063 // from src 1064 for (index = 0; index < n; index++) { 1065 d[index] = s[index]; 1066 if ('\0' == s[index]) { 1067 break; 1068 } 1069 } 1070 1071 // append null terminating byte 1072 for (; index < n; index++) { 1073 d[index] = 0; 1074 } 1075 1076 return dst; 1077 } 1078 1079 void *utf8ndup(const void *src, size_t n) 1080 { 1081 const char *s = (const char *)src; 1082 char *c = utf8_null; 1083 size_t bytes = 0; 1084 1085 // Find the end of the string or stop when n is reached 1086 while ('\0' != s[bytes] && bytes < n) { 1087 bytes++; 1088 } 1089 1090 // In case bytes is actually less than n, we need to set it 1091 // to be used later in the copy byte by byte. 1092 n = bytes; 1093 1094 c = (char *)malloc(bytes + 1); 1095 if (utf8_null == c) { 1096 // out of memory so we bail 1097 return utf8_null; 1098 } 1099 1100 bytes = 0; 1101 1102 // copy src byte-by-byte into our new utf8 string 1103 while ('\0' != s[bytes] && bytes < n) { 1104 c[bytes] = s[bytes]; 1105 bytes++; 1106 } 1107 1108 // append null terminating byte 1109 c[bytes] = '\0'; 1110 return c; 1111 } 1112 1113 void *utf8rchr(const void *src, int chr) 1114 { 1115 const char *s = (const char *)src; 1116 const char *match = utf8_null; 1117 char c[5] = {'\0', '\0', '\0', '\0', '\0'}; 1118 1119 if (0 == chr) { 1120 // being asked to return position of null terminating byte, so 1121 // just run s to the end, and return! 1122 while ('\0' != *s) { 1123 s++; 1124 } 1125 return (void *)s; 1126 } else if (0 == ((int)0xffffff80 & chr)) { 1127 // 1-byte/7-bit ascii 1128 // (0b0xxxxxxx) 1129 c[0] = (char)chr; 1130 } else if (0 == ((int)0xfffff800 & chr)) { 1131 // 2-byte/11-bit utf8 code point 1132 // (0b110xxxxx 0b10xxxxxx) 1133 c[0] = 0xc0 | (char)(chr >> 6); 1134 c[1] = 0x80 | (char)(chr & 0x3f); 1135 } else if (0 == ((int)0xffff0000 & chr)) { 1136 // 3-byte/16-bit utf8 code point 1137 // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) 1138 c[0] = 0xe0 | (char)(chr >> 12); 1139 c[1] = 0x80 | (char)((chr >> 6) & 0x3f); 1140 c[2] = 0x80 | (char)(chr & 0x3f); 1141 } else { // if (0 == ((int)0xffe00000 & chr)) { 1142 // 4-byte/21-bit utf8 code point 1143 // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) 1144 c[0] = 0xf0 | (char)(chr >> 18); 1145 c[1] = 0x80 | (char)((chr >> 12) & 0x3f); 1146 c[2] = 0x80 | (char)((chr >> 6) & 0x3f); 1147 c[3] = 0x80 | (char)(chr & 0x3f); 1148 } 1149 1150 // we've created a 2 utf8 codepoint string in c that is 1151 // the utf8 character asked for by chr, and a null 1152 // terminating byte 1153 1154 while ('\0' != *s) { 1155 size_t offset = 0; 1156 1157 while (s[offset] == c[offset]) { 1158 offset++; 1159 } 1160 1161 if ('\0' == c[offset]) { 1162 // we found a matching utf8 code point 1163 match = s; 1164 s += offset; 1165 } else { 1166 s += offset; 1167 1168 // need to march s along to next utf8 codepoint start 1169 // (the next byte that doesn't match 0b10xxxxxx) 1170 if ('\0' != *s) { 1171 do { 1172 s++; 1173 } while (0x80 == (0xc0 & *s)); 1174 } 1175 } 1176 } 1177 1178 // return the last match we found (or 0 if no match was found) 1179 return (void *)match; 1180 } 1181 1182 void *utf8pbrk(const void *str, const void *accept) 1183 { 1184 const char *s = (const char *)str; 1185 1186 while ('\0' != *s) { 1187 const char *a = (const char *)accept; 1188 size_t offset = 0; 1189 1190 while ('\0' != *a) { 1191 // checking that if *a is the start of a utf8 codepoint 1192 // (it is not 0b10xxxxxx) and we have successfully matched 1193 // a previous character (0 < offset) - we found a match 1194 if ((0x80 != (0xc0 & *a)) && (0 < offset)) { 1195 return (void *)s; 1196 } else { 1197 if (*a == s[offset]) { 1198 // part of a utf8 codepoint matched, so move our checking 1199 // onwards to the next byte 1200 offset++; 1201 a++; 1202 } else { 1203 // r could be in the middle of an unmatching utf8 code point, 1204 // so we need to march it on to the next character beginning, 1205 1206 do { 1207 a++; 1208 } while (0x80 == (0xc0 & *a)); 1209 1210 // reset offset too as we found a mismatch 1211 offset = 0; 1212 } 1213 } 1214 } 1215 1216 // we found a match on the last utf8 codepoint 1217 if (0 < offset) { 1218 return (void *)s; 1219 } 1220 1221 // the current utf8 codepoint in src did not match accept, but src 1222 // could have been partway through a utf8 codepoint, so we need to 1223 // march it onto the next utf8 codepoint starting byte 1224 do { 1225 s++; 1226 } while ((0x80 == (0xc0 & *s))); 1227 } 1228 1229 return utf8_null; 1230 } 1231 1232 size_t utf8size(const void *str) 1233 { 1234 const char *s = (const char *)str; 1235 size_t size = 0; 1236 while ('\0' != s[size]) { 1237 size++; 1238 } 1239 1240 // we are including the null terminating byte in the size calculation 1241 size++; 1242 return size; 1243 } 1244 1245 size_t utf8spn(const void *src, const void *accept) 1246 { 1247 const char *s = (const char *)src; 1248 size_t chars = 0; 1249 1250 while ('\0' != *s) { 1251 const char *a = (const char *)accept; 1252 size_t offset = 0; 1253 1254 while ('\0' != *a) { 1255 // checking that if *r is the start of a utf8 codepoint 1256 // (it is not 0b10xxxxxx) and we have successfully matched 1257 // a previous character (0 < offset) - we found a match 1258 if ((0x80 != (0xc0 & *a)) && (0 < offset)) { 1259 // found a match, so increment the number of utf8 codepoints 1260 // that have matched and stop checking whether any other utf8 1261 // codepoints in a match 1262 chars++; 1263 s += offset; 1264 break; 1265 } else { 1266 if (*a == s[offset]) { 1267 offset++; 1268 a++; 1269 } else { 1270 // a could be in the middle of an unmatching utf8 codepoint, 1271 // so we need to march it on to the next character beginning, 1272 do { 1273 a++; 1274 } while (0x80 == (0xc0 & *a)); 1275 1276 // reset offset too as we found a mismatch 1277 offset = 0; 1278 } 1279 } 1280 } 1281 1282 // if a got to its terminating null byte, then we didn't find a match. 1283 // Return the current number of matched utf8 codepoints 1284 if ('\0' == *a) { 1285 return chars; 1286 } 1287 } 1288 1289 return chars; 1290 } 1291 1292 void *utf8str(const void *haystack, const void *needle) 1293 { 1294 const char *h = (const char *)haystack; 1295 utf8_int32_t throwaway_codepoint; 1296 1297 // if needle has no utf8 codepoints before the null terminating 1298 // byte then return haystack 1299 if ('\0' == *((const char *)needle)) { 1300 return (void *)haystack; 1301 } 1302 1303 while ('\0' != *h) { 1304 const char *maybeMatch = h; 1305 const char *n = (const char *)needle; 1306 1307 while (*h == *n && (*h != '\0' && *n != '\0')) { 1308 n++; 1309 h++; 1310 } 1311 1312 if ('\0' == *n) { 1313 // we found the whole utf8 string for needle in haystack at 1314 // maybeMatch, so return it 1315 return (void *)maybeMatch; 1316 } else { 1317 // h could be in the middle of an unmatching utf8 codepoint, 1318 // so we need to march it on to the next character beginning 1319 // starting from the current character 1320 h = (const char *)utf8codepoint(maybeMatch, &throwaway_codepoint); 1321 } 1322 } 1323 1324 // no match 1325 return utf8_null; 1326 } 1327 1328 void *utf8casestr(const void *haystack, const void *needle) 1329 { 1330 const void *h = haystack; 1331 1332 // if needle has no utf8 codepoints before the null terminating 1333 // byte then return haystack 1334 if ('\0' == *((const char *)needle)) { 1335 return (void *)haystack; 1336 } 1337 1338 for (;;) { 1339 const void *maybeMatch = h; 1340 const void *n = needle; 1341 utf8_int32_t h_cp, n_cp; 1342 1343 // Get the next code point and track it 1344 const void *nextH = h = utf8codepoint(h, &h_cp); 1345 n = utf8codepoint(n, &n_cp); 1346 1347 while ((0 != h_cp) && (0 != n_cp)) { 1348 h_cp = utf8lwrcodepoint(h_cp); 1349 n_cp = utf8lwrcodepoint(n_cp); 1350 1351 // if we find a mismatch, bail out! 1352 if (h_cp != n_cp) { 1353 break; 1354 } 1355 1356 h = utf8codepoint(h, &h_cp); 1357 n = utf8codepoint(n, &n_cp); 1358 } 1359 1360 if (0 == n_cp) { 1361 // we found the whole utf8 string for needle in haystack at 1362 // maybeMatch, so return it 1363 return (void *)maybeMatch; 1364 } 1365 1366 if (0 == h_cp) { 1367 // no match 1368 return utf8_null; 1369 } 1370 1371 // Roll back to the next code point in the haystack to test 1372 h = nextH; 1373 } 1374 } 1375 1376 void *utf8valid(const void *str) 1377 { 1378 const char *s = (const char *)str; 1379 1380 while ('\0' != *s) { 1381 if (0xf0 == (0xf8 & *s)) { 1382 // ensure each of the 3 following bytes in this 4-byte 1383 // utf8 codepoint began with 0b10xxxxxx 1384 if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2])) || 1385 (0x80 != (0xc0 & s[3]))) { 1386 return (void *)s; 1387 } 1388 1389 // ensure that our utf8 codepoint ended after 4 bytes 1390 if (0x80 == (0xc0 & s[4])) { 1391 return (void *)s; 1392 } 1393 1394 // ensure that the top 5 bits of this 4-byte utf8 1395 // codepoint were not 0, as then we could have used 1396 // one of the smaller encodings 1397 if ((0 == (0x07 & s[0])) && (0 == (0x30 & s[1]))) { 1398 return (void *)s; 1399 } 1400 1401 // 4-byte utf8 code point (began with 0b11110xxx) 1402 s += 4; 1403 } else if (0xe0 == (0xf0 & *s)) { 1404 // ensure each of the 2 following bytes in this 3-byte 1405 // utf8 codepoint began with 0b10xxxxxx 1406 if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2]))) { 1407 return (void *)s; 1408 } 1409 1410 // ensure that our utf8 codepoint ended after 3 bytes 1411 if (0x80 == (0xc0 & s[3])) { 1412 return (void *)s; 1413 } 1414 1415 // ensure that the top 5 bits of this 3-byte utf8 1416 // codepoint were not 0, as then we could have used 1417 // one of the smaller encodings 1418 if ((0 == (0x0f & s[0])) && (0 == (0x20 & s[1]))) { 1419 return (void *)s; 1420 } 1421 1422 // 3-byte utf8 code point (began with 0b1110xxxx) 1423 s += 3; 1424 } else if (0xc0 == (0xe0 & *s)) { 1425 // ensure the 1 following byte in this 2-byte 1426 // utf8 codepoint began with 0b10xxxxxx 1427 if (0x80 != (0xc0 & s[1])) { 1428 return (void *)s; 1429 } 1430 1431 // ensure that our utf8 codepoint ended after 2 bytes 1432 if (0x80 == (0xc0 & s[2])) { 1433 return (void *)s; 1434 } 1435 1436 // ensure that the top 4 bits of this 2-byte utf8 1437 // codepoint were not 0, as then we could have used 1438 // one of the smaller encodings 1439 if (0 == (0x1e & s[0])) { 1440 return (void *)s; 1441 } 1442 1443 // 2-byte utf8 code point (began with 0b110xxxxx) 1444 s += 2; 1445 } else if (0x00 == (0x80 & *s)) { 1446 // 1-byte ascii (began with 0b0xxxxxxx) 1447 s += 1; 1448 } else { 1449 // we have an invalid 0b1xxxxxxx utf8 code point entry 1450 return (void *)s; 1451 } 1452 } 1453 1454 return utf8_null; 1455 } 1456 1457 void *utf8codepoint(const void *utf8_restrict str, 1458 utf8_int32_t *utf8_restrict out_codepoint) 1459 { 1460 const char *s = (const char *)str; 1461 1462 if (0xf0 == (0xf8 & s[0])) { 1463 // 4 byte utf8 codepoint 1464 *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) | 1465 ((0x3f & s[2]) << 6) | (0x3f & s[3]); 1466 s += 4; 1467 } else if (0xe0 == (0xf0 & s[0])) { 1468 // 3 byte utf8 codepoint 1469 *out_codepoint = 1470 ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]); 1471 s += 3; 1472 } else if (0xc0 == (0xe0 & s[0])) { 1473 // 2 byte utf8 codepoint 1474 *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]); 1475 s += 2; 1476 } else { 1477 // 1 byte utf8 codepoint otherwise 1478 *out_codepoint = s[0]; 1479 s += 1; 1480 } 1481 1482 return (void *)s; 1483 } 1484 1485 size_t utf8codepointsize(utf8_int32_t chr) 1486 { 1487 if (0 == ((utf8_int32_t)0xffffff80 & chr)) { 1488 return 1; 1489 } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { 1490 return 2; 1491 } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { 1492 return 3; 1493 } else { // if (0 == ((int)0xffe00000 & chr)) { 1494 return 4; 1495 } 1496 } 1497 1498 void *utf8catcodepoint(void *utf8_restrict str, utf8_int32_t chr, size_t n) 1499 { 1500 char *s = (char *)str; 1501 1502 if (0 == ((utf8_int32_t)0xffffff80 & chr)) { 1503 // 1-byte/7-bit ascii 1504 // (0b0xxxxxxx) 1505 if (n < 1) { 1506 return utf8_null; 1507 } 1508 s[0] = (char)chr; 1509 s += 1; 1510 } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { 1511 // 2-byte/11-bit utf8 code point 1512 // (0b110xxxxx 0b10xxxxxx) 1513 if (n < 2) { 1514 return utf8_null; 1515 } 1516 s[0] = 0xc0 | (char)(chr >> 6); 1517 s[1] = 0x80 | (char)(chr & 0x3f); 1518 s += 2; 1519 } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { 1520 // 3-byte/16-bit utf8 code point 1521 // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) 1522 if (n < 3) { 1523 return utf8_null; 1524 } 1525 s[0] = 0xe0 | (char)(chr >> 12); 1526 s[1] = 0x80 | (char)((chr >> 6) & 0x3f); 1527 s[2] = 0x80 | (char)(chr & 0x3f); 1528 s += 3; 1529 } else { // if (0 == ((int)0xffe00000 & chr)) { 1530 // 4-byte/21-bit utf8 code point 1531 // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) 1532 if (n < 4) { 1533 return utf8_null; 1534 } 1535 s[0] = 0xf0 | (char)(chr >> 18); 1536 s[1] = 0x80 | (char)((chr >> 12) & 0x3f); 1537 s[2] = 0x80 | (char)((chr >> 6) & 0x3f); 1538 s[3] = 0x80 | (char)(chr & 0x3f); 1539 s += 4; 1540 } 1541 1542 return s; 1543 } 1544 1545 int utf8islower(utf8_int32_t chr) { return chr != utf8uprcodepoint(chr); } 1546 1547 int utf8isupper(utf8_int32_t chr) { return chr != utf8lwrcodepoint(chr); } 1548 1549 void utf8lwr(void *utf8_restrict str) 1550 { 1551 void *p, *pn; 1552 utf8_int32_t cp; 1553 1554 p = (char *)str; 1555 pn = utf8codepoint(p, &cp); 1556 1557 while (cp != 0) { 1558 const utf8_int32_t lwr_cp = utf8lwrcodepoint(cp); 1559 const size_t size = utf8codepointsize(lwr_cp); 1560 1561 if (lwr_cp != cp) { 1562 utf8catcodepoint(p, lwr_cp, size); 1563 } 1564 1565 p = pn; 1566 pn = utf8codepoint(p, &cp); 1567 } 1568 } 1569 1570 void utf8upr(void *utf8_restrict str) 1571 { 1572 void *p, *pn; 1573 utf8_int32_t cp; 1574 1575 p = (char *)str; 1576 pn = utf8codepoint(p, &cp); 1577 1578 while (cp != 0) { 1579 const utf8_int32_t lwr_cp = utf8uprcodepoint(cp); 1580 const size_t size = utf8codepointsize(lwr_cp); 1581 1582 if (lwr_cp != cp) { 1583 utf8catcodepoint(p, lwr_cp, size); 1584 } 1585 1586 p = pn; 1587 pn = utf8codepoint(p, &cp); 1588 } 1589 } 1590 1591 utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) 1592 { 1593 if (((0x0041 <= cp) && (0x005a >= cp)) || 1594 ((0x00c0 <= cp) && (0x00d6 >= cp)) || 1595 ((0x00d8 <= cp) && (0x00de >= cp)) || 1596 ((0x0391 <= cp) && (0x03a1 >= cp)) || 1597 ((0x03a3 <= cp) && (0x03ab >= cp))) { 1598 cp += 32; 1599 } else if (((0x0100 <= cp) && (0x012f >= cp)) || 1600 ((0x0132 <= cp) && (0x0137 >= cp)) || 1601 ((0x014a <= cp) && (0x0177 >= cp)) || 1602 ((0x0182 <= cp) && (0x0185 >= cp)) || 1603 ((0x01a0 <= cp) && (0x01a5 >= cp)) || 1604 ((0x01de <= cp) && (0x01ef >= cp)) || 1605 ((0x01f8 <= cp) && (0x021f >= cp)) || 1606 ((0x0222 <= cp) && (0x0233 >= cp)) || 1607 ((0x0246 <= cp) && (0x024f >= cp)) || 1608 ((0x03d8 <= cp) && (0x03ef >= cp))) { 1609 cp |= 0x1; 1610 } else if (((0x0139 <= cp) && (0x0148 >= cp)) || 1611 ((0x0179 <= cp) && (0x017e >= cp)) || 1612 ((0x01af <= cp) && (0x01b0 >= cp)) || 1613 ((0x01b3 <= cp) && (0x01b6 >= cp)) || 1614 ((0x01cd <= cp) && (0x01dc >= cp))) { 1615 cp += 1; 1616 cp &= ~0x1; 1617 } else { 1618 switch (cp) { 1619 default: break; 1620 case 0x0178: cp = 0x00ff; break; 1621 case 0x0243: cp = 0x0180; break; 1622 case 0x018e: cp = 0x01dd; break; 1623 case 0x023d: cp = 0x019a; break; 1624 case 0x0220: cp = 0x019e; break; 1625 case 0x01b7: cp = 0x0292; break; 1626 case 0x01c4: cp = 0x01c6; break; 1627 case 0x01c7: cp = 0x01c9; break; 1628 case 0x01ca: cp = 0x01cc; break; 1629 case 0x01f1: cp = 0x01f3; break; 1630 case 0x01f7: cp = 0x01bf; break; 1631 case 0x0187: cp = 0x0188; break; 1632 case 0x018b: cp = 0x018c; break; 1633 case 0x0191: cp = 0x0192; break; 1634 case 0x0198: cp = 0x0199; break; 1635 case 0x01a7: cp = 0x01a8; break; 1636 case 0x01ac: cp = 0x01ad; break; 1637 case 0x01af: cp = 0x01b0; break; 1638 case 0x01b8: cp = 0x01b9; break; 1639 case 0x01bc: cp = 0x01bd; break; 1640 case 0x01f4: cp = 0x01f5; break; 1641 case 0x023b: cp = 0x023c; break; 1642 case 0x0241: cp = 0x0242; break; 1643 case 0x03fd: cp = 0x037b; break; 1644 case 0x03fe: cp = 0x037c; break; 1645 case 0x03ff: cp = 0x037d; break; 1646 case 0x037f: cp = 0x03f3; break; 1647 case 0x0386: cp = 0x03ac; break; 1648 case 0x0388: cp = 0x03ad; break; 1649 case 0x0389: cp = 0x03ae; break; 1650 case 0x038a: cp = 0x03af; break; 1651 case 0x038c: cp = 0x03cc; break; 1652 case 0x038e: cp = 0x03cd; break; 1653 case 0x038f: cp = 0x03ce; break; 1654 case 0x0370: cp = 0x0371; break; 1655 case 0x0372: cp = 0x0373; break; 1656 case 0x0376: cp = 0x0377; break; 1657 case 0x03f4: cp = 0x03d1; break; 1658 case 0x03cf: cp = 0x03d7; break; 1659 case 0x03f9: cp = 0x03f2; break; 1660 case 0x03f7: cp = 0x03f8; break; 1661 case 0x03fa: cp = 0x03fb; break; 1662 }; 1663 } 1664 1665 return cp; 1666 } 1667 1668 utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) 1669 { 1670 if (((0x0061 <= cp) && (0x007a >= cp)) || 1671 ((0x00e0 <= cp) && (0x00f6 >= cp)) || 1672 ((0x00f8 <= cp) && (0x00fe >= cp)) || 1673 ((0x03b1 <= cp) && (0x03c1 >= cp)) || 1674 ((0x03c3 <= cp) && (0x03cb >= cp))) { 1675 cp -= 32; 1676 } else if (((0x0100 <= cp) && (0x012f >= cp)) || 1677 ((0x0132 <= cp) && (0x0137 >= cp)) || 1678 ((0x014a <= cp) && (0x0177 >= cp)) || 1679 ((0x0182 <= cp) && (0x0185 >= cp)) || 1680 ((0x01a0 <= cp) && (0x01a5 >= cp)) || 1681 ((0x01de <= cp) && (0x01ef >= cp)) || 1682 ((0x01f8 <= cp) && (0x021f >= cp)) || 1683 ((0x0222 <= cp) && (0x0233 >= cp)) || 1684 ((0x0246 <= cp) && (0x024f >= cp)) || 1685 ((0x03d8 <= cp) && (0x03ef >= cp))) { 1686 cp &= ~0x1; 1687 } else if (((0x0139 <= cp) && (0x0148 >= cp)) || 1688 ((0x0179 <= cp) && (0x017e >= cp)) || 1689 ((0x01af <= cp) && (0x01b0 >= cp)) || 1690 ((0x01b3 <= cp) && (0x01b6 >= cp)) || 1691 ((0x01cd <= cp) && (0x01dc >= cp))) { 1692 cp -= 1; 1693 cp |= 0x1; 1694 } else { 1695 switch (cp) { 1696 default: break; 1697 case 0x00ff: cp = 0x0178; break; 1698 case 0x0180: cp = 0x0243; break; 1699 case 0x01dd: cp = 0x018e; break; 1700 case 0x019a: cp = 0x023d; break; 1701 case 0x019e: cp = 0x0220; break; 1702 case 0x0292: cp = 0x01b7; break; 1703 case 0x01c6: cp = 0x01c4; break; 1704 case 0x01c9: cp = 0x01c7; break; 1705 case 0x01cc: cp = 0x01ca; break; 1706 case 0x01f3: cp = 0x01f1; break; 1707 case 0x01bf: cp = 0x01f7; break; 1708 case 0x0188: cp = 0x0187; break; 1709 case 0x018c: cp = 0x018b; break; 1710 case 0x0192: cp = 0x0191; break; 1711 case 0x0199: cp = 0x0198; break; 1712 case 0x01a8: cp = 0x01a7; break; 1713 case 0x01ad: cp = 0x01ac; break; 1714 case 0x01b0: cp = 0x01af; break; 1715 case 0x01b9: cp = 0x01b8; break; 1716 case 0x01bd: cp = 0x01bc; break; 1717 case 0x01f5: cp = 0x01f4; break; 1718 case 0x023c: cp = 0x023b; break; 1719 case 0x0242: cp = 0x0241; break; 1720 case 0x037b: cp = 0x03fd; break; 1721 case 0x037c: cp = 0x03fe; break; 1722 case 0x037d: cp = 0x03ff; break; 1723 case 0x03f3: cp = 0x037f; break; 1724 case 0x03ac: cp = 0x0386; break; 1725 case 0x03ad: cp = 0x0388; break; 1726 case 0x03ae: cp = 0x0389; break; 1727 case 0x03af: cp = 0x038a; break; 1728 case 0x03cc: cp = 0x038c; break; 1729 case 0x03cd: cp = 0x038e; break; 1730 case 0x03ce: cp = 0x038f; break; 1731 case 0x0371: cp = 0x0370; break; 1732 case 0x0373: cp = 0x0372; break; 1733 case 0x0377: cp = 0x0376; break; 1734 case 0x03d1: cp = 0x03f4; break; 1735 case 0x03d7: cp = 0x03cf; break; 1736 case 0x03f2: cp = 0x03f9; break; 1737 case 0x03f8: cp = 0x03f7; break; 1738 case 0x03fb: cp = 0x03fa; break; 1739 }; 1740 } 1741 1742 return cp; 1743 } 1744 1745 #undef utf8_restrict 1746 #undef utf8_null 1747 1748 #ifdef __cplusplus 1749 } // extern "C" 1750 #endif 1751 1752 #if defined(__clang__) 1753 #pragma clang diagnostic pop 1754 #endif 1755 1756 #endif // SHEREDOM_UTF8_H_INCLUDED 1757 1758 1759 /******************************************************** 1760 End of file "utf8.h" 1761 ********************************************************/ 1762 1763 1764 /******************************************************** 1765 Begin of file "string_buffer.h" 1766 ********************************************************/ 1767 1768 #ifndef STRING_BUFFER_H 1769 #define STRING_BUFFER_H 1770 1771 /* #include "fort_utils.h" */ /* Commented by amalgamation script */ 1772 1773 1774 /***************************************************************************** 1775 * STRING BUFFER 1776 * ***************************************************************************/ 1777 1778 struct f_string_buffer { 1779 union { 1780 char *cstr; 1781 #ifdef FT_HAVE_WCHAR 1782 wchar_t *wstr; 1783 #endif 1784 #ifdef FT_HAVE_UTF8 1785 void *u8str; 1786 #endif 1787 void *data; 1788 } str; 1789 size_t data_sz; 1790 enum f_string_type type; 1791 }; 1792 1793 FT_INTERNAL 1794 f_string_buffer_t *create_string_buffer(size_t number_of_chars, enum f_string_type type); 1795 1796 FT_INTERNAL 1797 void destroy_string_buffer(f_string_buffer_t *buffer); 1798 1799 FT_INTERNAL 1800 f_string_buffer_t *copy_string_buffer(const f_string_buffer_t *buffer); 1801 1802 FT_INTERNAL 1803 f_status realloc_string_buffer_without_copy(f_string_buffer_t *buffer); 1804 1805 FT_INTERNAL 1806 f_status fill_buffer_from_string(f_string_buffer_t *buffer, const char *str); 1807 1808 #ifdef FT_HAVE_WCHAR 1809 FT_INTERNAL 1810 f_status fill_buffer_from_wstring(f_string_buffer_t *buffer, const wchar_t *str); 1811 #endif /* FT_HAVE_WCHAR */ 1812 1813 #ifdef FT_HAVE_UTF8 1814 FT_INTERNAL 1815 f_status fill_buffer_from_u8string(f_string_buffer_t *buffer, const void *str); 1816 #endif /* FT_HAVE_UTF8 */ 1817 1818 FT_INTERNAL 1819 size_t buffer_text_visible_width(const f_string_buffer_t *buffer); 1820 1821 FT_INTERNAL 1822 size_t buffer_text_visible_height(const f_string_buffer_t *buffer); 1823 1824 FT_INTERNAL 1825 size_t string_buffer_cod_width_capacity(const f_string_buffer_t *buffer); 1826 1827 FT_INTERNAL 1828 size_t string_buffer_raw_capacity(const f_string_buffer_t *buffer); 1829 1830 FT_INTERNAL 1831 size_t string_buffer_width_capacity(const f_string_buffer_t *buffer); 1832 1833 FT_INTERNAL 1834 void *buffer_get_data(f_string_buffer_t *buffer); 1835 1836 FT_INTERNAL 1837 int buffer_check_align(f_string_buffer_t *buffer); 1838 1839 FT_INTERNAL 1840 int buffer_printf(f_string_buffer_t *buffer, size_t buffer_row, f_conv_context_t *cntx, size_t cod_width, 1841 const char *content_style_tag, const char *reset_content_style_tag); 1842 1843 #ifdef FT_HAVE_UTF8 1844 FT_INTERNAL 1845 void buffer_set_u8strwid_func(int (*u8strwid)(const void *beg, const void *end, size_t *width)); 1846 #endif /* FT_HAVE_UTF8 */ 1847 1848 1849 #endif /* STRING_BUFFER_H */ 1850 1851 /******************************************************** 1852 End of file "string_buffer.h" 1853 ********************************************************/ 1854 1855 1856 /******************************************************** 1857 Begin of file "properties.h" 1858 ********************************************************/ 1859 1860 #ifndef PROPERTIES_H 1861 #define PROPERTIES_H 1862 1863 /* #include "fort_utils.h" */ /* Commented by amalgamation script */ 1864 #include <stdint.h> 1865 #include <limits.h> 1866 1867 #define PROP_IS_SET(ft_props, property) ((ft_props) & (property)) 1868 #define PROP_SET(ft_props, property) ((ft_props) |=(property)) 1869 #define PROP_UNSET(ft_props, property) ((ft_props) &= ~((uint32_t)(property))) 1870 1871 #define TEXT_STYLE_TAG_MAX_SIZE (64 * 2) 1872 1873 FT_INTERNAL 1874 void get_style_tag_for_cell(const f_table_properties_t *props, 1875 size_t row, size_t col, char *style_tag, size_t sz); 1876 1877 FT_INTERNAL 1878 void get_reset_style_tag_for_cell(const f_table_properties_t *props, 1879 size_t row, size_t col, char *style_tag, size_t sz); 1880 1881 FT_INTERNAL 1882 void get_style_tag_for_content(const f_table_properties_t *props, 1883 size_t row, size_t col, char *style_tag, size_t sz); 1884 1885 FT_INTERNAL 1886 void get_reset_style_tag_for_content(const f_table_properties_t *props, 1887 size_t row, size_t col, char *style_tag, size_t sz); 1888 1889 1890 struct f_cell_props { 1891 size_t cell_row; 1892 size_t cell_col; 1893 uint32_t properties_flags; 1894 1895 unsigned int col_min_width; 1896 enum ft_text_alignment align; 1897 unsigned int cell_padding_top; 1898 unsigned int cell_padding_bottom; 1899 unsigned int cell_padding_left; 1900 unsigned int cell_padding_right; 1901 unsigned int cell_empty_string_height; 1902 enum ft_row_type row_type; 1903 unsigned int content_fg_color_number; 1904 unsigned int content_bg_color_number; 1905 unsigned int cell_bg_color_number; 1906 enum ft_text_style cell_text_style; 1907 enum ft_text_style content_text_style; 1908 bool rgb; 1909 }; 1910 1911 typedef struct f_cell_props f_cell_props_t; 1912 typedef f_vector_t f_cell_prop_container_t; 1913 1914 FT_INTERNAL 1915 f_cell_prop_container_t *create_cell_prop_container(void); 1916 1917 FT_INTERNAL 1918 void destroy_cell_prop_container(f_cell_prop_container_t *cont); 1919 1920 FT_INTERNAL 1921 const f_cell_props_t *cget_cell_prop(const f_cell_prop_container_t *cont, size_t row, size_t col); 1922 1923 FT_INTERNAL 1924 f_cell_props_t *get_cell_prop_and_create_if_not_exists(f_cell_prop_container_t *cont, size_t row, size_t col); 1925 1926 FT_INTERNAL 1927 f_status set_cell_property(f_cell_prop_container_t *cont, size_t row, size_t col, uint32_t property, int value); 1928 1929 FT_INTERNAL 1930 int get_cell_property_hierarchically(const f_table_properties_t *properties, size_t row, size_t column, uint32_t property); 1931 1932 FT_INTERNAL 1933 f_status set_default_cell_property(uint32_t property, int value); 1934 1935 1936 /* TABLE BORDER DESСRIPTION 1937 * 1938 * 1939 * TL TT TT TT TV TT TT TT TT TT TT TT TR 1940 * LL IV RR 1941 * LL IV RR 1942 * LH IH IH IH II IH IH IH TI IH IH IH RH 1943 * LL IV IV RR 1944 * LL IV IV RR 1945 * LL LI IH IH IH RI RH 1946 * LL IV IV RR 1947 * LL IV IV RR 1948 * LH IH IH IH BI IH IH IH II IH IH IH RH 1949 * LL IV RR 1950 * LL IV RR 1951 * BL BB BB BB BV BB BB BB BV BB BB BB BR 1952 */ 1953 1954 1955 /* HORIZONTAL SEPARATOR DESCRIPTION 1956 * 1957 * 1958 * TL TT TT TT TV TT TT TT TV TT TT TT TR <----- TOP_SEPARATOR 1959 * LL IV IV RR 1960 * LH IH IH IH II IH IH IH II IH IH IH RH <----- INSIDE_SEPARATOR 1961 * LL IV IV RR 1962 * BL BB BB BB BV BB BB BB BV BB BB BB BR <----- BOTTOM_SEPARATOR 1963 */ 1964 1965 enum f_hor_separator_pos { 1966 TOP_SEPARATOR, 1967 INSIDE_SEPARATOR, 1968 BOTTOM_SEPARATOR 1969 }; 1970 1971 enum f_border_item_pos { 1972 TL_bip = 0, 1973 TT_bip = 1, 1974 TV_bip = 2, 1975 TR_bip = 3, 1976 1977 LL_bip = 4, 1978 IV_bip = 5, 1979 RR_bip = 6, 1980 1981 LH_bip = 7, 1982 IH_bip = 8, 1983 II_bip = 9, 1984 RH_bip = 10, 1985 1986 BL_bip = 11, 1987 BB_bip = 12, 1988 BV_bip = 13, 1989 BR_bip = 14, 1990 1991 LI_bip = 15, 1992 TI_bip = 16, 1993 RI_bip = 17, 1994 BI_bip = 18, 1995 1996 BORDER_ITEM_POS_SIZE 1997 }; 1998 1999 2000 enum f_separator_item_pos { 2001 LH_sip = 0, 2002 IH_sip = 1, 2003 II_sip = 2, 2004 RH_sip = 3, 2005 2006 TI_sip = 4, 2007 BI_sip = 5, 2008 2009 SEPARATOR_ITEM_POS_SIZE 2010 }; 2011 2012 2013 struct fort_border_style { 2014 const char *border_chars[BORDER_ITEM_POS_SIZE]; 2015 const char *header_border_chars[BORDER_ITEM_POS_SIZE]; 2016 const char *separator_chars[SEPARATOR_ITEM_POS_SIZE]; 2017 }; 2018 extern struct fort_border_style FORT_BASIC_STYLE; 2019 extern struct fort_border_style FORT_BASIC2_STYLE; 2020 extern struct fort_border_style FORT_SIMPLE_STYLE; 2021 extern struct fort_border_style FORT_PLAIN_STYLE; 2022 extern struct fort_border_style FORT_DOT_STYLE; 2023 extern struct fort_border_style FORT_EMPTY_STYLE; 2024 extern struct fort_border_style FORT_EMPTY2_STYLE; 2025 extern struct fort_border_style FORT_SOLID_STYLE; 2026 extern struct fort_border_style FORT_SOLID_ROUND_STYLE; 2027 extern struct fort_border_style FORT_NICE_STYLE; 2028 extern struct fort_border_style FORT_DOUBLE_STYLE; 2029 extern struct fort_border_style FORT_DOUBLE2_STYLE; 2030 extern struct fort_border_style FORT_BOLD_STYLE; 2031 extern struct fort_border_style FORT_BOLD2_STYLE; 2032 extern struct fort_border_style FORT_FRAME_STYLE; 2033 2034 2035 struct fort_entire_table_properties { 2036 unsigned int left_margin; 2037 unsigned int top_margin; 2038 unsigned int right_margin; 2039 unsigned int bottom_margin; 2040 enum ft_adding_strategy add_strategy; 2041 }; 2042 typedef struct fort_entire_table_properties fort_entire_table_properties_t; 2043 extern fort_entire_table_properties_t g_entire_table_properties; 2044 2045 FT_INTERNAL 2046 f_status set_entire_table_property(f_table_properties_t *table_properties, uint32_t property, int value); 2047 2048 FT_INTERNAL 2049 f_status set_default_entire_table_property(uint32_t property, int value); 2050 2051 struct f_table_properties { 2052 struct fort_border_style border_style; 2053 f_cell_prop_container_t *cell_properties; 2054 fort_entire_table_properties_t entire_table_properties; 2055 }; 2056 extern f_table_properties_t g_table_properties; 2057 2058 FT_INTERNAL 2059 size_t max_border_elem_strlen(struct f_table_properties *); 2060 2061 FT_INTERNAL 2062 f_table_properties_t *create_table_properties(void); 2063 2064 FT_INTERNAL 2065 void destroy_table_properties(f_table_properties_t *properties); 2066 2067 FT_INTERNAL 2068 f_table_properties_t *copy_table_properties(const f_table_properties_t *property); 2069 2070 #endif /* PROPERTIES_H */ 2071 2072 /******************************************************** 2073 End of file "properties.h" 2074 ********************************************************/ 2075 2076 2077 /******************************************************** 2078 Begin of file "cell.h" 2079 ********************************************************/ 2080 2081 #ifndef CELL_H 2082 #define CELL_H 2083 2084 /* #include "fort_utils.h" */ /* Commented by amalgamation script */ 2085 2086 FT_INTERNAL 2087 f_cell_t *create_cell(void); 2088 2089 FT_INTERNAL 2090 void destroy_cell(f_cell_t *cell); 2091 2092 FT_INTERNAL 2093 f_cell_t *copy_cell(f_cell_t *cell); 2094 2095 FT_INTERNAL 2096 size_t cell_vis_width(const f_cell_t *cell, const f_context_t *context); 2097 2098 FT_INTERNAL 2099 size_t cell_invis_codes_width(const f_cell_t *cell, const f_context_t *context); 2100 2101 FT_INTERNAL 2102 size_t hint_height_cell(const f_cell_t *cell, const f_context_t *context); 2103 2104 FT_INTERNAL 2105 void set_cell_type(f_cell_t *cell, enum f_cell_type type); 2106 2107 FT_INTERNAL 2108 enum f_cell_type get_cell_type(const f_cell_t *cell); 2109 2110 FT_INTERNAL 2111 int cell_printf(f_cell_t *cell, size_t row, f_conv_context_t *cntx, size_t cod_width); 2112 2113 FT_INTERNAL 2114 f_status fill_cell_from_string(f_cell_t *cell, const char *str); 2115 2116 #ifdef FT_HAVE_WCHAR 2117 FT_INTERNAL 2118 f_status fill_cell_from_wstring(f_cell_t *cell, const wchar_t *str); 2119 #endif 2120 2121 FT_INTERNAL 2122 f_status fill_cell_from_buffer(f_cell_t *cell, const f_string_buffer_t *buf); 2123 2124 FT_INTERNAL 2125 f_string_buffer_t *cell_get_string_buffer(f_cell_t *cell); 2126 2127 #endif /* CELL_H */ 2128 2129 /******************************************************** 2130 End of file "cell.h" 2131 ********************************************************/ 2132 2133 2134 /******************************************************** 2135 Begin of file "row.h" 2136 ********************************************************/ 2137 2138 #ifndef ROW_H 2139 #define ROW_H 2140 2141 /* #include "fort_utils.h" */ /* Commented by amalgamation script */ 2142 #include "fort.h" 2143 #include <stdarg.h> 2144 /* #include "properties.h" */ /* Commented by amalgamation script */ 2145 #ifdef FT_HAVE_WCHAR 2146 #include <wchar.h> 2147 #endif 2148 2149 FT_INTERNAL 2150 f_row_t *create_row(void); 2151 2152 FT_INTERNAL 2153 void destroy_row(f_row_t *row); 2154 2155 FT_INTERNAL 2156 f_row_t *copy_row(f_row_t *row); 2157 2158 FT_INTERNAL 2159 f_row_t *split_row(f_row_t *row, size_t pos); 2160 2161 // Delete range [left; right] of cells (both ends included) 2162 FT_INTERNAL 2163 int ft_row_erase_range(f_row_t *row, size_t left, size_t right); 2164 2165 FT_INTERNAL 2166 f_row_t *create_row_from_string(const char *str); 2167 2168 FT_INTERNAL 2169 f_row_t *create_row_from_fmt_string(const struct f_string_view *fmt, va_list *va_args); 2170 2171 FT_INTERNAL 2172 size_t columns_in_row(const f_row_t *row); 2173 2174 FT_INTERNAL 2175 f_cell_t *get_cell(f_row_t *row, size_t col); 2176 2177 FT_INTERNAL 2178 const f_cell_t *get_cell_c(const f_row_t *row, size_t col); 2179 2180 FT_INTERNAL 2181 f_cell_t *get_cell_and_create_if_not_exists(f_row_t *row, size_t col); 2182 2183 FT_INTERNAL 2184 f_cell_t *create_cell_in_position(f_row_t *row, size_t col); 2185 2186 FT_INTERNAL 2187 f_status swap_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos); 2188 2189 FT_INTERNAL 2190 f_status insert_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos); 2191 2192 FT_INTERNAL 2193 size_t group_cell_number(const f_row_t *row, size_t master_cell_col); 2194 2195 FT_INTERNAL 2196 int get_row_cell_types(const f_row_t *row, enum f_cell_type *types, size_t types_sz); 2197 2198 FT_INTERNAL 2199 f_status row_set_cell_span(f_row_t *row, size_t cell_column, size_t hor_span); 2200 2201 FT_INTERNAL 2202 int print_row_separator(f_conv_context_t *cntx, 2203 const size_t *col_width_arr, size_t cols, 2204 const f_row_t *upper_row, const f_row_t *lower_row, 2205 enum f_hor_separator_pos separatorPos, const f_separator_t *sep); 2206 2207 FT_INTERNAL 2208 int snprintf_row(const f_row_t *row, f_conv_context_t *cntx, size_t *col_width_arr, size_t col_width_arr_sz, 2209 size_t row_height); 2210 2211 #ifdef FT_HAVE_WCHAR 2212 FT_INTERNAL 2213 f_row_t *create_row_from_wstring(const wchar_t *str); 2214 #endif 2215 2216 2217 #endif /* ROW_H */ 2218 2219 /******************************************************** 2220 End of file "row.h" 2221 ********************************************************/ 2222 2223 2224 /******************************************************** 2225 Begin of file "table.h" 2226 ********************************************************/ 2227 2228 #ifndef TABLE_H 2229 #define TABLE_H 2230 2231 /* #include "fort_utils.h" */ /* Commented by amalgamation script */ 2232 2233 struct ft_table { 2234 f_vector_t *rows; 2235 f_table_properties_t *properties; 2236 f_string_buffer_t *conv_buffer; 2237 size_t cur_row; 2238 size_t cur_col; 2239 f_vector_t *separators; 2240 }; 2241 2242 FT_INTERNAL 2243 f_separator_t *create_separator(int enabled); 2244 2245 FT_INTERNAL 2246 void destroy_separator(f_separator_t *sep); 2247 2248 FT_INTERNAL 2249 f_separator_t *copy_separator(f_separator_t *sep); 2250 2251 FT_INTERNAL 2252 f_status get_table_sizes(const ft_table_t *table, size_t *rows, size_t *cols); 2253 2254 FT_INTERNAL 2255 f_row_t *get_row(ft_table_t *table, size_t row); 2256 2257 FT_INTERNAL 2258 const f_row_t *get_row_c(const ft_table_t *table, size_t row); 2259 2260 FT_INTERNAL 2261 f_row_t *get_row_and_create_if_not_exists(ft_table_t *table, size_t row); 2262 2263 FT_INTERNAL 2264 f_string_buffer_t *get_cur_str_buffer_and_create_if_not_exists(ft_table_t *table); 2265 2266 2267 FT_INTERNAL 2268 f_status table_rows_and_cols_geometry(const ft_table_t *table, 2269 size_t **col_width_arr_p, size_t *col_width_arr_sz, 2270 size_t **row_height_arr_p, size_t *row_height_arr_sz, 2271 enum f_geometry_type geom); 2272 2273 FT_INTERNAL 2274 f_status table_geometry(const ft_table_t *table, size_t *height, size_t *width); 2275 2276 /* 2277 * Returns geometry in codepoints(characters) (include codepoints of invisible 2278 * elements: e.g. styles tags). 2279 */ 2280 FT_INTERNAL 2281 f_status table_internal_codepoints_geometry(const ft_table_t *table, size_t *height, size_t *width); 2282 2283 #endif /* TABLE_H */ 2284 2285 /******************************************************** 2286 End of file "table.h" 2287 ********************************************************/ 2288 2289 2290 /******************************************************** 2291 Begin of file "cell.c" 2292 ********************************************************/ 2293 2294 /* #include "cell.h" */ /* Commented by amalgamation script */ 2295 /* #include "properties.h" */ /* Commented by amalgamation script */ 2296 /* #include "string_buffer.h" */ /* Commented by amalgamation script */ 2297 #include <assert.h> 2298 2299 struct f_cell { 2300 f_string_buffer_t *str_buffer; 2301 enum f_cell_type cell_type; 2302 }; 2303 2304 FT_INTERNAL 2305 f_cell_t *create_cell(void) 2306 { 2307 f_cell_t *cell = (f_cell_t *)F_CALLOC(sizeof(f_cell_t), 1); 2308 if (cell == NULL) 2309 return NULL; 2310 cell->str_buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, CHAR_BUF); 2311 if (cell->str_buffer == NULL) { 2312 F_FREE(cell); 2313 return NULL; 2314 } 2315 cell->cell_type = COMMON_CELL; 2316 return cell; 2317 } 2318 2319 FT_INTERNAL 2320 void destroy_cell(f_cell_t *cell) 2321 { 2322 if (cell == NULL) 2323 return; 2324 destroy_string_buffer(cell->str_buffer); 2325 F_FREE(cell); 2326 } 2327 2328 FT_INTERNAL 2329 f_cell_t *copy_cell(f_cell_t *cell) 2330 { 2331 assert(cell); 2332 2333 f_cell_t *result = create_cell(); 2334 if (result == NULL) 2335 return NULL; 2336 destroy_string_buffer(result->str_buffer); 2337 result->str_buffer = copy_string_buffer(cell->str_buffer); 2338 if (result->str_buffer == NULL) { 2339 destroy_cell(result); 2340 return NULL; 2341 } 2342 result->cell_type = cell->cell_type; 2343 return result; 2344 } 2345 2346 FT_INTERNAL 2347 void set_cell_type(f_cell_t *cell, enum f_cell_type type) 2348 { 2349 assert(cell); 2350 cell->cell_type = type; 2351 } 2352 2353 FT_INTERNAL 2354 enum f_cell_type get_cell_type(const f_cell_t *cell) 2355 { 2356 assert(cell); 2357 return cell->cell_type; 2358 } 2359 2360 FT_INTERNAL 2361 size_t cell_vis_width(const f_cell_t *cell, const f_context_t *context) 2362 { 2363 /* todo: 2364 * At the moment min width includes paddings. Maybe it is better that min width weren't include 2365 * paddings but be min width of the cell content without padding 2366 */ 2367 2368 assert(cell); 2369 assert(context); 2370 2371 f_table_properties_t *properties = context->table_properties; 2372 size_t row = context->row; 2373 size_t column = context->column; 2374 2375 size_t padding_left = get_cell_property_hierarchically(properties, row, column, FT_CPROP_LEFT_PADDING); 2376 size_t padding_right = get_cell_property_hierarchically(properties, row, column, FT_CPROP_RIGHT_PADDING); 2377 size_t result = padding_left + padding_right; 2378 if (cell->str_buffer && cell->str_buffer->str.data) { 2379 result += buffer_text_visible_width(cell->str_buffer); 2380 } 2381 result = MAX(result, (size_t)get_cell_property_hierarchically(properties, row, column, FT_CPROP_MIN_WIDTH)); 2382 return result; 2383 } 2384 2385 FT_INTERNAL 2386 size_t cell_invis_codes_width(const f_cell_t *cell, const f_context_t *context) 2387 { 2388 assert(cell); 2389 assert(context); 2390 2391 f_table_properties_t *properties = context->table_properties; 2392 size_t row = context->row; 2393 size_t column = context->column; 2394 2395 size_t result = 0; 2396 char cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE]; 2397 get_style_tag_for_cell(properties, row, column, cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE); 2398 result += strlen(cell_style_tag); 2399 2400 char reset_cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE]; 2401 get_reset_style_tag_for_cell(properties, row, column, reset_cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE); 2402 result += strlen(reset_cell_style_tag); 2403 2404 char content_style_tag[TEXT_STYLE_TAG_MAX_SIZE]; 2405 get_style_tag_for_content(properties, row, column, content_style_tag, TEXT_STYLE_TAG_MAX_SIZE); 2406 result += strlen(content_style_tag); 2407 2408 char reset_content_style_tag[TEXT_STYLE_TAG_MAX_SIZE]; 2409 get_reset_style_tag_for_content(properties, row, column, reset_content_style_tag, TEXT_STYLE_TAG_MAX_SIZE); 2410 result += strlen(reset_content_style_tag); 2411 return result; 2412 } 2413 2414 FT_INTERNAL 2415 size_t hint_height_cell(const f_cell_t *cell, const f_context_t *context) 2416 { 2417 assert(cell); 2418 assert(context); 2419 f_table_properties_t *properties = context->table_properties; 2420 size_t row = context->row; 2421 size_t column = context->column; 2422 2423 size_t padding_top = get_cell_property_hierarchically(properties, row, column, FT_CPROP_TOP_PADDING); 2424 size_t padding_bottom = get_cell_property_hierarchically(properties, row, column, FT_CPROP_BOTTOM_PADDING); 2425 size_t empty_string_height = get_cell_property_hierarchically(properties, row, column, FT_CPROP_EMPTY_STR_HEIGHT); 2426 2427 size_t result = padding_top + padding_bottom; 2428 if (cell->str_buffer && cell->str_buffer->str.data) { 2429 size_t text_height = buffer_text_visible_height(cell->str_buffer); 2430 result += text_height == 0 ? empty_string_height : text_height; 2431 } 2432 return result; 2433 } 2434 2435 2436 FT_INTERNAL 2437 int cell_printf(f_cell_t *cell, size_t row, f_conv_context_t *cntx, size_t vis_width) 2438 { 2439 const f_context_t *context = cntx->cntx; 2440 size_t buf_len = vis_width; 2441 2442 if (cell == NULL || (vis_width < cell_vis_width(cell, context))) { 2443 return -1; 2444 } 2445 2446 f_table_properties_t *properties = context->table_properties; 2447 unsigned int padding_top = get_cell_property_hierarchically(properties, context->row, context->column, FT_CPROP_TOP_PADDING); 2448 unsigned int padding_left = get_cell_property_hierarchically(properties, context->row, context->column, FT_CPROP_LEFT_PADDING); 2449 unsigned int padding_right = get_cell_property_hierarchically(properties, context->row, context->column, FT_CPROP_RIGHT_PADDING); 2450 2451 size_t written = 0; 2452 size_t invisible_written = 0; 2453 int tmp = 0; 2454 2455 /* todo: Dirty hack with changing buf_len! need refactoring. */ 2456 /* Also maybe it is better to move all struff with colors to buffers? */ 2457 char cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE]; 2458 get_style_tag_for_cell(properties, context->row, context->column, cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE); 2459 buf_len += strlen(cell_style_tag); 2460 2461 char reset_cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE]; 2462 get_reset_style_tag_for_cell(properties, context->row, context->column, reset_cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE); 2463 buf_len += strlen(reset_cell_style_tag); 2464 2465 char content_style_tag[TEXT_STYLE_TAG_MAX_SIZE]; 2466 get_style_tag_for_content(properties, context->row, context->column, content_style_tag, TEXT_STYLE_TAG_MAX_SIZE); 2467 buf_len += strlen(content_style_tag); 2468 2469 char reset_content_style_tag[TEXT_STYLE_TAG_MAX_SIZE]; 2470 get_reset_style_tag_for_content(properties, context->row, context->column, reset_content_style_tag, TEXT_STYLE_TAG_MAX_SIZE); 2471 buf_len += strlen(reset_content_style_tag); 2472 2473 /* CELL_STYLE_T LEFT_PADDING CONTENT_STYLE_T CONTENT RESET_CONTENT_STYLE_T RIGHT_PADDING RESET_CELL_STYLE_T 2474 * | | | | | | | | 2475 * L1 R1 2476 * L2 R2 2477 * L3 R3 2478 */ 2479 2480 size_t L2 = padding_left; 2481 2482 size_t R2 = padding_right; 2483 size_t R3 = strlen(reset_cell_style_tag); 2484 2485 #define TOTAL_WRITTEN (written + invisible_written) 2486 #define RIGHT (padding_right + extra_right) 2487 2488 #define WRITE_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(print_n_strings(cntx, 1, cell_style_tag)) 2489 #define WRITE_RESET_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(print_n_strings(cntx, 1, reset_cell_style_tag)) 2490 #define WRITE_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(print_n_strings(cntx, 1, content_style_tag)) 2491 #define WRITE_RESET_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(print_n_strings(cntx, 1, reset_content_style_tag)) 2492 2493 if (row >= hint_height_cell(cell, context) 2494 || row < padding_top 2495 || row >= (padding_top + buffer_text_visible_height(cell->str_buffer))) { 2496 WRITE_CELL_STYLE_TAG; 2497 WRITE_CONTENT_STYLE_TAG; 2498 WRITE_RESET_CONTENT_STYLE_TAG; 2499 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, buf_len - TOTAL_WRITTEN - R3, FT_SPACE)); 2500 WRITE_RESET_CELL_STYLE_TAG; 2501 2502 return (int)TOTAL_WRITTEN; 2503 } 2504 2505 WRITE_CELL_STYLE_TAG; 2506 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, L2, FT_SPACE)); 2507 if (cell->str_buffer) { 2508 CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf(cell->str_buffer, row - padding_top, cntx, vis_width - L2 - R2, content_style_tag, reset_content_style_tag)); 2509 } else { 2510 WRITE_CONTENT_STYLE_TAG; 2511 WRITE_RESET_CONTENT_STYLE_TAG; 2512 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, vis_width - L2 - R2, FT_SPACE)); 2513 } 2514 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, R2, FT_SPACE)); 2515 WRITE_RESET_CELL_STYLE_TAG; 2516 2517 return (int)TOTAL_WRITTEN; 2518 2519 clear: 2520 return -1; 2521 #undef WRITE_CELL_STYLE_TAG 2522 #undef WRITE_RESET_CELL_STYLE_TAG 2523 #undef WRITE_CONTENT_STYLE_TAG 2524 #undef WRITE_RESET_CONTENT_STYLE_TAG 2525 #undef TOTAL_WRITTEN 2526 #undef RIGHT 2527 } 2528 2529 FT_INTERNAL 2530 f_status fill_cell_from_string(f_cell_t *cell, const char *str) 2531 { 2532 assert(str); 2533 assert(cell); 2534 2535 return fill_buffer_from_string(cell->str_buffer, str); 2536 } 2537 2538 #ifdef FT_HAVE_WCHAR 2539 FT_INTERNAL 2540 f_status fill_cell_from_wstring(f_cell_t *cell, const wchar_t *str) 2541 { 2542 assert(str); 2543 assert(cell); 2544 2545 return fill_buffer_from_wstring(cell->str_buffer, str); 2546 } 2547 #endif 2548 2549 #ifdef FT_HAVE_UTF8 2550 static 2551 f_status fill_cell_from_u8string(f_cell_t *cell, const void *str) 2552 { 2553 assert(str); 2554 assert(cell); 2555 return fill_buffer_from_u8string(cell->str_buffer, str); 2556 } 2557 #endif /* FT_HAVE_UTF8 */ 2558 2559 FT_INTERNAL 2560 f_string_buffer_t *cell_get_string_buffer(f_cell_t *cell) 2561 { 2562 assert(cell); 2563 assert(cell->str_buffer); 2564 return cell->str_buffer; 2565 } 2566 2567 FT_INTERNAL 2568 f_status fill_cell_from_buffer(f_cell_t *cell, const f_string_buffer_t *buffer) 2569 { 2570 assert(cell); 2571 assert(buffer); 2572 switch (buffer->type) { 2573 case CHAR_BUF: 2574 return fill_cell_from_string(cell, buffer->str.cstr); 2575 #ifdef FT_HAVE_WCHAR 2576 case W_CHAR_BUF: 2577 return fill_cell_from_wstring(cell, buffer->str.wstr); 2578 #endif /* FT_HAVE_WCHAR */ 2579 #ifdef FT_HAVE_UTF8 2580 case UTF8_BUF: 2581 return fill_cell_from_u8string(cell, buffer->str.u8str); 2582 #endif /* FT_HAVE_UTF8 */ 2583 default: 2584 assert(0); 2585 return FT_GEN_ERROR; 2586 } 2587 2588 } 2589 2590 /******************************************************** 2591 End of file "cell.c" 2592 ********************************************************/ 2593 2594 2595 /******************************************************** 2596 Begin of file "fort_impl.c" 2597 ********************************************************/ 2598 2599 /* 2600 libfort 2601 2602 MIT License 2603 2604 Copyright (c) 2017 - 2018 Seleznev Anton 2605 2606 Permission is hereby granted, free of charge, to any person obtaining a copy 2607 of this software and associated documentation files (the "Software"), to deal 2608 in the Software without restriction, including without limitation the rights 2609 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 2610 copies of the Software, and to permit persons to whom the Software is 2611 furnished to do so, subject to the following conditions: 2612 2613 The above copyright notice and this permission notice shall be included in all 2614 copies or substantial portions of the Software. 2615 2616 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2617 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2618 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2619 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2620 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2621 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2622 SOFTWARE. 2623 */ 2624 2625 #include <stdlib.h> 2626 #include <stdarg.h> 2627 #include <stdio.h> 2628 #include "fort.h" 2629 #include <assert.h> 2630 #include <string.h> 2631 #include <wchar.h> 2632 2633 /* #include "vector.h" */ /* Commented by amalgamation script */ 2634 /* #include "fort_utils.h" */ /* Commented by amalgamation script */ 2635 /* #include "string_buffer.h" */ /* Commented by amalgamation script */ 2636 /* #include "table.h" */ /* Commented by amalgamation script */ 2637 /* #include "row.h" */ /* Commented by amalgamation script */ 2638 /* #include "properties.h" */ /* Commented by amalgamation script */ 2639 2640 2641 ft_table_t *ft_create_table(void) 2642 { 2643 ft_table_t *result = (ft_table_t *)F_CALLOC(1, sizeof(ft_table_t)); 2644 if (result == NULL) 2645 return NULL; 2646 2647 result->rows = create_vector(sizeof(f_row_t *), DEFAULT_VECTOR_CAPACITY); 2648 if (result->rows == NULL) { 2649 F_FREE(result); 2650 return NULL; 2651 } 2652 result->separators = create_vector(sizeof(f_separator_t *), DEFAULT_VECTOR_CAPACITY); 2653 if (result->separators == NULL) { 2654 destroy_vector(result->rows); 2655 F_FREE(result); 2656 return NULL; 2657 } 2658 2659 result->properties = create_table_properties(); 2660 if (result->properties == NULL) { 2661 destroy_vector(result->separators); 2662 destroy_vector(result->rows); 2663 F_FREE(result); 2664 return NULL; 2665 } 2666 result->conv_buffer = NULL; 2667 result->cur_row = 0; 2668 result->cur_col = 0; 2669 return result; 2670 } 2671 2672 2673 void ft_destroy_table(ft_table_t *table) 2674 { 2675 size_t i = 0; 2676 2677 if (table == NULL) 2678 return; 2679 2680 if (table->rows) { 2681 size_t row_n = vector_size(table->rows); 2682 for (i = 0; i < row_n; ++i) { 2683 destroy_row(VECTOR_AT(table->rows, i, f_row_t *)); 2684 } 2685 destroy_vector(table->rows); 2686 } 2687 if (table->separators) { 2688 size_t row_n = vector_size(table->separators); 2689 for (i = 0; i < row_n; ++i) { 2690 destroy_separator(VECTOR_AT(table->separators, i, f_separator_t *)); 2691 } 2692 destroy_vector(table->separators); 2693 } 2694 destroy_table_properties(table->properties); 2695 destroy_string_buffer(table->conv_buffer); 2696 F_FREE(table); 2697 } 2698 2699 ft_table_t *ft_copy_table(ft_table_t *table) 2700 { 2701 if (table == NULL) 2702 return NULL; 2703 2704 ft_table_t *result = ft_create_table(); 2705 if (result == NULL) 2706 return NULL; 2707 2708 size_t i = 0; 2709 size_t rows_n = vector_size(table->rows); 2710 for (i = 0; i < rows_n; ++i) { 2711 f_row_t *row = VECTOR_AT(table->rows, i, f_row_t *); 2712 f_row_t *new_row = copy_row(row); 2713 if (new_row == NULL) { 2714 ft_destroy_table(result); 2715 return NULL; 2716 } 2717 vector_push(result->rows, &new_row); 2718 } 2719 2720 size_t sep_sz = vector_size(table->separators); 2721 for (i = 0; i < sep_sz; ++i) { 2722 f_separator_t *sep = VECTOR_AT(table->separators, i, f_separator_t *); 2723 f_separator_t *new_sep = copy_separator(sep); 2724 if (new_sep == NULL) { 2725 ft_destroy_table(result); 2726 return NULL; 2727 } 2728 vector_push(result->separators, &new_sep); 2729 } 2730 2731 /* note: by default new table has allocated default properties, so we 2732 * have to destroy them first. 2733 */ 2734 if (result->properties) { 2735 destroy_table_properties(result->properties); 2736 } 2737 result->properties = copy_table_properties(table->properties); 2738 if (result->properties == NULL) { 2739 ft_destroy_table(result); 2740 return NULL; 2741 } 2742 2743 /* todo: copy conv_buffer ?? */ 2744 2745 result->cur_row = table->cur_row; 2746 result->cur_col = table->cur_col; 2747 return result; 2748 } 2749 2750 static int split_cur_row(ft_table_t *table, f_row_t **tail_of_cur_row) 2751 { 2752 if (table->cur_row >= vector_size(table->rows)) { 2753 tail_of_cur_row = NULL; 2754 return 0; 2755 } 2756 2757 f_row_t *row = VECTOR_AT(table->rows, table->cur_row, f_row_t *); 2758 if (table->cur_col >= columns_in_row(row)) { 2759 tail_of_cur_row = NULL; 2760 return 0; 2761 } 2762 2763 f_row_t *tail = split_row(row, table->cur_col); 2764 if (!tail) { 2765 tail_of_cur_row = NULL; 2766 return FT_GEN_ERROR; 2767 } 2768 2769 *tail_of_cur_row = tail; 2770 return 0; 2771 } 2772 2773 int ft_ln(ft_table_t *table) 2774 { 2775 assert(table); 2776 fort_entire_table_properties_t *table_props = &table->properties->entire_table_properties; 2777 switch (table_props->add_strategy) { 2778 case FT_STRATEGY_INSERT: { 2779 f_row_t *new_row = NULL; 2780 if (FT_IS_ERROR(split_cur_row(table, &new_row))) { 2781 return FT_GEN_ERROR; 2782 } 2783 if (new_row) { 2784 if (FT_IS_ERROR(vector_insert(table->rows, &new_row, table->cur_row + 1))) { 2785 destroy_row(new_row); 2786 return FT_GEN_ERROR; 2787 } 2788 } 2789 break; 2790 } 2791 case FT_STRATEGY_REPLACE: 2792 // do nothing 2793 break; 2794 default: 2795 assert(0 && "Unexpected situation inside libfort"); 2796 break; 2797 } 2798 table->cur_col = 0; 2799 table->cur_row++; 2800 return FT_SUCCESS; 2801 } 2802 2803 size_t ft_cur_row(const ft_table_t *table) 2804 { 2805 assert(table); 2806 return table->cur_row; 2807 } 2808 2809 size_t ft_cur_col(const ft_table_t *table) 2810 { 2811 assert(table); 2812 return table->cur_col; 2813 } 2814 2815 void ft_set_cur_cell(ft_table_t *table, size_t row, size_t col) 2816 { 2817 assert(table); 2818 table->cur_row = row; 2819 table->cur_col = col; 2820 } 2821 2822 int ft_is_empty(const ft_table_t *table) 2823 { 2824 assert(table); 2825 return ft_row_count(table) == 0; 2826 } 2827 2828 size_t ft_row_count(const ft_table_t *table) 2829 { 2830 assert(table && table->rows); 2831 return vector_size(table->rows); 2832 } 2833 2834 size_t ft_col_count(const ft_table_t *table) 2835 { 2836 assert(table && table->rows); 2837 size_t i = 0; 2838 size_t cols_n = 0; 2839 size_t rows_n = vector_size(table->rows); 2840 for (i = 0; i < rows_n; ++i) { 2841 f_row_t *row = VECTOR_AT(table->rows, i, f_row_t *); 2842 size_t ncols = columns_in_row(row); 2843 cols_n = MAX(cols_n, ncols); 2844 } 2845 return cols_n; 2846 } 2847 2848 int ft_erase_range(ft_table_t *table, 2849 size_t top_left_row, size_t top_left_col, 2850 size_t bottom_right_row, size_t bottom_right_col) 2851 { 2852 assert(table && table->rows); 2853 int status = FT_SUCCESS; 2854 2855 size_t rows_n = vector_size(table->rows); 2856 2857 if (top_left_row == FT_CUR_ROW) 2858 top_left_row = table->cur_row; 2859 if (bottom_right_row == FT_CUR_ROW) 2860 bottom_right_row = table->cur_row; 2861 2862 if (top_left_col == FT_CUR_COLUMN) 2863 top_left_col = table->cur_row; 2864 if (bottom_right_col == FT_CUR_COLUMN) 2865 bottom_right_col = table->cur_row; 2866 2867 if (top_left_row > bottom_right_row || top_left_col > bottom_right_col) 2868 return FT_EINVAL; 2869 2870 f_row_t *row = NULL; 2871 size_t i = top_left_row; 2872 while (i < rows_n && i <= bottom_right_row) { 2873 row = VECTOR_AT(table->rows, i, f_row_t *); 2874 status = ft_row_erase_range(row, top_left_col, bottom_right_col); 2875 if (FT_IS_ERROR(status)) 2876 return status; 2877 ++i; 2878 } 2879 2880 f_separator_t *separator = NULL; 2881 2882 size_t n_iterations = MIN(rows_n - 1, bottom_right_row) - top_left_row + 1; 2883 size_t j = 0; 2884 i = top_left_row; 2885 for (j = 0; j < n_iterations; ++j) { 2886 row = VECTOR_AT(table->rows, i, f_row_t *); 2887 if (columns_in_row(row)) { 2888 ++i; 2889 } else { 2890 destroy_row(row); 2891 status = vector_erase(table->rows, i); 2892 if (FT_IS_ERROR(status)) 2893 return status; 2894 if (i < vector_size(table->separators)) { 2895 separator = VECTOR_AT(table->separators, i, f_separator_t *); 2896 destroy_separator(separator); 2897 vector_erase(table->separators, i); 2898 } 2899 } 2900 } 2901 2902 return FT_SUCCESS; 2903 } 2904 2905 2906 static int ft_row_printf_impl_(ft_table_t *table, size_t row, const struct f_string_view *fmt, va_list *va) 2907 { 2908 size_t i = 0; 2909 size_t new_cols = 0; 2910 2911 if (table == NULL) 2912 return -1; 2913 2914 f_row_t *new_row = create_row_from_fmt_string(fmt, va); 2915 2916 if (new_row == NULL) { 2917 return -1; 2918 } 2919 2920 f_row_t **cur_row_p = NULL; 2921 size_t sz = vector_size(table->rows); 2922 if (row >= sz) { 2923 size_t push_n = row - sz + 1; 2924 for (i = 0; i < push_n; ++i) { 2925 f_row_t *padding_row = create_row(); 2926 if (padding_row == NULL) 2927 goto clear; 2928 2929 if (FT_IS_ERROR(vector_push(table->rows, &padding_row))) { 2930 destroy_row(padding_row); 2931 goto clear; 2932 } 2933 } 2934 } 2935 /* todo: clearing pushed items in case of error ?? */ 2936 2937 new_cols = columns_in_row(new_row); 2938 cur_row_p = &VECTOR_AT(table->rows, row, f_row_t *); 2939 2940 switch (table->properties->entire_table_properties.add_strategy) { 2941 case FT_STRATEGY_INSERT: { 2942 if (FT_IS_ERROR(insert_row(*cur_row_p, new_row, table->cur_col))) 2943 goto clear; 2944 break; 2945 } 2946 case FT_STRATEGY_REPLACE: { 2947 if (FT_IS_ERROR(swap_row(*cur_row_p, new_row, table->cur_col))) 2948 goto clear; 2949 break; 2950 } 2951 default: 2952 assert(0 && "Unexpected situation inside libfort"); 2953 break; 2954 } 2955 2956 table->cur_col += new_cols; 2957 destroy_row(new_row); 2958 return (int)new_cols; 2959 2960 clear: 2961 destroy_row(new_row); 2962 return -1; 2963 } 2964 2965 #if defined(FT_CLANG_COMPILER) || defined(FT_GCC_COMPILER) 2966 #define FT_PRINTF ft_printf 2967 #define FT_PRINTF_LN ft_printf_ln 2968 #else 2969 #define FT_PRINTF ft_printf_impl 2970 #define FT_PRINTF_LN ft_printf_ln_impl 2971 #endif 2972 2973 2974 2975 int FT_PRINTF(ft_table_t *table, const char *fmt, ...) 2976 { 2977 assert(table); 2978 va_list va; 2979 va_start(va, fmt); 2980 2981 struct f_string_view fmt_str; 2982 fmt_str.type = CHAR_BUF; 2983 fmt_str.u.cstr = fmt; 2984 int result = ft_row_printf_impl_(table, table->cur_row, &fmt_str, &va); 2985 va_end(va); 2986 return result; 2987 } 2988 2989 int FT_PRINTF_LN(ft_table_t *table, const char *fmt, ...) 2990 { 2991 assert(table); 2992 va_list va; 2993 va_start(va, fmt); 2994 2995 struct f_string_view fmt_str; 2996 fmt_str.type = CHAR_BUF; 2997 fmt_str.u.cstr = fmt; 2998 int result = ft_row_printf_impl_(table, table->cur_row, &fmt_str, &va); 2999 if (result >= 0) { 3000 ft_ln(table); 3001 } 3002 va_end(va); 3003 return result; 3004 } 3005 3006 #undef FT_PRINTF 3007 #undef FT_PRINTF_LN 3008 3009 #ifdef FT_HAVE_WCHAR 3010 int ft_wprintf(ft_table_t *table, const wchar_t *fmt, ...) 3011 { 3012 assert(table); 3013 va_list va; 3014 va_start(va, fmt); 3015 3016 struct f_string_view fmt_str; 3017 fmt_str.type = W_CHAR_BUF; 3018 fmt_str.u.wstr = fmt; 3019 int result = ft_row_printf_impl_(table, table->cur_row, &fmt_str, &va); 3020 va_end(va); 3021 return result; 3022 } 3023 3024 int ft_wprintf_ln(ft_table_t *table, const wchar_t *fmt, ...) 3025 { 3026 assert(table); 3027 va_list va; 3028 va_start(va, fmt); 3029 3030 struct f_string_view fmt_str; 3031 fmt_str.type = W_CHAR_BUF; 3032 fmt_str.u.wstr = fmt; 3033 int result = ft_row_printf_impl_(table, table->cur_row, &fmt_str, &va); 3034 if (result >= 0) { 3035 ft_ln(table); 3036 } 3037 va_end(va); 3038 return result; 3039 } 3040 3041 #endif 3042 3043 void ft_set_default_printf_field_separator(char separator) 3044 { 3045 g_col_separator = separator; 3046 } 3047 3048 static int ft_write_impl_(ft_table_t *table, const f_string_view_t *cell_content) 3049 { 3050 assert(table); 3051 f_string_buffer_t *buf = get_cur_str_buffer_and_create_if_not_exists(table); 3052 if (buf == NULL) 3053 return FT_GEN_ERROR; 3054 3055 int status = FT_SUCCESS; 3056 switch (cell_content->type) { 3057 case CHAR_BUF: 3058 status = fill_buffer_from_string(buf, cell_content->u.cstr); 3059 break; 3060 #ifdef FT_HAVE_WCHAR 3061 case W_CHAR_BUF: 3062 status = fill_buffer_from_wstring(buf, cell_content->u.wstr); 3063 break; 3064 #endif 3065 #ifdef FT_HAVE_UTF8 3066 case UTF8_BUF: 3067 status = fill_buffer_from_u8string(buf, cell_content->u.u8str); 3068 break; 3069 #endif 3070 default: 3071 status = FT_GEN_ERROR; 3072 } 3073 if (FT_IS_SUCCESS(status)) { 3074 table->cur_col++; 3075 } 3076 return status; 3077 } 3078 3079 static int ft_write_impl(ft_table_t *table, const char *cell_content) 3080 { 3081 f_string_view_t content; 3082 content.type = CHAR_BUF; 3083 content.u.cstr = cell_content; 3084 return ft_write_impl_(table, &content); 3085 } 3086 3087 #ifdef FT_HAVE_UTF8 3088 static int ft_u8write_impl(ft_table_t *table, const void *cell_content) 3089 { 3090 f_string_view_t content; 3091 content.type = UTF8_BUF; 3092 content.u.u8str = cell_content; 3093 return ft_write_impl_(table, &content); 3094 } 3095 #endif /* FT_HAVE_UTF8 */ 3096 3097 #ifdef FT_HAVE_WCHAR 3098 static int ft_wwrite_impl(ft_table_t *table, const wchar_t *cell_content) 3099 { 3100 f_string_view_t content; 3101 content.type = W_CHAR_BUF; 3102 content.u.wstr = cell_content; 3103 return ft_write_impl_(table, &content); 3104 } 3105 #endif 3106 3107 3108 int ft_nwrite(ft_table_t *table, size_t count, const char *cell_content, ...) 3109 { 3110 size_t i = 0; 3111 assert(table); 3112 int status = ft_write_impl(table, cell_content); 3113 if (FT_IS_ERROR(status)) 3114 return status; 3115 3116 va_list va; 3117 va_start(va, cell_content); 3118 --count; 3119 for (i = 0; i < count; ++i) { 3120 const char *cell = va_arg(va, const char *); 3121 status = ft_write_impl(table, cell); 3122 if (FT_IS_ERROR(status)) { 3123 va_end(va); 3124 return status; 3125 } 3126 } 3127 va_end(va); 3128 return status; 3129 } 3130 3131 int ft_nwrite_ln(ft_table_t *table, size_t count, const char *cell_content, ...) 3132 { 3133 size_t i = 0; 3134 assert(table); 3135 int status = ft_write_impl(table, cell_content); 3136 if (FT_IS_ERROR(status)) 3137 return status; 3138 3139 va_list va; 3140 va_start(va, cell_content); 3141 --count; 3142 for (i = 0; i < count; ++i) { 3143 const char *cell = va_arg(va, const char *); 3144 status = ft_write_impl(table, cell); 3145 if (FT_IS_ERROR(status)) { 3146 va_end(va); 3147 return status; 3148 } 3149 } 3150 va_end(va); 3151 3152 ft_ln(table); 3153 return status; 3154 } 3155 3156 3157 3158 3159 #ifdef FT_HAVE_WCHAR 3160 3161 int ft_nwwrite(ft_table_t *table, size_t n, const wchar_t *cell_content, ...) 3162 { 3163 size_t i = 0; 3164 assert(table); 3165 int status = ft_wwrite_impl(table, cell_content); 3166 if (FT_IS_ERROR(status)) 3167 return status; 3168 3169 va_list va; 3170 va_start(va, cell_content); 3171 --n; 3172 for (i = 0; i < n; ++i) { 3173 const wchar_t *cell = va_arg(va, const wchar_t *); 3174 status = ft_wwrite_impl(table, cell); 3175 if (FT_IS_ERROR(status)) { 3176 va_end(va); 3177 return status; 3178 } 3179 } 3180 va_end(va); 3181 return status; 3182 } 3183 3184 int ft_nwwrite_ln(ft_table_t *table, size_t n, const wchar_t *cell_content, ...) 3185 { 3186 size_t i = 0; 3187 assert(table); 3188 int status = ft_wwrite_impl(table, cell_content); 3189 if (FT_IS_ERROR(status)) 3190 return status; 3191 3192 va_list va; 3193 va_start(va, cell_content); 3194 --n; 3195 for (i = 0; i < n; ++i) { 3196 const wchar_t *cell = va_arg(va, const wchar_t *); 3197 status = ft_wwrite_impl(table, cell); 3198 if (FT_IS_ERROR(status)) { 3199 va_end(va); 3200 return status; 3201 } 3202 } 3203 va_end(va); 3204 3205 ft_ln(table); 3206 return status; 3207 } 3208 #endif 3209 3210 3211 int ft_row_write(ft_table_t *table, size_t cols, const char *cells[]) 3212 { 3213 size_t i = 0; 3214 assert(table); 3215 for (i = 0; i < cols; ++i) { 3216 int status = ft_write_impl(table, cells[i]); 3217 if (FT_IS_ERROR(status)) { 3218 /* todo: maybe current pos in case of error should be equal to the one before function call? */ 3219 return status; 3220 } 3221 } 3222 return FT_SUCCESS; 3223 } 3224 3225 int ft_row_write_ln(ft_table_t *table, size_t cols, const char *cells[]) 3226 { 3227 assert(table); 3228 int status = ft_row_write(table, cols, cells); 3229 if (FT_IS_SUCCESS(status)) { 3230 ft_ln(table); 3231 } 3232 return status; 3233 } 3234 3235 #ifdef FT_HAVE_WCHAR 3236 int ft_row_wwrite(ft_table_t *table, size_t cols, const wchar_t *cells[]) 3237 { 3238 size_t i = 0; 3239 assert(table); 3240 for (i = 0; i < cols; ++i) { 3241 int status = ft_wwrite_impl(table, cells[i]); 3242 if (FT_IS_ERROR(status)) { 3243 /* todo: maybe current pos in case of error should be equal 3244 * to the one before function call? 3245 */ 3246 return status; 3247 } 3248 } 3249 return FT_SUCCESS; 3250 } 3251 3252 int ft_row_wwrite_ln(ft_table_t *table, size_t cols, const wchar_t *cells[]) 3253 { 3254 assert(table); 3255 int status = ft_row_wwrite(table, cols, cells); 3256 if (FT_IS_SUCCESS(status)) { 3257 ft_ln(table); 3258 } 3259 return status; 3260 } 3261 #endif 3262 3263 3264 3265 int ft_table_write(ft_table_t *table, size_t rows, size_t cols, const char *table_cells[]) 3266 { 3267 size_t i = 0; 3268 assert(table); 3269 for (i = 0; i < rows; ++i) { 3270 int status = ft_row_write(table, cols, (const char **)&table_cells[i * cols]); 3271 if (FT_IS_ERROR(status)) { 3272 /* todo: maybe current pos in case of error should be equal 3273 * to the one before function call? 3274 */ 3275 return status; 3276 } 3277 if (i != rows - 1) 3278 ft_ln(table); 3279 } 3280 return FT_SUCCESS; 3281 } 3282 3283 int ft_table_write_ln(ft_table_t *table, size_t rows, size_t cols, const char *table_cells[]) 3284 { 3285 assert(table); 3286 int status = ft_table_write(table, rows, cols, table_cells); 3287 if (FT_IS_SUCCESS(status)) { 3288 ft_ln(table); 3289 } 3290 return status; 3291 } 3292 3293 3294 #ifdef FT_HAVE_WCHAR 3295 int ft_table_wwrite(ft_table_t *table, size_t rows, size_t cols, const wchar_t *table_cells[]) 3296 { 3297 size_t i = 0; 3298 assert(table); 3299 for (i = 0; i < rows; ++i) { 3300 int status = ft_row_wwrite(table, cols, (const wchar_t **)&table_cells[i * cols]); 3301 if (FT_IS_ERROR(status)) { 3302 /* todo: maybe current pos in case of error should be equal 3303 * to the one before function call? 3304 */ 3305 return status; 3306 } 3307 if (i != rows - 1) 3308 ft_ln(table); 3309 } 3310 return FT_SUCCESS; 3311 } 3312 3313 int ft_table_wwrite_ln(ft_table_t *table, size_t rows, size_t cols, const wchar_t *table_cells[]) 3314 { 3315 assert(table); 3316 int status = ft_table_wwrite(table, rows, cols, table_cells); 3317 if (FT_IS_SUCCESS(status)) { 3318 ft_ln(table); 3319 } 3320 return status; 3321 } 3322 #endif 3323 3324 static 3325 const char *empty_str_arr[] = {"", (const char *)L"", ""}; 3326 3327 static 3328 const void *ft_to_string_impl(const ft_table_t *table, enum f_string_type b_type) 3329 { 3330 assert(table); 3331 3332 const char *result = NULL; 3333 3334 /* Determine size of table string representation */ 3335 size_t cod_height = 0; 3336 size_t cod_width = 0; 3337 int status = table_internal_codepoints_geometry(table, &cod_height, &cod_width); 3338 if (FT_IS_ERROR(status)) { 3339 return NULL; 3340 } 3341 size_t n_codepoints = cod_height * cod_width + 1; 3342 3343 /* Allocate string buffer for string representation */ 3344 if (table->conv_buffer == NULL) { 3345 ((ft_table_t *)table)->conv_buffer = create_string_buffer(n_codepoints, b_type); 3346 if (table->conv_buffer == NULL) 3347 return NULL; 3348 } 3349 while (string_buffer_cod_width_capacity(table->conv_buffer) < n_codepoints) { 3350 if (FT_IS_ERROR(realloc_string_buffer_without_copy(table->conv_buffer))) { 3351 return NULL; 3352 } 3353 } 3354 if (!buffer_check_align(table->conv_buffer)) 3355 return NULL; 3356 char *buffer = (char *)buffer_get_data(table->conv_buffer); 3357 3358 size_t cols = 0; 3359 size_t rows = 0; 3360 size_t *col_vis_width_arr = NULL; 3361 size_t *row_vis_height_arr = NULL; 3362 status = table_rows_and_cols_geometry(table, &col_vis_width_arr, &cols, &row_vis_height_arr, &rows, VISIBLE_GEOMETRY); 3363 if (FT_IS_ERROR(status)) 3364 return NULL; 3365 3366 if (rows == 0) { 3367 F_FREE(col_vis_width_arr); 3368 F_FREE(row_vis_height_arr); 3369 return empty_str_arr[b_type]; 3370 } 3371 3372 int tmp = 0; 3373 size_t i = 0; 3374 f_context_t context; 3375 context.table_properties = (table->properties ? table->properties : &g_table_properties); 3376 f_row_t *prev_row = NULL; 3377 f_row_t *cur_row = NULL; 3378 f_separator_t *cur_sep = NULL; 3379 size_t sep_size = vector_size(table->separators); 3380 3381 f_conv_context_t cntx; 3382 cntx.u.buf = buffer; 3383 cntx.raw_avail = string_buffer_raw_capacity(table->conv_buffer); 3384 cntx.cntx = &context; 3385 cntx.b_type = b_type; 3386 3387 /* Print top margin */ 3388 for (i = 0; i < context.table_properties->entire_table_properties.top_margin; ++i) { 3389 FT_CHECK(print_n_strings(&cntx, cod_width - 1/* minus new_line*/, FT_SPACE)); 3390 FT_CHECK(print_n_strings(&cntx, 1, FT_NEWLINE)); 3391 } 3392 3393 for (i = 0; i < rows; ++i) { 3394 cur_sep = (i < sep_size) ? VECTOR_AT(table->separators, i, f_separator_t *) : NULL; 3395 cur_row = VECTOR_AT(table->rows, i, f_row_t *); 3396 enum f_hor_separator_pos separatorPos = (i == 0) ? TOP_SEPARATOR : INSIDE_SEPARATOR; 3397 context.row = i; 3398 FT_CHECK(print_row_separator(&cntx, col_vis_width_arr, cols, prev_row, cur_row, separatorPos, cur_sep)); 3399 FT_CHECK(snprintf_row(cur_row, &cntx, col_vis_width_arr, cols, row_vis_height_arr[i])); 3400 prev_row = cur_row; 3401 } 3402 cur_row = NULL; 3403 cur_sep = (i < sep_size) ? VECTOR_AT(table->separators, i, f_separator_t *) : NULL; 3404 context.row = i; 3405 FT_CHECK(print_row_separator(&cntx, col_vis_width_arr, cols, prev_row, cur_row, BOTTOM_SEPARATOR, cur_sep)); 3406 3407 /* Print bottom margin */ 3408 for (i = 0; i < context.table_properties->entire_table_properties.bottom_margin; ++i) { 3409 FT_CHECK(print_n_strings(&cntx, cod_width - 1/* minus new_line*/, FT_SPACE)); 3410 FT_CHECK(print_n_strings(&cntx, 1, FT_NEWLINE)); 3411 } 3412 3413 result = buffer; 3414 3415 clear: 3416 F_FREE(col_vis_width_arr); 3417 F_FREE(row_vis_height_arr); 3418 return result; 3419 } 3420 3421 const char *ft_to_string(const ft_table_t *table) 3422 { 3423 return (const char *)ft_to_string_impl(table, CHAR_BUF); 3424 } 3425 3426 #ifdef FT_HAVE_WCHAR 3427 const wchar_t *ft_to_wstring(const ft_table_t *table) 3428 { 3429 return (const wchar_t *)ft_to_string_impl(table, W_CHAR_BUF); 3430 } 3431 #endif 3432 3433 3434 int ft_add_separator(ft_table_t *table) 3435 { 3436 assert(table); 3437 assert(table->separators); 3438 3439 while (vector_size(table->separators) <= table->cur_row) { 3440 f_separator_t *sep_p = create_separator(F_FALSE); 3441 if (sep_p == NULL) 3442 return FT_MEMORY_ERROR; 3443 int status = vector_push(table->separators, &sep_p); 3444 if (FT_IS_ERROR(status)) 3445 return status; 3446 } 3447 3448 f_separator_t **sep_p = &VECTOR_AT(table->separators, table->cur_row, f_separator_t *); 3449 if (*sep_p == NULL) 3450 *sep_p = create_separator(F_TRUE); 3451 else 3452 (*sep_p)->enabled = F_TRUE; 3453 3454 if (*sep_p == NULL) 3455 return FT_GEN_ERROR; 3456 return FT_SUCCESS; 3457 } 3458 3459 static const struct fort_border_style *built_in_styles[] = { 3460 &FORT_BASIC_STYLE, 3461 &FORT_BASIC2_STYLE, 3462 &FORT_SIMPLE_STYLE, 3463 &FORT_PLAIN_STYLE, 3464 &FORT_DOT_STYLE, 3465 &FORT_EMPTY_STYLE, 3466 &FORT_EMPTY2_STYLE, 3467 &FORT_SOLID_STYLE, 3468 &FORT_SOLID_ROUND_STYLE, 3469 &FORT_NICE_STYLE, 3470 &FORT_DOUBLE_STYLE, 3471 &FORT_DOUBLE2_STYLE, 3472 &FORT_BOLD_STYLE, 3473 &FORT_BOLD2_STYLE, 3474 &FORT_FRAME_STYLE, 3475 }; 3476 #define BUILT_IN_STYLES_SZ (sizeof(built_in_styles) / sizeof(built_in_styles[0])) 3477 3478 /* todo: remove this stupid and dangerous code */ 3479 static const struct ft_border_style built_in_external_styles[BUILT_IN_STYLES_SZ] = { 3480 { 3481 {"", "", "", "", "", ""}, 3482 {"", "", "", "", "", ""}, 3483 "" 3484 } 3485 }; 3486 3487 const struct ft_border_style *const FT_BASIC_STYLE = &built_in_external_styles[0]; 3488 const struct ft_border_style *const FT_BASIC2_STYLE = &built_in_external_styles[1]; 3489 const struct ft_border_style *const FT_SIMPLE_STYLE = &built_in_external_styles[2]; 3490 const struct ft_border_style *const FT_PLAIN_STYLE = &built_in_external_styles[3]; 3491 const struct ft_border_style *const FT_DOT_STYLE = &built_in_external_styles[4]; 3492 const struct ft_border_style *const FT_EMPTY_STYLE = &built_in_external_styles[5]; 3493 const struct ft_border_style *const FT_EMPTY2_STYLE = &built_in_external_styles[6]; 3494 const struct ft_border_style *const FT_SOLID_STYLE = &built_in_external_styles[7]; 3495 const struct ft_border_style *const FT_SOLID_ROUND_STYLE = &built_in_external_styles[8]; 3496 const struct ft_border_style *const FT_NICE_STYLE = &built_in_external_styles[9]; 3497 const struct ft_border_style *const FT_DOUBLE_STYLE = &built_in_external_styles[10]; 3498 const struct ft_border_style *const FT_DOUBLE2_STYLE = &built_in_external_styles[11]; 3499 const struct ft_border_style *const FT_BOLD_STYLE = &built_in_external_styles[12]; 3500 const struct ft_border_style *const FT_BOLD2_STYLE = &built_in_external_styles[13]; 3501 const struct ft_border_style *const FT_FRAME_STYLE = &built_in_external_styles[14]; 3502 3503 static void set_border_props_for_props(f_table_properties_t *properties, const struct ft_border_style *style) 3504 { 3505 if (style >= built_in_external_styles && style < (built_in_external_styles + BUILT_IN_STYLES_SZ)) { 3506 size_t pos = (size_t)(style - built_in_external_styles); 3507 memcpy(&(properties->border_style), built_in_styles[pos], sizeof(struct fort_border_style)); 3508 return; 3509 } 3510 3511 const struct ft_border_chars *border_chs = &(style->border_chs); 3512 const struct ft_border_chars *header_border_chs = &(style->header_border_chs); 3513 3514 #define BOR_CHARS properties->border_style.border_chars 3515 #define H_BOR_CHARS properties->border_style.header_border_chars 3516 #define SEP_CHARS properties->border_style.separator_chars 3517 3518 BOR_CHARS[TT_bip] = border_chs->top_border_ch; 3519 BOR_CHARS[IH_bip] = border_chs->separator_ch; 3520 BOR_CHARS[BB_bip] = border_chs->bottom_border_ch; 3521 BOR_CHARS[LL_bip] = BOR_CHARS[IV_bip] = BOR_CHARS[RR_bip] = border_chs->side_border_ch; 3522 3523 BOR_CHARS[TL_bip] = BOR_CHARS[TV_bip] = BOR_CHARS[TR_bip] = border_chs->out_intersect_ch; 3524 BOR_CHARS[LH_bip] = BOR_CHARS[RH_bip] = border_chs->out_intersect_ch; 3525 BOR_CHARS[BL_bip] = BOR_CHARS[BV_bip] = BOR_CHARS[BR_bip] = border_chs->out_intersect_ch; 3526 BOR_CHARS[II_bip] = border_chs->in_intersect_ch; 3527 3528 BOR_CHARS[LI_bip] = BOR_CHARS[TI_bip] = BOR_CHARS[RI_bip] = BOR_CHARS[BI_bip] = border_chs->in_intersect_ch; 3529 3530 if (strlen(border_chs->separator_ch) == 0 && strlen(border_chs->in_intersect_ch) == 0) { 3531 BOR_CHARS[LH_bip] = BOR_CHARS[RH_bip] = "\0"; 3532 } 3533 3534 H_BOR_CHARS[TT_bip] = header_border_chs->top_border_ch; 3535 H_BOR_CHARS[IH_bip] = header_border_chs->separator_ch; 3536 H_BOR_CHARS[BB_bip] = header_border_chs->bottom_border_ch; 3537 H_BOR_CHARS[LL_bip] = H_BOR_CHARS[IV_bip] = H_BOR_CHARS[RR_bip] = header_border_chs->side_border_ch; 3538 3539 H_BOR_CHARS[TL_bip] = H_BOR_CHARS[TV_bip] = H_BOR_CHARS[TR_bip] = header_border_chs->out_intersect_ch; 3540 H_BOR_CHARS[LH_bip] = H_BOR_CHARS[RH_bip] = header_border_chs->out_intersect_ch; 3541 H_BOR_CHARS[BL_bip] = H_BOR_CHARS[BV_bip] = H_BOR_CHARS[BR_bip] = header_border_chs->out_intersect_ch; 3542 H_BOR_CHARS[II_bip] = header_border_chs->in_intersect_ch; 3543 3544 H_BOR_CHARS[LI_bip] = H_BOR_CHARS[TI_bip] = H_BOR_CHARS[RI_bip] = H_BOR_CHARS[BI_bip] = header_border_chs->in_intersect_ch; 3545 3546 if (strlen(header_border_chs->separator_ch) == 0 && strlen(header_border_chs->in_intersect_ch) == 0) { 3547 BOR_CHARS[LH_bip] = BOR_CHARS[RH_bip] = "\0"; 3548 } 3549 3550 SEP_CHARS[LH_sip] = SEP_CHARS[RH_sip] = SEP_CHARS[II_sip] = header_border_chs->out_intersect_ch; 3551 SEP_CHARS[TI_sip] = SEP_CHARS[BI_sip] = header_border_chs->out_intersect_ch; 3552 SEP_CHARS[IH_sip] = style->hor_separator_char; 3553 3554 3555 #undef BOR_CHARS 3556 #undef H_BOR_CHARS 3557 #undef SEP_CHARS 3558 } 3559 3560 3561 int ft_set_default_border_style(const struct ft_border_style *style) 3562 { 3563 set_border_props_for_props(&g_table_properties, style); 3564 return FT_SUCCESS; 3565 } 3566 3567 int ft_set_border_style(ft_table_t *table, const struct ft_border_style *style) 3568 { 3569 assert(table); 3570 if (table->properties == NULL) { 3571 table->properties = create_table_properties(); 3572 if (table->properties == NULL) 3573 return FT_MEMORY_ERROR; 3574 } 3575 set_border_props_for_props(table->properties, style); 3576 return FT_SUCCESS; 3577 } 3578 3579 3580 3581 int ft_set_cell_prop(ft_table_t *table, size_t row, size_t col, uint32_t property, int value) 3582 { 3583 assert(table); 3584 3585 if (table->properties == NULL) { 3586 table->properties = create_table_properties(); 3587 if (table->properties == NULL) 3588 return FT_MEMORY_ERROR; 3589 } 3590 if (table->properties->cell_properties == NULL) { 3591 table->properties->cell_properties = create_cell_prop_container(); 3592 if (table->properties->cell_properties == NULL) { 3593 return FT_GEN_ERROR; 3594 } 3595 } 3596 3597 if (row == FT_CUR_ROW) 3598 row = table->cur_row; 3599 if (col == FT_CUR_COLUMN) 3600 col = table->cur_col; 3601 3602 return set_cell_property(table->properties->cell_properties, row, col, property, value); 3603 } 3604 3605 int ft_set_default_cell_prop(uint32_t property, int value) 3606 { 3607 return set_default_cell_property(property, value); 3608 } 3609 3610 3611 int ft_set_default_tbl_prop(uint32_t property, int value) 3612 { 3613 return set_default_entire_table_property(property, value); 3614 } 3615 3616 int ft_set_tbl_prop(ft_table_t *table, uint32_t property, int value) 3617 { 3618 assert(table); 3619 3620 if (table->properties == NULL) { 3621 table->properties = create_table_properties(); 3622 if (table->properties == NULL) 3623 return FT_MEMORY_ERROR; 3624 } 3625 return set_entire_table_property(table->properties, property, value); 3626 } 3627 3628 void ft_set_memory_funcs(void *(*f_malloc)(size_t size), void (*f_free)(void *ptr)) 3629 { 3630 set_memory_funcs(f_malloc, f_free); 3631 } 3632 3633 const char *ft_strerror(int error_code) 3634 { 3635 switch (error_code) { 3636 case FT_MEMORY_ERROR: 3637 return "Out of memory"; 3638 case FT_GEN_ERROR: 3639 return "General error"; 3640 case FT_EINVAL: 3641 return "Invalid argument"; 3642 case FT_INTERN_ERROR: 3643 return "Internal libfort error"; 3644 default: 3645 if (error_code < 0) 3646 return "Unknown error code"; 3647 else 3648 return "Success"; 3649 } 3650 } 3651 3652 int ft_set_cell_span(ft_table_t *table, size_t row, size_t col, size_t hor_span) 3653 { 3654 assert(table); 3655 if (hor_span < 2) 3656 return FT_EINVAL; 3657 3658 if (row == FT_CUR_ROW) 3659 row = table->cur_row; 3660 if (row == FT_CUR_COLUMN) 3661 col = table->cur_col; 3662 3663 f_row_t *row_p = get_row_and_create_if_not_exists(table, row); 3664 if (row_p == NULL) 3665 return FT_GEN_ERROR; 3666 3667 return row_set_cell_span(row_p, col, hor_span); 3668 } 3669 3670 #ifdef FT_HAVE_UTF8 3671 3672 int ft_u8nwrite(ft_table_t *table, size_t n, const void *cell_content, ...) 3673 { 3674 size_t i = 0; 3675 assert(table); 3676 int status = ft_u8write_impl(table, cell_content); 3677 if (FT_IS_ERROR(status)) 3678 return status; 3679 3680 va_list va; 3681 va_start(va, cell_content); 3682 --n; 3683 for (i = 0; i < n; ++i) { 3684 const void *cell = va_arg(va, const void *); 3685 status = ft_u8write_impl(table, cell); 3686 if (FT_IS_ERROR(status)) { 3687 va_end(va); 3688 return status; 3689 } 3690 } 3691 va_end(va); 3692 3693 return status; 3694 } 3695 3696 int ft_u8nwrite_ln(ft_table_t *table, size_t n, const void *cell_content, ...) 3697 { 3698 size_t i = 0; 3699 assert(table); 3700 int status = ft_u8write_impl(table, cell_content); 3701 if (FT_IS_ERROR(status)) 3702 return status; 3703 3704 va_list va; 3705 va_start(va, cell_content); 3706 --n; 3707 for (i = 0; i < n; ++i) { 3708 const void *cell = va_arg(va, const void *); 3709 status = ft_u8write_impl(table, cell); 3710 if (FT_IS_ERROR(status)) { 3711 va_end(va); 3712 return status; 3713 } 3714 } 3715 va_end(va); 3716 3717 ft_ln(table); 3718 return status; 3719 } 3720 3721 FT_PRINTF_ATTRIBUTE_FORMAT(2, 3) 3722 int ft_u8printf(ft_table_t *table, const char *fmt, ...) 3723 { 3724 assert(table); 3725 va_list va; 3726 va_start(va, fmt); 3727 3728 struct f_string_view fmt_str; 3729 fmt_str.type = UTF8_BUF; 3730 fmt_str.u.cstr = fmt; 3731 int result = ft_row_printf_impl_(table, table->cur_row, &fmt_str, &va); 3732 va_end(va); 3733 return result; 3734 } 3735 3736 FT_PRINTF_ATTRIBUTE_FORMAT(2, 3) 3737 int ft_u8printf_ln(ft_table_t *table, const char *fmt, ...) 3738 { 3739 assert(table); 3740 va_list va; 3741 va_start(va, fmt); 3742 3743 struct f_string_view fmt_str; 3744 fmt_str.type = UTF8_BUF; 3745 fmt_str.u.cstr = fmt; 3746 int result = ft_row_printf_impl_(table, table->cur_row, &fmt_str, &va); 3747 if (result >= 0) { 3748 ft_ln(table); 3749 } 3750 va_end(va); 3751 return result; 3752 } 3753 3754 const void *ft_to_u8string(const ft_table_t *table) 3755 { 3756 return (const void *)ft_to_string_impl(table, UTF8_BUF); 3757 } 3758 3759 void ft_set_u8strwid_func(int (*u8strwid)(const void *beg, const void *end, size_t *width)) 3760 { 3761 buffer_set_u8strwid_func(u8strwid); 3762 } 3763 3764 #endif /* FT_HAVE_UTF8 */ 3765 3766 /******************************************************** 3767 End of file "fort_impl.c" 3768 ********************************************************/ 3769 3770 3771 /******************************************************** 3772 Begin of file "fort_utils.c" 3773 ********************************************************/ 3774 3775 /* #include "fort_utils.h" */ /* Commented by amalgamation script */ 3776 #ifdef FT_HAVE_WCHAR 3777 #include <wchar.h> 3778 #endif 3779 #if defined(FT_HAVE_UTF8) 3780 /* #include "utf8.h" */ /* Commented by amalgamation script */ 3781 #endif 3782 /* #include "string_buffer.h" */ /* Commented by amalgamation script */ 3783 3784 3785 char g_col_separator = FORT_DEFAULT_COL_SEPARATOR; 3786 3787 /***************************************************************************** 3788 * LIBFORT helpers 3789 *****************************************************************************/ 3790 3791 #if defined(FT_GCC_COMPILER) || defined(FT_CLANG_COMPILER) 3792 void *(*fort_malloc)(size_t size) = &malloc; 3793 void (*fort_free)(void *ptr) = &free; 3794 void *(*fort_calloc)(size_t nmemb, size_t size) = &calloc; 3795 void *(*fort_realloc)(void *ptr, size_t size) = &realloc; 3796 #else 3797 static void *local_malloc(size_t size) 3798 { 3799 return malloc(size); 3800 } 3801 3802 static void local_free(void *ptr) 3803 { 3804 free(ptr); 3805 } 3806 3807 static void *local_calloc(size_t nmemb, size_t size) 3808 { 3809 return calloc(nmemb, size); 3810 } 3811 3812 static void *local_realloc(void *ptr, size_t size) 3813 { 3814 return realloc(ptr, size); 3815 } 3816 3817 void *(*fort_malloc)(size_t size) = &local_malloc; 3818 void (*fort_free)(void *ptr) = &local_free; 3819 void *(*fort_calloc)(size_t nmemb, size_t size) = &local_calloc; 3820 void *(*fort_realloc)(void *ptr, size_t size) = &local_realloc; 3821 #endif 3822 3823 static void *custom_fort_calloc(size_t nmemb, size_t size) 3824 { 3825 size_t total_size = nmemb * size; 3826 void *result = F_MALLOC(total_size); 3827 if (result != NULL) 3828 memset(result, 0, total_size); 3829 return result; 3830 } 3831 3832 static void *custom_fort_realloc(void *ptr, size_t size) 3833 { 3834 if (ptr == NULL) 3835 return F_MALLOC(size); 3836 if (size == 0) { 3837 F_FREE(ptr); 3838 return NULL; 3839 } 3840 3841 void *new_chunk = F_MALLOC(size); 3842 if (new_chunk == NULL) 3843 return NULL; 3844 3845 /* 3846 * In theory we should copy MIN(size, size allocated for ptr) bytes, 3847 * but this is rather dummy implementation so we don't care about it 3848 */ 3849 memcpy(new_chunk, ptr, size); 3850 F_FREE(ptr); 3851 return new_chunk; 3852 } 3853 3854 3855 FT_INTERNAL 3856 void set_memory_funcs(void *(*f_malloc)(size_t size), void (*f_free)(void *ptr)) 3857 { 3858 assert((f_malloc == NULL && f_free == NULL) /* Use std functions */ 3859 || (f_malloc != NULL && f_free != NULL) /* Use custom functions */); 3860 3861 if (f_malloc == NULL && f_free == NULL) { 3862 #if defined(FT_GCC_COMPILER) || defined(FT_CLANG_COMPILER) 3863 fort_malloc = &malloc; 3864 fort_free = &free; 3865 fort_calloc = &calloc; 3866 fort_realloc = &realloc; 3867 #else 3868 fort_malloc = &local_malloc; 3869 fort_free = &local_free; 3870 fort_calloc = &local_calloc; 3871 fort_realloc = &local_realloc; 3872 #endif 3873 } else { 3874 fort_malloc = f_malloc; 3875 fort_free = f_free; 3876 fort_calloc = &custom_fort_calloc; 3877 fort_realloc = &custom_fort_realloc; 3878 } 3879 3880 } 3881 3882 FT_INTERNAL 3883 char *fort_strdup(const char *str) 3884 { 3885 if (str == NULL) 3886 return NULL; 3887 3888 size_t sz = strlen(str); 3889 char *str_copy = (char *)F_MALLOC((sz + 1) * sizeof(char)); 3890 if (str_copy == NULL) 3891 return NULL; 3892 3893 strcpy(str_copy, str); 3894 return str_copy; 3895 } 3896 3897 #if defined(FT_HAVE_WCHAR) 3898 FT_INTERNAL 3899 wchar_t *fort_wcsdup(const wchar_t *str) 3900 { 3901 if (str == NULL) 3902 return NULL; 3903 3904 size_t sz = wcslen(str); 3905 wchar_t *str_copy = (wchar_t *)F_MALLOC((sz + 1) * sizeof(wchar_t)); 3906 if (str_copy == NULL) 3907 return NULL; 3908 3909 wcscpy(str_copy, str); 3910 return str_copy; 3911 } 3912 #endif 3913 3914 3915 static 3916 size_t columns_number_in_fmt_string(const char *fmt) 3917 { 3918 size_t separator_counter = 0; 3919 const char *pos = fmt; 3920 while (1) { 3921 pos = strchr(pos, g_col_separator); 3922 if (pos == NULL) 3923 break; 3924 3925 separator_counter++; 3926 ++pos; 3927 } 3928 return separator_counter + 1; 3929 } 3930 3931 #if defined(FT_HAVE_WCHAR) 3932 static 3933 size_t columns_number_in_fmt_wstring(const wchar_t *fmt) 3934 { 3935 size_t separator_counter = 0; 3936 const wchar_t *pos = fmt; 3937 while (1) { 3938 pos = wcschr(pos, g_col_separator); 3939 if (pos == NULL) 3940 break; 3941 3942 separator_counter++; 3943 ++pos; 3944 } 3945 return separator_counter + 1; 3946 } 3947 #endif 3948 3949 #if defined(FT_HAVE_UTF8) 3950 static 3951 size_t columns_number_in_fmt_u8string(const void *fmt) 3952 { 3953 size_t separator_counter = 0; 3954 const char *pos = (const char *)fmt; 3955 while (1) { 3956 pos = (const char *)utf8chr(pos, g_col_separator); 3957 if (pos == NULL) 3958 break; 3959 3960 separator_counter++; 3961 ++pos; 3962 } 3963 return separator_counter + 1; 3964 } 3965 #endif 3966 3967 FT_INTERNAL 3968 size_t number_of_columns_in_format_string(const f_string_view_t *fmt) 3969 { 3970 switch (fmt->type) { 3971 case CHAR_BUF: 3972 return columns_number_in_fmt_string(fmt->u.cstr); 3973 #ifdef FT_HAVE_WCHAR 3974 case W_CHAR_BUF: 3975 return columns_number_in_fmt_wstring(fmt->u.wstr); 3976 #endif /* FT_HAVE_WCHAR */ 3977 #ifdef FT_HAVE_UTF8 3978 case UTF8_BUF: 3979 return columns_number_in_fmt_u8string(fmt->u.u8str); 3980 #endif /* FT_HAVE_UTF8 */ 3981 default: 3982 assert(0); 3983 } 3984 return 0; 3985 } 3986 3987 FT_INTERNAL 3988 size_t number_of_columns_in_format_buffer(const f_string_buffer_t *fmt) 3989 { 3990 switch (fmt->type) { 3991 case CHAR_BUF: 3992 return columns_number_in_fmt_string(fmt->str.cstr); 3993 #ifdef FT_HAVE_WCHAR 3994 case W_CHAR_BUF: 3995 return columns_number_in_fmt_wstring(fmt->str.wstr); 3996 #endif /* FT_HAVE_WCHAR */ 3997 #ifdef FT_HAVE_UTF8 3998 case UTF8_BUF: 3999 return columns_number_in_fmt_u8string(fmt->str.u8str); 4000 #endif /* FT_HAVE_UTF8 */ 4001 default: 4002 assert(0); 4003 } 4004 return 0; 4005 } 4006 4007 static 4008 int snprint_n_strings_impl(char *buf, size_t length, size_t n, const char *str) 4009 { 4010 size_t str_len = strlen(str); 4011 if (length <= n * str_len) 4012 return -1; 4013 4014 if (n == 0) 4015 return 0; 4016 4017 /* To ensure valid return value it is safely not print such big strings */ 4018 if (n * str_len > INT_MAX) 4019 return -1; 4020 4021 if (str_len == 0) 4022 return 0; 4023 4024 int status = snprintf(buf, length, "%0*d", (int)(n * str_len), 0); 4025 if (status < 0) 4026 return status; 4027 4028 size_t i = 0; 4029 for (i = 0; i < n; ++i) { 4030 const char *str_p = str; 4031 while (*str_p) 4032 *(buf++) = *(str_p++); 4033 } 4034 return (int)(n * str_len); 4035 } 4036 4037 static 4038 int snprint_n_strings(f_conv_context_t *cntx, size_t n, const char *str) 4039 { 4040 int w = snprint_n_strings_impl(cntx->u.buf, cntx->raw_avail, n, str); 4041 if (w >= 0) { 4042 cntx->u.buf += w; 4043 cntx->raw_avail -= w; 4044 } 4045 return w; 4046 } 4047 4048 #if defined(FT_HAVE_WCHAR) 4049 static 4050 int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str); 4051 #endif 4052 4053 #if defined(FT_HAVE_UTF8) 4054 static 4055 int u8nprint_n_strings(void *buf, size_t length, size_t n, const void *str); 4056 #endif 4057 4058 4059 FT_INTERNAL 4060 int print_n_strings(f_conv_context_t *cntx, size_t n, const char *str) 4061 { 4062 int cod_w; 4063 int raw_written; 4064 4065 switch (cntx->b_type) { 4066 case CHAR_BUF: 4067 raw_written = snprint_n_strings(cntx, n, str); 4068 cod_w = raw_written; 4069 return cod_w; 4070 #ifdef FT_HAVE_WCHAR 4071 case W_CHAR_BUF: 4072 cod_w = wsnprint_n_string(cntx->u.wbuf, cntx->raw_avail, n, str); 4073 if (cod_w < 0) 4074 return cod_w; 4075 raw_written = sizeof(wchar_t) * cod_w; 4076 4077 cntx->u.buf += raw_written; 4078 cntx->raw_avail -= raw_written; 4079 return cod_w; 4080 #endif /* FT_HAVE_WCHAR */ 4081 #ifdef FT_HAVE_UTF8 4082 case UTF8_BUF: 4083 /* Everying is very strange and differs with W_CHAR_BUF */ 4084 raw_written = u8nprint_n_strings(cntx->u.buf, cntx->raw_avail, n, str); 4085 if (raw_written < 0) { 4086 fprintf(stderr, " raw_written = %d\n", raw_written); 4087 return raw_written; 4088 } 4089 4090 cntx->u.buf += raw_written; 4091 cntx->raw_avail -= raw_written; 4092 return utf8len(str) * n; 4093 #endif /* FT_HAVE_UTF8 */ 4094 default: 4095 assert(0); 4096 return -1; 4097 } 4098 } 4099 4100 FT_INTERNAL 4101 int ft_nprint(f_conv_context_t *cntx, const char *str, size_t strlen) 4102 { 4103 if (cntx->raw_avail + 1/* for 0 */ < strlen) 4104 return -1; 4105 4106 memcpy(cntx->u.buf, str, strlen); 4107 cntx->u.buf += strlen; 4108 cntx->raw_avail -= strlen; 4109 *cntx->u.buf = '\0'; /* Do we need this ? */ 4110 return strlen; 4111 } 4112 4113 #ifdef FT_HAVE_WCHAR 4114 int ft_nwprint(f_conv_context_t *cntx, const wchar_t *str, size_t strlen) 4115 { 4116 if (cntx->raw_avail + 1/* for 0 */ < strlen) 4117 return -1; 4118 4119 size_t raw_len = strlen * sizeof(wchar_t); 4120 4121 memcpy(cntx->u.buf, str, raw_len); 4122 cntx->u.buf += raw_len; 4123 cntx->raw_avail -= raw_len; 4124 4125 /* Do we need this ? */ 4126 wchar_t end_of_string = L'\0'; 4127 memcpy(cntx->u.buf, &end_of_string, sizeof(wchar_t)); 4128 return strlen; 4129 } 4130 #endif /* FT_HAVE_WCHAR */ 4131 4132 #ifdef FT_HAVE_UTF8 4133 FT_INTERNAL 4134 int ft_nu8print(f_conv_context_t *cntx, const void *beg, const void *end) 4135 { 4136 const char *bc = (const char *)beg; 4137 const char *ec = (const char *)end; 4138 size_t raw_len = ec - bc; 4139 if (cntx->raw_avail + 1 < raw_len) 4140 return -1; 4141 4142 memcpy(cntx->u.buf, beg, raw_len); 4143 cntx->u.buf += raw_len; 4144 cntx->raw_avail -= raw_len; 4145 *(cntx->u.buf) = '\0'; /* Do we need this ? */ 4146 return raw_len; /* what return here ? */ 4147 } 4148 #endif /* FT_HAVE_UTF8 */ 4149 4150 #if defined(FT_HAVE_WCHAR) 4151 #define WCS_SIZE 64 4152 4153 static 4154 int wsnprint_n_string(wchar_t *buf, size_t length, size_t n, const char *str) 4155 { 4156 size_t str_len = strlen(str); 4157 4158 /* note: maybe it's, better to return -1 in case of multibyte character 4159 * strings (not sure this case is done correctly). 4160 */ 4161 if (str_len > 1) { 4162 const unsigned char *p = (const unsigned char *)str; 4163 while (*p) { 4164 if (*p <= 127) 4165 p++; 4166 else { 4167 wchar_t wcs[WCS_SIZE]; 4168 const char *ptr = str; 4169 size_t wcs_len; 4170 mbstate_t mbst; 4171 memset(&mbst, 0, sizeof(mbst)); 4172 wcs_len = mbsrtowcs(wcs, (const char **)&ptr, WCS_SIZE, &mbst); 4173 /* for simplicity */ 4174 if ((wcs_len == (size_t) - 1) || wcs_len > 1) { 4175 return -1; 4176 } else { 4177 wcs[wcs_len] = L'\0'; 4178 size_t k = n; 4179 while (k) { 4180 *buf = *wcs; 4181 ++buf; 4182 --k; 4183 } 4184 buf[n] = L'\0'; 4185 return (int)n; 4186 } 4187 } 4188 } 4189 } 4190 4191 if (length <= n * str_len) 4192 return -1; 4193 4194 if (n == 0) 4195 return 0; 4196 4197 /* To ensure valid return value it is safely not print such big strings */ 4198 if (n * str_len > INT_MAX) 4199 return -1; 4200 4201 if (str_len == 0) 4202 return 0; 4203 4204 int status = swprintf(buf, length, L"%0*d", (int)(n * str_len), 0); 4205 if (status < 0) 4206 return status; 4207 4208 size_t i = 0; 4209 for (i = 0; i < n; ++i) { 4210 const char *str_p = str; 4211 while (*str_p) 4212 *(buf++) = (wchar_t) * (str_p++); 4213 } 4214 return (int)(n * str_len); 4215 } 4216 #endif 4217 4218 4219 #if defined(FT_HAVE_UTF8) 4220 static 4221 int u8nprint_n_strings(void *buf, size_t length, size_t n, const void *str) 4222 { 4223 size_t str_size = utf8size(str) - 1; /* str_size - raw size in bytes, excluding \0 */ 4224 if (length <= n * str_size) 4225 return -1; 4226 4227 if (n == 0) 4228 return 0; 4229 4230 /* To ensure valid return value it is safely not print such big strings */ 4231 if (n * str_size > INT_MAX) 4232 return -1; 4233 4234 if (str_size == 0) 4235 return 0; 4236 4237 size_t i = n; 4238 while (i) { 4239 memcpy(buf, str, str_size); 4240 buf = (char *)buf + str_size; 4241 --i; 4242 } 4243 *(char *)buf = '\0'; 4244 return (int)(n * str_size); 4245 } 4246 #endif 4247 4248 /******************************************************** 4249 End of file "fort_utils.c" 4250 ********************************************************/ 4251 4252 4253 /******************************************************** 4254 Begin of file "properties.c" 4255 ********************************************************/ 4256 4257 /* #include "fort_utils.h" */ /* Commented by amalgamation script */ 4258 #include <assert.h> 4259 /* #include "properties.h" */ /* Commented by amalgamation script */ 4260 /* #include "vector.h" */ /* Commented by amalgamation script */ 4261 4262 #define FT_RESET_COLOR "\033[0m" 4263 4264 static const char *fg_colors[] = { 4265 "", 4266 "\033[30m", 4267 "\033[31m", 4268 "\033[32m", 4269 "\033[33m", 4270 "\033[34m", 4271 "\033[35m", 4272 "\033[36m", 4273 "\033[37m", 4274 "\033[90m", 4275 "\033[91m", 4276 "\033[92m", 4277 "\033[93m", 4278 "\033[94m", 4279 "\033[95m", 4280 "\033[96m", 4281 "\033[97m", 4282 }; 4283 4284 static const char *bg_colors[] = { 4285 "", 4286 "\033[40m", 4287 "\033[41m", 4288 "\033[42m", 4289 "\033[43m", 4290 "\033[44m", 4291 "\033[45m", 4292 "\033[46m", 4293 "\033[47m", 4294 "\033[100m", 4295 "\033[101m", 4296 "\033[102m", 4297 "\033[103m", 4298 "\033[104m", 4299 "\033[105m", 4300 "\033[106m", 4301 "\033[107m", 4302 }; 4303 4304 static const char *text_styles[] = { 4305 "", 4306 "\033[1m", 4307 "\033[2m", 4308 "\033[3m", 4309 "\033[4m", 4310 "\033[5m", 4311 "\033[7m", 4312 "\033[8m", 4313 }; 4314 4315 #define UNIVERSAL_RESET_TAG "\033[0m" 4316 4317 static const size_t n_fg_colors = sizeof(fg_colors) / sizeof(fg_colors[0]); 4318 static const size_t n_bg_colors = sizeof(bg_colors) / sizeof(bg_colors[0]); 4319 static const size_t n_styles = sizeof(text_styles) / sizeof(text_styles[0]); 4320 4321 void get_style_tag_for_cell(const f_table_properties_t *props, 4322 size_t row, size_t col, char *style_tag, size_t sz) 4323 { 4324 (void)sz; 4325 size_t i = 0; 4326 4327 unsigned bg_color_number = get_cell_property_hierarchically(props, row, col, FT_CPROP_CELL_BG_COLOR); 4328 unsigned text_style = get_cell_property_hierarchically(props, row, col, FT_CPROP_CELL_TEXT_STYLE); 4329 4330 style_tag[0] = '\0'; 4331 4332 if (text_style < (1U << n_styles)) { 4333 for (i = 0; i < n_styles; ++i) { 4334 if (text_style & (1 << i)) { 4335 strcat(style_tag, text_styles[i]); 4336 } 4337 } 4338 } else { 4339 goto error; 4340 } 4341 4342 if (get_cell_property_hierarchically(props, row, col, FT_CPROP_CELL_BG_RGBCOLOR)) { 4343 char b[20]; 4344 4345 #define BGTERMRGB "\x1b[48;2;" 4346 snprintf(b, sizeof(b), BGTERMRGB "%u;%u;%um", bg_color_number>>16, (bg_color_number&0xFF00)>>8, bg_color_number&0xFF); 4347 strcat(style_tag, b); 4348 } 4349 else if (bg_color_number < n_bg_colors) { 4350 strcat(style_tag, bg_colors[bg_color_number]); 4351 } else { 4352 goto error; 4353 } 4354 4355 return; 4356 4357 error: 4358 /* shouldn't be here */ 4359 assert(0); 4360 style_tag[0] = '\0'; 4361 return; 4362 } 4363 4364 void get_reset_style_tag_for_cell(const f_table_properties_t *props, 4365 size_t row, size_t col, char *reset_style_tag, size_t sz) 4366 { 4367 (void)sz; 4368 size_t i = 0; 4369 4370 unsigned bg_color_number = get_cell_property_hierarchically(props, row, col, FT_CPROP_CELL_BG_COLOR); 4371 unsigned text_style = get_cell_property_hierarchically(props, row, col, FT_CPROP_CELL_TEXT_STYLE); 4372 4373 reset_style_tag[0] = '\0'; 4374 4375 if (text_style < (1U << n_styles)) { 4376 for (i = 0; i < n_styles; ++i) { 4377 if (text_style & (1 << i)) { 4378 if (i != 0) // FT_TSTYLE_DEFAULT 4379 goto reset_style; 4380 } 4381 } 4382 } else { 4383 goto error; 4384 } 4385 4386 reset_style: 4387 strcat(reset_style_tag, UNIVERSAL_RESET_TAG); 4388 return; 4389 4390 error: 4391 /* shouldn't be here */ 4392 assert(0); 4393 reset_style_tag[0] = '\0'; 4394 return; 4395 } 4396 4397 4398 void get_style_tag_for_content(const f_table_properties_t *props, 4399 size_t row, size_t col, char *style_tag, size_t sz) 4400 { 4401 (void)sz; 4402 size_t i = 0; 4403 4404 unsigned text_style = get_cell_property_hierarchically(props, row, col, FT_CPROP_CONT_TEXT_STYLE); 4405 unsigned fg_color_number = get_cell_property_hierarchically(props, row, col, FT_CPROP_CONT_FG_COLOR); 4406 unsigned bg_color_number = get_cell_property_hierarchically(props, row, col, FT_CPROP_CONT_BG_COLOR); 4407 4408 style_tag[0] = '\0'; 4409 4410 if (text_style < (1U << n_styles)) { 4411 for (i = 0; i < n_styles; ++i) { 4412 if (text_style & (1 << i)) { 4413 strcat(style_tag, text_styles[i]); 4414 } 4415 } 4416 } else { 4417 goto error; 4418 } 4419 4420 if (fg_color_number < n_fg_colors) { 4421 if (fg_color_number) 4422 strcat(style_tag, fg_colors[fg_color_number]); 4423 } else { 4424 goto error; 4425 } 4426 4427 if (bg_color_number < n_bg_colors) { 4428 strcat(style_tag, bg_colors[bg_color_number]); 4429 } else { 4430 goto error; 4431 } 4432 4433 return; 4434 4435 error: 4436 /* shouldn't be here */ 4437 assert(0); 4438 style_tag[0] = '\0'; 4439 return; 4440 } 4441 4442 void get_reset_style_tag_for_content(const f_table_properties_t *props, 4443 size_t row, size_t col, char *reset_style_tag, size_t sz) 4444 { 4445 (void)sz; 4446 size_t i = 0; 4447 size_t len = 0; 4448 4449 unsigned text_style = get_cell_property_hierarchically(props, row, col, FT_CPROP_CONT_TEXT_STYLE); 4450 unsigned fg_color_number = get_cell_property_hierarchically(props, row, col, FT_CPROP_CONT_FG_COLOR); 4451 unsigned bg_color_number = get_cell_property_hierarchically(props, row, col, FT_CPROP_CONT_BG_COLOR); 4452 4453 reset_style_tag[0] = '\0'; 4454 4455 if (text_style < (1U << n_styles)) { 4456 for (i = 0; i < n_styles; ++i) { 4457 if (text_style & (1 << i)) { 4458 if (i != 0) // FT_TSTYLE_DEFAULT 4459 goto reset_style; 4460 } 4461 } 4462 } else { 4463 goto error; 4464 } 4465 4466 if (fg_color_number < n_fg_colors) { 4467 if (fg_color_number) 4468 goto reset_style; 4469 } else { 4470 goto error; 4471 } 4472 4473 if (bg_color_number < n_bg_colors) { 4474 if (bg_color_number) 4475 goto reset_style; 4476 } else { 4477 goto error; 4478 } 4479 4480 return; 4481 4482 4483 reset_style: 4484 strcat(reset_style_tag, UNIVERSAL_RESET_TAG); 4485 len = strlen(reset_style_tag); 4486 get_style_tag_for_cell(props, row, col, reset_style_tag + len, sz - len); 4487 return; 4488 4489 error: 4490 /* shouldn't be here */ 4491 assert(0); 4492 reset_style_tag[0] = '\0'; 4493 return; 4494 } 4495 4496 4497 static struct f_cell_props g_default_cell_properties = { 4498 FT_ANY_ROW, /* cell_row */ 4499 FT_ANY_COLUMN, /* cell_col */ 4500 4501 /* properties_flags */ 4502 FT_CPROP_MIN_WIDTH | FT_CPROP_TEXT_ALIGN | FT_CPROP_TOP_PADDING 4503 | FT_CPROP_BOTTOM_PADDING | FT_CPROP_LEFT_PADDING | FT_CPROP_RIGHT_PADDING 4504 | FT_CPROP_EMPTY_STR_HEIGHT | FT_CPROP_CONT_FG_COLOR | FT_CPROP_CELL_BG_COLOR 4505 | FT_CPROP_CONT_BG_COLOR | FT_CPROP_CELL_TEXT_STYLE | FT_CPROP_CONT_TEXT_STYLE, 4506 4507 0, /* col_min_width */ 4508 FT_ALIGNED_LEFT, /* align */ 4509 0, /* cell_padding_top */ 4510 0, /* cell_padding_bottom */ 4511 1, /* cell_padding_left */ 4512 1, /* cell_padding_right */ 4513 1, /* cell_empty_string_height */ 4514 4515 FT_ROW_COMMON, /* row_type */ 4516 FT_COLOR_DEFAULT, /* content_fg_color_number */ 4517 FT_COLOR_DEFAULT, /* content_bg_color_number */ 4518 FT_COLOR_DEFAULT, /* cell_bg_color_number */ 4519 FT_TSTYLE_DEFAULT, /* cell_text_style */ 4520 FT_TSTYLE_DEFAULT, /* content_text_style */ 4521 false, 4522 }; 4523 4524 static int get_prop_value_if_exists_otherwise_default(const struct f_cell_props *cell_opts, uint32_t property) 4525 { 4526 if (cell_opts == NULL || !PROP_IS_SET(cell_opts->properties_flags, property)) { 4527 cell_opts = &g_default_cell_properties; 4528 } 4529 4530 switch (property) { 4531 case FT_CPROP_MIN_WIDTH: 4532 return cell_opts->col_min_width; 4533 case FT_CPROP_TEXT_ALIGN: 4534 return cell_opts->align; 4535 case FT_CPROP_TOP_PADDING: 4536 return cell_opts->cell_padding_top; 4537 case FT_CPROP_BOTTOM_PADDING: 4538 return cell_opts->cell_padding_bottom; 4539 case FT_CPROP_LEFT_PADDING: 4540 return cell_opts->cell_padding_left; 4541 case FT_CPROP_RIGHT_PADDING: 4542 return cell_opts->cell_padding_right; 4543 case FT_CPROP_EMPTY_STR_HEIGHT: 4544 return cell_opts->cell_empty_string_height; 4545 case FT_CPROP_ROW_TYPE: 4546 return cell_opts->row_type; 4547 case FT_CPROP_CONT_FG_COLOR: 4548 return cell_opts->content_fg_color_number; 4549 case FT_CPROP_CONT_BG_COLOR: 4550 return cell_opts->content_bg_color_number; 4551 case FT_CPROP_CELL_BG_COLOR: 4552 return cell_opts->cell_bg_color_number; 4553 case FT_CPROP_CELL_BG_RGBCOLOR: 4554 return cell_opts->rgb; 4555 case FT_CPROP_CELL_TEXT_STYLE: 4556 return cell_opts->cell_text_style; 4557 case FT_CPROP_CONT_TEXT_STYLE: 4558 return cell_opts->content_text_style; 4559 default: 4560 /* todo: implement later */ 4561 exit(333); 4562 } 4563 } 4564 4565 4566 FT_INTERNAL 4567 f_cell_prop_container_t *create_cell_prop_container(void) 4568 { 4569 f_cell_prop_container_t *ret = create_vector(sizeof(f_cell_props_t), DEFAULT_VECTOR_CAPACITY); 4570 return ret; 4571 } 4572 4573 4574 FT_INTERNAL 4575 void destroy_cell_prop_container(f_cell_prop_container_t *cont) 4576 { 4577 if (cont) 4578 destroy_vector(cont); 4579 } 4580 4581 4582 FT_INTERNAL 4583 const f_cell_props_t *cget_cell_prop(const f_cell_prop_container_t *cont, size_t row, size_t col) 4584 { 4585 assert(cont); 4586 size_t sz = vector_size(cont); 4587 size_t i = 0; 4588 for (i = 0; i < sz; ++i) { 4589 const f_cell_props_t *opt = &VECTOR_AT_C(cont, i, const f_cell_props_t); 4590 if (opt->cell_row == row && opt->cell_col == col) 4591 return opt; 4592 } 4593 return NULL; 4594 } 4595 4596 4597 FT_INTERNAL 4598 f_cell_props_t *get_cell_prop_and_create_if_not_exists(f_cell_prop_container_t *cont, size_t row, size_t col) 4599 { 4600 assert(cont); 4601 size_t sz = vector_size(cont); 4602 size_t i = 0; 4603 for (i = 0; i < sz; ++i) { 4604 f_cell_props_t *opt = &VECTOR_AT(cont, i, f_cell_props_t); 4605 if (opt->cell_row == row && opt->cell_col == col) 4606 return opt; 4607 } 4608 4609 f_cell_props_t opt; 4610 if (row == FT_ANY_ROW && col == FT_ANY_COLUMN) 4611 memcpy(&opt, &g_default_cell_properties, sizeof(f_cell_props_t)); 4612 else 4613 memset(&opt, 0, sizeof(f_cell_props_t)); 4614 4615 opt.cell_row = row; 4616 opt.cell_col = col; 4617 if (FT_IS_SUCCESS(vector_push(cont, &opt))) { 4618 return &VECTOR_AT(cont, sz, f_cell_props_t); 4619 } 4620 4621 return NULL; 4622 } 4623 4624 4625 FT_INTERNAL 4626 int get_cell_property_hierarchically(const f_table_properties_t *propertiess, size_t row, size_t column, uint32_t property) 4627 { 4628 assert(propertiess); 4629 size_t row_origin = row; 4630 4631 const f_cell_props_t *opt = NULL; 4632 if (propertiess->cell_properties != NULL) { 4633 while (1) { 4634 opt = cget_cell_prop(propertiess->cell_properties, row, column); 4635 if (opt != NULL && PROP_IS_SET(opt->properties_flags, property)) 4636 break; 4637 4638 if (row != FT_ANY_ROW && column != FT_ANY_COLUMN) { 4639 row = FT_ANY_ROW; 4640 continue; 4641 } else if (row == FT_ANY_ROW && column != FT_ANY_COLUMN) { 4642 row = row_origin; 4643 column = FT_ANY_COLUMN; 4644 continue; 4645 } else if (row != FT_ANY_ROW && column == FT_ANY_COLUMN) { 4646 row = FT_ANY_ROW; 4647 column = FT_ANY_COLUMN; 4648 continue; 4649 } 4650 4651 opt = NULL; 4652 break; 4653 } 4654 } 4655 4656 return get_prop_value_if_exists_otherwise_default(opt, property); 4657 } 4658 4659 4660 static f_status set_cell_property_impl(f_cell_props_t *opt, uint32_t property, int value) 4661 { 4662 assert(opt); 4663 4664 PROP_SET(opt->properties_flags, property); 4665 if (PROP_IS_SET(property, FT_CPROP_MIN_WIDTH)) { 4666 CHECK_NOT_NEGATIVE(value); 4667 opt->col_min_width = value; 4668 } else if (PROP_IS_SET(property, FT_CPROP_TEXT_ALIGN)) { 4669 opt->align = (enum ft_text_alignment)value; 4670 } else if (PROP_IS_SET(property, FT_CPROP_TOP_PADDING)) { 4671 CHECK_NOT_NEGATIVE(value); 4672 opt->cell_padding_top = value; 4673 } else if (PROP_IS_SET(property, FT_CPROP_BOTTOM_PADDING)) { 4674 CHECK_NOT_NEGATIVE(value); 4675 opt->cell_padding_bottom = value; 4676 } else if (PROP_IS_SET(property, FT_CPROP_LEFT_PADDING)) { 4677 CHECK_NOT_NEGATIVE(value); 4678 opt->cell_padding_left = value; 4679 } else if (PROP_IS_SET(property, FT_CPROP_RIGHT_PADDING)) { 4680 CHECK_NOT_NEGATIVE(value); 4681 opt->cell_padding_right = value; 4682 } else if (PROP_IS_SET(property, FT_CPROP_EMPTY_STR_HEIGHT)) { 4683 CHECK_NOT_NEGATIVE(value); 4684 opt->cell_empty_string_height = value; 4685 } else if (PROP_IS_SET(property, FT_CPROP_ROW_TYPE)) { 4686 opt->row_type = (enum ft_row_type)value; 4687 } else if (PROP_IS_SET(property, FT_CPROP_CONT_FG_COLOR)) { 4688 opt->content_fg_color_number = value; 4689 } else if (PROP_IS_SET(property, FT_CPROP_CONT_BG_COLOR)) { 4690 opt->content_bg_color_number = value; 4691 } else if (PROP_IS_SET(property, FT_CPROP_CELL_BG_COLOR)) { 4692 opt->cell_bg_color_number = value; 4693 } else if (PROP_IS_SET(property, FT_CPROP_CELL_BG_RGBCOLOR)) { 4694 opt->cell_bg_color_number = value; 4695 opt->rgb = true; 4696 } else if (PROP_IS_SET(property, FT_CPROP_CELL_TEXT_STYLE)) { 4697 enum ft_text_style v = (enum ft_text_style)value; 4698 if (v == FT_TSTYLE_DEFAULT) { 4699 opt->cell_text_style = FT_TSTYLE_DEFAULT; 4700 } else { 4701 opt->cell_text_style = (enum ft_text_style)(opt->cell_text_style | v); 4702 } 4703 } else if (PROP_IS_SET(property, FT_CPROP_CONT_TEXT_STYLE)) { 4704 enum ft_text_style v = (enum ft_text_style)value; 4705 if (v == FT_TSTYLE_DEFAULT) { 4706 opt->content_text_style = v; 4707 } else { 4708 opt->content_text_style = (enum ft_text_style)(opt->content_text_style | v); 4709 } 4710 } 4711 4712 return FT_SUCCESS; 4713 4714 fort_fail: 4715 return FT_EINVAL; 4716 } 4717 4718 4719 FT_INTERNAL 4720 f_status set_cell_property(f_cell_prop_container_t *cont, size_t row, size_t col, uint32_t property, int value) 4721 { 4722 f_cell_props_t *opt = get_cell_prop_and_create_if_not_exists(cont, row, col); 4723 if (opt == NULL) 4724 return FT_GEN_ERROR; 4725 4726 return set_cell_property_impl(opt, property, value); 4727 /* 4728 PROP_SET(opt->propertiess, property); 4729 if (PROP_IS_SET(property, FT_CPROP_MIN_WIDTH)) { 4730 opt->col_min_width = value; 4731 } else if (PROP_IS_SET(property, FT_CPROP_TEXT_ALIGN)) { 4732 opt->align = value; 4733 } 4734 4735 return FT_SUCCESS; 4736 */ 4737 } 4738 4739 4740 FT_INTERNAL 4741 f_status set_default_cell_property(uint32_t property, int value) 4742 { 4743 return set_cell_property_impl(&g_default_cell_properties, property, value); 4744 } 4745 4746 4747 #define BASIC_STYLE { \ 4748 /* border_chars */ \ 4749 { \ 4750 "+", "-", "+", "+", \ 4751 "|", "|", "|", \ 4752 "\0", "\0", "\0", "\0", \ 4753 "+", "-", "+", "+", \ 4754 "+", "+", "+", "+", \ 4755 }, \ 4756 /* header_border_chars */ \ 4757 { \ 4758 "+", "-", "+", "+", \ 4759 "|", "|", "|", \ 4760 "+", "-", "+", "+", \ 4761 "+", "-", "+", "+", \ 4762 "+", "+", "+", "+", \ 4763 }, \ 4764 /* separator_chars */ \ 4765 { \ 4766 "+", "-", "+", "+", \ 4767 "+", "+", \ 4768 }, \ 4769 } 4770 4771 #define BASIC2_STYLE { \ 4772 /* border_chars */ \ 4773 { \ 4774 "+", "-", "+", "+", \ 4775 "|", "|", "|", \ 4776 "+", "-", "+", "+", \ 4777 "+", "-", "+", "+", \ 4778 "+", "+", "+", "+", \ 4779 }, \ 4780 /* header_border_chars */ \ 4781 { \ 4782 "+", "-", "+", "+", \ 4783 "|", "|", "|", \ 4784 "+", "-", "+", "+", \ 4785 "+", "-", "+", "+", \ 4786 "+", "+", "+", "+", \ 4787 }, \ 4788 /* separator_chars */ \ 4789 { \ 4790 "+", "-", "+", "+", \ 4791 "+", "+", \ 4792 }, \ 4793 } 4794 4795 #define SIMPLE_STYLE { \ 4796 /* border_chars */ \ 4797 { \ 4798 "\0", "\0", "\0", "\0", \ 4799 "\0", " ", "\0", \ 4800 "\0", "\0", "\0", "\0", \ 4801 "\0", "\0", "\0", "\0", \ 4802 "\0", "\0", "\0", "\0", \ 4803 }, \ 4804 /* header_border_chars */ \ 4805 { \ 4806 "\0", "\0", "\0", "\0", \ 4807 "\0", " ", "\0", \ 4808 "\0", "─", " ", "\0", \ 4809 "\0", " ", " ", "\0", \ 4810 " ", "─", " ", "─", \ 4811 }, \ 4812 /* separator_chars */ \ 4813 { \ 4814 "\0", "─", " ", "\0", \ 4815 " ", " ", \ 4816 }, \ 4817 } 4818 4819 #define PLAIN_STYLE { \ 4820 /* border_chars */ \ 4821 { \ 4822 "\0", "\0", "\0", "\0", \ 4823 "\0", " ", "\0", \ 4824 "\0", "\0", "\0", "\0", \ 4825 "\0", "\0", "\0", "\0", \ 4826 "\0", "\0", "\0", "\0", \ 4827 }, \ 4828 /* header_border_chars */ \ 4829 { \ 4830 "\0", "-", "-", "\0", \ 4831 "\0", " ", "\0", \ 4832 "\0", "-", "-", "\0", \ 4833 "\0", "-", "-", "\0", \ 4834 " ", "-", " ", "-", \ 4835 }, \ 4836 /* separator_chars */ \ 4837 { \ 4838 "\0", "-", "-", "\0", \ 4839 "-", "-", \ 4840 }, \ 4841 } 4842 4843 #define DOT_STYLE { \ 4844 /* border_chars */ \ 4845 { \ 4846 ".", ".", ".", ".", \ 4847 ":", ":", ":", \ 4848 "\0", "\0", "\0", "\0", \ 4849 ":", ".", ":", ":", \ 4850 "+", ":", "+", ":", \ 4851 }, \ 4852 /* header_border_chars */ \ 4853 { \ 4854 ".", ".", ".", ".", \ 4855 ":", ":", ":", \ 4856 ":", ".", ":", ":", \ 4857 ":", ".", ":", ":", \ 4858 "+", ".", "+", ".", \ 4859 }, \ 4860 /* separator_chars */ \ 4861 { \ 4862 ":", ".", ":", ":", \ 4863 ":", ":", \ 4864 }, \ 4865 } 4866 4867 #define EMPTY_STYLE { \ 4868 /* border_chars */ \ 4869 { \ 4870 "\0", "\0", "\0", "\0", \ 4871 "\0", "\0", "\0", \ 4872 "\0", "\0", "\0", "\0", \ 4873 "\0", "\0", "\0", "\0", \ 4874 "\0", "\0", "\0", "\0", \ 4875 }, \ 4876 /* header_border_chars */ \ 4877 { \ 4878 "\0", "\0", "\0", "\0", \ 4879 "\0", "\0", "\0", \ 4880 "\0", "\0", "\0", "\0", \ 4881 "\0", "\0", "\0", "\0", \ 4882 "\0", "\0", "\0", "\0", \ 4883 }, \ 4884 /* separator_chars */ \ 4885 { \ 4886 "\0", " ", "\0 ", "\0", \ 4887 "\0", "\0", \ 4888 }, \ 4889 } 4890 4891 4892 #define EMPTY2_STYLE { \ 4893 /* border_chars */ \ 4894 { \ 4895 " ", " ", " ", " ", \ 4896 " ", " ", " ", \ 4897 "\0", "\0", "\0", "\0", \ 4898 " ", " ", " ", " ", \ 4899 " ", " ", " ", " ", \ 4900 }, \ 4901 /* header_border_chars */ \ 4902 { \ 4903 " ", " ", " ", " ", \ 4904 " ", " ", " ", \ 4905 "\0", "\0", "\0", "\0", \ 4906 " ", " ", " ", " ", \ 4907 " ", " ", " ", " ", \ 4908 }, \ 4909 /* separator_chars */ \ 4910 { \ 4911 " ", " ", " ", " ", \ 4912 " ", " ", \ 4913 }, \ 4914 } 4915 4916 #define SOLID_STYLE { \ 4917 /* border_chars */ \ 4918 { \ 4919 "┌", "─", "┬", "┐", \ 4920 "│", "│", "│", \ 4921 "", "", "", "", \ 4922 "└", "─", "┴", "┘", \ 4923 "│", "─", "│", "─", \ 4924 }, \ 4925 /* header_border_chars */ \ 4926 { \ 4927 "┌", "─", "┬", "┐", \ 4928 "│", "│", "│", \ 4929 "├", "─", "┼", "┤", \ 4930 "└", "─", "┴", "┘", \ 4931 "┼", "┬", "┼", "┴", \ 4932 }, \ 4933 /* separator_chars */ \ 4934 { \ 4935 "├", "─", "┼", "┤", \ 4936 "┬", "┴", \ 4937 }, \ 4938 } 4939 4940 #define SOLID_ROUND_STYLE { \ 4941 /* border_chars */ \ 4942 { \ 4943 "╭", "─", "┬", "╮", \ 4944 "│", "│", "│", \ 4945 "", "", "", "", \ 4946 "╰", "─", "┴", "╯", \ 4947 "│", "─", "│", "─", \ 4948 }, \ 4949 /* header_border_chars */ \ 4950 { \ 4951 "╭", "─", "┬", "╮", \ 4952 "│", "│", "│", \ 4953 "├", "─", "┼", "┤", \ 4954 "╰", "─", "┴", "╯", \ 4955 "┼", "┬", "┼", "┴", \ 4956 }, \ 4957 /* separator_chars */ \ 4958 { \ 4959 "├", "─", "┼", "┤", \ 4960 "┬", "┴", \ 4961 }, \ 4962 } 4963 4964 #define NICE_STYLE { \ 4965 /* border_chars */ \ 4966 { \ 4967 "╔", "═", "╦", "╗", \ 4968 "║", "║", "║", \ 4969 "", "", "", "", \ 4970 "╚", "═", "╩", "╝", \ 4971 "┣", "┻", "┣", "┳", \ 4972 }, \ 4973 /* header_border_chars */ \ 4974 { \ 4975 "╔", "═", "╦", "╗", \ 4976 "║", "║", "║", \ 4977 "╠", "═", "╬", "╣", \ 4978 "╚", "═", "╩", "╝", \ 4979 "┣", "╦", "┣", "╩", \ 4980 }, \ 4981 /* separator_chars */ \ 4982 { \ 4983 "╟", "─", "╫", "╢", \ 4984 "╥", "╨", \ 4985 }, \ 4986 } 4987 4988 #define DOUBLE_STYLE { \ 4989 /* border_chars */ \ 4990 { \ 4991 "╔", "═", "╦", "╗", \ 4992 "║", "║", "║", \ 4993 "", "", "", "", \ 4994 "╚", "═", "╩", "╝", \ 4995 "┣", "┻", "┣", "┳", \ 4996 }, \ 4997 /* header_border_chars */ \ 4998 { \ 4999 "╔", "═", "╦", "╗", \ 5000 "║", "║", "║", \ 5001 "╠", "═", "╬", "╣", \ 5002 "╚", "═", "╩", "╝", \ 5003 "┣", "╦", "┣", "╩", \ 5004 }, \ 5005 /* separator_chars */ \ 5006 { \ 5007 "╠", "═", "╬", "╣", \ 5008 "╦", "╩", \ 5009 }, \ 5010 } 5011 5012 5013 5014 5015 #define DOUBLE2_STYLE { \ 5016 /* border_chars */ \ 5017 { \ 5018 "╔", "═", "╤", "╗", \ 5019 "║", "│", "║", \ 5020 "╟", "─", "┼", "╢", \ 5021 "╚", "═", "╧", "╝", \ 5022 "├", "┬", "┤", "┴", \ 5023 }, \ 5024 /* header_border_chars */ \ 5025 { \ 5026 "╔", "═", "╤", "╗", \ 5027 "║", "│", "║", \ 5028 "╠", "═", "╪", "╣", \ 5029 "╚", "═", "╧", "╝", \ 5030 "├", "╤", "┤", "╧", \ 5031 }, \ 5032 /* separator_chars */ \ 5033 { \ 5034 "╠", "═", "╪", "╣", \ 5035 "╤", "╧", \ 5036 }, \ 5037 } 5038 5039 5040 #define BOLD_STYLE { \ 5041 /* border_chars */ \ 5042 { \ 5043 "┏", "━", "┳", "┓", \ 5044 "┃", "┃", "┃", \ 5045 "", "", "", "", \ 5046 "┗", "━", "┻", "┛", \ 5047 "┣", "┻", "┣", "┳", \ 5048 }, \ 5049 /* header_border_chars */ \ 5050 { \ 5051 "┏", "━", "┳", "┓", \ 5052 "┃", "┃", "┃", \ 5053 "┣", "━", "╋", "┫", \ 5054 "┗", "━", "┻", "┛", \ 5055 "┣", "┳", "┣", "┻", \ 5056 }, \ 5057 /* separator_chars */ \ 5058 { \ 5059 "┣", "━", "╋", "┫", \ 5060 "┳", "┻", \ 5061 }, \ 5062 } 5063 5064 #define BOLD2_STYLE { \ 5065 /* border_chars */ \ 5066 { \ 5067 "┏", "━", "┯", "┓", \ 5068 "┃", "│", "┃", \ 5069 "┠", "─", "┼", "┨", \ 5070 "┗", "━", "┷", "┛", \ 5071 "┣", "┬", "┣", "┴", \ 5072 }, \ 5073 /* header_border_chars */ \ 5074 { \ 5075 "┏", "━", "┯", "┓", \ 5076 "┃", "│", "┃", \ 5077 "┣", "━", "┿", "┫", \ 5078 "┗", "━", "┷", "┛", \ 5079 "┣", "┯", "┣", "┷", \ 5080 }, \ 5081 /* separator_chars */ \ 5082 { \ 5083 "┣", "━", "┿", "┫", \ 5084 "┯", "┷", \ 5085 }, \ 5086 } 5087 5088 #define FRAME_STYLE { \ 5089 /* border_chars */ \ 5090 { \ 5091 "▛", "▀", "▀", "▜", \ 5092 "▌", "┃", "▐", \ 5093 "", "", "", "", \ 5094 "▙", "▄", "▄", "▟", \ 5095 "┣", "━", "┣", "━" \ 5096 }, \ 5097 /* header_border_chars */ \ 5098 { \ 5099 "▛", "▀", "▀", "▜", \ 5100 "▌", "┃", "▐", \ 5101 "▌", "━", "╋", "▐", \ 5102 "▙", "▄", "▄", "▟", \ 5103 "┣", "━", "┣", "━", \ 5104 }, \ 5105 /* separator_chars */ \ 5106 { \ 5107 "▌", "━", "╋", "▐", \ 5108 "╋", "╋", \ 5109 }, \ 5110 } 5111 5112 5113 struct fort_border_style FORT_BASIC_STYLE = BASIC_STYLE; 5114 struct fort_border_style FORT_BASIC2_STYLE = BASIC2_STYLE; 5115 struct fort_border_style FORT_SIMPLE_STYLE = SIMPLE_STYLE; 5116 struct fort_border_style FORT_PLAIN_STYLE = PLAIN_STYLE; 5117 struct fort_border_style FORT_DOT_STYLE = DOT_STYLE; 5118 struct fort_border_style FORT_EMPTY_STYLE = EMPTY_STYLE; 5119 struct fort_border_style FORT_EMPTY2_STYLE = EMPTY2_STYLE; 5120 struct fort_border_style FORT_SOLID_STYLE = SOLID_STYLE; 5121 struct fort_border_style FORT_SOLID_ROUND_STYLE = SOLID_ROUND_STYLE; 5122 struct fort_border_style FORT_NICE_STYLE = NICE_STYLE; 5123 struct fort_border_style FORT_DOUBLE_STYLE = DOUBLE_STYLE; 5124 struct fort_border_style FORT_DOUBLE2_STYLE = DOUBLE2_STYLE; 5125 struct fort_border_style FORT_BOLD_STYLE = BOLD_STYLE; 5126 struct fort_border_style FORT_BOLD2_STYLE = BOLD2_STYLE; 5127 struct fort_border_style FORT_FRAME_STYLE = FRAME_STYLE; 5128 5129 5130 5131 fort_entire_table_properties_t g_entire_table_properties = { 5132 0, /* left_margin */ 5133 0, /* top_margin */ 5134 0, /* right_margin */ 5135 0, /* bottom_margin */ 5136 FT_STRATEGY_REPLACE, /* add_strategy */ 5137 }; 5138 5139 static f_status set_entire_table_property_internal(fort_entire_table_properties_t *properties, uint32_t property, int value) 5140 { 5141 assert(properties); 5142 CHECK_NOT_NEGATIVE(value); 5143 if (PROP_IS_SET(property, FT_TPROP_LEFT_MARGIN)) { 5144 properties->left_margin = value; 5145 } else if (PROP_IS_SET(property, FT_TPROP_TOP_MARGIN)) { 5146 properties->top_margin = value; 5147 } else if (PROP_IS_SET(property, FT_TPROP_RIGHT_MARGIN)) { 5148 properties->right_margin = value; 5149 } else if (PROP_IS_SET(property, FT_TPROP_BOTTOM_MARGIN)) { 5150 properties->bottom_margin = value; 5151 } else if (PROP_IS_SET(property, FT_TPROP_ADDING_STRATEGY)) { 5152 properties->add_strategy = (enum ft_adding_strategy)value; 5153 } else { 5154 return FT_EINVAL; 5155 } 5156 return FT_SUCCESS; 5157 5158 fort_fail: 5159 return FT_EINVAL; 5160 } 5161 5162 5163 FT_INTERNAL 5164 f_status set_entire_table_property(f_table_properties_t *table_properties, uint32_t property, int value) 5165 { 5166 assert(table_properties); 5167 return set_entire_table_property_internal(&table_properties->entire_table_properties, property, value); 5168 } 5169 5170 5171 FT_INTERNAL 5172 f_status set_default_entire_table_property(uint32_t property, int value) 5173 { 5174 return set_entire_table_property_internal(&g_entire_table_properties, property, value); 5175 } 5176 5177 5178 FT_INTERNAL 5179 size_t max_border_elem_strlen(struct f_table_properties *properties) 5180 { 5181 assert(properties); 5182 size_t result = 1; 5183 int i = 0; 5184 for (i = 0; i < BORDER_ITEM_POS_SIZE; ++i) { 5185 result = MAX(result, strlen(properties->border_style.border_chars[i])); 5186 } 5187 5188 for (i = 0; i < BORDER_ITEM_POS_SIZE; ++i) { 5189 result = MAX(result, strlen(properties->border_style.header_border_chars[i])); 5190 } 5191 5192 for (i = 0; i < SEPARATOR_ITEM_POS_SIZE; ++i) { 5193 result = MAX(result, strlen(properties->border_style.separator_chars[i])); 5194 } 5195 return result; 5196 } 5197 5198 5199 f_table_properties_t g_table_properties = { 5200 /* border_style */ 5201 BASIC_STYLE, 5202 NULL, /* cell_properties */ 5203 /* entire_table_properties */ 5204 { 5205 0, /* left_margin */ 5206 0, /* top_margin */ 5207 0, /* right_margin */ 5208 0, /* bottom_margin */ 5209 FT_STRATEGY_REPLACE, /* add_strategy */ 5210 } 5211 }; 5212 5213 5214 FT_INTERNAL 5215 f_table_properties_t *create_table_properties(void) 5216 { 5217 f_table_properties_t *properties = (f_table_properties_t *)F_CALLOC(sizeof(f_table_properties_t), 1); 5218 if (properties == NULL) { 5219 return NULL; 5220 } 5221 memcpy(properties, &g_table_properties, sizeof(f_table_properties_t)); 5222 properties->cell_properties = create_cell_prop_container(); 5223 if (properties->cell_properties == NULL) { 5224 destroy_table_properties(properties); 5225 return NULL; 5226 } 5227 memcpy(&properties->entire_table_properties, &g_entire_table_properties, sizeof(fort_entire_table_properties_t)); 5228 return properties; 5229 } 5230 5231 FT_INTERNAL 5232 void destroy_table_properties(f_table_properties_t *properties) 5233 { 5234 if (properties == NULL) 5235 return; 5236 5237 if (properties->cell_properties != NULL) { 5238 destroy_cell_prop_container(properties->cell_properties); 5239 } 5240 F_FREE(properties); 5241 } 5242 5243 static 5244 f_cell_prop_container_t *copy_cell_properties(f_cell_prop_container_t *cont) 5245 { 5246 f_cell_prop_container_t *result = create_cell_prop_container(); 5247 if (result == NULL) 5248 return NULL; 5249 5250 size_t i = 0; 5251 size_t sz = vector_size(cont); 5252 for (i = 0; i < sz; ++i) { 5253 f_cell_props_t *opt = (f_cell_props_t *)vector_at(cont, i); 5254 if (FT_IS_ERROR(vector_push(result, opt))) { 5255 destroy_cell_prop_container(result); 5256 return NULL; 5257 } 5258 } 5259 return result; 5260 } 5261 5262 FT_INTERNAL 5263 f_table_properties_t *copy_table_properties(const f_table_properties_t *properties) 5264 { 5265 f_table_properties_t *new_opt = create_table_properties(); 5266 if (new_opt == NULL) 5267 return NULL; 5268 5269 destroy_vector(new_opt->cell_properties); 5270 new_opt->cell_properties = copy_cell_properties(properties->cell_properties); 5271 if (new_opt->cell_properties == NULL) { 5272 destroy_table_properties(new_opt); 5273 return NULL; 5274 } 5275 5276 memcpy(&new_opt->border_style, &properties->border_style, sizeof(struct fort_border_style)); 5277 memcpy(&new_opt->entire_table_properties, 5278 &properties->entire_table_properties, sizeof(fort_entire_table_properties_t)); 5279 5280 return new_opt; 5281 } 5282 5283 /******************************************************** 5284 End of file "properties.c" 5285 ********************************************************/ 5286 5287 5288 /******************************************************** 5289 Begin of file "row.c" 5290 ********************************************************/ 5291 5292 #include <assert.h> 5293 #include <ctype.h> 5294 /* #include "row.h" */ /* Commented by amalgamation script */ 5295 /* #include "cell.h" */ /* Commented by amalgamation script */ 5296 /* #include "string_buffer.h" */ /* Commented by amalgamation script */ 5297 /* #include "vector.h" */ /* Commented by amalgamation script */ 5298 5299 5300 struct f_row { 5301 f_vector_t *cells; 5302 }; 5303 5304 static 5305 f_row_t *create_row_impl(f_vector_t *cells) 5306 { 5307 f_row_t *row = (f_row_t *)F_CALLOC(1, sizeof(f_row_t)); 5308 if (row == NULL) 5309 return NULL; 5310 if (cells) { 5311 row->cells = cells; 5312 } else { 5313 row->cells = create_vector(sizeof(f_cell_t *), DEFAULT_VECTOR_CAPACITY); 5314 if (row->cells == NULL) { 5315 F_FREE(row); 5316 return NULL; 5317 } 5318 } 5319 return row; 5320 } 5321 5322 FT_INTERNAL 5323 f_row_t *create_row(void) 5324 { 5325 return create_row_impl(NULL); 5326 } 5327 5328 static 5329 void destroy_each_cell(f_vector_t *cells) 5330 { 5331 size_t i = 0; 5332 size_t cells_n = vector_size(cells); 5333 for (i = 0; i < cells_n; ++i) { 5334 f_cell_t *cell = VECTOR_AT(cells, i, f_cell_t *); 5335 destroy_cell(cell); 5336 } 5337 } 5338 5339 FT_INTERNAL 5340 void destroy_row(f_row_t *row) 5341 { 5342 if (row == NULL) 5343 return; 5344 5345 if (row->cells) { 5346 destroy_each_cell(row->cells); 5347 destroy_vector(row->cells); 5348 } 5349 5350 F_FREE(row); 5351 } 5352 5353 FT_INTERNAL 5354 f_row_t *copy_row(f_row_t *row) 5355 { 5356 assert(row); 5357 f_row_t *result = create_row(); 5358 if (result == NULL) 5359 return NULL; 5360 5361 size_t i = 0; 5362 size_t cols_n = vector_size(row->cells); 5363 for (i = 0; i < cols_n; ++i) { 5364 f_cell_t *cell = VECTOR_AT(row->cells, i, f_cell_t *); 5365 f_cell_t *new_cell = copy_cell(cell); 5366 if (new_cell == NULL) { 5367 destroy_row(result); 5368 return NULL; 5369 } 5370 vector_push(result->cells, &new_cell); 5371 } 5372 5373 return result; 5374 } 5375 5376 FT_INTERNAL 5377 f_row_t *split_row(f_row_t *row, size_t pos) 5378 { 5379 assert(row); 5380 5381 f_vector_t *cells = vector_split(row->cells, pos); 5382 if (!cells) 5383 return NULL; 5384 f_row_t *tail = create_row_impl(cells); 5385 if (!tail) { 5386 destroy_each_cell(cells); 5387 destroy_vector(cells); 5388 } 5389 return tail; 5390 } 5391 5392 FT_INTERNAL 5393 int ft_row_erase_range(f_row_t *row, size_t left, size_t right) 5394 { 5395 assert(row); 5396 size_t cols_n = vector_size(row->cells); 5397 if (cols_n == 0 || (right < left)) 5398 return FT_SUCCESS; 5399 5400 f_cell_t *cell = NULL; 5401 size_t i = left; 5402 while (i < cols_n && i <= right) { 5403 cell = VECTOR_AT(row->cells, i, f_cell_t *); 5404 destroy_cell(cell); 5405 ++i; 5406 } 5407 size_t n_destroy = MIN(cols_n - 1, right) - left + 1; 5408 while (n_destroy--) { 5409 vector_erase(row->cells, left); 5410 } 5411 return FT_SUCCESS; 5412 } 5413 5414 FT_INTERNAL 5415 size_t columns_in_row(const f_row_t *row) 5416 { 5417 if (row == NULL || row->cells == NULL) 5418 return 0; 5419 5420 return vector_size(row->cells); 5421 } 5422 5423 5424 static 5425 f_cell_t *get_cell_impl(f_row_t *row, size_t col, enum f_get_policy policy) 5426 { 5427 if (row == NULL || row->cells == NULL) { 5428 return NULL; 5429 } 5430 5431 switch (policy) { 5432 case DONT_CREATE_ON_NULL: 5433 if (col < columns_in_row(row)) { 5434 return VECTOR_AT(row->cells, col, f_cell_t *); 5435 } 5436 return NULL; 5437 case CREATE_ON_NULL: 5438 while (col >= columns_in_row(row)) { 5439 f_cell_t *new_cell = create_cell(); 5440 if (new_cell == NULL) 5441 return NULL; 5442 if (FT_IS_ERROR(vector_push(row->cells, &new_cell))) { 5443 destroy_cell(new_cell); 5444 return NULL; 5445 } 5446 } 5447 return VECTOR_AT(row->cells, col, f_cell_t *); 5448 } 5449 5450 assert(0 && "Shouldn't be here!"); 5451 return NULL; 5452 } 5453 5454 5455 FT_INTERNAL 5456 f_cell_t *get_cell(f_row_t *row, size_t col) 5457 { 5458 return get_cell_impl(row, col, DONT_CREATE_ON_NULL); 5459 } 5460 5461 5462 FT_INTERNAL 5463 const f_cell_t *get_cell_c(const f_row_t *row, size_t col) 5464 { 5465 return get_cell((f_row_t *)row, col); 5466 } 5467 5468 5469 FT_INTERNAL 5470 f_cell_t *get_cell_and_create_if_not_exists(f_row_t *row, size_t col) 5471 { 5472 return get_cell_impl(row, col, CREATE_ON_NULL); 5473 } 5474 5475 FT_INTERNAL 5476 f_cell_t *create_cell_in_position(f_row_t *row, size_t col) 5477 { 5478 if (row == NULL || row->cells == NULL) { 5479 return NULL; 5480 } 5481 5482 f_cell_t *new_cell = create_cell(); 5483 if (new_cell == NULL) 5484 return NULL; 5485 if (FT_IS_ERROR(vector_insert(row->cells, &new_cell, col))) { 5486 destroy_cell(new_cell); 5487 return NULL; 5488 } 5489 return VECTOR_AT(row->cells, col, f_cell_t *); 5490 } 5491 5492 5493 FT_INTERNAL 5494 f_status swap_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos) 5495 { 5496 assert(cur_row); 5497 assert(ins_row); 5498 size_t cur_sz = vector_size(cur_row->cells); 5499 if (cur_sz == 0 && pos == 0) { 5500 f_row_t tmp; 5501 memcpy(&tmp, cur_row, sizeof(f_row_t)); 5502 memcpy(cur_row, ins_row, sizeof(f_row_t)); 5503 memcpy(ins_row, &tmp, sizeof(f_row_t)); 5504 return FT_SUCCESS; 5505 } 5506 5507 // Append empty cells to `cur_row` if needed. 5508 while (vector_size(cur_row->cells) < pos) { 5509 create_cell_in_position(cur_row, vector_size(cur_row->cells)); 5510 } 5511 5512 return vector_swap(cur_row->cells, ins_row->cells, pos); 5513 } 5514 5515 /* Ownership of cells of `ins_row` is passed to `cur_row`. */ 5516 FT_INTERNAL 5517 f_status insert_row(f_row_t *cur_row, f_row_t *ins_row, size_t pos) 5518 { 5519 assert(cur_row); 5520 assert(ins_row); 5521 5522 while (vector_size(cur_row->cells) < pos) { 5523 f_cell_t *new_cell = create_cell(); 5524 if (!new_cell) 5525 return FT_GEN_ERROR; 5526 vector_push(cur_row->cells, &new_cell); 5527 } 5528 5529 size_t sz = vector_size(ins_row->cells); 5530 size_t i = 0; 5531 for (i = 0; i < sz; ++i) { 5532 f_cell_t *cell = VECTOR_AT(ins_row->cells, i, f_cell_t *); 5533 if (FT_IS_ERROR(vector_insert(cur_row->cells, &cell, pos + i))) { 5534 /* clean up what we have inserted */ 5535 while (i--) { 5536 vector_erase(cur_row->cells, pos); 5537 } 5538 return FT_GEN_ERROR; 5539 } 5540 } 5541 /* Clear cells so that it will be safe to destroy this row */ 5542 vector_clear(ins_row->cells); 5543 return FT_SUCCESS; 5544 } 5545 5546 5547 FT_INTERNAL 5548 size_t group_cell_number(const f_row_t *row, size_t master_cell_col) 5549 { 5550 assert(row); 5551 const f_cell_t *master_cell = get_cell_c(row, master_cell_col); 5552 if (master_cell == NULL) 5553 return 0; 5554 5555 if (get_cell_type(master_cell) != GROUP_MASTER_CELL) 5556 return 1; 5557 5558 size_t total_cols = vector_size(row->cells); 5559 size_t slave_col = master_cell_col + 1; 5560 while (slave_col < total_cols) { 5561 const f_cell_t *cell = get_cell_c(row, slave_col); 5562 if (cell && get_cell_type(cell) == GROUP_SLAVE_CELL) { 5563 ++slave_col; 5564 } else { 5565 break; 5566 } 5567 } 5568 return slave_col - master_cell_col; 5569 } 5570 5571 5572 FT_INTERNAL 5573 int get_row_cell_types(const f_row_t *row, enum f_cell_type *types, size_t types_sz) 5574 { 5575 assert(row); 5576 assert(types); 5577 size_t i = 0; 5578 for (i = 0; i < types_sz; ++i) { 5579 const f_cell_t *cell = get_cell_c(row, i); 5580 if (cell) { 5581 types[i] = get_cell_type(cell); 5582 } else { 5583 types[i] = COMMON_CELL; 5584 } 5585 } 5586 return FT_SUCCESS; 5587 } 5588 5589 5590 FT_INTERNAL 5591 f_status row_set_cell_span(f_row_t *row, size_t cell_column, size_t hor_span) 5592 { 5593 assert(row); 5594 5595 if (hor_span < 2) 5596 return FT_EINVAL; 5597 5598 f_cell_t *main_cell = get_cell_and_create_if_not_exists(row, cell_column); 5599 if (main_cell == NULL) { 5600 return FT_GEN_ERROR; 5601 } 5602 set_cell_type(main_cell, GROUP_MASTER_CELL); 5603 --hor_span; 5604 ++cell_column; 5605 5606 while (hor_span) { 5607 f_cell_t *slave_cell = get_cell_and_create_if_not_exists(row, cell_column); 5608 if (slave_cell == NULL) { 5609 return FT_GEN_ERROR; 5610 } 5611 set_cell_type(slave_cell, GROUP_SLAVE_CELL); 5612 --hor_span; 5613 ++cell_column; 5614 } 5615 5616 return FT_SUCCESS; 5617 } 5618 5619 static 5620 int print_row_separator_impl(f_conv_context_t *cntx, 5621 const size_t *col_width_arr, size_t cols, 5622 const f_row_t *upper_row, const f_row_t *lower_row, 5623 enum f_hor_separator_pos separatorPos, 5624 const f_separator_t *sep) 5625 { 5626 assert(cntx); 5627 5628 int status = FT_GEN_ERROR; 5629 5630 const f_context_t *context = cntx->cntx; 5631 5632 /* Get cell types 5633 * 5634 * Regions above top row and below bottom row areconsidered full of virtual 5635 * GROUP_SLAVE_CELL cells 5636 */ 5637 enum f_cell_type *top_row_types = (enum f_cell_type *)F_MALLOC(sizeof(enum f_cell_type) * cols * 2); 5638 if (top_row_types == NULL) { 5639 return FT_MEMORY_ERROR; 5640 } 5641 enum f_cell_type *bottom_row_types = top_row_types + cols; 5642 if (upper_row) { 5643 get_row_cell_types(upper_row, top_row_types, cols); 5644 } else { 5645 size_t i = 0; 5646 for (i = 0; i < cols; ++i) 5647 top_row_types[i] = GROUP_SLAVE_CELL; 5648 } 5649 if (lower_row) { 5650 get_row_cell_types(lower_row, bottom_row_types, cols); 5651 } else { 5652 size_t i = 0; 5653 for (i = 0; i < cols; ++i) 5654 bottom_row_types[i] = GROUP_SLAVE_CELL; 5655 } 5656 5657 5658 f_table_properties_t *properties = context->table_properties; 5659 fort_entire_table_properties_t *entire_tprops = &properties->entire_table_properties; 5660 5661 size_t written = 0; 5662 int tmp = 0; 5663 5664 enum ft_row_type lower_row_type = FT_ROW_COMMON; 5665 if (lower_row != NULL) { 5666 lower_row_type = (enum ft_row_type)get_cell_property_hierarchically(properties, context->row, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE); 5667 } 5668 enum ft_row_type upper_row_type = FT_ROW_COMMON; 5669 if (upper_row != NULL) { 5670 upper_row_type = (enum ft_row_type)get_cell_property_hierarchically(properties, context->row - 1, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE); 5671 } 5672 5673 /* Row separator anatomy 5674 * 5675 * | C11 | C12 C13 | C14 C15 | 5676 * L I I I IV I I IT I I I IB I I II I I R 5677 * | C21 | C22 | C23 C24 C25 | 5678 */ 5679 const char **L = NULL; 5680 const char **I = NULL; 5681 const char **IV = NULL; 5682 const char **R = NULL; 5683 const char **IT = NULL; 5684 const char **IB = NULL; 5685 const char **II = NULL; 5686 5687 struct fort_border_style *border_style = &properties->border_style; 5688 5689 typedef const char *(*border_chars_point_t)[BORDER_ITEM_POS_SIZE]; 5690 const char *(*border_chars)[BORDER_ITEM_POS_SIZE] = NULL; 5691 border_chars = (border_chars_point_t)&border_style->border_chars; 5692 if (upper_row_type == FT_ROW_HEADER || lower_row_type == FT_ROW_HEADER) { 5693 border_chars = (border_chars_point_t)&border_style->header_border_chars; 5694 } 5695 5696 if (sep && sep->enabled) { 5697 L = &(border_style->separator_chars[LH_sip]); 5698 I = &(border_style->separator_chars[IH_sip]); 5699 IV = &(border_style->separator_chars[II_sip]); 5700 R = &(border_style->separator_chars[RH_sip]); 5701 5702 IT = &(border_style->separator_chars[TI_sip]); 5703 IB = &(border_style->separator_chars[BI_sip]); 5704 II = &(border_style->separator_chars[IH_sip]); 5705 5706 if (lower_row == NULL) { 5707 L = &(*border_chars)[BL_bip]; 5708 R = &(*border_chars)[BR_bip]; 5709 } else if (upper_row == NULL) { 5710 L = &(*border_chars)[TL_bip]; 5711 R = &(*border_chars)[TR_bip]; 5712 } 5713 } else { 5714 switch (separatorPos) { 5715 case TOP_SEPARATOR: 5716 L = &(*border_chars)[TL_bip]; 5717 I = &(*border_chars)[TT_bip]; 5718 IV = &(*border_chars)[TV_bip]; 5719 R = &(*border_chars)[TR_bip]; 5720 5721 IT = &(*border_chars)[TV_bip]; 5722 IB = &(*border_chars)[TV_bip]; 5723 II = &(*border_chars)[TT_bip]; 5724 break; 5725 case INSIDE_SEPARATOR: 5726 L = &(*border_chars)[LH_bip]; 5727 I = &(*border_chars)[IH_bip]; 5728 IV = &(*border_chars)[II_bip]; 5729 R = &(*border_chars)[RH_bip]; 5730 5731 IT = &(*border_chars)[TI_bip]; 5732 IB = &(*border_chars)[BI_bip]; 5733 II = &(*border_chars)[IH_bip]; 5734 break; 5735 case BOTTOM_SEPARATOR: 5736 L = &(*border_chars)[BL_bip]; 5737 I = &(*border_chars)[BB_bip]; 5738 IV = &(*border_chars)[BV_bip]; 5739 R = &(*border_chars)[BR_bip]; 5740 5741 IT = &(*border_chars)[BV_bip]; 5742 IB = &(*border_chars)[BV_bip]; 5743 II = &(*border_chars)[BB_bip]; 5744 break; 5745 default: 5746 break; 5747 } 5748 } 5749 5750 size_t i = 0; 5751 5752 /* If all chars are not printable, skip line separator */ 5753 /* NOTE: argument of `isprint` should be explicitly converted to 5754 * unsigned char according to 5755 * https://en.cppreference.com/w/c/string/byte/isprint 5756 */ 5757 if ((strlen(*L) == 0 || (strlen(*L) == 1 && !isprint((unsigned char) **L))) 5758 && (strlen(*I) == 0 || (strlen(*I) == 1 && !isprint((unsigned char) **I))) 5759 && (strlen(*IV) == 0 || (strlen(*IV) == 1 && !isprint((unsigned char) **IV))) 5760 && (strlen(*R) == 0 || (strlen(*R) == 1 && !isprint((unsigned char) **R)))) { 5761 status = 0; 5762 goto clear; 5763 } 5764 5765 /* Print left margin */ 5766 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, entire_tprops->left_margin, FT_SPACE)); 5767 5768 for (i = 0; i < cols; ++i) { 5769 if (i == 0) { 5770 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *L)); 5771 } else { 5772 if ((top_row_types[i] == COMMON_CELL || top_row_types[i] == GROUP_MASTER_CELL) 5773 && (bottom_row_types[i] == COMMON_CELL || bottom_row_types[i] == GROUP_MASTER_CELL)) { 5774 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *IV)); 5775 } else if (top_row_types[i] == GROUP_SLAVE_CELL && bottom_row_types[i] == GROUP_SLAVE_CELL) { 5776 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *II)); 5777 } else if (top_row_types[i] == GROUP_SLAVE_CELL) { 5778 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *IT)); 5779 } else { 5780 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *IB)); 5781 } 5782 } 5783 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, col_width_arr[i], *I)); 5784 } 5785 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *R)); 5786 5787 /* Print right margin */ 5788 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, entire_tprops->right_margin, FT_SPACE)); 5789 5790 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, FT_NEWLINE)); 5791 5792 status = (int)written; 5793 5794 clear: 5795 F_FREE(top_row_types); 5796 return status; 5797 } 5798 5799 FT_INTERNAL 5800 int print_row_separator(f_conv_context_t *cntx, 5801 const size_t *col_width_arr, size_t cols, 5802 const f_row_t *upper_row, const f_row_t *lower_row, 5803 enum f_hor_separator_pos separatorPos, const f_separator_t *sep) 5804 { 5805 return print_row_separator_impl(cntx, col_width_arr, cols, upper_row, lower_row, 5806 separatorPos, sep); 5807 } 5808 5809 FT_INTERNAL 5810 f_row_t *create_row_from_string(const char *str) 5811 { 5812 typedef char char_type; 5813 char_type *(*strdup_)(const char_type * str) = F_STRDUP; 5814 const char_type zero_char = '\0'; 5815 f_status(*fill_cell_from_string_)(f_cell_t *cell, const char *str) = fill_cell_from_string; 5816 const char_type *const zero_string = ""; 5817 #define STRCHR strchr 5818 5819 char_type *pos = NULL; 5820 char_type *base_pos = NULL; 5821 size_t number_of_separators = 0; 5822 5823 f_row_t *row = create_row(); 5824 if (row == NULL) 5825 return NULL; 5826 5827 if (str == NULL) 5828 return row; 5829 5830 char_type *str_copy = strdup_(str); 5831 if (str_copy == NULL) 5832 goto clear; 5833 5834 pos = str_copy; 5835 base_pos = str_copy; 5836 number_of_separators = 0; 5837 while (*pos) { 5838 pos = STRCHR(pos, g_col_separator); 5839 if (pos != NULL) { 5840 *(pos) = zero_char; 5841 ++pos; 5842 number_of_separators++; 5843 } 5844 5845 f_cell_t *cell = create_cell(); 5846 if (cell == NULL) 5847 goto clear; 5848 5849 int status = fill_cell_from_string_(cell, base_pos); 5850 if (FT_IS_ERROR(status)) { 5851 destroy_cell(cell); 5852 goto clear; 5853 } 5854 5855 status = vector_push(row->cells, &cell); 5856 if (FT_IS_ERROR(status)) { 5857 destroy_cell(cell); 5858 goto clear; 5859 } 5860 5861 if (pos == NULL) 5862 break; 5863 base_pos = pos; 5864 } 5865 5866 /* special case if in format string last cell is empty */ 5867 while (vector_size(row->cells) < (number_of_separators + 1)) { 5868 f_cell_t *cell = create_cell(); 5869 if (cell == NULL) 5870 goto clear; 5871 5872 int status = fill_cell_from_string_(cell, zero_string); 5873 if (FT_IS_ERROR(status)) { 5874 destroy_cell(cell); 5875 goto clear; 5876 } 5877 5878 status = vector_push(row->cells, &cell); 5879 if (FT_IS_ERROR(status)) { 5880 destroy_cell(cell); 5881 goto clear; 5882 } 5883 } 5884 5885 F_FREE(str_copy); 5886 return row; 5887 5888 clear: 5889 destroy_row(row); 5890 F_FREE(str_copy); 5891 return NULL; 5892 5893 #undef STRCHR 5894 } 5895 5896 5897 #ifdef FT_HAVE_WCHAR 5898 FT_INTERNAL 5899 f_row_t *create_row_from_wstring(const wchar_t *str) 5900 { 5901 typedef wchar_t char_type; 5902 char_type *(*strdup_)(const char_type * str) = F_WCSDUP; 5903 const char_type zero_char = L'\0'; 5904 f_status(*fill_cell_from_string_)(f_cell_t *cell, const wchar_t *str) = fill_cell_from_wstring; 5905 const char_type *const zero_string = L""; 5906 #define STRCHR wcschr 5907 5908 char_type *pos = NULL; 5909 char_type *base_pos = NULL; 5910 size_t number_of_separators = 0; 5911 5912 f_row_t *row = create_row(); 5913 if (row == NULL) 5914 return NULL; 5915 5916 if (str == NULL) 5917 return row; 5918 5919 char_type *str_copy = strdup_(str); 5920 if (str_copy == NULL) 5921 goto clear; 5922 5923 pos = str_copy; 5924 base_pos = str_copy; 5925 number_of_separators = 0; 5926 while (*pos) { 5927 pos = STRCHR(pos, g_col_separator); 5928 if (pos != NULL) { 5929 *(pos) = zero_char; 5930 ++pos; 5931 number_of_separators++; 5932 } 5933 5934 f_cell_t *cell = create_cell(); 5935 if (cell == NULL) 5936 goto clear; 5937 5938 int status = fill_cell_from_string_(cell, base_pos); 5939 if (FT_IS_ERROR(status)) { 5940 destroy_cell(cell); 5941 goto clear; 5942 } 5943 5944 status = vector_push(row->cells, &cell); 5945 if (FT_IS_ERROR(status)) { 5946 destroy_cell(cell); 5947 goto clear; 5948 } 5949 5950 if (pos == NULL) 5951 break; 5952 base_pos = pos; 5953 } 5954 5955 /* special case if in format string last cell is empty */ 5956 while (vector_size(row->cells) < (number_of_separators + 1)) { 5957 f_cell_t *cell = create_cell(); 5958 if (cell == NULL) 5959 goto clear; 5960 5961 int status = fill_cell_from_string_(cell, zero_string); 5962 if (FT_IS_ERROR(status)) { 5963 destroy_cell(cell); 5964 goto clear; 5965 } 5966 5967 status = vector_push(row->cells, &cell); 5968 if (FT_IS_ERROR(status)) { 5969 destroy_cell(cell); 5970 goto clear; 5971 } 5972 } 5973 5974 F_FREE(str_copy); 5975 return row; 5976 5977 clear: 5978 destroy_row(row); 5979 F_FREE(str_copy); 5980 return NULL; 5981 #undef STRCHR 5982 } 5983 #endif 5984 5985 FT_INTERNAL 5986 f_row_t *create_row_from_buffer(const f_string_buffer_t *buffer) 5987 { 5988 switch (buffer->type) { 5989 case CHAR_BUF: 5990 return create_row_from_string(buffer->str.cstr); 5991 #ifdef FT_HAVE_WCHAR 5992 case W_CHAR_BUF: 5993 return create_row_from_wstring(buffer->str.wstr); 5994 #endif /* FT_HAVE_WCHAR */ 5995 #ifdef FT_HAVE_UTF8 5996 case UTF8_BUF: 5997 return create_row_from_string((const char *)buffer->str.u8str); 5998 #endif /* FT_HAVE_UTF8 */ 5999 default: 6000 assert(0); 6001 return NULL; 6002 } 6003 } 6004 6005 static int 6006 vsnprintf_buffer(f_string_buffer_t *buffer, const struct f_string_view *fmt, 6007 va_list *va) 6008 { 6009 /* Disable compiler diagnostic (format string is not a string literal) */ 6010 #if defined(FT_CLANG_COMPILER) 6011 #pragma clang diagnostic push 6012 #pragma clang diagnostic ignored "-Wformat-nonliteral" 6013 #endif 6014 #if defined(FT_GCC_COMPILER) 6015 #pragma GCC diagnostic push 6016 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 6017 #endif 6018 size_t width_capacity = string_buffer_width_capacity(buffer); 6019 switch (buffer->type) { 6020 case CHAR_BUF: 6021 return vsnprintf(buffer->str.cstr, width_capacity, fmt->u.cstr, *va); 6022 #ifdef FT_HAVE_WCHAR 6023 case W_CHAR_BUF: 6024 return vswprintf(buffer->str.wstr, width_capacity, fmt->u.wstr, *va); 6025 #endif 6026 #ifdef FT_HAVE_UTF8 6027 case UTF8_BUF: 6028 return vsnprintf(buffer->str.cstr, width_capacity, fmt->u.cstr, *va); 6029 #endif 6030 default: 6031 assert(0); 6032 return 0; 6033 } 6034 #if defined(FT_CLANG_COMPILER) 6035 #pragma clang diagnostic pop 6036 #endif 6037 #if defined(FT_GCC_COMPILER) 6038 #pragma GCC diagnostic pop 6039 #endif 6040 } 6041 6042 FT_INTERNAL 6043 f_row_t *create_row_from_fmt_string(const struct f_string_view *fmt, va_list *va_args) 6044 { 6045 f_string_buffer_t *buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, fmt->type); 6046 if (buffer == NULL) 6047 return NULL; 6048 6049 size_t cols_origin = number_of_columns_in_format_string(fmt); 6050 size_t cols = 0; 6051 6052 while (1) { 6053 va_list va; 6054 va_copy(va, *va_args); 6055 int virtual_sz = vsnprintf_buffer(buffer, fmt, &va); 6056 va_end(va); 6057 /* If error encountered */ 6058 if (virtual_sz < 0) 6059 goto clear; 6060 6061 /* Successful write */ 6062 if ((size_t)virtual_sz < string_buffer_width_capacity(buffer)) 6063 break; 6064 6065 /* Otherwise buffer was too small, so incr. buffer size ant try again. */ 6066 if (!FT_IS_SUCCESS(realloc_string_buffer_without_copy(buffer))) 6067 goto clear; 6068 } 6069 6070 cols = number_of_columns_in_format_buffer(buffer); 6071 if (cols == cols_origin) { 6072 f_row_t *row = create_row_from_buffer(buffer); 6073 if (row == NULL) { 6074 goto clear; 6075 } 6076 6077 destroy_string_buffer(buffer); 6078 return row; 6079 } 6080 6081 if (cols_origin == 1) { 6082 f_row_t *row = create_row(); 6083 if (row == NULL) { 6084 goto clear; 6085 } 6086 6087 f_cell_t *cell = get_cell_and_create_if_not_exists(row, 0); 6088 if (cell == NULL) { 6089 destroy_row(row); 6090 goto clear; 6091 } 6092 6093 f_status result = fill_cell_from_buffer(cell, buffer); 6094 if (FT_IS_ERROR(result)) { 6095 destroy_row(row); 6096 goto clear; 6097 } 6098 6099 destroy_string_buffer(buffer); 6100 return row; 6101 } 6102 6103 /* 6104 * todo: add processing of cols != cols_origin in a general way 6105 * (when cols_origin != 1). 6106 */ 6107 6108 clear: 6109 destroy_string_buffer(buffer); 6110 return NULL; 6111 } 6112 6113 6114 FT_INTERNAL 6115 int snprintf_row(const f_row_t *row, f_conv_context_t *cntx, size_t *col_width_arr, size_t col_width_arr_sz, 6116 size_t row_height) 6117 { 6118 const f_context_t *context = cntx->cntx; 6119 assert(context); 6120 6121 if (row == NULL) 6122 return -1; 6123 6124 size_t cols_in_row = columns_in_row(row); 6125 if (cols_in_row > col_width_arr_sz) 6126 return -1; 6127 6128 /* Row separator anatomy 6129 * 6130 * L data IV data IV data R 6131 */ 6132 f_table_properties_t *properties = context->table_properties; 6133 6134 typedef const char *(*border_chars_point_t)[BORDER_ITEM_POS_SIZE]; 6135 enum ft_row_type row_type = (enum ft_row_type)get_cell_property_hierarchically(properties, context->row, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE); 6136 const char *(*bord_chars)[BORDER_ITEM_POS_SIZE] = (row_type == FT_ROW_HEADER) 6137 ? (border_chars_point_t)(&properties->border_style.header_border_chars) 6138 : (border_chars_point_t)(&properties->border_style.border_chars); 6139 const char **L = &(*bord_chars)[LL_bip]; 6140 const char **IV = &(*bord_chars)[IV_bip]; 6141 const char **R = &(*bord_chars)[RR_bip]; 6142 6143 6144 size_t written = 0; 6145 int tmp = 0; 6146 size_t i = 0; 6147 fort_entire_table_properties_t *entire_tprops = &context->table_properties->entire_table_properties; 6148 for (i = 0; i < row_height; ++i) { 6149 /* Print left margin */ 6150 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, entire_tprops->left_margin, FT_SPACE)); 6151 6152 /* Print left table boundary */ 6153 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *L)); 6154 size_t j = 0; 6155 while (j < col_width_arr_sz) { 6156 if (j < cols_in_row) { 6157 ((f_context_t *)context)->column = j; 6158 f_cell_t *cell = VECTOR_AT(row->cells, j, f_cell_t *); 6159 size_t cell_vis_width = 0; 6160 6161 size_t group_slave_sz = group_cell_number(row, j); 6162 cell_vis_width = col_width_arr[j]; 6163 size_t slave_j = 0; 6164 size_t master_j = j; 6165 for (slave_j = master_j + 1; slave_j < (master_j + group_slave_sz); ++slave_j) { 6166 cell_vis_width += col_width_arr[slave_j] + FORT_COL_SEPARATOR_LENGTH; 6167 ++j; 6168 } 6169 6170 CHCK_RSLT_ADD_TO_WRITTEN(cell_printf(cell, i, cntx, cell_vis_width)); 6171 } else { 6172 /* Print empty cell */ 6173 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, col_width_arr[j], FT_SPACE)); 6174 } 6175 6176 /* Print boundary between cells */ 6177 if (j < col_width_arr_sz - 1) 6178 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *IV)); 6179 6180 ++j; 6181 } 6182 6183 /* Print right table boundary */ 6184 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, *R)); 6185 6186 /* Print right margin */ 6187 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, entire_tprops->right_margin, FT_SPACE)); 6188 6189 /* Print new line character */ 6190 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, FT_NEWLINE)); 6191 } 6192 return (int)written; 6193 6194 clear: 6195 return -1; 6196 } 6197 6198 /******************************************************** 6199 End of file "row.c" 6200 ********************************************************/ 6201 6202 6203 /******************************************************** 6204 Begin of file "string_buffer.c" 6205 ********************************************************/ 6206 6207 /* #include "string_buffer.h" */ /* Commented by amalgamation script */ 6208 /* #include "properties.h" */ /* Commented by amalgamation script */ 6209 /* #include "wcwidth.h" */ /* Commented by amalgamation script */ 6210 #include <assert.h> 6211 #include <stddef.h> 6212 #ifdef FT_HAVE_WCHAR 6213 #include <wchar.h> 6214 #endif 6215 #if defined(FT_HAVE_UTF8) 6216 /* #include "utf8.h" */ /* Commented by amalgamation script */ 6217 #endif 6218 6219 static ptrdiff_t str_iter_width(const char *beg, const char *end) 6220 { 6221 assert(end >= beg); 6222 return (end - beg); 6223 } 6224 6225 6226 #ifdef FT_HAVE_WCHAR 6227 static ptrdiff_t wcs_iter_width(const wchar_t *beg, const wchar_t *end) 6228 { 6229 assert(end >= beg); 6230 return mk_wcswidth(beg, (size_t)(end - beg)); 6231 } 6232 #endif /* FT_HAVE_WCHAR */ 6233 6234 6235 static size_t buf_str_len(const f_string_buffer_t *buf) 6236 { 6237 assert(buf); 6238 6239 switch (buf->type) { 6240 case CHAR_BUF: 6241 return strlen(buf->str.cstr); 6242 #ifdef FT_HAVE_WCHAR 6243 case W_CHAR_BUF: 6244 return wcslen(buf->str.wstr); 6245 #endif 6246 #ifdef FT_HAVE_UTF8 6247 case UTF8_BUF: 6248 return utf8len(buf->str.u8str); 6249 #endif 6250 } 6251 6252 assert(0); 6253 return 0; 6254 } 6255 6256 6257 FT_INTERNAL 6258 size_t strchr_count(const char *str, char ch) 6259 { 6260 if (str == NULL) 6261 return 0; 6262 6263 size_t count = 0; 6264 str = strchr(str, ch); 6265 while (str) { 6266 count++; 6267 str++; 6268 str = strchr(str, ch); 6269 } 6270 return count; 6271 } 6272 6273 #ifdef FT_HAVE_WCHAR 6274 FT_INTERNAL 6275 size_t wstrchr_count(const wchar_t *str, wchar_t ch) 6276 { 6277 if (str == NULL) 6278 return 0; 6279 6280 size_t count = 0; 6281 str = wcschr(str, ch); 6282 while (str) { 6283 count++; 6284 str++; 6285 str = wcschr(str, ch); 6286 } 6287 return count; 6288 } 6289 #endif 6290 6291 6292 #if defined(FT_HAVE_UTF8) 6293 /* todo: do something with code below!!! */ 6294 FT_INTERNAL 6295 void *ut8next(const void *str) 6296 { 6297 utf8_int32_t out_codepoint; 6298 return utf8codepoint(str, &out_codepoint); 6299 } 6300 6301 FT_INTERNAL 6302 size_t utf8chr_count(const void *str, utf8_int32_t ch) 6303 { 6304 if (str == NULL) 6305 return 0; 6306 6307 size_t count = 0; 6308 str = utf8chr(str, ch); 6309 while (str) { 6310 count++; 6311 str = ut8next(str); 6312 str = utf8chr(str, ch); 6313 } 6314 return count; 6315 } 6316 #endif /* FT_HAVE_UTF8 */ 6317 6318 6319 FT_INTERNAL 6320 const char *str_n_substring_beg(const char *str, char ch_separator, size_t n) 6321 { 6322 if (str == NULL) 6323 return NULL; 6324 6325 if (n == 0) 6326 return str; 6327 6328 str = strchr(str, ch_separator); 6329 --n; 6330 while (n > 0) { 6331 if (str == NULL) 6332 return NULL; 6333 --n; 6334 str++; 6335 str = strchr(str, ch_separator); 6336 } 6337 return str ? (str + 1) : NULL; 6338 } 6339 6340 6341 #ifdef FT_HAVE_WCHAR 6342 FT_INTERNAL 6343 const wchar_t *wstr_n_substring_beg(const wchar_t *str, wchar_t ch_separator, size_t n) 6344 { 6345 if (str == NULL) 6346 return NULL; 6347 6348 if (n == 0) 6349 return str; 6350 6351 str = wcschr(str, ch_separator); 6352 --n; 6353 while (n > 0) { 6354 if (str == NULL) 6355 return NULL; 6356 --n; 6357 str++; 6358 str = wcschr(str, ch_separator); 6359 } 6360 return str ? (str + 1) : NULL; 6361 } 6362 #endif /* FT_HAVE_WCHAR */ 6363 6364 #if defined(FT_HAVE_UTF8) 6365 FT_INTERNAL 6366 const void *utf8_n_substring_beg(const void *str, utf8_int32_t ch_separator, size_t n) 6367 { 6368 if (str == NULL) 6369 return NULL; 6370 6371 if (n == 0) 6372 return str; 6373 6374 str = utf8chr(str, ch_separator); 6375 --n; 6376 while (n > 0) { 6377 if (str == NULL) 6378 return NULL; 6379 --n; 6380 str = ut8next(str); 6381 str = utf8chr(str, ch_separator); 6382 } 6383 return str ? (ut8next(str)) : NULL; 6384 } 6385 #endif 6386 6387 6388 FT_INTERNAL 6389 void str_n_substring(const char *str, char ch_separator, size_t n, const char **begin, const char **end) 6390 { 6391 const char *beg = str_n_substring_beg(str, ch_separator, n); 6392 if (beg == NULL) { 6393 *begin = NULL; 6394 *end = NULL; 6395 return; 6396 } 6397 6398 const char *en = strchr(beg, ch_separator); 6399 if (en == NULL) { 6400 en = str + strlen(str); 6401 } 6402 6403 *begin = beg; 6404 *end = en; 6405 return; 6406 } 6407 6408 6409 #ifdef FT_HAVE_WCHAR 6410 FT_INTERNAL 6411 void wstr_n_substring(const wchar_t *str, wchar_t ch_separator, size_t n, const wchar_t **begin, const wchar_t **end) 6412 { 6413 const wchar_t *beg = wstr_n_substring_beg(str, ch_separator, n); 6414 if (beg == NULL) { 6415 *begin = NULL; 6416 *end = NULL; 6417 return; 6418 } 6419 6420 const wchar_t *en = wcschr(beg, ch_separator); 6421 if (en == NULL) { 6422 en = str + wcslen(str); 6423 } 6424 6425 *begin = beg; 6426 *end = en; 6427 return; 6428 } 6429 #endif /* FT_HAVE_WCHAR */ 6430 6431 #if defined(FT_HAVE_UTF8) 6432 FT_INTERNAL 6433 void utf8_n_substring(const void *str, utf8_int32_t ch_separator, size_t n, const void **begin, const void **end) 6434 { 6435 const char *beg = (const char *)utf8_n_substring_beg(str, ch_separator, n); 6436 if (beg == NULL) { 6437 *begin = NULL; 6438 *end = NULL; 6439 return; 6440 } 6441 6442 const char *en = (const char *)utf8chr(beg, ch_separator); 6443 if (en == NULL) { 6444 en = (const char *)str + strlen((const char *)str); 6445 } 6446 6447 *begin = beg; 6448 *end = en; 6449 return; 6450 } 6451 #endif /* FT_HAVE_UTF8 */ 6452 6453 6454 6455 FT_INTERNAL 6456 f_string_buffer_t *create_string_buffer(size_t n_chars, enum f_string_type type) 6457 { 6458 size_t char_sz = 0; 6459 switch (type) { 6460 case CHAR_BUF: 6461 char_sz = 1; 6462 break; 6463 #ifdef FT_HAVE_WCHAR 6464 case W_CHAR_BUF: 6465 char_sz = sizeof(wchar_t); 6466 break; 6467 #endif 6468 #ifdef FT_HAVE_UTF8 6469 case UTF8_BUF: 6470 char_sz = 4; 6471 break; 6472 #endif 6473 } 6474 6475 size_t sz = n_chars * char_sz; 6476 f_string_buffer_t *result = (f_string_buffer_t *)F_MALLOC(sizeof(f_string_buffer_t)); 6477 if (result == NULL) 6478 return NULL; 6479 result->str.data = F_MALLOC(sz); 6480 if (result->str.data == NULL) { 6481 F_FREE(result); 6482 return NULL; 6483 } 6484 result->data_sz = sz; 6485 result->type = type; 6486 6487 if (sz) { 6488 switch (type) { 6489 case CHAR_BUF: 6490 result->str.cstr[0] = '\0'; 6491 break; 6492 #ifdef FT_HAVE_WCHAR 6493 case W_CHAR_BUF: 6494 result->str.wstr[0] = L'\0'; 6495 break; 6496 #endif 6497 #ifdef FT_HAVE_UTF8 6498 case UTF8_BUF: 6499 result->str.cstr[0] = '\0'; 6500 break; 6501 #endif 6502 } 6503 } 6504 6505 return result; 6506 } 6507 6508 6509 FT_INTERNAL 6510 void destroy_string_buffer(f_string_buffer_t *buffer) 6511 { 6512 if (buffer == NULL) 6513 return; 6514 F_FREE(buffer->str.data); 6515 buffer->str.data = NULL; 6516 F_FREE(buffer); 6517 } 6518 6519 FT_INTERNAL 6520 f_string_buffer_t *copy_string_buffer(const f_string_buffer_t *buffer) 6521 { 6522 assert(buffer); 6523 f_string_buffer_t *result = create_string_buffer(buffer->data_sz, buffer->type); 6524 if (result == NULL) 6525 return NULL; 6526 switch (buffer->type) { 6527 case CHAR_BUF: 6528 if (FT_IS_ERROR(fill_buffer_from_string(result, buffer->str.cstr))) { 6529 destroy_string_buffer(result); 6530 return NULL; 6531 } 6532 break; 6533 #ifdef FT_HAVE_WCHAR 6534 case W_CHAR_BUF: 6535 if (FT_IS_ERROR(fill_buffer_from_wstring(result, buffer->str.wstr))) { 6536 destroy_string_buffer(result); 6537 return NULL; 6538 } 6539 break; 6540 #endif /* FT_HAVE_WCHAR */ 6541 default: 6542 destroy_string_buffer(result); 6543 return NULL; 6544 } 6545 return result; 6546 } 6547 6548 FT_INTERNAL 6549 f_status realloc_string_buffer_without_copy(f_string_buffer_t *buffer) 6550 { 6551 assert(buffer); 6552 char *new_str = (char *)F_MALLOC(buffer->data_sz * 2); 6553 if (new_str == NULL) { 6554 return FT_MEMORY_ERROR; 6555 } 6556 F_FREE(buffer->str.data); 6557 buffer->str.data = new_str; 6558 buffer->data_sz *= 2; 6559 return FT_SUCCESS; 6560 } 6561 6562 6563 FT_INTERNAL 6564 f_status fill_buffer_from_string(f_string_buffer_t *buffer, const char *str) 6565 { 6566 assert(buffer); 6567 assert(str); 6568 6569 char *copy = F_STRDUP(str); 6570 if (copy == NULL) 6571 return FT_MEMORY_ERROR; 6572 6573 F_FREE(buffer->str.data); 6574 buffer->str.cstr = copy; 6575 buffer->type = CHAR_BUF; 6576 6577 return FT_SUCCESS; 6578 } 6579 6580 6581 #ifdef FT_HAVE_WCHAR 6582 FT_INTERNAL 6583 f_status fill_buffer_from_wstring(f_string_buffer_t *buffer, const wchar_t *str) 6584 { 6585 assert(buffer); 6586 assert(str); 6587 6588 wchar_t *copy = F_WCSDUP(str); 6589 if (copy == NULL) 6590 return FT_MEMORY_ERROR; 6591 6592 F_FREE(buffer->str.data); 6593 buffer->str.wstr = copy; 6594 buffer->type = W_CHAR_BUF; 6595 6596 return FT_SUCCESS; 6597 } 6598 #endif /* FT_HAVE_WCHAR */ 6599 6600 #ifdef FT_HAVE_UTF8 6601 FT_INTERNAL 6602 f_status fill_buffer_from_u8string(f_string_buffer_t *buffer, const void *str) 6603 { 6604 assert(buffer); 6605 assert(str); 6606 6607 void *copy = F_UTF8DUP(str); 6608 if (copy == NULL) 6609 return FT_MEMORY_ERROR; 6610 6611 F_FREE(buffer->str.u8str); 6612 buffer->str.u8str = copy; 6613 buffer->type = UTF8_BUF; 6614 6615 return FT_SUCCESS; 6616 } 6617 #endif /* FT_HAVE_UTF8 */ 6618 6619 FT_INTERNAL 6620 size_t buffer_text_visible_height(const f_string_buffer_t *buffer) 6621 { 6622 if (buffer == NULL || buffer->str.data == NULL || buf_str_len(buffer) == 0) { 6623 return 0; 6624 } 6625 if (buffer->type == CHAR_BUF) 6626 return 1 + strchr_count(buffer->str.cstr, '\n'); 6627 #ifdef FT_HAVE_WCHAR 6628 else if (buffer->type == W_CHAR_BUF) 6629 return 1 + wstrchr_count(buffer->str.wstr, L'\n'); 6630 #endif /* FT_HAVE_WCHAR */ 6631 #ifdef FT_HAVE_UTF8 6632 else if (buffer->type == UTF8_BUF) 6633 return 1 + utf8chr_count(buffer->str.u8str, '\n'); 6634 #endif /* FT_HAVE_WCHAR */ 6635 6636 assert(0); 6637 return 0; 6638 } 6639 6640 FT_INTERNAL 6641 size_t string_buffer_cod_width_capacity(const f_string_buffer_t *buffer) 6642 { 6643 return string_buffer_width_capacity(buffer); 6644 } 6645 6646 FT_INTERNAL 6647 size_t string_buffer_raw_capacity(const f_string_buffer_t *buffer) 6648 { 6649 return buffer->data_sz; 6650 } 6651 6652 #ifdef FT_HAVE_UTF8 6653 /* User provided function to compute utf8 string visible width */ 6654 static int (*_custom_u8strwid)(const void *beg, const void *end, size_t *width) = NULL; 6655 6656 FT_INTERNAL 6657 void buffer_set_u8strwid_func(int (*u8strwid)(const void *beg, const void *end, size_t *width)) 6658 { 6659 _custom_u8strwid = u8strwid; 6660 } 6661 6662 static 6663 size_t utf8_width(const void *beg, const void *end) 6664 { 6665 if (_custom_u8strwid) { 6666 size_t width = 0; 6667 if (!_custom_u8strwid(beg, end, &width)) 6668 return width; 6669 } 6670 6671 size_t sz = (size_t)((const char *)end - (const char *)beg); 6672 char *tmp = (char *)F_MALLOC(sizeof(char) * (sz + 1)); 6673 // @todo: add check to tmp 6674 assert(tmp); 6675 6676 memcpy(tmp, beg, sz); 6677 tmp[sz] = '\0'; 6678 size_t result = utf8width(tmp); 6679 F_FREE(tmp); 6680 return result; 6681 } 6682 #endif /* FT_HAVE_WCHAR */ 6683 6684 FT_INTERNAL 6685 size_t buffer_text_visible_width(const f_string_buffer_t *buffer) 6686 { 6687 size_t max_length = 0; 6688 if (buffer->type == CHAR_BUF) { 6689 size_t n = 0; 6690 while (1) { 6691 const char *beg = NULL; 6692 const char *end = NULL; 6693 str_n_substring(buffer->str.cstr, '\n', n, &beg, &end); 6694 if (beg == NULL || end == NULL) 6695 return max_length; 6696 6697 max_length = MAX(max_length, (size_t)(end - beg)); 6698 ++n; 6699 } 6700 #ifdef FT_HAVE_WCHAR 6701 } else if (buffer->type == W_CHAR_BUF) { 6702 size_t n = 0; 6703 while (1) { 6704 const wchar_t *beg = NULL; 6705 const wchar_t *end = NULL; 6706 wstr_n_substring(buffer->str.wstr, L'\n', n, &beg, &end); 6707 if (beg == NULL || end == NULL) 6708 return max_length; 6709 6710 int line_width = mk_wcswidth(beg, (size_t)(end - beg)); 6711 if (line_width < 0) /* For safety */ 6712 line_width = 0; 6713 max_length = MAX(max_length, (size_t)line_width); 6714 6715 ++n; 6716 } 6717 #endif /* FT_HAVE_WCHAR */ 6718 #ifdef FT_HAVE_UTF8 6719 } else if (buffer->type == UTF8_BUF) { 6720 size_t n = 0; 6721 while (1) { 6722 const void *beg = NULL; 6723 const void *end = NULL; 6724 utf8_n_substring(buffer->str.u8str, '\n', n, &beg, &end); 6725 if (beg == NULL || end == NULL) 6726 return max_length; 6727 6728 max_length = MAX(max_length, (size_t)utf8_width(beg, end)); 6729 ++n; 6730 } 6731 #endif /* FT_HAVE_WCHAR */ 6732 } 6733 6734 return max_length; /* shouldn't be here */ 6735 } 6736 6737 6738 static void 6739 buffer_substring(const f_string_buffer_t *buffer, size_t buffer_row, const void **begin, const void **end, ptrdiff_t *str_it_width) 6740 { 6741 switch (buffer->type) { 6742 case CHAR_BUF: 6743 str_n_substring(buffer->str.cstr, '\n', buffer_row, (const char **)begin, (const char **)end); 6744 if ((*(const char **)begin) && (*(const char **)end)) 6745 *str_it_width = str_iter_width(*(const char **)begin, *(const char **)end); 6746 break; 6747 #ifdef FT_HAVE_WCHAR 6748 case W_CHAR_BUF: 6749 wstr_n_substring(buffer->str.wstr, L'\n', buffer_row, (const wchar_t **)begin, (const wchar_t **)end); 6750 if ((*(const wchar_t **)begin) && (*(const wchar_t **)end)) 6751 *str_it_width = wcs_iter_width(*(const wchar_t **)begin, *(const wchar_t **)end); 6752 break; 6753 #endif /* FT_HAVE_WCHAR */ 6754 #ifdef FT_HAVE_UTF8 6755 case UTF8_BUF: 6756 utf8_n_substring(buffer->str.u8str, '\n', buffer_row, begin, end); 6757 if ((*(const char **)begin) && (*(const char **)end)) 6758 *str_it_width = utf8_width(*begin, *end); 6759 break; 6760 #endif /* FT_HAVE_UTF8 */ 6761 default: 6762 assert(0); 6763 } 6764 } 6765 6766 6767 static int 6768 buffer_print_range(f_conv_context_t *cntx, const void *beg, const void *end) 6769 { 6770 size_t len; 6771 switch (cntx->b_type) { 6772 case CHAR_BUF: 6773 len = (size_t)((const char *)end - (const char *)beg); 6774 return ft_nprint(cntx, (const char *)beg, len); 6775 #ifdef FT_HAVE_WCHAR 6776 case W_CHAR_BUF: 6777 len = (size_t)((const wchar_t *)end - (const wchar_t *)beg); 6778 return ft_nwprint(cntx, (const wchar_t *)beg, len); 6779 #endif /* FT_HAVE_WCHAR */ 6780 #ifdef FT_HAVE_UTF8 6781 case UTF8_BUF: 6782 return ft_nu8print(cntx, beg, end); 6783 #endif /* FT_HAVE_UTF8 */ 6784 default: 6785 assert(0); 6786 return -1; 6787 } 6788 } 6789 6790 6791 FT_INTERNAL 6792 int buffer_printf(f_string_buffer_t *buffer, size_t buffer_row, f_conv_context_t *cntx, size_t vis_width, 6793 const char *content_style_tag, const char *reset_content_style_tag) 6794 { 6795 const f_context_t *context = cntx->cntx; 6796 f_table_properties_t *props = context->table_properties; 6797 size_t row = context->row; 6798 size_t column = context->column; 6799 6800 if (buffer == NULL || buffer->str.data == NULL 6801 || buffer_row >= buffer_text_visible_height(buffer)) { 6802 return -1; 6803 } 6804 6805 size_t content_width = buffer_text_visible_width(buffer); 6806 if (vis_width < content_width) 6807 return -1; 6808 6809 size_t left = 0; 6810 size_t right = 0; 6811 switch (get_cell_property_hierarchically(props, row, column, FT_CPROP_TEXT_ALIGN)) { 6812 case FT_ALIGNED_LEFT: 6813 left = 0; 6814 right = (vis_width) - content_width; 6815 break; 6816 case FT_ALIGNED_CENTER: 6817 left = ((vis_width) - content_width) / 2; 6818 right = ((vis_width) - content_width) - left; 6819 break; 6820 case FT_ALIGNED_RIGHT: 6821 left = (vis_width) - content_width; 6822 right = 0; 6823 break; 6824 default: 6825 assert(0); 6826 break; 6827 } 6828 6829 size_t written = 0; 6830 int tmp = 0; 6831 ptrdiff_t str_it_width = 0; 6832 const void *beg = NULL; 6833 const void *end = NULL; 6834 buffer_substring(buffer, buffer_row, &beg, &end, &str_it_width); 6835 if (beg == NULL || end == NULL) 6836 return -1; 6837 if (str_it_width < 0 || content_width < (size_t)str_it_width) 6838 return -1; 6839 6840 size_t padding = content_width - (size_t)str_it_width; 6841 6842 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, left, FT_SPACE)); 6843 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, content_style_tag)); 6844 CHCK_RSLT_ADD_TO_WRITTEN(buffer_print_range(cntx, beg, end)); 6845 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, 1, reset_content_style_tag)); 6846 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, padding, FT_SPACE)); 6847 CHCK_RSLT_ADD_TO_WRITTEN(print_n_strings(cntx, right, FT_SPACE)); 6848 return (int)written; 6849 6850 clear: 6851 return -1; 6852 } 6853 6854 FT_INTERNAL 6855 size_t string_buffer_width_capacity(const f_string_buffer_t *buffer) 6856 { 6857 assert(buffer); 6858 switch (buffer->type) { 6859 case CHAR_BUF: 6860 return buffer->data_sz; 6861 #ifdef FT_HAVE_WCHAR 6862 case W_CHAR_BUF: 6863 return buffer->data_sz / sizeof(wchar_t); 6864 #endif 6865 #ifdef FT_HAVE_UTF8 6866 case UTF8_BUF: 6867 return buffer->data_sz / 4; 6868 #endif 6869 default: 6870 assert(0); 6871 return 0; 6872 } 6873 } 6874 6875 6876 FT_INTERNAL 6877 void *buffer_get_data(f_string_buffer_t *buffer) 6878 { 6879 assert(buffer); 6880 return buffer->str.data; 6881 } 6882 6883 FT_INTERNAL 6884 int buffer_check_align(f_string_buffer_t *buffer) 6885 { 6886 assert(buffer); 6887 assert(buffer->str.data); 6888 6889 switch (buffer->type) { 6890 case CHAR_BUF: 6891 return 1; 6892 #ifdef FT_HAVE_WCHAR 6893 case W_CHAR_BUF: 6894 return (((uintptr_t)buffer->str.data) & (sizeof(wchar_t) - 1)) == 0; 6895 #endif 6896 #ifdef FT_HAVE_UTF8 6897 case UTF8_BUF: 6898 return 1; 6899 #endif 6900 default: 6901 assert(0); 6902 return 0; 6903 } 6904 } 6905 6906 /******************************************************** 6907 End of file "string_buffer.c" 6908 ********************************************************/ 6909 6910 6911 /******************************************************** 6912 Begin of file "table.c" 6913 ********************************************************/ 6914 6915 /* #include "table.h" */ /* Commented by amalgamation script */ 6916 /* #include "string_buffer.h" */ /* Commented by amalgamation script */ 6917 /* #include "cell.h" */ /* Commented by amalgamation script */ 6918 /* #include "vector.h" */ /* Commented by amalgamation script */ 6919 /* #include "row.h" */ /* Commented by amalgamation script */ 6920 6921 FT_INTERNAL 6922 f_separator_t *create_separator(int enabled) 6923 { 6924 f_separator_t *res = (f_separator_t *)F_CALLOC(1, sizeof(f_separator_t)); 6925 if (res == NULL) 6926 return NULL; 6927 res->enabled = enabled; 6928 return res; 6929 } 6930 6931 6932 FT_INTERNAL 6933 void destroy_separator(f_separator_t *sep) 6934 { 6935 F_FREE(sep); 6936 } 6937 6938 6939 FT_INTERNAL 6940 f_separator_t *copy_separator(f_separator_t *sep) 6941 { 6942 assert(sep); 6943 return create_separator(sep->enabled); 6944 } 6945 6946 6947 static 6948 f_row_t *get_row_impl(ft_table_t *table, size_t row, enum f_get_policy policy) 6949 { 6950 if (table == NULL || table->rows == NULL) { 6951 return NULL; 6952 } 6953 6954 switch (policy) { 6955 case DONT_CREATE_ON_NULL: 6956 if (row < vector_size(table->rows)) { 6957 return VECTOR_AT(table->rows, row, f_row_t *); 6958 } 6959 return NULL; 6960 case CREATE_ON_NULL: 6961 while (row >= vector_size(table->rows)) { 6962 f_row_t *new_row = create_row(); 6963 if (new_row == NULL) 6964 return NULL; 6965 if (FT_IS_ERROR(vector_push(table->rows, &new_row))) { 6966 destroy_row(new_row); 6967 return NULL; 6968 } 6969 } 6970 return VECTOR_AT(table->rows, row, f_row_t *); 6971 } 6972 6973 assert(0 && "Shouldn't be here!"); 6974 return NULL; 6975 } 6976 6977 6978 FT_INTERNAL 6979 f_row_t *get_row(ft_table_t *table, size_t row) 6980 { 6981 return get_row_impl(table, row, DONT_CREATE_ON_NULL); 6982 } 6983 6984 6985 FT_INTERNAL 6986 const f_row_t *get_row_c(const ft_table_t *table, size_t row) 6987 { 6988 return get_row((ft_table_t *)table, row); 6989 } 6990 6991 6992 FT_INTERNAL 6993 f_row_t *get_row_and_create_if_not_exists(ft_table_t *table, size_t row) 6994 { 6995 return get_row_impl(table, row, CREATE_ON_NULL); 6996 } 6997 6998 FT_INTERNAL 6999 f_string_buffer_t *get_cur_str_buffer_and_create_if_not_exists(ft_table_t *table) 7000 { 7001 assert(table); 7002 7003 f_row_t *row = get_row_and_create_if_not_exists(table, table->cur_row); 7004 if (row == NULL) 7005 return NULL; 7006 7007 f_cell_t *cell = NULL; 7008 fort_entire_table_properties_t *table_props = &table->properties->entire_table_properties; 7009 switch (table_props->add_strategy) { 7010 case FT_STRATEGY_INSERT: 7011 cell = create_cell_in_position(row, table->cur_col); 7012 break; 7013 case FT_STRATEGY_REPLACE: 7014 cell = get_cell_and_create_if_not_exists(row, table->cur_col); 7015 break; 7016 default: 7017 assert(0 && "Unexpected situation inside libfort"); 7018 break; 7019 } 7020 7021 if (cell == NULL) 7022 return NULL; 7023 7024 return cell_get_string_buffer(cell); 7025 } 7026 7027 7028 /* 7029 * Returns number of cells (rows * cols) 7030 */ 7031 FT_INTERNAL 7032 f_status get_table_sizes(const ft_table_t *table, size_t *rows, size_t *cols) 7033 { 7034 *rows = 0; 7035 *cols = 0; 7036 if (table && table->rows) { 7037 *rows = vector_size(table->rows); 7038 size_t row_index = 0; 7039 for (row_index = 0; row_index < vector_size(table->rows); ++row_index) { 7040 f_row_t *row = VECTOR_AT(table->rows, row_index, f_row_t *); 7041 size_t cols_in_row = columns_in_row(row); 7042 if (cols_in_row > *cols) 7043 *cols = cols_in_row; 7044 } 7045 } 7046 return FT_SUCCESS; 7047 } 7048 7049 7050 FT_INTERNAL 7051 f_status table_rows_and_cols_geometry(const ft_table_t *table, 7052 size_t **col_width_arr_p, size_t *col_width_arr_sz, 7053 size_t **row_height_arr_p, size_t *row_height_arr_sz, 7054 enum f_geometry_type geom) 7055 { 7056 if (table == NULL) { 7057 return FT_GEN_ERROR; 7058 } 7059 7060 size_t max_invis_codepoints = 0; 7061 size_t cols = 0; 7062 size_t rows = 0; 7063 int status = get_table_sizes(table, &rows, &cols); 7064 if (FT_IS_ERROR(status)) 7065 return status; 7066 7067 size_t *col_width_arr = (size_t *)F_CALLOC(cols, sizeof(size_t)); 7068 size_t *row_height_arr = (size_t *)F_CALLOC(rows, sizeof(size_t)); 7069 if (col_width_arr == NULL || row_height_arr == NULL) { 7070 F_FREE(col_width_arr); 7071 F_FREE(row_height_arr); 7072 return FT_GEN_ERROR; 7073 } 7074 7075 int combined_cells_found = 0; 7076 f_context_t context; 7077 context.table_properties = (table->properties ? table->properties : &g_table_properties); 7078 size_t col = 0; 7079 for (col = 0; col < cols; ++col) { 7080 col_width_arr[col] = 0; 7081 size_t row = 0; 7082 for (row = 0; row < rows; ++row) { 7083 const f_row_t *row_p = get_row_c(table, row); 7084 const f_cell_t *cell = get_cell_c(row_p, col); 7085 context.column = col; 7086 context.row = row; 7087 if (cell) { 7088 switch (get_cell_type(cell)) { 7089 case COMMON_CELL: 7090 col_width_arr[col] = MAX(col_width_arr[col], cell_vis_width(cell, &context)); 7091 break; 7092 case GROUP_MASTER_CELL: 7093 combined_cells_found = 1; 7094 break; 7095 case GROUP_SLAVE_CELL: 7096 ; /* Do nothing */ 7097 break; 7098 } 7099 row_height_arr[row] = MAX(row_height_arr[row], hint_height_cell(cell, &context)); 7100 } else { 7101 size_t cell_empty_string_height = get_cell_property_hierarchically(context.table_properties, context.row, context.column, FT_CPROP_EMPTY_STR_HEIGHT); 7102 if (cell_empty_string_height) { 7103 size_t cell_top_padding = get_cell_property_hierarchically(context.table_properties, context.row, context.column, FT_CPROP_TOP_PADDING); 7104 size_t cell_bottom_padding = get_cell_property_hierarchically(context.table_properties, context.row, context.column, FT_CPROP_BOTTOM_PADDING); 7105 row_height_arr[row] = MAX(row_height_arr[row], cell_empty_string_height + cell_top_padding + cell_bottom_padding); 7106 } 7107 } 7108 } 7109 7110 if (geom == INTERN_REPR_GEOMETRY) { 7111 max_invis_codepoints = 0; 7112 for (row = 0; row < rows; ++row) { 7113 const f_row_t *row_p = get_row_c(table, row); 7114 const f_cell_t *cell = get_cell_c(row_p, col); 7115 if (!cell) 7116 continue; 7117 context.column = col; 7118 context.row = row; 7119 size_t inv_codepoints = cell_invis_codes_width(cell, &context); 7120 max_invis_codepoints = MAX(max_invis_codepoints, inv_codepoints); 7121 } 7122 col_width_arr[col] += max_invis_codepoints; 7123 } 7124 } 7125 7126 if (combined_cells_found) { 7127 for (col = 0; col < cols; ++col) { 7128 size_t row = 0; 7129 for (row = 0; row < rows; ++row) { 7130 const f_row_t *row_p = get_row_c(table, row); 7131 const f_cell_t *cell = get_cell_c(row_p, col); 7132 context.column = col; 7133 context.row = row; 7134 if (cell) { 7135 if (get_cell_type(cell) == GROUP_MASTER_CELL) { 7136 size_t hint_width = cell_vis_width(cell, &context); 7137 if (geom == INTERN_REPR_GEOMETRY) { 7138 hint_width += cell_invis_codes_width(cell, &context); 7139 } 7140 size_t slave_col = col + group_cell_number(row_p, col); 7141 size_t cur_adj_col = col; 7142 size_t group_width = col_width_arr[col]; 7143 size_t i; 7144 for (i = col + 1; i < slave_col; ++i) 7145 group_width += col_width_arr[i] + FORT_COL_SEPARATOR_LENGTH; 7146 /* adjust col. widths */ 7147 while (1) { 7148 if (group_width >= hint_width) 7149 break; 7150 col_width_arr[cur_adj_col] += 1; 7151 group_width++; 7152 cur_adj_col++; 7153 if (cur_adj_col == slave_col) 7154 cur_adj_col = col; 7155 } 7156 } 7157 } 7158 } 7159 } 7160 } 7161 7162 /* todo: Maybe it is better to move min width checking to a particular cell 7163 * width checking. At the moment min width includes paddings. Maybe it is 7164 * better that min width weren't include paddings but be min width of the 7165 * cell content without padding 7166 */ 7167 /* 7168 if (table->properties) { 7169 for (size_t i = 0; i < cols; ++i) { 7170 col_width_arr[i] = MAX((int)col_width_arr[i], fort_props_column_width(table->properties, i)); 7171 } 7172 } 7173 */ 7174 7175 *col_width_arr_p = col_width_arr; 7176 *col_width_arr_sz = cols; 7177 *row_height_arr_p = row_height_arr; 7178 *row_height_arr_sz = rows; 7179 return FT_SUCCESS; 7180 } 7181 7182 7183 /* 7184 * Returns geometry in characters 7185 */ 7186 FT_INTERNAL 7187 f_status table_geometry(const ft_table_t *table, size_t *height, size_t *width) 7188 { 7189 if (table == NULL) 7190 return FT_GEN_ERROR; 7191 7192 *height = 0; 7193 *width = 0; 7194 size_t cols = 0; 7195 size_t rows = 0; 7196 size_t *col_width_arr = NULL; 7197 size_t *row_height_arr = NULL; 7198 7199 int status = table_rows_and_cols_geometry(table, &col_width_arr, &cols, &row_height_arr, &rows, INTERN_REPR_GEOMETRY); 7200 if (FT_IS_ERROR(status)) 7201 return status; 7202 7203 *width = 1 + (cols == 0 ? 1 : cols) + 1; /* for boundaries (that take 1 symbol) + newline */ 7204 size_t i = 0; 7205 for (i = 0; i < cols; ++i) { 7206 *width += col_width_arr[i]; 7207 } 7208 7209 /* todo: add check for non printable horizontal row separators */ 7210 *height = 1 + (rows == 0 ? 1 : rows); /* for boundaries (that take 1 symbol) */ 7211 for (i = 0; i < rows; ++i) { 7212 *height += row_height_arr[i]; 7213 } 7214 F_FREE(col_width_arr); 7215 F_FREE(row_height_arr); 7216 7217 f_table_properties_t *properties = table->properties; 7218 if (properties) { 7219 *height += properties->entire_table_properties.top_margin; 7220 *height += properties->entire_table_properties.bottom_margin; 7221 *width += properties->entire_table_properties.left_margin; 7222 *width += properties->entire_table_properties.right_margin; 7223 } 7224 7225 /* Take into account that border elements can be more than one byte long */ 7226 f_table_properties_t *table_properties = properties ? properties : &g_table_properties; 7227 size_t max_border_elem_len = max_border_elem_strlen(table_properties); 7228 *width *= max_border_elem_len; 7229 7230 return FT_SUCCESS; 7231 } 7232 7233 FT_INTERNAL 7234 f_status table_internal_codepoints_geometry(const ft_table_t *table, size_t *height, size_t *width) 7235 { 7236 return table_geometry(table, height, width); 7237 } 7238 7239 /******************************************************** 7240 End of file "table.c" 7241 ********************************************************/ 7242 7243 7244 /******************************************************** 7245 Begin of file "vector.c" 7246 ********************************************************/ 7247 7248 /* #include "vector.h" */ /* Commented by amalgamation script */ 7249 #include <assert.h> 7250 #include <string.h> 7251 7252 struct f_vector { 7253 size_t m_size; 7254 void *m_data; 7255 size_t m_capacity; 7256 size_t m_item_size; 7257 }; 7258 7259 7260 static int vector_reallocate_(f_vector_t *vector, size_t new_capacity) 7261 { 7262 assert(vector); 7263 assert(new_capacity > vector->m_capacity); 7264 7265 size_t new_size = new_capacity * vector->m_item_size; 7266 vector->m_data = F_REALLOC(vector->m_data, new_size); 7267 if (vector->m_data == NULL) 7268 return -1; 7269 return 0; 7270 } 7271 7272 7273 FT_INTERNAL 7274 f_vector_t *create_vector(size_t item_size, size_t capacity) 7275 { 7276 f_vector_t *vector = (f_vector_t *)F_MALLOC(sizeof(f_vector_t)); 7277 if (vector == NULL) { 7278 return NULL; 7279 } 7280 7281 size_t init_size = MAX(item_size * capacity, 1); 7282 vector->m_data = F_MALLOC(init_size); 7283 if (vector->m_data == NULL) { 7284 F_FREE(vector); 7285 return NULL; 7286 } 7287 7288 vector->m_size = 0; 7289 vector->m_capacity = capacity; 7290 vector->m_item_size = item_size; 7291 7292 return vector; 7293 } 7294 7295 7296 FT_INTERNAL 7297 void destroy_vector(f_vector_t *vector) 7298 { 7299 assert(vector); 7300 F_FREE(vector->m_data); 7301 F_FREE(vector); 7302 } 7303 7304 7305 FT_INTERNAL 7306 size_t vector_size(const f_vector_t *vector) 7307 { 7308 assert(vector); 7309 return vector->m_size; 7310 } 7311 7312 7313 FT_INTERNAL 7314 size_t vector_capacity(const f_vector_t *vector) 7315 { 7316 assert(vector); 7317 return vector->m_capacity; 7318 } 7319 7320 7321 FT_INTERNAL 7322 int vector_push(f_vector_t *vector, const void *item) 7323 { 7324 assert(vector); 7325 assert(item); 7326 7327 if (vector->m_size == vector->m_capacity) { 7328 if (vector_reallocate_(vector, vector->m_capacity * 2) == -1) 7329 return FT_GEN_ERROR; 7330 vector->m_capacity = vector->m_capacity * 2; 7331 } 7332 7333 size_t offset = vector->m_size * vector->m_item_size; 7334 memcpy((char *)vector->m_data + offset, item, vector->m_item_size); 7335 7336 ++(vector->m_size); 7337 7338 return FT_SUCCESS; 7339 } 7340 7341 FT_INTERNAL 7342 int vector_insert(f_vector_t *vector, const void *item, size_t pos) 7343 { 7344 assert(vector); 7345 assert(item); 7346 size_t needed_capacity = MAX(pos + 1, vector->m_size + 1); 7347 if (vector->m_capacity < needed_capacity) { 7348 if (vector_reallocate_(vector, needed_capacity) == -1) 7349 return FT_GEN_ERROR; 7350 vector->m_capacity = needed_capacity; 7351 } 7352 size_t offset = pos * vector->m_item_size; 7353 if (pos >= vector->m_size) { 7354 /* Data in the middle are not initialized */ 7355 memcpy((char *)vector->m_data + offset, item, vector->m_item_size); 7356 vector->m_size = pos + 1; 7357 return FT_SUCCESS; 7358 } else { 7359 /* Shift following data by one position */ 7360 memmove((char *)vector->m_data + offset + vector->m_item_size, 7361 (char *)vector->m_data + offset, 7362 vector->m_item_size * (vector->m_size - pos)); 7363 memcpy((char *)vector->m_data + offset, item, vector->m_item_size); 7364 ++(vector->m_size); 7365 return FT_SUCCESS; 7366 } 7367 } 7368 7369 FT_INTERNAL 7370 f_vector_t *vector_split(f_vector_t *vector, size_t pos) 7371 { 7372 size_t trailing_sz = vector->m_size > pos ? vector->m_size - pos : 0; 7373 f_vector_t *new_vector = create_vector(vector->m_item_size, trailing_sz); 7374 if (!new_vector) 7375 return new_vector; 7376 if (new_vector->m_capacity < trailing_sz) { 7377 destroy_vector(new_vector); 7378 return NULL; 7379 } 7380 7381 if (trailing_sz == 0) 7382 return new_vector; 7383 7384 size_t offset = vector->m_item_size * pos; 7385 memcpy(new_vector->m_data, (char *)vector->m_data + offset, 7386 trailing_sz * vector->m_item_size); 7387 new_vector->m_size = trailing_sz; 7388 vector->m_size = pos; 7389 return new_vector; 7390 } 7391 7392 FT_INTERNAL 7393 const void *vector_at_c(const f_vector_t *vector, size_t index) 7394 { 7395 if (index >= vector->m_size) 7396 return NULL; 7397 7398 return (char *)vector->m_data + index * vector->m_item_size; 7399 } 7400 7401 7402 FT_INTERNAL 7403 void *vector_at(f_vector_t *vector, size_t index) 7404 { 7405 if (index >= vector->m_size) 7406 return NULL; 7407 7408 return (char *)vector->m_data + index * vector->m_item_size; 7409 } 7410 7411 7412 FT_INTERNAL 7413 f_status vector_swap(f_vector_t *cur_vec, f_vector_t *mv_vec, size_t pos) 7414 { 7415 assert(cur_vec); 7416 assert(mv_vec); 7417 assert(cur_vec != mv_vec); 7418 assert(cur_vec->m_item_size == mv_vec->m_item_size); 7419 7420 size_t cur_sz = vector_size(cur_vec); 7421 size_t mv_sz = vector_size(mv_vec); 7422 if (mv_sz == 0) { 7423 return FT_SUCCESS; 7424 } 7425 7426 size_t min_targ_size = pos + mv_sz; 7427 if (vector_capacity(cur_vec) < min_targ_size) { 7428 if (vector_reallocate_(cur_vec, min_targ_size) == -1) 7429 return FT_GEN_ERROR; 7430 cur_vec->m_capacity = min_targ_size; 7431 } 7432 7433 size_t offset = pos * cur_vec->m_item_size; 7434 void *tmp = NULL; 7435 size_t new_mv_sz = 0; 7436 if (cur_sz > pos) { 7437 new_mv_sz = MIN(cur_sz - pos, mv_sz); 7438 tmp = F_MALLOC(cur_vec->m_item_size * new_mv_sz); 7439 if (tmp == NULL) { 7440 return FT_MEMORY_ERROR; 7441 } 7442 } 7443 7444 if (tmp) { 7445 memcpy(tmp, 7446 (char *)cur_vec->m_data + offset, 7447 cur_vec->m_item_size * new_mv_sz); 7448 } 7449 7450 memcpy((char *)cur_vec->m_data + offset, 7451 mv_vec->m_data, 7452 cur_vec->m_item_size * mv_sz); 7453 7454 if (tmp) { 7455 memcpy(mv_vec->m_data, 7456 tmp, 7457 cur_vec->m_item_size * new_mv_sz); 7458 } 7459 7460 cur_vec->m_size = MAX(cur_vec->m_size, min_targ_size); 7461 mv_vec->m_size = new_mv_sz; 7462 F_FREE(tmp); 7463 return FT_SUCCESS; 7464 } 7465 7466 FT_INTERNAL 7467 void vector_clear(f_vector_t *vector) 7468 { 7469 vector->m_size = 0; 7470 } 7471 7472 FT_INTERNAL 7473 int vector_erase(f_vector_t *vector, size_t index) 7474 { 7475 assert(vector); 7476 7477 if (vector->m_size == 0 || index >= vector->m_size) 7478 return FT_GEN_ERROR; 7479 7480 memmove((char *)vector->m_data + vector->m_item_size * index, 7481 (char *)vector->m_data + vector->m_item_size * (index + 1), 7482 (vector->m_size - 1 - index) * vector->m_item_size); 7483 vector->m_size--; 7484 return FT_SUCCESS; 7485 } 7486 7487 #ifdef FT_TEST_BUILD 7488 7489 f_vector_t *copy_vector(f_vector_t *v) 7490 { 7491 if (v == NULL) 7492 return NULL; 7493 7494 f_vector_t *new_vector = create_vector(v->m_item_size, v->m_capacity); 7495 if (new_vector == NULL) 7496 return NULL; 7497 7498 memcpy(new_vector->m_data, v->m_data, v->m_item_size * v->m_size); 7499 new_vector->m_size = v->m_size ; 7500 new_vector->m_item_size = v->m_item_size ; 7501 return new_vector; 7502 } 7503 7504 size_t vector_index_of(const f_vector_t *vector, const void *item) 7505 { 7506 assert(vector); 7507 assert(item); 7508 7509 size_t i = 0; 7510 for (i = 0; i < vector->m_size; ++i) { 7511 void *data_pos = (char *)vector->m_data + i * vector->m_item_size; 7512 if (memcmp(data_pos, item, vector->m_item_size) == 0) { 7513 return i; 7514 } 7515 } 7516 return INVALID_VEC_INDEX; 7517 } 7518 7519 #endif 7520 7521 /******************************************************** 7522 End of file "vector.c" 7523 ********************************************************/ 7524 7525 7526 /******************************************************** 7527 Begin of file "wcwidth.c" 7528 ********************************************************/ 7529 7530 /* 7531 * This is an implementation of wcwidth() and wcswidth() (defined in 7532 * IEEE Std 1002.1-2001) for Unicode. 7533 * 7534 * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html 7535 * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html 7536 * 7537 * In fixed-width output devices, Latin characters all occupy a single 7538 * "cell" position of equal width, whereas ideographic CJK characters 7539 * occupy two such cells. Interoperability between terminal-line 7540 * applications and (teletype-style) character terminals using the 7541 * UTF-8 encoding requires agreement on which character should advance 7542 * the cursor by how many cell positions. No established formal 7543 * standards exist at present on which Unicode character shall occupy 7544 * how many cell positions on character terminals. These routines are 7545 * a first attempt of defining such behavior based on simple rules 7546 * applied to data provided by the Unicode Consortium. 7547 * 7548 * For some graphical characters, the Unicode standard explicitly 7549 * defines a character-cell width via the definition of the East Asian 7550 * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes. 7551 * In all these cases, there is no ambiguity about which width a 7552 * terminal shall use. For characters in the East Asian Ambiguous (A) 7553 * class, the width choice depends purely on a preference of backward 7554 * compatibility with either historic CJK or Western practice. 7555 * Choosing single-width for these characters is easy to justify as 7556 * the appropriate long-term solution, as the CJK practice of 7557 * displaying these characters as double-width comes from historic 7558 * implementation simplicity (8-bit encoded characters were displayed 7559 * single-width and 16-bit ones double-width, even for Greek, 7560 * Cyrillic, etc.) and not any typographic considerations. 7561 * 7562 * Much less clear is the choice of width for the Not East Asian 7563 * (Neutral) class. Existing practice does not dictate a width for any 7564 * of these characters. It would nevertheless make sense 7565 * typographically to allocate two character cells to characters such 7566 * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be 7567 * represented adequately with a single-width glyph. The following 7568 * routines at present merely assign a single-cell width to all 7569 * neutral characters, in the interest of simplicity. This is not 7570 * entirely satisfactory and should be reconsidered before 7571 * establishing a formal standard in this area. At the moment, the 7572 * decision which Not East Asian (Neutral) characters should be 7573 * represented by double-width glyphs cannot yet be answered by 7574 * applying a simple rule from the Unicode database content. Setting 7575 * up a proper standard for the behavior of UTF-8 character terminals 7576 * will require a careful analysis not only of each Unicode character, 7577 * but also of each presentation form, something the author of these 7578 * routines has avoided to do so far. 7579 * 7580 * http://www.unicode.org/unicode/reports/tr11/ 7581 * 7582 * Markus Kuhn -- 2007-05-26 (Unicode 5.0) 7583 * 7584 * Permission to use, copy, modify, and distribute this software 7585 * for any purpose and without fee is hereby granted. The author 7586 * disclaims all warranties with regard to this software. 7587 * 7588 * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c 7589 */ 7590 7591 /* #include "wcwidth.h" */ /* Commented by amalgamation script */ 7592 7593 #ifdef FT_HAVE_WCHAR 7594 7595 7596 struct interval { 7597 int32_t first; 7598 int32_t last; 7599 }; 7600 7601 /* auxiliary function for binary search in interval table */ 7602 static int bisearch(int32_t ucs, const struct interval *table, int max) 7603 { 7604 int min = 0; 7605 7606 if (ucs < table[0].first || ucs > table[max].last) 7607 return 0; 7608 while (max >= min) { 7609 int mid = (min + max) / 2; 7610 if (ucs > table[mid].last) 7611 min = mid + 1; 7612 else if (ucs < table[mid].first) 7613 max = mid - 1; 7614 else 7615 return 1; 7616 } 7617 7618 return 0; 7619 } 7620 7621 7622 /* The following two functions define the column width of an ISO 10646 7623 * character as follows: 7624 * 7625 * - The null character (U+0000) has a column width of 0. 7626 * 7627 * - Other C0/C1 control characters and DEL will lead to a return 7628 * value of -1. 7629 * 7630 * - Non-spacing and enclosing combining characters (general 7631 * category code Mn or Me in the Unicode database) have a 7632 * column width of 0. 7633 * 7634 * - SOFT HYPHEN (U+00AD) has a column width of 1. 7635 * 7636 * - Other format characters (general category code Cf in the Unicode 7637 * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. 7638 * 7639 * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) 7640 * have a column width of 0. 7641 * 7642 * - Spacing characters in the East Asian Wide (W) or East Asian 7643 * Full-width (F) category as defined in Unicode Technical 7644 * Report #11 have a column width of 2. 7645 * 7646 * - All remaining characters (including all printable 7647 * ISO 8859-1 and WGL4 characters, Unicode control characters, 7648 * etc.) have a column width of 1. 7649 * 7650 * This implementation assumes that wchar_t characters are encoded 7651 * in ISO 10646. 7652 */ 7653 7654 static int mk_wcwidth(wchar_t wcs) 7655 { 7656 /* sorted list of non-overlapping intervals of non-spacing characters */ 7657 /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ 7658 static const struct interval combining[] = { 7659 { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 }, 7660 { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, 7661 { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 }, 7662 { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 }, 7663 { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, 7664 { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, 7665 { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 }, 7666 { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, 7667 { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, 7668 { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, 7669 { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, 7670 { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, 7671 { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, 7672 { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, 7673 { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, 7674 { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D }, 7675 { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, 7676 { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, 7677 { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC }, 7678 { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, 7679 { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, 7680 { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, 7681 { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, 7682 { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, 7683 { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, 7684 { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, 7685 { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, 7686 { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, 7687 { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, 7688 { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F }, 7689 { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, 7690 { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, 7691 { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, 7692 { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, 7693 { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, 7694 { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, 7695 { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 }, 7696 { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF }, 7697 { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 }, 7698 { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F }, 7699 { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, 7700 { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, 7701 { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, 7702 { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, 7703 { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 }, 7704 { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, 7705 { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, 7706 { 0xE0100, 0xE01EF } 7707 }; 7708 7709 /* We convert wchar_t to int32_t to avoid compiler warnings 7710 * about implicit integer conversions 7711 * https://github.com/seleznevae/libfort/issues/20 7712 * 7713 * note: didn't test if we can do it 7714 */ 7715 int32_t ucs = (int32_t)wcs; 7716 7717 /* test for 8-bit control characters */ 7718 if (ucs == 0) 7719 return 0; 7720 if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) 7721 return -1; 7722 7723 /* binary search in table of non-spacing characters */ 7724 if (bisearch(ucs, combining, 7725 sizeof(combining) / sizeof(struct interval) - 1)) 7726 return 0; 7727 7728 /* if we arrive here, ucs is not a combining or C0/C1 control character */ 7729 7730 return 1 + 7731 (ucs >= 0x1100 && 7732 (ucs <= 0x115f || /* Hangul Jamo init. consonants */ 7733 ucs == 0x2329 || ucs == 0x232a || 7734 (ucs >= 0x2e80 && ucs <= 0xa4cf && 7735 ucs != 0x303f) || /* CJK ... Yi */ 7736 (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ 7737 (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ 7738 (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ 7739 (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ 7740 (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ 7741 (ucs >= 0xffe0 && ucs <= 0xffe6) || 7742 (ucs >= 0x20000 && ucs <= 0x2fffd) || 7743 (ucs >= 0x30000 && ucs <= 0x3fffd))); 7744 } 7745 7746 7747 FT_INTERNAL 7748 int mk_wcswidth(const wchar_t *pwcs, size_t n) 7749 { 7750 int width = 0; 7751 7752 for (; *pwcs && n-- > 0; pwcs++) { 7753 int w; 7754 if ((w = mk_wcwidth(*pwcs)) < 0) 7755 return -1; 7756 else 7757 width += w; 7758 } 7759 7760 return width; 7761 } 7762 #endif /* FT_HAVE_WCHAR */ 7763 7764 /******************************************************** 7765 End of file "wcwidth.c" 7766 ********************************************************/ 7767