00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00038 #define _GNU_SOURCE
00039 #include "config.h"
00040 #include <glib.h>
00041 #include <glib/gi18n.h>
00042 #include <glib/gprintf.h>
00043 #include <qof.h>
00044 #include <stdlib.h>
00045 #include <stdio.h>
00046 #include <regex.h>
00047 #include <time.h>
00048 #include "qof-main.h"
00049
00050 #define MAX_LINE 79
00051
00052
00053 static QofLogModule log_module = QOF_MAIN_CLI;
00054
00055 void
00056 qof_main_wrap_line (FILE * fp, gint indent,
00057 const gchar * template, ...)
00058 {
00059 gint line_length, msg_length;
00060 va_list wraps;
00061 gchar *message;
00062
00063 line_length = MAX_LINE;
00064
00065
00066 indent = indent >= line_length ? indent % line_length : indent;
00067 indent = indent < 0 ? 0 : indent;
00068 message = NULL;
00069 g_return_if_fail (template);
00070 va_start (wraps, template);
00071 message = g_strdup_vprintf (template, wraps);
00072 va_end (wraps);
00073 g_return_if_fail (message);
00074 msg_length = strlen (message);
00075 while (msg_length > line_length)
00076 {
00077 gchar *chunk;
00078 gchar format[16];
00079
00080 chunk = message + line_length - 1;
00081 while (chunk > message && !g_ascii_isspace (*chunk))
00082 chunk--;
00083 if (chunk == message)
00084 break;
00085 while (chunk > (message + 1) && g_ascii_isspace (*chunk))
00086 chunk--;
00087 chunk++;
00088 g_sprintf (format, "%%.%ds\n%%%ds", (gint) (chunk - message),
00089 indent);
00090 g_fprintf (fp, format, message, "");
00091 message = chunk;
00092 while (g_ascii_isspace (*message) && *message)
00093 message++;
00094 msg_length = strlen (message);
00095 if (line_length == MAX_LINE)
00096 line_length -= indent;
00097 }
00098 if (msg_length)
00099 g_fprintf (fp, "%s\n", message);
00100 }
00101
00102 static void
00103 qof_main_run_sql (QofMainContext * context)
00104 {
00105 QofSqlQuery *q;
00106 QofBook *book;
00107 gchar *sql;
00108
00109 ENTER (" ");
00110 q = qof_sql_query_new ();
00111 sql = g_strdup (context->sql_str);
00112 book = qof_session_get_book (context->input_session);
00113 qof_sql_query_set_book (q, book);
00114 qof_sql_query_run (q, sql);
00115 context->query = qof_sql_query_get_query (q);
00116 LEAVE (" ");
00117 }
00118
00119 static void
00120 qof_main_run_query (QofMainContext * context)
00121 {
00122 QofBook *book;
00123 GList *results;
00124
00125 ENTER (" ");
00126 results = NULL;
00127 book = qof_session_get_book (context->input_session);
00128 qof_query_set_book (context->query, book);
00129 results = qof_query_run (context->query);
00130 if (results != NULL)
00131 qof_entity_copy_list (context->export_session, results);
00132 LEAVE (" ");
00133 }
00134
00135 void
00136 qof_main_free (QofMainContext * context)
00137 {
00138 g_free (context->filename);
00139 g_free (context->write_file);
00140 g_free (context->sql_file);
00141 g_free (context->database);
00142 g_free (context->category);
00143 }
00144
00145 static void
00146 find_param_cb (QofParam * param, gpointer user_data)
00147 {
00148 gchar * tmp;
00149 QofMainContext *context;
00150 QofQueryPredData *time_pred_data;
00151
00152 context = (QofMainContext *) user_data;
00153 if ((param->param_getfcn == NULL) ||
00154 (param->param_setfcn == NULL))
00155 return;
00156 if (0 == safe_strcmp (context->param_type, param->param_type))
00157 {
00158 time_pred_data = qof_query_time_predicate (QOF_COMPARE_GTE,
00159 QOF_DATE_MATCH_NORMAL, context->min_qt);
00160 tmp = g_strdup (param->param_name);
00161 qof_query_add_term (context->query,
00162 qof_query_build_param_list (tmp, NULL), time_pred_data, QOF_QUERY_AND);
00163 time_pred_data = qof_query_time_predicate (QOF_COMPARE_LTE,
00164 QOF_DATE_MATCH_NORMAL, context->max_qt);
00165 qof_query_add_term (context->query,
00166 qof_query_build_param_list (tmp, NULL), time_pred_data, QOF_QUERY_AND);
00167 qof_main_run_query (context);
00168 qof_query_purge_terms (context->query,
00169 qof_query_build_param_list (tmp, QOF_ID_BOOK, QOF_TYPE_GUID, NULL));
00170 PINFO (" param_name=%s added", tmp);
00171 }
00172 LEAVE (" ");
00173 }
00174
00175
00176 static void
00177 build_database_list (QofIdTypeConst obj_type, QofMainContext * context)
00178 {
00179 if (!obj_type || !context)
00180 return;
00181 if (!qof_class_is_registered (obj_type))
00182 return;
00183 ENTER (" object_type=%s", obj_type);
00184 context->query = qof_query_create_for (obj_type);
00185 if (context->category != NULL)
00186 {
00187 QofQueryPredData *category_pred;
00188
00189 category_pred =
00190 qof_query_string_predicate (QOF_COMPARE_EQUAL,
00191 context->category, QOF_STRING_MATCH_CASEINSENSITIVE,
00192 FALSE);
00193 qof_query_add_term (context->query,
00194 qof_query_build_param_list (CATEGORY_NAME, NULL),
00195 category_pred, QOF_QUERY_AND);
00196 }
00197 if (context->min_qt)
00198 {
00199 PINFO (" Preparing a time based queryset.");
00200 context->param_type = QOF_TYPE_TIME;
00201 qof_class_param_foreach (obj_type, find_param_cb, context);
00202 }
00203 else
00204 {
00205 qof_main_run_query (context);
00206 if (context->query)
00207 qof_query_clear (context->query);
00208 }
00209 LEAVE (" ");
00210 }
00211
00212 static void
00213 select_cb (QofObject * obj, gpointer data)
00214 {
00215 QofMainContext *context;
00216
00217 context = (QofMainContext *) data;
00218 g_return_if_fail (context);
00219 if (0 != safe_strcmp (context->exclude, obj->e_type))
00220 build_database_list (obj->e_type, context);
00221 }
00222
00223 void
00224 qof_main_moderate_query (QofMainContext * context)
00225 {
00226 GSList *date_param_list, *category_param_list;
00227 gboolean all;
00228
00229 ENTER (" ");
00230 all = TRUE;
00231 context->query = qof_query_create ();
00232 date_param_list = NULL;
00233 category_param_list = NULL;
00234 while (context->sql_list)
00235 {
00236 PINFO ("running sql_list");
00237 context->sql_str = g_strdup (context->sql_list->data);
00238 qof_main_run_sql (context);
00239 qof_main_run_query (context);
00240 if (context->query)
00241 qof_query_clear (context->query);
00242 g_free (context->sql_str);
00243 context->sql_str = NULL;
00244 all = FALSE;
00245 context->sql_list = g_list_next (context->sql_list);
00246 }
00247 if (0 < g_list_length (context->sql_list))
00248 {
00249 context->sql_str = NULL;
00250 g_list_free (context->sql_list);
00251 all = FALSE;
00252 }
00253 if (context->sql_str != NULL)
00254 {
00255 PINFO ("running sql_str");
00256 qof_main_run_sql (context);
00257 qof_main_run_query (context);
00258 if (context->query)
00259 qof_query_clear (context->query);
00260 all = FALSE;
00261 }
00262 if ((context->exclude != NULL)
00263 && (qof_class_is_registered (context->exclude)))
00264 {
00265 qof_object_foreach_type (select_cb, context);
00266 all = FALSE;
00267 }
00268 if ((context->database != NULL)
00269 && (qof_class_is_registered (context->database)))
00270 {
00271 build_database_list (context->database, context);
00272 all = FALSE;
00273 }
00274 if (all == TRUE)
00275 qof_object_foreach_type (select_cb, context);
00276 LEAVE (" ");
00277 }
00278
00279 static void
00280 option_cb (QofBackendOption * option, gpointer data)
00281 {
00282 QofMainContext *context;
00283
00284 context = (QofMainContext *) data;
00285 g_return_if_fail (context);
00286
00287
00288
00289 ENTER (" compression=%" G_GINT64_FORMAT " encoding=%s",
00290 context->gz_level, context->encoding);
00291 if (0 == safe_strcmp (QSF_COMPRESS, option->option_name))
00292 option->value = (gpointer) & context->gz_level;
00293 if (0 == safe_strcmp (QSF_ENCODING, option->option_name))
00294 option->value = (gpointer) g_strdup(context->encoding);
00295 if (0 == safe_strcmp (QSF_DATE_CONVERT, option->option_name))
00296 option->value = (gpointer) & context->convert;
00297 LEAVE (" ");
00298 }
00299
00300 void
00301 qof_mod_compression (gint64 gz_level, QofMainContext * context)
00302 {
00303 KvpFrame *be_config;
00304 QofBook *book;
00305 QofBackend *be;
00306
00307 ENTER (" compression=%" G_GINT64_FORMAT, gz_level);
00308 if ((gz_level > 0) && (gz_level <= 9))
00309 {
00310 book = qof_session_get_book (context->export_session);
00311 be = qof_book_get_backend (book);
00312 be_config = qof_backend_get_config (be);
00313 context->gz_level = gz_level;
00314 qof_backend_option_foreach (be_config, option_cb, context);
00315 qof_backend_load_config (be, be_config);
00316 }
00317 LEAVE (" ");
00318 }
00319
00320 void
00321 qof_mod_encoding (const gchar * encoding, QofMainContext * context)
00322 {
00323 KvpFrame *be_config;
00324 QofBook *book;
00325 QofBackend *be;
00326
00327 ENTER (" encode to %s", encoding);
00328 book = qof_session_get_book (context->export_session);
00329 be = qof_book_get_backend (book);
00330 be_config = qof_backend_get_config (be);
00331 context->encoding = encoding;
00332 qof_backend_option_foreach (be_config, option_cb, context);
00333 qof_backend_load_config (be, be_config);
00334 LEAVE (" ");
00335 }
00336
00337 void
00338 qof_mod_convert_deprecated (gint64 convert, QofMainContext * context)
00339 {
00340 KvpFrame *be_config;
00341 QofBook *book;
00342 QofBackend *be;
00343 gboolean set;
00344
00345 set = (convert == 0) ? FALSE : TRUE;
00346 ENTER (" convert deprecated date values? %i No if 0.", set);
00347 book = qof_session_get_book (context->export_session);
00348 be = qof_book_get_backend (book);
00349 be_config = qof_backend_get_config (be);
00350 context->convert = convert;
00351 qof_backend_option_foreach (be_config, option_cb, context);
00352 qof_backend_load_config (be, be_config);
00353 LEAVE (" ");
00354 }
00355
00356 void
00357 qof_cmd_xmlfile (QofMainContext * context)
00358 {
00359 QofSession *input_session, *export_session;
00360
00361 ENTER (" ");
00362 input_session = context->input_session;
00363 if (0 == safe_strcmp (context->exclude, context->database)
00364 && (context->exclude != NULL))
00365 {
00366 qof_main_wrap_line (stderr, ERR_INDENT,
00367
00368
00369 _("%s: Error: Cannot exclude database \"%s\" with option -e "
00370 "because option -d is set to include the database: \"%s\". "
00371 "Use the \'-l\' command to see the full list of supported "
00372 "databases.\n"), PACKAGE, context->exclude,
00373 context->database);
00374 qof_session_end (input_session);
00375 LEAVE (" conflicting options");
00376 return;
00377 }
00378 qof_session_begin (input_session, context->filename, TRUE, FALSE);
00379 qof_main_show_error (input_session);
00380 if (0 != safe_strcmp (QOF_STDOUT, context->filename))
00381 qof_session_load (input_session, NULL);
00382 qof_main_show_error (input_session);
00383 export_session = qof_session_new ();
00384 context->export_session = export_session;
00385 if (context->write_file)
00386 {
00387 qof_session_begin (export_session, context->write_file, TRUE,
00388 TRUE);
00389 qof_mod_compression (context->gz_level, context);
00390 }
00391 else
00392 qof_session_begin (export_session, QOF_STDOUT, TRUE, FALSE);
00393 qof_main_show_error (export_session);
00394
00395 qof_mod_encoding (context->encoding, context);
00396 qof_main_moderate_query (context);
00397 qof_session_save (export_session, NULL);
00398 qof_main_show_error (export_session);
00399 qof_main_show_error (input_session);
00400 qof_session_end (input_session);
00401 qof_session_end (export_session);
00402 LEAVE (" ");
00403 }
00404
00405 static void
00406 qof_main_list (QofObject * obj, gpointer G_GNUC_UNUSED data)
00407 {
00408 fprintf (stdout, "%-20s%-20s\n", obj->e_type, obj->type_label);
00409 }
00410
00411 void
00412 qof_main_select (QofMainContext * context)
00413 {
00414 g_return_if_fail (context);
00415 qof_object_foreach_type (select_cb, context);
00416 }
00417
00418 void
00419 qof_cmd_list (void)
00420 {
00421 qof_main_wrap_line (stdout, 0,
00422
00423
00424 _("\n%s: You can use the supported database names with '%s -d' "
00425 "and in SQL queries (as the table name) with '%s -s|f'. "
00426 "Descriptions are shown only for readability.\n"),
00427 PACKAGE, PACKAGE, PACKAGE);
00428 fprintf (stdout, "%-20s%-20s\n", _("Name"), _("Description"));
00429 qof_object_foreach_type (qof_main_list, NULL);
00430 qof_main_wrap_line (stdout, 0,
00431
00432
00433 _("\nUse '%s -d <database> --explain' to see the list of fields "
00434 "within any supported database."), PACKAGE);
00435 fprintf (stdout, _("\nThank you for using %s\n\n"), PACKAGE);
00436 }
00437
00438 static void
00439 explain_cb (QofParam * param, gpointer G_GNUC_UNUSED user_data)
00440 {
00441 if (param->param_getfcn && param->param_setfcn)
00442 fprintf (stdout, _("Type: %s\tName: %s\n"),
00443 param->param_type, param->param_name);
00444 }
00445
00446 void
00447 qof_cmd_explain (QofMainContext * context)
00448 {
00449 if (context->error)
00450 return;
00451 fprintf (stdout, _("\nParameters of the %s database:\n\n"),
00452 context->database);
00453 qof_class_param_foreach (context->database, explain_cb, NULL);
00454 fprintf (stdout, _("\nThank you for using %s\n\n"), PACKAGE);
00455 }
00456
00457 void
00458 qof_mod_category (const gchar * category, QofMainContext * data)
00459 {
00460 data->category = g_strdup (category);
00461 }
00462
00463 glong
00464 qof_mod_get_local_offset (void)
00465 {
00466 glong local_offset;
00467 struct tm local;
00468 time_t now;
00469
00470 local_offset = 0;
00471 now = time (NULL);
00472 local = *localtime_r (&now, &local);
00473 local_offset -= local.tm_gmtoff;
00474 return local_offset;
00475 }
00476
00477 void
00478 qof_mod_database (const gchar * database, QofMainContext * data)
00479 {
00480 if (qof_class_is_registered (database))
00481 data->database = g_strdup (database);
00482 }
00483
00484 void
00485 qof_mod_time (const gchar * date_time, QofMainContext * data)
00486 {
00487 QofDate *qd;
00488 gboolean all_year, all_month;
00489 gint adding_days;
00490 gchar *info;
00491
00492
00493 ENTER (" date_time=%s", date_time);
00494 all_month = all_year = FALSE;
00495 g_return_if_fail (date_time);
00496 qd = qof_date_parse (date_time, QOF_DATE_FORMAT_ISO);
00497 if (!qd)
00498 qd = qof_date_parse (date_time, QOF_DATE_FORMAT_UTC);
00499 info = qof_date_print (qd, QOF_DATE_FORMAT_ISO8601);
00500 PINFO (" parsed start_time=%s", info);
00501 g_free (info);
00502
00503 qof_date_set_day_start (qd);
00504 data->min_qt = qof_date_to_qtime (qd);
00505
00506 qof_time_add_secs (data->min_qt,
00507 qof_mod_get_local_offset());
00508
00509 if (strlen (date_time) == 4)
00510 {
00511 PINFO (" match entire year %s", date_time);
00512
00513 adding_days = qof_date_isleap(qd->qd_year) ? 365 : 364;
00514 qof_date_adddays (qd, adding_days);
00515 }
00516
00517 if (strlen (date_time) == 7)
00518 {
00519 PINFO (" match entire month %s", date_time);
00520 adding_days = qof_date_get_mday (qd->qd_mon, qd->qd_year);
00521 qof_date_adddays (qd, adding_days - 1);
00522 }
00523
00524 qof_date_set_day_end (qd);
00525 data->max_qt = qof_date_to_qtime (qd);
00526
00527 qof_time_add_secs (data->max_qt,
00528 qof_mod_get_local_offset());
00529 LEAVE (" ");
00530 }
00531
00532 void
00533 qof_mod_exclude (const gchar * exclude, QofMainContext * data)
00534 {
00535 if (qof_class_is_registered (exclude))
00536 data->exclude = g_strdup (exclude);
00537 }
00538
00539 void
00540 qof_mod_sql (const gchar * sql_query, QofMainContext * data)
00541 {
00542 data->sql_str = g_strdup (sql_query);
00543 }
00544
00545 void
00546 qof_mod_sql_file (const gchar * sql_file, QofMainContext * data)
00547 {
00548 FILE *filehandle;
00549 #ifndef HAVE_GETLINE
00550 gchar lineptr[1024];
00551 #else
00552 gchar *lineptr;
00553 #endif
00554 gchar *buf;
00555 size_t n;
00556 QofQuery *q;
00557 regex_t *r;
00558 gint reg_exp_check;
00559 const gchar *fmt;
00560 static gchar *pattern = QOF_SQL_SUPPORTED;
00561
00562 ENTER (" ");
00563 data->sql_file = g_strdup (sql_file);
00564 n = 0;
00565 q = NULL;
00566 data->sql_list = NULL;
00567 filehandle = fopen (sql_file, "r");
00568 if (!filehandle)
00569 {
00570 fmt = _("%s: There was an error reading the file '%s'.\n");
00571 qof_main_wrap_line (stderr, ERR_INDENT, fmt, PACKAGE, sql_file);
00572 return;
00573 }
00574 r = g_new (regex_t, 1);
00575 #ifndef HAVE_GETLINE
00576 while (NULL != (fgets (lineptr, sizeof (lineptr), filehandle)))
00577 #else
00578 lineptr = NULL;
00579 while (0 < getline (&lineptr, &n, filehandle))
00580 #endif
00581 {
00582 reg_exp_check =
00583 regcomp (r, pattern, REG_ICASE | REG_NOSUB | REG_EXTENDED);
00584 g_return_if_fail (reg_exp_check == 0);
00585 if (0 != regexec (r, lineptr, 0, NULL, 0))
00586 continue;
00587 buf = g_strdup (g_strchomp (lineptr));
00588 data->sql_list = g_list_prepend (data->sql_list, buf);
00589 }
00590 regfree (r);
00591 g_free (r);
00592 fclose (filehandle);
00593 LEAVE (" sql_list=%d", g_list_length (data->sql_list));
00594 }
00595
00596 void
00597 qof_mod_write (const gchar * write_file, QofMainContext * data)
00598 {
00599 data->write_file = g_strdup (write_file);
00600 }
00601
00602 void
00603 qof_main_show_error (QofSession * session)
00604 {
00605 const gchar *fmt;
00606
00607 if (qof_error_check (session))
00608 {
00609 fmt = "%s: %s\n";
00610 qof_main_wrap_line (stderr, ERR_INDENT, fmt, PACKAGE,
00611 qof_error_get_message (session));
00612 }
00613 }
00614
00617