From 0e6f440ce7bd3090c86b07a26ff8a780c3b7779b Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sun, 6 Mar 2022 21:58:57 +0100 Subject: [PATCH] fix utils, add tests --- src/tests/bin/utils | Bin 73448 -> 82012 bytes src/tests/launcher.o | Bin 4748 -> 0 bytes src/tests/utils/array.o | Bin 3512 -> 0 bytes src/tests/utils/cstring.c | 177 +++++++++++- src/tests/utils/cstring.o | Bin 38984 -> 0 bytes src/tests/utils/main.o | Bin 1968 -> 0 bytes .../{test_readln.txt => test_readline.txt} | 0 src/utils/cstring.c | 261 ++++++++++-------- src/utils/cstring.h | 88 +++--- 9 files changed, 352 insertions(+), 174 deletions(-) delete mode 100644 src/tests/launcher.o delete mode 100644 src/tests/utils/array.o delete mode 100644 src/tests/utils/cstring.o delete mode 100644 src/tests/utils/main.o rename src/tests/utils/{test_readln.txt => test_readline.txt} (100%) diff --git a/src/tests/bin/utils b/src/tests/bin/utils index 0e2bec665416d58d4ed7269b5d09a46a3bd43c27..b9bbc5bf3d056dd85cf6fb97df92d39cf2989e55 100755 GIT binary patch literal 82012 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 diff --git a/src/tests/launcher.o b/src/tests/launcher.o deleted file mode 100644 index ea0fcf62be96e941c18256b011391060f1540775..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4748 zcma)9ZEO_R6}|gmV-tf7r8Fs|nIv{_O4-^5Riq%o0%NDDgN-p1V!>*?9%I9L*X+*n zQJ@x?lGIvOt&|@jQk5!Fe^gCXAysV>HBy~A!9kTO|DZ~L&?>5&$dR4OXh}KtQs|MSg)GZTlm2ASCqRLF8b73kpQkQ>;EN@N)Ca;Mxv+_0`aj*_Y z+svs8ldfxLEbPoy6>~RAZu7sQ2W*5zZ!2g8=HSosHtkG5zzxK8qL)|0Q&-8)^mAd{ z8*?(<;{6(V+Av0SE$8;b*ty-k#UtywczG* z`af_C|1aO+f35ake^>uYxqIDpcj^vz>+aJXp7olt_*4d~^ljDQX-}AQ@FdQKd9j<3 ziR0m7Zr+nC?GhU`=Wbt^LF#G>jsg2pg7fBF{>Z}h@j`oj*qNFuo?K8V+ULx!FAHPz zj}zui?mJO_Jykif{7q&1 z1N?VO=??qF^2C1h{7LiD8$ILOXqAfFGrR@q5)tn688-MM{1^(iIeUF+XV3YZJ?wY( z3KWn;-ug`c5)s9HPHH9`tf*cv)3SukpwDKxYePGo-EEb%m%sDBV$r$qq2!jmNy*Gg zRT($E!YNquhjBa#@dcg`Uk&Oreyf<{Cf>8A}bq#@hWkmcVI14E3CZyVAY{Z_l|*s;Udn>K7K zYiEst_$kZiwXBrUpU$QFjP2XE%cf1K_>ct{j%Tx0A13|r!K9iDr85*H(#dp&dTBk~ z-O=9B)ope?i|nnhAD6b>yT55Pw(ULeq|w|IX^Au&Eln*=%`HuvMVM-iz<0YOaK0+A zt|lDjscgg=Z=RzAT%s$hE(Le3s4!m$IpNTrzX`9|DR6OgvLieOI6+EC7} ztg8&>&ew&4xig`E1m1x#s>0X}V*~2!2`3SJ0(hJM9@oEt<@MPA26Q4moqktEsIwC~ zLA-zNrPBwUrq9t~&X3+hho1+(fDQ*jy6ezlB@4@E#d4*PFiDFemduNjIR--_?vq!!b+&g3B zkCqh>%Rf6R|U?wwEiPx$nY`?w_Ixm04n%0v=!(Cq4#u8sq3rgU^g z_X75JcXUc`_9@BQ>EW2$^iIbI?ZMPB&D;*DiQ6SL8Hi`qESD+mp(U#E##D>tG&YzT zv?Ufhv-KO1W0oBoPQ>hiT@?uYNJ9Z#HyB?eB!7-I}}@uaBDv$;gV%4S_c zVGa%6mDur&EsRJ7EZIyhm9jE1Knz=#cuI+tW4t0ft^SNZKOR?6`Gdzc&_uDzO{*7%~v*EC)QhS3b(()?ZWheiIR`NtY( zfg8~{*nh*1h^#;jkUs>hM&n=&5*sys9T+yy-hshK@mq+9czb}1cL+%Pvq0KiB;w1P z{gnKNK-&KlNV}f{Y4v6q)k?W6( z{7kR^Qm=oi`9C#h)2jX=@=1i>4M62rug8GFdgP6W_(p(??-G!9FA-t)3NZXN^fJBv zj>bP|ya}ZJ-+;9LjO&Qu-$d9iuW;pcK*}EhQoex*`Bp98q2js}EP}LJ~K=aEQuM*k(BH6P;cDxs8XIvccW*I9P zv8^+MaZBo4e#_(tj#QHP*)QcR; zq;tav;eH3dk@&9m#uiNYcH_Gnk4C+}@Hhm=4ex39{SA=qxGp1)-k^*F$6fV>og^4n z;AjlFqCbH0NB<4DXoJV8#{2N4zJoO9o*XD=6_2NP3woZ6a&O**IsI`D4(fUDTyjru zE9UAxwBl)eka#lcdH2z+=k&{Q4ti)&r9nMjM>KkZm!VfaJbx##$hjBa73i^#c*Bc< zKLXfScWS{QG}l9zGk+*q6)W>s?h919u{a6mD=^0qRC+8$`tovzsnkD!@1U}My(w#; PT<lO!m)P^?LoC=`

zncPtCP)bE=mzJHZAtt9L-?(*UdMaARARZBK|0{6*6c(u-LqVHUqn@I0ivS3#&<6oWz zE8=t@#k_hKVw@4pp++9fMSBFTq4Ub+hQ@J(x%N-udCZeO9f??oe~z{a>v})QdAG^A zirlB*6q6ji;AM!dlOxGGyWqh)8b70b7# zTjaACrvBFnd@+H4PT*gF&E2B@ABp@w35-K;80UL9fuBs^?ZD<Cm(vu{UdkF&44yRU1%v%hmk zPnXlICvln3cY}QSNJ$0)-;boDB{+ePDdwBN9g751$#T45$E{TSAan+zx}-MXc;#v- zjChr*=lPXNY*wjM3!(3Lf$xUCgq~YT05_j^yg}a^_Vdm_VGPyJ7boH|rA{T%P>=#K zc}Lg19L_(DBF0<0cqN_%eD(p6weX8tMV{69=XJhQ$M?Wz9}?-)co05~!K@wB35XvQ zIYN)m<9qa&=L4NT4ZjGl`p59uRU&7IG2d4@{;l@swZ8liicdEP#}97=z_9NtXZD;JAC-VD1`4t*P+ z-A$Fy^@gKK{6S|RaErd!hl4WS?z^yy;4Y8xx1!H;#dV7AJv`4l$$J4Y!^5Lh9P%DR z!*MpgP<$4xcm~Fpqv3k1Z&U{X>?}TEA0f$k`Sqg~_1B|u3}dvHV_L*UkN;+pZ+Hj5 zqlPilZ$p4%j0}0N8j{Wta)0r8&w z!J($V5B<2_>j37Q`BgT09{SW<2p!rF2|ea$$I#-ut9RhB=8(tpp9H7nc{s&2AZGZp( diff --git a/src/tests/utils/cstring.c b/src/tests/utils/cstring.c index daa612c..b44aef2 100644 --- a/src/tests/utils/cstring.c +++ b/src/tests/utils/cstring.c @@ -17,10 +17,12 @@ * along with this program. If not, see . */ +#include + #include "launcher.h" #include "utils/cstring.h" -#define TEST_FILE_READLN "utils/test_readln.txt" +#define TEST_FILE_READLINE "utils/test_readline.txt" cstring *s; @@ -77,8 +79,8 @@ START(add_all_but_p) ASSERT_EQUALS_STR("Multi-line", str, s->string); reset(); - str = - "Les accents en français sont bien là et se retrouvent avec une fréquence élevée"; + str = "Les accents en français sont bien là et se " + "retrouvent avec une fréquence élevée"; cstring_add(s, str); ASSERT_EQUALS_STR("accents", str, s->string); reset(); @@ -439,12 +441,12 @@ START(clone) if (clone) FAIL("Cloning NULL must return NULL"); - clone = cstring_clone(s); + clone = cstring_clone(""); ASSERT_EQUALS_STR("Cannot clone the empty string", "", clone->string); free_cstring(clone); cstring_add(s, "Testy viva la vida"); - clone = cstring_clone(s); + clone = cstring_clone(s->string); ASSERT_EQUALS_STR("Failed to clone the string", s->string, clone->string); free_cstring(clone); @@ -531,6 +533,44 @@ START(trim) END +START(remove_crlf) + char *str = "testy"; + + cstring_add(s, str); + s->length = cstring_remove_crlf(s->string); + ASSERT_EQUALS_STR("no-op failed", str, s->string); + + reset(); + cstring_add(s, str); + cstring_add(s, "\n"); + s->length = cstring_remove_crlf(s->string); + ASSERT_EQUALS_STR("\\n failed", str, s->string); + + reset(); + cstring_add(s, str); + cstring_add(s, "\r\n"); + s->length = cstring_remove_crlf(s->string); + ASSERT_EQUALS_STR("\\r\\n failed", str, s->string); + + reset(); + cstring_add(s, str); + cstring_add(s, "\n\n"); + s->length = cstring_remove_crlf(s->string); + ASSERT_EQUALS_STR("\\n\\n failed", "testy\n", s->string); + + reset(); + cstring_add(s, str); + cstring_add(s, "\r\n\r\n"); + s->length = cstring_remove_crlf(s->string); + ASSERT_EQUALS_STR("\\r\\n\\r\\n failed", "testy\r\n", s->string); + + reset(); + cstring_add(s, "\n"); + s->length = cstring_remove_crlf(s->string); + ASSERT_EQUALS_STR("\\n uniq failed", "", s->string); + + END + START(toupper) cstring_add(s, ""); cstring_toupper(s); @@ -589,9 +629,9 @@ START(tolower) END -START(readln) +START(readline) int read; - FILE *testin = fopen(TEST_FILE_READLN, "r"); + FILE *testin = fopen(TEST_FILE_READLINE, "r"); if (!testin) FAIL("Test file not found: test_readln.txt"); @@ -619,6 +659,121 @@ START(readln) END +START(add_path) + cstring_add_path(s, "root"); + ASSERT_EQUALS_STR("failed to create root path", "/root", s->string); + + cstring_add_path(s, "dir"); + ASSERT_EQUALS_STR("failed to add a dir", "/root/dir", s->string); + + cstring_add_path(s, "sub/"); + ASSERT_EQUALS_STR("extra / failed", "/root/dir/sub", s->string); + + END + +START(pop_path) + cstring_add(s, ""); + ASSERT_EQUALS_INT("empty test failed", 0, cstring_pop_path(s, 1)); + + reset(); + cstring_add(s, "root"); + ASSERT_EQUALS_INT("0 nbr test failed", 0, cstring_pop_path(s, 0)); + ASSERT_EQUALS_STR("0 test failed", "root", s->string); + + reset(); + cstring_add(s, "root/"); + ASSERT_EQUALS_INT("0² nbr test failed", 0, cstring_pop_path(s, 0)); + ASSERT_EQUALS_STR("0² test failed", "root", s->string); + + reset(); + cstring_add(s, "/"); + ASSERT_EQUALS_INT("root test nbr failed", 0, cstring_pop_path(s, 1)); + ASSERT_EQUALS_STR("root test failed", "/", s->string); + + reset(); + cstring_add(s, "/"); + ASSERT_EQUALS_INT("root² test nbr failed", 0, cstring_pop_path(s, 2)); + ASSERT_EQUALS_STR("root² test failed", "/", s->string); + + reset(); + cstring_add(s, "/root"); + ASSERT_EQUALS_INT("/root test nbr failed", 1, cstring_pop_path(s, 1)); + ASSERT_EQUALS_STR("/root test failed", "/", s->string); + + reset(); + cstring_add(s, "/root"); + ASSERT_EQUALS_INT("/root³ test nbr failed", 1, cstring_pop_path(s, 2)); + ASSERT_EQUALS_STR("/root³ test failed", "/", s->string); + + reset(); + cstring_add(s, "/root/dir/file"); + ASSERT_EQUALS_INT("2 test nbr failed", 2, cstring_pop_path(s, 2)); + ASSERT_EQUALS_STR("2 test failed", "/root", s->string); + + reset(); + cstring_add(s, "/root/dir/file/"); + ASSERT_EQUALS_INT("trailing / test nbr failed", 1, + cstring_pop_path(s, 1)); + ASSERT_EQUALS_STR("trailing / test failed", "/root/dir", s->string); + + END + +START(basename) + char *str; + + cstring_add(s, ""); + str = cstring_basename(s->string, NULL); + ASSERT_EQUALS_STR("empty test", "", str); + free(str); + + reset(); + cstring_add(s, "/root/path/dir/file"); + str = cstring_basename(s->string, NULL); + ASSERT_EQUALS_STR("simple test", "file", str); + free(str); + + reset(); + cstring_add(s, "/root/path/dir/file"); + str = cstring_basename(s->string, ".ext"); + ASSERT_EQUALS_STR("no ext test", "file", str); + free(str); + + reset(); + cstring_add(s, "/root/path/dir/file.test"); + str = cstring_basename(s->string, ".ext"); + ASSERT_EQUALS_STR("wrong ext test", "file.test", str); + free(str); + + reset(); + cstring_add(s, "/root/path/dir/file.ext"); + str = cstring_basename(s->string, ".ext"); + ASSERT_EQUALS_STR("good ext test", "file", str); + free(str); + + END + +START(dirname) + char *str; + + cstring_add(s, "/root/path"); + str = cstring_dirname(s->string); + ASSERT_EQUALS_STR("simple test", "/root", str); + free(str); + + reset(); + cstring_add(s, "/root/path/"); + str = cstring_dirname(s->string); + ASSERT_EQUALS_STR("trailing / test", "/root", str); + free(str); + + reset(); + cstring_add(s, "/"); + str = cstring_dirname(s->string); + ASSERT_EQUALS_STR("root is root of root test", "/", str); + free(str); + + END + START(many_adds) size_t count = 50000000; for (size_t i = 0; i < count; i++) { @@ -652,10 +807,14 @@ Suite *test_cstring(const char title[]) { tcase_add_test(core, clone); tcase_add_test(core, rtrim); tcase_add_test(core, trim); + tcase_add_test(core, remove_crlf); tcase_add_test(core, toupper); tcase_add_test(core, tolower); - - tcase_add_test(core, readln); + tcase_add_test(core, readline); + tcase_add_test(core, add_path); + tcase_add_test(core, pop_path); + tcase_add_test(core, basename); + tcase_add_test(core, dirname); suite_add_tcase(suite, core); diff --git a/src/tests/utils/cstring.o b/src/tests/utils/cstring.o deleted file mode 100644 index 6da56ba8c5f72a86f64f551b887872196a1bc9f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38984 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 I_;URI7l6r=$^ZZW diff --git a/src/tests/utils/main.o b/src/tests/utils/main.o deleted file mode 100644 index b632e13739d6fac0ba3325195c0e8fcb10512729..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1968 zcma)6&re)c6h1R=Xa|IrqF7C7J56c|D$fB;L#i=AJFr1%_>t5Y@^}nSK$ti9-kSup zq^T27GJg(eAhV3jM|YVqbspL;RdKpp?wF6Oy@}&zx$_#TktApQSk^&1pw`o;gTPn*(2LwwCjg!$Eh)?~NraPWB0T>I>~}m)vo9Su-`fdYIaWU@5nObrc>l^o#;$4s9)Kd(ysE9!6%bwm%LTB2N?3iSb;a^Sg< zCkC=uSX)8_!ro@v1TS2q1)r0!&A8IjusJlkhj}#d<2XLV_zB%R#=nT;4&xmn%dm`Z z#Bsi{-0LE@0u_%SV%ua~u0{~ajTSWwElrhtYjNB2D_`G)sCc&uT>_(cR*f_qTN`&7H? zYswD*(LWLszXmWhNHn~u*k@gekA(RTBqonK6I&Q1KbQhBHt-u@`sRE;0z@%~#+;!7 ze}Dg;BJmbt>>vM~$YVeD*8)_9XA$I`VWbtW9hS9B@8HTT0O#EZ>rglY`+2`%qwiHl He+=&xxIQxa diff --git a/src/tests/utils/test_readln.txt b/src/tests/utils/test_readline.txt similarity index 100% rename from src/tests/utils/test_readln.txt rename to src/tests/utils/test_readline.txt diff --git a/src/utils/cstring.c b/src/utils/cstring.c index d501537..7c06927 100644 --- a/src/utils/cstring.c +++ b/src/utils/cstring.c @@ -1,7 +1,7 @@ /* * CUtils: some small C utilities * - * Copyright (C) 2012 Niki Roo + * Copyright (C) 2011 Niki Roo * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +19,10 @@ /* Name: cstring.c - Copyright: niki (cc-by-nc) 2011 + Copyright: niki (gpl3 or later) 2011 Author: niki Date: 2011-06-16 - Description: cstring is a collection of helper functions to manipulate string of text + Description: cstring is a collection of helper functions to manipulate text */ #include "cstring.h" @@ -33,6 +33,9 @@ #include #include +// For upper/lowercase +#include + #ifndef BUFFER_SIZE #define BUFFER_SIZE 81 #endif @@ -43,7 +46,7 @@ #define CSTRING_SEP '/' #endif -//start of private prototypes +// Private functions typedef struct { size_t buffer_length; @@ -53,8 +56,14 @@ typedef struct { static void cstring_swap(cstring *a, cstring *b); /** Change the case to upper -or- lower case (UTF8-compatible) */ static void cstring_change_case(cstring *self, int up); +/** For path-related functions */ +static void normalize_path(cstring *self); + +// Private variables -//end of private prototypes +static char *locale = NULL; + +// end of privates cstring *new_cstring() { cstring *string; @@ -334,16 +343,15 @@ int cstring_replace(cstring *self, const char from[], const char to[]) { cstring *buffer; size_t i; size_t step; - char *swap; int occur; - // easy optimization: + // easy optimisation: if (!from || !from[0]) return 0; if (from && to && from[0] && to[0] && !from[1] && !to[1]) return cstring_replace_car(self->string, from[0], to[0]); - // optimize for same-size strings? + // optimise for same-size strings? step = strlen(from) - 1; buffer = new_cstring(); @@ -358,12 +366,7 @@ int cstring_replace(cstring *self, const char from[], const char to[]) { } } - // not clean, but quicker: - swap = self->string; - self->string = buffer->string; - buffer->string = swap; - self->length = buffer->length; - + cstring_swap(self, buffer); free_cstring(buffer); return occur; } @@ -459,12 +462,12 @@ char *cstring_convert(cstring *self) { return string; } -cstring *cstring_clone(cstring *self) { +cstring *cstring_clone(const char self[]) { if (self == NULL) return NULL; cstring *clone = new_cstring(); - cstring_add(clone, self->string); + cstring_add(clone, self); return clone; } @@ -497,27 +500,16 @@ void cstring_trim(cstring *self, char car) { } } -size_t cstring_remove_crlf(cstring *self) { - size_t removed; - - removed = cstring_sremove_crlf(self->string, self->length); - self->length -= removed; - - return removed; -} - -size_t cstring_sremove_crlf(char data[], size_t n) { - size_t removed; - - removed = n; - while (removed > 0 - && (data[removed - 1] == '\r' || data[removed - 1] == '\n')) { - removed--; - } +size_t cstring_remove_crlf(char *self) { + size_t sz = strlen(self); + if (sz && self[sz - 1] == '\n') + sz--; + if (sz && self[sz - 1] == '\r') + sz--; - data[removed] = '\0'; + self[sz] = '\0'; - return removed; + return sz; } void cstring_toupper(cstring *self) { @@ -529,30 +521,75 @@ void cstring_tolower(cstring *self) { } void cstring_change_case(cstring *self, int up) { - wchar_t *wide; + // Change LC_ALL to LANG if not found + // TODO: only take part we need (also, this is still bad practise) + if (!locale) { + locale = setlocale(LC_ALL, NULL); + if (!locale || !locale[0] || !strcmp("C", locale)) { + char *lang = getenv("LANG"); + if (lang && lang[0]) { + locale = setlocale(LC_ALL, lang); + if (!locale) + locale = ""; + } + } + } + + cstring *rep; + mbstate_t state_from, state_to; + wchar_t wide; char tmp[10]; - const char *src = self->string; - size_t s, i; - mbstate_t state; - - // init the state (passing NULL is not thread-safe) - memset(&state, '\0', sizeof(mbstate_t)); - - // won't contain MORE chars (but maybe less) - wide = (wchar_t *) malloc((self->length + 1) * sizeof(wchar_t)); - s = mbsrtowcs(wide, &src, self->length, &state); - wide[s] = (wchar_t) '\0'; - cstring_clear(self); - for (i = 0; i <= s; i++) { + size_t count; + + // init the state (NULL = internal hidden state, not thread-safe) + memset(&state_from, '\0', sizeof(mbstate_t)); + memset(&state_to, '\0', sizeof(mbstate_t)); + + rep = new_cstring(); + + size_t i = 0; + while (i < self->length) { + count = mbrtowc(&wide, self->string + i, self->length - i, &state_from); + + //incomplete (should not happen) + if (count == (size_t) -2) { + // return; + cstring_add_car(rep, '_'); + i++; + continue; + } + // invalid multibyte sequence + if (count == (size_t) -1) { + // return; + cstring_add_car(rep, '_'); + i++; + continue; + } + + // End of String (should not happen, see WHILE condition) + if (!count) + break; + + // char is ok + i += count; + if (up) - wide[i] = (wchar_t) towupper((wint_t) wide[i]); + wide = (wchar_t) towupper((wint_t) wide); else - wide[i] = (wchar_t) towlower((wint_t) wide[i]); - memset(&state, '\0', sizeof(mbstate_t)); - wcrtomb(tmp, wide[i], &state); - cstring_add(self, tmp); + wide = (wchar_t) towlower((wint_t) wide); + + count = wcrtomb(tmp, wide, &state_to); + if (count == (size_t) -1) { + // failed to convert :( + cstring_add_car(rep, '_'); + } else { + tmp[count] = '\0'; + cstring_add(rep, tmp); + } } - free(wide); + + cstring_swap(self, rep); + free_cstring(rep); } int cstring_readline(cstring *self, FILE *file) { @@ -570,26 +607,25 @@ int cstring_readline(cstring *self, FILE *file) { cstring_clear(self); buffer[0] = '\0'; - // Note: strlen() could return 0 if the file contains \0 - // at the start of a line + // Note: fgets() could return NULL if EOF is reached if (!fgets(buffer, (int) BUFFER_SIZE - 1, file)) return 0; - size = strlen(buffer); + size = strlen(buffer); full_line = ((file && feof(file)) || size == 0 || buffer[size - 1] == '\n'); - size -= cstring_sremove_crlf(buffer, size); + size = cstring_remove_crlf(buffer); cstring_add(self, buffer); // No luck, we need to continue getting data while (!full_line) { if (!fgets(buffer, (int) BUFFER_SIZE - 1, file)) break; - size = strlen(buffer); + size = strlen(buffer); full_line = ((file && feof(file)) || size == 0 || buffer[size - 1] == '\n'); - size -= cstring_sremove_crlf(buffer, size); + size = cstring_remove_crlf(buffer); cstring_add(self, buffer); } @@ -599,78 +635,81 @@ int cstring_readline(cstring *self, FILE *file) { return 0; } +static void normalize_path(cstring *self) { + while (self->length && self->string[self->length - 1] == CSTRING_SEP) + self->length--; + self->string[self->length] = '\0'; +} + void cstring_add_path(cstring *self, const char subpath[]) { + while (self->length && self->string[self->length - 1] == CSTRING_SEP) + self->length--; cstring_add_car(self, CSTRING_SEP); - cstring_add(self, subpath); + if (subpath && subpath[0]) { + cstring_add(self, subpath); + } + + normalize_path(self); } int cstring_pop_path(cstring *self, int how_many) { - char sep[] = { CSTRING_SEP }; int count = 0; + size_t tmp; + char first = '\0'; - cstring_rtrim(self, CSTRING_SEP); - for (int i = 0; i < how_many; i++) { - size_t idx = cstring_rfind(self->string, sep, 0); - if (!idx) - break; + if (self->length) + first = self->string[0]; - cstring_cut_at(self, idx - 1); - count++; + normalize_path(self); + for (int i = 0; i < how_many; i++) { + tmp = self->length; + while (self->length && self->string[self->length - 1] != CSTRING_SEP) + self->length--; + while (self->length && self->string[self->length - 1] == CSTRING_SEP) + self->length--; + if (self->length != tmp) + count++; } + normalize_path(self); + + // Root is root of root + if (first == CSTRING_SEP && !self->length) + cstring_add_car(self, CSTRING_SEP); return count; } -cstring *cstring_getdir(const char path[]) { - cstring *result; +char *cstring_basename(const char path[], const char ext[]) { size_t i; - size_t sz = strlen(path); - i = sz - 1; - if (i >= 0 && path[i] == CSTRING_SEP) + i = sz; + while (i && path[i] != CSTRING_SEP) i--; - for (; i >= 0 && path[i] != CSTRING_SEP; i--) - ; - - if (i < 0) - return new_cstring(); - - result = new_cstring(); - cstring_addn(result, path, i); - - return result; -} - -cstring *cstring_getfile(cstring *path) { - cstring *result; - ssize_t i; - i = (ssize_t) path->length - 1; - if (i >= 0 && path->string[i] == CSTRING_SEP) - i--; - for (; i >= 0 && path->string[i] != CSTRING_SEP; i--) - ; + cstring *rep; + if (path[i] != CSTRING_SEP) { + rep = cstring_clone(path); + } else { + rep = new_cstring(); + cstring_addf(rep, path, i + 1); + } - if (i < 0 || (size_t) (i + 1) >= path->length) - return new_cstring(); + if (ext && ext[0] && cstring_ends_with(rep->string, ext)) { + cstring_cut_at(rep, rep->length - strlen(ext)); + } - result = new_cstring(); - cstring_add(result, path->string + i + 1); - return result; + return cstring_convert(rep); } -cstring *cstring_getfiles(const char path[]) { - cstring *copy = new_cstring(); - cstring_add(copy, path); - - cstring *result = cstring_getfile(copy); - - free_cstring(copy); - - return result; +char *cstring_dirname(const char path[]) { + cstring *rep = cstring_clone(path); + cstring_pop_path(rep, 1); + return cstring_convert(rep); } -int cstring_is_whole(cstring *self) { - return mbstowcs(NULL, self->string, 0) != (size_t) -1; +int cstring_is_utf8(cstring *self) { + size_t rep = mbstowcs(NULL, self->string, 0); + // -2 = invalid, -1 = not whole + return (rep != (size_t) -2) && (rep != (size_t) -1); } diff --git a/src/utils/cstring.h b/src/utils/cstring.h index 7a378f0..ecd34d6 100644 --- a/src/utils/cstring.h +++ b/src/utils/cstring.h @@ -323,7 +323,7 @@ char *cstring_convert(cstring *self); * * @param self the string to clone */ -cstring *cstring_clone(cstring *self); +cstring *cstring_clone(const char self[]); /** * Trim this cstring of all trailing 'car' instances. @@ -346,10 +346,22 @@ void cstring_rtrim(cstring *self, char car); */ void cstring_trim(cstring *self, char car); +/** + * Remove the \r and \n sequence (or one OR the other) at the end of the string. + * + * @param self the string to change + * + * @return the new length of the string + */ +size_t cstring_remove_crlf(char *self); + /** * Change the case to upper-case (UTF-8 compatible, but the string MUST be * whole). * + * @note: if LC_ALL is not set or is set to C and a viable $LANG exists, it will + * set LC_ALL to $LANG + * * @param self the cstring to work on */ void cstring_toupper(cstring *self); @@ -358,6 +370,9 @@ void cstring_toupper(cstring *self); * Change the case to lower-case (UTF-8 compatible, but the string MUST be * whole). * + * @note: if LC_ALL is not set or is set to C and a viable $LANG exists, it will + * set LC_ALL to $LANG + * * @param self the cstring to work on */ void cstring_tolower(cstring *self); @@ -372,16 +387,6 @@ void cstring_tolower(cstring *self); */ int cstring_readline(cstring *self, FILE *file); -/** - * Read a whole line (CR, LN or CR+LN terminated) from the given socket. - * - * @param self the cstring to read into - * @param fd the socket to read from - * - * @return 1 if a line was read, 0 if not - */ -int cstring_readnet(cstring *self, int fd); - /** * Add a path to the given cstring (if it is currently empty, it * will result in a root path). @@ -394,7 +399,16 @@ int cstring_readnet(cstring *self, int fd); */ void cstring_add_path(cstring *self, const char subpath[]); -//TODO: desc +/** + * Remove the how_many components of the path described by this + * cstring. Will ignore extra path separators and always trim it from the final + * result (i.e., some//path/ is identical to some/path). + * + * @note popping "0" path will simply make sure the string does not end in "/" + * + * @param how_many how many path components to remove (for instance, to go from + * /some/path/to/file to /some/path you would need 2) + */ int cstring_pop_path(cstring *self, int how_many); /** @@ -402,10 +416,13 @@ int cstring_pop_path(cstring *self, int how_many); * '/home/user/file.ext' becomes 'file.ext'). * * @param path the path to get the dir of (it can be a dir itself) + * @param ext the extension to remove if any (can be empty or NULL for none) + * + * @note the extension should include the "." if any * * @return a new string representing the parent directory */ -char *cstring_basename(const char path[]); +char *cstring_basename(const char path[], const char ext[]); /** * Return the dirname of this path (for instance, @@ -418,49 +435,12 @@ char *cstring_basename(const char path[]); char *cstring_dirname(const char path[]); /** - * Return the latest path component of this path (usually a FILE). - * - * @param path the path to get the basename of (it can be a dir itself) - * - * @return a new cstring representing the latest path component - */ -cstring *cstring_getfile(cstring *path); - -/** - * Return the latest path component of this path (usually a FILE). - * - * @param path the path to get the basename of (it can be a dir itself) - * - * @return a new string representing the latest path component - */ -cstring *cstring_getfiles(const char path[]); - -/** - * Remove all the \r and \n at the end of the given cstring. - * - * @param self the cstring to change - * - * @return how many removed characters - */ -size_t cstring_remove_crlf(cstring *self); - -/** - * Remove all the \r and \n at the end of the given string. - * - * @param self the string to change - * @param n the size of the string - * - * @return how many removed characters - */ -size_t cstring_sremove_crlf(char *self, size_t n); - -/** - * Check if the string is whole (i.e., it doesn't contain incomplete UTF-8 - * sequences). + * Check if the string is a correct and whole UTF-8 string (i.e., it is indeed + * an UTF-8 string and doesn't contain incomplete UTF-8 sequences). * - * @return TRUE if it is whole + * @return TRUE if it is UTF-8 */ -int cstring_is_whole(cstring *self); +int cstring_is_utf8(cstring *self); #endif -- 2.27.0