18#if __has_include(<linux/fs.h>)
26#define IS_DIRSEP(c) ((c) == ASE_DIRSEP || (c) == ASE_DIRSEP2)
27#define IS_SEARCHPATH_SEPARATOR(c) ((c) == ASE_SEARCHPATH_SEPARATOR || (c) == ';')
28#define UPPER_ALPHA(L) (L >= 'A' && L <= 'Z')
29#define LOWER_ALPHA(L) (L >= 'a' && L <= 'z')
30#define ISALPHA(L) (LOWER_ALPHA (L) || UPPER_ALPHA (L))
35 String pw_name, pw_passwd, pw_gecos, pw_dir, pw_shell;
46[[maybe_unused]]
static bool
47startswith_dosdrive (
const char *p)
53startswith_dosdrive (
const String &s)
63 return dir.
empty() ?
"." : dir;
74 if (base2 > base || !base)
79 if (startswith_dosdrive (path))
95 char *
const cpath = ::realpath (path.
c_str(), NULL);
98 const String result = cpath;
111 if (path.
empty() || !IS_DIRSEP (path.
back()))
121 while (s.
size() > 1 && IS_DIRSEP (s.
back()))
139 return abspath (join (incwd, path),
"");
142 return join (pcwd, path);
143 return join (
cwd(), path);
151 if (IS_DIRSEP (path[0]))
153 if (startswith_dosdrive (path) && IS_DIRSEP (path[2]))
162 const char *c = path.
data();
165 ((c[0] >=
'A' && c[0] <=
'Z') ||
166 (c[0] >=
'a' && c[0] <=
'z')) &&
170 if (!IS_DIRSEP (c[0]))
173 while (IS_DIRSEP (c[0]) || (c[1] ==
'.' && IS_DIRSEP (c[1])))
174 c += 1 + (c[1] ==
'.');
184 if (path ==
"." || path ==
"..")
186 if (l >= 1 && IS_DIRSEP (path[l-1]))
188 if (l >= 2 && IS_DIRSEP (path[l-2]) && path[l-1] ==
'.')
190 if (l >= 3 && IS_DIRSEP (path[l-3]) && path[l-2] ==
'.' && path[l-1] ==
'.')
200 if (
check (target,
"d"))
202 if (
check (target,
"e"))
212 const int saved_errno =
errno;
213 if (
check (target,
"d"))
228 *relpath = child.
substr (dir.
size(), String::npos);
246 unsigned long ficlone = 0;
253 const int srcfd =
open (src.
c_str(), O_RDONLY | O_NOCTTY);
256 const int dstfd =
open (dest.
c_str(), O_WRONLY | O_CREAT | O_EXCL, 0644);
257 bool cloned = dstfd >= 0 ? 0 ==
ioctl (dstfd, ficlone, srcfd) :
false;
261 cloned &= 0 ==
close (dstfd);
289 if (username.
empty())
292 const char *homedir =
getenv (
"HOME");
293 if (homedir &&
isabs (homedir))
296 CxxPasswd pwn (username);
304 const char *var =
getenv (
"XDG_DATA_HOME");
305 if (var &&
isabs (var))
314 const char *var =
getenv (
"XDG_CONFIG_HOME");
315 if (var &&
isabs (var))
324 const char *var =
getenv (
"XDG_CACHE_HOME");
325 if (var &&
isabs (var))
334 const char *var =
getenv (
"XDG_RUNTIME_DIR");
335 if (var &&
isabs (var))
345 StringStringM defs = {
346 {
"XDG_DESKTOP_DIR",
"$HOME/Desktop" },
347 {
"XDG_DOWNLOAD_DIR",
"$HOME/Downloads" },
348 {
"XDG_TEMPLATES_DIR",
"$HOME/Templates" },
349 {
"XDG_PUBLICSHARE_DIR",
"$HOME/Public" },
350 {
"XDG_DOCUMENTS_DIR",
"$HOME/Documents" },
351 {
"XDG_MUSIC_DIR",
"$HOME/Music" },
352 {
"XDG_PICTURES_DIR",
"$HOME/Pictures" },
353 {
"XDG_VIDEOS_DIR",
"$HOME/Videos" },
359 IniFile ff { udirs,
data };
361 for (
String key : ff.attributes (global))
363 const String v = ff.value_as_string (global +
"." + key);
364 if (!key.empty() && !v.empty())
369 for (
auto &it : defs)
371 it.second = uhome + it.second.substr (5);
373 for (
const auto &pair : defs)
374 printerr (
"XDG: %s = %s\n", pair.first, pair.second);
379xdg_dir (
const String &xdgdir)
386 if (udir ==
"CONFIG")
390 if (udir ==
"RUNTIME")
392 static const StringStringM defs = xdg_user_dirs();
393 const auto it = defs.find (
"XDG_" +
string_toupper (xdgdir) +
"_DIR");
394 if (it == defs.end())
395 warning (
"%s: unknown XDG dir: %s", __func__, xdgdir);
396 return it != defs.end() ? it->second :
"";
403 const char *var =
getenv (
"XDG_CONFIG_DIRS");
414 const char *var =
getenv (
"XDG_DATA_DIRS");
418 return "/usr/local/share:/usr/share";
422access_config_names (
const String *newval)
429 if (cfg_names.
empty())
444 return access_config_names (NULL);
451 access_config_names (&names);
455split_extension (
const std::string &filepath,
const bool lastdot)
457 const char *
const fullpath = filepath.
c_str();
458 const char *
const slash1 =
strrchr (fullpath,
'/'), *
const slash2 =
strrchr (fullpath,
'\\');
459 const char *
const slash = slash2 > slash1 ? slash2 : slash1;
460 const char *
const dot = lastdot ?
strrchr (slash ? slash : fullpath,
'.') :
strchr (slash ? slash : fullpath,
'.');
474 const size_t dir =
std::min (dir1, dir2);
476 if (dir != String::npos)
477 username = path.
substr (1, dir - 1);
479 username = path.
substr (1);
481 if (userhome.
empty())
483 return join (userhome, dir == String::npos ?
"" : path.
substr (dir));
487skip_root (
const String &path)
491 if (path.
size() >= 3 &&
492 ( (path[0] >=
'A' && path[0] <=
'Z') || (path[0] >=
'a' && path[0] <=
'z') ) &&
493 path[1] ==
':' && IS_DIRSEP (path[2]))
497 if (path.
size() >= 3 && IS_DIRSEP (path[0]) && IS_DIRSEP (path[1]) && !IS_DIRSEP (path[2]))
499 const char *p = &path[3];
500 while (*p && !IS_DIRSEP (*p))
503 return path.
substr (++p - &path[0]);
506 const char *p = &path[0];
507 while (*p && IS_DIRSEP (*p))
509 return path.
substr (p - &path[0]);
518 return ec ? 0 : size;
522errno_check_file (
const char *file_name,
const char *mode)
524 uint access_mask = 0, nac = 0;
526 if (strchr (mode,
'e'))
527 nac++, access_mask |= F_OK;
528 if (strchr (mode,
'r'))
529 nac++, access_mask |= R_OK;
530 if (strchr (mode,
'w'))
531 nac++, access_mask |= W_OK;
532 bool check_exec =
strchr (mode,
'x') != NULL;
534 nac++, access_mask |= X_OK;
539 if (nac && access (file_name, access_mask) < 0)
542 const bool check_size0 =
strchr (mode,
'z') != NULL;
543 const bool check_size1 =
strchr (mode,
's') != NULL;
544 const bool check_file =
strchr (mode,
'f') != NULL;
545 const bool check_dir =
strchr (mode,
'd') != NULL;
546 const bool check_link =
strchr (mode,
'L') != NULL ||
strchr (mode,
'h') != NULL;
547 const bool check_char =
strchr (mode,
'c') != NULL;
548 const bool check_block =
strchr (mode,
'b') != NULL;
549 const bool check_pipe =
strchr (mode,
'p') != NULL;
550 const bool check_socket =
strchr (mode,
'S') != NULL;
552 if (check_exec || check_size0 || check_size1 || check_file || check_dir ||
553 check_link || check_char || check_block || check_pipe || check_socket)
559 if (lstat (file_name, &st) < 0)
562 else if (stat (file_name, &st) < 0)
566 printerr (
"file-check(\"%s\",\"%s\"): %u %s%s%s%s%s%s%s\n",
569 S_ISREG (st.st_mode) ?
"f" :
"",
570 S_ISDIR (st.st_mode) ?
"d" :
"",
571 S_ISLNK (st.st_mode) ?
"L" :
"",
572 S_ISCHR (st.st_mode) ?
"c" :
"",
573 S_ISBLK (st.st_mode) ?
"b" :
"",
574 S_ISFIFO (st.st_mode) ?
"p" :
"",
575 S_ISSOCK (st.st_mode) ?
"S" :
"");
577 if (check_size0 && st.st_size != 0)
579 if (check_size1 && st.st_size == 0)
581 if (S_ISDIR (st.st_mode) && (check_file || check_link || check_char || check_block || check_pipe))
583 if (check_file && !S_ISREG (st.st_mode))
585 if (check_dir && !S_ISDIR (st.st_mode))
587 if (check_link && !S_ISLNK (st.st_mode))
589 if (check_char && !S_ISCHR (st.st_mode))
591 if (check_block && !S_ISBLK (st.st_mode))
593 if (check_pipe && !S_ISFIFO (st.st_mode))
595 if (check_socket && !S_ISSOCK (st.st_mode))
597 if (check_exec && !(st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
628 errno = err < 0 ? -err : 0;
644 return file1.
size() == file2.
size();
645 struct stat st1 = { 0, }, st2 = { 0, };
646 int err1 = 0, err2 = 0;
655 return (st1.st_dev == st2.st_dev &&
656 st1.st_ino == st2.st_ino &&
657 st1.st_rdev == st2.st_rdev);
666 char *dir = get_current_dir_name();
669 const String result = dir;
678 char *buf = (
char*)
malloc (size);
681 const char *
const dir =
getcwd (buf, size);
684 const String result = dir;
697searchpath_split (
const String &searchpath)
701 for (i = 0; i < searchpath.
size(); i++)
702 if (IS_SEARCHPATH_SEPARATOR (searchpath[i]))
717 const bool dirsearch = element.
size() > 0 && IS_DIRSEP (element[element.
size() - 1]);
718 const String needle = dirsearch && element.
size() > 1 ? element.
substr (0, element.
size() - 1) : element;
719 size_t pos = searchpath.
find (needle);
720 while (pos != String::npos)
722 size_t end = pos + needle.
size();
723 if (pos == 0 || IS_SEARCHPATH_SEPARATOR (searchpath[pos - 1]))
725 if (dirsearch && IS_DIRSEP (searchpath[end]))
727 if (searchpath[end] == 0 || IS_SEARCHPATH_SEPARATOR (searchpath[end]))
730 pos = searchpath.
find (needle, end);
740 return check (file, mode) ? file :
"";
741 StringS sv = searchpath_split (searchpath);
742 for (
size_t i = 0; i < sv.
size(); i++)
743 if (
check (join (sv[i], file), mode))
744 return join (sv[i], file);
753 for (
const auto &file : searchpath_split (searchpath))
754 if (
check (file, mode))
765 if (head.
back() == joiner)
767 if (tail[0] == joiner)
768 return head + tail.
substr (1);
771 if (tail[0] == joiner)
773 return head + joiner + tail;
781 for (
const auto &e : searchpath_split (searchpath))
782 for (
const auto &p : searchpath_split (postfixes))
788searchpath_join (
const StringS &string_vector)
800 const char *vpath =
getenv (
"VPATH");
814 glob_t iglob = { 0, };
815 const int ir = ::glob (pathpattern.
c_str(), GLOB_TILDE | GLOB_MARK,
nullptr, &iglob);
818 for (
size_t i = 0; i < iglob.gl_pathc; i++) {
819 const char *
const p = iglob.gl_pathv[i];
821 if (IS_DIRSEP (p[l-1]))
833 glob_t iglob = { 0, };
834 const int ir = ::glob (pathpattern.
c_str(), GLOB_TILDE,
nullptr, &iglob);
837 for (
size_t i = 0; i < iglob.gl_pathc; i++)
846 glob_t iglob = { 0, };
847 const int ir = ::glob (basedir.
c_str(), GLOB_TILDE_CHECK | GLOB_NOSORT | GLOB_MARK | GLOB_ONLYDIR,
nullptr, &iglob);
850 for (
size_t i = 0; i < iglob.gl_pathc; i++)
855 rglob (subdir +
"*", pattern, matches);
856 glob_t jglob = { 0, };
857 const int jr = ::glob ((subdir + pattern).c_str(), GLOB_NOSORT,
nullptr, &jglob);
860 for (
size_t j = 0; j < jglob.gl_pathc; j++)
873 char *rpath = ::realpath (pathnames[i].c_str(),
nullptr);
875 pathnames[j++] = rpath;
880 strings_version_sort (&pathnames);
890 if (dirs[i].empty() || dirs[i] ==
".")
891 dirs.erase (dirs.begin() + i--);
892 else if (dirs[i] ==
"..")
894 dirs.erase (dirs.begin() + i--);
896 dirs.erase (dirs.begin() + i--);
902file_memread (FILE *stream,
size_t *lengthp, ssize_t maxlength)
904 size_t sz = maxlength <= 0 || maxlength > 1048576 ? 1048576 : maxlength;
905 char *buffer = (
char*) malloc (sz);
908 char *current = buffer;
910 while (!feof (stream))
912 ssize_t bytes =
fread (current, 1, sz - (current - buffer), stream);
913 if (bytes <= 0 && ferror (stream) && errno != EAGAIN)
919 if (maxlength >= 0 && current - buffer >= maxlength)
921 current = buffer + maxlength;
924 if (current == buffer + sz)
926 bytes = current - buffer;
928 char *newstring = (
char*) realloc (buffer, sz);
935 current = buffer + bytes;
938 int savederr =
errno;
939 *lengthp = current - buffer;
950memread (
const String &filename,
size_t *lengthp, ssize_t maxlength)
952 FILE *file =
fopen (filename.c_str(),
"r");
958 char *contents = file_memread (file, lengthp, maxlength);
959 int savederr =
errno;
961 contents = (
char*) realloc (contents, *lengthp);
967memfree (
char *memread_mem)
974memwrite (
const String &filename,
size_t len,
const uint8 *bytes,
bool append,
int perms)
976 FILE *file =
fopen (filename.c_str(), append ?
"a" :
"w");
979 if (perms != -1 && fchmod (fileno (file), perms) != 0) {
980 const int err =
errno;
982 unlink (filename.c_str());
986 const size_t nbytes =
fwrite (bytes, 1, len, file);
987 bool success =
ferror (file) == 0 && nbytes == len;
988 success =
fclose (file) == 0 && success;
990 const int err =
errno;
991 unlink (filename.c_str());
999stringread (
const String &filename, ssize_t maxlength)
1004 char *
data = memread (filename, &length, maxlength);
1007 s =
String (data, length);
1016stringwrite (
const String &filename,
const String &data,
bool mkdirs_,
int perms)
1019 mkdirs (dirname (filename), 0750);
1020 return memwrite (filename,
data.size(), (
const uint8*)
data.data(),
false, perms);
1024stringappend (
const String &filename,
const String &data,
bool mkdirs_,
int perms)
1027 mkdirs (dirname (filename), 0750);
1028 return memwrite (filename,
data.size(), (
const uint8*)
data.data(),
true, perms);
1039 pw_uid (-1), pw_gid (-1)
1041 const int strbuf_size = 5 * 1024;
1042 char strbuf[strbuf_size + 256];
1043 struct passwd pwnambuf, *p = NULL;
1044 if (username.
empty())
1055 while ((ret != 0 || p == NULL) && errno == EINTR);
1064 ret =
getpwnam_r (username.
c_str(), &pwnambuf, strbuf, strbuf_size, &p);
1065 while ((ret != 0 || p == NULL) && errno == EINTR);
1071 pw_name = p->pw_name;
1072 pw_passwd = p->pw_passwd;
1075 pw_gecos = p->pw_gecos;
1077 pw_shell = p->pw_shell;
1095 s = Path::join (
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"a",
"b",
"c",
"d",
"e",
"f");
1096#if ASE_DIRSEP == '/'
1097 p =
"0/1/2/3/4/5/6/7/8/9/a/b/c/d/e/f";
1099 p =
"0\\1\\2\\3\\4\\5\\6\\7\\8\\9\\a\\b\\c\\d\\e\\f";
1103 s = Path::searchpath_join (
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"a",
"b",
"c",
"d",
"e",
"f");
1104#if ASE_SEARCHPATH_SEPARATOR == ';'
1105 p =
"0;1;2;3;4;5;6;7;8;9;a;b;c;d;e;f";
1107 p =
"0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f";
1111 bool b = Path::isabs (p);
1112 TCMP (b, ==,
false);
1114#if ASE_DIRSEP == '/'
1115 s = Path::join (dirsep, s);
1117 s = Path::join (
"C:\\", s);
1119 b = Path::isabs (s);
1121 s = Path::skip_root (s);
1125 TCMP (Path::basename (
"simple"), ==,
"simple");
1126 TCMP (Path::basename (
"skipthis" +
String (dirsep) +
"file"), ==,
"file");
1127 TCMP (Path::basename (
String (dirsep) +
"skipthis" +
String (dirsep) +
"file"), ==,
"file");
1128 TCMP (Path::dirname (
"file"), ==,
".");
1129 TCMP (Path::dirname (
"dir" +
String (dirsep)), ==,
"dir");
1130 TCMP (Path::dirname (
"dir" +
String (dirsep) +
"file"), ==,
"dir");
1131 TCMP (Path::cwd(), !=,
"");
1132 TCMP (Path::check (Path::join (Path::cwd(),
"..", Path::basename (Path::cwd())),
"rd"), ==,
true);
1133 TASSERT (Path::isroot (
"/") ==
true);
1134 TASSERT (Path::isroot (
"//") ==
true);
1135 TASSERT (Path::isroot (
"//////////") ==
true);
1136 TASSERT (Path::isroot (
"/.") ==
true);
1137 TASSERT (Path::isroot (
"./") ==
false);
1138 TASSERT (Path::isroot (
".////") ==
false);
1139 TASSERT (Path::isroot (
"/./") ==
true);
1140 TASSERT (Path::isroot (
"/./././././") ==
true);
1141 TASSERT (Path::isroot (
"/././././.") ==
true);
1142 TASSERT (Path::isroot (
"///././././//.///") ==
true);
1143 TASSERT (Path::isroot (
"///././././//.///.") ==
true);
1144 TASSERT (Path::isroot (
"abc") ==
false);
1145 TASSERT (Path::isroot (
"C:/",
true) ==
true);
1146 TASSERT (Path::isroot (
"C:/.",
true) ==
true);
1147 TASSERT (Path::isroot (
"8:/",
true) ==
false);
1148 TASSERT (Path::isroot (
"8:/..",
true) ==
false);
1149 TASSERT (Path::isroot (
"C:/D",
true) ==
false);
1150 TCMP (Path::isdirname (
""), ==,
false);
1151 TCMP (Path::isdirname (
"foo"), ==,
false);
1152 TCMP (Path::isdirname (
"foo/"), ==,
true);
1153 TCMP (Path::isdirname (
"/foo"), ==,
false);
1154 TCMP (Path::isdirname (
"foo/."), ==,
true);
1155 TCMP (Path::isdirname (
"foo/.."), ==,
true);
1156 TCMP (Path::isdirname (
"foo/..."), ==,
false);
1157 TCMP (Path::isdirname (
"foo/..../"), ==,
true);
1158 TCMP (Path::isdirname (
"/."), ==,
true);
1159 TCMP (Path::isdirname (
"/.."), ==,
true);
1160 TCMP (Path::isdirname (
"/"), ==,
true);
1161 TCMP (Path::isdirname (
"."), ==,
true);
1162 TCMP (Path::isdirname (
".."), ==,
true);
1163 TCMP (Path::expand_tilde (
""), ==,
"");
1164 const char *env_home =
getenv (
"HOME");
1166 TCMP (Path::expand_tilde (
"~"), ==, env_home);
1167 const char *env_logname =
getenv (
"LOGNAME");
1168 if (env_home && env_logname)
1169 TCMP (Path::expand_tilde (
"~" +
String (env_logname)), ==, env_home);
1170 TCMP (Path::expand_tilde (
"~:unknown/"), ==,
"~:unknown/");
1171 TCMP (Path::searchpath_multiply (
"/:/tmp",
"foo:bar"), ==,
"/foo:/bar:/tmp/foo:/tmp/bar");
1172 const String abs_basedir = Path::abspath (anklang_runpath (RPath::PREFIXDIR));
1173 TCMP (Path::searchpath_list (
"/:" + abs_basedir,
"e"), ==,
StringS ({
"/", abs_basedir }));
1174 TCMP (Path::searchpath_contains (
"/foo/:/bar",
"/"), ==,
false);
1175 TCMP (Path::searchpath_contains (
"/foo/:/bar",
"/foo"), ==,
false);
1176 TCMP (Path::searchpath_contains (
"/foo/:/bar",
"/foo/"), ==,
true);
1177 TCMP (Path::searchpath_contains (
"/foo/:/bar",
"/bar"), ==,
true);
1178 TCMP (Path::searchpath_contains (
"/foo/:/bar",
"/bar/"), ==,
true);
1179 TCMP (Path::skip_root (
"foo/"), ==,
"foo/");
1180 TCMP (Path::skip_root (
"/foo/"), ==,
"foo/");
1181 TCMP (Path::skip_root (
"///foo/"), ==,
"foo/");
1183 TCMP (Path::check (
"/tmp/empty",
"z"), ==,
true);
1184 TCMP (Path::check (
"/tmp/empty",
"s"), ==,
false);
1186 TCMP (Path::check (
"/etc/os-release",
"s"), ==,
true);
1187 TCMP (Path::check (
"/etc/os-release",
"z"), ==,
false);
1189 TCMP (Path::skip_root (
"//foo/."), ==,
".");
1190 TCMP (Path::skip_root (
"C:/foo/."), ==,
"foo/.");
1191 TCMP (Path::skip_root (
"\\\\foo\\."), ==,
".");
1192 TCMP (Path::skip_root (
"C:\\foo\\."), ==,
"foo\\.");
1194 TCMP (Path::skip_root (
"//foo/."), ==,
"foo/.");
1195 TCMP (Path::skip_root (
"C:/foo/."), ==,
"C:/foo/.");
T has_relative_path(T... args)
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
#define TEST_INTEGRITY(FUNC)
Register func as an integrity test.
T lexically_normal(T... args)
String user_home(const String &username)
Get a user's home directory, uses $HOME if no username is given.
String cwd()
Return the current working directoy, including symlinks used in $PWD if available.
bool searchpath_contains(const String &searchpath, const String &element)
Check if searchpath contains element, a trailing slash searches for directories.
String config_dirs()
Get the $XDG_CONFIG_DIRS directory list, see: https://specifications.freedesktop.org/basedir-spec/lat...
void unique_realpaths(StringS &pathnames)
Convert all pathnames via realpath() and eliminate duplicates.
String config_names()
Get config names as set with config_names(), if unset defaults to program_alias().
String basename(const String &path)
Strips all directory components from path and returns the resulting file name.
String config_home()
Get the $XDG_CONFIG_HOME directory, see: https://specifications.freedesktop.org/basedir-spec/latest.
String searchpath_multiply(const String &searchpath, const String &postfixes)
Yield a new searchpath by combining each element of searchpath with each element of postfixes.
bool mkdirs(const String &dirpath, uint mode)
Create the directories in dirpath with mode, check errno on false returns.
bool check(const String &file, const String &mode)
String expand_tilde(const String &path)
Expand a "~/" or "~user/" path which refers to user home directories.
bool equals(const String &file1, const String &file2)
String dir_terminate(const String &path)
Append trailing slash to path, unless it's present.
String simplify_abspath(const std::string &abspath_expression)
Remove extra slashes, './' and '../' from abspath_expression.
bool isdirname(const String &path)
Return wether path is pointing to a directory component.
String strip_slashes(const String &path)
Strip trailing directory terminators.
String data_home()
Get the $XDG_DATA_HOME directory, see: https://specifications.freedesktop.org/basedir-spec/latest.
String cache_home()
Get the $XDG_CACHE_HOME directory, see: https://specifications.freedesktop.org/basedir-spec/latest.
String join_with(const String &head, char joiner, const String &tail)
Construct head + joiner + tail avoiding duplicates of joiner.
String runtime_dir()
Get the $XDG_RUNTIME_DIR directory, see: https://specifications.freedesktop.org/basedir-spec/latest.
String searchpath_find(const String &searchpath, const String &file, const String &mode)
Find the first file in searchpath which matches mode (see check()).
String abspath(const String &path, const String &incwd)
void rmrf(const String &dir)
Recursively delete directory tree.
size_t file_size(const String &path)
Retrieve the on-disk size in bytes of path.
bool copy_file(const String &src, const String &dest)
Copy a file to a new non-existing location, sets errno and returns false on error.
bool isabs(const String &path)
Return wether path is an absolute pathname.
bool isroot(const String &path, bool dos_drives)
Return wether path is an absolute pathname which identifies the root directory.
String data_dirs()
Get the $XDG_DATA_DIRS directory list, see: https://specifications.freedesktop.org/basedir-spec/lates...
bool dircontains(const String &dirpath, const String &descendant, String *relpath)
Check if descendant belongs to the directory hierarchy under dirpath.
void rglob(const String &basedir, const String &pattern, StringS &matches)
Recursively match files with glob pattern under basedir.
StringS searchpath_list(const String &searchpath, const String &mode)
Find all searchpath entries matching mode (see check()).
String normalize(const String &path)
Convert path to normal form.
The Anklang C++ API namespace.
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
String string_join(const String &junctor, const StringS &strvec)
StringS string_split(const String &string, const String &splitter, size_t maxn)
uint8_t uint8
An 8-bit unsigned integer.
String string_toupper(const String &str)
Convert all string characters into Unicode upper case characters.
String program_cwd()
The current working directory during startup.
String program_alias()
Retrieve the program name as used for logging or debug messages.
std::string String
Convenience alias for std::string.
uint32_t uint
Provide 'uint' as convenience type.
bool string_startswith(const String &string, const String &fragment)
Returns whether string starts with fragment.
#define ASE_DOS_PATHS
Equals 1 on _WIN32 and _WIN64 and 0 on Unix.
#define ASE_DIRSEP
Platform directory separator character, '/' on Unix-like systems, a '\' on _WIN32.
#define ASE_DIRSEP2
Secondary directory separator character, '/' on Unix-like systems.
#define ASE_SEARCHPATH_SEPARATOR
Platform searchpath separator, ':' on Unix-like systems, ';' on _WIN32.
#define TASSERT(cond)
Unconditional test assertion, enters breakpoint if not fullfilled.
#define TCMP(a, cmp, b)
Compare a and b according to operator cmp, verbose on failiure.