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.