Line data Source code
1 : /* File: main_commands.c; Copyright and License: see below */
2 :
3 : #include "main_commands.h"
4 : #include "gui_main.h"
5 : #include "gui_error_info_printer.h"
6 : #include "io_exporter.h"
7 : #include "io_importer.h"
8 : #include "ctrl_controller.h"
9 : #include "u8/u8_trace.h"
10 : #include "u8/u8_log.h"
11 : #include <gtk/gtk.h>
12 : #include <stdbool.h>
13 : #include <assert.h>
14 :
15 : static io_data_file_t single_big_data_file; /*!< a data_file struct, placed in the data segment due to its >5MB size */
16 :
17 0 : u8_error_t main_commands_init ( main_commands_t *this_, bool start_gui, int argc, char **argv )
18 : {
19 0 : U8_TRACE_BEGIN();
20 0 : u8_error_t result = U8_ERROR_NONE;
21 :
22 0 : (*this_).argc = argc;
23 0 : (*this_).argv = argv;
24 :
25 : /* initialize the base libraries: gobject, gio, glib, gdk and gtk */
26 0 : if ( start_gui )
27 : {
28 0 : gtk_init();
29 : /* if this program was not terminated, gtk init was successful. */
30 : }
31 : else
32 : {
33 0 : const gboolean success = gtk_init_check();
34 0 : if ( ! success )
35 : {
36 0 : U8_LOG_WARNING("gtk could not be initialized.");
37 : /* no error here, if no gui requested - test fail otherwise */
38 : }
39 : }
40 :
41 0 : U8_TRACE_INFO("starting DB and its controller...");
42 0 : U8_TRACE_INFO_INT("sizeof(io_data_file_t)/B:",sizeof(io_data_file_t));
43 0 : (*this_).data_file = &single_big_data_file;
44 0 : io_data_file_init( (*this_).data_file );
45 :
46 0 : U8_TRACE_END_ERR( result );
47 0 : return result;
48 : }
49 :
50 0 : void main_commands_destroy ( main_commands_t *this_ )
51 : {
52 0 : U8_TRACE_BEGIN();
53 :
54 0 : U8_TRACE_INFO("stopping DB and its controller...");
55 0 : io_data_file_destroy( (*this_).data_file );
56 :
57 0 : U8_TRACE_END();
58 0 : }
59 :
60 0 : u8_error_t main_commands_repair ( main_commands_t *this_,
61 : const char *data_file_path,
62 : bool check_only,
63 : utf8stream_writer_t *out_english_report )
64 : {
65 0 : U8_TRACE_BEGIN();
66 0 : assert( data_file_path != NULL );
67 0 : const bool do_repair = ( ! check_only );
68 0 : u8_error_t result = U8_ERROR_NONE;
69 :
70 0 : U8_TRACE_INFO("opening DB...");
71 : u8_error_info_t err_info;
72 : data_stat_t stat;
73 0 : data_stat_init( &stat );
74 0 : result |= io_data_file_open( (*this_).data_file, data_file_path, check_only, &stat, &err_info );
75 0 : data_stat_trace( &stat );
76 0 : data_stat_destroy( &stat );
77 0 : if ( result != U8_ERROR_NONE )
78 : {
79 0 : result |= main_commands_private_report_error_on_open( this_, result, data_file_path, out_english_report );
80 : }
81 0 : result |= main_commands_private_report_error_info( this_, &err_info, out_english_report );
82 :
83 0 : U8_TRACE_INFO("reparing/testing...");
84 0 : utf8stream_writer_write_str( out_english_report, "\n\n" );
85 0 : result |= ctrl_controller_repair_database( io_data_file_get_controller_ptr( (*this_).data_file ),
86 : do_repair,
87 : NULL,
88 : NULL,
89 : out_english_report
90 : );
91 0 : utf8stream_writer_write_str( out_english_report, "\n" );
92 0 : U8_TRACE_INFO("reparing/testing finished.");
93 :
94 0 : U8_TRACE_INFO("closing DB...");
95 0 : io_data_file_close( (*this_).data_file );
96 :
97 0 : U8_TRACE_END_ERR( result );
98 0 : return result;
99 : }
100 :
101 0 : u8_error_t main_commands_start_gui ( main_commands_t *this_,
102 : const char *data_file_path,
103 : utf8stream_writer_t *out_english_report )
104 : {
105 0 : U8_TRACE_BEGIN();
106 0 : u8_error_t result = U8_ERROR_NONE;
107 :
108 0 : U8_TRACE_TIMESTAMP();
109 0 : U8_TRACE_INFO("opening DB...");
110 0 : if ( NULL != data_file_path )
111 : {
112 : u8_error_info_t err_info;
113 : data_stat_t stat;
114 0 : data_stat_init( &stat );
115 0 : result |= io_data_file_open_writeable( (*this_).data_file, data_file_path, &stat, &err_info );
116 0 : data_stat_trace( &stat );
117 0 : data_stat_destroy( &stat );
118 0 : if ( result != U8_ERROR_NONE )
119 : {
120 0 : result |= main_commands_private_report_error_on_open( this_, result, data_file_path, out_english_report );
121 : }
122 0 : result |= main_commands_private_report_error_info( this_, &err_info, out_english_report );
123 : }
124 :
125 0 : U8_TRACE_TIMESTAMP();
126 0 : U8_TRACE_INFO("running GUI...");
127 0 : gui_main( (*this_).data_file, (*this_).argc, (*this_).argv );
128 0 : U8_TRACE_INFO("GUI stopped.");
129 :
130 0 : U8_TRACE_TIMESTAMP();
131 0 : U8_TRACE_INFO("closing DB...");
132 0 : io_data_file_close( (*this_).data_file );
133 :
134 0 : U8_TRACE_END_ERR( result );
135 0 : return result;
136 : }
137 :
138 0 : u8_error_t main_commands_export ( main_commands_t *this_,
139 : const char *data_file_path,
140 : io_file_format_t export_format,
141 : const char *export_directory,
142 : utf8stream_writer_t *out_english_report )
143 : {
144 0 : U8_TRACE_BEGIN();
145 0 : assert( data_file_path != NULL );
146 0 : assert( export_directory != NULL );
147 0 : u8_error_t export_err = U8_ERROR_NONE;
148 :
149 0 : U8_TRACE_INFO("opening DB...");
150 : u8_error_info_t err_info;
151 : data_stat_t stat;
152 0 : data_stat_init( &stat );
153 0 : export_err |= io_data_file_open_read_only( (*this_).data_file, data_file_path, &stat, &err_info );
154 0 : data_stat_trace( &stat );
155 0 : data_stat_destroy( &stat );
156 0 : if ( export_err != U8_ERROR_NONE )
157 : {
158 0 : export_err |= main_commands_private_report_error_on_open( this_, export_err, data_file_path, out_english_report );
159 : }
160 0 : export_err |= main_commands_private_report_error_info( this_, &err_info, out_english_report );
161 :
162 0 : U8_TRACE_INFO("exporting DB...");
163 0 : U8_TRACE_INFO_STR( "chosen folder:", export_directory );
164 0 : const char *document_filename = io_data_file_get_filename_const( (*this_).data_file );
165 0 : if ( io_data_file_is_open( (*this_).data_file ) )
166 : {
167 : static data_database_reader_t db_reader;
168 0 : data_database_reader_init( &db_reader, io_data_file_get_database_ptr( (*this_).data_file ) );
169 : static io_exporter_t exporter;
170 0 : io_exporter_init( &exporter, &db_reader );
171 : {
172 : data_stat_t export_stat;
173 0 : data_stat_init ( &export_stat );
174 0 : export_err = io_exporter_export_files( &exporter, export_format, export_directory, document_filename, &export_stat );
175 0 : export_err |= main_commands_private_report_stat( this_, &export_stat, "exported", out_english_report );
176 0 : data_stat_trace( &export_stat );
177 0 : data_stat_destroy ( &export_stat );
178 : }
179 0 : io_exporter_destroy( &exporter );
180 0 : data_database_reader_destroy( &db_reader );
181 : }
182 : else
183 : {
184 0 : export_err = U8_ERROR_NO_DB;
185 : }
186 :
187 0 : U8_TRACE_INFO("closing DB...");
188 0 : io_data_file_close( (*this_).data_file );
189 :
190 0 : U8_TRACE_END_ERR( export_err );
191 0 : return export_err;
192 : }
193 :
194 0 : u8_error_t main_commands_import ( main_commands_t *this_,
195 : const char *data_file_path,
196 : io_import_mode_t import_mode,
197 : const char *import_file_path,
198 : utf8stream_writer_t *out_english_report )
199 : {
200 0 : U8_TRACE_BEGIN();
201 0 : assert( data_file_path != NULL );
202 0 : assert( import_file_path != NULL );
203 0 : u8_error_t import_err = U8_ERROR_NONE;
204 :
205 0 : U8_TRACE_INFO("opening DB...");
206 : u8_error_info_t err_info;
207 : data_stat_t stat;
208 0 : data_stat_init( &stat );
209 0 : import_err |= io_data_file_open_writeable( (*this_).data_file, data_file_path, &stat, &err_info );
210 0 : data_stat_trace( &stat );
211 0 : data_stat_destroy( &stat );
212 0 : if ( import_err != U8_ERROR_NONE )
213 : {
214 0 : import_err |= main_commands_private_report_error_on_open( this_, import_err, data_file_path, out_english_report );
215 : }
216 0 : import_err |= main_commands_private_report_error_info( this_, &err_info, out_english_report );
217 :
218 0 : U8_TRACE_INFO("importing data...");
219 0 : U8_TRACE_INFO_STR( "chosen data:", import_file_path );
220 0 : if ( io_data_file_is_open( (*this_).data_file ) )
221 : {
222 : static data_database_reader_t db_reader;
223 0 : data_database_reader_init( &db_reader, io_data_file_get_database_ptr( (*this_).data_file ) );
224 : static io_importer_t importer;
225 0 : io_importer_init( &importer, &db_reader, io_data_file_get_controller_ptr( (*this_).data_file ));
226 : {
227 : data_stat_t import_stat;
228 0 : data_stat_init ( &import_stat );
229 : u8_error_info_t err_info;
230 0 : import_err = io_importer_import_file( &importer, import_mode, import_file_path, &import_stat, &err_info, out_english_report );
231 0 : import_err |= main_commands_private_report_stat( this_, &import_stat, "imported", out_english_report );
232 0 : import_err |= main_commands_private_report_error_info( this_, &err_info, out_english_report );
233 0 : data_stat_trace( &import_stat );
234 0 : data_stat_destroy ( &import_stat );
235 : }
236 0 : io_importer_destroy( &importer );
237 0 : data_database_reader_destroy( &db_reader );
238 : }
239 : else
240 : {
241 0 : import_err = U8_ERROR_NO_DB;
242 : }
243 :
244 0 : U8_TRACE_INFO("closing DB...");
245 0 : io_data_file_close( (*this_).data_file );
246 :
247 : {
248 0 : utf8stream_writer_write_str( out_english_report, "\nplease test the integrity of the database_file:\n" );
249 0 : utf8stream_writer_write_str( out_english_report, "crystal-facet-uml -t " );
250 0 : utf8stream_writer_write_str( out_english_report, data_file_path );
251 0 : utf8stream_writer_write_str( out_english_report, "\n\n" );
252 : }
253 :
254 0 : U8_TRACE_END_ERR( import_err );
255 0 : return import_err;
256 : }
257 :
258 : static const char *const series[DATA_STAT_SERIES_MAX] = {
259 : [DATA_STAT_SERIES_CREATED] = " new/exp",
260 : [DATA_STAT_SERIES_MODIFIED] = "modified",
261 : [DATA_STAT_SERIES_DELETED] = " deleted",
262 : [DATA_STAT_SERIES_IGNORED] = " ignored",
263 : [DATA_STAT_SERIES_WARNING] = "warnings",
264 : [DATA_STAT_SERIES_ERROR] = " errors",
265 : };
266 :
267 : static const char *const tables[DATA_STAT_TABLE_MAX] = {
268 : [DATA_TABLE_VOID] = "life",
269 : [DATA_TABLE_CLASSIFIER] = "clas",
270 : [DATA_TABLE_FEATURE] = "feat",
271 : [DATA_TABLE_RELATIONSHIP] = "rel",
272 : [DATA_TABLE_DIAGRAMELEMENT] = "d_ele",
273 : [DATA_TABLE_DIAGRAM] = "diag",
274 : };
275 :
276 0 : u8_error_t main_commands_private_report_stat ( main_commands_t *this_,
277 : const data_stat_t *stat,
278 : const char* mode_name,
279 : utf8stream_writer_t *out_english_report )
280 : {
281 0 : U8_TRACE_BEGIN();
282 0 : assert( stat != NULL );
283 0 : assert( mode_name != NULL );
284 0 : assert( out_english_report != NULL );
285 0 : u8_error_t write_err = U8_ERROR_NONE;
286 :
287 : /* HEADLINE */
288 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\n\t" );
289 :
290 0 : for ( int tables_idx = 0; tables_idx < DATA_STAT_TABLE_MAX; tables_idx ++ )
291 : {
292 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\t" );
293 0 : write_err |= utf8stream_writer_write_str( out_english_report, tables[tables_idx] );
294 : }
295 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\n" );
296 :
297 : /* TABLE */
298 0 : for ( int series_idx = 0; series_idx < DATA_STAT_SERIES_MAX; series_idx ++ )
299 : {
300 0 : const uint_fast32_t s_cnt = data_stat_get_series_count( stat, series_idx );
301 :
302 0 : if ( series_idx == DATA_STAT_SERIES_CREATED )
303 : {
304 0 : write_err |= utf8stream_writer_write_str( out_english_report, mode_name );
305 : }
306 : else
307 : {
308 0 : write_err |= utf8stream_writer_write_str( out_english_report, series[series_idx] );
309 : }
310 0 : write_err |= utf8stream_writer_write_str( out_english_report, ": " );
311 :
312 0 : for ( int tables_idx = 0; tables_idx < DATA_STAT_TABLE_MAX; tables_idx ++ )
313 : {
314 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\t" );
315 0 : const uint_fast32_t cnt = data_stat_get_count( stat, tables_idx, series_idx );
316 0 : if ( cnt != 0 )
317 : {
318 0 : write_err |= utf8stream_writer_write_int( out_english_report, cnt );
319 : }
320 : }
321 :
322 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\t: " );
323 0 : write_err |= utf8stream_writer_write_int( out_english_report, s_cnt );
324 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\n" );
325 : }
326 :
327 : /* ROW OF SUMS */
328 0 : write_err |= utf8stream_writer_write_str( out_english_report, " SUM:" );
329 0 : for ( int tables_idx = 0; tables_idx < DATA_STAT_TABLE_MAX; tables_idx ++ )
330 : {
331 0 : const uint_fast32_t t_cnt = data_stat_get_table_count( stat, tables_idx );
332 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\t" );
333 0 : write_err |= utf8stream_writer_write_int( out_english_report, t_cnt );
334 : }
335 0 : const uint_fast32_t total = data_stat_get_total_count( stat );
336 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\t: " );
337 0 : write_err |= utf8stream_writer_write_int( out_english_report, total );
338 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\n" );
339 :
340 0 : U8_TRACE_END_ERR( write_err );
341 0 : return write_err;
342 : }
343 :
344 0 : u8_error_t main_commands_private_report_error_on_open ( main_commands_t *this_,
345 : const u8_error_t error,
346 : const char* file_name,
347 : utf8stream_writer_t *out_english_report )
348 : {
349 0 : U8_TRACE_BEGIN();
350 0 : assert( file_name != NULL );
351 0 : assert( out_english_report != NULL );
352 0 : u8_error_t write_err = U8_ERROR_NONE;
353 :
354 0 : if ( U8_ERROR_NO_DB == error )
355 : {
356 : /* Most likely the parent directory of database is read only */
357 0 : write_err |= utf8stream_writer_write_str( out_english_report,
358 : "error: not possible to create a temporary database file for "
359 : );
360 0 : write_err |= utf8stream_writer_write_str( out_english_report, file_name );
361 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\n" );
362 : }
363 0 : else if ( U8_ERROR_LOCKED_BY_TEMP_FILE == error )
364 : {
365 : /* Most likely the parent directory of database is read only */
366 0 : write_err |= utf8stream_writer_write_str( out_english_report,
367 : "error: a temporary database file locks "
368 : );
369 0 : write_err |= utf8stream_writer_write_str( out_english_report, file_name );
370 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\n" );
371 0 : write_err |= utf8stream_writer_write_str( out_english_report,
372 : "if the file is not used concurrently, either open that .tmp-cfu file or delete it.\n"
373 : );
374 : }
375 : else
376 : {
377 0 : write_err |= utf8stream_writer_write_str( out_english_report, "error opening database_file " );
378 0 : write_err |= utf8stream_writer_write_str( out_english_report, file_name );
379 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\n" );
380 : }
381 :
382 0 : U8_TRACE_END_ERR( write_err );
383 0 : return write_err;
384 : }
385 :
386 0 : u8_error_t main_commands_private_report_error_info ( main_commands_t *this_,
387 : const u8_error_info_t *error_info,
388 : utf8stream_writer_t *out_english_report )
389 : {
390 0 : U8_TRACE_BEGIN();
391 0 : assert( error_info != NULL );
392 0 : assert( out_english_report != NULL );
393 0 : u8_error_t write_err = U8_ERROR_NONE;
394 :
395 0 : if ( u8_error_info_is_error( error_info ) )
396 : {
397 : char info_string_buf[80];
398 0 : utf8stringbuf_t info_string = UTF8STRINGBUF(info_string_buf);
399 0 : utf8stringbuf_clear( &info_string );
400 : {
401 : gui_error_info_printer_t my_err_info_printer;
402 0 : gui_error_info_printer_init( &my_err_info_printer );
403 0 : write_err |= gui_error_info_printer_show_error_info( &my_err_info_printer, error_info, info_string );
404 0 : gui_error_info_printer_destroy( &my_err_info_printer );
405 : }
406 0 : write_err |= utf8stream_writer_write_str( out_english_report, utf8stringbuf_get_string( &info_string ) );
407 0 : write_err |= utf8stream_writer_write_str( out_english_report, "\n" );
408 : }
409 :
410 0 : U8_TRACE_END_ERR( write_err );
411 0 : return write_err;
412 : }
413 :
414 :
415 : /*
416 : Copyright 2016-2026 Andreas Warnke
417 :
418 : Licensed under the Apache License, Version 2.0 (the "License");
419 : you may not use this file except in compliance with the License.
420 : You may obtain a copy of the License at
421 :
422 : http://www.apache.org/licenses/LICENSE-2.0
423 :
424 : Unless required by applicable law or agreed to in writing, software
425 : distributed under the License is distributed on an "AS IS" BASIS,
426 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
427 : See the License for the specific language governing permissions and
428 : limitations under the License.
429 : */
|