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