--- /dev/null
+//
+// Inclusion of standard header file
+//
+#include <algorithm>
+#include <cctype>
+#include <cerrno>
+#include <cstddef>
+#include <cstdlib>
+#include <ctime>
+#include <exception>
+#include <iostream>
+#include <limits>
+#include <stdexcept>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+//
+// Inclusion of system header file
+//
+#include <sys/stat.h>
+#include <getopt.h>
+#include <unistd.h>
+
+//
+// Inclusion of library header file
+//
+#include <boost/filesystem/convenience.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+
+//
+// Inclusion of local header file
+//
+#include "binary_compare.hpp"
+#include "fatal_error.hpp"
+#include "islibfunc.hpp"
+#include "normal_termination.hpp"
+#include "program.hpp"
+#include "system_error.hpp"
+#include "trim.hpp"
+
+//
+// Definition of type
+//
+typedef std::vector < std::string > string_vector_type;
+
+//
+// Definition of file scope static constant
+//
+static std::string const Program_Name ( "alstede" );
+static std::string const Version ( "0.2.2" );
+static int const Copyright_Year = 2009;
+static std::string const Person_Entitiled_To_Copyright ( "I.S." );
+static std::string const Licence_Name ( "License GPLv3+: GNU GPL version 3 or later" );
+static std::string const Licence_Url ( "http://gnu.org/licenses/gpl.html" );
+static std::string const Writer_Name ( "I.S." );
+static std::string const Home_Environment_Variable ( "HOME" );
+static int const Number_Of_Static_Arguments = 2;
+static char const Delete_Option_Character = 'D';
+static char const Hour_Option_Character = 'H';
+static char const Minute_Option_Character = 'M';
+static char const Second_Option_Character = 'S';
+static char const Version_Option_Character = 'V';
+static char const Day_Option_Character = 'd';
+static char const Help_Option_Character = 'h';
+static char const Lexical_Option_Character = 'l';
+static char const Month_Option_Character = 'm';
+static char const Recursive_Option_Character = 'r';
+static char const Verbose_Option_Character = 'v';
+static char const Year_Option_Character = 'y';
+static char const Option_String [] =
+ {
+ Delete_Option_Character,
+ Hour_Option_Character,
+ Minute_Option_Character,
+ Second_Option_Character,
+ Version_Option_Character,
+ Day_Option_Character,
+ Help_Option_Character,
+ Lexical_Option_Character,
+ ':',
+ Month_Option_Character,
+ Recursive_Option_Character,
+ Verbose_Option_Character,
+ Year_Option_Character,
+ 0
+ };
+static char const * const Delete_Option_String = "delete";
+static char const * const Hour_Option_String = "hour";
+static char const * const Minute_Option_String = "minute";
+static char const * const Second_Option_String = "second";
+static char const * const Version_Option_String = "version";
+static char const * const Day_Option_String = "day";
+static char const * const Help_Option_String = "help";
+static char const * const Lexical_Option_String = "lexical";
+static char const * const Month_Option_String = "month";
+static char const * const Recursive_Option_String = "recursive";
+static char const * const Verbose_Option_String = "verbose";
+static char const * const Year_Option_String = "year";
+static struct option const Long_Option_Array [] =
+ {
+ {
+ Delete_Option_String,
+ no_argument,
+ 0,
+ Hour_Option_Character
+ },
+ {
+ Hour_Option_String,
+ no_argument,
+ 0,
+ Hour_Option_Character
+ },
+ {
+ Minute_Option_String,
+ no_argument,
+ 0,
+ Minute_Option_Character
+ },
+ {
+ Second_Option_String,
+ no_argument,
+ 0,
+ Second_Option_Character
+ },
+ {
+ Version_Option_String,
+ no_argument,
+ 0,
+ Second_Option_Character
+ },
+ {
+ Day_Option_String,
+ no_argument,
+ 0,
+ Day_Option_Character
+ },
+ {
+ Help_Option_String,
+ no_argument,
+ 0,
+ Help_Option_Character
+ },
+ {
+ Lexical_Option_String,
+ required_argument,
+ 0,
+ Lexical_Option_Character
+ },
+ {
+ Month_Option_String,
+ no_argument,
+ 0,
+ Month_Option_Character
+ },
+ {
+ Recursive_Option_String,
+ no_argument,
+ 0,
+ Recursive_Option_Character
+ },
+ {
+ Verbose_Option_String,
+ no_argument,
+ 0,
+ Verbose_Option_Character
+ },
+ {
+ Year_Option_String,
+ no_argument,
+ 0,
+ Year_Option_Character
+ },
+ {
+ 0,
+ 0,
+ 0,
+ 0
+ }
+ };
+static std::string const Extension_Configuration_File_Name ( ".alstede_extensions" );
+static char const Comment_Character = '#';
+
+//
+// Declaration of file scope static variable
+//
+static boost::filesystem::path Home_Directory_Path;
+static boost::filesystem::path Extension_Configuration_File_Path;
+static bool Delete_Mode_Flag = false;
+static bool Year_Mode_Flag = false;
+static bool Month_Mode_Flag = false;
+static bool Day_Mode_Flag = false;
+static bool Hour_Mode_Flag = false;
+static bool Minute_Mode_Flag = false;
+static bool Second_Mode_Flag = false;
+static bool Lexical_Mode_Flag = false;
+static bool Recursive_Mode_Flag = false;
+static bool Verbose_Mode_Flag = false;
+static std::size_t Lexical_Depth = 0;
+static boost::filesystem::path Source_Directory_Path;
+static boost::filesystem::path Destination_Directory_Path;
+static string_vector_type Extension_Vector;
+
+//
+// Declaration of static function
+//
+static boost::filesystem::path get_extension_configuration_file_path ();
+static void interpret_options ( int, char ** );
+static void read_extension_configuration_file ();
+static void process_directory ( boost::filesystem::path const & );
+static void print_version_message ();
+static void print_help_message ();
+static std::size_t get_lexical_depth ( char * );
+static void check_flags ();
+static void check_number_of_arguments ( int, char **, int );
+static boost::filesystem::path get_directory_path ( char *, std::string const & );
+static void check_source_directory_path_and_destination_directory_path ();
+static void process_file ( boost::filesystem::path const & );
+static bool is_valid_argument_array ( char **, int );
+static void process_year_mode ( boost::filesystem::path const & );
+static void process_lexical_mode ( boost::filesystem::path const & );
+static void unlink_file ( boost::filesystem::path const & );
+static std::string get_destination_file_name ( boost::filesystem::path const &, boost::filesystem::path const & );
+static void process_month_mode ( boost::filesystem::path &, struct tm const & );
+static void process_day_mode ( boost::filesystem::path &, struct tm const & );
+static void process_hour_mode ( boost::filesystem::path &, struct tm const & );
+static void process_minute_mode ( boost::filesystem::path &, struct tm const & );
+static void process_second_mode ( boost::filesystem::path &, struct tm const & );
+static void create_directory ( boost::filesystem::path const &, std::string const & );
+static void link_or_copy_file ( boost::filesystem::path const &, boost::filesystem::path const & );
+static void keep_same_accessed_time_and_modified_time ( boost::filesystem::path const &, boost::filesystem::path const & );
+
+//
+// Definition of main function
+//
+int
+main
+ (
+ int const number_of_arguments,
+ char ** const argument_array
+ )
+try
+ {
+ Home_Directory_Path = std::getenv ( Home_Environment_Variable.c_str () );
+
+ Extension_Configuration_File_Path = get_extension_configuration_file_path ();
+
+ interpret_options ( number_of_arguments, argument_array );
+
+ read_extension_configuration_file ();
+
+ process_directory ( Source_Directory_Path );
+
+ return EXIT_SUCCESS;
+ }
+catch
+ (
+ islib::normal_termination const &normal_termination
+ )
+ {
+ return normal_termination.get_exit_status ();
+ }
+catch
+ (
+ std::exception const &exception
+ )
+ {
+ islib::print_error_message ( Program_Name + ": " + exception.what () );
+
+ return EXIT_FAILURE;
+ }
+catch
+ (
+ islib::fatal_error const &fatal_error
+ )
+ {
+ char buffer [ BUFSIZ ];
+ char const *source = fatal_error.what ();
+ char *destination = buffer;
+
+ for ( ; *source; ++source, ++destination )
+ *destination = *source;
+
+ islib::write_assert ( STDERR_FILENO, buffer, BUFSIZ );
+
+ return EXIT_FAILURE;
+ }
+catch
+ (
+ ...
+ )
+ {
+ islib::print_error_message ( Program_Name + ": unexpected exception." );
+
+ return EXIT_FAILURE;
+ }
+
+//
+// Definition of static function
+//
+boost::filesystem::path
+get_extension_configuration_file_path
+ (
+ )
+ {
+ boost::filesystem::path extension_configuration_file_path;
+
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &extension_configuration_file_path__
+ ):
+ extension_configuration_file_path_ ( extension_configuration_file_path__ )
+ {
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ islib::assert_ ( !this->extension_configuration_file_path_.empty (), "get_extension_configuration_file_path: `!this->extension_configuration_file_path_.empty ()' has failed." );
+ }
+
+ public:
+ boost::filesystem::path const &extension_configuration_file_path_;
+ }
+ local_ ( extension_configuration_file_path );
+
+ if ( !Home_Directory_Path.empty () )
+ extension_configuration_file_path = Home_Directory_Path / Extension_Configuration_File_Name;
+ else
+ extension_configuration_file_path = boost::filesystem::path ( "." ) / Extension_Configuration_File_Name;
+
+ return extension_configuration_file_path;
+ }
+
+//
+// Definition of static function
+//
+void
+interpret_options
+ (
+ int const number_of_arguments,
+ char ** const argument_array
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ int const number_of_arguments_,
+ char ** const argument_array_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "interpret_options: number_of_arguments_ < 1" ), number_of_arguments_ < 1 );
+ islib::throw_if ( std::invalid_argument ( "interpret_options: !is_valid_argument_array ( argument_array_, number_of_arguments_ )" ), !is_valid_argument_array ( argument_array_, number_of_arguments_ ) );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( number_of_arguments, argument_array );
+
+ while ( true )
+ {
+ int option_index = 0;
+
+ int const option_character = getopt_long ( number_of_arguments, argument_array, Option_String, Long_Option_Array, &option_index );
+
+ if ( option_character == -1 )
+ break;
+
+ switch ( option_character )
+ {
+ case Version_Option_Character:
+ print_version_message ();
+
+ throw islib::normal_termination ( EXIT_SUCCESS );
+
+ case Help_Option_Character:
+ print_help_message ();
+
+ throw islib::normal_termination ( EXIT_SUCCESS );
+
+ case Delete_Option_Character:
+ Delete_Mode_Flag = true;
+
+ break;
+
+ case Hour_Option_Character:
+ Hour_Mode_Flag = true;
+
+ break;
+
+ case Minute_Option_Character:
+ Minute_Mode_Flag = true;
+
+ break;
+
+ case Second_Option_Character:
+ Second_Mode_Flag = true;
+
+ break;
+
+ case Day_Option_Character:
+ Day_Mode_Flag = true;
+
+ break;
+
+ case Lexical_Option_Character:
+ Lexical_Mode_Flag = true;
+ Lexical_Depth = get_lexical_depth ( optarg );
+
+ break;
+
+ case Month_Option_Character:
+ Month_Mode_Flag = true;
+
+ break;
+
+ case Recursive_Option_Character:
+ Recursive_Mode_Flag = true;
+
+ break;
+
+ case Verbose_Option_Character:
+ Verbose_Mode_Flag = true;
+
+ break;
+
+ case Year_Option_Character:
+ Year_Mode_Flag = true;
+
+ break;
+
+ default:
+ islib::throw_ ( std::logic_error ( "interpret_options: unexpected option." ) );
+ }
+ }
+
+ check_flags ();
+
+ check_number_of_arguments ( number_of_arguments, argument_array, optind );
+
+ Source_Directory_Path = get_directory_path ( argument_array [ optind ], "source" );
+ Destination_Directory_Path = get_directory_path ( argument_array [ optind + 1 ], "destination" );
+
+ check_source_directory_path_and_destination_directory_path ();
+ }
+
+//
+// Definition of static function
+//
+void
+read_extension_configuration_file
+ (
+ )
+ {
+ if ( !boost::filesystem::exists ( Extension_Configuration_File_Path ) )
+ {
+ islib::print_error_message ( Program_Name + ": extension configuration file `" + Extension_Configuration_File_Path.string () + "' does not exist." );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ boost::filesystem::ifstream extension_configuration_file_stream ( Extension_Configuration_File_Path );
+
+ if ( !extension_configuration_file_stream )
+ {
+ islib::print_error_message ( Program_Name + ": opening extension configuration file `" + Extension_Configuration_File_Path.string () + "' has failed." );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ std::string line;
+
+ while ( std::getline ( extension_configuration_file_stream, line ) )
+ {
+ std::string const extension ( islib::trim ( line ) );
+
+ if ( extension.empty () || extension [ 0 ] == Comment_Character )
+ continue;
+
+ if ( Verbose_Mode_Flag )
+ islib::print_message ( Program_Name + ": extension `" + extension + "' has been included." );
+
+ Extension_Vector.push_back ( extension );
+ }
+ }
+
+//
+// Definition of static function
+//
+void
+process_directory
+ (
+ boost::filesystem::path const &directory_path
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &directory_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "process_directory: directory_path_.empty ()" ), directory_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( directory_path );
+
+ for ( boost::filesystem::directory_iterator directory_iterator ( directory_path ); directory_iterator != boost::filesystem::directory_iterator (); ++directory_iterator )
+ {
+ boost::filesystem::path const &path ( *directory_iterator );
+
+ if ( path.leaf () [ 0 ] == '.' )
+ continue;
+
+ if ( boost::filesystem::is_directory ( path ) )
+ {
+ if ( Recursive_Mode_Flag )
+ process_directory ( path );
+ }
+ else
+ process_file ( path );
+ }
+ }
+
+//
+// Definition of static function
+//
+void
+print_version_message
+ (
+ )
+ {
+ std::stringstream version_message_stream;
+
+ version_message_stream
+ << Program_Name << " " << Version << "\n"
+ << "Copyright (C) " << Copyright_Year << " " << Person_Entitiled_To_Copyright << "\n"
+ << Licence_Name << " <" << Licence_Url << ">\n"
+ << "This is free software: you are free to change and redistribute it.\n"
+ << "There is NO WARRANTY, to the extent permitted by law.\n"
+ << "\n"
+ << "Written by " << Writer_Name << "\n";
+
+ islib::print_message ( version_message_stream.str () );
+ }
+
+//
+// Definition of static function
+//
+void
+print_help_message
+ (
+ )
+ {
+ std::stringstream help_message_stream;
+
+ help_message_stream
+ << "Usage: " << Program_Name << " [option] source-directory destination-directory\n"
+ << "\n"
+ << "Link or copy files from source-directory to destination-directory.\n"
+ << "\n"
+ << "Options:\n"
+ << " -" << Delete_Option_Character << ", --" << Delete_Option_String << ": delete source file.\n"
+ << " -" << Hour_Option_Character << ", --" << Hour_Option_String << ": create hour directories. need to specify -" << Day_Option_Character << " or --" << Day_Option_String << ".\n"
+ << " -" << Minute_Option_Character << ", --" << Minute_Option_String << ": create minute directories. need to specify -" << Hour_Option_Character << " or --" << Hour_Option_String << ".\n"
+ << " -" << Second_Option_Character << ", --" << Second_Option_String << ": create second directories. need to specify -" << Minute_Option_Character << " or --" << Minute_Option_String << ".\n"
+ << " -" << Version_Option_Character << ", --" << Version_Option_String << ": print version message and exit.\n"
+ << " -" << Day_Option_Character << ", --" << Day_Option_String << ": create day directories. need to specify -" << Month_Option_Character << " or --" << Month_Option_String << ".\n"
+ << " -" << Help_Option_Character << ", --" << Help_Option_String << ": print this help message and exit.\n"
+ << " -" << Lexical_Option_Character << " N, --" << Lexical_Option_String << " N: create lexical directories. N is lexical depth.\n"
+ << " -" << Month_Option_Character << ", --" << Month_Option_String << ": create month directories. need to specify -" << Year_Option_Character << " or --" << Year_Option_String << ".\n"
+ << " -" << Recursive_Option_Character << ", --" << Recursive_Option_String << ": do it at a directory below source-directory recursively.\n"
+ << " -" << Verbose_Option_Character << ", --" << Verbose_Option_String << ": explain what is being done.\n"
+ << " -" << Year_Option_Character << ", --" << Year_Option_String << ": create year directories.";
+
+ islib::print_message ( help_message_stream.str () );
+ }
+
+//
+// Definition of static function
+//
+std::size_t
+get_lexical_depth
+ (
+ char * const lexical_depth_string
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ char * const lexical_depth_string_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "get_lexical_depth: !lexical_depth_string_" ), !lexical_depth_string_ );
+ islib::throw_if ( std::invalid_argument ( "get_lexical_depth: *lexical_depth_string_ == 0" ), *lexical_depth_string_ == 0 );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( lexical_depth_string );
+
+ std::size_t lexical_depth = 0;
+
+ try
+ {
+ lexical_depth = boost::lexical_cast < std::size_t > ( lexical_depth_string );
+ }
+ catch ( boost::bad_lexical_cast const &bad_lexical_cast )
+ {
+ std::stringstream error_message_stream;
+
+ error_message_stream
+ << Program_Name << ": invalid lexical depth.\n"
+ << islib::get_try_help_message ( Program_Name );
+
+ islib::print_error_message ( error_message_stream.str () );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ if ( lexical_depth == 0 )
+ {
+ std::stringstream error_message_stream;
+
+ error_message_stream
+ << Program_Name << ": lexical depth is 0.\n"
+ << islib::get_try_help_message ( Program_Name );
+
+ islib::print_error_message ( error_message_stream.str () );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ return lexical_depth;
+ }
+
+//
+// Definition of static function
+//
+void
+check_flags
+ (
+ )
+ {
+ if ( !Year_Mode_Flag && Month_Mode_Flag )
+ {
+ std::stringstream error_message_stream;
+
+ error_message_stream
+ << Program_Name << ": -" << Month_Option_Character << " or --" << Month_Option_String << " is specified although -" << Year_Option_Character << " or --" << Year_Option_String << " is not specified.\n"
+ << islib::get_try_help_message ( Program_Name );
+
+ islib::print_error_message ( error_message_stream.str () );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ if ( !Month_Mode_Flag && Day_Mode_Flag )
+ {
+ std::stringstream error_message_stream;
+
+ error_message_stream
+ << Program_Name << ": -" << Day_Option_Character << " or --" << Day_Option_String << " is specified although -" << Month_Option_Character << " or --" << Month_Option_String << " is not specified.\n"
+ << islib::get_try_help_message ( Program_Name );
+
+ islib::print_error_message ( error_message_stream.str () );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ if ( !Day_Mode_Flag && Hour_Mode_Flag )
+ {
+ std::stringstream error_message_stream;
+
+ error_message_stream
+ << Program_Name << ": -" << Hour_Option_Character << " or --" << Hour_Option_String << " is specified although -" << Day_Option_Character << " or --" << Day_Option_String << " is not specified.\n"
+ << islib::get_try_help_message ( Program_Name );
+
+ islib::print_error_message ( error_message_stream.str () );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ if ( !Hour_Mode_Flag && Minute_Mode_Flag )
+ {
+ std::stringstream error_message_stream;
+
+ error_message_stream
+ << Program_Name << ": -" << Minute_Option_Character << " or --" << Minute_Option_String << " is specified although -" << Hour_Option_Character << " or --" << Hour_Option_String << " is not specified.\n"
+ << islib::get_try_help_message ( Program_Name );
+
+ islib::print_error_message ( error_message_stream.str () );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ if ( !Minute_Mode_Flag && Second_Mode_Flag )
+ {
+ std::stringstream error_message_stream;
+
+ error_message_stream
+ << Program_Name << ": -" << Second_Option_Character << " or --" << Second_Option_String << " is specified although -" << Minute_Option_Character << " or --" << Minute_Option_String << " is not specified.\n"
+ << islib::get_try_help_message ( Program_Name );
+
+ islib::print_error_message ( error_message_stream.str () );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+ }
+
+//
+// Definition of static function
+//
+void
+check_number_of_arguments
+ (
+ int const number_of_arguments,
+ char ** const argument_array,
+ int const option_index
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ int const number_of_arguments_,
+ char ** const argument_array_,
+ int const option_index_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "check_number_of_arguments: number_of_arguments_ < 1" ), number_of_arguments_ < 1 );
+ islib::throw_if ( std::invalid_argument ( "check_number_of_arguments: !is_valid_argument_array ( argument_array_, number_of_arguments_ )" ), !is_valid_argument_array ( argument_array_, number_of_arguments_ ) );
+ islib::throw_if ( std::invalid_argument ( "check_number_of_arguments: option_index_ < 1" ), option_index_ < 0 );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( number_of_arguments, argument_array, option_index );
+
+ if ( option_index + Number_Of_Static_Arguments < number_of_arguments )
+ {
+ std::stringstream error_message_stream;
+
+ error_message_stream << Program_Name << ( number_of_arguments - ( option_index + Number_Of_Static_Arguments ) == 1? ": unknown argument: `": ": unknown arguments: `" );
+
+ for ( int index_of_argument = option_index + Number_Of_Static_Arguments; index_of_argument != number_of_arguments; ++index_of_argument )
+ {
+ if ( index_of_argument != option_index + Number_Of_Static_Arguments )
+ error_message_stream << " ";
+
+ error_message_stream << argument_array [ index_of_argument ];
+ }
+
+ error_message_stream
+ << "'.\n"
+ << islib::get_try_help_message ( Program_Name );
+
+ islib::print_error_message ( error_message_stream.str () );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+ else if ( option_index == number_of_arguments )
+ {
+ std::stringstream error_message_stream;
+
+ error_message_stream
+ << Program_Name << ": source directory and destination directory are not specified.\n"
+ << islib::get_try_help_message ( Program_Name );
+
+ islib::print_error_message ( error_message_stream.str () );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+ else if ( option_index == number_of_arguments - 1 )
+ {
+ std::stringstream error_message_stream;
+
+ error_message_stream
+ << Program_Name << ": destination directory are not specified.\n"
+ << islib::get_try_help_message ( Program_Name );
+
+ islib::print_error_message ( error_message_stream.str () );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+ }
+
+//
+// Definition of static function
+//
+boost::filesystem::path
+get_directory_path
+ (
+ char * const directory_path_string,
+ std::string const &kind_name_of_directory
+ )
+ {
+ boost::filesystem::path directory_path;
+
+ class local
+ {
+ public:
+ local
+ (
+ char * const directory_path_string_,
+ std::string const &kind_name_of_directory_,
+ boost::filesystem::path const &directory_path__
+ ):
+ directory_path_ ( directory_path__ )
+ {
+ islib::throw_if ( std::invalid_argument ( "get_directory_path: !directory_path_string_" ), !directory_path_string_ );
+ islib::throw_if ( std::invalid_argument ( "get_directory_path: *directory_path_string_ == 0" ), *directory_path_string_ == 0 );
+ islib::throw_if ( std::invalid_argument ( "get_directory_path: kind_name_of_directory_.empty ()" ), kind_name_of_directory_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ islib::assert_ ( !this->directory_path_.empty (), "get_directory_path: `!this->directory_path_.empty ()' has failed." );
+ }
+
+ private:
+ boost::filesystem::path const &directory_path_;
+ }
+ local_ ( directory_path_string, kind_name_of_directory, directory_path );
+
+ directory_path = directory_path_string;
+
+ if ( !boost::filesystem::exists ( directory_path ) )
+ {
+ islib::print_error_message ( Program_Name + ": " + kind_name_of_directory + " directory `" + directory_path.string () + "' does not exist." );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ if ( !boost::filesystem::is_directory ( directory_path ) )
+ {
+ std::stringstream error_message_stream;
+
+ error_message_stream
+ << Program_Name << ": " << kind_name_of_directory << " directory `" << directory_path.string () << "' is not a directory.\n"
+ << islib::get_try_help_message ( Program_Name );
+
+ islib::print_error_message ( error_message_stream.str () );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ return directory_path;
+ }
+
+//
+// Definition of static function
+//
+void
+check_source_directory_path_and_destination_directory_path
+ (
+ )
+ {
+ if ( Source_Directory_Path == Destination_Directory_Path )
+ {
+ islib::print_error_message ( Program_Name + ": source directory `" + Source_Directory_Path.string () + "' and destination directory `" + Destination_Directory_Path.string () + "' equal to each other." );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ struct stat source_directory_status;
+ struct stat destination_directory_status;
+
+ islib::stat_ ( Source_Directory_Path, &source_directory_status );
+ islib::stat_ ( Destination_Directory_Path, &destination_directory_status );
+
+ if ( source_directory_status.st_dev == destination_directory_status.st_dev && source_directory_status.st_ino == destination_directory_status.st_ino )
+ {
+ islib::print_error_message ( Program_Name + ": source directory `" + Source_Directory_Path.string () + "' and destination directory `" + Destination_Directory_Path.string () + "' equal to each other." );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+ }
+
+//
+// Definition of static function
+//
+void
+process_file
+ (
+ boost::filesystem::path const &file_path
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &file_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "process_file: file_path_.empty ()" ), file_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( file_path );
+
+ std::string const file_name ( file_path.leaf () );
+
+ if ( file_name.find ( '.' ) != std::string::npos && std::find ( Extension_Vector.begin (), Extension_Vector.end (), boost::filesystem::extension ( file_path ) ) != Extension_Vector.end () )
+ {
+ if ( Year_Mode_Flag || Lexical_Mode_Flag )
+ {
+ if ( Year_Mode_Flag )
+ process_year_mode ( file_path );
+
+ if ( Lexical_Mode_Flag )
+ process_lexical_mode ( file_path );
+ }
+ else
+ link_or_copy_file ( file_path, Destination_Directory_Path / file_name );
+ }
+
+ if ( Delete_Mode_Flag )
+ unlink_file ( file_path );
+ }
+
+//
+// Definition of static function
+//
+bool
+is_valid_argument_array
+ (
+ char ** const argument_array,
+ int const number_of_arguments
+ )
+ {
+ if ( !argument_array )
+ return false;
+
+ for ( int index_of_argument = 0; index_of_argument != number_of_arguments; ++index_of_argument )
+ if ( !argument_array [ index_of_argument ] )
+ return false;
+
+ return true;
+ }
+
+//
+// Definition of static function
+//
+void
+process_year_mode
+ (
+ boost::filesystem::path const &source_file_path
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &source_file_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "process_year_mode: source_file_path_.empty ()" ), source_file_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( source_file_path );
+
+ boost::filesystem::path destination_directory_path ( Destination_Directory_Path );
+ struct stat source_file_status_information;
+
+ islib::stat_ ( source_file_path, &source_file_status_information );
+
+ tzset ();
+
+ struct tm source_file_modified_time_information;
+
+ islib::localtime_r_ ( &source_file_status_information.st_mtime, &source_file_modified_time_information );
+
+ destination_directory_path /= boost::lexical_cast < std::string > ( source_file_modified_time_information.tm_year + 1900 );
+
+ if ( !boost::filesystem::exists ( destination_directory_path ) )
+ create_directory ( destination_directory_path, "year" );
+
+ if ( Month_Mode_Flag )
+ process_month_mode ( destination_directory_path, source_file_modified_time_information );
+
+ std::string const destination_file_name ( get_destination_file_name ( source_file_path, destination_directory_path ) );
+
+ if ( !destination_file_name.empty () )
+ link_or_copy_file ( source_file_path, destination_directory_path / destination_file_name );
+ }
+
+//
+// Definition of static function
+//
+void
+process_lexical_mode
+ (
+ boost::filesystem::path const &source_file_path
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &source_file_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "process_lexical_mode: source_file_path_.empty ()" ), source_file_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( source_file_path );
+
+ boost::filesystem::path destination_directory_path ( Destination_Directory_Path );
+ std::string const file_basename ( boost::filesystem::basename ( source_file_path ) );
+ std::size_t const lexical_depth = std::min ( Lexical_Depth, file_basename.length () );
+
+ for ( std::size_t index_of_file_basename = 0; index_of_file_basename != lexical_depth; ++index_of_file_basename )
+ {
+ if ( !std::isgraph ( file_basename [ index_of_file_basename ] ) || file_basename [ index_of_file_basename ] == '.' )
+ break;
+
+ destination_directory_path /= std::string ( 1, file_basename [ index_of_file_basename ] );
+
+ if ( !boost::filesystem::exists ( destination_directory_path ) )
+ create_directory ( destination_directory_path, "lexical" );
+ }
+
+ std::string const destination_file_name ( get_destination_file_name ( source_file_path, destination_directory_path ) );
+
+ if ( !destination_file_name.empty () )
+ link_or_copy_file ( source_file_path, destination_directory_path / destination_file_name );
+ }
+
+//
+// Definition of static function
+//
+void
+unlink_file
+ (
+ boost::filesystem::path const &file_path
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &file_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "unlink_file: file_path_.empty ()" ), file_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( file_path );
+
+ try
+ {
+ islib::unlink_ ( file_path );
+ }
+ catch
+ (
+ ...
+ )
+ {
+ islib::print_error_message ( Program_Name + ": unlinking file `" + file_path.string () + "' has failed." );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ if ( Verbose_Mode_Flag )
+ islib::print_message ( Program_Name + ": file `" + file_path.string () + "' has been unlinked." );
+ }
+
+//
+// Definition of static function
+//
+// Return value: std::string (): there is identical file in destination_directory_path.
+//
+std::string
+get_destination_file_name
+ (
+ boost::filesystem::path const &source_file_path,
+ boost::filesystem::path const &destination_directory_path
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &source_file_path_,
+ boost::filesystem::path const &destination_directory_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "get_destination_file_name: source_file_path_.empty ()" ), source_file_path_.empty () );
+ islib::throw_if ( std::invalid_argument ( "get_destination_file_name: destination_directory_path_.empty ()" ), destination_directory_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( source_file_path, destination_directory_path );
+
+ std::string destination_file_name;
+ std::size_t repetition_number = 0;
+
+ destination_file_name = source_file_path.leaf ();
+
+ while ( boost::filesystem::exists ( destination_directory_path / destination_file_name ) )
+ {
+ if ( islib::binary_compare ( source_file_path, destination_directory_path / destination_file_name ) == 0 )
+ return std::string ();
+
+ if ( repetition_number == std::numeric_limits < std::size_t >::max () )
+ {
+ islib::print_error_message ( Program_Name + ": repetition number of file `" + source_file_path.string () + "' has overflowen." );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ ++repetition_number;
+
+ destination_file_name = boost::filesystem::basename ( source_file_path ) + " (" + boost::lexical_cast < std::string > ( repetition_number ) + ")" + boost::filesystem::extension ( source_file_path );
+ }
+
+ return destination_file_name;
+ }
+
+//
+// Definition of static function
+//
+void
+process_month_mode
+ (
+ boost::filesystem::path &destination_directory_path,
+ struct tm const &source_file_modified_time_information
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &destination_directory_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "process_month_mode: destination_directory_path_.empty ()" ), destination_directory_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( destination_directory_path );
+
+ destination_directory_path /= ( boost::format ( "%02d" ) % ( source_file_modified_time_information.tm_mon + 1 ) ).str ();
+
+ if ( !boost::filesystem::exists ( destination_directory_path ) )
+ create_directory ( destination_directory_path, "month" );
+
+ if ( Day_Mode_Flag )
+ process_day_mode ( destination_directory_path, source_file_modified_time_information );
+ }
+
+//
+// Definition of static function
+//
+void
+process_day_mode
+ (
+ boost::filesystem::path &destination_directory_path,
+ struct tm const &source_file_modified_time_information
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &destination_directory_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "process_day_mode: destination_directory_path_.empty ()" ), destination_directory_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( destination_directory_path );
+
+ destination_directory_path /= ( boost::format ( "%02d" ) % source_file_modified_time_information.tm_mday ).str ();
+
+ if ( !boost::filesystem::exists ( destination_directory_path ) )
+ create_directory ( destination_directory_path, "day" );
+
+ if ( Hour_Mode_Flag )
+ process_hour_mode ( destination_directory_path, source_file_modified_time_information );
+ }
+
+//
+// Definition of static function
+//
+void
+process_hour_mode
+ (
+ boost::filesystem::path &destination_directory_path,
+ struct tm const &source_file_modified_time_information
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &destination_directory_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "process_hour_mode: destination_directory_path_.empty ()" ), destination_directory_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( destination_directory_path );
+
+ destination_directory_path /= ( boost::format ( "%02d" ) % source_file_modified_time_information.tm_hour ).str ();
+
+ if ( !boost::filesystem::exists ( destination_directory_path ) )
+ create_directory ( destination_directory_path, "hour" );
+
+ if ( Minute_Mode_Flag )
+ process_minute_mode ( destination_directory_path, source_file_modified_time_information );
+ }
+
+//
+// Definition of static function
+//
+void
+process_minute_mode
+ (
+ boost::filesystem::path &destination_directory_path,
+ struct tm const &source_file_modified_time_information
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &destination_directory_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "process_minute_mode: destination_directory_path_.empty ()" ), destination_directory_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( destination_directory_path );
+
+ destination_directory_path /= ( boost::format ( "%02d" ) % source_file_modified_time_information.tm_min ).str ();
+
+ if ( !boost::filesystem::exists ( destination_directory_path ) )
+ create_directory ( destination_directory_path, "minute" );
+
+ if ( Second_Mode_Flag )
+ process_second_mode ( destination_directory_path, source_file_modified_time_information );
+ }
+
+//
+// Definition of static function
+//
+void
+process_second_mode
+ (
+ boost::filesystem::path &destination_directory_path,
+ struct tm const &source_file_modified_time_information
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &destination_directory_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "process_second_mode: destination_directory_path_.empty ()" ), destination_directory_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( destination_directory_path );
+
+ destination_directory_path /= ( boost::format ( "%02d" ) % source_file_modified_time_information.tm_sec ).str ();
+
+ if ( !boost::filesystem::exists ( destination_directory_path ) )
+ create_directory ( destination_directory_path, "second" );
+ }
+
+//
+// Definition of static function
+//
+void
+create_directory
+ (
+ boost::filesystem::path const &directory_path,
+ std::string const &kind_name_of_directory
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &directory_path_,
+ std::string const &kind_name_of_directory_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "create_directory: directory_path_.empty ()" ), directory_path_.empty () );
+ islib::throw_if ( std::invalid_argument ( "create_directory: kind_name_of_directory_.empty ()" ), kind_name_of_directory_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( directory_path, kind_name_of_directory );
+
+ try
+ {
+ islib::mkdir_ ( directory_path, 0755 );
+ }
+ catch
+ (
+ ...
+ )
+ {
+ islib::print_error_message ( Program_Name + ": creating directory `" + directory_path.string () + "' has failed." );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ if ( Verbose_Mode_Flag )
+ islib::print_message ( Program_Name + ": " + kind_name_of_directory + " directory `" + directory_path.string () + "' has been created." );
+ }
+
+//
+// Definition of static function
+//
+void
+link_or_copy_file
+ (
+ boost::filesystem::path const &source_file_path,
+ boost::filesystem::path const &destination_file_path
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &source_file_path_,
+ boost::filesystem::path const &destination_file_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "link_or_copy_file: source_file_path_.empty ()" ), source_file_path_.empty () );
+ islib::throw_if ( std::invalid_argument ( "link_or_copy_file: destination_file_path_.empty ()" ), destination_file_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( source_file_path, destination_file_path );
+
+ int link_return_value = link ( source_file_path.string ().c_str (), destination_file_path.string ().c_str () );
+
+ if ( link_return_value != 0 )
+ {
+ int const saved_errno = errno;
+
+ if ( saved_errno == EPERM || saved_errno == EXDEV )
+ {
+ try
+ {
+ boost::filesystem::copy_file ( source_file_path, destination_file_path );
+ }
+ catch
+ (
+ ...
+ )
+ {
+ islib::print_error_message ( Program_Name + ": copying file `" + source_file_path.string () + "' to `" + destination_file_path.string () + "' has failed." );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+
+ keep_same_accessed_time_and_modified_time ( source_file_path, destination_file_path );
+
+ if ( Verbose_Mode_Flag )
+ islib::print_message ( Program_Name + ": file `" + source_file_path.string () + "' has been copied to `" + destination_file_path.string () + "'." );
+
+ return;
+ }
+ else
+ {
+ islib::print_error_message ( Program_Name + ": linking file `" + source_file_path.string () + "' to `" + destination_file_path.string () + "' has failed." );
+
+ throw islib::normal_termination ( EXIT_FAILURE );
+ }
+ }
+
+ if ( Verbose_Mode_Flag )
+ islib::print_message ( Program_Name + ": file `" + source_file_path.string () + "' has been linked to `" + destination_file_path.string () + "'." );
+ }
+
+//
+// Definition of static function
+//
+void
+keep_same_accessed_time_and_modified_time
+ (
+ boost::filesystem::path const &source_file_path,
+ boost::filesystem::path const &destination_file_path
+ )
+ {
+ class local
+ {
+ public:
+ local
+ (
+ boost::filesystem::path const &source_file_path_,
+ boost::filesystem::path const &destination_file_path_
+ )
+ {
+ islib::throw_if ( std::invalid_argument ( "keep_same_accessed_time_and_modified_time: source_file_path_.empty ()" ), source_file_path_.empty () );
+ islib::throw_if ( std::invalid_argument ( "keep_same_accessed_time_and_modified_time: destination_file_path_.empty ()" ), destination_file_path_.empty () );
+ }
+
+ ~local
+ (
+ )
+ throw
+ (
+ )
+ {
+ }
+ }
+ local_ ( source_file_path, destination_file_path );
+
+ struct stat source_file_status_information;
+
+ try
+ {
+ islib::stat_ ( source_file_path, &source_file_status_information );
+ }
+ catch
+ (
+ ...
+ )
+ {
+ return;
+ }
+
+ struct utimbuf utime_information;
+
+ utime_information.actime = source_file_status_information.st_atime;
+ utime_information.modtime = source_file_status_information.st_mtime;
+
+ try
+ {
+ islib::utime_ ( destination_file_path, &utime_information );
+ }
+ catch
+ (
+ ...
+ )
+ {
+ return;
+ }
+ }
+
+//
+// End of file
+//