mirror of
https://github.com/ascii-boxes/boxes.git
synced 2025-01-05 13:38:58 +01:00
Add new "bxstring" module which is meant to evolve into boxes' string abstraction
It handles embedded escape sequences, mbcs encodings, and characters wider than 1 column.
This commit is contained in:
parent
77d02890a7
commit
b0d3384bd4
1
Makefile
1
Makefile
@ -183,6 +183,7 @@ win32.utest: $(OUT_DIR)
|
||||
$(MAKE) -C utest BOXES_PLATFORM=win32 C_INCLUDE_PATH=../$(PCRE2_DIR)/src:../$(WIN_CMOCKA_DIR)/include \
|
||||
LDFLAGS_ADDTL="-L../$(PCRE2_DIR)/.libs -L../$(WIN_CMOCKA_DIR)/lib" utest
|
||||
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Cleanup
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -23,11 +23,11 @@ GEN_HDR = parser.h boxes.h lex.yy.h
|
||||
GEN_SRC = parser.c lex.yy.c
|
||||
GEN_FILES = $(GEN_SRC) $(GEN_HDR)
|
||||
ORIG_HDRCL = boxes.in.h config.h
|
||||
ORIG_HDR = $(ORIG_HDRCL) cmdline.h discovery.h generate.h input.h list.h parsecode.h parsing.h query.h regulex.h \
|
||||
remove.h shape.h tools.h unicode.h
|
||||
ORIG_HDR = $(ORIG_HDRCL) bxstring.h cmdline.h discovery.h generate.h input.h list.h parsecode.h parsing.h query.h \
|
||||
regulex.h remove.h shape.h tools.h unicode.h
|
||||
ORIG_GEN = lexer.l parser.y
|
||||
ORIG_NORM = boxes.c cmdline.c discovery.c generate.c input.c list.c parsecode.c parsing.c query.c regulex.c remove.c \
|
||||
shape.c tools.c unicode.c
|
||||
ORIG_NORM = boxes.c bxstring.c cmdline.c discovery.c generate.c input.c list.c parsecode.c parsing.c query.c \
|
||||
regulex.c remove.c shape.c tools.c unicode.c
|
||||
ORIG_SRC = $(ORIG_GEN) $(ORIG_NORM)
|
||||
ORIG_FILES = $(ORIG_SRC) $(ORIG_HDR)
|
||||
|
||||
@ -108,6 +108,7 @@ lex.yy.c lex.yy.h: lexer.l | check_dir
|
||||
$(LEX) --header-file=lex.yy.h $<
|
||||
|
||||
boxes.o: boxes.c boxes.h cmdline.h discovery.h generate.h input.h list.h remove.h tools.h unicode.h config.h | check_dir
|
||||
bxstring.o: bxstring.c bxstring.h tools.h unicode.h config.h | check_dir
|
||||
cmdline.o: cmdline.c cmdline.h boxes.h tools.h config.h | check_dir
|
||||
discovery.o: discovery.c discovery.h boxes.h tools.h config.h | check_dir
|
||||
generate.o: generate.c generate.h boxes.h shape.h tools.h unicode.h config.h | check_dir
|
||||
|
184
src/bxstring.c
Normal file
184
src/bxstring.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License, version 3, as published by the Free Software Foundation.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* The boxes-internal representation of strings.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unictype.h>
|
||||
#include <unistr.h>
|
||||
#include <uniwidth.h>
|
||||
|
||||
#include "bxstring.h"
|
||||
#include "tools.h"
|
||||
#include "unicode.h"
|
||||
|
||||
|
||||
|
||||
bxstr_t *bxs_from_ascii(char *pAscii)
|
||||
{
|
||||
if (pAscii == NULL) {
|
||||
bx_fprintf(stderr, "%s: internal error: from_ascii() called with NULL\n", PROJECT);
|
||||
return NULL;
|
||||
}
|
||||
if (strchr(pAscii, '\t') != NULL) {
|
||||
bx_fprintf(stderr, "%s: internal error: from_ascii() called with tabs: \"%s\"\n", PROJECT, pAscii);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bxstr_t *result = (bxstr_t *) calloc(1, sizeof(bxstr_t));
|
||||
result->memory = u32_strconv_from_arg(pAscii, "ASCII");
|
||||
if (result->memory == NULL) {
|
||||
BFREE(result);
|
||||
return NULL;
|
||||
}
|
||||
result->ascii = strdup(pAscii);
|
||||
|
||||
size_t num_esc = 0;
|
||||
char *ascii_copy;
|
||||
size_t *map;
|
||||
result->num_chars_invisible = count_invisible_chars(result->memory, &num_esc, &ascii_copy, &(map));
|
||||
BFREE(ascii_copy);
|
||||
|
||||
result->num_chars = strlen(pAscii);
|
||||
result->num_columns = result->num_chars;
|
||||
result->num_chars_visible = result->num_chars - result->num_chars_invisible;
|
||||
|
||||
result->indent = strspn(pAscii, " ");
|
||||
result->trailing = my_strrspn(pAscii, " ");
|
||||
|
||||
result->first_char = malloc(result->num_chars_visible * sizeof(size_t));
|
||||
result->visible_char = malloc(result->num_chars_visible * sizeof(size_t));
|
||||
for (size_t i = 0; i < result->num_chars_visible; i++) {
|
||||
result->first_char[i] = i;
|
||||
result->visible_char[i] = i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bxstr_t *bxs_from_unicode(uint32_t *pInput)
|
||||
{
|
||||
if (pInput == NULL) {
|
||||
bx_fprintf(stderr, "%s: internal error: from_unicode() called with NULL\n", PROJECT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bxstr_t *result = (bxstr_t *) calloc(1, sizeof(bxstr_t));
|
||||
result->memory = u32_strdup(pInput);
|
||||
result->num_chars = u32_strlen(pInput);
|
||||
size_t ascii_len = ((size_t) u32_strwidth(pInput, encoding)) + 1; /* often generous, but always enough */
|
||||
result->ascii = (char *) calloc(ascii_len, sizeof(char));
|
||||
size_t map_size = 5;
|
||||
result->first_char = (size_t *) calloc(map_size, sizeof(size_t));
|
||||
result->visible_char = (size_t *) calloc(map_size, sizeof(size_t));
|
||||
char *ascii_ptr = result->ascii;
|
||||
|
||||
const uint32_t *rest = pInput;
|
||||
size_t step_invis = 0;
|
||||
int indent_active = 1;
|
||||
size_t blank_streak = 0;
|
||||
int first_candidate = -1;
|
||||
size_t idx = 0;
|
||||
|
||||
for (ucs4_t c = pInput[0]; c != char_nul; c = rest[0]) {
|
||||
if (result->num_chars_visible >= map_size - 2) {
|
||||
map_size = map_size * 2 + 1;
|
||||
result->first_char = (size_t *) realloc(result->first_char, map_size * sizeof(size_t));
|
||||
result->visible_char = (size_t *) realloc(result->visible_char, map_size * sizeof(size_t));
|
||||
}
|
||||
|
||||
if (c == char_tab) {
|
||||
bx_fprintf(stderr, "%s: internal error: tab encountered in from_unicode()\n", PROJECT);
|
||||
bxs_free(result);
|
||||
return NULL;
|
||||
}
|
||||
else if (c == char_esc) {
|
||||
if (is_csi_reset(rest)) {
|
||||
first_candidate = -1;
|
||||
}
|
||||
else {
|
||||
first_candidate = idx;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int cols = 1;
|
||||
if (is_ascii_printable(c)) {
|
||||
*ascii_ptr = c & 0xff;
|
||||
++ascii_ptr;
|
||||
}
|
||||
else {
|
||||
cols = BMAX(0, uc_width(c, encoding));
|
||||
if (cols > 0) {
|
||||
memset(ascii_ptr, (int) (uc_is_blank(c) ? ' ' : 'x'), cols);
|
||||
ascii_ptr += cols;
|
||||
}
|
||||
}
|
||||
if (uc_is_blank(c)) {
|
||||
if (indent_active) {
|
||||
result->indent += cols;
|
||||
}
|
||||
blank_streak++;
|
||||
}
|
||||
result->num_columns += BMAX(0, cols);
|
||||
result->visible_char[result->num_chars_visible] = idx;
|
||||
result->first_char[result->num_chars_visible] = first_candidate < 0 ? idx : (size_t) first_candidate;
|
||||
first_candidate = -1;
|
||||
}
|
||||
|
||||
if (!uc_is_blank(c) && c != char_esc) {
|
||||
indent_active = 0;
|
||||
blank_streak = 0;
|
||||
}
|
||||
|
||||
rest = advance_next32(rest, &step_invis);
|
||||
|
||||
if (step_invis == 0) {
|
||||
result->num_chars_visible++;
|
||||
idx++;
|
||||
}
|
||||
else {
|
||||
result->num_chars_invisible += step_invis;
|
||||
idx += step_invis;
|
||||
}
|
||||
}
|
||||
|
||||
*ascii_ptr = '\0';
|
||||
result->visible_char[result->num_chars_visible] = idx; // both point to the terminator
|
||||
result->first_char[result->num_chars_visible] = idx;
|
||||
result->trailing = blank_streak;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void bxs_free(bxstr_t *pString)
|
||||
{
|
||||
if (pString != NULL) {
|
||||
BFREE(pString->memory);
|
||||
BFREE(pString->ascii);
|
||||
BFREE(pString->first_char);
|
||||
BFREE(pString->visible_char);
|
||||
BFREE(pString);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* vim: set cindent sw=4: */
|
70
src/bxstring.h
Normal file
70
src/bxstring.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License, version 3, as published by the Free Software Foundation.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* The boxes-internal representation of strings.
|
||||
*/
|
||||
|
||||
#ifndef BXSTRING_H
|
||||
#define BXSTRING_H
|
||||
|
||||
#include <unitypes.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t *memory; /* Immutable. Pointer to the original memory area for the string, NUL terminated */
|
||||
char *ascii; /* Immutable. ASCII version of the original string, tabs expanded, invisible characters removed, multi-byte chars replaced with one or more 'x'. NUL terminated. CHECK remove this eventually */
|
||||
size_t indent; /* Immutable. Number of spaces at the beginning of the original string */
|
||||
size_t num_columns; /* Immutable. Total number of screen columns required to display the string (important for double-wide characters such as Chinese) */
|
||||
size_t num_chars; /* Immutable. Number of characters in the original string (visible + invisible) */
|
||||
size_t num_chars_visible; /* Immutable. Number of visible characters in the original string */
|
||||
size_t num_chars_invisible; /* Immutable. Number of invisible characters in the original string */
|
||||
size_t trailing; /* Immutable. Number of trailing spaces in the original string */
|
||||
size_t *first_char; /* Immutable. Array of index values into `memory` of the first actual character (possibly invisible) of each visible character */
|
||||
size_t *visible_char; /* Immutable. Array of index values into `memory` of the visible characters themselves */
|
||||
int offset_start; /* Number of visible characters to cut from the beginning of the string. Must be smaller than or equal to `indent`. Can be negative, in which case spaces will be prepended. */
|
||||
int offset_end; /* Number of visible characters to cut from the end of the string. Must be smaller than or equal to `trailing`. Can be negative, in which case spaces will be appended. */
|
||||
} bxstr_t;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a `bxstr_t` from an ASCII string.
|
||||
* @param pAscii the ASCII string, which does not contain tabs or ANSI escapes
|
||||
* @return a pointer to a new `bxstr_t` for which memory has been allocated
|
||||
*/
|
||||
bxstr_t *bxs_from_ascii(char *pAscii);
|
||||
|
||||
|
||||
/**
|
||||
* Construct a `bxstr_t` from a Unicode string.
|
||||
* @param pInput the utf-8 encoded string, which may include ANSI escapes, but NOT tabs
|
||||
* @return a pointer to a new `bxstr_t` for which memory has been allocated,
|
||||
* or NULL if `pInput` was NULL or an error occurred (such as tabs encountered)
|
||||
*/
|
||||
bxstr_t *bxs_from_unicode(uint32_t *pInput);
|
||||
|
||||
|
||||
/**
|
||||
* Free the memory allocated by the given `bxstr_t`.
|
||||
* @param pString the `bxstr_t` to free
|
||||
*/
|
||||
void bxs_free(bxstr_t *pString);
|
||||
|
||||
|
||||
/* TODO */
|
||||
|
||||
#endif
|
||||
|
||||
/*EOF*/ /* vim: set cindent sw=4: */
|
150
src/tools.c
150
src/tools.c
@ -18,13 +18,13 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <unictype.h>
|
||||
#include <unistr.h>
|
||||
#include <unitypes.h>
|
||||
@ -32,8 +32,8 @@
|
||||
|
||||
#include "boxes.h"
|
||||
#include "shape.h"
|
||||
#include "unicode.h"
|
||||
#include "tools.h"
|
||||
#include "unicode.h"
|
||||
|
||||
|
||||
|
||||
@ -55,15 +55,20 @@ int strisyes(const char *s)
|
||||
|
||||
if (!strncasecmp("on", s, 3)) {
|
||||
return 1;
|
||||
} else if (!strncasecmp("yes", s, 4)) {
|
||||
}
|
||||
else if (!strncasecmp("yes", s, 4)) {
|
||||
return 1;
|
||||
} else if (!strncasecmp("true", s, 5)) {
|
||||
}
|
||||
else if (!strncasecmp("true", s, 5)) {
|
||||
return 1;
|
||||
} else if (!strncmp("1", s, 2)) {
|
||||
}
|
||||
else if (!strncmp("1", s, 2)) {
|
||||
return 1;
|
||||
} else if (!strncasecmp("t", s, 2)) {
|
||||
}
|
||||
else if (!strncasecmp("t", s, 2)) {
|
||||
return 1;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -88,15 +93,20 @@ int strisno(const char *s)
|
||||
|
||||
if (!strncasecmp("off", s, 4)) {
|
||||
return 1;
|
||||
} else if (!strncasecmp("no", s, 3)) {
|
||||
}
|
||||
else if (!strncasecmp("no", s, 3)) {
|
||||
return 1;
|
||||
} else if (!strncasecmp("false", s, 6)) {
|
||||
}
|
||||
else if (!strncasecmp("false", s, 6)) {
|
||||
return 1;
|
||||
} else if (!strncmp("0", s, 2)) {
|
||||
}
|
||||
else if (!strncmp("0", s, 2)) {
|
||||
return 1;
|
||||
} else if (!strncasecmp("f", s, 2)) {
|
||||
}
|
||||
else if (!strncasecmp("f", s, 2)) {
|
||||
return 1;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -121,7 +131,7 @@ void concat_strings(char *dst, int max_len, int count, ...)
|
||||
va_list va;
|
||||
const char *src;
|
||||
|
||||
va_start (va, count);
|
||||
va_start(va, count);
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
@ -139,12 +149,11 @@ void concat_strings(char *dst, int max_len, int count, ...)
|
||||
* Loop over all input strings.
|
||||
*/
|
||||
while (count-- > 0 && max_len > 1) {
|
||||
|
||||
/*
|
||||
* Grab an input string pointer. If it's NULL, skip it (eg. treat
|
||||
* it as empty.
|
||||
*/
|
||||
src = va_arg (va, const char *);
|
||||
src = va_arg(va, const char *);
|
||||
|
||||
if (src == NULL) {
|
||||
continue;
|
||||
@ -159,7 +168,7 @@ void concat_strings(char *dst, int max_len, int count, ...)
|
||||
}
|
||||
}
|
||||
|
||||
va_end (va);
|
||||
va_end(va);
|
||||
|
||||
/*
|
||||
* Terminate the string with an ASCII NUL.
|
||||
@ -179,27 +188,27 @@ char *concat_strings_alloc(size_t count, ...)
|
||||
const char *src;
|
||||
va_list va;
|
||||
|
||||
va_start (va, count);
|
||||
va_start(va, count);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
src = va_arg (va, const char *);
|
||||
src = va_arg(va, const char *);
|
||||
if (src != NULL) {
|
||||
total_len += strlen(src);
|
||||
}
|
||||
}
|
||||
va_end (va);
|
||||
va_end(va);
|
||||
|
||||
char *result = malloc(total_len + 1);
|
||||
char *p = result;
|
||||
|
||||
va_start (va, count);
|
||||
va_start(va, count);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
src = va_arg (va, const char *);
|
||||
src = va_arg(va, const char *);
|
||||
if (src != NULL && src[0] != '\0') {
|
||||
strcpy(p, src);
|
||||
p += strlen(src);
|
||||
}
|
||||
}
|
||||
va_end (va);
|
||||
va_end(va);
|
||||
|
||||
*p = '\0';
|
||||
return result;
|
||||
@ -236,8 +245,8 @@ int empty_line(const line_t *line)
|
||||
|
||||
|
||||
|
||||
size_t expand_tabs_into(const uint32_t *input_buffer, const int tabstop, uint32_t **text,
|
||||
size_t **tabpos, size_t *tabpos_len)
|
||||
size_t expand_tabs_into(const uint32_t *input_buffer, const int tabstop, uint32_t **text, size_t **tabpos,
|
||||
size_t *tabpos_len)
|
||||
/*
|
||||
* Expand tab chars in input_buffer and store result in text.
|
||||
*
|
||||
@ -257,9 +266,9 @@ size_t expand_tabs_into(const uint32_t *input_buffer, const int tabstop, uint32_
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
{
|
||||
static uint32_t temp[LINE_MAX_BYTES + 100]; /* work string */
|
||||
size_t io; /* character position in work string */
|
||||
size_t tabnum = 0; /* index of the current tab */
|
||||
static uint32_t temp[LINE_MAX_BYTES + 100]; /* work string */
|
||||
size_t io; /* character position in work string */
|
||||
size_t tabnum = 0; /* index of the current tab */
|
||||
|
||||
*text = NULL;
|
||||
*tabpos = NULL;
|
||||
@ -281,7 +290,7 @@ size_t expand_tabs_into(const uint32_t *input_buffer, const int tabstop, uint32_
|
||||
if (*tabpos_len > 0) {
|
||||
*tabpos = (size_t *) calloc((*tabpos_len) + 1, sizeof(size_t));
|
||||
if (*tabpos == NULL) {
|
||||
return 0; /* out of memory */
|
||||
return 0; /* out of memory */
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,9 +331,7 @@ void btrim(char *text, size_t *len)
|
||||
{
|
||||
long idx = (long) (*len) - 1;
|
||||
|
||||
while (idx >= 0 && (text[idx] == '\n' || text[idx] == '\r'
|
||||
|| text[idx] == '\t' || text[idx] == ' ')) /**/
|
||||
{
|
||||
while (idx >= 0 && (text[idx] == '\n' || text[idx] == '\r' || text[idx] == '\t' || text[idx] == ' ')) {
|
||||
text[idx--] = '\0';
|
||||
}
|
||||
|
||||
@ -415,7 +422,8 @@ char *my_strnrstr(const char *s1, const char *s2, const size_t s2_len, int skip)
|
||||
if (comp == 0) {
|
||||
if (skip--) {
|
||||
--p;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
@ -429,6 +437,26 @@ char *my_strnrstr(const char *s1, const char *s2, const size_t s2_len, int skip)
|
||||
|
||||
|
||||
|
||||
size_t my_strrspn(const char *s, const char *accept)
|
||||
{
|
||||
if (!s || *s == '\0') {
|
||||
return 0;
|
||||
}
|
||||
if (!accept || *accept == '\0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = strlen(s) - 1; i >= 0; i--) {
|
||||
size_t idx = (size_t) i;
|
||||
if (strchr(accept, s[idx]) == NULL) {
|
||||
return strlen(s) - (idx + 1);
|
||||
}
|
||||
}
|
||||
return strlen(s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
char *tabbify_indent(const size_t lineno, char *indentspc, const size_t indentspc_len)
|
||||
/*
|
||||
* Checks if tab expansion mode is "keep", and if so, calculates a new
|
||||
@ -470,11 +498,9 @@ char *tabbify_indent(const size_t lineno, char *indentspc, const size_t indentsp
|
||||
result[indentspc_len] = '\0';
|
||||
result_len = indentspc_len;
|
||||
|
||||
for (i = 0; i < input.lines[lineno].tabpos_len
|
||||
&& input.lines[lineno].tabpos[i] < indentspc_len; ++i) /**/
|
||||
{
|
||||
for (i = 0; i < input.lines[lineno].tabpos_len && input.lines[lineno].tabpos[i] < indentspc_len; ++i) {
|
||||
size_t tpos = input.lines[lineno].tabpos[i];
|
||||
size_t nspc = opt.tabstop - (tpos % opt.tabstop); /* no of spcs covered by tab */
|
||||
size_t nspc = opt.tabstop - (tpos % opt.tabstop); /* no of spcs covered by tab */
|
||||
if (tpos + nspc > input.indent) {
|
||||
break;
|
||||
}
|
||||
@ -527,7 +553,8 @@ void print_input_lines(const char *heading)
|
||||
fprintf(stderr, "%d%s", (int) input.lines[i].posmap[j], j == (input.lines[i].len - 1) ? "" : ", ");
|
||||
}
|
||||
fprintf(stderr, "]\n");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "null\n");
|
||||
}
|
||||
}
|
||||
@ -551,10 +578,10 @@ void print_input_lines(const char *heading)
|
||||
* @param <posmap> pointer to the position map, which maps each position in <ascii> to a position in <s>
|
||||
* @returns the number of invisible characters in <s>
|
||||
*/
|
||||
static size_t count_invisible_chars(const uint32_t *s, size_t *num_esc, char **ascii, size_t **posmap)
|
||||
size_t count_invisible_chars(const uint32_t *s, size_t *num_esc, char **ascii, size_t **posmap)
|
||||
{
|
||||
size_t invis = 0; /* counts invisible column positions */
|
||||
*num_esc = 0; /* counts the number of escape sequences found */
|
||||
size_t invis = 0; /* counts invisible column positions */
|
||||
*num_esc = 0; /* counts the number of escape sequences found */
|
||||
|
||||
if (is_empty(s)) {
|
||||
(*ascii) = (char *) strdup("");
|
||||
@ -565,8 +592,8 @@ static size_t count_invisible_chars(const uint32_t *s, size_t *num_esc, char **a
|
||||
size_t buflen = (size_t) u32_strwidth(s, encoding) + 1;
|
||||
size_t map_size = BMAX((size_t) 5, buflen);
|
||||
size_t map_idx = 0;
|
||||
size_t *map = (size_t *) calloc(map_size, sizeof(size_t)); /* might not be enough if many double-wide chars */
|
||||
(*ascii) = (char *) calloc(buflen, sizeof(char)); /* maybe a little too much, but certainly enough */
|
||||
size_t *map = (size_t *) calloc(map_size, sizeof(size_t)); /* might not be enough if many double-wide chars */
|
||||
(*ascii) = (char *) calloc(buflen, sizeof(char)); /* maybe a little too much, but certainly enough */
|
||||
char *p = *ascii;
|
||||
|
||||
size_t mb_idx = 0;
|
||||
@ -611,6 +638,41 @@ static size_t count_invisible_chars(const uint32_t *s, size_t *num_esc, char **a
|
||||
|
||||
|
||||
|
||||
int is_csi_reset(const uint32_t *csi)
|
||||
{
|
||||
ucs4_t puc = '\0';
|
||||
const uint32_t *rest = csi;
|
||||
size_t csi_pos = 0;
|
||||
while ((rest = u32_next(&puc, rest))) {
|
||||
switch(csi_pos) {
|
||||
case 0:
|
||||
if (puc != char_esc) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (puc != '[' && puc != '(') {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (puc != '0') {
|
||||
if (puc >= 0x40 && puc <= 0x7e) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return (puc >= 0x40 && puc <= 0x7e) ? 1 : 0;
|
||||
}
|
||||
csi_pos++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void analyze_line_ascii(input_t *input_ptr, line_t *line)
|
||||
{
|
||||
size_t num_esc = 0;
|
||||
@ -742,4 +804,4 @@ void bx_fprintf(FILE *stream, const char *format, ...)
|
||||
}
|
||||
|
||||
|
||||
/*EOF*/ /* vim: set sw=4: */
|
||||
/* vim: set sw=4: */
|
||||
|
30
src/tools.h
30
src/tools.h
@ -33,10 +33,10 @@
|
||||
})
|
||||
|
||||
#define BFREE(p) { /* free memory and clear pointer */ \
|
||||
if (p) { \
|
||||
free((void *) p); \
|
||||
(p) = NULL; \
|
||||
} \
|
||||
if (p) { \
|
||||
free((void *) (p)); \
|
||||
(p) = NULL; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@ -49,8 +49,16 @@ void btrim(char *text, size_t *len);
|
||||
|
||||
void btrim32(uint32_t *text, size_t *len);
|
||||
|
||||
char *my_strnrstr(const char *s1, const char *s2, const size_t s2_len,
|
||||
int skip);
|
||||
char *my_strnrstr(const char *s1, const char *s2, const size_t s2_len, int skip);
|
||||
|
||||
/**
|
||||
* Calculates the length (in bytes) of the segment at the end of `s` which consists entirely of bytes in `accept`.
|
||||
* This is like `strspn()`, but from the end of the string.
|
||||
* @param <s> the string to search
|
||||
* @param <accept> acceptable characters that form the trailing segment
|
||||
* @return the number of bytes found as described above
|
||||
*/
|
||||
size_t my_strrspn(const char *s, const char *accept);
|
||||
|
||||
int strisyes(const char *s);
|
||||
|
||||
@ -75,6 +83,16 @@ void print_input_lines(const char *heading);
|
||||
|
||||
void analyze_line_ascii(input_t *input_ptr, line_t *line);
|
||||
|
||||
size_t count_invisible_chars(const uint32_t *s, size_t *num_esc, char **ascii, size_t **posmap);
|
||||
|
||||
/**
|
||||
* Determine whether the given sequence of characters is a CSI (also called "escape sequence") that resets all
|
||||
* modifications, typically `ESC[0m`.
|
||||
* @param csi a pointer into a zero-terminated UTF-32 string
|
||||
* @returns 1 if true, 0 if false
|
||||
*/
|
||||
int is_csi_reset(const uint32_t *csi);
|
||||
|
||||
int array_contains(char **array, const size_t array_len, const char *s);
|
||||
|
||||
/**
|
||||
|
@ -28,7 +28,7 @@
|
||||
* However, people might not conform to this, so we use ISO_8859-15 as a reasonable superset. */
|
||||
extern const char *config_encoding;
|
||||
|
||||
/** the character encoding of input (and output) text */
|
||||
/* effective character encoding of input and output text */
|
||||
extern const char *encoding;
|
||||
|
||||
/** ucs4_t character '\t' (tab) */
|
||||
|
@ -19,7 +19,7 @@ SRC_DIR = ../src
|
||||
UTEST_DIR = ../utest
|
||||
VPATH = $(SRC_DIR):$(SRC_DIR)/misc:$(UTEST_DIR)
|
||||
|
||||
UTEST_NORM = global_mock.c cmdline_test.c tools_test.c regulex_test.o main.o
|
||||
UTEST_NORM = global_mock.c bxstring_test.o cmdline_test.c tools_test.c regulex_test.o main.o utest_tools.o
|
||||
MOCKS = bx_fprintf
|
||||
|
||||
.PHONY: check_dir flags_unix flags_win32 flags_ utest
|
||||
@ -66,8 +66,10 @@ unittest.exe: $(UTEST_OBJ) | check_dir
|
||||
-lkernel32 -l:libunistring.a -l:libpcre2-32.a -l:libiconv.a -l:libcmocka.dll.a
|
||||
|
||||
|
||||
global_mock.o: global_mock.c global_mock.h boxes.h unicode.h config.h | check_dir
|
||||
cmdline_test.o: cmdline_test.c cmdline_test.h global_mock.h boxes.h cmdline.h config.h | check_dir
|
||||
tools_test.o: tools_test.c tools_test.h tools.h config.h | check_dir
|
||||
regulex_test.o: regulex_test.c regulex_test.h global_mock.h regulex.h config.h | check_dir
|
||||
main.o: main.c global_mock.h tools_test.h regulex_test.h config.h | check_dir
|
||||
global_mock.o: global_mock.c global_mock.h boxes.h unicode.h config.h | check_dir
|
||||
bxstring_test.o: bxstring_test.c bxstring_test.h global_mock.h bxstring.h config.h | check_dir
|
||||
cmdline_test.o: cmdline_test.c cmdline_test.h global_mock.h boxes.h cmdline.h config.h | check_dir
|
||||
tools_test.o: tools_test.c tools_test.h tools.h config.h | check_dir
|
||||
regulex_test.o: regulex_test.c regulex_test.h global_mock.h regulex.h config.h | check_dir
|
||||
main.o: main.c global_mock.h tools_test.h regulex_test.h config.h | check_dir
|
||||
utest_tools.o: utest_tools.c utest_tools.h config.h | check_dir
|
||||
|
161
utest/bxstring_test.c
Normal file
161
utest/bxstring_test.c
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License, version 3, as published by the Free Software Foundation.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* Unit tests of the 'bxstring' module
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include "bxstring.h"
|
||||
#include "bxstring_test.h"
|
||||
#include "global_mock.h"
|
||||
#include "tools.h"
|
||||
#include "unicode.h"
|
||||
#include "utest_tools.h"
|
||||
|
||||
|
||||
|
||||
void test_ascii_simple(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
bxstr_t *actual = bxs_from_ascii("foo");
|
||||
|
||||
assert_non_null(actual);
|
||||
assert_non_null(actual->memory);
|
||||
assert_string_equal("foo", actual->ascii);
|
||||
assert_int_equal(0, (int) actual->indent);
|
||||
assert_int_equal(3, (int) actual->num_columns);
|
||||
assert_int_equal(3, (int) actual->num_chars);
|
||||
assert_int_equal(3, (int) actual->num_chars_visible);
|
||||
assert_int_equal(0, (int) actual->num_chars_invisible);
|
||||
assert_int_equal(0, (int) actual->trailing);
|
||||
int expected_indexes[] = {0, 1, 2};
|
||||
assert_array_equal(expected_indexes, actual->first_char, 3);
|
||||
assert_array_equal(expected_indexes, actual->visible_char, 3);
|
||||
assert_int_equal(0, actual->offset_start);
|
||||
assert_int_equal(0, actual->offset_end);
|
||||
|
||||
bxs_free(actual);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void test_ansi_unicode_book(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
uint32_t *ustr32 = u32_strconv_from_arg(
|
||||
"\x1b[38;5;203m \x1b[0m \x1b[38;5;198m x\x1b[0mxx\x1b[38;5;208m\xc3\xa4\x1b[0m\x1b[38;5;203mb\x1b[0m ",
|
||||
"UTF-8");
|
||||
assert_non_null(ustr32);
|
||||
bxstr_t *actual = bxs_from_unicode(ustr32);
|
||||
|
||||
assert_non_null(actual);
|
||||
assert_non_null(actual->memory);
|
||||
assert_string_equal(" xxxxb ", actual->ascii); // 'ä' replaced by 'x'
|
||||
assert_int_equal(4, (int) actual->indent);
|
||||
assert_int_equal(10, (int) actual->num_columns);
|
||||
assert_int_equal(70, (int) actual->num_chars);
|
||||
assert_int_equal(10, (int) actual->num_chars_visible);
|
||||
assert_int_equal(60, (int) actual->num_chars_invisible);
|
||||
assert_int_equal(1, (int) actual->trailing);
|
||||
int expected_firstchar_idx[] = {0, 16, 17, 18, 30, 35, 36, 37, 53, 69, 70};
|
||||
assert_array_equal(expected_firstchar_idx, actual->first_char, 11);
|
||||
int expected_vischar_idx[] = {11, 16, 17, 29, 30, 35, 36, 48, 64, 69, 70};
|
||||
assert_array_equal(expected_vischar_idx, actual->visible_char, 11);
|
||||
assert_int_equal(0, actual->offset_start);
|
||||
assert_int_equal(0, actual->offset_end);
|
||||
|
||||
BFREE(ustr32);
|
||||
bxs_free(actual);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void test_ansi_unicode_space_kinds(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
uint32_t *ustr32 = u32_strconv_from_arg(
|
||||
"\xe2\x80\x83\xe2\x80\x82 X", /* em-space, en-space, space, x */
|
||||
"UTF-8");
|
||||
assert_non_null(ustr32);
|
||||
bxstr_t *actual = bxs_from_unicode(ustr32);
|
||||
|
||||
assert_non_null(actual);
|
||||
assert_non_null(actual->memory);
|
||||
assert_string_equal(" X", actual->ascii);
|
||||
assert_int_equal(3, (int) actual->indent);
|
||||
assert_int_equal(4, (int) actual->num_columns);
|
||||
assert_int_equal(4, (int) actual->num_chars);
|
||||
assert_int_equal(4, (int) actual->num_chars_visible);
|
||||
assert_int_equal(0, (int) actual->num_chars_invisible);
|
||||
assert_int_equal(0, (int) actual->trailing);
|
||||
int expected_firstchar_idx[] = {0, 1, 2, 3};
|
||||
assert_array_equal(expected_firstchar_idx, actual->first_char, 4);
|
||||
int expected_vischar_idx[] = {0, 1, 2, 3};
|
||||
assert_array_equal(expected_vischar_idx, actual->visible_char, 4);
|
||||
assert_int_equal(0, actual->offset_start);
|
||||
assert_int_equal(0, actual->offset_end);
|
||||
|
||||
BFREE(ustr32);
|
||||
bxs_free(actual);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void test_ansi_unicode_chinese(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
uint32_t *ustr32 = u32_strconv_from_arg(
|
||||
"\xe5\x85\xac\xe7\x88\xb8\xe8\xa6\x81\xe9\x81\x93\xef\xbc\x81", /* 公爸要道! */
|
||||
"UTF-8");
|
||||
assert_non_null(ustr32);
|
||||
bxstr_t *actual = bxs_from_unicode(ustr32);
|
||||
|
||||
assert_non_null(actual);
|
||||
assert_non_null(actual->memory);
|
||||
assert_string_equal("xxxxxxxxxx", actual->ascii);
|
||||
assert_int_equal(0, (int) actual->indent);
|
||||
assert_int_equal(10, (int) actual->num_columns);
|
||||
assert_int_equal(5, (int) actual->num_chars);
|
||||
assert_int_equal(5, (int) actual->num_chars_visible);
|
||||
assert_int_equal(0, (int) actual->num_chars_invisible);
|
||||
assert_int_equal(0, (int) actual->trailing);
|
||||
int expected_firstchar_idx[] = {0, 1, 2, 3, 4};
|
||||
assert_array_equal(expected_firstchar_idx, actual->first_char, 5);
|
||||
int expected_vischar_idx[] = {0, 1, 2, 3, 4};
|
||||
assert_array_equal(expected_vischar_idx, actual->visible_char, 5);
|
||||
assert_int_equal(0, actual->offset_start);
|
||||
assert_int_equal(0, actual->offset_end);
|
||||
|
||||
BFREE(ustr32);
|
||||
bxs_free(actual);
|
||||
}
|
||||
|
||||
|
||||
// TODO test case for incomplete/broken escape sequences
|
||||
|
||||
|
||||
/* vim: set cindent sw=4: */
|
32
utest/bxstring_test.h
Normal file
32
utest/bxstring_test.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License, version 3, as published by the Free Software Foundation.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* Unit tests of the 'cmdline' module
|
||||
*/
|
||||
|
||||
#ifndef BXSTRING_TEST_H
|
||||
#define BXSTRING_TEST_H
|
||||
|
||||
|
||||
void test_ascii_simple(void **state);
|
||||
void test_ansi_unicode_book(void **state);
|
||||
void test_ansi_unicode_space_kinds(void **state);
|
||||
void test_ansi_unicode_chinese(void **state);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* vim: set cindent sw=4: */
|
@ -61,7 +61,7 @@ void collect_reset()
|
||||
|
||||
/**
|
||||
* Mock of the `bx_fprintf()` function which records its output instead of printing it. Assumes that no output string
|
||||
* will be longer than 512 characters.
|
||||
* of our test cases will be longer than 512 characters.
|
||||
* @param stream `stdout` or `stderr`
|
||||
* @param format the format string, followed by the arguments
|
||||
*/
|
||||
|
14
utest/main.c
14
utest/main.c
@ -24,6 +24,7 @@
|
||||
#include <cmocka.h>
|
||||
|
||||
#include "global_mock.h"
|
||||
#include "bxstring_test.h"
|
||||
#include "cmdline_test.h"
|
||||
#include "tools_test.h"
|
||||
#include "regulex_test.h"
|
||||
@ -91,13 +92,24 @@ int main(void)
|
||||
cmocka_unit_test(test_strisyes_true),
|
||||
cmocka_unit_test(test_strisyes_false),
|
||||
cmocka_unit_test(test_strisno_true),
|
||||
cmocka_unit_test(test_strisno_false)
|
||||
cmocka_unit_test(test_strisno_false),
|
||||
cmocka_unit_test(test_my_strrspn_edge),
|
||||
cmocka_unit_test(test_my_strrspn),
|
||||
cmocka_unit_test(test_is_csi_reset)
|
||||
};
|
||||
|
||||
const struct CMUnitTest bxstring_tests[] = {
|
||||
cmocka_unit_test_setup(test_ascii_simple, beforeTest),
|
||||
cmocka_unit_test_setup(test_ansi_unicode_book, beforeTest),
|
||||
cmocka_unit_test_setup(test_ansi_unicode_space_kinds, beforeTest),
|
||||
cmocka_unit_test_setup(test_ansi_unicode_chinese, beforeTest)
|
||||
};
|
||||
|
||||
int num_failed = 0;
|
||||
num_failed += cmocka_run_group_tests(cmdline_tests, NULL, NULL);
|
||||
num_failed += cmocka_run_group_tests(regulex_tests, NULL, NULL);
|
||||
num_failed += cmocka_run_group_tests(tools_tests, NULL, NULL);
|
||||
num_failed += cmocka_run_group_tests(bxstring_tests, NULL, NULL);
|
||||
|
||||
teardown();
|
||||
return num_failed;
|
||||
|
@ -18,17 +18,21 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include "tools.h"
|
||||
#include "tools_test.h"
|
||||
#include "unicode.h"
|
||||
|
||||
|
||||
void test_strisyes_true(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_int_equal(1, strisyes("On"));
|
||||
assert_int_equal(1, strisyes("on"));
|
||||
@ -44,7 +48,7 @@ void test_strisyes_true(void **state)
|
||||
|
||||
void test_strisyes_false(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_int_equal(0, strisyes(NULL));
|
||||
assert_int_equal(0, strisyes(""));
|
||||
@ -63,7 +67,7 @@ void test_strisyes_false(void **state)
|
||||
|
||||
void test_strisno_true(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_int_equal(1, strisno("off"));
|
||||
assert_int_equal(1, strisno("Off"));
|
||||
@ -79,7 +83,7 @@ void test_strisno_true(void **state)
|
||||
|
||||
void test_strisno_false(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_int_equal(0, strisno(NULL));
|
||||
assert_int_equal(0, strisno(""));
|
||||
@ -96,4 +100,49 @@ void test_strisno_false(void **state)
|
||||
}
|
||||
|
||||
|
||||
/*EOF*/ /* vim: set cindent sw=4: */
|
||||
void test_my_strrspn_edge(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_int_equal(0, (int) my_strrspn(NULL, "abc"));
|
||||
assert_int_equal(0, (int) my_strrspn("", "abc"));
|
||||
assert_int_equal(0, (int) my_strrspn("abc", NULL));
|
||||
assert_int_equal(0, (int) my_strrspn("abc", ""));
|
||||
assert_int_equal(0, (int) my_strrspn(NULL, NULL));
|
||||
}
|
||||
|
||||
|
||||
void test_my_strrspn(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_int_equal(2, (int) my_strrspn("foo", "o"));
|
||||
assert_int_equal(0, (int) my_strrspn("foo", "ABC"));
|
||||
assert_int_equal(3, (int) my_strrspn("foo", "foobar"));
|
||||
assert_int_equal(1, (int) my_strrspn("foo ", " "));
|
||||
assert_int_equal(1, (int) my_strrspn("a", "a"));
|
||||
assert_int_equal(0, (int) my_strrspn("a", "A"));
|
||||
assert_int_equal(2, (int) my_strrspn("axxaa", "a"));
|
||||
}
|
||||
|
||||
|
||||
void test_is_csi_reset(void **state)
|
||||
{
|
||||
(void) state; /* unused */
|
||||
|
||||
assert_int_equal(1, is_csi_reset(u32_strconv_from_arg("\x1b[0m", "ASCII")));
|
||||
assert_int_equal(1, is_csi_reset(u32_strconv_from_arg("\x1b[m", "ASCII")));
|
||||
assert_int_equal(1, is_csi_reset(u32_strconv_from_arg("\x1b(0m", "ASCII")));
|
||||
assert_int_equal(1, is_csi_reset(u32_strconv_from_arg("\x1b(m", "ASCII")));
|
||||
assert_int_equal(1, is_csi_reset(u32_strconv_from_arg("\x1b[0m foo", "ASCII")));
|
||||
|
||||
assert_int_equal(0, is_csi_reset(u32_strconv_from_arg("", "ASCII")));
|
||||
assert_int_equal(0, is_csi_reset(u32_strconv_from_arg("normal", "ASCII")));
|
||||
assert_int_equal(0, is_csi_reset(u32_strconv_from_arg("\x1b[", "ASCII")));
|
||||
assert_int_equal(0, is_csi_reset(u32_strconv_from_arg("not yet \x1b[0m", "ASCII")));
|
||||
assert_int_equal(0, is_csi_reset(u32_strconv_from_arg("\x1b[38;5;203m", "ASCII")));
|
||||
assert_int_equal(0, is_csi_reset(u32_strconv_from_arg("\x1b_BROKEN", "ASCII")));
|
||||
}
|
||||
|
||||
|
||||
/* vim: set cindent sw=4: */
|
||||
|
@ -27,6 +27,11 @@ void test_strisyes_false(void **state);
|
||||
void test_strisno_true(void **state);
|
||||
void test_strisno_false(void **state);
|
||||
|
||||
void test_my_strrspn_edge(void **state);
|
||||
void test_my_strrspn(void **state);
|
||||
|
||||
void test_is_csi_reset(void **state);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
86
utest/utest_tools.c
Normal file
86
utest/utest_tools.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License, version 3, as published by the Free Software Foundation.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* Helper functions for all the unit tests.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "utest_tools.h"
|
||||
|
||||
|
||||
|
||||
void assert_array_equal(int p_expected[], size_t *p_actual, size_t p_len_expected)
|
||||
{
|
||||
if (p_expected == NULL && p_actual == NULL) {
|
||||
assert_int_equal(0, p_len_expected);
|
||||
return;
|
||||
}
|
||||
if (p_expected == NULL) {
|
||||
assert_null(p_actual);
|
||||
assert_int_equal(0, p_len_expected);
|
||||
}
|
||||
if (p_actual == NULL) {
|
||||
assert_null(p_expected);
|
||||
assert_int_equal(0, p_len_expected);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < p_len_expected; i++) {
|
||||
assert_int_equal(p_expected[i], (int) p_actual[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void print_array_i(int p_array[], size_t p_len)
|
||||
{
|
||||
if (p_array != NULL) {
|
||||
printf("[");
|
||||
for (size_t i = 0; i < p_len; i++) {
|
||||
printf("%d%s", p_array[i], i < p_len - 1 ? ", " : "");
|
||||
}
|
||||
printf("]\n");
|
||||
}
|
||||
else {
|
||||
printf("NULL\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void print_array_s(size_t p_array[], size_t p_len)
|
||||
{
|
||||
if (p_array != NULL) {
|
||||
printf("[");
|
||||
for (size_t i = 0; i < p_len; i++) {
|
||||
printf("%d%s", (int) p_array[i], i < p_len - 1 ? ", " : "");
|
||||
}
|
||||
printf("]\n");
|
||||
}
|
||||
else {
|
||||
printf("NULL\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* vim: set cindent sw=4: */
|
44
utest/utest_tools.h
Normal file
44
utest/utest_tools.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License, version 3, as published by the Free Software Foundation.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* Helper functions for all the unit tests.
|
||||
*/
|
||||
|
||||
#ifndef UTEST_TOOLS_H
|
||||
#define UTEST_TOOLS_H
|
||||
|
||||
|
||||
/**
|
||||
* Assert that the two given arrays have the same contents.
|
||||
* @param <p_expected> the expected array
|
||||
* @param <p_actual> the actual array
|
||||
* @param <p_len_expected> number of elements in `p_expected`
|
||||
*/
|
||||
void assert_array_equal(int p_expected[], size_t *p_actual, size_t p_len_expected);
|
||||
|
||||
|
||||
/**
|
||||
* Print the contents of the given array for debugging purposes.
|
||||
* @param p_array the array to print
|
||||
* @param p_len the number of elements in the array
|
||||
*/
|
||||
void print_array_i(int p_array[], size_t p_len);
|
||||
|
||||
void print_array_s(size_t p_array[], size_t p_len);
|
||||
|
||||
#endif
|
||||
|
||||
/*EOF*/ /* vim: set cindent sw=4: */
|
Loading…
Reference in New Issue
Block a user