void split_fullpath(const char *fullpath, char *dirname, char *basename, const size_t buf_len) {
    if (buf_len == 0) {
        return;
    }
    char *p = strrchr(fullpath, separator);
    if (p) {
        p += 1;
        if (dirname) {
            size_t dirlen = min(buf_len - 1, (size_t) (p - fullpath));
            strncpy(dirname, fullpath, dirlen);
            dirname[dirlen] = '\0';
        }
        if (basename) {
            strncpy(basename, p, buf_len - 1);
            basename[buf_len - 1] = '\0';
        }
    }
    else {
        if (dirname) {
            dirname[0] = '\0';
        }
        if (basename) {
            strncpy(basename, fullpath, buf_len - 1);
            basename[buf_len - 1] = '\0';
        }
    }
    if (basename) {
        p = strrchr(basename, '.');
        if (p) {
            *p = '\0';
        }
    }
}
void split_fullpath(const char *fullpath, char *dirname, char *basename, const size_t buf_len) {
    if (buf_len == 0) {
        return;
    }
    char *p = strrchr(fullpath, separator);
    if (p) {
        p += 1;
        if (dirname) {
            size_t dirlen = min(buf_len - 1, (size_t) (p - fullpath));
            strncpy(dirname, fullpath, dirlen);
            dirname[dirlen] = '\0';
        }
        if (basename) {
            strncpy(basename, p, buf_len - 1);
            basename[buf_len - 1] = '\0';
        }
    }
    else {
        if (dirname) {
            dirname[0] = '\0';
        }
        if (basename) {
            strncpy(basename, fullpath, buf_len - 1);
            basename[buf_len - 1] = '\0';
        }
    }
    if (basename) {
        p = strrchr(basename, '.');
        if (p) {
            *p = '\0';
        }
    }
}