Skip to content

Commit 32c1e95

Browse files
authored
Merge pull request #223 from tsoding/next-stream
Release v3.6.0
2 parents 3f835d7 + a774f51 commit 32c1e95

4 files changed

Lines changed: 101 additions & 29 deletions

File tree

nob.h

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* nob - v3.5.0 - Public Domain - https://github.com/tsoding/nob.h
1+
/* nob - v3.6.0 - Public Domain - https://github.com/tsoding/nob.h
22
33
This library is the next generation of the [NoBuild](https://github.com/tsoding/nobuild) idea.
44
@@ -216,7 +216,7 @@ typedef enum {
216216
NOB_NO_LOGS,
217217
} Nob_Log_Level;
218218

219-
// Any messages with the level below nob_minimal_log_level are going to be suppressed.
219+
// Any messages with the level below nob_minimal_log_level are going to be suppressed by the nob_default_log_handler.
220220
extern Nob_Log_Level nob_minimal_log_level;
221221

222222
typedef void (Nob_Log_Handler)(Nob_Log_Level level, const char *fmt, va_list args);
@@ -888,15 +888,28 @@ NOBDEF const char *nob_temp_sv_to_cstr(Nob_String_View sv);
888888
NOBDEF Nob_String_View nob_sv_chop_while(Nob_String_View *sv, int (*p)(int x));
889889
NOBDEF Nob_String_View nob_sv_chop_by_delim(Nob_String_View *sv, char delim);
890890
NOBDEF Nob_String_View nob_sv_chop_left(Nob_String_View *sv, size_t n);
891+
NOBDEF Nob_String_View nob_sv_chop_right(Nob_String_View *sv, size_t n);
891892
// If `sv` starts with `prefix` chops off the prefix and returns true.
892893
// Otherwise, leaves `sv` unmodified and returns false.
893894
NOBDEF bool nob_sv_chop_prefix(Nob_String_View *sv, Nob_String_View prefix);
895+
// If `sv` ends with `suffix` chops off the suffix and returns true.
896+
// Otherwise, leaves `sv` unmodified and returns false.
897+
NOBDEF bool nob_sv_chop_suffix(Nob_String_View *sv, Nob_String_View suffix);
894898
NOBDEF Nob_String_View nob_sv_trim(Nob_String_View sv);
895899
NOBDEF Nob_String_View nob_sv_trim_left(Nob_String_View sv);
896900
NOBDEF Nob_String_View nob_sv_trim_right(Nob_String_View sv);
897901
NOBDEF bool nob_sv_eq(Nob_String_View a, Nob_String_View b);
902+
NOB_DEPRECATED("Use nob_sv_ends_with_cstr(sv, suffix) instead. "
903+
"Pay attention to the `s` at the end of the `end`. "
904+
"The reason this function was deprecated is because "
905+
"of the typo in the name, of course, but also "
906+
"because the second argument was a NULL-terminated string "
907+
"while nob_sv_starts_with() accepted Nob_String_View as the "
908+
"prefix which created an inconsistency in the API.")
898909
NOBDEF bool nob_sv_end_with(Nob_String_View sv, const char *cstr);
899-
NOBDEF bool nob_sv_starts_with(Nob_String_View sv, Nob_String_View expected_prefix);
910+
NOBDEF bool nob_sv_ends_with_cstr(Nob_String_View sv, const char *cstr);
911+
NOBDEF bool nob_sv_ends_with(Nob_String_View sv, Nob_String_View suffix);
912+
NOBDEF bool nob_sv_starts_with(Nob_String_View sv, Nob_String_View prefix);
900913
NOBDEF Nob_String_View nob_sv_from_cstr(const char *cstr);
901914
NOBDEF Nob_String_View nob_sv_from_parts(const char *data, size_t count);
902915
// nob_sb_to_sv() enables you to just view Nob_String_Builder as Nob_String_View
@@ -992,7 +1005,7 @@ NOBDEF void nob__go_rebuild_urself(int argc, char **argv, const char *source_pat
9921005
#ifdef _WIN32
9931006
// On Windows executables almost always invoked without extension, so
9941007
// it's ./nob, not ./nob.exe. For renaming the extension is a must.
995-
if (!nob_sv_end_with(nob_sv_from_cstr(binary_path), ".exe")) {
1008+
if (!nob_sv_ends_with_cstr(nob_sv_from_cstr(binary_path), ".exe")) {
9961009
binary_path = nob_temp_sprintf("%s.exe", binary_path);
9971010
}
9981011
#endif
@@ -2553,6 +2566,15 @@ NOBDEF bool nob_sv_chop_prefix(Nob_String_View *sv, Nob_String_View prefix)
25532566
return false;
25542567
}
25552568

2569+
NOBDEF bool nob_sv_chop_suffix(Nob_String_View *sv, Nob_String_View suffix)
2570+
{
2571+
if (nob_sv_ends_with(*sv, suffix)) {
2572+
nob_sv_chop_right(sv, suffix.count);
2573+
return true;
2574+
}
2575+
return false;
2576+
}
2577+
25562578
NOBDEF Nob_String_View nob_sv_chop_left(Nob_String_View *sv, size_t n)
25572579
{
25582580
if (n > sv->count) {
@@ -2567,6 +2589,19 @@ NOBDEF Nob_String_View nob_sv_chop_left(Nob_String_View *sv, size_t n)
25672589
return result;
25682590
}
25692591

2592+
NOBDEF Nob_String_View nob_sv_chop_right(Nob_String_View *sv, size_t n)
2593+
{
2594+
if (n > sv->count) {
2595+
n = sv->count;
2596+
}
2597+
2598+
Nob_String_View result = nob_sv_from_parts(sv->data + sv->count - n, n);
2599+
2600+
sv->count -= n;
2601+
2602+
return result;
2603+
}
2604+
25702605
NOBDEF Nob_String_View nob_sv_from_parts(const char *data, size_t count)
25712606
{
25722607
Nob_String_View sv;
@@ -2616,16 +2651,26 @@ NOBDEF bool nob_sv_eq(Nob_String_View a, Nob_String_View b)
26162651

26172652
NOBDEF bool nob_sv_end_with(Nob_String_View sv, const char *cstr)
26182653
{
2619-
size_t cstr_count = strlen(cstr);
2620-
if (sv.count >= cstr_count) {
2621-
size_t ending_start = sv.count - cstr_count;
2622-
Nob_String_View sv_ending = nob_sv_from_parts(sv.data + ending_start, cstr_count);
2623-
return nob_sv_eq(sv_ending, nob_sv_from_cstr(cstr));
2654+
return nob_sv_ends_with_cstr(sv, cstr);
2655+
}
2656+
2657+
NOBDEF bool nob_sv_ends_with_cstr(Nob_String_View sv, const char *cstr)
2658+
{
2659+
return nob_sv_ends_with(sv, nob_sv_from_cstr(cstr));
2660+
}
2661+
2662+
NOBDEF bool nob_sv_ends_with(Nob_String_View sv, Nob_String_View suffix)
2663+
{
2664+
if (sv.count >= suffix.count) {
2665+
Nob_String_View sv_tail = {
2666+
.count = suffix.count,
2667+
.data = sv.data + sv.count - suffix.count,
2668+
};
2669+
return nob_sv_eq(sv_tail, suffix);
26242670
}
26252671
return false;
26262672
}
26272673

2628-
26292674
NOBDEF bool nob_sv_starts_with(Nob_String_View sv, Nob_String_View expected_prefix)
26302675
{
26312676
if (expected_prefix.count <= sv.count) {
@@ -2939,13 +2984,17 @@ NOBDEF char *nob_temp_running_executable_path(void)
29392984
#define sv_chop_by_delim nob_sv_chop_by_delim
29402985
#define sv_chop_while nob_sv_chop_while
29412986
#define sv_chop_prefix nob_sv_chop_prefix
2987+
#define sv_chop_suffix nob_sv_chop_suffix
29422988
#define sv_chop_left nob_sv_chop_left
2989+
#define sv_chop_right nob_sv_chop_right
29432990
#define sv_trim nob_sv_trim
29442991
#define sv_trim_left nob_sv_trim_left
29452992
#define sv_trim_right nob_sv_trim_right
29462993
#define sv_eq nob_sv_eq
29472994
#define sv_starts_with nob_sv_starts_with
29482995
#define sv_end_with nob_sv_end_with
2996+
#define sv_ends_with nob_sv_ends_with
2997+
#define sv_ends_with_cstr nob_sv_ends_with_cstr
29492998
#define sv_from_cstr nob_sv_from_cstr
29502999
#define sv_from_parts nob_sv_from_parts
29513000
#define sb_to_sv nob_sb_to_sv
@@ -2959,7 +3008,12 @@ NOBDEF char *nob_temp_running_executable_path(void)
29593008
/*
29603009
Revision history:
29613010
2962-
3.5.0 (2026-03-13) Add nob_null_log_handler (by @rexim)
3011+
3.6.0 (2026-03-16) Add nob_sv_chop_suffix()
3012+
Deprecate nob_sv_end_with()
3013+
Add nob_sv_ends_with_cstr() instead of nob_sv_end_with()
3014+
Add nob_sv_ends_with()
3015+
Add nob_sv_chop_right()
3016+
3.5.0 (2026-03-13) Add nob_null_log_handler() (by @rexim)
29633017
Rename nob_log_handler to Nob_Log_Handler (by @rexim)
29643018
3.4.0 (2026-03-12) Add nob_da_first() (by @rexim)
29653019
Add nob_da_pop() (by @rexim)

tests/nob_string_view.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
void trace_case(String_View sv, const char *suffix)
44
{
5-
bool result = sv_end_with(sv, suffix);
6-
printf("sv_end_with(\"" SV_Fmt "\", \"%s\") => %s\n", SV_Arg(sv), suffix, result ? "true" : "false");
5+
bool result = sv_ends_with_cstr(sv, suffix);
6+
printf("sv_ends_with_cstr(\"" SV_Fmt "\", \"%s\") => %s\n", SV_Arg(sv), suffix, result ? "true" : "false");
77
}
88

99
int main(void)
@@ -35,5 +35,17 @@ int main(void)
3535
printf("sv = \"" SV_Fmt "\", prefix = \"" SV_Fmt "\", result = %s\n", SV_Arg(sv), SV_Arg(prefix), result ? "true" : "false");
3636
}
3737

38+
{
39+
printf("-- sv_chop_suffix --\n");
40+
String_View sv = sv_from_cstr("hello world");
41+
String_View suffix = sv_from_cstr("foo");
42+
bool result = sv_chop_suffix(&sv, suffix);
43+
printf("sv = \"" SV_Fmt "\", suffix = \"" SV_Fmt "\", result = %s\n", SV_Arg(sv), SV_Arg(suffix), result ? "true" : "false");
44+
45+
suffix = sv_from_cstr("world");
46+
result = sv_chop_suffix(&sv, suffix);
47+
printf("sv = \"" SV_Fmt "\", suffix = \"" SV_Fmt "\", result = %s\n", SV_Arg(sv), SV_Arg(suffix), result ? "true" : "false");
48+
}
49+
3850
return 0;
3951
}

tests/nob_string_view.stdout.txt

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
-- sv_end_with --
2-
sv_end_with("./example.exe", "./example.exe") => true
3-
sv_end_with("./example.exe", ".exe") => true
4-
sv_end_with("./example.exe", "e") => true
5-
sv_end_with("./example.exe", "") => true
6-
sv_end_with("", "") => true
7-
sv_end_with("./example.exe", ".png") => false
8-
sv_end_with("./example.exe", "/path/to/example.exe") => false
9-
sv_end_with("", ".obj") => false
2+
sv_ends_with_cstr("./example.exe", "./example.exe") => true
3+
sv_ends_with_cstr("./example.exe", ".exe") => true
4+
sv_ends_with_cstr("./example.exe", "e") => true
5+
sv_ends_with_cstr("./example.exe", "") => true
6+
sv_ends_with_cstr("", "") => true
7+
sv_ends_with_cstr("./example.exe", ".png") => false
8+
sv_ends_with_cstr("./example.exe", "/path/to/example.exe") => false
9+
sv_ends_with_cstr("", ".obj") => false
1010
-- sv_chop_prefix --
1111
sv = "hello world", prefix = "foo", result = false
1212
sv = " world", prefix = "hello", result = true
13+
-- sv_chop_suffix --
14+
sv = "hello world", suffix = "foo", result = false
15+
sv = "hello ", suffix = "world", result = true
Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
-- sv_end_with --
2-
sv_end_with("./example.exe", "./example.exe") => true
3-
sv_end_with("./example.exe", ".exe") => true
4-
sv_end_with("./example.exe", "e") => true
5-
sv_end_with("./example.exe", "") => true
6-
sv_end_with("", "") => true
7-
sv_end_with("./example.exe", ".png") => false
8-
sv_end_with("./example.exe", "/path/to/example.exe") => false
9-
sv_end_with("", ".obj") => false
2+
sv_ends_with_cstr("./example.exe", "./example.exe") => true
3+
sv_ends_with_cstr("./example.exe", ".exe") => true
4+
sv_ends_with_cstr("./example.exe", "e") => true
5+
sv_ends_with_cstr("./example.exe", "") => true
6+
sv_ends_with_cstr("", "") => true
7+
sv_ends_with_cstr("./example.exe", ".png") => false
8+
sv_ends_with_cstr("./example.exe", "/path/to/example.exe") => false
9+
sv_ends_with_cstr("", ".obj") => false
1010
-- sv_chop_prefix --
1111
sv = "hello world", prefix = "foo", result = false
1212
sv = " world", prefix = "hello", result = true
13+
-- sv_chop_suffix --
14+
sv = "hello world", suffix = "foo", result = false
15+
sv = "hello ", suffix = "world", result = true

0 commit comments

Comments
 (0)