mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-22 21:01:40 +03:00
[FL-3884] Proper integer parsing (#3839)
* feat: strint_to_uint32 and tests * fix: permit explicit bases and prefixes * feat: strint_to_{int32,uint16,int16} * feat: strint_to_u?int64 * refactor: replace strtol, strtoul, sscanf with strint_to_* * fix: api symbols * docs: document parameter `end` of strint_to_uint_32 * style: apply changes requested by hedger * refactor: fix pvs-studio diagnostic * style: apply changes requested by CookiePLMonster * fix: unused var * fix: pointer type * refactor: convert atoi to strint_to_* * fix: strint_to_uint8 doesn't actually exist ._ . * fix: memory leak * style: address review comments * Toolbox: couple small comments in the code and doxygen comment update. SubGhz, Loader: fix strint usage. * Loader: fix incorrect cast Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
6a48dd28f5
commit
c9791a280a
@ -1,5 +1,7 @@
|
||||
#include "../rpc_debug_app.h"
|
||||
|
||||
#include <lib/toolbox/strint.h>
|
||||
|
||||
static bool rpc_debug_app_scene_input_error_code_validator_callback(
|
||||
const char* text,
|
||||
FuriString* error,
|
||||
@ -44,9 +46,8 @@ bool rpc_debug_app_scene_input_error_code_on_event(void* context, SceneManagerEv
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == RpcDebugAppCustomEventInputErrorCode) {
|
||||
char* end;
|
||||
int error_code = strtol(app->text_store, &end, 10);
|
||||
if(!*end) {
|
||||
uint32_t error_code;
|
||||
if(strint_to_uint32(app->text_store, NULL, &error_code, 10) == StrintParseNoError) {
|
||||
rpc_system_app_set_error_code(app->rpc, error_code);
|
||||
}
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
|
||||
#include <lib/toolbox/strint.h>
|
||||
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
@ -320,7 +322,7 @@ int32_t uart_echo_app(void* p) {
|
||||
uint32_t baudrate = DEFAULT_BAUD_RATE;
|
||||
if(p) {
|
||||
const char* baudrate_str = p;
|
||||
if(sscanf(baudrate_str, "%lu", &baudrate) != 1) {
|
||||
if(strint_to_uint32(baudrate_str, NULL, &baudrate, 10) != StrintParseNoError) {
|
||||
FURI_LOG_E(TAG, "Invalid baudrate: %s", baudrate_str);
|
||||
baudrate = DEFAULT_BAUD_RATE;
|
||||
}
|
||||
|
@ -220,3 +220,11 @@ App(
|
||||
entry_point="get_api",
|
||||
requires=["unit_tests"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="test_strint",
|
||||
sources=["tests/common/*.c", "tests/strint/*.c"],
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="get_api",
|
||||
requires=["unit_tests"],
|
||||
)
|
||||
|
142
applications/debug/unit_tests/tests/strint/strint_test.c
Normal file
142
applications/debug/unit_tests/tests/strint/strint_test.c
Normal file
@ -0,0 +1,142 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include "../test.h" // IWYU pragma: keep
|
||||
|
||||
#include <toolbox/strint.h>
|
||||
|
||||
MU_TEST(strint_test_basic) {
|
||||
uint32_t result = 0;
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("123456", NULL, &result, 10));
|
||||
mu_assert_int_eq(123456, result);
|
||||
}
|
||||
|
||||
MU_TEST(strint_test_junk) {
|
||||
uint32_t result = 0;
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32(" 123456 ", NULL, &result, 10));
|
||||
mu_assert_int_eq(123456, result);
|
||||
mu_assert_int_eq(
|
||||
StrintParseNoError, strint_to_uint32(" \r\n\r\n 123456 ", NULL, &result, 10));
|
||||
mu_assert_int_eq(123456, result);
|
||||
}
|
||||
|
||||
MU_TEST(strint_test_tail) {
|
||||
uint32_t result = 0;
|
||||
char* tail;
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("123456tail", &tail, &result, 10));
|
||||
mu_assert_int_eq(123456, result);
|
||||
mu_assert_string_eq("tail", tail);
|
||||
mu_assert_int_eq(
|
||||
StrintParseNoError, strint_to_uint32(" \r\n 123456tail", &tail, &result, 10));
|
||||
mu_assert_int_eq(123456, result);
|
||||
mu_assert_string_eq("tail", tail);
|
||||
}
|
||||
|
||||
MU_TEST(strint_test_errors) {
|
||||
uint32_t result = 123;
|
||||
mu_assert_int_eq(StrintParseAbsentError, strint_to_uint32("", NULL, &result, 10));
|
||||
mu_assert_int_eq(123, result);
|
||||
mu_assert_int_eq(StrintParseAbsentError, strint_to_uint32(" asd\r\n", NULL, &result, 10));
|
||||
mu_assert_int_eq(123, result);
|
||||
mu_assert_int_eq(StrintParseSignError, strint_to_uint32("+++123456", NULL, &result, 10));
|
||||
mu_assert_int_eq(123, result);
|
||||
mu_assert_int_eq(StrintParseSignError, strint_to_uint32("-1", NULL, &result, 10));
|
||||
mu_assert_int_eq(123, result);
|
||||
mu_assert_int_eq(
|
||||
StrintParseOverflowError,
|
||||
strint_to_uint32("0xAAAAAAAAAAAAAAAADEADBEEF!!!!!!", NULL, &result, 0));
|
||||
mu_assert_int_eq(123, result);
|
||||
mu_assert_int_eq(StrintParseOverflowError, strint_to_uint32("4294967296", NULL, &result, 0));
|
||||
mu_assert_int_eq(123, result);
|
||||
|
||||
int32_t result_i32 = 123;
|
||||
mu_assert_int_eq(
|
||||
StrintParseOverflowError, strint_to_int32("-2147483649", NULL, &result_i32, 0));
|
||||
mu_assert_int_eq(123, result_i32);
|
||||
}
|
||||
|
||||
MU_TEST(strint_test_bases) {
|
||||
uint32_t result = 0;
|
||||
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0x123", NULL, &result, 0));
|
||||
mu_assert_int_eq(0x123, result);
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0X123", NULL, &result, 0));
|
||||
mu_assert_int_eq(0x123, result);
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0xDEADBEEF", NULL, &result, 0));
|
||||
mu_assert_int_eq(0xDEADBEEF, result);
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0xDEADBEEF", NULL, &result, 16));
|
||||
mu_assert_int_eq(0xDEADBEEF, result);
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("123", NULL, &result, 16));
|
||||
mu_assert_int_eq(0x123, result);
|
||||
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("123", NULL, &result, 0));
|
||||
mu_assert_int_eq(123, result);
|
||||
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0123", NULL, &result, 0));
|
||||
mu_assert_int_eq(0123, result);
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0123", NULL, &result, 8));
|
||||
mu_assert_int_eq(0123, result);
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("123", NULL, &result, 8));
|
||||
mu_assert_int_eq(0123, result);
|
||||
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0b101", NULL, &result, 0));
|
||||
mu_assert_int_eq(0b101, result);
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0b101", NULL, &result, 2));
|
||||
mu_assert_int_eq(0b101, result);
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0B101", NULL, &result, 0));
|
||||
mu_assert_int_eq(0b101, result);
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("101", NULL, &result, 2));
|
||||
mu_assert_int_eq(0b101, result);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(strint_test_limits) {
|
||||
uint64_t result_u64 = 0;
|
||||
mu_assert_int_eq(
|
||||
StrintParseNoError, strint_to_uint64("18446744073709551615", NULL, &result_u64, 0));
|
||||
// `mu_assert_int_eq' does not support longs :(
|
||||
mu_assert(UINT64_MAX == result_u64, "result does not equal UINT64_MAX");
|
||||
|
||||
int64_t result_i64 = 0;
|
||||
mu_assert_int_eq(
|
||||
StrintParseNoError, strint_to_int64("9223372036854775807", NULL, &result_i64, 0));
|
||||
mu_assert(INT64_MAX == result_i64, "result does not equal INT64_MAX");
|
||||
mu_assert_int_eq(
|
||||
StrintParseNoError, strint_to_int64("-9223372036854775808", NULL, &result_i64, 0));
|
||||
mu_assert(INT64_MIN == result_i64, "result does not equal INT64_MIN");
|
||||
|
||||
uint32_t result_u32 = 0;
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("4294967295", NULL, &result_u32, 0));
|
||||
mu_assert_int_eq(UINT32_MAX, result_u32);
|
||||
|
||||
int32_t result_i32 = 0;
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_int32("2147483647", NULL, &result_i32, 0));
|
||||
mu_assert_int_eq(INT32_MAX, result_i32);
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_int32("-2147483648", NULL, &result_i32, 0));
|
||||
mu_assert_int_eq(INT32_MIN, result_i32);
|
||||
|
||||
uint16_t result_u16 = 0;
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_uint16("65535", NULL, &result_u16, 0));
|
||||
mu_assert_int_eq(UINT16_MAX, result_u16);
|
||||
|
||||
int16_t result_i16 = 0;
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_int16("32767", NULL, &result_i16, 0));
|
||||
mu_assert_int_eq(INT16_MAX, result_i16);
|
||||
mu_assert_int_eq(StrintParseNoError, strint_to_int16("-32768", NULL, &result_i16, 0));
|
||||
mu_assert_int_eq(INT16_MIN, result_i16);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(test_strint_suite) {
|
||||
MU_RUN_TEST(strint_test_basic);
|
||||
MU_RUN_TEST(strint_test_junk);
|
||||
MU_RUN_TEST(strint_test_tail);
|
||||
MU_RUN_TEST(strint_test_errors);
|
||||
MU_RUN_TEST(strint_test_bases);
|
||||
MU_RUN_TEST(strint_test_limits);
|
||||
}
|
||||
|
||||
int run_minunit_test_strint(void) {
|
||||
MU_RUN_SUITE(test_strint_suite);
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
|
||||
TEST_API_DEFINE(run_minunit_test_strint)
|
@ -3,6 +3,7 @@
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <lib/toolbox/strint.h>
|
||||
#include <storage/storage.h>
|
||||
#include "ducky_script.h"
|
||||
#include "ducky_script_i.h"
|
||||
@ -64,7 +65,7 @@ uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept
|
||||
|
||||
bool ducky_get_number(const char* param, uint32_t* val) {
|
||||
uint32_t value = 0;
|
||||
if(sscanf(param, "%lu", &value) == 1) {
|
||||
if(strint_to_uint32(param, NULL, &value, 10) == StrintParseNoError) {
|
||||
*val = value;
|
||||
return true;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <furi_hal_infrared.h>
|
||||
#include <flipper_format.h>
|
||||
#include <toolbox/args.h>
|
||||
#include <toolbox/strint.h>
|
||||
#include <m-dict.h>
|
||||
|
||||
#include "infrared_signal.h"
|
||||
@ -176,25 +177,28 @@ static bool infrared_cli_parse_raw(const char* str, InfraredSignal* signal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t* timings = malloc(sizeof(uint32_t) * MAX_TIMINGS_AMOUNT);
|
||||
uint32_t frequency = atoi(frequency_str);
|
||||
float duty_cycle = (float)atoi(duty_cycle_str) / 100;
|
||||
uint32_t frequency;
|
||||
uint32_t duty_cycle_u32;
|
||||
if(strint_to_uint32(frequency_str, NULL, &frequency, 10) != StrintParseNoError ||
|
||||
strint_to_uint32(duty_cycle_str, NULL, &duty_cycle_u32, 10) != StrintParseNoError)
|
||||
return false;
|
||||
float duty_cycle = duty_cycle_u32 / 100.0f;
|
||||
|
||||
str += strlen(frequency_str) + strlen(duty_cycle_str) + INFRARED_CLI_BUF_SIZE;
|
||||
|
||||
uint32_t* timings = malloc(sizeof(uint32_t) * MAX_TIMINGS_AMOUNT);
|
||||
size_t timings_size = 0;
|
||||
while(1) {
|
||||
while(*str == ' ') {
|
||||
++str;
|
||||
}
|
||||
|
||||
char timing_str[INFRARED_CLI_BUF_SIZE];
|
||||
if(sscanf(str, "%9s", timing_str) != 1) {
|
||||
uint32_t timing;
|
||||
char* next_token;
|
||||
if(strint_to_uint32(str, &next_token, &timing, 10) != StrintParseNoError) {
|
||||
break;
|
||||
}
|
||||
|
||||
str += strlen(timing_str);
|
||||
uint32_t timing = atoi(timing_str);
|
||||
str = next_token;
|
||||
|
||||
if((timing <= 0) || (timings_size >= MAX_TIMINGS_AMOUNT)) {
|
||||
break;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <lib/nfc/protocols/mf_desfire/mf_desfire.h>
|
||||
#include <lib/toolbox/strint.h>
|
||||
|
||||
#include <applications/services/locale/locale.h>
|
||||
#include <datetime/datetime.h>
|
||||
@ -72,7 +73,10 @@ static bool itso_parse(const NfcDevice* device, FuriString* parsed_data) {
|
||||
dateBuff[17] = '\0';
|
||||
|
||||
// DateStamp is defined in BS EN 1545 - Days passed since 01/01/1997
|
||||
uint32_t dateStamp = (int)strtol(datep, NULL, 16);
|
||||
uint32_t dateStamp;
|
||||
if(strint_to_uint32(datep, NULL, &dateStamp, 16) != StrintParseNoError) {
|
||||
return false;
|
||||
}
|
||||
uint32_t unixTimestamp = dateStamp * 24 * 60 * 60 + 852076800U;
|
||||
|
||||
furi_string_set(parsed_data, "\e#ITSO Card\n");
|
||||
|
@ -3,18 +3,20 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <lib/subghz/subghz_keystore.h>
|
||||
#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
|
||||
|
||||
#include <lib/subghz/subghz_keystore.h>
|
||||
#include <lib/subghz/receiver.h>
|
||||
#include <lib/subghz/transmitter.h>
|
||||
#include <lib/subghz/subghz_file_encoder_worker.h>
|
||||
#include <lib/subghz/protocols/protocol_items.h>
|
||||
#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
|
||||
#include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
|
||||
#include <lib/subghz/devices/devices.h>
|
||||
#include <lib/subghz/devices/cc1101_configs.h>
|
||||
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <lib/toolbox/strint.h>
|
||||
|
||||
#include "helpers/subghz_chat.h"
|
||||
|
||||
#include <notification/notification_messages.h>
|
||||
@ -71,9 +73,8 @@ void subghz_cli_command_tx_carrier(Cli* cli, FuriString* args, void* context) {
|
||||
uint32_t frequency = 433920000;
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu", &frequency);
|
||||
if(ret != 1) {
|
||||
printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency);
|
||||
if(strint_to_uint32(furi_string_get_cstr(args), NULL, &frequency, 10) !=
|
||||
StrintParseNoError) {
|
||||
cli_print_usage("subghz tx_carrier", "<Frequency: in Hz>", furi_string_get_cstr(args));
|
||||
return;
|
||||
}
|
||||
@ -115,9 +116,8 @@ void subghz_cli_command_rx_carrier(Cli* cli, FuriString* args, void* context) {
|
||||
uint32_t frequency = 433920000;
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu", &frequency);
|
||||
if(ret != 1) {
|
||||
printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency);
|
||||
if(strint_to_uint32(furi_string_get_cstr(args), NULL, &frequency, 10) !=
|
||||
StrintParseNoError) {
|
||||
cli_print_usage("subghz rx_carrier", "<Frequency: in Hz>", furi_string_get_cstr(args));
|
||||
return;
|
||||
}
|
||||
@ -181,23 +181,14 @@ void subghz_cli_command_tx(Cli* cli, FuriString* args, void* context) {
|
||||
uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(
|
||||
furi_string_get_cstr(args),
|
||||
"%lx %lu %lu %lu %lu",
|
||||
&key,
|
||||
&frequency,
|
||||
&te,
|
||||
&repeat,
|
||||
&device_ind);
|
||||
if(ret != 5) {
|
||||
printf(
|
||||
"sscanf returned %d, key: %lx, frequency: %lu, te: %lu, repeat: %lu, device: %lu\r\n ",
|
||||
ret,
|
||||
key,
|
||||
frequency,
|
||||
te,
|
||||
repeat,
|
||||
device_ind);
|
||||
char* args_cstr = (char*)furi_string_get_cstr(args);
|
||||
StrintParseError parse_err = StrintParseNoError;
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &key, 16);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &frequency, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &te, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &repeat, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &device_ind, 10);
|
||||
if(parse_err) {
|
||||
cli_print_usage(
|
||||
"subghz tx",
|
||||
"<3 Byte Key: in hex> <Frequency: in Hz> <Te us> <Repeat count> <Device: 0 - CC1101_INT, 1 - CC1101_EXT>",
|
||||
@ -314,10 +305,11 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) {
|
||||
uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu %lu", &frequency, &device_ind);
|
||||
if(ret != 2) {
|
||||
printf(
|
||||
"sscanf returned %d, frequency: %lu device: %lu\r\n", ret, frequency, device_ind);
|
||||
char* args_cstr = (char*)furi_string_get_cstr(args);
|
||||
StrintParseError parse_err = StrintParseNoError;
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &frequency, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &device_ind, 10);
|
||||
if(parse_err) {
|
||||
cli_print_usage(
|
||||
"subghz rx",
|
||||
"<Frequency: in Hz> <Device: 0 - CC1101_INT, 1 - CC1101_EXT>",
|
||||
@ -401,9 +393,8 @@ void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) {
|
||||
uint32_t frequency = 433920000;
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu", &frequency);
|
||||
if(ret != 1) {
|
||||
printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency);
|
||||
if(strint_to_uint32(furi_string_get_cstr(args), NULL, &frequency, 10) !=
|
||||
StrintParseNoError) {
|
||||
cli_print_usage("subghz rx", "<Frequency: in Hz>", furi_string_get_cstr(args));
|
||||
return;
|
||||
}
|
||||
@ -622,9 +613,11 @@ void subghz_cli_command_tx_from_file(Cli* cli, FuriString* args, void* context)
|
||||
}
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu %lu", &repeat, &device_ind);
|
||||
if(ret != 2) {
|
||||
printf("sscanf returned %d, repeat: %lu device: %lu\r\n", ret, repeat, device_ind);
|
||||
char* args_cstr = (char*)furi_string_get_cstr(args);
|
||||
StrintParseError parse_err = StrintParseNoError;
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &frequency, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &device_ind, 10);
|
||||
if(parse_err) {
|
||||
cli_print_usage(
|
||||
"subghz tx_from_file:",
|
||||
"<file_name: path_file> <Repeat count> <Device: 0 - CC1101_INT, 1 - CC1101_EXT>",
|
||||
@ -936,10 +929,11 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) {
|
||||
uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu %lu", &frequency, &device_ind);
|
||||
if(ret != 2) {
|
||||
printf("sscanf returned %d, Frequency: %lu\r\n", ret, frequency);
|
||||
printf("sscanf returned %d, Device: %lu\r\n", ret, device_ind);
|
||||
char* args_cstr = (char*)furi_string_get_cstr(args);
|
||||
StrintParseError parse_err = StrintParseNoError;
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &frequency, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &device_ind, 10);
|
||||
if(parse_err) {
|
||||
cli_print_usage(
|
||||
"subghz chat",
|
||||
"<Frequency: in Hz> <Device: 0 - CC1101_INT, 1 - CC1101_EXT>",
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <notification/notification_messages.h>
|
||||
#include <loader/loader.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <lib/toolbox/strint.h>
|
||||
|
||||
// Close to ISO, `date +'%Y-%m-%d %H:%M:%S %u'`
|
||||
#define CLI_DATE_FORMAT "%.4d-%.2d-%.2d %.2d:%.2d:%.2d %d"
|
||||
@ -361,9 +362,9 @@ void cli_command_led(Cli* cli, FuriString* args, void* context) {
|
||||
}
|
||||
furi_string_free(light_name);
|
||||
// Read light value from the rest of the string
|
||||
char* end_ptr;
|
||||
uint32_t value = strtoul(furi_string_get_cstr(args), &end_ptr, 0);
|
||||
if(!(value < 256 && *end_ptr == '\0')) {
|
||||
uint32_t value;
|
||||
if(strint_to_uint32(furi_string_get_cstr(args), NULL, &value, 0) != StrintParseNoError ||
|
||||
value >= 256) {
|
||||
cli_print_usage("led", "<r|g|b|bl> <0-255>", furi_string_get_cstr(args));
|
||||
return;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <gui/elements.h>
|
||||
#include <furi.h>
|
||||
#include <assets_icons.h>
|
||||
#include <lib/toolbox/strint.h>
|
||||
|
||||
struct NumberInput {
|
||||
View* view;
|
||||
@ -163,7 +164,11 @@ static void number_input_handle_right(NumberInputModel* model) {
|
||||
}
|
||||
|
||||
static bool is_number_too_large(NumberInputModel* model) {
|
||||
int64_t value = strtoll(furi_string_get_cstr(model->text_buffer), NULL, 10);
|
||||
int64_t value;
|
||||
if(strint_to_int64(furi_string_get_cstr(model->text_buffer), NULL, &value, 10) !=
|
||||
StrintParseNoError) {
|
||||
return true;
|
||||
}
|
||||
if(value > (int64_t)model->max_value) {
|
||||
return true;
|
||||
}
|
||||
@ -171,7 +176,11 @@ static bool is_number_too_large(NumberInputModel* model) {
|
||||
}
|
||||
|
||||
static bool is_number_too_small(NumberInputModel* model) {
|
||||
int64_t value = strtoll(furi_string_get_cstr(model->text_buffer), NULL, 10);
|
||||
int64_t value;
|
||||
if(strint_to_int64(furi_string_get_cstr(model->text_buffer), NULL, &value, 10) !=
|
||||
StrintParseNoError) {
|
||||
return true;
|
||||
}
|
||||
if(value < (int64_t)model->min_value) {
|
||||
return true;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <cli/cli.h>
|
||||
#include <applications.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <lib/toolbox/strint.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
static void loader_cli_print_usage(void) {
|
||||
@ -89,18 +90,22 @@ static void loader_cli_close(Loader* loader) {
|
||||
|
||||
static void loader_cli_signal(FuriString* args, Loader* loader) {
|
||||
uint32_t signal;
|
||||
void* arg = NULL;
|
||||
uint32_t arg = 0;
|
||||
StrintParseError parse_err = 0;
|
||||
char* args_cstr = (char*)furi_string_get_cstr(args);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &signal, 10);
|
||||
parse_err |= strint_to_uint32(args_cstr, &args_cstr, &arg, 16);
|
||||
|
||||
if(!sscanf(furi_string_get_cstr(args), "%lu %p", &signal, &arg)) {
|
||||
if(parse_err) {
|
||||
printf("Signal must be a decimal number\r\n");
|
||||
} else if(!loader_is_locked(loader)) {
|
||||
printf("No application is running\r\n");
|
||||
} else {
|
||||
const bool is_handled = loader_signal(loader, signal, arg);
|
||||
const bool is_handled = loader_signal(loader, signal, (void*)arg);
|
||||
printf(
|
||||
"Signal %lu with argument 0x%p was %s\r\n",
|
||||
signal,
|
||||
arg,
|
||||
(void*)arg,
|
||||
is_handled ? "handled" : "ignored");
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,9 @@
|
||||
|
||||
#include <cli/cli.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <lib/toolbox/md5_calc.h>
|
||||
#include <lib/toolbox/dir_walk.h>
|
||||
#include <lib/toolbox/md5_calc.h>
|
||||
#include <lib/toolbox/strint.h>
|
||||
#include <lib/toolbox/tar/tar_archive.h>
|
||||
#include <storage/storage.h>
|
||||
#include <storage/storage_sd_api.h>
|
||||
@ -267,9 +268,8 @@ static void storage_cli_read_chunks(Cli* cli, FuriString* path, FuriString* args
|
||||
File* file = storage_file_alloc(api);
|
||||
|
||||
uint32_t buffer_size;
|
||||
int parsed_count = sscanf(furi_string_get_cstr(args), "%lu", &buffer_size);
|
||||
|
||||
if(parsed_count != 1) {
|
||||
if(strint_to_uint32(furi_string_get_cstr(args), NULL, &buffer_size, 10) !=
|
||||
StrintParseNoError) {
|
||||
storage_cli_print_usage();
|
||||
} else if(storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
uint64_t file_size = storage_file_size(file);
|
||||
@ -307,9 +307,8 @@ static void storage_cli_write_chunk(Cli* cli, FuriString* path, FuriString* args
|
||||
File* file = storage_file_alloc(api);
|
||||
|
||||
uint32_t buffer_size;
|
||||
int parsed_count = sscanf(furi_string_get_cstr(args), "%lu", &buffer_size);
|
||||
|
||||
if(parsed_count != 1) {
|
||||
if(strint_to_uint32(furi_string_get_cstr(args), NULL, &buffer_size, 10) !=
|
||||
StrintParseNoError) {
|
||||
storage_cli_print_usage();
|
||||
} else {
|
||||
if(storage_file_open(file, furi_string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_APPEND)) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <inttypes.h>
|
||||
#include <toolbox/hex.h>
|
||||
#include <toolbox/strint.h>
|
||||
#include <core/check.h>
|
||||
#include "flipper_format_stream.h"
|
||||
#include "flipper_format_stream_i.h"
|
||||
@ -396,14 +397,16 @@ bool flipper_format_stream_read_value_line(
|
||||
#endif
|
||||
case FlipperStreamValueInt32: {
|
||||
int32_t* data = _data;
|
||||
scan_values = sscanf(furi_string_get_cstr(value), "%" PRIi32, &data[i]);
|
||||
if(strint_to_int32(furi_string_get_cstr(value), NULL, &data[i], 10) ==
|
||||
StrintParseNoError) {
|
||||
scan_values = 1;
|
||||
}
|
||||
}; break;
|
||||
case FlipperStreamValueUint32: {
|
||||
uint32_t* data = _data;
|
||||
// Minus sign is allowed in scanf() for unsigned numbers, resulting in unintentionally huge values with no error reported
|
||||
if(!furi_string_start_with(value, "-")) {
|
||||
scan_values =
|
||||
sscanf(furi_string_get_cstr(value), "%" PRIu32, &data[i]);
|
||||
if(strint_to_uint32(furi_string_get_cstr(value), NULL, &data[i], 10) ==
|
||||
StrintParseNoError) {
|
||||
scan_values = 1;
|
||||
}
|
||||
}; break;
|
||||
case FlipperStreamValueHexUint64: {
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
#include <lib/subghz/devices/devices.h>
|
||||
#include <lib/toolbox/strint.h>
|
||||
|
||||
#define TAG "SubGhzFileEncoderWorker"
|
||||
|
||||
@ -45,27 +46,26 @@ void subghz_file_encoder_worker_add_level_duration(
|
||||
}
|
||||
|
||||
bool subghz_file_encoder_worker_data_parse(SubGhzFileEncoderWorker* instance, const char* strStart) {
|
||||
char* str1;
|
||||
bool res = false;
|
||||
// Line sample: "RAW_Data: -1, 2, -2..."
|
||||
|
||||
// Look for a key in the line
|
||||
str1 = strstr(strStart, "RAW_Data: ");
|
||||
// Look for the key in the line
|
||||
char* str = strstr(strStart, "RAW_Data: ");
|
||||
bool res = false;
|
||||
|
||||
if(str1 != NULL) {
|
||||
if(str) {
|
||||
// Skip key
|
||||
str1 = strchr(str1, ' ');
|
||||
str = strchr(str, ' ');
|
||||
|
||||
// Check that there is still an element in the line
|
||||
while(strchr(str1, ' ') != NULL) {
|
||||
str1 = strchr(str1, ' ');
|
||||
|
||||
// Skip space
|
||||
str1 += 1;
|
||||
subghz_file_encoder_worker_add_level_duration(instance, atoi(str1));
|
||||
// Parse next element
|
||||
int32_t duration;
|
||||
while(strint_to_int32(str, &str, &duration, 10) == StrintParseNoError) {
|
||||
subghz_file_encoder_worker_add_level_duration(instance, duration);
|
||||
if(*str == ',') str++; // could also be `\0`
|
||||
}
|
||||
|
||||
res = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ env.Append(
|
||||
File("stream/file_stream.h"),
|
||||
File("stream/string_stream.h"),
|
||||
File("stream/buffered_file_stream.h"),
|
||||
File("strint.h"),
|
||||
File("protocols/protocol_dict.h"),
|
||||
File("pretty_format.h"),
|
||||
File("hex.h"),
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "args.h"
|
||||
#include "hex.h"
|
||||
#include "strint.h"
|
||||
#include "m-core.h"
|
||||
|
||||
size_t args_get_first_word_length(FuriString* args) {
|
||||
size_t ws = furi_string_search_char(args, ' ');
|
||||
@ -21,7 +23,9 @@ bool args_read_int_and_trim(FuriString* args, int* value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sscanf(furi_string_get_cstr(args), "%d", value) == 1) {
|
||||
int32_t temp;
|
||||
if(strint_to_int32(furi_string_get_cstr(args), NULL, &temp, 10) == StrintParseNoError) {
|
||||
*value = temp;
|
||||
furi_string_right(args, cmd_length);
|
||||
furi_string_trim(args);
|
||||
return true;
|
||||
|
121
lib/toolbox/strint.c
Normal file
121
lib/toolbox/strint.c
Normal file
@ -0,0 +1,121 @@
|
||||
#include "strint.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// Splitting out the actual parser helps reduce code size. The manually
|
||||
// monomorphized `strint_to_*`s are just wrappers around this generic
|
||||
// implementation.
|
||||
/**
|
||||
* @brief Converts a string to a `uint64_t` and an auxillary sign bit, checking
|
||||
* the bounds of the integer.
|
||||
* @param [in] str Input string
|
||||
* @param [out] end Pointer to first character after the number in input string
|
||||
* @param [out] abs_out Absolute part of result
|
||||
* @param [out] negative_out Sign part of result (true=negative, false=positive)
|
||||
* @param [in] base Integer base
|
||||
* @param [in] max_abs_negative Largest permissible absolute part of result if
|
||||
* the sign is negative
|
||||
* @param [in] max_positive Largest permissible absolute part of result if the
|
||||
* sign is positive
|
||||
*/
|
||||
StrintParseError strint_to_uint64_internal(
|
||||
const char* str,
|
||||
char** end,
|
||||
uint64_t* abs_out,
|
||||
bool* negative_out,
|
||||
uint8_t base,
|
||||
uint64_t max_abs_negative,
|
||||
uint64_t max_positive) {
|
||||
// skip whitespace
|
||||
while(((*str >= '\t') && (*str <= '\r')) || *str == ' ') {
|
||||
str++;
|
||||
}
|
||||
|
||||
// read sign
|
||||
bool negative = false;
|
||||
if(*str == '+' || *str == '-') {
|
||||
if(*str == '-') negative = true;
|
||||
str++;
|
||||
}
|
||||
if(*str == '+' || *str == '-') return StrintParseSignError;
|
||||
if(max_abs_negative == 0 && negative) return StrintParseSignError;
|
||||
|
||||
// infer base
|
||||
// not assigning directly to `base' to permit prefixes with explicit bases
|
||||
uint8_t inferred_base = 0;
|
||||
if(strncasecmp(str, "0x", 2) == 0) {
|
||||
inferred_base = 16;
|
||||
str += 2;
|
||||
} else if(strncasecmp(str, "0b", 2) == 0) {
|
||||
inferred_base = 2;
|
||||
str += 2;
|
||||
} else if(*str == '0') {
|
||||
inferred_base = 8;
|
||||
str++;
|
||||
} else {
|
||||
inferred_base = 10;
|
||||
}
|
||||
if(base == 0) base = inferred_base;
|
||||
|
||||
// read digits
|
||||
uint64_t limit = negative ? max_abs_negative : max_positive;
|
||||
uint64_t mul_limit = limit / base;
|
||||
uint64_t result = 0;
|
||||
int read_total = 0;
|
||||
while(*str != 0) {
|
||||
int digit_value;
|
||||
if(*str >= '0' && *str <= '9') {
|
||||
digit_value = *str - '0';
|
||||
} else if(*str >= 'A' && *str <= 'Z') {
|
||||
digit_value = *str - 'A' + 10;
|
||||
} else if(*str >= 'a' && *str <= 'z') {
|
||||
digit_value = *str - 'a' + 10;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if(digit_value >= base) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(result > mul_limit) return StrintParseOverflowError;
|
||||
result *= base;
|
||||
if(result > limit - digit_value) return StrintParseOverflowError;
|
||||
result += digit_value;
|
||||
|
||||
read_total++;
|
||||
str++;
|
||||
}
|
||||
|
||||
if(read_total == 0) {
|
||||
if(inferred_base == 8) {
|
||||
// there's just a single zero
|
||||
result = 0;
|
||||
} else {
|
||||
return StrintParseAbsentError;
|
||||
}
|
||||
}
|
||||
|
||||
if(abs_out) *abs_out = result;
|
||||
if(negative_out) *negative_out = negative;
|
||||
if(end) *end = (char*)str; // rabbit hole: https://c-faq.com/ansi/constmismatch.html
|
||||
return StrintParseNoError;
|
||||
}
|
||||
|
||||
#define STRINT_MONO(name, ret_type, neg_abs_limit, pos_limit) \
|
||||
StrintParseError name(const char* str, char** end, ret_type* out, uint8_t base) { \
|
||||
uint64_t absolute; \
|
||||
bool negative; \
|
||||
StrintParseError err = strint_to_uint64_internal( \
|
||||
str, end, &absolute, &negative, base, (neg_abs_limit), (pos_limit)); \
|
||||
if(err) return err; \
|
||||
if(out) *out = (negative ? (-(ret_type)absolute) : ((ret_type)absolute)); \
|
||||
return StrintParseNoError; \
|
||||
}
|
||||
|
||||
STRINT_MONO(strint_to_uint64, uint64_t, 0, UINT64_MAX)
|
||||
STRINT_MONO(strint_to_int64, int64_t, (uint64_t)INT64_MAX + 1, INT64_MAX)
|
||||
STRINT_MONO(strint_to_uint32, uint32_t, 0, UINT32_MAX)
|
||||
STRINT_MONO(strint_to_int32, int32_t, (uint64_t)INT32_MAX + 1, INT32_MAX)
|
||||
STRINT_MONO(strint_to_uint16, uint16_t, 0, UINT16_MAX)
|
||||
STRINT_MONO(strint_to_int16, int16_t, (uint64_t)INT16_MAX + 1, INT16_MAX)
|
70
lib/toolbox/strint.h
Normal file
70
lib/toolbox/strint.h
Normal file
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @file strint.h
|
||||
* Performs conversions between strings and integers.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** String to integer conversion error */
|
||||
typedef enum {
|
||||
StrintParseNoError, //!< Conversion performed successfully
|
||||
StrintParseSignError, //!< Multiple leading `+` or `-` characters, or leading `-` character if the type is unsigned
|
||||
StrintParseAbsentError, //!< No valid digits after the leading whitespace, sign and prefix
|
||||
StrintParseOverflowError, //!< Result does not fit in the requested type
|
||||
} StrintParseError;
|
||||
|
||||
/** See `strint_to_uint32` */
|
||||
StrintParseError strint_to_uint64(const char* str, char** end, uint64_t* out, uint8_t base);
|
||||
|
||||
/** See `strint_to_uint32` */
|
||||
StrintParseError strint_to_int64(const char* str, char** end, int64_t* out, uint8_t base);
|
||||
|
||||
/** Converts a string to a `uint32_t`
|
||||
*
|
||||
* @param[in] str Input string
|
||||
* @param[out] end Pointer to first character after the number in input string
|
||||
* @param[out] out Parse result
|
||||
* @param[in] base Integer base
|
||||
*
|
||||
* @return Parse error
|
||||
*
|
||||
* Parses the number in the input string. The number may be surrounded by
|
||||
* whitespace characters to the left and any non-digit characters to the right.
|
||||
* What's considered a digit is determined by the input base in the following
|
||||
* order: `0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ`. The number may be prefixed
|
||||
* with either a `+` or a `-` to indicate its sign. The pointer to the first
|
||||
* character after the leading whitespace, allowed prefixes and digits is
|
||||
* assigned to `end`.
|
||||
*
|
||||
* If the input base is 0, the base is inferred from the leading characters of
|
||||
* the number:
|
||||
* - If it starts with `0x`, it's read in base 16;
|
||||
* - If it starts with a `0`, it's read in base 8;
|
||||
* - If it starts with `0b`, it's read in base 2.
|
||||
* - Otherwise, it's read in base 10.
|
||||
*
|
||||
* For a description of the return codes, see `StrintParseError`. If the return
|
||||
* code is something other than `StrintParseNoError`, the values at `end` and
|
||||
* `out` are unaltered.
|
||||
*/
|
||||
StrintParseError strint_to_uint32(const char* str, char** end, uint32_t* out, uint8_t base);
|
||||
|
||||
/** See `strint_to_uint32` */
|
||||
StrintParseError strint_to_int32(const char* str, char** end, int32_t* out, uint8_t base);
|
||||
|
||||
/** See `strint_to_uint32` */
|
||||
StrintParseError strint_to_uint16(const char* str, char** end, uint16_t* out, uint8_t base);
|
||||
|
||||
/** See `strint_to_uint32` */
|
||||
StrintParseError strint_to_int16(const char* str, char** end, int16_t* out, uint8_t base);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,6 +1,7 @@
|
||||
#include "manifest.h"
|
||||
|
||||
#include <toolbox/stream/buffered_file_stream.h>
|
||||
#include <toolbox/strint.h>
|
||||
#include <toolbox/hex.h>
|
||||
|
||||
struct ResourceManifestReader {
|
||||
@ -97,7 +98,12 @@ ResourceManifestEntry* resource_manifest_reader_next(ResourceManifestReader* res
|
||||
furi_string_right(
|
||||
resource_manifest->linebuf, sizeof(resource_manifest->entry.hash) * 2 + 1);
|
||||
|
||||
resource_manifest->entry.size = atoi(furi_string_get_cstr(resource_manifest->linebuf));
|
||||
if(strint_to_uint32(
|
||||
furi_string_get_cstr(resource_manifest->linebuf),
|
||||
NULL,
|
||||
&resource_manifest->entry.size,
|
||||
10) != StrintParseNoError)
|
||||
break;
|
||||
|
||||
/* Remove size */
|
||||
size_t offs = furi_string_search_char(resource_manifest->linebuf, ':');
|
||||
|
@ -170,6 +170,7 @@ Header,+,lib/toolbox/stream/buffered_file_stream.h,,
|
||||
Header,+,lib/toolbox/stream/file_stream.h,,
|
||||
Header,+,lib/toolbox/stream/stream.h,,
|
||||
Header,+,lib/toolbox/stream/string_stream.h,,
|
||||
Header,+,lib/toolbox/strint.h,,
|
||||
Header,+,lib/toolbox/tar/tar_archive.h,,
|
||||
Header,+,lib/toolbox/value_index.h,,
|
||||
Header,+,lib/toolbox/varint.h,,
|
||||
@ -2589,6 +2590,12 @@ Function,-,strerror,char*,int
|
||||
Function,-,strerror_l,char*,"int, locale_t"
|
||||
Function,-,strerror_r,char*,"int, char*, size_t"
|
||||
Function,+,string_stream_alloc,Stream*,
|
||||
Function,+,strint_to_int16,StrintParseError,"const char*, char**, int16_t*, uint8_t"
|
||||
Function,+,strint_to_int32,StrintParseError,"const char*, char**, int32_t*, uint8_t"
|
||||
Function,+,strint_to_int64,StrintParseError,"const char*, char**, int64_t*, uint8_t"
|
||||
Function,+,strint_to_uint16,StrintParseError,"const char*, char**, uint16_t*, uint8_t"
|
||||
Function,+,strint_to_uint32,StrintParseError,"const char*, char**, uint32_t*, uint8_t"
|
||||
Function,+,strint_to_uint64,StrintParseError,"const char*, char**, uint64_t*, uint8_t"
|
||||
Function,-,strlcat,size_t,"char*, const char*, size_t"
|
||||
Function,+,strlcpy,size_t,"char*, const char*, size_t"
|
||||
Function,+,strlen,size_t,const char*
|
||||
|
|
@ -242,6 +242,7 @@ Header,+,lib/toolbox/stream/buffered_file_stream.h,,
|
||||
Header,+,lib/toolbox/stream/file_stream.h,,
|
||||
Header,+,lib/toolbox/stream/stream.h,,
|
||||
Header,+,lib/toolbox/stream/string_stream.h,,
|
||||
Header,+,lib/toolbox/strint.h,,
|
||||
Header,+,lib/toolbox/tar/tar_archive.h,,
|
||||
Header,+,lib/toolbox/value_index.h,,
|
||||
Header,+,lib/toolbox/varint.h,,
|
||||
@ -3266,6 +3267,12 @@ Function,-,strerror,char*,int
|
||||
Function,-,strerror_l,char*,"int, locale_t"
|
||||
Function,-,strerror_r,char*,"int, char*, size_t"
|
||||
Function,+,string_stream_alloc,Stream*,
|
||||
Function,+,strint_to_int16,StrintParseError,"const char*, char**, int16_t*, uint8_t"
|
||||
Function,+,strint_to_int32,StrintParseError,"const char*, char**, int32_t*, uint8_t"
|
||||
Function,+,strint_to_int64,StrintParseError,"const char*, char**, int64_t*, uint8_t"
|
||||
Function,+,strint_to_uint16,StrintParseError,"const char*, char**, uint16_t*, uint8_t"
|
||||
Function,+,strint_to_uint32,StrintParseError,"const char*, char**, uint32_t*, uint8_t"
|
||||
Function,+,strint_to_uint64,StrintParseError,"const char*, char**, uint64_t*, uint8_t"
|
||||
Function,-,strlcat,size_t,"char*, const char*, size_t"
|
||||
Function,+,strlcpy,size_t,"char*, const char*, size_t"
|
||||
Function,+,strlen,size_t,const char*
|
||||
|
|
Loading…
Reference in New Issue
Block a user