M*LIB: non-inlined strings, FuriString primitive (#1795)
* Quicksave 1 * Header stage complete * Source stage complete * Lint & merge fixes * Includes * Documentation step 1 * FBT: output free size considering BT STACK * Documentation step 2 * py lint * Fix music player plugin * unit test stage 1: string allocator, mem, getters, setters, appends, compare, search. * unit test: string equality * unit test: string replace * unit test: string start_with, end_with * unit test: string trim * unit test: utf-8 * Rename * Revert fw_size changes * Simplify CLI backspace handling * Simplify CLI character insert * Merge fixes * Furi: correct filenaming and spelling * Bt: remove furi string include Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern size_t xPortGetTotalHeapSize(void);
|
||||
extern size_t xPortGetFreeHeapSize(void);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file kenrel.h
|
||||
* @file kernel.h
|
||||
* Furi Kernel primitives
|
||||
*/
|
||||
#pragma once
|
||||
|
@@ -25,8 +25,8 @@ void furi_log_init() {
|
||||
void furi_log_print_format(FuriLogLevel level, const char* tag, const char* format, ...) {
|
||||
if(level <= furi_log.log_level &&
|
||||
furi_mutex_acquire(furi_log.mutex, FuriWaitForever) == FuriStatusOk) {
|
||||
string_t string;
|
||||
string_init(string);
|
||||
FuriString* string;
|
||||
string = furi_string_alloc();
|
||||
|
||||
const char* color = FURI_LOG_CLR_RESET;
|
||||
const char* log_letter = " ";
|
||||
@@ -56,23 +56,23 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form
|
||||
}
|
||||
|
||||
// Timestamp
|
||||
string_printf(
|
||||
furi_string_printf(
|
||||
string,
|
||||
"%lu %s[%s][%s] " FURI_LOG_CLR_RESET,
|
||||
furi_log.timetamp(),
|
||||
color,
|
||||
log_letter,
|
||||
tag);
|
||||
furi_log.puts(string_get_cstr(string));
|
||||
string_reset(string);
|
||||
furi_log.puts(furi_string_get_cstr(string));
|
||||
furi_string_reset(string);
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
string_vprintf(string, format, args);
|
||||
furi_string_vprintf(string, format, args);
|
||||
va_end(args);
|
||||
|
||||
furi_log.puts(string_get_cstr(string));
|
||||
string_clear(string);
|
||||
furi_log.puts(furi_string_get_cstr(string));
|
||||
furi_string_free(string);
|
||||
|
||||
furi_log.puts("\r\n");
|
||||
|
||||
|
@@ -4,7 +4,6 @@
|
||||
#include "mutex.h"
|
||||
#include "event_flag.h"
|
||||
|
||||
#include <m-string.h>
|
||||
#include <m-dict.h>
|
||||
#include <toolbox/m_cstr_dup.h>
|
||||
|
||||
|
302
furi/core/string.c
Normal file
302
furi/core/string.c
Normal file
@@ -0,0 +1,302 @@
|
||||
#include "string.h"
|
||||
#include <m-string.h>
|
||||
|
||||
struct FuriString {
|
||||
string_t string;
|
||||
};
|
||||
|
||||
#undef furi_string_alloc_set
|
||||
#undef furi_string_set
|
||||
#undef furi_string_cmp
|
||||
#undef furi_string_cmpi
|
||||
#undef furi_string_search
|
||||
#undef furi_string_search_str
|
||||
#undef furi_string_equal
|
||||
#undef furi_string_replace
|
||||
#undef furi_string_replace_str
|
||||
#undef furi_string_replace_all
|
||||
#undef furi_string_start_with
|
||||
#undef furi_string_end_with
|
||||
#undef furi_string_search_char
|
||||
#undef furi_string_search_rchar
|
||||
#undef furi_string_trim
|
||||
#undef furi_string_cat
|
||||
|
||||
FuriString* furi_string_alloc() {
|
||||
FuriString* string = malloc(sizeof(FuriString));
|
||||
string_init(string->string);
|
||||
return string;
|
||||
}
|
||||
|
||||
FuriString* furi_string_alloc_set(const FuriString* s) {
|
||||
FuriString* string = malloc(sizeof(FuriString));
|
||||
string_init_set(string->string, s->string);
|
||||
return string;
|
||||
}
|
||||
|
||||
FuriString* furi_string_alloc_set_str(const char cstr[]) {
|
||||
FuriString* string = malloc(sizeof(FuriString));
|
||||
string_init_set(string->string, cstr);
|
||||
return string;
|
||||
}
|
||||
|
||||
FuriString* furi_string_alloc_printf(const char format[], ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
FuriString* string = furi_string_alloc_vprintf(format, args);
|
||||
va_end(args);
|
||||
return string;
|
||||
}
|
||||
|
||||
FuriString* furi_string_alloc_vprintf(const char format[], va_list args) {
|
||||
FuriString* string = malloc(sizeof(FuriString));
|
||||
string_init_vprintf(string->string, format, args);
|
||||
return string;
|
||||
}
|
||||
|
||||
FuriString* furi_string_alloc_move(FuriString* s) {
|
||||
FuriString* string = malloc(sizeof(FuriString));
|
||||
string_init_move(string->string, s->string);
|
||||
free(s);
|
||||
return string;
|
||||
}
|
||||
|
||||
void furi_string_free(FuriString* s) {
|
||||
string_clear(s->string);
|
||||
free(s);
|
||||
}
|
||||
|
||||
void furi_string_reserve(FuriString* s, size_t alloc) {
|
||||
string_reserve(s->string, alloc);
|
||||
}
|
||||
|
||||
void furi_string_reset(FuriString* s) {
|
||||
string_reset(s->string);
|
||||
}
|
||||
|
||||
void furi_string_swap(FuriString* v1, FuriString* v2) {
|
||||
string_swap(v1->string, v2->string);
|
||||
}
|
||||
|
||||
void furi_string_move(FuriString* v1, FuriString* v2) {
|
||||
string_clear(v1->string);
|
||||
string_init_move(v1->string, v2->string);
|
||||
free(v2);
|
||||
}
|
||||
|
||||
size_t furi_string_hash(const FuriString* v) {
|
||||
return string_hash(v->string);
|
||||
}
|
||||
|
||||
char furi_string_get_char(const FuriString* v, size_t index) {
|
||||
return string_get_char(v->string, index);
|
||||
}
|
||||
|
||||
const char* furi_string_get_cstr(const FuriString* s) {
|
||||
return string_get_cstr(s->string);
|
||||
}
|
||||
|
||||
void furi_string_set(FuriString* s, FuriString* source) {
|
||||
string_set(s->string, source->string);
|
||||
}
|
||||
|
||||
void furi_string_set_str(FuriString* s, const char cstr[]) {
|
||||
string_set(s->string, cstr);
|
||||
}
|
||||
|
||||
void furi_string_set_strn(FuriString* s, const char str[], size_t n) {
|
||||
string_set_strn(s->string, str, n);
|
||||
}
|
||||
|
||||
void furi_string_set_char(FuriString* s, size_t index, const char c) {
|
||||
string_set_char(s->string, index, c);
|
||||
}
|
||||
|
||||
int furi_string_cmp(const FuriString* s1, const FuriString* s2) {
|
||||
return string_cmp(s1->string, s2->string);
|
||||
}
|
||||
|
||||
int furi_string_cmp_str(const FuriString* s1, const char str[]) {
|
||||
return string_cmp(s1->string, str);
|
||||
}
|
||||
|
||||
int furi_string_cmpi(const FuriString* v1, const FuriString* v2) {
|
||||
return string_cmpi(v1->string, v2->string);
|
||||
}
|
||||
|
||||
int furi_string_cmpi_str(const FuriString* v1, const char p2[]) {
|
||||
return string_cmpi_str(v1->string, p2);
|
||||
}
|
||||
|
||||
size_t furi_string_search(const FuriString* v, const FuriString* needle, size_t start) {
|
||||
return string_search(v->string, needle->string, start);
|
||||
}
|
||||
|
||||
size_t furi_string_search_str(const FuriString* v, const char needle[], size_t start) {
|
||||
return string_search(v->string, needle, start);
|
||||
}
|
||||
|
||||
bool furi_string_equal(const FuriString* v1, const FuriString* v2) {
|
||||
return string_equal_p(v1->string, v2->string);
|
||||
}
|
||||
|
||||
bool furi_string_equal_str(const FuriString* v1, const char v2[]) {
|
||||
return string_equal_p(v1->string, v2);
|
||||
}
|
||||
|
||||
void furi_string_push_back(FuriString* v, char c) {
|
||||
string_push_back(v->string, c);
|
||||
}
|
||||
|
||||
size_t furi_string_size(const FuriString* s) {
|
||||
return string_size(s->string);
|
||||
}
|
||||
|
||||
int furi_string_printf(FuriString* v, const char format[], ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int result = furi_string_vprintf(v, format, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
int furi_string_vprintf(FuriString* v, const char format[], va_list args) {
|
||||
return string_vprintf(v->string, format, args);
|
||||
}
|
||||
|
||||
int furi_string_cat_printf(FuriString* v, const char format[], ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int result = furi_string_cat_vprintf(v, format, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
int furi_string_cat_vprintf(FuriString* v, const char format[], va_list args) {
|
||||
FuriString* string = furi_string_alloc();
|
||||
int ret = furi_string_vprintf(string, format, args);
|
||||
furi_string_cat(v, string);
|
||||
furi_string_free(string);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool furi_string_empty(const FuriString* v) {
|
||||
return string_empty_p(v->string);
|
||||
}
|
||||
|
||||
void furi_string_replace_at(FuriString* v, size_t pos, size_t len, const char str2[]) {
|
||||
string_replace_at(v->string, pos, len, str2);
|
||||
}
|
||||
|
||||
size_t
|
||||
furi_string_replace(FuriString* string, FuriString* needle, FuriString* replace, size_t start) {
|
||||
return string_replace(string->string, needle->string, replace->string, start);
|
||||
}
|
||||
|
||||
size_t furi_string_replace_str(FuriString* v, const char str1[], const char str2[], size_t start) {
|
||||
return string_replace_str(v->string, str1, str2, start);
|
||||
}
|
||||
|
||||
void furi_string_replace_all_str(FuriString* v, const char str1[], const char str2[]) {
|
||||
string_replace_all_str(v->string, str1, str2);
|
||||
}
|
||||
|
||||
void furi_string_replace_all(FuriString* v, const FuriString* str1, const FuriString* str2) {
|
||||
string_replace_all(v->string, str1->string, str2->string);
|
||||
}
|
||||
|
||||
bool furi_string_start_with(const FuriString* v, const FuriString* v2) {
|
||||
return string_start_with_string_p(v->string, v2->string);
|
||||
}
|
||||
|
||||
bool furi_string_start_with_str(const FuriString* v, const char str[]) {
|
||||
return string_start_with_str_p(v->string, str);
|
||||
}
|
||||
|
||||
bool furi_string_end_with(const FuriString* v, const FuriString* v2) {
|
||||
return string_end_with_string_p(v->string, v2->string);
|
||||
}
|
||||
|
||||
bool furi_string_end_with_str(const FuriString* v, const char str[]) {
|
||||
return string_end_with_str_p(v->string, str);
|
||||
}
|
||||
|
||||
size_t furi_string_search_char(const FuriString* v, char c, size_t start) {
|
||||
return string_search_char(v->string, c, start);
|
||||
}
|
||||
|
||||
size_t furi_string_search_rchar(const FuriString* v, char c, size_t start) {
|
||||
return string_search_rchar(v->string, c, start);
|
||||
}
|
||||
|
||||
void furi_string_left(FuriString* v, size_t index) {
|
||||
string_left(v->string, index);
|
||||
}
|
||||
|
||||
void furi_string_right(FuriString* v, size_t index) {
|
||||
string_right(v->string, index);
|
||||
}
|
||||
|
||||
void furi_string_mid(FuriString* v, size_t index, size_t size) {
|
||||
string_mid(v->string, index, size);
|
||||
}
|
||||
|
||||
void furi_string_trim(FuriString* v, const char charac[]) {
|
||||
string_strim(v->string, charac);
|
||||
}
|
||||
|
||||
void furi_string_cat(FuriString* v, const FuriString* v2) {
|
||||
string_cat(v->string, v2->string);
|
||||
}
|
||||
|
||||
void furi_string_cat_str(FuriString* v, const char str[]) {
|
||||
string_cat(v->string, str);
|
||||
}
|
||||
|
||||
void furi_string_set_n(FuriString* v, const FuriString* ref, size_t offset, size_t length) {
|
||||
string_set_n(v->string, ref->string, offset, length);
|
||||
}
|
||||
|
||||
size_t furi_string_utf8_length(FuriString* str) {
|
||||
return string_length_u(str->string);
|
||||
}
|
||||
|
||||
void furi_string_utf8_push(FuriString* str, FuriStringUnicodeValue u) {
|
||||
string_push_u(str->string, u);
|
||||
}
|
||||
|
||||
static m_str1ng_utf8_state_e furi_state_to_state(FuriStringUTF8State state) {
|
||||
switch(state) {
|
||||
case FuriStringUTF8StateStarting:
|
||||
return M_STRING_UTF8_STARTING;
|
||||
case FuriStringUTF8StateDecoding1:
|
||||
return M_STRING_UTF8_DECODING_1;
|
||||
case FuriStringUTF8StateDecoding2:
|
||||
return M_STRING_UTF8_DECODING_2;
|
||||
case FuriStringUTF8StateDecoding3:
|
||||
return M_STRING_UTF8_DOCODING_3;
|
||||
default:
|
||||
return M_STRING_UTF8_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static FuriStringUTF8State state_to_furi_state(m_str1ng_utf8_state_e state) {
|
||||
switch(state) {
|
||||
case M_STRING_UTF8_STARTING:
|
||||
return FuriStringUTF8StateStarting;
|
||||
case M_STRING_UTF8_DECODING_1:
|
||||
return FuriStringUTF8StateDecoding1;
|
||||
case M_STRING_UTF8_DECODING_2:
|
||||
return FuriStringUTF8StateDecoding2;
|
||||
case M_STRING_UTF8_DOCODING_3:
|
||||
return FuriStringUTF8StateDecoding3;
|
||||
default:
|
||||
return FuriStringUTF8StateError;
|
||||
}
|
||||
}
|
||||
|
||||
void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnicodeValue* unicode) {
|
||||
m_str1ng_utf8_state_e m_state = furi_state_to_state(*state);
|
||||
m_str1ng_utf8_decode(c, &m_state, unicode);
|
||||
*state = state_to_furi_state(m_state);
|
||||
}
|
738
furi/core/string.h
Normal file
738
furi/core/string.h
Normal file
@@ -0,0 +1,738 @@
|
||||
/**
|
||||
* @file string.h
|
||||
* Furi string primitive
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <m-core.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Furi string failure constant.
|
||||
*/
|
||||
#define FURI_STRING_FAILURE ((size_t)-1)
|
||||
|
||||
/**
|
||||
* @brief Furi string primitive.
|
||||
*/
|
||||
typedef struct FuriString FuriString;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Constructors
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Allocate new FuriString.
|
||||
* @return FuriString*
|
||||
*/
|
||||
FuriString* furi_string_alloc();
|
||||
|
||||
/**
|
||||
* @brief Allocate new FuriString and set it to string.
|
||||
* Allocate & Set the string a to the string.
|
||||
* @param source
|
||||
* @return FuriString*
|
||||
*/
|
||||
FuriString* furi_string_alloc_set(const FuriString* source);
|
||||
|
||||
/**
|
||||
* @brief Allocate new FuriString and set it to C string.
|
||||
* Allocate & Set the string a to the C string.
|
||||
* @param cstr_source
|
||||
* @return FuriString*
|
||||
*/
|
||||
FuriString* furi_string_alloc_set_str(const char cstr_source[]);
|
||||
|
||||
/**
|
||||
* @brief Allocate new FuriString and printf to it.
|
||||
* Initialize and set a string to the given formatted value.
|
||||
* @param format
|
||||
* @param ...
|
||||
* @return FuriString*
|
||||
*/
|
||||
FuriString* furi_string_alloc_printf(const char format[], ...);
|
||||
|
||||
/**
|
||||
* @brief Allocate new FuriString and printf to it.
|
||||
* Initialize and set a string to the given formatted value.
|
||||
* @param format
|
||||
* @param args
|
||||
* @return FuriString*
|
||||
*/
|
||||
FuriString* furi_string_alloc_vprintf(const char format[], va_list args);
|
||||
|
||||
/**
|
||||
* @brief Allocate new FuriString and move source string content to it.
|
||||
* Allocate the string, set it to the other one, and destroy the other one.
|
||||
* @param source
|
||||
* @return FuriString*
|
||||
*/
|
||||
FuriString* furi_string_alloc_move(FuriString* source);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Destructors
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Free FuriString.
|
||||
* @param string
|
||||
*/
|
||||
void furi_string_free(FuriString* string);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// String memory management
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Reserve memory for string.
|
||||
* Modify the string capacity to be able to handle at least 'alloc' characters (including final null char).
|
||||
* @param string
|
||||
* @param size
|
||||
*/
|
||||
void furi_string_reserve(FuriString* string, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Reset string.
|
||||
* Make the string empty.
|
||||
* @param s
|
||||
*/
|
||||
void furi_string_reset(FuriString* string);
|
||||
|
||||
/**
|
||||
* @brief Swap two strings.
|
||||
* Swap the two strings string_1 and string_2.
|
||||
* @param string_1
|
||||
* @param string_2
|
||||
*/
|
||||
void furi_string_swap(FuriString* string_1, FuriString* string_2);
|
||||
|
||||
/**
|
||||
* @brief Move string_2 content to string_1.
|
||||
* Set the string to the other one, and destroy the other one.
|
||||
* @param string_1
|
||||
* @param string_2
|
||||
*/
|
||||
void furi_string_move(FuriString* string_1, FuriString* string_2);
|
||||
|
||||
/**
|
||||
* @brief Compute a hash for the string.
|
||||
* @param string
|
||||
* @return size_t
|
||||
*/
|
||||
size_t furi_string_hash(const FuriString* string);
|
||||
|
||||
/**
|
||||
* @brief Get string size (usually length, but not for UTF-8)
|
||||
* @param string
|
||||
* @return size_t
|
||||
*/
|
||||
size_t furi_string_size(const FuriString* string);
|
||||
|
||||
/**
|
||||
* @brief Check that string is empty or not
|
||||
* @param string
|
||||
* @return bool
|
||||
*/
|
||||
bool furi_string_empty(const FuriString* string);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Getters
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Get the character at the given index.
|
||||
* Return the selected character of the string.
|
||||
* @param string
|
||||
* @param index
|
||||
* @return char
|
||||
*/
|
||||
char furi_string_get_char(const FuriString* string, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Return the string view a classic C string.
|
||||
* @param string
|
||||
* @return const char*
|
||||
*/
|
||||
const char* furi_string_get_cstr(const FuriString* string);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Setters
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Set the string to the other string.
|
||||
* Set the string to the source string.
|
||||
* @param string
|
||||
* @param source
|
||||
*/
|
||||
void furi_string_set(FuriString* string, FuriString* source);
|
||||
|
||||
/**
|
||||
* @brief Set the string to the other C string.
|
||||
* Set the string to the source C string.
|
||||
* @param string
|
||||
* @param source
|
||||
*/
|
||||
void furi_string_set_str(FuriString* string, const char source[]);
|
||||
|
||||
/**
|
||||
* @brief Set the string to the n first characters of the C string.
|
||||
* @param string
|
||||
* @param source
|
||||
* @param length
|
||||
*/
|
||||
void furi_string_set_strn(FuriString* string, const char source[], size_t length);
|
||||
|
||||
/**
|
||||
* @brief Set the character at the given index.
|
||||
* @param string
|
||||
* @param index
|
||||
* @param c
|
||||
*/
|
||||
void furi_string_set_char(FuriString* string, size_t index, const char c);
|
||||
|
||||
/**
|
||||
* @brief Set the string to the n first characters of other one.
|
||||
* @param string
|
||||
* @param source
|
||||
* @param offset
|
||||
* @param length
|
||||
*/
|
||||
void furi_string_set_n(FuriString* string, const FuriString* source, size_t offset, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Format in the string the given printf format
|
||||
* @param string
|
||||
* @param format
|
||||
* @param ...
|
||||
* @return int
|
||||
*/
|
||||
int furi_string_printf(FuriString* string, const char format[], ...);
|
||||
|
||||
/**
|
||||
* @brief Format in the string the given printf format
|
||||
* @param string
|
||||
* @param format
|
||||
* @param args
|
||||
* @return int
|
||||
*/
|
||||
int furi_string_vprintf(FuriString* string, const char format[], va_list args);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Appending
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Append a character to the string.
|
||||
* @param string
|
||||
* @param c
|
||||
*/
|
||||
void furi_string_push_back(FuriString* string, char c);
|
||||
|
||||
/**
|
||||
* @brief Append a string to the string.
|
||||
* Concatenate the string with the other string.
|
||||
* @param string_1
|
||||
* @param string_2
|
||||
*/
|
||||
void furi_string_cat(FuriString* string_1, const FuriString* string_2);
|
||||
|
||||
/**
|
||||
* @brief Append a C string to the string.
|
||||
* Concatenate the string with the C string.
|
||||
* @param string_1
|
||||
* @param cstring_2
|
||||
*/
|
||||
void furi_string_cat_str(FuriString* string_1, const char cstring_2[]);
|
||||
|
||||
/**
|
||||
* @brief Append to the string the formatted string of the given printf format.
|
||||
* @param string
|
||||
* @param format
|
||||
* @param ...
|
||||
* @return int
|
||||
*/
|
||||
int furi_string_cat_printf(FuriString* string, const char format[], ...);
|
||||
|
||||
/**
|
||||
* @brief Append to the string the formatted string of the given printf format.
|
||||
* @param string
|
||||
* @param format
|
||||
* @param args
|
||||
* @return int
|
||||
*/
|
||||
int furi_string_cat_vprintf(FuriString* string, const char format[], va_list args);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Comparators
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Compare two strings and return the sort order.
|
||||
* @param string_1
|
||||
* @param string_2
|
||||
* @return int
|
||||
*/
|
||||
int furi_string_cmp(const FuriString* string_1, const FuriString* string_2);
|
||||
|
||||
/**
|
||||
* @brief Compare string with C string and return the sort order.
|
||||
* @param string_1
|
||||
* @param cstring_2
|
||||
* @return int
|
||||
*/
|
||||
int furi_string_cmp_str(const FuriString* string_1, const char cstring_2[]);
|
||||
|
||||
/**
|
||||
* @brief Compare two strings (case insensitive according to the current locale) and return the sort order.
|
||||
* Note: doesn't work with UTF-8 strings.
|
||||
* @param string_1
|
||||
* @param string_2
|
||||
* @return int
|
||||
*/
|
||||
int furi_string_cmpi(const FuriString* string_1, const FuriString* string_2);
|
||||
|
||||
/**
|
||||
* @brief Compare string with C string (case insensitive according to the current locale) and return the sort order.
|
||||
* Note: doesn't work with UTF-8 strings.
|
||||
* @param string_1
|
||||
* @param cstring_2
|
||||
* @return int
|
||||
*/
|
||||
int furi_string_cmpi_str(const FuriString* string_1, const char cstring_2[]);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Search
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Search the first occurrence of the needle in the string from the position start.
|
||||
* Return STRING_FAILURE if not found.
|
||||
* By default, start is zero.
|
||||
* @param string
|
||||
* @param needle
|
||||
* @param start
|
||||
* @return size_t
|
||||
*/
|
||||
size_t furi_string_search(const FuriString* string, const FuriString* needle, size_t start);
|
||||
|
||||
/**
|
||||
* @brief Search the first occurrence of the needle in the string from the position start.
|
||||
* Return STRING_FAILURE if not found.
|
||||
* @param string
|
||||
* @param needle
|
||||
* @param start
|
||||
* @return size_t
|
||||
*/
|
||||
size_t furi_string_search_str(const FuriString* string, const char needle[], size_t start);
|
||||
|
||||
/**
|
||||
* @brief Search for the position of the character c from the position start (include) in the string.
|
||||
* Return STRING_FAILURE if not found.
|
||||
* By default, start is zero.
|
||||
* @param string
|
||||
* @param c
|
||||
* @param start
|
||||
* @return size_t
|
||||
*/
|
||||
size_t furi_string_search_char(const FuriString* string, char c, size_t start);
|
||||
|
||||
/**
|
||||
* @brief Reverse search for the position of the character c from the position start (include) in the string.
|
||||
* Return STRING_FAILURE if not found.
|
||||
* By default, start is zero.
|
||||
* @param string
|
||||
* @param c
|
||||
* @param start
|
||||
* @return size_t
|
||||
*/
|
||||
size_t furi_string_search_rchar(const FuriString* string, char c, size_t start);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Equality
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Test if two strings are equal.
|
||||
* @param string_1
|
||||
* @param string_2
|
||||
* @return bool
|
||||
*/
|
||||
bool furi_string_equal(const FuriString* string_1, const FuriString* string_2);
|
||||
|
||||
/**
|
||||
* @brief Test if the string is equal to the C string.
|
||||
* @param string_1
|
||||
* @param cstring_2
|
||||
* @return bool
|
||||
*/
|
||||
bool furi_string_equal_str(const FuriString* string_1, const char cstring_2[]);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Replace
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Replace in the string the sub-string at position 'pos' for 'len' bytes into the C string 'replace'.
|
||||
* @param string
|
||||
* @param pos
|
||||
* @param len
|
||||
* @param replace
|
||||
*/
|
||||
void furi_string_replace_at(FuriString* string, size_t pos, size_t len, const char replace[]);
|
||||
|
||||
/**
|
||||
* @brief Replace a string 'needle' to string 'replace' in a string from 'start' position.
|
||||
* By default, start is zero.
|
||||
* Return STRING_FAILURE if 'needle' not found or replace position.
|
||||
* @param string
|
||||
* @param needle
|
||||
* @param replace
|
||||
* @param start
|
||||
* @return size_t
|
||||
*/
|
||||
size_t
|
||||
furi_string_replace(FuriString* string, FuriString* needle, FuriString* replace, size_t start);
|
||||
|
||||
/**
|
||||
* @brief Replace a C string 'needle' to C string 'replace' in a string from 'start' position.
|
||||
* By default, start is zero.
|
||||
* Return STRING_FAILURE if 'needle' not found or replace position.
|
||||
* @param string
|
||||
* @param needle
|
||||
* @param replace
|
||||
* @param start
|
||||
* @return size_t
|
||||
*/
|
||||
size_t furi_string_replace_str(
|
||||
FuriString* string,
|
||||
const char needle[],
|
||||
const char replace[],
|
||||
size_t start);
|
||||
|
||||
/**
|
||||
* @brief Replace all occurrences of 'needle' string into 'replace' string.
|
||||
* @param string
|
||||
* @param needle
|
||||
* @param replace
|
||||
*/
|
||||
void furi_string_replace_all(
|
||||
FuriString* string,
|
||||
const FuriString* needle,
|
||||
const FuriString* replace);
|
||||
|
||||
/**
|
||||
* @brief Replace all occurrences of 'needle' C string into 'replace' C string.
|
||||
* @param string
|
||||
* @param needle
|
||||
* @param replace
|
||||
*/
|
||||
void furi_string_replace_all_str(FuriString* string, const char needle[], const char replace[]);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Start / End tests
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Test if the string starts with the given string.
|
||||
* @param string
|
||||
* @param start
|
||||
* @return bool
|
||||
*/
|
||||
bool furi_string_start_with(const FuriString* string, const FuriString* start);
|
||||
|
||||
/**
|
||||
* @brief Test if the string starts with the given C string.
|
||||
* @param string
|
||||
* @param start
|
||||
* @return bool
|
||||
*/
|
||||
bool furi_string_start_with_str(const FuriString* string, const char start[]);
|
||||
|
||||
/**
|
||||
* @brief Test if the string ends with the given string.
|
||||
* @param string
|
||||
* @param end
|
||||
* @return bool
|
||||
*/
|
||||
bool furi_string_end_with(const FuriString* string, const FuriString* end);
|
||||
|
||||
/**
|
||||
* @brief Test if the string ends with the given C string.
|
||||
* @param string
|
||||
* @param end
|
||||
* @return bool
|
||||
*/
|
||||
bool furi_string_end_with_str(const FuriString* string, const char end[]);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Trim
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Trim the string left to the first 'index' bytes.
|
||||
* @param string
|
||||
* @param index
|
||||
*/
|
||||
void furi_string_left(FuriString* string, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Trim the string right from the 'index' position to the last position.
|
||||
* @param string
|
||||
* @param index
|
||||
*/
|
||||
void furi_string_right(FuriString* string, size_t index);
|
||||
|
||||
/**
|
||||
* @brief Trim the string from position index to size bytes.
|
||||
* See also furi_string_set_n.
|
||||
* @param string
|
||||
* @param index
|
||||
* @param size
|
||||
*/
|
||||
void furi_string_mid(FuriString* string, size_t index, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Trim a string from the given set of characters (default is " \n\r\t").
|
||||
* @param string
|
||||
* @param chars
|
||||
*/
|
||||
void furi_string_trim(FuriString* string, const char chars[]);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// UTF8
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief An unicode value.
|
||||
*/
|
||||
typedef unsigned int FuriStringUnicodeValue;
|
||||
|
||||
/**
|
||||
* @brief Compute the length in UTF8 characters in the string.
|
||||
* @param string
|
||||
* @return size_t
|
||||
*/
|
||||
size_t furi_string_utf8_length(FuriString* string);
|
||||
|
||||
/**
|
||||
* @brief Push unicode into string, encoding it in UTF8.
|
||||
* @param string
|
||||
* @param unicode
|
||||
*/
|
||||
void furi_string_utf8_push(FuriString* string, FuriStringUnicodeValue unicode);
|
||||
|
||||
/**
|
||||
* @brief State of the UTF8 decoding machine state.
|
||||
*/
|
||||
typedef enum {
|
||||
FuriStringUTF8StateStarting,
|
||||
FuriStringUTF8StateDecoding1,
|
||||
FuriStringUTF8StateDecoding2,
|
||||
FuriStringUTF8StateDecoding3,
|
||||
FuriStringUTF8StateError
|
||||
} FuriStringUTF8State;
|
||||
|
||||
/**
|
||||
* @brief Main generic UTF8 decoder.
|
||||
* It takes a character, and the previous state and the previous value of the unicode value.
|
||||
* It updates the state and the decoded unicode value.
|
||||
* A decoded unicode encoded value is valid only when the state is FuriStringUTF8StateStarting.
|
||||
* @param c
|
||||
* @param state
|
||||
* @param unicode
|
||||
*/
|
||||
void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnicodeValue* unicode);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Lasciate ogne speranza, voi ch’entrate
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
* Select either the string function or the str function depending on
|
||||
* the b operand to the function.
|
||||
* func1 is the string function / func2 is the str function.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Select for 1 argument
|
||||
*/
|
||||
#define FURI_STRING_SELECT1(func1, func2, a) \
|
||||
_Generic((a), char* : func2, const char* : func2, FuriString* : func1, const FuriString* : func1)(a)
|
||||
|
||||
/**
|
||||
* @brief Select for 2 arguments
|
||||
*/
|
||||
#define FURI_STRING_SELECT2(func1, func2, a, b) \
|
||||
_Generic((b), char* : func2, const char* : func2, FuriString* : func1, const FuriString* : func1)(a, b)
|
||||
|
||||
/**
|
||||
* @brief Select for 3 arguments
|
||||
*/
|
||||
#define FURI_STRING_SELECT3(func1, func2, a, b, c) \
|
||||
_Generic((b), char* : func2, const char* : func2, FuriString* : func1, const FuriString* : func1)(a, b, c)
|
||||
|
||||
/**
|
||||
* @brief Select for 4 arguments
|
||||
*/
|
||||
#define FURI_STRING_SELECT4(func1, func2, a, b, c, d) \
|
||||
_Generic((b), char* : func2, const char* : func2, FuriString* : func1, const FuriString* : func1)(a, b, c, d)
|
||||
|
||||
/**
|
||||
* @brief Allocate new FuriString and set it content to string (or C string).
|
||||
* ([c]string)
|
||||
*/
|
||||
#define furi_string_alloc_set(a) \
|
||||
FURI_STRING_SELECT1(furi_string_alloc_set, furi_string_alloc_set_str, a)
|
||||
|
||||
/**
|
||||
* @brief Set the string content to string (or C string).
|
||||
* (string, [c]string)
|
||||
*/
|
||||
#define furi_string_set(a, b) FURI_STRING_SELECT2(furi_string_set, furi_string_set_str, a, b)
|
||||
|
||||
/**
|
||||
* @brief Compare string with string (or C string) and return the sort order.
|
||||
* Note: doesn't work with UTF-8 strings.
|
||||
* (string, [c]string)
|
||||
*/
|
||||
#define furi_string_cmp(a, b) FURI_STRING_SELECT2(furi_string_cmp, furi_string_cmp_str, a, b)
|
||||
|
||||
/**
|
||||
* @brief Compare string with string (or C string) (case insensitive according to the current locale) and return the sort order.
|
||||
* Note: doesn't work with UTF-8 strings.
|
||||
* (string, [c]string)
|
||||
*/
|
||||
#define furi_string_cmpi(a, b) FURI_STRING_SELECT2(furi_string_cmpi, furi_string_cmpi_str, a, b)
|
||||
|
||||
/**
|
||||
* @brief Test if the string is equal to the string (or C string).
|
||||
* (string, [c]string)
|
||||
*/
|
||||
#define furi_string_equal(a, b) FURI_STRING_SELECT2(furi_string_equal, furi_string_equal_str, a, b)
|
||||
|
||||
/**
|
||||
* @brief Replace all occurrences of string into string (or C string to another C string) in a string.
|
||||
* (string, [c]string, [c]string)
|
||||
*/
|
||||
#define furi_string_replace_all(a, b, c) \
|
||||
FURI_STRING_SELECT3(furi_string_replace_all, furi_string_replace_all_str, a, b, c)
|
||||
|
||||
/**
|
||||
* @brief Search for a string (or C string) in a string
|
||||
* (string, [c]string[, start=0])
|
||||
*/
|
||||
#define furi_string_search(v, ...) \
|
||||
M_APPLY( \
|
||||
FURI_STRING_SELECT3, \
|
||||
furi_string_search, \
|
||||
furi_string_search_str, \
|
||||
v, \
|
||||
M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Search for a C string in a string
|
||||
* (string, cstring[, start=0])
|
||||
*/
|
||||
#define furi_string_search_str(v, ...) \
|
||||
M_APPLY(furi_string_search_str, v, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Test if the string starts with the given string (or C string).
|
||||
* (string, [c]string)
|
||||
*/
|
||||
#define furi_string_start_with(a, b) \
|
||||
FURI_STRING_SELECT2(furi_string_start_with, furi_string_start_with_str, a, b)
|
||||
|
||||
/**
|
||||
* @brief Test if the string ends with the given string (or C string).
|
||||
* (string, [c]string)
|
||||
*/
|
||||
#define furi_string_end_with(a, b) \
|
||||
FURI_STRING_SELECT2(furi_string_end_with, furi_string_end_with_str, a, b)
|
||||
|
||||
/**
|
||||
* @brief Append a string (or C string) to the string.
|
||||
* (string, [c]string)
|
||||
*/
|
||||
#define furi_string_cat(a, b) FURI_STRING_SELECT2(furi_string_cat, furi_string_cat_str, a, b)
|
||||
|
||||
/**
|
||||
* @brief Trim a string from the given set of characters (default is " \n\r\t").
|
||||
* (string[, set=" \n\r\t"])
|
||||
*/
|
||||
#define furi_string_trim(...) M_APPLY(furi_string_trim, M_IF_DEFAULT1(" \n\r\t", __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Search for a character in a string.
|
||||
* (string, character[, start=0])
|
||||
*/
|
||||
#define furi_string_search_char(v, ...) \
|
||||
M_APPLY(furi_string_search_char, v, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Reverse Search for a character in a string.
|
||||
* (string, character[, start=0])
|
||||
*/
|
||||
#define furi_string_search_rchar(v, ...) \
|
||||
M_APPLY(furi_string_search_rchar, v, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Replace a string to another string (or C string to another C string) in a string.
|
||||
* (string, [c]string, [c]string[, start=0])
|
||||
*/
|
||||
#define furi_string_replace(a, b, ...) \
|
||||
M_APPLY( \
|
||||
FURI_STRING_SELECT4, \
|
||||
furi_string_replace, \
|
||||
furi_string_replace_str, \
|
||||
a, \
|
||||
b, \
|
||||
M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Replace a C string to another C string in a string.
|
||||
* (string, cstring, cstring[, start=0])
|
||||
*/
|
||||
#define furi_string_replace_str(a, b, ...) \
|
||||
M_APPLY(furi_string_replace_str, a, b, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief INIT OPLIST for FuriString.
|
||||
*/
|
||||
#define F_STR_INIT(a) ((a) = furi_string_alloc())
|
||||
|
||||
/**
|
||||
* @brief INIT SET OPLIST for FuriString.
|
||||
*/
|
||||
#define F_STR_INIT_SET(a, b) ((a) = furi_string_alloc_set(b))
|
||||
|
||||
/**
|
||||
* @brief OPLIST for FuriString.
|
||||
*/
|
||||
#define FURI_STRING_OPLIST \
|
||||
(INIT(F_STR_INIT), \
|
||||
INIT_SET(F_STR_INIT_SET), \
|
||||
SET(furi_string_set), \
|
||||
INIT_MOVE(furi_string_alloc_move), \
|
||||
MOVE(furi_string_move), \
|
||||
SWAP(furi_string_swap), \
|
||||
RESET(furi_string_reset), \
|
||||
EMPTY_P(furi_string_empty), \
|
||||
CLEAR(furi_string_free), \
|
||||
HASH(furi_string_hash), \
|
||||
EQUAL(furi_string_equal), \
|
||||
CMP(furi_string_cmp), \
|
||||
TYPE(FuriString*))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -5,10 +5,10 @@
|
||||
#include "check.h"
|
||||
#include "common_defines.h"
|
||||
#include "mutex.h"
|
||||
#include "string.h"
|
||||
|
||||
#include <task.h>
|
||||
#include "log.h"
|
||||
#include <m-string.h>
|
||||
#include <furi_hal_rtc.h>
|
||||
#include <furi_hal_console.h>
|
||||
|
||||
@@ -18,7 +18,7 @@ typedef struct FuriThreadStdout FuriThreadStdout;
|
||||
|
||||
struct FuriThreadStdout {
|
||||
FuriThreadStdoutWriteCallback write_callback;
|
||||
string_t buffer;
|
||||
FuriString* buffer;
|
||||
};
|
||||
|
||||
struct FuriThread {
|
||||
@@ -109,7 +109,7 @@ static void furi_thread_body(void* context) {
|
||||
|
||||
FuriThread* furi_thread_alloc() {
|
||||
FuriThread* thread = malloc(sizeof(FuriThread));
|
||||
string_init(thread->output.buffer);
|
||||
thread->output.buffer = furi_string_alloc();
|
||||
thread->is_service = false;
|
||||
return thread;
|
||||
}
|
||||
@@ -119,7 +119,7 @@ void furi_thread_free(FuriThread* thread) {
|
||||
furi_assert(thread->state == FuriThreadStateStopped);
|
||||
|
||||
if(thread->name) free((void*)thread->name);
|
||||
string_clear(thread->output.buffer);
|
||||
furi_string_free(thread->output.buffer);
|
||||
|
||||
free(thread);
|
||||
}
|
||||
@@ -485,11 +485,11 @@ static size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, s
|
||||
}
|
||||
|
||||
static int32_t __furi_thread_stdout_flush(FuriThread* thread) {
|
||||
string_ptr buffer = thread->output.buffer;
|
||||
size_t size = string_size(buffer);
|
||||
FuriString* buffer = thread->output.buffer;
|
||||
size_t size = furi_string_size(buffer);
|
||||
if(size > 0) {
|
||||
__furi_thread_stdout_write(thread, string_get_cstr(buffer), size);
|
||||
string_reset(buffer);
|
||||
__furi_thread_stdout_write(thread, furi_string_get_cstr(buffer), size);
|
||||
furi_string_reset(buffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -516,7 +516,7 @@ size_t furi_thread_stdout_write(const char* data, size_t size) {
|
||||
} else {
|
||||
// string_cat doesn't work here because we need to write the exact size data
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
string_push_back(thread->output.buffer, data[i]);
|
||||
furi_string_push_back(thread->output.buffer, data[i]);
|
||||
if(data[i] == '\n') {
|
||||
__furi_thread_stdout_flush(thread);
|
||||
}
|
||||
|
Reference in New Issue
Block a user