From 452d55d012e11df77229fe977dca9a48b38392a0 Mon Sep 17 00:00:00 2001 From: anon Date: Sat, 19 Aug 2023 13:18:34 +0200 Subject: [PATCH] clean up, merged prototypes and anon's prototype rework --- LICENSE | 0 Makefile | 24 +++- chad.mk | 21 +++ hl_xolatile.c | 100 -------------- makefile_xolatile | 8 -- source/chad.h | 34 +++++ source/hl.h | 106 +++++++++++++++ source/main.c | 95 ++++++++++++++ src/main.c | 386 ------------------------------------------------------ src2/Highlight.h | 61 --------- src2/main.cpp | 45 ------- 11 files changed, 274 insertions(+), 606 deletions(-) delete mode 100644 LICENSE create mode 100644 chad.mk delete mode 100644 hl_xolatile.c delete mode 100644 makefile_xolatile create mode 100644 source/chad.h create mode 100644 source/hl.h create mode 100644 source/main.c delete mode 100644 src/main.c delete mode 100644 src2/Highlight.h delete mode 100644 src2/main.cpp diff --git a/LICENSE b/LICENSE deleted file mode 100644 index e69de29..0000000 diff --git a/Makefile b/Makefile index 6bc4f36..b6b3473 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,27 @@ -CFLAGS:=-std=c99 -O2 -Wall -Wextra -Wpedantic -Wvla -Wshadow -Wundef +include chad.mk +DEBUG:=1 +CFLAGS:=-std=c99 -O2 -Wvla -Wshadow -Wundef $(if ${DEBUG}, ${CHAD_DEBUG},'') CPPFLAGS:=-D_FORTIFY_SOURCE=2 -SRC.dir:=src/ +SRC.dir:=source/ SRC:=$(shell find ${SRC.dir} -iname '*.c') +HDR:=$(shell find ${SRC.dir} -iname '*.h') OBJ:=$(subst .c,.o,${SRC}) +OUT:=hl +OUTARGS:=${OUT} < source/main.c + +main: ${OBJ} ${HDR} + ${LINK.c} ${OBJ} -o hl + %.o: %.c ${COMPILE.c} $< -o $@ -hl: ${OBJ} - ${LINK.c} ${OBJ} -o $@ +install: + cp hl /usr/bin/hl -new: - g++ src2/main.cpp -o hl -ggdb +clean: + -rm ${OBJ} + -rm ${OUT} + +test: chad_test diff --git a/chad.mk b/chad.mk new file mode 100644 index 0000000..161bf90 --- /dev/null +++ b/chad.mk @@ -0,0 +1,21 @@ +# Make script for Chad projects +# This script depends on the following variables +# - OUT : output program name +# - OUTARGS : default flags to fork ${OUT} with + +# +CHAD_DEBUG:=-Og -ggdb -pg -fno-inline + +# Programs to check warnings for as defined by the Chad standard +GCC:=gcc +GCC.warnings:=-Wall -Wextra -Wpedantic +CLANG:=clang +CLANG.warnings:=-Weverything +VALGRIND:=valgrind + +chad_test: + ${GCC} ${GCC.warnings} ${SRC} -o ${OUT} + ${CLANG} ${GCC.warnings} ${SRC} -o ${OUT} + ${VALGRIND} ${OUT} ${OUTARGS} + +.DEFAULT_GOAL:=main diff --git a/hl_xolatile.c b/hl_xolatile.c deleted file mode 100644 index 1a04cd5..0000000 --- a/hl_xolatile.c +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#define UNUSED(x) ((void) (x)) - -#define ALLOCATION_CHUNK (10UL) - -enum { - NORMAL, BOLD, DARKNESS, ITALIC, - UNDERLINE, BLINK, DUNNO_6, REVERSE, - INVISIBLE -}; - -enum { - GREY, RED, GREEN, YELLOW, - BLUE, PINK, CYAN, WHITE, - CANCEL -}; - -static char * buffer = NULL; -static size_t buffer_size = 0; - -static void render_character(char * character) { - write(STDOUT_FILENO, character, sizeof (*character)); -} - -static void render_string(char * string) { - write(STDOUT_FILENO, string, strlen(string)); -} - -static void render_colour(int colour, - int effect) { - char format[8] = "\033[ ;3 m"; - - format[2] = (char) (effect % 9) + '0'; - format[5] = (char) (colour % 8) + '0'; - - render_string(format); -} - -static void render_cancel(void) { - render_string("\033[0m"); -} - -static int is_separator(char character) { - if (( isascii(character)) - && (!isalnum(character)) - && (character != '_')) { - return 1; - } else { - return 0; - } -} - -static int compare_multiple_strings(char * string, - const char * * strings, - const int count) { - int i = 0; - - do { - if (!strcmp(string, strings[i])) { - return 1; - } - } while (++i != count); - - return 0; -} - -int main(int argc, - char * * argv) { - UNUSED(argc); - UNUSED(argv); - - buffer = realloc(buffer, ALLOCATION_CHUNK); - - do { - if (!((buffer_size + 1) % ALLOCATION_CHUNK)) { - // Linear incremental reallocation (advanced)! - size_t chunks = (buffer_size + 1) / ALLOCATION_CHUNK; - buffer = realloc(buffer, ++chunks * ALLOCATION_CHUNK); - } - buffer[buffer_size] = '\0'; - read(STDIN_FILENO, &buffer[buffer_size], sizeof (*buffer)); - ++buffer_size; - } while (buffer[buffer_size - 1]); - - buffer[buffer_size - 1] = '\0'; - - render_colour(RED, BOLD); - render_string(buffer); - render_cancel(); - - free (buffer); - - return 0; -} diff --git a/makefile_xolatile b/makefile_xolatile deleted file mode 100644 index 7ca689d..0000000 --- a/makefile_xolatile +++ /dev/null @@ -1,8 +0,0 @@ -default: - gcc -g -Wall -Wextra -Wpedantic -o hl hl_xolatile.c - clang -g -Weverything -o hl hl_xolatile.c - -# 'This shit requires to be in /usr/bin currently...' -# 'There are unused functions that will be used, ignore now.' -# 'Next please do [$ sudo cp hl /usr/bin/hl].' -# 'Then test it with example [$ echo ABCDEF | valgrind hl].' diff --git a/source/chad.h b/source/chad.h new file mode 100644 index 0000000..7c8954e --- /dev/null +++ b/source/chad.h @@ -0,0 +1,34 @@ +#ifndef CHAD_H +#define CHAD_H + +#include + +#define UNUSED(x) ((void)x) + +// Terminal manipulation +#define TERMINAL_RESET "\033[0m" + +#define TERMINAL_COLOR_FG_BLACK "\033[30m" +#define TERMINAL_COLOR_FG_RED "\033[31m" +#define TERMINAL_COLOR_FG_GREEN "\033[32m" +#define TERMINAL_COLOR_FG_YELLOW "\033[33m" +#define TERMINAL_COLOR_FG_BLUE "\033[34m" +#define TERMINAL_COLOR_FG_MAGENTA "\033[35m" +#define TERMINAL_COLOR_FG_CYAN "\033[36m" +#define TERMINAL_COLOR_FG_WHITE "\033[37m" + +#define TERMINAL_COLOR_BG_BLACK "\033[40m" +#define TERMINAL_COLOR_BG_RED "\033[41m" +#define TERMINAL_COLOR_BG_GREEN "\033[42m" +#define TERMINAL_COLOR_BG_YELLOW "\033[43m" +#define TERMINAL_COLOR_BG_BLUE "\033[44m" +#define TERMINAL_COLOR_BG_MAGENTA "\033[45m" +#define TERMINAL_COLOR_BG_CYAN "\033[46m" +#define TERMINAL_COLOR_BG_WHITE "\033[47m" + +#define TERMINAL_STYLE_BOLD "\033[1m" +#define TERMINAL_STYLE_ITALICS "\033[3m" +#define TERMINAL_STYLE_REVERSE "\033[7m" + + +#endif diff --git a/source/hl.h b/source/hl.h new file mode 100644 index 0000000..5c565b6 --- /dev/null +++ b/source/hl.h @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include "chad.h" + +typedef void (*attribute_callback_t)(const char * const string, + const int length, + void * const attributes); + +typedef struct { + char * key; + attribute_callback_t callback; + UT_hash_handle hh; +} display_t; +display_t * display_table = NULL; + +typedef struct { + void * attributes; + struct hl_group_t * link; +} hl_group_t; + +typedef enum { + KEYWORD, + MATCH, + REGION +} token_t; + +typedef struct { + hl_group_t * hl; + token_t t; + char* syntax; +} token; // XXX: this will have to be renamed + +/* Temp solution + */ +token * token_table[1000]; +int token_table_top = 0; + +token * new_token(const char * const syntax, + const token_t t, + const hl_group_t * const g) { + token * mt = (token*)malloc(sizeof(token)); + mt->hl = g; + mt->t = t; + mt->syntax = syntax; + token_table[token_table_top++] = mt; + return mt; +} + +void new_keyword_tokens(const char * const * words, + hl_group_t * const g) { + while (*words) { + new_token(*words, KEYWORD, g); + words = words + 1; + } +} + +int token_fits(const char* const pattern, + const char* const to) { + if (pattern == NULL) { + return true; + } + for (int i = 0;; i++) { + if (pattern[i] == '\00') { + return i; + } + if (to[i] == '\00' + || pattern[i] != to[i]) { + return false; + } + } +} + +bool is_word_separator(const char character) { + if (( isascii(character)) + && (!isalnum(character)) + && ( character != '_')) { + return 1; + } else { + return 0; + } +} + +void render_string(const char * const string, + const char * const mode) { + for (const char * s = string; *s != '\00';) { + int f; + int i = 0; + for (; i < token_table_top; i++) { + f = token_fits(token_table[i]->syntax, s); + if(f){ break; }; + } + // + display_t * display; + HASH_FIND_STR(display_table, mode, display); + // + if(f){ + display->callback(s, f, token_table[i]->hl->attributes); + s += f; + } else { + display->callback(s, 0, NULL); + ++s; + } + } +} diff --git a/source/main.c b/source/main.c new file mode 100644 index 0000000..f326730 --- /dev/null +++ b/source/main.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include "hl.h" + +#define ALLOCATION_CHUNK (10UL) + +static char * buffer = NULL; +static size_t buffer_size = 0; + +typedef struct { + int attribute; + int foreground_color; + int background_color; +} terminal_hl_t; + +void cterm_render_callback(const char * const string, + const int length, + void * const attributes) { + if(!length){ + putchar(*string); + return; + } + + UNUSED(attributes); + fputs(TERMINAL_STYLE_BOLD, stdout); + for (int i = 0; i < length; i++) { + putchar(*(string+i)); + } + fputs(TERMINAL_RESET, stdout); +} + +int main(int argc, + char * * argv) { + UNUSED(argc); + UNUSED(argv); + + // Buffer init + buffer = realloc(buffer, ALLOCATION_CHUNK); + + do { + if (!((buffer_size + 1) % ALLOCATION_CHUNK)) { + /* Linear incremental reallocation (advanced)! + */ + size_t chunks = (buffer_size + 1) / ALLOCATION_CHUNK; + buffer = realloc(buffer, ++chunks * ALLOCATION_CHUNK); + } + buffer[buffer_size] = '\0'; + read(STDIN_FILENO, &buffer[buffer_size], sizeof (*buffer)); + ++buffer_size; + } while (buffer[buffer_size - 1]); + + buffer[buffer_size - 1] = '\0'; + + // Highlight init + const char * c_keywords[] = { + "register", "volatile", "auto", "const", "static", "extern", "if", "else", + "do", "while", "for", "continue", "switch", "case", "default", "break", + "enum", "union", "struct", "typedef", "goto", "void", "return", "sizeof", + "char", "short", "int", "long", "signed", "unsigned", "float", "double", + NULL + }; + + const char * preprocessor_keywords[] = { + "#include", "#pragma", "#define", "#undef", "#ifdef", "#ifndef", "#elifdef", "#elifndef", + "#if", "#elif", "#else", "#endif", "#embed", "#line", "#error", "#warning", + NULL + }; + + terminal_hl_t my_hl = (terminal_hl_t) { + .attribute = 1 + }; + + display_t * cterm = &(display_t) { + .key = "cterm", + .callback = cterm_render_callback + }; + hl_group_t mygroup = (hl_group_t) { + .link = NULL + }; + + HASH_ADD_STR(display_table, + key, + cterm); + new_keyword_tokens(c_keywords, &mygroup); + new_keyword_tokens(preprocessor_keywords, &mygroup); + + // + render_string(buffer, "cterm"); + putchar('\n'); + free (buffer); + + return 0; +} diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 32855f6..0000000 --- a/src/main.c +++ /dev/null @@ -1,386 +0,0 @@ -#include -#include -#include -#include -#include - -#define ALLOCATION_CHUNK (1024UL) -#define ALLOCATION_LIMIT (1024UL * 1024UL) - -#ifndef PROGRAM_NAME -# define PROGRAM_NAME "hl" -#endif - -enum { NORMAL, BOLD, DARKNESS, ITALIC, UNDERLINE, BLINK, DUNNO_6, REVERSE, INVISIBLE }; -enum { GREY, RED, GREEN, YELLOW, BLUE, PINK, CYAN, WHITE, CANCEL }; - -static int colour_short_comment = GREY; -static int colour_long_comment = GREY; -static int colour_short_string = PINK; -static int colour_long_string = RED; -static int colour_separator = BLUE; -static int colour_number = CYAN; -static int colour_keyword = YELLOW; -static int colour_preprocessor = YELLOW; -static int colour_default = WHITE; - -static int effect_short_comment = BOLD; -static int effect_long_comment = BOLD; -static int effect_short_string = BOLD; -static int effect_long_string = BOLD; -static int effect_separator = BOLD; -static int effect_number = BOLD; -static int effect_keyword = BOLD; -static int effect_preprocessor = BOLD; -static int effect_default = BOLD; - -static unsigned long int buffer_size = 0; - -static void render_character ( - char character -) { - putchar (character); -} - -static void render_string ( - char * string -) { - while (* string) render_character (* string++); -} - -static void render_colour ( - int colour, - int effect -) { - if (colour == CANCEL) { - render_string ("\033[0m"); - return; - } - - render_string ("\033["); - render_character ((char) (effect % 9) + '0'); - render_string (";3"); - render_character ((char) (colour % 8) + '0'); - render_character ('m'); -} - -static int is_space ( - char character -) { - switch (character) - { - case ' ': case '\t': case '\r': case '\n': - return (1); - default: - return (0); - } -} - -static int is_separator ( - char character -) { - switch (character) - { - case ' ': case '\t': case '\r': case '\n': - case '+': case '-': case '*': case '/': - case '(': case ')': case '[': case ']': - case '{': case '}': case '<': case '>': - case ';': case ':': case ',': case '.': - case '!': case '&': case '|': case '?': - case '~': case '^': case '%': case '=': - return (1); - default: - return (0); - } -} - -static int compare_multiple_strings ( - char * string, - const char ** strings, - const int count -) { - int i = 0; - - do { - if (strcmp (string, strings [i]) == 0) { - return (1); - } - ++i; - } while (i != count); - - return (0); -} - -static int render_short_comment ( - char * buffer, - int data_offset -) { - render_colour (colour_short_comment, effect_short_comment); - - do { - render_character (buffer [data_offset]); - ++data_offset; - } while ((buffer [data_offset] != '\n') && (buffer [data_offset] != '\0')); - - render_character (buffer [data_offset]); - ++data_offset; - - return (data_offset); -} - -static int render_long_comment ( - char * buffer, - int data_offset -) { - render_colour (colour_long_comment, effect_long_comment); - - do { - render_character (buffer [data_offset]); - ++data_offset; - } while (((buffer [data_offset] != '/') || - (buffer [data_offset - 1] != '*')) && - (buffer [data_offset] != '\0')); - - render_character (buffer [data_offset]); - ++data_offset; - - return (data_offset); -} - -static int render_short_string ( - char * buffer, - int data_offset -) { - render_colour (colour_short_string, effect_short_string); - - do { - render_character (buffer [data_offset]); - ++data_offset; - if (buffer [data_offset - 1] == '\\') { - render_character (buffer [data_offset]); - ++data_offset; - } - } while ((buffer [data_offset] != '\'') && (buffer [data_offset] != '\0')); - - render_character (buffer [data_offset]); - ++data_offset; - - return (data_offset); -} - -static int render_long_string ( - char * buffer, - int data_offset -) { - render_colour (colour_long_string, effect_long_string); - - do { - render_character (buffer [data_offset]); - ++data_offset; - if (buffer [data_offset - 1] == '\\') { - render_character (buffer [data_offset]); - ++data_offset; - } - } while ((buffer [data_offset] != '"') && (buffer [data_offset] != '\0')); - - render_character (buffer [data_offset]); - ++data_offset; - - return (data_offset); -} - -static int render_separator ( - char * buffer, - int data_offset -) { - if (is_space (buffer [data_offset]) != 0) { - render_colour (WHITE, NORMAL); - } else { - render_colour (colour_separator, effect_separator); - } - - render_character (buffer [data_offset]); - ++data_offset; - - return (data_offset); -} - -static int render_number ( - char * buffer, - int data_offset -) { - render_colour (colour_number, effect_number); - - do { - render_character (buffer [data_offset]); - ++data_offset; - } while ((is_separator (buffer [data_offset]) == 0) && (buffer [data_offset] != '\0')); - - return (data_offset); -} - -static int render_word ( - char * buffer, - int data_offset -) { - const char * c_keywords [32] = { - "register", "volatile", "auto", "const", "static", "extern", "if", "else", - "do", "while", "for", "continue", "switch", "case", "default", "break", - "enum", "union", "struct", "typedef", "goto", "void", "return", "sizeof", - "char", "short", "int", "long", "signed", "unsigned", "float", "double" - }; - - const char * preprocessor_keywords [16] = { - "#include", "#pragma", "#define", "#undef", "#ifdef", "#ifndef", "#elifdef", "#elifndef", - "#if", "#elif", "#else", "#endif", "#embed", "#line", "#error", "#warning" - }; - - char * word = NULL; - - int i = 0; - - do { - word = realloc (word, sizeof (* word) * (unsigned long int) (i + 1)); - word [i] = buffer [data_offset + i]; - ++i; - } while ((is_separator (buffer [data_offset + i]) == 0) && (buffer [data_offset + i] != '\0')); - - word = realloc (word, sizeof (* word) * (unsigned long int) (i + 1)); - word [i] = '\0'; - - if (compare_multiple_strings (word, c_keywords, 32) != 0) { - render_colour (colour_keyword, effect_keyword); - } else if (compare_multiple_strings (word, preprocessor_keywords, 16) != 0) { - render_colour (colour_preprocessor, effect_preprocessor); - } else { - render_colour (colour_default, effect_default); - } - - do { - render_character (buffer [data_offset]); - ++data_offset; - } while ((is_separator (buffer [data_offset]) == 0) && (buffer [data_offset] != '\0')); - - free (word); - - return (data_offset); -} - -void -handle_buffer( - char * buffer -) { - int offset = 0; - while (buffer [offset] != '\0') { - if ((buffer [offset] == '/') && (buffer [offset + 1] == '/')) { - offset = render_short_comment (buffer, offset); - } else if ((buffer [offset] == '/') && (buffer [offset + 1] == '*')) { - offset = render_long_comment (buffer, offset); - } else if (buffer [offset] == '\'') { - offset = render_short_string (buffer, offset); - } else if (buffer [offset] == '"') { - offset = render_long_string (buffer, offset); - } else if (is_separator (buffer [offset]) != 0) { - offset = render_separator (buffer, offset); - } else if ((buffer [offset] >= '0') && (buffer [offset] <= '9')) { - offset = render_number (buffer, offset); - } else { - offset = render_word (buffer, offset); - } - render_colour (CANCEL, NORMAL); - } -} - -static char * -slurp(const char * fn) -{ - size_t len; - char * b; - FILE * fp = fopen(fn, "r"); - if (fp) - { - fseek(fp, 0, SEEK_END); - len = ftell(fp); - rewind(fp); - b = malloc(len); - if (b && - len != fread(b, 1, len, fp)) - { perror(PROGRAM_NAME); } - fclose(fp); - return b; - } - else - { return NULL; } -} - -/* "Short" */ -#define SHORT_OPT(c,s) \ - if ((c == argv[0][0] && argv[0][1] == '\0') || \ - 0 == strncmp(argv[0], s, strlen(s))) - -#define OPT(s) \ - if (0 == strncmp(argv[0], s, strlen(s))) - -int main ( - int argc, - char ** argv -) { - char * buffer = NULL; - - if (argc != 1) { - (void) argv; - while (++argv, --argc) { - if (argv[0][0] == '-') { - argv[0]++; - SHORT_OPT ('?',"help") { - fprintf (stderr, PROGRAM_NAME ": hl [OPTIONS] FILES ...\n"); - return (0); - } - OPT ("version") { - fprintf(stderr, PROGRAM_NAME ": Version 9000\n"); - return (0); - } - else { - fprintf (stderr, PROGRAM_NAME ": Unrecognized option '%s'\n", argv [0]); - return (1); - } - } else { - if ((buffer = slurp (argv [0]))) { - handle_buffer (buffer); - free (buffer); - } - } - } - return (0); - } - - buffer = realloc (buffer, ALLOCATION_CHUNK); - -#define MEMFAIL(v) if (v == NULL) { perror(PROGRAM_NAME); return (1); } - MEMFAIL(buffer); - - do { - if ((buffer_size + 1) % ALLOCATION_CHUNK == 0) { - buffer = realloc (buffer, - ((buffer_size + 1) - / ALLOCATION_CHUNK + 1) - * ALLOCATION_CHUNK); - MEMFAIL(buffer); - } - buffer [buffer_size] = '\0'; /* Fixing Valgrind warnings... */ - read (STDIN_FILENO, & buffer [buffer_size], sizeof (* buffer)); - ++buffer_size; - } while ((buffer [buffer_size - 1] != '\0') /*|| - (buffer_size != ALLOCATION_LIMIT)*/); - - buffer [buffer_size - 1] = '\0'; - - // Checking if short comments work... - /* Checking if long comments work... */ - - handle_buffer(buffer); - - free (buffer); - - return (0); -} diff --git a/src2/Highlight.h b/src2/Highlight.h deleted file mode 100644 index 29cceb2..0000000 --- a/src2/Highlight.h +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include - -typedef enum { - BOLD, - ITALICS, - UNDERLINE, - END -} attr_t; - -typedef void (*attr_callback_t)(void); -void bold_on(void){ - fputs("\033[1m", stdout); -} -void bold_off(void){ - fputs("\033[0m", stdout); -} -attr_callback_t attr_callbacks[END*2] = { - (attr_callback_t)bold_on, - (attr_callback_t)bold_off, -}; - -typedef int color; - -struct hl_t { - attr_t attrs; - color fg_color; - color bg_color; - //? font; -}; - -struct hl_group { - char* name; - std::map o; - hl_group* link; -}; - -typedef enum { - KEYWORD, - MATCH, - REGION -} token_t; - -struct token{ - hl_group* hl; - token_t t; - char* syntax; -}; - -std::vector token_table; - -token* newtoken(char* syntax, token_t t, hl_group* g){ - token* mt = new (token){ - .hl = g, - .t = t, - .syntax = syntax - }; - token_table.push_back(mt); - return mt; -} diff --git a/src2/main.cpp b/src2/main.cpp deleted file mode 100644 index 627b816..0000000 --- a/src2/main.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "Highlight.h" - -const char *const test_string = "this (test) is my test string which im with testing in this test"; - -int fits(const char* const pattern, const char* const to){ - if(pattern == NULL){ return true; } - for(int i = 0;; i++){ - if(pattern[i] == '\00'){ return i; } - if(to[i] == '\00' or pattern[i] != to[i]){ return false; } - } -} - -void render_string(const char* const string, char* mode){ - for(const char* s = string; *s != '\00';){ - for(auto &i : token_table){ - int f; - f = fits(i->syntax, s); - if(f){ - int pos = i->hl->o.find(mode)->second.attrs; - attr_callbacks[pos](); - for(int h = 0; h < f; h++){ - putchar(*(s+h)); - } - attr_callbacks[pos+1](); - s += f; - }else{ - putchar(*s); - ++s; - } - } - } -} - -signed main(){ - hl_group mygroup = (hl_group){ - .name = "test", - .link = NULL - }; - mygroup.o["cterm"] = (hl_t){ - .attrs = BOLD - }; - token* mytoken = newtoken("test", KEYWORD, &mygroup); - render_string(test_string, "cterm"); - putchar('\n'); -}