Logo Search packages:      
Sourcecode: bibledit version File versions  Download package

projectutils.cpp

/*
** Copyright (C) 2003-2006 Teus Benschop.
**  
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**  
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**  
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**  
*/


#include "libraries.h"
#include "utilities.h"
#include <libgen.h>
#include <glib.h>
#include <config.h>
#include "constants.h"
#include "projectutils.h"
#include "directories.h"
#include "gwrappers.h"
#include "shell.h"
#include "sqlite3.h"
#include "books.h"
#include "vacuum.h"
#include "bible.h"
#include "progresswindow.h"
#include "import.h"
#include "projectutilsold1.h"


#define BOOK_SUFFIX ".book.sql2"


void project_store_sanitize_line (ustring& line)
/* 
Joins lines without starting usfm to a previous one. 
Makes changes in-place.
*/
{
  // Look for a newline.
  size_t position = line.find ("\n");
  while (position != string::npos) {
    position++;
    if (position >= line.size())
      break;
    // If found, and the next character is not a backslash (\), then put a space 
    // instead of the newline.
    if (line.substr (position, 1) != "\\") {
      line.replace (position - 1, 1, " ");
    }
    // Keep going till through.
    position = line.find ("\n", position);
  }
}


void project_store_chapter_internal (
       const ustring& project, const ustring& book, unsigned int chapter, 
       CategorizeChapterVerse& ccv, unsigned int first, unsigned int last,
       unsigned int timestamp)
{
  // Some variables.  
  sqlite3 *db;
  int rc;
  char *error = NULL;
  try
  {
    // Connect to the database.
    rc = sqlite3_open (project_book_filename (project, book).c_str (), &db);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Variable.
    char * sql;
    // Begin transaction;
    rc = sqlite3_exec (db, "begin;", NULL, NULL, &error);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Drop the chapter's table if it's there.
    sql = g_strdup_printf ("drop table '%d';", chapter);
    rc = sqlite3_exec (db, sql, NULL, NULL, &error);
    g_free (sql);
    // Create new chapter's table.
    sql = g_strdup_printf ("create table '%d' (verse text, sequence integer, usfm text);", chapter);
    rc = sqlite3_exec (db, sql, NULL, NULL, &error);
    g_free (sql);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Store the new data.
    for (unsigned int i = first; i < last; i++) {
      ustring text = double_apostrophy (ccv.line[i]);
      project_store_sanitize_line (text);
      sql = g_strdup_printf ("insert into '%d' values ('%s', %d, '%s')", chapter, ccv.verse[i].c_str(), ccv.sequence[i], text.c_str());
      rc = sqlite3_exec (db, sql, NULL, NULL, &error);
      g_free (sql);
      if (rc) {
        throw runtime_error (sqlite3_errmsg(db));
      }
    }    
    // Commit the changes.
    rc = sqlite3_exec (db, "commit;", NULL, NULL, &error);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
  }
  catch (exception & ex)
  {
    gw_critical (ex.what ());
  }
  // Close connection.
  sqlite3_close (db);
  // Timestamp.
  project_update_book (project, book, timestamp);
}


void projects_initial_check (bool gui)
// Does some initial checks on the projects we have.
// Upgrades projects of an older version to the current version.
{
  {
    // The older generation of Bibledit stored each book in a project under the
    // name of "current-version". Look them all up.
    vector<ustring> available_books;
    {
      FILE *stream;
      ustring s = "find";
      s.append (shell_quote_space (directories_get_projects ()));
      s.append ("-name current-version");
      stream = popen (s.c_str (), "r");
      char buf[1024];
      while (fgets (buf, sizeof (buf), stream)) {
        s = buf;
        s = trim (s);
        available_books.push_back (s);
      }
      pclose (stream);
    }

    // Handle books to upgrade.
    if (available_books.size() > 0) {
    
      // Progress information.
      ProgressWindow * progresswindow = NULL;
      if (gui) {
        progresswindow = new ProgressWindow ("Upgrading projects", false);
        progresswindow->set_iterate (0, 1, available_books.size());
      }

      // Go through each book found and deal with it.
      for (unsigned int bk = 0; bk < available_books.size(); bk++) {
    
        // Some variables.
        ustring bookfilename = available_books[bk];
        ustring bookdirectory = gw_path_get_dirname (bookfilename);
        ustring bookname = gw_path_get_basename (bookdirectory);
        ustring projectname = gw_path_get_basename (gw_path_get_dirname (bookdirectory));

        // Create project if needed.
        if (!project_old1_exists (projectname)) {
          cout << "Upgrading project " << projectname << endl;
          if (gui)
            progresswindow->set_text (projectname);
          project_old1_create (projectname);
        }
      
        // Import data.
        cout << projectname << " " << bookname << endl;
        if (gui) progresswindow->iterate ();
        // Read the book. It is assumed it is in Unicode already.
        ImportBookRead ibr (bookfilename, "");
        ibr.usfm ();
        // Each line gets associated chapter and verse information.
        CategorizeChapterVerse ccv (ibr.lines);
        // Store it in the databases.
        project_old1_store_book (projectname, bookname, ccv);
        // Handle books that were symbolic links.
        if (g_file_test (bookfilename.c_str(), G_FILE_TEST_IS_SYMLINK)) {
          gchar * link = g_file_read_link (bookfilename.c_str(), NULL);
          if (link) {
            project_link_book (projectname, bookname, link);
            g_free (link);
          }
        } 
        // Delete directory for this book.
        remove_directory (bookdirectory);
      }    
      if (progresswindow)
        delete progresswindow;
    }
  }
  
  // Ensure that the books database is present in each project and remove old stuff.
  {
    ustring databasefile = books_filename_template ();
    vector <ustring> projects = projects_get_all ();
    for (unsigned int i = 0; i < projects.size(); i++) {
      ustring filename = books_filename (projects[i]);
      if (!g_file_test (filename.c_str(), G_FILE_TEST_IS_REGULAR)) {
        // Create new database.
        books_create (projects[i]);
        // Clear out old ones.
        ustring oldfile;
        oldfile = gw_build_filename (directories_get_projects (), projects[i], "books.sql2");
        unlink (oldfile.c_str());
        oldfile = gw_build_filename (directories_get_projects (), projects[i], "books.sql3");
        unlink (oldfile.c_str());
      }
    }
  }
  
  // Upgrade to a faster type of storing and retrieving data: each books in its own database.
  {
    vector<ustring> projects = projects_old1_get_all ();
    if (projects.size() > 0) {
      ProgressWindow * progresswindow = NULL;
      if (gui) {
        progresswindow = new ProgressWindow ("Upgrading projects", false);
        progresswindow->set_iterate (0, 1, projects.size());
      }
      for (unsigned int p = 0; p < projects.size(); p++) {
        ustring project = projects[p];
        cout << "Upgrading project " << project << endl;
        if (gui) progresswindow->iterate ();
        project_create (project);
        vector<ustring> books = project_old1_get_books (project);
        for (unsigned int b = 0; b < books.size(); b++) {
          ustring book = books[b];
          if (gui) progresswindow->set_text (project + " " + book);
          vector<unsigned int> chapters = project_old1_get_chapters (project, book);
          for (unsigned int ch = 0; ch < chapters.size(); ch++) {
            unsigned int chapter = chapters[ch];
            vector <ustring> lines = project_old1_retrieve_chapter (project, book, chapter);
            CategorizeChapterVerse ccv (lines);
            project_store_chapter (project, book, ccv);
          }
        }
        unlink (project_old1_filename (project).c_str());
      }
      if (progresswindow) delete progresswindow;
    }
  }
}


vector<ustring> projects_get_all ()
// Gets sorted list of all projects.
{
  ReadDirectories rd (directories_get_projects (), "", "");
  sort (rd.directories.begin(), rd.directories.end());
  return rd.directories;
}


ustring project_filename (const ustring& project)
{
  return gw_build_filename (directories_get_projects (), project, "data.sql2");
}


ustring project_book_filename (const ustring& project, const ustring& book)
{
  return gw_build_filename (directories_get_projects (), project, book + BOOK_SUFFIX);
}


bool project_exists (const ustring& project)
{
  return g_file_test (gw_build_filename (directories_get_projects(), project).c_str(), G_FILE_TEST_IS_DIR);
}


void project_create (const ustring& project)
{
  // Create project directory.
  create_directory (gw_build_filename (directories_get_projects (), project));
  // Some variables.  
  sqlite3 *db;
  int rc;
  char *error = NULL;
  try
  {
    // Connect to the database.
    rc = sqlite3_open (project_filename (project).c_str (), &db);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Variable.
    char * sql;
    // Create the synchronization table.
    // It stores the state of the synchronization between internal database and external USFM files.
    sql = g_strdup_printf ("create table sync (book text, updated integer, filename text, filetime integer, filesize integer);");
    rc = sqlite3_exec (db, sql, NULL, NULL, &error);
    g_free (sql);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Create the index table.
    // Information to keep the index up-to-date.
    sql = g_strdup_printf ("create table idx (timestamp integer);");
    rc = sqlite3_exec (db, sql, NULL, NULL, &error);
    g_free (sql);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
  }
  catch (exception & ex)
  {
    gw_critical (ex.what ());
  }
  // Close connection.
  sqlite3_close (db);
  // Create books data.
  books_create (project);
}


void project_delete (const ustring& project)
// Deletes a project.
{
  ustring directory = gw_build_filename (directories_get_projects (), project);
  remove_directory (directory);
}


void project_copy (const ustring& project, const ustring& newproject)
// Copies "project" to "newproject.
{
  ustring olddirectory = gw_build_filename (directories_get_projects (), project);
  ustring newdirectory = gw_build_filename (directories_get_projects (), newproject);
  ustring command = "cp -r";
  command.append (shell_quote_space (olddirectory));
  command.append (shell_quote_space (newdirectory));
  system (command.c_str());
}


void project_move (const ustring& project, const ustring& newproject)
{
  ustring oldname = (gw_build_filename (directories_get_projects (), project));
  ustring newname = (gw_build_filename (directories_get_projects (), newproject));
  ustring command = "mv";
  command.append (shell_quote_space(oldname));
  command.append (shell_quote_space(newname));
  system (command.c_str ());
}


void project_store_book (const ustring& project, const ustring& book, CategorizeChapterVerse& ccv)
{
  // If nothing to save, bail out.
  if (ccv.chapter.empty()) return;
  // Timestamp.
  unsigned int timestamp = time (0);
  // Make pointers to each chapter.
  vector <unsigned int> chapters;
  vector <unsigned int> firsts;
  vector <unsigned int> lasts;
  unsigned int currentchapter = ccv.chapter[0];
  unsigned int first = 0;
  for (unsigned int i = 0; i < ccv.chapter.size(); i++) {
    if (ccv.chapter[i] != currentchapter) {
      chapters.push_back (currentchapter);
      currentchapter = ccv.chapter[i];
      firsts.push_back (first);
      first = i;
      lasts.push_back (i);
    }
  }
  chapters.push_back (currentchapter);
  firsts.push_back (first);
  lasts.push_back (ccv.chapter.size());
  // Store each chapter.
  for (unsigned int i = 0; i < chapters.size(); i++) {
    project_store_chapter_internal (project, book, chapters[i], ccv, firsts[i], lasts[i], timestamp);
  }  
  // Store data about book.
  project_update_book (project, book, timestamp);
}


void project_remove_book (const ustring& project, const ustring& book)
{
  unlink (project_book_filename (project, book).c_str());
  sqlite3 *db;
  int rc;
  char *error = NULL;
  try
  {
    rc = sqlite3_open (project_filename (project).c_str (), &db);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Remove possible link.
    char * sql;
    sql = g_strdup_printf ("delete from sync where book = '%s';", book.c_str());
    rc = sqlite3_exec (db, sql, NULL, NULL, &error);
    g_free (sql);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
  }
  catch (exception & ex)
  {
    gw_critical (ex.what ());
  }
  // Close connection.
  sqlite3_close (db);
}


void project_store_chapter (const ustring& project, const ustring& book, CategorizeChapterVerse& ccv)
{
  // If there's nothing to save, bail out.
  if (ccv.chapter.size() == 0)
    return;
  // Do the actual storing.
  unsigned int chapter = ccv.chapter[0];
  unsigned int timestamp = time (0);
  project_store_chapter_internal (project, book, chapter, ccv, 0, ccv.chapter.size(), timestamp);
  project_update_book (project, book, timestamp);
}


void project_store_verse (const ustring& project, const ustring& book, const ustring& chapter, const ustring& verse, const ustring& data)
{
  // If there's nothing to save, bail out.
  if (data.empty())
    return;
  // Some variables.  
  sqlite3 *db;
  int rc;
  char *error = NULL;
  try
  {
    // Connect to the database.
    rc = sqlite3_open (project_book_filename (project, book).c_str (), &db);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Begin transaction;
    rc = sqlite3_exec (db, "begin;", NULL, NULL, &error);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Update the verse's data. 
    ustring text = double_apostrophy (data);
    project_store_sanitize_line (text);
    char * sql;
    sql = g_strdup_printf ("update '%s' set usfm = '%s' where verse = '%s';", chapter.c_str(), text.c_str(), verse.c_str());
    rc = sqlite3_exec (db, sql, NULL, NULL, &error);
    g_free (sql);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Commit the changes.
    rc = sqlite3_exec (db, "commit;", NULL, NULL, &error);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
  }
  catch (exception & ex)
  {
    gw_critical (ex.what ());
  }
  // Close connection.
  sqlite3_close (db);
  // Timestamp.
  unsigned int timestamp = time (0);
  project_update_book (project, book, timestamp);
}


void project_update_book (const ustring& project, const ustring& book, unsigned int timestamp)
// Sets flags/variables that indicate this book has been updated.
{
  // Some variables.  
  sqlite3 *db;
  int rc;
  char *error = NULL;
  try
  {
    // Connect to the database.
    rc = sqlite3_open (project_filename (project).c_str (), &db);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Variable.
    char * sql;
    // Delete the timestamp.
    sql = g_strdup_printf ("delete from idx;");
    rc = sqlite3_exec (db, sql, NULL, NULL, &error);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Store timestamp
    sql = g_strdup_printf ("insert into idx values (%d)", timestamp);
    rc = sqlite3_exec (db, sql, NULL, NULL, &error);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Set updated flag for synchronization, if book given.
    if (!book.empty()) {
      sql = g_strdup_printf ("update sync set updated = %d where book = '%s';", 1, book.c_str());
      rc = sqlite3_exec (db, sql, NULL, NULL, &error);
      if (rc) {
        throw runtime_error (sqlite3_errmsg(db));
      }    
    }
    // Free memory.
    g_free (sql);
  }
  catch (exception & ex)
  {
    gw_critical (ex.what ());
  }
  // Close connection.
  sqlite3_close (db);
}


ustring project_retrieve_verse_extended (const ustring& project, const ustring& book, unsigned int chapter, const ustring& verse)
/*
This function will be called when the exact verse was not found in the text.
E.g. it requested verse "1-2", and the text happens to have verse "1" and
verse "2", but not the combined verse. This extended function handles these
and similar cases.
This is roughly the strategy to be followed to get the right verse.
- The requested verse may have the a or b suffix, e.g. verse 4a.
- Therefore use a system of "half" verses.
- Create a vector with all the half verses requested.
- Create sets with all the half verses that are in a particular verse, e.g.
  v 1-2 will contain 1a and 1b, and v 3-5 contains 3a, 3b, 4a, 4b, 5a, 5b.
- Take any set that contains any of the requested half verses and get the 
  text(s) of the verse(s).
*/
{
  // Holds the verse text we will retrieve.
  ustring line;
  
  // Get the requested half-verses.
  vector<int> requested_verses = verses_encode (verse);

  // Get all verses in this chapter.
  vector <ustring> all_verses = project_get_verses (project, book, chapter);

  // Get the sets with the half-verses of each available verse in this chapter.
  vector< set<int> > available_verses_sets;
  for (unsigned int i = 0; i < all_verses.size (); i++) {
    vector<int> verses_v = verses_encode (all_verses[i]);
    set<int> verses_s (verses_v.begin(), verses_v.end());
    available_verses_sets.push_back (verses_s);
  }

  // Retrieve any verse that relates to the verse we look for.
  for (unsigned int a = 0; a < available_verses_sets.size(); a++) {
    for (unsigned int r = 0; r < requested_verses.size(); r++) {
      if (available_verses_sets[a].find (requested_verses[r]) != available_verses_sets[a].end()) {
        if (!line.empty ()) 
          line.append ("\n");
        line.append (project_retrieve_verse (project, book, chapter, all_verses[a]));
      }
    }
  }

  // Return whatever we got.
  return line;   
}


ustring project_retrieve_verse (const ustring& project, const ustring& book, unsigned int chapter, const ustring& verse)
{
  // Holds the retrieved verse.
  ustring line;
  // Database variables.  
  sqlite3 *db;
  int rc;
  char *error = NULL;
  try
  {
    // Open database.
    rc = sqlite3_open(project_book_filename (project, book).c_str (), &db);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    sqlite3_busy_timeout (db, 1000);
    // Read the verse.    
    SqliteReader sqlitereader (0);
    char * sql;
    sql = g_strdup_printf ("select usfm from '%d' where verse = '%s';", chapter, verse.c_str());
    rc = sqlite3_exec(db, sql, sqlitereader.callback, &sqlitereader, &error);
    g_free (sql);
    if (rc != SQLITE_OK) {
      throw runtime_error (error);
    }
    if ((sqlitereader.ustring0.size() > 0)) {
      line = sqlitereader.ustring0[0];
    }
  }
  catch (exception & ex)
  {
    gw_critical (ex.what ());
  }
  // Close connection.  
  sqlite3_close (db);
  // If the verse was not found, use extended retrieval mechanism to get it.
  if (line.empty()) {
    line = project_retrieve_verse_extended (project, book, chapter, verse);
  }
  // Return the data.
  return line;
}


vector<ustring> project_retrieve_chapter (const ustring& project, const ustring& book, unsigned int chapter)
{
  // Holds the chapter.
  vector<ustring> result;
  // Database variables.  
  sqlite3 *db;
  int rc;
  char *error = NULL;
  try
  {
    // Open database.
    rc = sqlite3_open(project_book_filename (project, book).c_str (), &db);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    sqlite3_busy_timeout (db, 1000);
    // Read the chapter including the sequence of the verses.
    SqliteReader sqlitereader (0);
    char * sql;
    sql = g_strdup_printf ("select usfm, sequence from '%d';", chapter);
    rc = sqlite3_exec(db, sql, sqlitereader.callback, &sqlitereader, &error);
    g_free (sql);
    if (rc != SQLITE_OK) {
      throw runtime_error (error);
    }
    vector<ustring> lines (sqlitereader.ustring0.begin(), sqlitereader.ustring0.end());
    // Verses have been stored in the database before. 
    // We cannot be sure however that the verses will be retrieved in the order
    // they were stored. Some factors cause that.
    // For example, while replacing it is possible that only one verse gets 
    // stored. 
    // A sequence variable is used. The verses are sorted on that sequence,
    // so they will be put in the right order.
    vector <unsigned int> sequence;
    for (unsigned int i = 0; i < sqlitereader.ustring1.size(); i++) {
      sequence.push_back (convert_to_int (sqlitereader.ustring1[i]));
    }
    quick_sort (sequence, lines, 0, sequence.size());
    // Make separate lines from it.
    for (unsigned int i = 0; i < lines.size(); i++) {
      ParseLine parseline (lines[i]);
      for (unsigned int i2 = 0; i2 < parseline.lines.size(); i2++) {
        result.push_back (parseline.lines[i2]);
      }
    }
  }
  catch (exception & ex)
  {
    gw_critical (ex.what ());
  }
  // Close connection.  
  sqlite3_close (db);
  // Return the chapter.
  return result;
}


vector<ustring> project_retrieve_book (const ustring& project, const ustring& book)
// Retrieves the text of the whole book.
{
  // Storage for the data.
  vector<ustring> lines;
  // All chapters.
  vector<unsigned int> chapters = project_get_chapters (project, book);
  // Get text of each chapter.
  for (unsigned int i = 0; i < chapters.size(); i++) {
    vector<ustring> ln = project_retrieve_chapter (project, book, chapters[i]);
    for (unsigned int i2 = 0; i2 < ln.size(); i2++) {
      lines.push_back (ln[i2]);
    }
  }
  // Return data.
  return lines;
}


unsigned int project_retrieve_timestamp (const ustring& project)
{
  // Holds the retrieved timestamp.
  unsigned int timestamp = time (0);
  // Database variables.  
  sqlite3 *db;
  int rc;
  char *error = NULL;
  try
  {
    // Open database.
    rc = sqlite3_open(project_filename (project).c_str (), &db);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    sqlite3_busy_timeout (db, 1000);
    // Read the timestamp
    SqliteReader sqlitereader (0);
    char * sql;
    sql = g_strdup_printf ("select timestamp from idx;");
    rc = sqlite3_exec(db, sql, sqlitereader.callback, &sqlitereader, &error);
    g_free (sql);
    if (rc != SQLITE_OK) {
      throw runtime_error (error);
    }
    if ((sqlitereader.ustring0.size() > 0)) {
      timestamp = convert_to_int (sqlitereader.ustring0[0]);
    }
  }
  catch (exception & ex)
  {
    gw_critical (ex.what ());
  }
  // Close connection.  
  sqlite3_close (db);
  // Return the timestamp.
  return timestamp;
}


void project_link_book (const ustring& project, const ustring& book, const ustring& file)
// This does the administration for linking "book" to "file".
{
  // Some variables.  
  sqlite3 *db;
  int rc;
  char *error = NULL;
  try
  {
    // Connect to the database.
    rc = sqlite3_open (project_filename (project).c_str (), &db);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Variable.
    char * sql;
    // Delete any existing link for this book.
    sql = g_strdup_printf ("delete from sync where book = '%s';", book.c_str()); 
    rc = sqlite3_exec (db, sql, NULL, NULL, &error);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Store new link.
    unsigned int filetime = file_get_modification_time (file);
    unsigned int filesize = file_get_size (file);
    sql = g_strdup_printf ("insert into sync values ('%s', %d, '%s', %d, %d)", 
                           book.c_str(), 0, file.c_str(), filetime, filesize);
    rc = sqlite3_exec (db, sql, NULL, NULL, &error);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    // Free memory.
    g_free (sql);
  }
  catch (exception & ex)
  {
    gw_critical (ex.what ());
  }
  // Close connection.
  sqlite3_close (db);
}


ProjectLinksGet::ProjectLinksGet (const ustring& project)
// This retrieves data for all linked books.
{
  sqlite3 *db;
  int rc;
  char *error = NULL;
  try
  {
    rc = sqlite3_open (project_filename (project).c_str (), &db);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    SqliteReader sqlitereader (0);
    char * sql;
    sql = g_strdup_printf ("select book, updated, filename, filetime, filesize from sync;");
    rc = sqlite3_exec(db, sql, sqlitereader.callback, &sqlitereader, &error);
    g_free (sql);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    if (sqlitereader.ustring0.size () > 0) {
      for (unsigned int i = 0; i < sqlitereader.ustring0.size(); i++) {
        books.push_back (sqlitereader.ustring0[i]);
        updateds.push_back (convert_to_bool (sqlitereader.ustring1[i]));
        filenames.push_back (sqlitereader.ustring2[i]);
        filetimes.push_back (convert_to_int (sqlitereader.ustring3[i]));
        filesizes.push_back (convert_to_int (sqlitereader.ustring4[i]));      
      }
    }
  }
  catch (exception & ex)
  {
    gw_critical (ex.what ());
  }
  sqlite3_close (db);
}


vector<ustring> project_get_books (const ustring& project)
// Gives all books in this project.
// Reorders the book according to settings made by user.
{
  vector <ustring> books;
  {
    ReadFiles rf (gw_build_filename (directories_get_projects (), project), "", BOOK_SUFFIX);
    for (unsigned int i = 0; i < rf.files.size(); i++) {
      ustring book (rf.files[i]);
      book = book.substr (0, book.length() - strlen (BOOK_SUFFIX));
      books.push_back (book);
    }
  }
  books_order (project, books);
  return books;
}


vector<unsigned int> project_get_chapters (const ustring& project, const ustring& book)
// Gives all chapters in a book of a project.
{
  vector <unsigned int> chapters;
  sqlite3 *db;
  int rc;
  char *error = NULL;
  try
  {
    rc = sqlite3_open(project_book_filename (project, book).c_str (), &db);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    sqlite3_busy_timeout (db, 1000);
    SqliteReader sqlitereader (0);
    char * sql;
    sql = g_strdup_printf ("select name from sqlite_master;");
    rc = sqlite3_exec(db, sql, sqlitereader.callback, &sqlitereader, &error);
    g_free (sql);
    if (rc != SQLITE_OK) {
      throw runtime_error (error);
    }
    for (unsigned int i = 0; i < sqlitereader.ustring0.size(); i++) {
      chapters.push_back (convert_to_int (sqlitereader.ustring0[i]));
    }
  }
  catch (exception & ex)
  {
    gw_critical (ex.what ());
  }
  sqlite3_close (db);
  sort (chapters.begin(), chapters.end());
  return chapters;
}


vector<ustring> project_get_verses (const ustring& project, const ustring& book, unsigned int chapter)
{
  // Holds the verse numbers.
  vector<ustring> result;
  // Database variables.  
  sqlite3 *db;
  int rc;
  char *error = NULL;
  try
  {
    // Open database.
    rc = sqlite3_open(project_book_filename (project, book).c_str (), &db);
    if (rc) {
      throw runtime_error (sqlite3_errmsg(db));
    }
    sqlite3_busy_timeout (db, 1000);
    // Read the verses including the sequence.
    SqliteReader sqlitereader (0);
    char * sql;
    sql = g_strdup_printf ("select verse, sequence from '%d';", chapter);
    rc = sqlite3_exec(db, sql, sqlitereader.callback, &sqlitereader, &error);
    g_free (sql);
    if (rc != SQLITE_OK) {
      throw runtime_error (error);
    }
    result.assign (sqlitereader.ustring0.begin(), sqlitereader.ustring0.end());
    // Sequence for ordering the verses.
    vector <unsigned int> sequence;
    for (unsigned int i = 0; i < sqlitereader.ustring1.size(); i++) {
      sequence.push_back (convert_to_int (sqlitereader.ustring1[i]));
    }
    quick_sort (sequence, result, 0, sequence.size());
  }
  catch (exception & ex)
  {
    gw_critical (ex.what ());
  }
  // Close connection.  
  sqlite3_close (db);
  // Return the verses.
  return result;
}


bool project_book_exists (const ustring& project, const ustring& book)
{
  ustring filename = project_book_filename (project, book);
  return g_file_test (filename.c_str(), G_FILE_TEST_IS_REGULAR);  
}


void project_vacuum (const ustring& project, unsigned int starttime)
{
  vacuum_database (project_filename (project), starttime);
  vector<ustring> books = project_get_books (project);
  for (unsigned int i = 0; i < books.size(); i++) {
    ustring filename = project_book_filename (project, books[i]);
    vacuum_database (filename, starttime);
  }
}

Generated by  Doxygen 1.6.0   Back to index