size_t cleanup_dirname()

in mysql_sys/mf_pack.cc [80:178]


size_t cleanup_dirname(char *to, const char *from) {
  char *pos;
  const char *from_ptr;
  char *start;
  char parent[5], /* for "FN_PARENTDIR" */
      buff[FN_REFLEN + 1], *end_parentdir;
#ifdef _WIN32
  CHARSET_INFO *fs = fs_character_set();
#endif
  DBUG_TRACE;
  DBUG_PRINT("enter", ("from: '%s'", from));

  start = buff;
  from_ptr = from;
#ifdef FN_DEVCHAR
  {
    const char *dev_pos = strrchr(from_ptr, FN_DEVCHAR);
    if (dev_pos != nullptr) { /* Skip device part */
      size_t length = (dev_pos - from_ptr) + 1;
      start = my_stpnmov(buff, from_ptr, length);
      from_ptr += length;
    }
  }
#endif

  parent[0] = FN_LIBCHAR;
  size_t length = my_stpcpy(parent + 1, FN_PARENTDIR) - parent;
  const char *end = start + FN_REFLEN;
  for (pos = start; pos < end && ((*pos = *from_ptr++) != 0); pos++) {
#ifdef _WIN32
    uint l;
    if (use_mb(fs) && (l = my_ismbchar(fs, from_ptr - 1, from_ptr + 2))) {
      for (l--; l; *++pos = *from_ptr++, l--)
        ;
      start = pos + 1; /* Don't look inside multi-byte char */
      continue;
    }
#endif
    if (*pos == '/') *pos = FN_LIBCHAR;
    if (*pos == FN_LIBCHAR) {
      if ((size_t)(pos - start) > length &&
          memcmp(pos - length, parent, length) ==
              0) { /* If .../../; skip prev */
        pos -= length;
        if (pos != start) { /* not /../ */
          pos--;
          if (*pos == FN_HOMELIB && (pos == start || pos[-1] == FN_LIBCHAR)) {
            if (!home_dir) {
              pos += length + 1; /* Don't unpack ~/.. */
              continue;
            }
            pos = my_stpcpy(buff, home_dir) - 1; /* Unpacks ~/.. */
            if (*pos == FN_LIBCHAR) pos--;       /* home ended with '/' */
          }
          if (*pos == FN_CURLIB && (pos == start || pos[-1] == FN_LIBCHAR)) {
            if (my_getwd(curr_dir, FN_REFLEN, MYF(0))) {
              pos += length + 1; /* Don't unpack ./.. */
              continue;
            }
            pos = my_stpcpy(buff, curr_dir) - 1; /* Unpacks ./.. */
            if (*pos == FN_LIBCHAR) pos--;       /* home ended with '/' */
          }
          end_parentdir = pos;
          while (pos >= start && *pos != FN_LIBCHAR) /* remove prev dir */
            pos--;
          if (pos[1] == FN_HOMELIB ||
              (pos >= start &&
               memcmp(pos, parent, length) == 0)) { /* Don't remove ~user/ */
            pos = my_stpcpy(end_parentdir + 1, parent);
            *pos = FN_LIBCHAR;
            continue;
          }
        }
      } else if ((size_t)(pos - start) == length - 1 &&
                 !memcmp(start, parent + 1, length - 1))
        start = pos; /* Starts with "../" */
      else if (pos - start > 0 && pos[-1] == FN_LIBCHAR) {
#ifdef FN_NETWORK_DRIVES
        if (pos - start != 1)
#endif
          pos--; /* Remove dupplicate '/' */
      } else if (pos - start > 1 && pos[-1] == FN_CURLIB &&
                 pos[-2] == FN_LIBCHAR)
        pos -= 2; /* Skip /./ */
      else if (pos > buff + 1 && pos[-1] == FN_HOMELIB &&
               pos[-2] == FN_LIBCHAR) { /* Found ..../~/  */
        buff[0] = FN_HOMELIB;
        buff[1] = FN_LIBCHAR;
        start = buff;
        pos = buff + 1;
      }
    }
  }

  buff[FN_REFLEN - 1] = '\0';
  (void)my_stpcpy(to, buff);
  DBUG_PRINT("exit", ("to: '%s'", to));
  return (size_t)(pos - buff);
} /* cleanup_dirname */