2018-02-27 16:14:14 +03:00
|
|
|
#pragma once
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <carp_memory.h>
|
|
|
|
#include <core.h>
|
|
|
|
|
2018-05-20 08:18:15 +03:00
|
|
|
String String_allocate(int len, char byte) {
|
|
|
|
/* Allocate a string of length 'len + 1'
|
|
|
|
* setting the first len bytes to byte
|
|
|
|
* and adding a null terminator
|
|
|
|
*
|
|
|
|
* String_alloc(10, "a") == "aaaaaaaaaa"
|
|
|
|
*/
|
|
|
|
String ptr = CARP_MALLOC(len+1);
|
|
|
|
memset(ptr, byte, len);
|
|
|
|
ptr[len] = '\0';
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2018-03-18 16:53:03 +03:00
|
|
|
void String_delete(String s) {
|
2018-02-27 16:14:14 +03:00
|
|
|
CARP_FREE(s);
|
|
|
|
}
|
|
|
|
|
2018-05-19 09:49:48 +03:00
|
|
|
void String_string_MINUS_set_BANG_(String *s, int i, char ch) {
|
2018-05-20 06:31:21 +03:00
|
|
|
int l = strlen(*s);
|
2019-06-13 15:16:15 +03:00
|
|
|
(void)l;
|
2018-05-20 06:31:21 +03:00
|
|
|
assert(i >= 0);
|
|
|
|
assert(i < l);
|
2018-05-19 09:49:48 +03:00
|
|
|
(*s)[i] = ch;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
void String_string_MINUS_set_MINUS_at_BANG_(String *into, int i, const String *src) {
|
2018-05-20 06:53:30 +03:00
|
|
|
char *dest = (*into) + i;
|
|
|
|
int lsrc = strlen(*src);
|
|
|
|
|
|
|
|
int linto = strlen(*into);
|
2019-06-13 15:16:15 +03:00
|
|
|
(void)linto;
|
2018-05-20 06:53:30 +03:00
|
|
|
assert(i >= 0);
|
|
|
|
/* given a string and indicies
|
|
|
|
*
|
|
|
|
* 0 1 2 3 4 5 6 7 8 9
|
|
|
|
* "a b c d e f g h i j"
|
|
|
|
* linto = strlen(...) = 10
|
|
|
|
*
|
|
|
|
* if we want to insert at '6' a string of length '4'
|
|
|
|
*
|
|
|
|
* 0 1 2 3
|
|
|
|
* "w x y z"
|
|
|
|
* ldest = strlen(...) = 4
|
|
|
|
*
|
|
|
|
* we need to make sure that the new string will not grow the first
|
|
|
|
*
|
|
|
|
* 0 1 2 3 4 5 6 7 8 9
|
|
|
|
* "a b c d e f g h i j"
|
|
|
|
* ^
|
|
|
|
* |
|
|
|
|
* 0 1 2 3
|
|
|
|
* "w x y z"
|
|
|
|
*
|
|
|
|
* we check this by
|
|
|
|
* (i + ldest - 1) < linto
|
|
|
|
* (6 + 4 - 1) < 10
|
|
|
|
* (10 - 1) < 10
|
|
|
|
* 9 < 10
|
|
|
|
* true
|
|
|
|
*
|
|
|
|
* so this write is safe
|
|
|
|
*/
|
|
|
|
assert((i+lsrc-1) < linto);
|
|
|
|
|
|
|
|
strncpy(dest, *src, lsrc);
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String String_copy(const String *s) {
|
2018-02-27 16:14:14 +03:00
|
|
|
size_t len = strlen(*s) + 1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String ptr = CARP_MALLOC(len);
|
|
|
|
return (String) memcpy(ptr, *s, len);
|
2018-02-27 16:14:14 +03:00
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
bool String__EQ_(const String *a, const String *b) {
|
2018-02-27 16:14:14 +03:00
|
|
|
return strcmp(*a, *b) == 0;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
bool String__GT_(const String *a, const String *b) {
|
2018-06-26 09:00:33 +03:00
|
|
|
return strcmp(*a, *b) > 0;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
bool String__LT_(const String *a, const String *b) {
|
2018-06-26 09:00:33 +03:00
|
|
|
return strcmp(*a, *b) < 0;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String String_append(const String *a, const String *b) {
|
2018-05-20 07:04:47 +03:00
|
|
|
int la = strlen(*a);
|
|
|
|
int lb = strlen(*b);
|
2018-02-27 16:14:14 +03:00
|
|
|
int total = la + lb + 1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(total);
|
2018-05-20 07:04:47 +03:00
|
|
|
snprintf(buffer, total, "%s%s", *a, *b);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
int String_length(const String *s) {
|
2018-02-27 16:14:14 +03:00
|
|
|
return strlen(*s);
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
char* String_cstr(const String *s) {
|
2018-02-27 16:14:14 +03:00
|
|
|
return *s;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String String_str(const String *s) {
|
|
|
|
return String_copy(s);
|
2018-02-27 17:30:22 +03:00
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String String_prn(const String *s) {
|
2018-02-27 16:14:14 +03:00
|
|
|
int n = strlen(*s) + 4;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(n);
|
2018-02-27 16:14:14 +03:00
|
|
|
snprintf(buffer, n, "@\"%s\"", *s);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
char String_char_MINUS_at(const String* s, int i) {
|
2018-02-27 16:14:14 +03:00
|
|
|
return (*s)[i];
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String String_format(const String *str, const String *s) {
|
2018-02-27 16:14:14 +03:00
|
|
|
int size = snprintf(NULL, 0, *str, *s)+1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(size);
|
2018-02-27 16:14:14 +03:00
|
|
|
snprintf(buffer, size, *str, *s);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
Array String_chars(const String *s) {
|
2018-02-27 16:14:14 +03:00
|
|
|
Array chars;
|
|
|
|
chars.len = strlen(*s);
|
2018-03-07 14:03:59 +03:00
|
|
|
chars.capacity = chars.len;
|
2018-02-27 16:14:14 +03:00
|
|
|
chars.data = String_copy(s);
|
|
|
|
return chars;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String String_from_MINUS_chars(const Array *a) {
|
2018-03-18 16:53:03 +03:00
|
|
|
String s = CARP_MALLOC(a->len+1);
|
2019-06-14 15:38:19 +03:00
|
|
|
memcpy(s, a->data, a->len);
|
2018-03-12 16:56:05 +03:00
|
|
|
s[a->len] = '\0';
|
2018-02-27 16:14:14 +03:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String String_tail(const String* s) {
|
|
|
|
int len = strlen(*s);
|
|
|
|
String news = CARP_MALLOC(len);
|
|
|
|
memcpy(news, (*s)+1, len-1);
|
|
|
|
news[len-1] = '\0';
|
|
|
|
return news;
|
2018-02-27 16:14:14 +03:00
|
|
|
}
|
|
|
|
|
2018-03-18 16:53:03 +03:00
|
|
|
String String_empty() {
|
|
|
|
String s = CARP_MALLOC(1);
|
2018-02-27 16:14:14 +03:00
|
|
|
s[0] = '\0';
|
|
|
|
return s;
|
|
|
|
}
|
2018-02-27 16:49:06 +03:00
|
|
|
|
2018-03-18 16:53:03 +03:00
|
|
|
String Bool_str(bool b) {
|
2019-06-14 15:38:19 +03:00
|
|
|
const String true_str = "true";
|
|
|
|
const String false_str = "false";
|
2018-02-27 16:49:06 +03:00
|
|
|
if(b) {
|
|
|
|
return String_copy(&true_str);
|
|
|
|
} else {
|
|
|
|
return String_copy(&false_str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String Bool_format(const String* str, bool b) {
|
2018-02-27 16:49:06 +03:00
|
|
|
int size = snprintf(NULL, 0, *str, b)+1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(size);
|
2018-02-27 16:49:06 +03:00
|
|
|
snprintf(buffer, size, *str, b);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2018-03-18 16:53:03 +03:00
|
|
|
String Char_str(char c) {
|
2018-05-20 19:28:45 +03:00
|
|
|
String buffer = CARP_MALLOC(2);
|
|
|
|
snprintf(buffer, 2, "%c", c);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
String Char_prn(char c) {
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(3);
|
2018-02-27 16:49:06 +03:00
|
|
|
snprintf(buffer, 3, "\\%c", c);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String Char_format(const String* str, char b) {
|
2018-02-27 16:49:06 +03:00
|
|
|
int size = snprintf(NULL, 0, *str, b)+1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(size);
|
2018-02-27 16:49:06 +03:00
|
|
|
snprintf(buffer, size, *str, b);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2018-03-18 16:53:03 +03:00
|
|
|
String Double_str(double x) {
|
2018-02-27 16:49:06 +03:00
|
|
|
int size = snprintf(NULL, 0, "%g", x)+1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(size);
|
2018-02-27 16:49:06 +03:00
|
|
|
snprintf(buffer, size, "%g", x);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String Double_format(const String* s, double x) {
|
2018-02-27 16:49:06 +03:00
|
|
|
int size = snprintf(NULL, 0, *s, x)+1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(size);
|
2018-02-27 16:49:06 +03:00
|
|
|
snprintf(buffer, size, *s, x);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2018-03-18 16:53:03 +03:00
|
|
|
String Float_str(float x) {
|
2018-02-27 16:49:06 +03:00
|
|
|
int size = snprintf(NULL, 0, "%gf", x)+1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(size);
|
2018-02-27 16:49:06 +03:00
|
|
|
snprintf(buffer, size, "%gf", x);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String Float_format(const String* str, float x) {
|
2018-02-27 16:49:06 +03:00
|
|
|
int size = snprintf(NULL, 0, *str, x)+1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(size);
|
2018-02-27 16:49:06 +03:00
|
|
|
snprintf(buffer, size, *str, x);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2018-03-18 16:53:03 +03:00
|
|
|
String Int_str(int x) {
|
2018-02-27 16:49:06 +03:00
|
|
|
int size = snprintf(NULL, 0, "%d", x)+1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(size);
|
2018-02-27 16:49:06 +03:00
|
|
|
snprintf(buffer, size, "%d", x);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String Int_format(const String* str, int x) {
|
2018-02-27 16:49:06 +03:00
|
|
|
int size = snprintf(NULL, 0, *str, x)+1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(size);
|
2018-02-27 16:49:06 +03:00
|
|
|
snprintf(buffer, size, *str, x);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
int Int_from_MINUS_string(const String *s) {
|
2018-02-27 16:49:06 +03:00
|
|
|
return atoi(*s);
|
|
|
|
}
|
|
|
|
|
2018-03-18 16:53:03 +03:00
|
|
|
String Long_str(long x) {
|
2018-02-27 16:49:06 +03:00
|
|
|
int size = snprintf(NULL, 0, "%ldl", x)+1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(size);
|
2018-02-27 16:49:06 +03:00
|
|
|
snprintf(buffer, size, "%ldl", x);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
String Long_format(const String* str, long x) {
|
2018-02-27 16:49:06 +03:00
|
|
|
int size = snprintf(NULL, 0, *str, x)+1;
|
2018-03-18 16:53:03 +03:00
|
|
|
String buffer = CARP_MALLOC(size);
|
2018-02-27 16:49:06 +03:00
|
|
|
snprintf(buffer, size, *str, x);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
long Long_from_MINUS_string(const String *s) {
|
2018-02-27 16:49:06 +03:00
|
|
|
return atol(*s);
|
|
|
|
}
|
2018-05-20 11:25:13 +03:00
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
int String_index_MINUS_of_MINUS_from(const String *s, char c, int i) {
|
2018-05-20 11:41:36 +03:00
|
|
|
/* Return index of first occurrence of `c` in `s` AFTER index i
|
2018-05-20 11:25:13 +03:00
|
|
|
* Returns -1 if not found
|
|
|
|
*/
|
2018-05-20 11:41:36 +03:00
|
|
|
++i; // skip first character as we want AFTER i
|
2018-05-20 11:25:13 +03:00
|
|
|
int len = strlen(*s);
|
2018-05-20 11:41:36 +03:00
|
|
|
for (; i<len; ++i) {
|
2018-05-20 11:25:13 +03:00
|
|
|
if (c == (*s)[i]) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2018-05-20 11:41:36 +03:00
|
|
|
|
2019-06-14 15:38:19 +03:00
|
|
|
int String_index_MINUS_of(const String *s, char c) {
|
2018-05-20 11:41:36 +03:00
|
|
|
/* Return index of first occurrence of `c` in `s`
|
|
|
|
* Returns -1 if not found
|
|
|
|
*/
|
|
|
|
return String_index_MINUS_of_MINUS_from(s, c, -1);
|
|
|
|
}
|