aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraxtloss <axtlos@disroot.org>2024-10-17 02:39:27 +0200
committeraxtloss <axtlos@disroot.org>2024-10-17 02:39:27 +0200
commit7f0fc08c05142f9f70cb05a4b1b1d6f0b1a3279b (patch)
tree0c1934e2d6940a99e97f2adefdac46cd3b9e384d
parentb2182396df5d99ff5c26161aaffa5ced879742c5 (diff)
downloadextlib-7f0fc08c05142f9f70cb05a4b1b1d6f0b1a3279b.tar.gz
extlib-7f0fc08c05142f9f70cb05a4b1b1d6f0b1a3279b.tar.bz2
Add strfmt
-rw-r--r--doc/strfmt.386
-rw-r--r--src/extlib.h71
-rw-r--r--src/extstring.c75
-rw-r--r--tests/driver.c12
-rw-r--r--tests/test_strfmt.c52
-rw-r--r--tests/tests.c2
6 files changed, 293 insertions, 5 deletions
diff --git a/doc/strfmt.3 b/doc/strfmt.3
new file mode 100644
index 0000000..7beefd0
--- /dev/null
+++ b/doc/strfmt.3
@@ -0,0 +1,86 @@
+'\" t
+.\" Copyright 2024 axtlos (axtlos@disroot.org)
+.\"
+.\" SPDX-License-Identifier: BSD-3-Clause
+
+.TH strfmt 3 2024-10-17 "extlib"
+.SH NAME
+strfmt \- style a string through ansi escape codes
+.SH LIBRARY
+extlib extended standard library
+.RI ( libextlib ", " \-lextlib )
+.SH SYNOPSIS
+.nf
+.B #include <extlib.h>
+.P
+.BI "char *strfmt (char *s, struct style fmt);"
+.P
+.BI "struct style { int color, boolean background, int styles }"
+.P
+.fi
+.SH DESCRIPTION
+The
+.BR strfmt ()
+function wraps
+.I *s
+in ANSI escape codes according to the style given in
+.IR fmt .
+Extlib contains convenience enums for the basic 16 colours
+and the greyscale colours 232-255. But any number in the 1-255 range can be supplied.
+The greyscale colours assume 256 colour support from the terminal, and may not work on every platform.
+.fi
+.SH RETURN VALUE
+.BR strfmt ()
+returns a copy of the string
+.I *s
+wrapped in ANSI escape codes.
+If
+.I fmt
+does not define any style (i.e
+.BI "(struct style) { 0, false, 0 }"
+), a copy of
+.I *s
+is returned.
+.SH EXAMPLES
+The following code will write the text "meow" in different styles.
+.\" SRC BEGIN (strfmt.c)
+.EX
+#include <stdlib.h>
+#include <stdio.h>
+#include <extlib.h>
+#include <stdbool.h>
+\&
+int
+main (void)
+{
+ // Red text, with no extra styles
+ char *red_text = strfmt ("meow", (struct style) { RED, false, 0 });
+ puts (red_text);
+ free (red_text);
+\&
+ // Blue, bold and italic text
+ char *blue_bi_text = strfmt ("meow", (struct style) { RED, false, BOLD|ITALIC });
+ puts (blue_bi_text);
+ free (blue_bi_text);
+\&
+ // Regular text on a magenta background
+ char *magenta_bg_text = strfmt ("meow", (struct style) { MAGENTA, true, 0 });
+ puts (magenta_bg_text);
+ free (magenta_bg_text);
+\&
+ // Gray, bold, italic, underlined, blinking, strikethrough text
+ char *gray_text = strfmt ("meow", (struct style) { GRAY23, false, BOLD|ITALIC|UNDERLINE|BLINKING });
+ puts (gray_text);
+ free (gray_text);
+\&
+ // Regular text, with no color or style
+ char *text = strfmt ("meow", (struct style) { 0, false, 0 });
+ puts (text);
+ free (text);
+\&
+ exit (EXIT_SUCCESS);
+}
+.SH AUTHORS
+This manual page was written by Rose
+.IR <axtlos@disroot.org> .
+.\" SRC END
diff --git a/src/extlib.h b/src/extlib.h
index 03bb53b..c3d342a 100644
--- a/src/extlib.h
+++ b/src/extlib.h
@@ -6,6 +6,7 @@
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
+#include <stdbool.h>
#ifdef USE_SECURE_MEM
#define free(x) error - use free_secure
@@ -76,3 +77,73 @@ float min (float v, float min_v);
/// Limit a value between min and max
float cap (float v, float min_v, float max_v);
+
+#ifndef STYLESDEF
+/// Original 16 terminal colors
+enum colors16 {
+ BLACK,
+ RED,
+ GREEN,
+ YELLOW,
+ BLUE,
+ MAGENTA,
+ CYAN,
+ WHITE,
+ GRAY,
+ BRIGHTRED,
+ BRIGHTGREEN,
+ BRIGHTYELLOW,
+ BRIGHTBLUE,
+ BRIGHTMAGENTA,
+ BRIGHTCYAN,
+ BRIGHTWHITE
+};
+
+enum grayscale {
+ GRAY1 = 232,
+ GRAY2,
+ GRAY3,
+ GRAY4,
+ GRAY5,
+ GRAY6,
+ GRAY7,
+ GRAY8,
+ GRAY9,
+ GRAY10,
+ GRAY11,
+ GRAY12,
+ GRAY13,
+ GRAY14,
+ GRAY15,
+ GRAY16,
+ GRAY17,
+ GRAY18,
+ GRAY19,
+ GRAY20,
+ GRAY21,
+ GRAY22,
+ GRAY23,
+ GRAY24
+};
+
+enum effects {
+ BOLD = 1,
+ DIM = 2,
+ ITALIC = 4,
+ UNDERLINE = 8,
+ BLINKING = 16,
+ INVERSE = 32,
+ HIDDEN = 64,
+ STRIKETHROUGH = 128
+};
+
+struct style {
+ int color;
+ bool background;
+ int styles;
+};
+#define STYLESDEF
+#endif
+
+/// Format a string with ANSI escape codes
+char *strfmt (char *s, struct style);
diff --git a/src/extstring.c b/src/extstring.c
index b69b1f7..685db4f 100644
--- a/src/extstring.c
+++ b/src/extstring.c
@@ -8,6 +8,17 @@
#include <ctype.h>
#include "extlib.h"
+enum gfxnums {
+ num_BOLD = 1,
+ num_DIM,
+ num_ITALIC,
+ num_UNDERLINE,
+ num_BLINKING,
+ num_INVERSE,
+ num_HIDDEN,
+ num_STRIKETHROUGH,
+};
+
char *
strlwr (char *s)
{
@@ -122,3 +133,67 @@ join_str (char **s, size_t len, char *delim)
return ret;
}
+
+// all freed strings in this function dont contain confidential data
+// so free_secure isnt necessary
+#undef free
+void
+append_gfxsqnc (char **escape_sqnc, size_t *sqnc_size, int gfx_num)
+{
+ size_t gfxbase_len = strlen ("\e[XXm")+1;
+ char *tmp_sqnc = malloc (*sqnc_size + gfxbase_len);
+ *sqnc_size += gfxbase_len;
+ sprintf (tmp_sqnc, "%s\e[%dm", *escape_sqnc, gfx_num);
+ free (*escape_sqnc);
+ *escape_sqnc = tmp_sqnc;
+}
+
+char *
+strfmt (char *s, struct style fmt)
+{
+ size_t gfxbase_len = strlen ("\e[XXm")+1;
+ size_t sqnc_size = strlen ("\e[0m") + strlen (s)+1;
+ char *escape_sqnc = strdup ("");
+ if (fmt.color > 0) {
+ char *clrbase = malloc (strlen ("\e[38;5;m")+4);
+ sprintf (clrbase, "\e[%d;5;%dm", fmt.background ? 48 : 38, fmt.color);
+ char *tmp_sqnc = malloc (sqnc_size + strlen (clrbase));
+ sqnc_size += strlen (clrbase);
+ sprintf (tmp_sqnc, "%s%s", escape_sqnc, clrbase);
+ free (escape_sqnc);
+ escape_sqnc = tmp_sqnc;
+ free (clrbase);
+ }
+
+ if ((fmt.styles & BOLD))
+ append_gfxsqnc (&escape_sqnc, &sqnc_size, num_BOLD);
+
+ if ((fmt.styles & DIM))
+ append_gfxsqnc (&escape_sqnc, &sqnc_size, num_DIM);
+
+ if ((fmt.styles & ITALIC))
+ append_gfxsqnc (&escape_sqnc, &sqnc_size, num_ITALIC);
+
+ if ((fmt.styles & UNDERLINE))
+ append_gfxsqnc (&escape_sqnc, &sqnc_size, num_UNDERLINE);
+
+ if ((fmt.styles & BLINKING))
+ append_gfxsqnc (&escape_sqnc, &sqnc_size, num_BLINKING);
+
+ if ((fmt.styles & INVERSE))
+ append_gfxsqnc (&escape_sqnc, &sqnc_size, num_INVERSE);
+
+ if ((fmt.styles & HIDDEN))
+ append_gfxsqnc (&escape_sqnc, &sqnc_size, num_HIDDEN);
+
+ if ((fmt.styles & STRIKETHROUGH))
+ append_gfxsqnc (&escape_sqnc, &sqnc_size, num_STRIKETHROUGH);
+
+ if (strlen (escape_sqnc) <= 2) {
+ free (escape_sqnc);
+ return strdup (s);
+ }
+
+ sprintf (escape_sqnc, "%s%s\e[0m", escape_sqnc, s);
+ return escape_sqnc;
+}
diff --git a/tests/driver.c b/tests/driver.c
index d3739b5..4d998b8 100644
--- a/tests/driver.c
+++ b/tests/driver.c
@@ -6,9 +6,8 @@
#include "../src/extlib.h"
#include "test_driver.h"
-const char* success = "\033[1;32m";
-const char* fail = " \033[1;31m";
-const char *reset = "\033[0m";
+char* success;
+char* fail;
int tests_count;
struct test_t** registered_tests;
@@ -19,9 +18,9 @@ test_runner (struct test_t *test, int n)
printf ("Test Case %d: %s -- %s\n", n, test->test_name, test->test_desc);
int test_result = test->test_func();
if (test_result == 0)
- printf ("Test Case %d: %s -- %sSUCCESS%s\n\n", n, test->test_name, success, reset);
+ printf ("Test Case %d: %s -- %s\n\n", n, test->test_name, success);
else
- printf ("Test Case %d: %s -- %sFAIL %d%s\n\n", n, test->test_name, fail, test_result, reset);
+ printf ("Test Case %d: %s -- %s %d\n\n", n, test->test_name, fail, test_result);
}
void
@@ -36,6 +35,9 @@ register_test (struct test_t *test)
int
main (int argc, char *argv[])
{
+ success = strfmt("SUCCESS", (struct style) {.color = GREEN, .background = false, .styles = BOLD|UNDERLINE});
+ fail = strfmt("FAIL", (struct style) {.color = RED, .background = false, .styles = BOLD|UNDERLINE});
+
registered_tests = malloc (8);
tests_entrypoint();
for (int i = 0; i < tests_count; i++)
diff --git a/tests/test_strfmt.c b/tests/test_strfmt.c
new file mode 100644
index 0000000..c8ab08e
--- /dev/null
+++ b/tests/test_strfmt.c
@@ -0,0 +1,52 @@
+#include <string.h>
+#define USE_SECURE_MEM
+#include "../src/extlib.h"
+#include "stdbool.h"
+
+int
+test_strfmt ()
+{
+ int errno = 0;
+ char *test_string_1 = strfmt ("meow", (struct style) {0, false, BOLD});
+ printf ("\e[1mtest_strfmt\e[0m:: No Color, Bold: %s\n", test_string_1);
+ if (strcmp (test_string_1, "\e[1mmeow\e[0m") != 0)
+ errno = 1;
+
+ char *test_string_2 = strfmt ("meow", (struct style) {RED, false, 0});
+ printf ("\e[1mtest_strfmt\e[0m:: Red, No style: %s\n", test_string_2);
+ if (strcmp (test_string_2, "\e[38;5;1mmeow\e[0m") != 0)
+ errno = 2;
+
+ char *test_string_3 = strfmt ("meow", (struct style) {RED, false, BOLD});
+ printf ("\e[1mtest_strfmt\e[0m:: Red, Bold: %s\n", test_string_3);
+ if (strcmp (test_string_3, "\e[38;5;1m\e[1mmeow\e[0m") != 0)
+ errno = 3;
+
+ char *test_string_4 = strfmt ("meow", (struct style) {RED, true, 0});
+ printf ("\e[1mtest_strfmt\e[0m:: Red background, No style: %s\n", test_string_4);
+ if (strcmp (test_string_4, "\e[48;5;1mmeow\e[0m") != 0)
+ errno = 4;
+
+ char *test_string_5 = strfmt ("meow", (struct style) {RED, true, BOLD});
+ printf ("\e[1mtest_strfmt\e[0m:: Red background, Bold: %s\n", test_string_5);
+ if (strcmp (test_string_5, "\e[48;5;1m\e[1mmeow\e[0m") != 0)
+ errno = 5;
+
+ free_secure ((void **) &test_string_1, strlen (test_string_1));
+ free_secure ((void **) &test_string_2, strlen (test_string_2));
+ free_secure ((void **) &test_string_3, strlen (test_string_3));
+ free_secure ((void **) &test_string_4, strlen (test_string_4));
+ free_secure ((void **) &test_string_5, strlen (test_string_5));
+ return errno;
+}
+
+struct test_t*
+test_strfmt_t ()
+{
+ struct test_t* test = malloc (sizeof (struct test_t));
+ test->test_func=test_strfmt;
+ test->test_name="test_strfmt";
+ test->test_desc="strfmt";
+ return test;
+}
+
diff --git a/tests/tests.c b/tests/tests.c
index 73dd1af..295cbc8 100644
--- a/tests/tests.c
+++ b/tests/tests.c
@@ -7,6 +7,7 @@
#include "test_replace_str.c"
#include "test_strlwr_strupr.c"
#include "test_trim.c"
+#include "test_strfmt.c"
inline void
tests_entrypoint ()
@@ -19,4 +20,5 @@ tests_entrypoint ()
register_test (test_replace_str_t ());
register_test (test_strlwr_strupr_t ());
register_test (test_trim_t ());
+ register_test (test_strfmt_t ());
}