Skip to content

Instantly share code, notes, and snippets.

@peterdelevoryas
Created January 11, 2022 23:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peterdelevoryas/aa4c4cf3fd812a817ffaa66a58a68cf6 to your computer and use it in GitHub Desktop.
Save peterdelevoryas/aa4c4cf3fd812a817ffaa66a58a68cf6 to your computer and use it in GitHub Desktop.
Unit test
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define ESCAPE "\x1B"
#define ESC_BAT ESCAPE"B"
#define ESC_MCU_BL_VER ESCAPE"U"
#define ESC_MCU_RUN_VER ESCAPE"R"
#define ESC_ALT ESCAPE"[5;7m"
#define ESC_RST ESCAPE"[m"
#define ESC_NOR ESCAPE"[0m"
#define LINE_DELIMITER '\x1F'
#ifdef CONFIG_FBY3
#define FRAME_BUFF_SIZE 5120
#else
#define FRAME_BUFF_SIZE 4096
#endif
#define FRAME_PAGE_BUF_SIZE 256
#define MAX_UART_SEL_NAME_SIZE 16
struct frame {
char title[32];
size_t max_size;
size_t max_page;
char *buf;
uint16_t idx_head, idx_tail;
uint8_t line_per_page;
uint8_t line_width;
uint16_t lines, pages;
uint8_t esc_sts;
uint8_t overwrite;
time_t mtime;
int (*init)(struct frame *self, size_t size);
int (*append)(struct frame *self, char *string, int indent);
int (*insert)(struct frame *self, char *string, int indent);
int (*getPage)(struct frame *self, int page, char *page_buf, size_t page_buf_size);
int (*isFull)(struct frame *self);
int (*isEscSeq)(struct frame *self, char chr);
int (*parse)(struct frame *self, char *buf, size_t buf_size, char *input, int indent);
};
// return 0 on seccuess
static int frame_init (struct frame *self, size_t size) {
// Reset status
self->idx_head = self->idx_tail = 0;
self->lines = 0;
self->esc_sts = 0;
self->pages = 1;
if (self->buf != NULL && self->max_size == size) {
// reinit
return 0;
}
if (self->buf != NULL && self->max_size != size){
free(self->buf);
}
// Initialize Configuration
self->title[0] = '\0';
self->buf = malloc(size);
self->max_size = size;
self->max_page = size;
self->line_per_page = 7;
self->line_width = 16;
self->overwrite = 0;
if (self->buf)
return 0;
else
return -1;
}
static const char *find_esc(const char *buf, int blen, const char *esc, size_t elen) {
const char *ptr;
// to find the last CSI-codes
if (!(ptr = memrchr(buf, esc[0], blen)))
return NULL;
if ((blen - (ptr - buf) >= elen) && !memcmp(ptr, esc, elen))
return ptr;
return NULL;
}
void print_string(const char *s)
{
int is_escape = 0;
for (int i = 0; s[i]; i++) {
char c = s[i];
switch (c) {
case 'a'...'l':
case 'n'...'z':
if (is_escape) {
printf(" ");
}
printf("%c", c);
is_escape = 0;
break;
case '[':
case ';':
case '0'...'9':
case 'm':
if (!is_escape) {
printf(" ");
}
printf("%c", c);
is_escape = 1;
break;
default:
printf(" \\x%02x", (unsigned char)c);
is_escape = 1;
break;
}
}
}
// return 0 on seccuess
static int frame_append (struct frame *self, char *string, int indent)
{
const size_t buf_size = 64;
char buf[buf_size];
char *ptr;
int ret;
ret = self->parse(self, buf, buf_size, string, indent);
if (ret < 0)
return ret;
strcpy(buf, string);
print_string(buf);
printf("\n");
for (ptr = buf; *ptr != '\0'; ptr++) {
if (self->isFull(self)) {
if (self->overwrite) {
if (self->buf[self->idx_head] == LINE_DELIMITER)
self->lines--;
self->idx_head = (self->idx_head + 1) % self->max_size;
} else
return -1;
}
if (*ptr == LINE_DELIMITER) {
self->lines++;
// workaround when Blink CSI-codes spread 2 pages,
// add ESC_RST to the end of previous page,
// add ESC_ALT to the start of next page
if (!(self->lines % self->line_per_page)) {
const char *esc = find_esc(buf, ptr - buf, ESC_ALT, strlen(ESC_ALT));
if (esc != NULL) {
esc += strlen(ESC_ALT);
if (!find_esc(esc, ptr - esc, ESC_RST, strlen(ESC_RST))) {
char tmp[16], *ptmp;
snprintf(tmp, sizeof(tmp), ESC_RST"%c"ESC_ALT, LINE_DELIMITER);
for (ptmp = tmp; *ptmp; ptmp++) {
if (self->isFull(self)) {
if (!self->overwrite) {
return -1;
}
if (self->buf[self->idx_head] == LINE_DELIMITER)
self->lines--;
self->idx_head = (self->idx_head + 1) % self->max_size;
}
self->buf[self->idx_tail] = *ptmp;
self->idx_tail = (self->idx_tail + 1) % self->max_size;
}
continue;
}
}
}
}
self->buf[self->idx_tail] = *ptr;
self->idx_tail = (self->idx_tail + 1) % self->max_size;
}
self->pages = (self->lines / self->line_per_page) +
((self->lines % self->line_per_page)?1:0);
if (self->pages > self->max_page)
self->pages = self->max_page;
return 0;
}
int do_nothing(void) {
return 0;
}
void unit_test(const char *input) {
struct frame f;
memset(&f, 0, sizeof(f));
f.isFull = (void*)do_nothing;
f.parse = (void*)do_nothing;
frame_init(&f, 32);
f.lines = f.line_per_page - 1;
char s[256];
int n = sprintf(s, "%s", input);
while ((n + 1) % f.line_per_page) {
s[n++] = 'a';
}
s[n++] = LINE_DELIMITER;
s[n] = '\0';
printf("input: ");
frame_append(&f, s, 0);
printf("output: ");
print_string(f.buf);
printf("\n");
}
int main(void)
{
printf("ESC_ALT=");
print_string(ESC_ALT);
printf("\n");
printf("ESC_RST=");
print_string(ESC_RST);
printf("\n");
printf("Workaround will be applied:\n");
unit_test("abc" ESC_ALT "def");
unit_test("abc" ESC_RST "def" ESC_ALT);
printf("Workaround won't be applied:\n");
unit_test("abc" ESC_ALT "def" ESC_RST);
unit_test("abcdef");
unit_test("abc" ESC_RST);
}
@peterdelevoryas
Copy link
Author

gcc test.c && ./a.out:

ESC_ALT= \x1b[5;7m
ESC_RST= \x1b[m
Workaround will be applied:
input:  abc \x1b[5;7m defa \x1f
output: abc \x1b[5;7m defa \x1b[m \x1f \x1b[5;7m
input:  abc \x1b[m def \x1b[5;7m aaaaa \x1f
output: abc \x1b[m def \x1b[5;7m aaaaa \x1b[m \x1f \x1b[5;7m
Workaround won't be applied:
input:  abc \x1b[5;7m def \x1b[m aaaaa \x1f
output: abc \x1b[5;7m def \x1b[m aaaaa \x1f
input:  abcdef \x1f
output: abcdef \x1f
input:  abc \x1b[m \x1f
output: abc \x1b[m \x1f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment