1
0

Remove glib dependency

This commit is contained in:
2026-06-17 12:46:59 +02:00
parent 1d8a03a7b9
commit 93cacaa6fe
5 changed files with 78 additions and 168 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ find_package(CURL)
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
find_package(SQLite3) find_package(SQLite3)
find_package(Boost REQUIRED COMPONENTS filesystem process) find_package(Boost REQUIRED COMPONENTS filesystem process)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET glib-2.0 gio-2.0 bzip2) pkg_check_modules(deps REQUIRED IMPORTED_TARGET bzip2)
add_library(backend) add_library(backend)
target_sources(backend target_sources(backend
+3 -49
View File
@@ -7,13 +7,11 @@ module;
#include "config.h" #include "config.h"
#include <filesystem> #include <filesystem>
#include <gio/gio.h>
#include <cstdint> #include <cstdint>
#include <stdlib.h> #include <stdlib.h>
#include <iostream> #include <iostream>
#include <zlib.h> #include <zlib.h>
#include <curl/curl.h> #include <curl/curl.h>
#include <glib/gstdio.h>
#include <sqlite3.h> #include <sqlite3.h>
#include <forward_list> #include <forward_list>
#include <array> #include <array>
@@ -33,14 +31,10 @@ namespace katja
{ {
static std::forward_list<std::unique_ptr<Pkgtools>> repos; static std::forward_list<std::unique_ptr<Pkgtools>> repos;
void pk_backend_initialize(GKeyFile *conf) void pk_backend_initialize()
{ {
char **groups;
int ret; int ret;
std::uint8_t i; std::uint8_t i;
std::size_t groups_len;
GKeyFile *key_conf;
GError *err = nullptr;
sqlite3 *db; sqlite3 *db;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
@@ -53,16 +47,6 @@ void pk_backend_initialize(GKeyFile *conf)
std::cerr << path.native() << ": " << sqlite3_errmsg(db) << std::endl; std::cerr << path.native() << ": " << sqlite3_errmsg(db) << std::endl;
} }
/* Read the configuration file */
key_conf = g_key_file_new();
path = std::filesystem::path(SYSCONFDIR) / "PackageKit" / "Slackware.conf";
g_key_file_load_from_file(key_conf, path.c_str(), G_KEY_FILE_NONE, &err);
if (err)
{
std::cerr << path.native() << ": " << err->message << std::endl;
g_error_free(err);
}
std::chrono::time_point<std::chrono::file_clock> file_info = std::filesystem::last_write_time(path); std::chrono::time_point<std::chrono::file_clock> file_info = std::filesystem::last_write_time(path);
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(file_info.time_since_epoch()); auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(file_info.time_since_epoch());
@@ -87,26 +71,6 @@ void pk_backend_initialize(GKeyFile *conf)
std::cerr << "Failed to update database: " << path.native() << std::endl; std::cerr << "Failed to update database: " << path.native() << std::endl;
} }
sqlite3_close_v2(db); sqlite3_close_v2(db);
/* Initialize an object for each well-formed repository */
groups = g_key_file_get_groups(key_conf, &groups_len);
for (i = 0; i < groups_len; i++)
{
char *blacklist = g_key_file_get_string(key_conf, groups[i], "Blacklist", nullptr);
char *mirror = g_key_file_get_string(key_conf, groups[i], "Mirror", nullptr);
if (g_key_file_has_key(key_conf, groups[i], "Priority", nullptr))
{
auto repo = std::make_unique<Slackpkg>(groups[i], mirror, i + 1, blacklist,
g_key_file_get_string_list(key_conf, groups[i], "Priority", nullptr, nullptr));
repos.emplace_front(std::move(repo));
}
g_free(mirror);
g_free(blacklist);
}
g_free(groups);
g_key_file_free(key_conf);
} }
void pk_backend_destroy() void pk_backend_destroy()
@@ -230,7 +194,6 @@ void pk_backend_get_details(JobData *job_data, char **package_ids)
std::size_t i; std::size_t i;
std::regex expr; std::regex expr;
std::smatch match_info; std::smatch match_info;
GError *err = nullptr;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
std::string desc; std::string desc;
@@ -368,7 +331,7 @@ out:
void pk_backend_install_packages(JobData *job_data, const std::vector<std::string> package_ids) void pk_backend_install_packages(JobData *job_data, const std::vector<std::string> package_ids)
{ {
unsigned i; unsigned i;
gdouble percent_step; double percent_step;
std::list<std::string> install_list; std::list<std::string> install_list;
sqlite3_stmt *pkglist_stmt = nullptr, *collection_stmt = nullptr; sqlite3_stmt *pkglist_stmt = nullptr, *collection_stmt = nullptr;
@@ -478,7 +441,6 @@ void pk_backend_remove_packages(JobData* job_data, const std::vector<std::string
{ {
unsigned i; unsigned i;
double percent_step; double percent_step;
GError *err = nullptr;
/* Add percent_step percents per removed package */ /* Add percent_step percents per removed package */
percent_step = 100.0 / package_ids.size(); percent_step = 100.0 / package_ids.size();
@@ -491,15 +453,7 @@ void pk_backend_remove_packages(JobData* job_data, const std::vector<std::string
std::string cmd_line = "/sbin/removepkg " + tokens[0]; std::string cmd_line = "/sbin/removepkg " + tokens[0];
/* Pkgtools return always 0 */ /* Pkgtools return always 0 */
g_spawn_command_line_sync(cmd_line.c_str(), nullptr, nullptr, nullptr, &err); system(cmd_line.c_str());
if (err)
{
std::cerr << err->message << std::endl;
g_error_free(err);
return;
}
job_data->set_percentage(100); job_data->set_percentage(100);
} }
+1 -2
View File
@@ -9,7 +9,6 @@ module;
#include <curl/curl.h> #include <curl/curl.h>
#include <sqlite3.h> #include <sqlite3.h>
#include <cstdint> #include <cstdint>
#include <glib-object.h>
#include <string> #include <string>
#include <regex> #include <regex>
#include <forward_list> #include <forward_list>
@@ -153,7 +152,7 @@ public:
/ reinterpret_cast<const char*>(sqlite3_column_text(statement, 0)); / reinterpret_cast<const char*>(sqlite3_column_text(statement, 0));
std::string cmd_line = "/sbin/upgradepkg --install-new " + pkg_filename.native(); std::string cmd_line = "/sbin/upgradepkg --install-new " + pkg_filename.native();
g_spawn_command_line_sync(cmd_line.c_str(), nullptr, nullptr, nullptr, nullptr); system(cmd_line.c_str());
} }
sqlite3_finalize(statement); sqlite3_finalize(statement);
} }
+72 -114
View File
@@ -11,13 +11,14 @@ module;
#include <cstdint> #include <cstdint>
#include <cstddef> #include <cstddef>
#include <string.h> #include <string.h>
#include <gio/gio.h>
#include <curl/curl.h> #include <curl/curl.h>
#include <string> #include <string>
#include <regex> #include <regex>
#include <vector> #include <vector>
#include <forward_list> #include <forward_list>
#include <filesystem> #include <filesystem>
#include <boost/algorithm/string.hpp>
#include <fstream>
export module katja.slackpkg; export module katja.slackpkg;
@@ -72,18 +73,16 @@ public:
CURL *curl = nullptr; CURL *curl = nullptr;
cache_entry source_dest; cache_entry source_dest;
std::forward_list<cache_entry> file_list; std::forward_list<cache_entry> file_list;
GFile *tmp_dir, *repo_tmp_dir;
/* Create the temporary directory for the repository */ /* Create the temporary directory for the repository */
tmp_dir = g_file_new_for_path(tmpl.native().c_str()); std::filesystem::path tmp_dir = tmpl / this->name;
repo_tmp_dir = g_file_get_child(tmp_dir, this->name.c_str()); std::filesystem::create_directories(tmp_dir);
g_file_make_directory(repo_tmp_dir, nullptr, nullptr);
/* Download PACKAGES.TXT. These files are most important, break if some of them couldn't be found */ /* Download PACKAGES.TXT. These files are most important, break if some of them couldn't be found */
for (const std::string& current_priority : this->priority) for (const std::string& current_priority : this->priority)
{ {
source_dest.first = this->mirror + current_priority + "/PACKAGES.TXT"; source_dest.first = this->mirror + current_priority + "/PACKAGES.TXT";
source_dest.second = tmpl / this->name / "PACKAGES.TXT"; source_dest.second = tmp_dir / "PACKAGES.TXT";
if (get_file(&curl, source_dest.first.c_str(), std::nullopt) == CURLE_OK) if (get_file(&curl, source_dest.first.c_str(), std::nullopt) == CURLE_OK)
{ {
@@ -104,9 +103,6 @@ public:
} }
} }
out: out:
g_object_unref(repo_tmp_dir);
g_object_unref(tmp_dir);
if (curl) if (curl)
{ {
curl_easy_cleanup(curl); curl_easy_cleanup(curl);
@@ -127,23 +123,19 @@ public:
void generate_cache(JobData *job_data, const std::filesystem::path& tmpl) noexcept void generate_cache(JobData *job_data, const std::filesystem::path& tmpl) noexcept
{ {
std::vector<std::string> pkg_tokens; std::vector<std::string> pkg_tokens;
char *query = nullptr, *filename = nullptr, *location = nullptr, *summary = nullptr, *line; char *query = nullptr;
unsigned pkg_compressed = 0, pkg_uncompressed = 0; unsigned pkg_compressed = 0, pkg_uncompressed = 0;
std::uint8_t pkg_name_len; std::uint8_t pkg_name_len;
GString *desc; std::string desc, line, location;
GFile *list_file;
GFileInputStream *fin = nullptr;
GDataInputStream *data_in = nullptr;
sqlite3_stmt *insert_statement = nullptr, *update_statement = nullptr, *insert_default_statement = nullptr; sqlite3_stmt *insert_statement = nullptr, *update_statement = nullptr, *insert_default_statement = nullptr;
sqlite3_stmt *statement; sqlite3_stmt *statement;
std::optional<std::string> filename, summary;
/* Check if the temporary directory for this repository exists, then the file metadata have to be generated */ /* Check if the temporary directory for this repository exists, then the file metadata have to be generated */
std::filesystem::path packages_txt = tmpl / this->name / "PACKAGES.TXT"; std::filesystem::path packages_txt = tmpl / this->name / "PACKAGES.TXT";
list_file = g_file_new_for_path(packages_txt.native().c_str()); std::ifstream data_in(packages_txt);
fin = g_file_read(list_file, nullptr, nullptr);
g_object_unref(list_file);
if (!fin) if (!data_in)
{ {
goto out; goto out;
} }
@@ -201,64 +193,63 @@ public:
goto out; goto out;
} }
data_in = g_data_input_stream_new(G_INPUT_STREAM(fin)); desc = "";
desc = g_string_new("");
sqlite3_exec(job_data->db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr); sqlite3_exec(job_data->db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr);
while ((line = g_data_input_stream_read_line(data_in, nullptr, nullptr, nullptr))) while (std::getline(data_in, line))
{ {
if (!strncmp(line, "PACKAGE NAME: ", 15)) if (boost::starts_with(line, "PACKAGE NAME: "))
{ {
filename = g_strdup(line + 15); filename = line.substr(15);
if (this->is_blacklisted(filename)) if (this->is_blacklisted(filename.value()))
{ {
g_free(filename); filename.reset();
filename = nullptr;
} }
} }
else if (filename && !strncmp(line, "PACKAGE LOCATION: ", 19)) else if (filename.has_value() && boost::starts_with(line, "PACKAGE LOCATION: "))
{ {
location = g_strdup(line + 21); /* Exclude ./ at the path beginning */ location = line.substr(21); /* Exclude ./ at the path beginning */
} }
else if (filename && !strncmp(line, "PACKAGE SIZE (compressed): ", 28)) else if (filename.has_value() && boost::starts_with(line, "PACKAGE SIZE (compressed): "))
{ {
/* Remove the unit (kilobytes) */ /* Remove the unit (kilobytes) */
pkg_compressed = atoi(g_strndup(line + 28, strlen(line + 28) - 2)) * 1024; std::from_chars(line.c_str() + 28, line.c_str() + line.size() - 2, pkg_compressed);
pkg_compressed *= 1024;
} }
else if (filename && !strncmp(line, "PACKAGE SIZE (uncompressed): ", 30)) else if (filename.has_value() && boost::starts_with(line, "PACKAGE SIZE (uncompressed): "))
{ {
/* Remove the unit (kilobytes) */ /* Remove the unit (kilobytes) */
pkg_uncompressed = atoi(g_strndup(line + 30, strlen(line + 30) - 2)) * 1024; std::from_chars(line.c_str() + 30, line.c_str() + line.size() - 2, pkg_uncompressed);
pkg_uncompressed *= 1024;
} }
else if (filename && !g_strcmp0(line, "PACKAGE DESCRIPTION:")) else if (filename.has_value() && boost::starts_with(line, "PACKAGE DESCRIPTION:"))
{ {
g_free(line); std::getline(data_in, line);
line = g_data_input_stream_read_line(data_in, nullptr, nullptr, nullptr); /* Short description */
summary = g_strstr_len(line, -1, "("); auto summary_position = line.find_first_of('(');
if (summary) /* Else summary = nullptr */ if (summary_position != std::string::npos) /* Else summary = nullptr */
{ {
summary = g_strndup(summary + 1, strlen(summary) - 2); /* Without ( ) */ summary = line.substr(summary_position + 1, line.size() - summary_position - 2); /* Without ( ) */
} }
pkg_tokens = split_package_name(filename).value(); pkg_tokens = split_package_name(filename.value()).value();
pkg_name_len = pkg_tokens[0].size(); /* Description begins with pkg_name: */ pkg_name_len = pkg_tokens[0].size(); /* Description begins with pkg_name: */
} }
else if (filename && !strncmp(line, pkg_tokens[0].c_str(), pkg_name_len)) else if (filename.has_value() && boost::starts_with(line, pkg_tokens[0]))
{ {
g_string_append(desc, line + pkg_name_len + 1); desc += line.substr(pkg_name_len + 1);
} }
else if (filename && !g_strcmp0(line, "")) else if (filename.has_value() && line == "")
{ {
if (g_strcmp0(location, "patches/packages")) /* Insert a new package */ if (location != "patches/packages") /* Insert a new package */
{ {
/* Get the package group based on its location */ /* Get the package group based on its location */
const char *cat = g_strrstr(location, "/"); auto category_position = location.find_last_of('/');
if (cat) if (category_position != std::string::npos)
{ {
++cat;
statement = insert_statement; statement = insert_statement;
sqlite3_bind_text(insert_statement, 12, cat, -1, SQLITE_TRANSIENT); sqlite3_bind_text(insert_statement, 12,
location.c_str() + category_position + 1, -1, SQLITE_TRANSIENT);
} }
else else
{ {
@@ -274,9 +265,10 @@ public:
sqlite3_bind_text(statement, 2, pkg_tokens[1].c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 2, pkg_tokens[1].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, pkg_tokens[2].c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 3, pkg_tokens[2].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 4, pkg_tokens[4].c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 4, pkg_tokens[4].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 5, location, -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 5, location.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 6, summary, -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 6,
sqlite3_bind_text(statement, 7, desc->str, -1, SQLITE_TRANSIENT); summary.has_value() ? summary.value().c_str() : nullptr, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 7, desc.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_int(statement, 8, pkg_compressed); sqlite3_bind_int(statement, 8, pkg_compressed);
sqlite3_bind_int(statement, 9, pkg_uncompressed); sqlite3_bind_int(statement, 9, pkg_uncompressed);
sqlite3_bind_text(statement, 10, pkg_tokens[0].c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 10, pkg_tokens[0].c_str(), -1, SQLITE_TRANSIENT);
@@ -286,20 +278,15 @@ public:
sqlite3_reset(statement); sqlite3_reset(statement);
/* Reset for the next package */ /* Reset for the next package */
g_free(filename); summary.reset();
g_free(location); filename.reset();
g_free(summary); location = "";
filename = location = summary = nullptr; desc = "";
g_string_assign(desc, "");
pkg_compressed = pkg_uncompressed = 0; pkg_compressed = pkg_uncompressed = 0;
} }
g_free(line);
} }
sqlite3_exec(job_data->db, "END TRANSACTION", nullptr, nullptr, nullptr); sqlite3_exec(job_data->db, "END TRANSACTION", nullptr, nullptr, nullptr);
g_string_free(desc, true);
g_object_unref(data_in);
/* Parse MANIFEST.bz2 */ /* Parse MANIFEST.bz2 */
for (const std::string& current_priority : this->priority) for (const std::string& current_priority : this->priority)
{ {
@@ -310,11 +297,6 @@ public:
sqlite3_free(query); sqlite3_free(query);
sqlite3_finalize(insert_default_statement); sqlite3_finalize(insert_default_statement);
sqlite3_finalize(insert_statement); sqlite3_finalize(insert_statement);
if (fin)
{
g_object_unref(fin);
}
} }
private: private:
@@ -335,13 +317,13 @@ private:
FILE *manifest; FILE *manifest;
int err, read_len; int err, read_len;
unsigned pos; unsigned pos;
char buf[max_buf_size], *pkg_filename, *rest = nullptr, *start; char buf[max_buf_size];
std::optional<std::string> rest;
std::filesystem::path path; std::filesystem::path path;
char *full_name = nullptr; std::vector<std::string> lines;
char **line, **lines;
BZFILE *manifest_bz2; BZFILE *manifest_bz2;
GRegex *pkg_expr = nullptr, *file_expr = nullptr; std::regex pkg_expr, file_expr;
GMatchInfo *match_info; std::smatch match_info;
sqlite3_stmt *statement = nullptr; sqlite3_stmt *statement = nullptr;
path = tmpl / this->name / filename; path = tmpl / this->name / filename;
@@ -357,21 +339,13 @@ private:
} }
/* Prepare regular expressions */ /* Prepare regular expressions */
pkg_expr = g_regex_new("^\\|\\|[[:blank:]]+Package:[[:blank:]]+.+\\/(.+)\\.(t[blxg]z$)?", pkg_expr = std::regex("^\\|\\|[[:blank:]]+Package:[[:blank:]]+.+\\/(.+)\\.(t[blxg]z$)?",
static_cast<GRegexCompileFlags> (G_REGEX_OPTIMIZE | G_REGEX_DUPNAMES), std::regex::optimize);
static_cast<GRegexMatchFlags> (0), file_expr = std::regex("^[-bcdlps][-r][-w][-xsS][-r][-w][-xsS][-r][-w]"
nullptr);
file_expr = g_regex_new("^[-bcdlps][-r][-w][-xsS][-r][-w][-xsS][-r][-w]"
"[-xtT][[:space:]][^[:space:]]+[[:space:]]+" "[-xtT][[:space:]][^[:space:]]+[[:space:]]+"
"[[:digit:]]+[[:space:]][[:digit:]-]+[[:space:]]" "[[:digit:]]+[[:space:]][[:digit:]-]+[[:space:]]"
"[[:digit:]:]+[[:space:]](?!install\\/|\\.)(.*)", "[[:digit:]:]+[[:space:]](?!install\\/|\\.)(.*)",
static_cast<GRegexCompileFlags> (G_REGEX_OPTIMIZE | G_REGEX_DUPNAMES), std::regex::optimize);
static_cast<GRegexMatchFlags> (0),
nullptr);
if (!(file_expr) || !(pkg_expr))
{
goto out;
}
/* Prepare SQL statements */ /* Prepare SQL statements */
if (sqlite3_prepare_v2(job_data->db, if (sqlite3_prepare_v2(job_data->db,
@@ -393,66 +367,50 @@ private:
buf[read_len] = '\0'; buf[read_len] = '\0';
/* Split the read text into lines */ /* Split the read text into lines */
lines = g_strsplit(buf, "\n", 0); boost::split(lines, buf, boost::is_any_of("\n"));
if (rest) if (rest.has_value())
{ /* Add to the first line rest characters from the previous read operation */ { /* Add to the first line rest characters from the previous read operation */
start = lines[0]; lines[0] = rest.value() + lines[0];
lines[0] = g_strconcat(rest, lines[0], nullptr); rest.reset();
g_free(start);
g_free(rest);
} }
if (err != BZ_STREAM_END) /* The last line can be incomplete */ if (err != BZ_STREAM_END) /* The last line can be incomplete */
{ {
pos = g_strv_length(lines) - 1; pos = lines.size() - 1;
rest = lines[pos]; rest = lines[pos];
lines[pos] = nullptr;
} }
for (line = lines; *line; line++) for (const auto& line : lines)
{ {
if (g_regex_match(pkg_expr, *line, static_cast<GRegexMatchFlags> (0), &match_info)) std::optional<std::string> full_name;
if (std::regex_match(std::cbegin(line), std::cend(line), match_info, pkg_expr))
{ {
if (g_match_info_get_match_count(match_info) > 2) if (match_info.size() > 2)
{ /* If the extension matches */ { /* If the extension matches */
g_free(full_name); full_name = match_info.str(1);
full_name = g_match_info_fetch(match_info, 1);
} }
else else
{ {
full_name = nullptr; full_name.reset();
} }
} }
g_match_info_free(match_info); if (full_name.has_value()
&& std::regex_match(std::cbegin(line), std::cend(line), match_info, file_expr))
match_info = nullptr;
if (full_name && g_regex_match(file_expr, *line, static_cast<GRegexMatchFlags> (0), &match_info))
{ {
pkg_filename = g_match_info_fetch(match_info, 1); std::string pkg_filename = match_info.str(1);
sqlite3_bind_text(statement, 1, full_name, -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 1, full_name.value().c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, pkg_filename, -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 2, pkg_filename.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_step(statement); sqlite3_step(statement);
sqlite3_clear_bindings(statement); sqlite3_clear_bindings(statement);
sqlite3_reset(statement); sqlite3_reset(statement);
g_free(pkg_filename);
} }
g_match_info_free(match_info);
} }
g_strfreev(lines);
} }
sqlite3_exec(job_data->db, "END TRANSACTION", nullptr, nullptr, nullptr); sqlite3_exec(job_data->db, "END TRANSACTION", nullptr, nullptr, nullptr);
g_free(full_name);
BZ2_bzReadClose(&err, manifest_bz2); BZ2_bzReadClose(&err, manifest_bz2);
out: out:
sqlite3_finalize(statement); sqlite3_finalize(statement);
if (file_expr)
{
g_regex_unref(file_expr);
}
if (pkg_expr)
{
g_regex_unref(pkg_expr);
}
fclose(manifest); fclose(manifest);
} }
}; };
+1 -2
View File
@@ -8,7 +8,6 @@ module;
#include <cstdint> #include <cstdint>
#include <sqlite3.h> #include <sqlite3.h>
#include <string.h> #include <string.h>
#include <gio/gio.h>
#include <curl/curl.h> #include <curl/curl.h>
#include <sqlite3.h> #include <sqlite3.h>
#include <string> #include <string>
@@ -82,7 +81,7 @@ CURLcode get_file(CURL **curl, const char *source_url, const std::optional<std::
{ {
FILE *fout = nullptr; FILE *fout = nullptr;
CURLcode ret; CURLcode ret;
glong response_code; long response_code;
std::string dest_dir_name; std::string dest_dir_name;
if ((*curl == nullptr) && (!(*curl = curl_easy_init()))) if ((*curl == nullptr) && (!(*curl = curl_easy_init())))