unleashed-firmware/lib/mjs/common/mg_str.c
Nikolay Minaylov 0154018363
[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor

Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 15:54:32 +07:00

176 lines
5.0 KiB
C

/*
* Copyright (c) 2014-2018 Cesanta Software Limited
* All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the ""License"");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an ""AS IS"" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mg_mem.h"
#include "mg_str.h"
#include "platform.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
int mg_ncasecmp(const char* s1, const char* s2, size_t len) WEAK;
struct mg_str mg_mk_str(const char* s) WEAK;
struct mg_str mg_mk_str(const char* s) {
struct mg_str ret = {s, 0};
if(s != NULL) ret.len = strlen(s);
return ret;
}
struct mg_str mg_mk_str_n(const char* s, size_t len) WEAK;
struct mg_str mg_mk_str_n(const char* s, size_t len) {
struct mg_str ret = {s, len};
return ret;
}
int mg_vcmp(const struct mg_str* str1, const char* str2) WEAK;
int mg_vcmp(const struct mg_str* str1, const char* str2) {
size_t n2 = strlen(str2), n1 = str1->len;
int r = strncmp(str1->p, str2, (n1 < n2) ? n1 : n2);
if(r == 0) {
return n1 - n2;
}
return r;
}
int mg_vcasecmp(const struct mg_str* str1, const char* str2) WEAK;
int mg_vcasecmp(const struct mg_str* str1, const char* str2) {
size_t n2 = strlen(str2), n1 = str1->len;
int r = mg_ncasecmp(str1->p, str2, (n1 < n2) ? n1 : n2);
if(r == 0) {
return n1 - n2;
}
return r;
}
static struct mg_str mg_strdup_common(const struct mg_str s, int nul_terminate) {
struct mg_str r = {NULL, 0};
if(s.len > 0 && s.p != NULL) {
char* sc = (char*)MG_MALLOC(s.len + (nul_terminate ? 1 : 0));
if(sc != NULL) {
memcpy(sc, s.p, s.len);
if(nul_terminate) sc[s.len] = '\0';
r.p = sc;
r.len = s.len;
}
}
return r;
}
struct mg_str mg_strdup(const struct mg_str s) WEAK;
struct mg_str mg_strdup(const struct mg_str s) {
return mg_strdup_common(s, 0 /* NUL-terminate */);
}
struct mg_str mg_strdup_nul(const struct mg_str s) WEAK;
struct mg_str mg_strdup_nul(const struct mg_str s) {
return mg_strdup_common(s, 1 /* NUL-terminate */);
}
const char* mg_strchr(const struct mg_str s, int c) WEAK;
const char* mg_strchr(const struct mg_str s, int c) {
size_t i;
for(i = 0; i < s.len; i++) {
if(s.p[i] == c) return &s.p[i];
}
return NULL;
}
int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK;
int mg_strcmp(const struct mg_str str1, const struct mg_str str2) {
size_t i = 0;
while(i < str1.len && i < str2.len) {
int c1 = str1.p[i];
int c2 = str2.p[i];
if(c1 < c2) return -1;
if(c1 > c2) return 1;
i++;
}
if(i < str1.len) return 1;
if(i < str2.len) return -1;
return 0;
}
int mg_strncmp(const struct mg_str, const struct mg_str, size_t n) WEAK;
int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n) {
struct mg_str s1 = str1;
struct mg_str s2 = str2;
if(s1.len > n) {
s1.len = n;
}
if(s2.len > n) {
s2.len = n;
}
return mg_strcmp(s1, s2);
}
int mg_strcasecmp(const struct mg_str str1, const struct mg_str str2) WEAK;
int mg_strcasecmp(const struct mg_str str1, const struct mg_str str2) {
size_t i = 0;
while(i < str1.len && i < str2.len) {
int c1 = tolower((int)str1.p[i]);
int c2 = tolower((int)str2.p[i]);
if(c1 < c2) return -1;
if(c1 > c2) return 1;
i++;
}
if(i < str1.len) return 1;
if(i < str2.len) return -1;
return 0;
}
void mg_strfree(struct mg_str* s) WEAK;
void mg_strfree(struct mg_str* s) {
char* sp = (char*)s->p;
s->p = NULL;
s->len = 0;
if(sp != NULL) free(sp);
}
const char* mg_strstr(const struct mg_str haystack, const struct mg_str needle) WEAK;
const char* mg_strstr(const struct mg_str haystack, const struct mg_str needle) {
size_t i;
if(needle.len > haystack.len) return NULL;
for(i = 0; i <= haystack.len - needle.len; i++) {
if(memcmp(haystack.p + i, needle.p, needle.len) == 0) {
return haystack.p + i;
}
}
return NULL;
}
struct mg_str mg_strstrip(struct mg_str s) WEAK;
struct mg_str mg_strstrip(struct mg_str s) {
while(s.len > 0 && isspace((int)*s.p)) {
s.p++;
s.len--;
}
while(s.len > 0 && isspace((int)*(s.p + s.len - 1))) {
s.len--;
}
return s;
}
int mg_str_starts_with(struct mg_str s, struct mg_str prefix) WEAK;
int mg_str_starts_with(struct mg_str s, struct mg_str prefix) {
const struct mg_str sp = MG_MK_STR_N(s.p, prefix.len);
if(s.len < prefix.len) return 0;
return (mg_strcmp(sp, prefix) == 0);
}