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

utilities.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 "gwrappers.h"
#include "directories.h"
#include <errno.h>
#include "shell.h"


ustring trim (const ustring & s)
{
  if (s.length () == 0)
    return s;
  // Strip spaces, tabs, new lines, carriage returns.
  size_t beg = s.find_first_not_of (" \t\n\r");
  size_t end = s.find_last_not_of (" \t\n\r");
  // No non-spaces  
  if (beg == string::npos)
    return "";
  return ustring (s, beg, end - beg + 1);
}


#define MY_NUMBERS "0123456789"


ustring number_in_string (const ustring & str)
{
  // Looks for and returns a positive number in a string.
  ustring output = str;
  output.erase (0, output.find_first_of (MY_NUMBERS));
  size_t end_position = output.find_first_not_of (MY_NUMBERS);
  if (end_position != string::npos) {
    output.erase (end_position, output.length ());
  }
  return output;
}


#undef MY_NUMBERS


unsigned int digit_count_in_string (const ustring & str)
{
  unsigned int digitcount = 0;
  string s (str);
  for (unsigned int i = 0; i < s.length(); i++) {
    if (g_ascii_isdigit (guchar (s[i])))
      digitcount++;
  }
  return digitcount;
}


ustring upperCase (const ustring & s)
{
// Make an uppercase copy of s
  string upper (s);
  for (size_t i = 0; i < s.length (); ++i)
    upper[i] = toupper (upper[i]);
  return upper;
}


ustring lowerCase (const ustring & s)
{
// Make a lowercase copy of s
  string lower (s);
  for (size_t i = 0; i < s.length (); ++i)
    lower[i] = tolower (lower[i]);
  return lower;
}


ustring remove_spaces (const ustring & s)
{
  ustring s2 = s;
  size_t spacepos = s2.find (" ");
  while (spacepos != string::npos) {
    s2.erase (spacepos, 1);
    spacepos = s2.find (" ");
  }
  return s2;
}


void create_directory (const ustring & dir)
{
  // Creates directory, with the parents, if need be.
  // Function mkdir could be used (see man 2 mkdir), but this does not allow for 
  // the creation of the parent directories. The core utility mkdir provides
  // this functionality, so is preferred, and used here.
  ustring s;
  s = "mkdir -p" + shell_quote_space (dir);
  system (s.c_str());
}


void remove_directory (const ustring & dir)
// Removes a directory and all its contents.
{
  ustring s;
  s = "rm -rf" + shell_quote_space (dir);
  system (s.c_str());
}


unsigned int convert_to_int (const ustring & str)
{
  unsigned int i = 0;
  istringstream r (str);
  r >> i;
  return i;
}


ustring convert_to_string (int i)
{
  ostringstream r;
  r << i;
  return r.str ();
}


ustring convert_to_string (unsigned int i)
{
  ostringstream r;
  r << i;
  return r.str ();
}


ustring convert_to_string (bool b)
{
  if (b)
    return "1";
  else
    return "0";
}


ustring convert_to_string (double d)
{
  ostringstream r;
  r << d;
  return r.str ();
}


ustring convert_to_string (long unsigned int i)
{
  ostringstream r;
  r << i;
  return r.str ();
}


bool convert_to_bool (const ustring & s)
{
  if (s == "")
    return false;
  if (s == "0")
    return false;
  if (s == "F")
    return false;
  else
    return true;
}


double convert_to_double (const ustring & s)
{
  double result;
  istringstream i (s);
  i >> result;
  return result;
}


ustring convert_bool_to_yes_no (bool b)
{
  if (b) return "yes";
  else return "no";
}

void write_lines (const ustring & file, vector < ustring > &lines)
{
  WriteText wt (file);
  for (unsigned int i = 0; i < lines.size (); i++) {
    wt.text (lines[i]);
    wt.text ("\n");
  }
}


ustring temporary_file (const ustring & filename)
{
  return gw_build_filename (directories_get_temp(), filename);
}


bool string_in_file (const ustring & filename, const ustring & line)
// Returns true if the string "line" is found in file "filename".
{
  // Macintosh OS X, and other BSD-likes, do not have the GNU extensions, so 
  // instead of grep --quiet we write grep -q.
  ustring command = "grep -q" + shell_quote_space (line) + shell_quote_space (filename) + "> /dev/null 2>&1";
  int i = system (command.c_str ());  // Will return exitstatus 0 if a match was found.
  return (i == 0);
}


ustring string_reverse (const ustring & s)
{
  ustring returnvalue;
  for (int i = s.length () - 1; i >= 0; i--)
    returnvalue.append (s.substr (i, 1));
  return returnvalue;
}


ustring double_apostrophy (const ustring & line)
{
  /*
     SQLite needs any apostrophy in the data to be prefixed by another one.
     This function does that.
   */
  ustring returnvalue;
  returnvalue = line;
  size_t offset = returnvalue.find ("'");
  while (offset != string::npos)
  {
    returnvalue.insert (offset, "'");
    offset++;
    offset++;
    offset = returnvalue.find ("'", offset);
  }
  return returnvalue;
}


unsigned int file_get_modification_time (const ustring & filename)
{
  struct stat statbuf;
  stat (filename.c_str(), &statbuf);
  return statbuf.st_mtime;
}


unsigned int file_get_size (const ustring & filename)
{
  struct stat statbuf;
  stat (filename.c_str(), &statbuf);
  return statbuf.st_size;
}


void textbuffer_get_lines (GtkTextBuffer * buffer, vector<ustring>& lines)
// Reads all the lines in the textbuffer.
{
  // We need to know the number of lines.
  int number_of_lines = gtk_text_buffer_get_line_count (buffer);
  GtkTextIter iterator;
  GtkTextIter endofline;
  // Get all lines.
  for (int i = 0; i < number_of_lines; i++) {
    gtk_text_buffer_get_iter_at_line (buffer, &iterator, i);
    // Ensure that also the last line, without a newline character, gets taken.
    if (i + 1 == number_of_lines) {
      gtk_text_buffer_get_end_iter (buffer, &endofline);
    } else {
      gtk_text_buffer_get_iter_at_line (buffer, &endofline, i + 1);
      gtk_text_iter_backward_char (&endofline);
    }
    // Get the line.
    ustring line = gtk_text_buffer_get_text (buffer, &iterator, &endofline, false);
    // Trim and store it.
    lines.push_back (trim (line));
  }  
}


bool replace_text (ustring& line, const ustring& look_for, const ustring& replace_with)
// Replaces some text. Returns true if any replacement was done.
{
  bool replacements_done = false;
  size_t offposition = line.find (look_for);
  while (offposition != string::npos) {
    line.replace (offposition, look_for.length (), replace_with);
    offposition = line.find (look_for, offposition + replace_with.length ());
    replacements_done = true;
  }
  return replacements_done;
}


void quick_swap(ustring& a, ustring& b)
{
  ustring t = a;
  a = b;
  b = t; 
}


void quick_swap(unsigned int& a, unsigned int& b)
{
  unsigned int t = a;
  a = b;
  b = t; 
}


void quick_sort(vector<unsigned int>& one, vector<ustring>& two, unsigned int beg, unsigned int end)
/*
This function is unusual in the sense that it does not sort one container, as
the big majority of sort functions do, but it accepts two containers.
It sorts on the first, and reorders the second container at the same time, 
following the reordering done in the first container.
*/
{
  if (end > beg + 1) {
    unsigned int piv = one[beg];
    unsigned int l = beg + 1;
    unsigned int r = end;
    while (l < r) {
      if (one[l] <= piv) {
        l++;
      } else {
        --r;
        quick_swap(one[l], one[r]);
        quick_swap(two[l], two[r]);
      }
    }
    --l;
    quick_swap(one[l], one[beg]);
    quick_swap(two[l], two[beg]);
    quick_sort(one, two, beg, l);
    quick_sort(one, two, r, end);
  }
}


void quick_sort(vector<ustring>& one, vector<unsigned int>& two, unsigned int beg, unsigned int end)
{
  if (end > beg + 1) {
    ustring piv = one[beg];
    unsigned int l = beg + 1;
    unsigned int r = end;
    while (l < r) {
      if (one[l] <= piv) {
        l++;
      } else {
        --r;
        quick_swap(one[l], one[r]);
        quick_swap(two[l], two[r]);
      }
    }
    --l;
    quick_swap(one[l], one[beg]);
    quick_swap(two[l], two[beg]);
    quick_sort(one, two, beg, l);
    quick_sort(one, two, r, end);
  }
}


void quick_sort(vector<unsigned int>& one, vector<unsigned int>& two, unsigned int beg, unsigned int end)
{
  if (end > beg + 1) {
    unsigned int piv = one[beg];
    unsigned int l = beg + 1;
    unsigned int r = end;
    while (l < r) {
      if (one[l] <= piv) {
        l++;
      } else {
        --r;
        quick_swap(one[l], one[r]);
        quick_swap(two[l], two[r]);
      }
    }
    --l;
    quick_swap(one[l], one[beg]);
    quick_swap(two[l], two[beg]);
    quick_sort(one, two, beg, l);
    quick_sort(one, two, r, end);
  }
}


gchar * de_windows_notepad (gchar * contents)
// Some Windows textfiles, probably the ones created with Notepad, have 
// the "feature" to put \xEF\xBB\xBF at the start of the file.
// This function removes those characters.
{
  gchar * returnvalue = contents;
  char *ef_bb_bf = g_strstr_len (contents, 3, "\xef\xbb\xbf");
  if (ef_bb_bf) {
    ef_bb_bf += 3;
    returnvalue = g_strdup (ef_bb_bf);
    g_free (contents);
  }
  return returnvalue;
}


ustring spaces (unsigned int count)
// Returns "count" spaces.
{
  ustring space;
  for (unsigned int i = 0; i < count; i++)
    space.append (" ");
  return space;
}


ReadDirectories::ReadDirectories (const ustring & path, const ustring & prefix,
                                  const ustring & suffix)
{
  // Reads the directories in directory "path" that end on "suffix".
  // It does not return regular files.
  try
  {
    GDir *dir = g_dir_open (path.c_str(), 0, NULL);
    const gchar *s;
    vector <ustring> entries;
    while ((s = g_dir_read_name (dir)) != NULL)
      entries.push_back (s);
    g_dir_close (dir);    
    for (unsigned int i = 0; i < entries.size (); i++) {
      if (g_str_has_suffix (entries[i].c_str(), suffix.c_str()))
        if (g_str_has_prefix (entries[i].c_str(), prefix.c_str()))
          if (g_file_test (gw_build_filename (path, entries[i]).c_str(),  G_FILE_TEST_IS_DIR))
            directories.push_back (entries[i]);
    }
  }
  catch (...)
  {
  }
}


ReadDirectories::~ReadDirectories ()
{
}


ReadFiles::ReadFiles (const ustring & path, const ustring & prefix,
                      const ustring & suffix)
{
  // Reads the regular files in directory "path" that end on "suffix".
  // It does not return directories.
  try
  {
    GDir *dir = g_dir_open (path.c_str(), 0, NULL);
    const gchar *s;
    vector <ustring> entries;
    while ((s = g_dir_read_name (dir)) != NULL)
      entries.push_back (s);
    g_dir_close (dir);    
    for (unsigned int i = 0; i < entries.size (); i++) {
      if (g_str_has_suffix (entries[i].c_str(), suffix.c_str()))
        if (g_str_has_prefix (entries[i].c_str(), prefix.c_str()))
          if (!g_file_test (gw_build_filename (path, entries[i]).c_str(), G_FILE_TEST_IS_DIR))
            files.push_back (entries[i]);
    }
  }
  catch (...)
  {
  }
}


ReadFiles::~ReadFiles ()
{
}


ReadText::ReadText (const ustring & file, bool silent, bool trimming)
{
  // Reads the text and stores it line by line, trimmed, into "lines".
  // If "silent" is true, then no exception will be thrown in case of an error.
  // The lines will be trimmed if "trimming" is true.
  ifstream in (file.c_str ());
  if (!in) {
    if (!silent) {
      cerr << "Error opening file " << file << endl;
      throw;
    }
    return;
  }
  string s;
  while (getline (in, s)) {
    if (trimming)
      s = trim (s);
    lines.push_back (s);
  }
}


ReadText::~ReadText ()
{
}


WriteText::WriteText (const ustring & file)
{
/*
  This opens a textfile for writing.
  At first it uses the streaming system (e.g. out << text << endl), but because
  this causes crashes on Macintosh when writing Unicode, this has been changed
  to regular Linux calls: open, write.
*/
  fd = open (file.c_str (), O_CREAT | O_WRONLY | O_TRUNC, 0666);
  if (fd < 0)
  {
    gw_critical ("Error creating file " + file);
    perror (NULL);
  }
}


WriteText::~WriteText ()
{
  close (fd);
}


void WriteText::text (const ustring& text)
// Write the text. For calculating the lenght, do not use text.length(),
// because this gives the number of unicode characters, not the length in bytes. 
// Use strlen () instead.
{
  write (fd, text.c_str(), strlen (text.c_str()));
}


Parse::Parse (const ustring & line, bool remove_punctuation)
// Parses a line of text in its separate words.
{
  ustring processed_line;
  processed_line = trim (line);
  processed_line.append (" ");
  size_t spaceposition;
  spaceposition = processed_line.find (" ");
  while (spaceposition != string::npos) {
    ustring word = processed_line.substr (0, spaceposition);
    if (remove_punctuation) {
      string::size_type location = word.find_last_of (".,;:");
      if (location != string::npos)
        word = word.substr (0, location);
    }
    words.push_back (word);
    processed_line.erase (0, spaceposition + 1);
    spaceposition = processed_line.find (" ");
  }
}


Parse::~Parse ()
{
}


ParseWords::ParseWords (const ustring& text)
// Parses a line of text in its separate words.
// Note: This is comparable to object Parse, but does a better job.
{
  // Load text into buffer.
  ustring text2 (text);
  text2.append (" ");
  GtkTextBuffer * textbuffer;
  textbuffer = gtk_text_buffer_new (NULL);
  gtk_text_buffer_set_text (textbuffer, text2.c_str(), -1);
  // Iterators.  
  GtkTextIter startiter, enditer;
  // Parse into separate words.
  gtk_text_buffer_get_start_iter (textbuffer, &enditer);
  while (gtk_text_iter_forward_word_end (&enditer)) {
    startiter = enditer;
    gtk_text_iter_backward_word_start (&startiter);    
    GtkTextIter iter = startiter;
    ustring word = gtk_text_iter_get_text (&startiter, &enditer);
    words.push_back (word);
  }
  // Free memory
  g_object_unref (textbuffer);
}


ParseLine::ParseLine (const ustring & text)
// Parses text in its separate lines.
{
  ustring processed_line;
  processed_line = trim (text);
  size_t newlineposition;
  newlineposition = processed_line.find ("\n");
  while (newlineposition != string::npos) {
    ustring word = processed_line.substr (0, newlineposition);
    lines.push_back (trim(word));
    processed_line.erase (0, newlineposition + 1);
    processed_line = trim (processed_line);
    newlineposition = processed_line.find ("\n");
  }
  if (!processed_line.empty())
    lines.push_back(trim(processed_line));
}


ParseLine::~ParseLine ()
{
}

Generated by  Doxygen 1.6.0   Back to index