Freeciv21
Develop your civilization from humble roots to a global empire
mpdb.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 #include "mpdb.h"
15 
16 // utility
17 #include "capability.h"
18 #include "fcintl.h"
19 #include "registry.h"
20 #include "registry_ini.h"
21 
22 #include <QDir>
23 #include <QFileInfo>
24 
25 #include <sqlite3.h>
26 
27 #define MPDB_CAPSTR "+mpdb"
28 
29 #define MPDB_FORMAT_VERSION "1"
30 
31 static sqlite3 *main_handle = nullptr;
32 static sqlite3 *scenario_handle = nullptr;
33 
34 static int mpdb_query(sqlite3 *handle, const char *query);
35 
39 void load_install_info_list(const char *filename)
40 {
41  struct section_file *file;
42  const char *caps;
43 
44  file = secfile_load(filename, false);
45 
46  if (file == nullptr) {
47  /* This happens in first run - or actually all runs until something is
48  * installed. Previous run has not saved database. */
49  log_debug("No install info file");
50 
51  return;
52  }
53 
54  caps = secfile_lookup_str(file, "info.options");
55 
56  if (caps == nullptr) {
57  qCritical("MPDB %s missing capability information", filename);
58  secfile_destroy(file);
59  return;
60  }
61 
62  if (!has_capabilities(MPDB_CAPSTR, caps)) {
63  qCritical("Incompatible mpdb file %s:", filename);
64  qCritical(" file options: %s", caps);
65  qCritical(" supported options: %s", MPDB_CAPSTR);
66 
67  secfile_destroy(file);
68 
69  return;
70  }
71 
72  if (file != nullptr) {
73  bool all_read = false;
74  int i;
75 
76  for (i = 0; !all_read; i++) {
77  const char *str;
78  char buf[80];
79 
80  fc_snprintf(buf, sizeof(buf), "modpacks.mp%d", i);
81 
82  str = secfile_lookup_str_default(file, nullptr, "%s.name", buf);
83 
84  if (str != nullptr) {
85  const char *type;
86  const char *ver;
87 
88  type = secfile_lookup_str(file, "%s.type", buf);
89  ver = secfile_lookup_str(file, "%s.version", buf);
90 
91  auto mptype = modpack_type_by_name(type, fc_strcasecmp);
92  fc_assert_action(modpack_type_is_valid(mptype), break);
93  mpdb_update_modpack(str, mptype, ver);
94  } else {
95  all_read = true;
96  }
97  }
98 
99  secfile_destroy(file);
100  }
101 }
102 
106 static int mpdb_query(sqlite3 *handle, const char *query)
107 {
108  int ret;
109  sqlite3_stmt *stmt;
110 
111  ret = sqlite3_prepare_v2(handle, query, -1, &stmt, nullptr);
112 
113  if (ret == SQLITE_OK) {
114  ret = sqlite3_step(stmt);
115  }
116 
117  if (ret != SQLITE_DONE && ret != SQLITE_ROW) {
118  qCritical("Query \"%s\" failed. (%d)", query, ret);
119  }
120 
121  if (int errcode = sqlite3_finalize(stmt); errcode != SQLITE_OK) {
122  qCritical("Finalizing query \"%s\" returned error. (%d)", query,
123  errcode);
124  }
125 
126  return ret;
127 }
128 
132 void create_mpdb(const char *filename, bool scenario_db)
133 {
134  sqlite3 **handle;
135  int ret;
136 
137  // Create parent directory
138  if (QFileInfo info(filename); !QDir().mkpath(info.dir().path())) {
139  qCritical(_("Can't create directory \"%s\" for modpack database."),
140  qUtf8Printable(info.dir().path()));
141  return;
142  }
143 
144  if (scenario_db) {
145  handle = &scenario_handle;
146  } else {
147  handle = &main_handle;
148  }
149 
150  ret = sqlite3_open_v2(filename, handle,
151  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr);
152 
153  if (ret == SQLITE_OK) {
154  ret = mpdb_query(
155  *handle,
156  "create table meta (version INTEGER default " MPDB_FORMAT_VERSION
157  ");");
158  }
159 
160  if (ret == SQLITE_DONE) {
161  ret = mpdb_query(*handle,
162  "create table modpacks (name VARCHAR(60) NOT null, "
163  "type VARCHAR(32), version VARCHAR(32) NOT null);");
164  }
165 
166  if (ret == SQLITE_DONE) {
167  log_debug("Created %s", filename);
168  } else {
169  qCritical(_("Creating \"%s\" failed: %s"), filename,
170  sqlite3_errstr(ret));
171  }
172 }
173 
177 void open_mpdb(const char *filename, bool scenario_db)
178 {
179  sqlite3 **handle;
180  int ret;
181 
182  if (scenario_db) {
183  handle = &scenario_handle;
184  } else {
185  handle = &main_handle;
186  }
187 
188  ret = sqlite3_open_v2(filename, handle, SQLITE_OPEN_READWRITE, nullptr);
189 
190  if (ret != SQLITE_OK) {
191  qCritical(_("Opening \"%s\" failed: %s"), filename, sqlite3_errstr(ret));
192  }
193 }
194 
199 {
200  sqlite3_close(main_handle);
201  main_handle = nullptr;
202  sqlite3_close(scenario_handle);
203  scenario_handle = nullptr;
204 }
205 
209 bool mpdb_update_modpack(const char *name, enum modpack_type type,
210  const char *version)
211 {
212  sqlite3 **handle;
213  int ret;
214  char qbuf[2048];
215 
216  if (type == MPT_SCENARIO) {
217  handle = &scenario_handle;
218  } else {
219  handle = &main_handle;
220  }
221 
222  sqlite3_snprintf(sizeof(qbuf), qbuf,
223  "select * from modpacks where name is '%q';", name);
224  ret = mpdb_query(*handle, qbuf);
225 
226  if (ret == SQLITE_ROW) {
227  sqlite3_snprintf(sizeof(qbuf), qbuf,
228  "update modpacks set type = '%q', version = '%q' where "
229  "name is '%q';",
230  modpack_type_name(type), version, name);
231  ret = mpdb_query(*handle, qbuf);
232  } else {
233  // Completely new modpack
234  sqlite3_snprintf(sizeof(qbuf), qbuf,
235  "insert into modpacks values ('%q', '%q', '%q');", name,
236  modpack_type_name(type), version);
237  ret = mpdb_query(*handle, qbuf);
238  }
239 
240  if (ret != SQLITE_DONE) {
241  qCritical(_("Failed to insert modpack '%s' information"), name);
242  }
243 
244  return ret != SQLITE_DONE;
245 }
246 
251 const char *mpdb_installed_version(const char *name, enum modpack_type type)
252 {
253  sqlite3 **handle;
254  int ret;
255  char qbuf[2048];
256  const char *version = nullptr;
257  sqlite3_stmt *stmt;
258 
259  if (type == MPT_SCENARIO) {
260  handle = &scenario_handle;
261  } else {
262  handle = &main_handle;
263  }
264 
265  sqlite3_snprintf(sizeof(qbuf), qbuf,
266  "select * from modpacks where name is '%q';", name);
267  ret = sqlite3_prepare_v2(*handle, qbuf, -1, &stmt, nullptr);
268 
269  if (ret == SQLITE_OK) {
270  ret = sqlite3_step(stmt);
271  }
272 
273  if (ret == SQLITE_ROW) {
274  version = qstrdup((const char *) sqlite3_column_text(stmt, 2));
275  }
276 
277  if (ret != SQLITE_DONE && ret != SQLITE_ROW) {
278  qCritical("Query to get installed version for \"%s\" failed. (%d)", name,
279  ret);
280  }
281 
282  if (int errcode = sqlite3_finalize(stmt); errcode != SQLITE_OK) {
283  qCritical(
284  "Finalizing query to get installed version for \"%s\" failed. (%d)",
285  name, errcode);
286  }
287 
288  return version;
289 }
bool has_capabilities(const char *us, const char *them)
This routine returns true if all the mandatory capabilities in us appear in them.
Definition: capability.cpp:80
#define _(String)
Definition: fcintl.h:50
const char * name
Definition: inputfile.cpp:118
#define fc_assert_action(condition, action)
Definition: log.h:104
#define log_debug(message,...)
Definition: log.h:65
#define MPDB_FORMAT_VERSION
Definition: mpdb.cpp:29
void close_mpdbs()
Close open databases.
Definition: mpdb.cpp:198
static sqlite3 * main_handle
Definition: mpdb.cpp:31
static sqlite3 * scenario_handle
Definition: mpdb.cpp:32
#define MPDB_CAPSTR
Definition: mpdb.cpp:27
void load_install_info_list(const char *filename)
Construct install info list from file.
Definition: mpdb.cpp:39
const char * mpdb_installed_version(const char *name, enum modpack_type type)
Return version of modpack.
Definition: mpdb.cpp:251
void create_mpdb(const char *filename, bool scenario_db)
Create modpack database.
Definition: mpdb.cpp:132
void open_mpdb(const char *filename, bool scenario_db)
Open existing database.
Definition: mpdb.cpp:177
bool mpdb_update_modpack(const char *name, enum modpack_type type, const char *version)
Update modpack information in database.
Definition: mpdb.cpp:209
static int mpdb_query(sqlite3 *handle, const char *query)
SQL query to database.
Definition: mpdb.cpp:106
struct section_file * secfile_load(const QString &filename, bool allow_duplicates)
Create a section file from a file.
Definition: registry.cpp:21
void secfile_destroy(struct section_file *secfile)
Free a section file.
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
Lookup a string value in the secfile.
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
Lookup a string value in the secfile.
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
int fc_strcasecmp(const char *str0, const char *str1)
Compare strings like strcmp(), but ignoring case.
Definition: support.cpp:89