Evo C++ Library v0.5.1
filepath.h
Go to the documentation of this file.
1 // Evo C++ Library
2 /* Copyright 2019 Justin Crowell
3 Distributed under the BSD 2-Clause License -- see included file LICENSE.txt for details.
4 */
6 
7 #pragma once
8 #ifndef INCL_evo_filepath_h
9 #define INCL_evo_filepath_h
10 
11 #include "substring.h"
12 
13 // Namespace: evo
14 namespace evo {
17 
19 
47 class FilePath {
48 private:
49 #if defined(_WIN32)
50  // Windows: Check for reserved filename: CON, PRN, AUX, NUL, COM0 - COM9, LPT0 - LPT9
51  static bool reserved_filename(const char* name, StrSizeT size) {
52  if (size > 4 && name[4] == '.')
53  size = 4;
54  else if (size > 3 && name[3] == '.')
55  size = 3;
56  char buf[3];
57  switch (size) {
58  case 3:
59  buf[0] = ascii_tolower(name[0]);
60  buf[1] = ascii_tolower(name[1]);
61  buf[2] = ascii_tolower(name[2]);
62  if ( (buf[0] == 'c' && buf[1] == 'o' && buf[2] == 'n') ||
63  (buf[0] == 'p' && buf[1] == 'r' && buf[2] == 'n') ||
64  (buf[0] == 'a' && buf[1] == 'u' && buf[2] == 'x') ||
65  (buf[0] == 'n' && buf[1] == 'u' && buf[2] == 'l') )
66  return true;
67  break;
68  case 4:
69  buf[0] = ascii_tolower(name[0]);
70  buf[1] = ascii_tolower(name[1]);
71  buf[2] = ascii_tolower(name[2]);
72  if ( ( (buf[0] == 'c' && buf[1] == 'o' && buf[2] == 'm') ||
73  (buf[0] == 'l' && buf[1] == 'p' && buf[2] == 't') ) &&
74  name[3] >= '1' && name[3] <= '9' )
75  return true;
76  break;
77  default:
78  break;
79  }
80  return false;
81  }
82 
83  // Windows: Path component name cannot end with space, and name other than '.' or '..' cannot end with a '.'
84  static bool valid_filename(const char* name, StrSizeT size, bool strict) {
85  const char lastch = name[size - 1];
86  if (lastch == ' ' || (size > 1 && lastch == '.' && (size > 2 || *name != '.')))
87  return false;
88  return (!strict || !reserved_filename(name, size));
89  }
90 #endif
91 
92 public:
93  static const char PATH_DELIM_WIN32 = '\\';
94  static const char PATH_DELIM_POSIX = '/';
95 
96 #if defined(_WIN32)
97  static const char PATH_DELIM = PATH_DELIM_WIN32;
98 #else
99  static const char PATH_DELIM = PATH_DELIM_POSIX;
100 #endif
101 
113  static bool abs(const SubString& path, bool strict=true) {
114  #if defined(_WIN32)
115  if (path.starts(PATH_DELIM) || path.starts(PATH_DELIM_POSIX))
116  return true;
117  if (strict)
118  return (path.size() >= 3 && path[1] == ':' && (path[2] == PATH_DELIM || path[2] == PATH_DELIM_POSIX));
119  return (path.size() >= 2 && path[1] == ':');
120  #else
121  return path.starts(PATH_DELIM);
122  #endif
123  }
124 
132  static bool hasdrive(const SubString& path) {
133  #if defined(_WIN32)
134  return (path.starts("\\\\", 2) || path.starts("//", 2) || (path.size() >= 2 && path[1] == ':'));
135  #else
136  return false;
137  #endif
138  }
139 
160  static bool validate(const SubString& path, bool strict=true) {
161  const char* p = path.data();
162  const char* end = p + path.size();
163  if (p == end)
164  return false;
165 
166  #if defined(_WIN32)
167  const char* CHARMAP = // invalid path chars: 0 for invalid, 1 for valid
168  "0000000000000000000000000000000011011111110111101111111111010100" // 00-63
169  "1111111111111111111111111111111111111111111111111111111111110111" // 64-127
170  "1111111111111111111111111111111111111111111111111111111111111111" // 128-191
171  "1111111111111111111111111111111111111111111111111111111111111111"; // 191-255
172 
173  const char* name = NULL;
174  if (path.size() >= 2 && p[1] == ':') {
175  if (CHARMAP[(uchar)*p] == '0' || (path.size() > 2 && p[2] != PATH_DELIM))
176  return false;
177  p += 3;
178  name = p;
179  }
180 
181  for (; p < end; ++p) {
182  if (*p == PATH_DELIM) {
183  if (name != NULL && name < p && !valid_filename(name, (StrSizeT)(p - name), strict))
184  return false;
185  name = p + 1;
186  } else if (CHARMAP[(uchar)*p] == '0')
187  return false;
188  }
189  if (name != NULL && name < p && !valid_filename(name, (StrSizeT)(p - name), strict))
190  return false;
191 
192  #else
193  if (strict) {
194  for (; p < end; ++p)
195  if ((uchar)*p < ' ')
196  return false;
197  } else
198  for (; p < end; ++p)
199  if (*p == 0)
200  return false;
201  #endif
202  return true;
203  }
204 
226  static bool validate_filename(const SubString& filename, bool strict=true) {
227  const char* p = filename.data();
228  const char* end = p + filename.size();
229  if (p == end)
230  return false;
231 
232  #if defined(_WIN32)
233  const char* CHARMAP = // invalid filename chars: 0 for invalid, 1 for valid
234  "0000000000000000000000000000000011011111110111101111111111010100" // 00-63
235  "1111111111111111111111111111011111111111111111111111111111110111" // 64-127
236  "1111111111111111111111111111111111111111111111111111111111111111" // 128-191
237  "1111111111111111111111111111111111111111111111111111111111111111"; // 191-255
238 
239  for (; p < end; ++p)
240  if (CHARMAP[(uchar)*p] == '0')
241  return false;
242  if (!valid_filename(filename.data(), filename.size(), strict))
243  return false;
244 
245  #else
246  if (strict) {
247  for (; p < end; ++p)
248  if ((uchar)*p < ' ' || *p == PATH_DELIM)
249  return false;
250  } else
251  for (; p < end; ++p)
252  if (*p == 0 || *p == PATH_DELIM)
253  return false;
254  #endif
255  return true;
256  }
257 
267  static String& normalize(String& outpath, const SubString& path) {
268  const SubString CUR_DIR(".", 1);
269  const SubString PARENT_DIR("..", 2);
270  String output;
271  output.setempty().reserve(path.size());
272 
273  #if defined(_WIN32)
274  bool network_path = false;
275  if (path.starts("\\\\", 2) || path.starts("//", 2)) {
276  output.add(path.data(), 2);
277  network_path = true;
278  } else
279  #endif
280  if (path.starts(PATH_DELIM))
281  output.add(PATH_DELIM); // preserve absolute path
282 
283  SubString input(path), value;
284  while (input.token(value, PATH_DELIM)) {
285  if (value == PARENT_DIR) {
286  StrSizeT i = output.findr(PATH_DELIM);
287  #if defined(_WIN32)
288  if (i == END) {
289  if (network_path)
290  i = 2; // truncate all for UNC, which requires a hostname
291  else if (output.size() >= 2 && output[1] == ':')
292  i = 3; // truncate to drive path
293  else
294  i = 0; // truncate relative path
295  } else if (i == 1) {
296  if (output[0] == PATH_DELIM)
297  i = 0; // truncate all for UNC, which requires a hostname
298  } else if (i == 0) {
299  if (output.size() < 2 || output[1] != PATH_DELIM)
300  ++i; // keep non-UNC absolute path
301  // else truncate all for UNC, which requires a hostname
302  } else if (i == 2 && output[1] == ':')
303  ++i; // keep absolute path with drive
304  #else
305  if (i == END) {
306  i = 0; // truncate relative path
307  } else if (i == 0)
308  ++i; // keep absolute path
309  #endif
310  output.truncate(i);
311  } else if (value.size() > 0 && value != CUR_DIR) {
312  if (output.size() > 0 && !output.ends(PATH_DELIM))
313  output.add(PATH_DELIM);
314  output.add(value);
315  }
316  }
317 
318  #if defined(_WIN32)
319  if (output.size() == 2 && output[1] == ':')
320  output.add(PATH_DELIM);
321  #endif
322 
323  outpath = output;
324  return outpath;
325  }
326 
335  static String& normalize_case(String& outpath, const SubString& path) {
336  String output;
337  #if defined(_WIN32)
338  if (!path.null()) {
339  output.setempty();
340  const char* p = path.data();
341  char* outp = output.advBuffer(path.size());
342  for (const char* end = p + path.size(); p < end; ++p) {
343  if (*p == PATH_DELIM_POSIX)
344  *outp = PATH_DELIM;
345  else
346  *outp = ascii_tolower(*p);
347  ++outp;
348  }
349  }
350  #else
351  output = path;
352  #endif
353  outpath = output;
354  return outpath;
355  }
356 
373  static SubString drive(const SubString& path) {
374  SubString drv;
375  #if defined(_WIN32)
376  if (path.starts("\\\\", 2) || path.starts("//", 2)) {
377  const SubString DELIMS("\\/", 2);
378  StrSizeT i = path.findany(DELIMS.data(), DELIMS.size(), 2);
379  if (i != NONE)
380  i = path.findany(DELIMS.data(), DELIMS.size(), i + 1); // find end of share name
381  if (i == NONE)
382  drv = path;
383  else
384  drv.set(path, 0, i);
385  } else if (path.size() >= 2 && path[1] == ':')
386  drv.set(path, 0, 2);
387  #endif
388  return drv;
389  }
390 
402  static SubString dirpath(const SubString& path) {
403  SubString dir;
404  #if defined(_WIN32)
405  const SubString DELIMS("\\/:", 3);
406  const StrSizeT i = path.findanyr(DELIMS.data(), DELIMS.size());
407  if (i == 0) {
408  dir.set(path, 0, 1);
409  } else if (i == 1) {
410  if (path[i] == ':')
411  dir.set(path, 0, 2);
412  else if (path[0] == path[1])
413  dir.set(path, 0, 2);
414  else
415  dir.set(path, 0, i);
416  } else if (i == 2 && path[1] == ':')
417  dir.set(path, 0, 3);
418  #else
419  const StrSizeT i = path.findr(PATH_DELIM);
420  if (i == 0)
421  dir.set(path, 0, 1);
422  #endif
423  else if (i != NONE)
424  dir.set(path, 0, i);
425  return dir;
426  }
427 
436  static SubString filename(const SubString& path) {
437  SubString name;
438  #if defined(_WIN32)
439  const SubString DELIMS("\\/:", 3);
440  const StrSizeT i = path.findanyr(DELIMS.data(), DELIMS.size());
441  #else
442  const StrSizeT i = path.findr(PATH_DELIM);
443  #endif
444  if (i == NONE)
445  name = path;
446  else
447  name.set(path, i + 1, ALL);
448  return name;
449  }
450 
461  static SubString filename_base(const SubString& path) {
462  SubString name;
463  #if defined(_WIN32)
464  const SubString DELIMS_DOT(".\\/:", 4);
465  const SubString DELIMS("\\/:", 3);
466  const StrSizeT i = path.findanyr(DELIMS_DOT.data(), DELIMS_DOT.size());
467  char ch;
468  if (i == NONE || (i == 0 && path[i] == '.'))
469  name = path;
470  else if (path[i] != '.')
471  name.set(path, i + 1, ALL);
472  else if (i > 0 && ((ch=path[i-1]) == PATH_DELIM || ch == PATH_DELIM_POSIX || ch == ':'))
473  name.set(path, i, ALL);
474  else {
475  const StrSizeT j = path.findanyr(DELIMS.data(), DELIMS.size(), 0, i);
476  name.set2(path, (j == NONE ? 0 : j + 1), i);
477  }
478  #else
479  const SubString DELIMS("./", 2);
480  const StrSizeT i = path.findanyr(DELIMS.data(), DELIMS.size());
481  if (i == NONE || (i == 0 && path[i] == '.'))
482  name = path;
483  else if (path[i] != '.')
484  name.set(path, i + 1, ALL);
485  else if (i > 0 && path[i-1] == PATH_DELIM)
486  name.set(path, i, ALL);
487  else {
488  const StrSizeT j = path.findr(PATH_DELIM, 0, i);
489  name.set2(path, (j == NONE ? 0 : j + 1), i);
490  }
491  #endif
492  return name;
493  }
494 
504  static SubString filename_ext(const SubString& path) {
505  #if defined(_WIN32)
506  const SubString DELIMS(".\\/:", 4);
507  #else
508  const SubString DELIMS("./", 2);
509  #endif
510  SubString name;
511  const StrSizeT i = path.findanyr(DELIMS.data(), DELIMS.size());
512  if (i == 0 && path[0] == '.')
513  name.setempty();
514  else if (i != NONE && path[i] == '.') {
515  #if defined(_WIN32)
516  char ch;
517  if (i == 2 && path[1] == ':')
518  name.setempty();
519  else if (i > 0 && ((ch=path[i-1]) == PATH_DELIM || ch == PATH_DELIM_POSIX))
520  #else
521  if (i > 0 && path[i-1] == PATH_DELIM)
522  #endif
523  name.setempty();
524  else
525  name.set(path, i + 1, ALL);
526  }
527  return name;
528  }
529 
542  template<class T>
543  static T& split_list(T& list, const SubString& path) {
544  SubString remain;
545  if (path.null()) {
546  list.set();
547  } else {
548  list.setempty();
549  #if defined(_WIN32)
550  SubString a, b;
551  a = split_drive(b, path);
552  if (a.empty()) {
553  if (path.starts(PATH_DELIM) || path.starts(PATH_DELIM_POSIX))
554  list.add(SubString(path, 0, 1));
555  } else if (b.starts(PATH_DELIM) || b.starts(PATH_DELIM_POSIX)) {
556  list.add(SubString(path, 0, a.size() + 1));
557  b.triml(1);
558  } else
559  list.add(a);
560  remain = b;
561  const SubString DELIMS("\\/", 2);
562  for (;;) {
563  if (remain.splitat(remain.findany(DELIMS.data(), DELIMS.size()), a, b)) {
564  if (a.size() > 0)
565  list.add(a);
566  remain = b;
567  } else {
568  if (a.size() > 0)
569  list.add(a);
570  break;
571  }
572  }
573  #else
574  SubString val;
575  if (path.starts(PATH_DELIM)) {
576  list.add(SubString("/", 1));
577  remain.set(path, 1, ALL);
578  } else
579  remain = path;
580  while (remain.token(val, PATH_DELIM))
581  list.add(val);
582  #endif
583  }
584  return list;
585  }
586 
597  static SubString split_drive(SubString& outpath, const SubString& path) {
598  SubString drv;
599  #if defined(_WIN32)
600  if (path.starts("\\\\", 2) || path.starts("//", 2)) {
601  const SubString DELIMS("\\/", 2);
602  StrSizeT i = path.findany(DELIMS.data(), DELIMS.size(), 2);
603  if (i != NONE)
604  i = path.findany(DELIMS.data(), DELIMS.size(), i + 1); // find end of share name
605  if (i == NONE) {
606  drv = path;
607  outpath.setempty();
608  } else {
609  drv.set(path, 0, i);
610  outpath.set(path, i, ALL);
611  }
612  } else if (path.size() >= 2 && path[1] == ':') {
613  drv.set(path, 0, 2);
614  outpath.set(path, 2, ALL);
615  } else
616  outpath = path;
617  #else
618  outpath = path;
619  #endif
620  return drv;
621  }
622 
636  static SubString split_dirpath(SubString& outfilename, const SubString& path) {
637  SubString dir;
638  #if defined(_WIN32)
639  const SubString DELIMS("\\/:", 3);
640  const StrSizeT i = path.findanyr(DELIMS.data(), DELIMS.size());
641  if (i == 0) {
642  dir.set(path, 0, 1);
643  outfilename.set(path, 1, ALL);
644  } else if (i == 1) {
645  if (path[i] == ':') {
646  dir.set(path, 0, 2);
647  outfilename.set(path, 2, ALL);
648  } else if (path[0] == path[1]) {
649  dir.set(path, 0, 2);
650  outfilename.set(path, 2, ALL);
651  } else {
652  dir.set(path, 0, i);
653  outfilename.set(path, i + 1, ALL);
654  }
655  } else if (i == 2 && path[1] == ':') {
656  dir.set(path, 0, 3);
657  outfilename.set(path, i + 1, ALL);
658  }
659  #else
660  const StrSizeT i = path.findr(PATH_DELIM);
661  if (i == 0) {
662  dir.set(path, 0, 1);
663  outfilename.set(path, 1, ALL);
664  }
665  #endif
666  else if (i != NONE) {
667  dir.set(path, 0, i);
668  outfilename.set(path, i + 1, ALL);
669  } else if (!path.null())
670  outfilename = path;
671  return dir;
672  }
673 
686  SubString name;
687  const StrSizeT i = filename.findr('.');
688  if (i == NONE || i == 0) {
689  name = filename;
690  ext.set();
691  } else {
692  name.set(filename, 0, i);
693  ext.set(filename, i + 1, ALL);
694  }
695  return name;
696  }
697 
707  drive = FilePath::split_drive(dirpath, path);
708  dirpath = FilePath::split_dirpath(filename, dirpath);
709  }
710 
720  static void split_all(SubString& drive, SubString& dirpath, SubString& basename, SubString& ext, const SubString& path) {
722  drive = FilePath::split_drive(dirpath, path);
723  dirpath = FilePath::split_dirpath(filename, dirpath);
724  basename = FilePath::split_filename(ext, filename);
725  }
726 
739  static String& join(String& basepath, const SubString& addpath) {
740  #if defined(_WIN32)
741  if (addpath.size() >= 2 && addpath[1] == ':')
742  basepath = addpath;
743  else
744  #endif
745  if (addpath.starts(PATH_DELIM)) {
746  basepath = addpath;
747  } else if (addpath.size() > 0) {
748  basepath.addsep(PATH_DELIM);
749  basepath.add(addpath);
750  }
751  return basepath;
752  }
753 
761  template<class T>
762  static String& join_list(String& out, const T& list) {
763  const typename T::Size sz = list.size();
764  if (sz > 0) {
765  const String& first = list[0];
766  out.add(first);
767 
768  typename T::Size i = 1;
769  if (sz > 1 && (first.ends(PATH_DELIM_POSIX) || first.ends(':')))
770  out.add(list[i++]);
771 
772  for (; i < sz; ++i) {
773  #if defined(_WIN32)
774  if (!out.ends(PATH_DELIM_POSIX))
775  #endif
776  out.addsep(PATH_DELIM);
777  out.add(list[i]);
778  }
779  }
780  return out;
781  }
782 
791  static String& join_drive(String& out, const SubString& drive, const SubString& dirpath) {
792  return out.reserve(drive.size() + dirpath.size()).add(drive).add(dirpath);
793  }
794 
803  static String& join_dirpath(String& out, const SubString& dirpath, const SubString& filename) {
804  if (dirpath.empty())
805  out.add(filename);
806  else if (filename.empty())
807  out.add(dirpath);
808  #if defined(_WIN32)
809  else if (dirpath.size() == 2 && dirpath[1] == ':') {
810  out.reserve(dirpath.size() + filename.size());
811  out.add(dirpath);
812  out.add(filename);
813  }
814  #endif
815  else {
816  out.reserve(dirpath.size() + 1 + filename.size());
817  out.add(dirpath);
818  #if defined(_WIN32)
819  if (!out.ends(PATH_DELIM_POSIX))
820  #endif
821  out.addsep(PATH_DELIM);
822  out.add(filename);
823  }
824  return out;
825  }
826 
835  static String& join_filename(String& out, const SubString& basename, const SubString& ext) {
836  if (basename.empty()) {
837  if (ext.size() > 0)
838  out.add('.').add(ext);
839  } else if (ext.empty())
840  out.add(basename);
841  else {
842  out.reserve(basename.size() + 1 + ext.size());
843  out.add(basename);
844  out.addsep('.');
845  out.add(ext);
846  }
847  return out;
848  }
849 
859  static String& join_all(String& out, const SubString& drive, const SubString& dirpath, const SubString& filename) {
860  if (drive.empty() && dirpath.empty())
861  out.add(filename);
862  #if defined(_WIN32)
863  else if (dirpath.empty() && drive.ends(':')) {
864  out.reserve(drive.size() + filename.size());
865  out.add(drive);
866  out.add(filename);
867  }
868  #endif
869  else {
870  out.reserve(drive.size() + dirpath.size() + 1 + filename.size());
871  out.add(drive);
872  out.add(dirpath);
873  #if defined(_WIN32)
874  if (!out.ends(PATH_DELIM_POSIX))
875  #endif
876  out.addsep(PATH_DELIM);
877  out.add(filename);
878  }
879  return out;
880  }
881 
892  static String& join_all(String& out, const SubString& drive, const SubString& dirpath, const SubString& basename, const SubString& ext) {
893  if (drive.empty() && dirpath.empty()) {
894  out.reserve(basename.size() + 1 + ext.size());
895  out.add(basename);
896  if (ext.size() > 0) {
897  out.addsep('.');
898  out.add(ext);
899  }
900  #if defined(_WIN32)
901  } else if (dirpath.empty() && drive.ends(':')) {
902  out.reserve(drive.size() + basename.size() + 1 + ext.size());
903  out.add(drive);
904  out.add(basename);
905  if (ext.size() > 0) {
906  out.addsep('.');
907  out.add(ext);
908  }
909  #endif
910  } else {
911  out.reserve(drive.size() + dirpath.size() + 2 + basename.size() + ext.size());
912  out.add(drive);
913  out.add(dirpath);
914  #if defined(_WIN32)
915  if (!out.ends(PATH_DELIM_POSIX))
916  #endif
917  out.addsep(PATH_DELIM);
918  out.add(basename);
919  if (ext.size() > 0) {
920  out.addsep('.');
921  out.add(ext);
922  }
923  }
924  return out;
925  }
926 };
927 
929 
930 }
931 #endif
bool splitat(Key index, T1 &left, T2 &right) const
Split into left/right sublists at index.
bool empty() const
Get whether empty.
char ascii_tolower(char ch)
Convert ASCII character to lowercase.
Definition: str.h:119
static String & join_list(String &out, const T &list)
Join list of path components.
Definition: filepath.h:762
Size size() const
Get size.
Definition: list.h:759
SubString & triml(Size size)
Trim left (beginning) items.
Definition: substring.h:1307
Evo SubString container.
bool token(StringT &value, char delim)
Extract next token from string.
Definition: substring.h:383
static bool validate_filename(const SubString &filename, bool strict=true)
Validate whether filename is valid.
Definition: filepath.h:226
static String & join(String &basepath, const SubString &addpath)
Join two paths together.
Definition: filepath.h:739
static bool hasdrive(const SubString &path)
Check whether given path has a drive component.
Definition: filepath.h:132
T first(T val1, T val2)
Definition: alg.h:85
static void split_all(SubString &drive, SubString &dirpath, SubString &basename, SubString &ext, const SubString &path)
Split input path into drive, dirpath, file basename, and file extension components.
Definition: filepath.h:720
static SubString filename_base(const SubString &path)
Get base filename from path, which is the filename without the extension.
Definition: filepath.h:461
Key findany(const char *chars, Size count, Key start=0, Key end=END) const
Find first occurrence of any given characters with forward search.
Definition: substring.h:828
static SubString dirpath(const SubString &path)
Get directory path from path.
Definition: filepath.h:402
static SubString split_filename(SubString &ext, const SubString &filename)
Split filename into base name and extension.
Definition: filepath.h:685
Size size() const
Get size.
static T & split_list(T &list, const SubString &path)
Split path into list of components.
Definition: filepath.h:543
bool starts(const char *str) const
Check if starts with given terminated string.
Definition: substring.h:658
static const char PATH_DELIM_WIN32
Path delimiter char for Windows systems.
Definition: filepath.h:93
uint32 StrSizeT
Default Evo string size type.
Definition: sys.h:734
static bool abs(const SubString &path, bool strict=true)
Check whether path is an absolute path.
Definition: filepath.h:113
String container.
Definition: string.h:674
static const char PATH_DELIM_POSIX
Path delimiter char for Linux/Unix systems.
Definition: filepath.h:94
static SubString filename_ext(const SubString &path)
Get file extension from filename in path.
Definition: filepath.h:504
static String & join_filename(String &out, const SubString &basename, const SubString &ext)
Join file base name and extension components and write to output string.
Definition: filepath.h:835
static const EndT END
Special integer value for indicating end of items or no item.
Definition: type.h:1846
static const EndT ALL
Special integer value for indicating all items or all remaining items.
Definition: type.h:1839
static String & join_dirpath(String &out, const SubString &dirpath, const SubString &filename)
Join dirpath and filename and write to output string.
Definition: filepath.h:803
String & setempty()
Set as empty but not null.
Definition: string.h:982
static String & join_all(String &out, const SubString &drive, const SubString &dirpath, const SubString &filename)
Join drive, dirpath, and filename components and write to output string.
Definition: filepath.h:859
static const char PATH_DELIM
Path delimiter char for current OS.
Definition: filepath.h:99
static SubString split_drive(SubString &outpath, const SubString &path)
Get Windows drive and remaining path from path.
Definition: filepath.h:597
bool ends(char ch) const
Check if this ends with given character.
Definition: string.h:1694
Evo C++ Library namespace.
Definition: alg.h:11
static const EndT NONE
Special integer value for indicating no item or unknown item.
Definition: type.h:1832
SubString & set2(const StringBase &data, Key index1, Key index2)
Set as reference to subset of source data using start/end positions.
Definition: substring.h:1299
static SubString filename(const SubString &path)
Get filename from path.
Definition: filepath.h:436
String & addsep(char delim=',')
Append separator/delimiter if needed (modifier).
Definition: string.h:2799
static String & normalize_case(String &outpath, const SubString &path)
Normalize path case.
Definition: filepath.h:335
SubString & setempty()
Set as empty but not null.
Definition: substring.h:1303
static String & normalize(String &outpath, const SubString &path)
Normalize path and remove redundant components.
Definition: filepath.h:267
String & add(char ch)
Append character (modifier).
Definition: string.h:2741
static String & join_all(String &out, const SubString &drive, const SubString &dirpath, const SubString &basename, const SubString &ext)
Join drive, dirpath, and filename components and write to output string.
Definition: filepath.h:892
File and directory path helpers.
Definition: filepath.h:47
T * advBuffer(Size size)
Advanced: Resize and get buffer pointer (modifier).
Definition: list.h:2728
bool null() const
Get whether null.
static String & join_drive(String &out, const SubString &drive, const SubString &dirpath)
Join drive and dirpath and write to output string.
Definition: filepath.h:791
String & truncate(Size size=0)
Truncate to given size.
Definition: string.h:4987
Key findr(char ch) const
Find last occurrence of character with reverse search.
Definition: string.h:1879
static SubString drive(const SubString &path)
Get Windows drive from path.
Definition: filepath.h:373
static void split_all(SubString &drive, SubString &dirpath, SubString &filename, const SubString &path)
Split input path into drive, dirpath, and filename components.
Definition: filepath.h:706
Key findr(char ch) const
Find last occurrence of character with reverse search.
Definition: substring.h:747
static SubString split_dirpath(SubString &outfilename, const SubString &path)
Get directory path from path.
Definition: filepath.h:636
static bool validate(const SubString &path, bool strict=true)
Validate whether path is valid.
Definition: filepath.h:160
SubString & set(const char *data)
Set as reference to terminated string.
Definition: substring.h:353
Reference and access existing string data.
Definition: substring.h:229
bool ends(const char *str) const
Check if ends with given terminated string.
Definition: substring.h:671
Key findanyr(const char *chars, Size count, Key start=0, Key end=END) const
Find last occurrence of any given characters with reverse search.
Definition: substring.h:853
const char * data() const
Get data pointer.
String & reserve(Size size, bool prefer_realloc=false)
Reserve capacity for additional items (modifier).
Definition: string.h:5027