OSDN Git Service

Remove Makefile.
[alstede/alstede.git] / alstede.cpp
1 //
2 // Inclusion of standard header file
3 //
4 #include <algorithm>
5 #include <cctype>
6 #include <cerrno>
7 #include <cstddef>
8 #include <cstdlib>
9 #include <ctime>
10 #include <exception>
11 #include <iostream>
12 #include <limits>
13 #include <stdexcept>
14 #include <sstream>
15 #include <string>
16 #include <utility>
17 #include <vector>
18
19 //
20 // Inclusion of system header file
21 //
22 #include <sys/stat.h>
23 #include <getopt.h>
24 #include <unistd.h>
25
26 //
27 // Inclusion of library header file
28 //
29 #include <boost/filesystem/convenience.hpp>
30 #include <boost/filesystem/fstream.hpp>
31 #include <boost/filesystem/operations.hpp>
32 #include <boost/filesystem/path.hpp>
33 #include <boost/format.hpp>
34 #include <boost/lexical_cast.hpp>
35
36 //
37 // Inclusion of local header file
38 //
39 #include "binary_compare.hpp"
40 #include "fatal_error.hpp"
41 #include "islibfunc.hpp"
42 #include "normal_termination.hpp"
43 #include "program.hpp"
44 #include "system_error.hpp"
45 #include "trim.hpp"
46
47 //
48 // Definition of type
49 //
50 typedef std::vector < std::string > string_vector_type;
51
52 //
53 // Definition of file scope static constant
54 //
55 static std::string const Program_Name ( "alstede" );
56 static std::string const Version ( "0.2.3" );
57 static int const Copyright_Year = 2009;
58 static std::string const Person_Entitiled_To_Copyright ( "I.S." );
59 static std::string const Licence_Name ( "License GPLv3+: GNU GPL version 3 or later" );
60 static std::string const Licence_Url ( "http://gnu.org/licenses/gpl.html" );
61 static std::string const Writer_Name ( "I.S." );
62 static std::string const Home_Environment_Variable ( "HOME" );
63 static int const Number_Of_Static_Arguments = 2;
64 static char const Delete_Option_Character = 'D';
65 static char const Hour_Option_Character = 'H';
66 static char const Minute_Option_Character = 'M';
67 static char const Second_Option_Character = 'S';
68 static char const Version_Option_Character = 'V';
69 static char const Day_Option_Character = 'd';
70 static char const Help_Option_Character = 'h';
71 static char const Lexical_Option_Character = 'l';
72 static char const Month_Option_Character = 'm';
73 static char const Recursive_Option_Character = 'r';
74 static char const Verbose_Option_Character = 'v';
75 static char const Year_Option_Character = 'y';
76 static char const Option_String [] =
77   {
78     Delete_Option_Character,
79     Hour_Option_Character,
80     Minute_Option_Character,
81     Second_Option_Character,
82     Version_Option_Character,
83     Day_Option_Character,
84     Help_Option_Character,
85     Lexical_Option_Character,
86     ':',
87     Month_Option_Character,
88     Recursive_Option_Character,
89     Verbose_Option_Character,
90     Year_Option_Character,
91     0
92   };
93 static char const * const Delete_Option_String = "delete";
94 static char const * const Hour_Option_String = "hour";
95 static char const * const Minute_Option_String = "minute";
96 static char const * const Second_Option_String = "second";
97 static char const * const Version_Option_String = "version";
98 static char const * const Day_Option_String = "day";
99 static char const * const Help_Option_String = "help";
100 static char const * const Lexical_Option_String = "lexical";
101 static char const * const Month_Option_String = "month";
102 static char const * const Recursive_Option_String = "recursive";
103 static char const * const Verbose_Option_String = "verbose";
104 static char const * const Year_Option_String = "year";
105 static struct option const Long_Option_Array [] =
106   {
107     {
108       Delete_Option_String,
109       no_argument,
110       0,
111       Hour_Option_Character
112     },
113     {
114       Hour_Option_String,
115       no_argument,
116       0,
117       Hour_Option_Character
118     },
119     {
120       Minute_Option_String,
121       no_argument,
122       0,
123       Minute_Option_Character
124     },
125     {
126       Second_Option_String,
127       no_argument,
128       0,
129       Second_Option_Character
130     },
131     {
132       Version_Option_String,
133       no_argument,
134       0,
135       Second_Option_Character
136     },
137     {
138       Day_Option_String,
139       no_argument,
140       0,
141       Day_Option_Character
142     },
143     {
144       Help_Option_String,
145       no_argument,
146       0,
147       Help_Option_Character
148     },
149     {
150       Lexical_Option_String,
151       required_argument,
152       0,
153       Lexical_Option_Character
154     },
155     {
156       Month_Option_String,
157       no_argument,
158       0,
159       Month_Option_Character
160     },
161     {
162       Recursive_Option_String,
163       no_argument,
164       0,
165       Recursive_Option_Character
166     },
167     {
168       Verbose_Option_String,
169       no_argument,
170       0,
171       Verbose_Option_Character
172     },
173     {
174       Year_Option_String,
175       no_argument,
176       0,
177       Year_Option_Character
178     },
179     {
180       0,
181       0,
182       0,
183       0
184     }
185   };
186 static std::string const Extension_Configuration_File_Name ( ".alstede_extensions" );
187 static char const Comment_Character = '#';
188
189 //
190 // Declaration of file scope static variable
191 //
192 static boost::filesystem::path Home_Directory_Path;
193 static boost::filesystem::path Extension_Configuration_File_Path;
194 static bool Delete_Mode_Flag = false;
195 static bool Year_Mode_Flag = false;
196 static bool Month_Mode_Flag = false;
197 static bool Day_Mode_Flag = false;
198 static bool Hour_Mode_Flag = false;
199 static bool Minute_Mode_Flag = false;
200 static bool Second_Mode_Flag = false;
201 static bool Lexical_Mode_Flag = false;
202 static bool Recursive_Mode_Flag = false;
203 static bool Verbose_Mode_Flag = false;
204 static std::size_t Lexical_Depth = 0;
205 static boost::filesystem::path Source_Directory_Path;
206 static boost::filesystem::path Destination_Directory_Path;
207 static string_vector_type Extension_Vector;
208
209 //
210 // Declaration of static function
211 //
212 static boost::filesystem::path get_extension_configuration_file_path ();
213 static void interpret_options ( int, char ** );
214 static void read_extension_configuration_file ();
215 static void process_directory ( boost::filesystem::path const & );
216 static void print_version_message ();
217 static void print_help_message ();
218 static std::size_t get_lexical_depth ( char * );
219 static void check_flags ();
220 static void check_number_of_arguments ( int, char **, int );
221 static boost::filesystem::path get_directory_path ( char *, std::string const & );
222 static void check_source_directory_path_and_destination_directory_path ();
223 static void process_file ( boost::filesystem::path const & );
224 static bool is_valid_argument_array ( char **, int );
225 static void process_year_mode ( boost::filesystem::path const & );
226 static void process_lexical_mode ( boost::filesystem::path const & );
227 static void unlink_file ( boost::filesystem::path const & );
228 static std::string get_destination_file_name ( boost::filesystem::path const &, boost::filesystem::path const & );
229 static void process_month_mode ( boost::filesystem::path &, struct tm const & );
230 static void process_day_mode ( boost::filesystem::path &, struct tm const & );
231 static void process_hour_mode ( boost::filesystem::path &, struct tm const & );
232 static void process_minute_mode ( boost::filesystem::path &, struct tm const & );
233 static void process_second_mode ( boost::filesystem::path &, struct tm const & );
234 static void create_directory ( boost::filesystem::path const &, std::string const & );
235 static void link_or_copy_file ( boost::filesystem::path const &, boost::filesystem::path const & );
236 static void keep_same_accessed_time_and_modified_time ( boost::filesystem::path const &, boost::filesystem::path const & );
237
238 //
239 // Definition of main function
240 //
241 int
242 main
243   (
244     int const number_of_arguments,
245     char ** const argument_array
246   )
247 try
248   {
249     Home_Directory_Path = std::getenv ( Home_Environment_Variable.c_str () );
250
251     Extension_Configuration_File_Path = get_extension_configuration_file_path ();
252
253     interpret_options ( number_of_arguments, argument_array );
254
255     read_extension_configuration_file ();
256
257     process_directory ( Source_Directory_Path );
258
259     return EXIT_SUCCESS;
260   }
261 catch
262   (
263     islib::normal_termination const &normal_termination
264   )
265   {
266     return normal_termination.get_exit_status ();
267   }
268 catch
269   (
270     std::exception const &exception
271   )
272   {
273     islib::print_error_message ( Program_Name + ": " + exception.what () );
274
275     return EXIT_FAILURE;
276   }
277 catch
278   (
279     islib::fatal_error const &fatal_error
280   )
281   {
282     char buffer [ BUFSIZ ];
283     char const *source = fatal_error.what ();
284     char *destination = buffer;
285
286     for ( ; *source; ++source, ++destination )
287       *destination = *source;
288
289     islib::write_assert ( STDERR_FILENO, buffer, BUFSIZ );
290
291     return EXIT_FAILURE;
292   }
293 catch
294   (
295     ...
296   )
297   {
298     islib::print_error_message ( Program_Name + ": unexpected exception." );
299
300     return EXIT_FAILURE;
301   }
302
303 //
304 // Definition of static function
305 //
306 boost::filesystem::path
307 get_extension_configuration_file_path
308   (
309   )
310   {
311     boost::filesystem::path extension_configuration_file_path;
312
313     class local
314       {
315       public:
316         local
317           (
318             boost::filesystem::path const &extension_configuration_file_path__
319           ):
320           extension_configuration_file_path_ ( extension_configuration_file_path__ )
321           {
322           }
323         
324         ~local
325           (
326           )
327           throw
328             (
329             )
330           {
331             islib::assert_ ( !this->extension_configuration_file_path_.empty (), "get_extension_configuration_file_path: `!this->extension_configuration_file_path_.empty ()' has failed." );
332           }
333
334       public:
335         boost::filesystem::path const &extension_configuration_file_path_;
336       }
337     local_ ( extension_configuration_file_path );
338
339     if ( !Home_Directory_Path.empty () )
340       extension_configuration_file_path = Home_Directory_Path / Extension_Configuration_File_Name;
341     else
342       extension_configuration_file_path = boost::filesystem::path ( "." ) / Extension_Configuration_File_Name;
343
344     return extension_configuration_file_path;
345   }
346
347 //
348 // Definition of static function
349 //
350 void
351 interpret_options
352   (
353     int const number_of_arguments,
354     char ** const argument_array
355   )
356   {
357     class local
358       {
359       public:
360         local
361           (
362             int const number_of_arguments_,
363             char ** const argument_array_
364           )
365           {
366             islib::throw_if ( std::invalid_argument ( "interpret_options: number_of_arguments_ < 1" ), number_of_arguments_ < 1 );
367             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_ ) );
368           }
369         
370         ~local
371           (
372           )
373           throw
374             (
375             )
376           {
377           }
378       }
379     local_ ( number_of_arguments, argument_array );
380
381     while ( true )
382       {
383         int option_index = 0;
384
385         int const option_character = getopt_long ( number_of_arguments, argument_array, Option_String, Long_Option_Array, &option_index );
386
387         if ( option_character == -1 )
388           break;
389
390         switch ( option_character )
391           {
392           case Version_Option_Character:
393             print_version_message ();
394
395             throw islib::normal_termination ( EXIT_SUCCESS );
396
397           case Help_Option_Character:
398             print_help_message ();
399
400             throw islib::normal_termination ( EXIT_SUCCESS );
401
402           case Delete_Option_Character:
403             Delete_Mode_Flag = true;
404
405             break;
406
407           case Hour_Option_Character:
408             Hour_Mode_Flag = true;
409
410             break;
411
412           case Minute_Option_Character:
413             Minute_Mode_Flag = true;
414
415             break;
416
417           case Second_Option_Character:
418             Second_Mode_Flag = true;
419
420             break;
421
422           case Day_Option_Character:
423             Day_Mode_Flag = true;
424
425             break;
426
427           case Lexical_Option_Character:
428             Lexical_Mode_Flag = true;
429             Lexical_Depth = get_lexical_depth ( optarg );
430
431             break;
432
433           case Month_Option_Character:
434             Month_Mode_Flag = true;
435
436             break;
437
438           case Recursive_Option_Character:
439             Recursive_Mode_Flag = true;
440
441             break;
442
443           case Verbose_Option_Character:
444             Verbose_Mode_Flag = true;
445
446             break;
447
448           case Year_Option_Character:
449             Year_Mode_Flag = true;
450
451             break;
452
453           default:
454             islib::throw_ ( std::logic_error ( "interpret_options: unexpected option." ) );
455           }
456       }
457
458     check_flags ();
459
460     check_number_of_arguments ( number_of_arguments, argument_array, optind );
461
462     Source_Directory_Path = get_directory_path ( argument_array [ optind ], "source" );
463     Destination_Directory_Path = get_directory_path ( argument_array [ optind + 1 ], "destination" );
464
465     check_source_directory_path_and_destination_directory_path ();
466   }
467
468 //
469 // Definition of static function
470 //
471 void
472 read_extension_configuration_file
473   (
474   )
475   {
476     if ( !boost::filesystem::exists ( Extension_Configuration_File_Path ) )
477       {
478         islib::print_error_message ( Program_Name + ": extension configuration file `" + Extension_Configuration_File_Path.string () + "' does not exist." );
479
480         throw islib::normal_termination ( EXIT_FAILURE );
481       }
482
483     boost::filesystem::ifstream extension_configuration_file_stream ( Extension_Configuration_File_Path );
484
485     if ( !extension_configuration_file_stream )
486       {
487         islib::print_error_message ( Program_Name + ": opening extension configuration file `" + Extension_Configuration_File_Path.string () + "' has failed." );
488
489         throw islib::normal_termination ( EXIT_FAILURE );
490       }
491
492     std::string line;
493
494     while ( std::getline ( extension_configuration_file_stream, line ) )
495       {
496         std::string const extension ( islib::trim ( line ) );
497
498         if ( extension.empty () || extension [ 0 ] == Comment_Character )
499           continue;
500
501         if ( Verbose_Mode_Flag )
502           islib::print_message ( Program_Name + ": extension `" + extension + "' has been included." );
503
504         Extension_Vector.push_back ( extension );
505       }
506   }
507
508 //
509 // Definition of static function
510 //
511 void
512 process_directory
513   (
514     boost::filesystem::path const &directory_path
515   )
516   {
517     class local
518       {
519       public:
520         local
521           (
522             boost::filesystem::path const &directory_path_
523           )
524           {
525             islib::throw_if ( std::invalid_argument ( "process_directory: directory_path_.empty ()" ), directory_path_.empty () );
526           }
527         
528         ~local
529           (
530           )
531           throw
532             (
533             )
534           {
535           }
536       }
537     local_ ( directory_path );
538
539     for ( boost::filesystem::directory_iterator directory_iterator ( directory_path ); directory_iterator != boost::filesystem::directory_iterator (); ++directory_iterator )
540       {
541         boost::filesystem::path const &path ( *directory_iterator );
542
543         if ( path.leaf () [ 0 ] == '.' )
544           continue;
545
546         if ( boost::filesystem::is_directory ( path ) )
547           {
548             if ( Recursive_Mode_Flag )
549               process_directory ( path );
550           }
551         else
552           process_file ( path );
553       }
554   }
555
556 //
557 // Definition of static function
558 //
559 void
560 print_version_message
561   (
562   )
563   {
564     std::stringstream version_message_stream;
565
566     version_message_stream
567       << Program_Name << " " << Version << "\n"
568       << "Copyright (C) " << Copyright_Year << " " << Person_Entitiled_To_Copyright << "\n"
569       << Licence_Name << " <" << Licence_Url << ">\n"
570       << "This is free software: you are free to change and redistribute it.\n"
571       << "There is NO WARRANTY, to the extent permitted by law.\n"
572       << "\n"
573       << "Written by " << Writer_Name << "\n";
574
575     islib::print_message ( version_message_stream.str () );
576   }
577
578 //
579 // Definition of static function
580 //
581 void
582 print_help_message
583   (
584   )
585   {
586     std::stringstream help_message_stream;
587
588     help_message_stream
589       << "Usage: " << Program_Name << " [option] source-directory destination-directory\n"
590       << "\n"
591       << "Link or copy files from source-directory to destination-directory.\n"
592       << "\n"
593       << "Options:\n"
594       << "  -" << Delete_Option_Character << ", --" << Delete_Option_String << ": delete source file.\n"
595       << "  -" << Hour_Option_Character << ", --" << Hour_Option_String << ": create hour directories. need to specify -" << Day_Option_Character << " or --" << Day_Option_String << ".\n"
596       << "  -" << Minute_Option_Character << ", --" << Minute_Option_String << ": create minute directories. need to specify -" << Hour_Option_Character << " or --" << Hour_Option_String << ".\n"
597       << "  -" << Second_Option_Character << ", --" << Second_Option_String << ": create second directories. need to specify -" << Minute_Option_Character << " or --" << Minute_Option_String << ".\n"
598       << "  -" << Version_Option_Character << ", --" << Version_Option_String << ": print version message and exit.\n"
599       << "  -" << Day_Option_Character << ", --" << Day_Option_String << ": create day directories. need to specify -" << Month_Option_Character << " or --" << Month_Option_String << ".\n"
600       << "  -" << Help_Option_Character << ", --" << Help_Option_String << ": print this help message and exit.\n"
601       << "  -" << Lexical_Option_Character << " N, --" << Lexical_Option_String << " N: create lexical directories. N is lexical depth.\n"
602       << "  -" << Month_Option_Character << ", --" << Month_Option_String << ": create month directories. need to specify -" << Year_Option_Character << " or --" << Year_Option_String << ".\n"
603       << "  -" << Recursive_Option_Character << ", --" << Recursive_Option_String << ": do it at a directory below source-directory recursively.\n"
604       << "  -" << Verbose_Option_Character << ", --" << Verbose_Option_String << ": explain what is being done.\n"
605       << "  -" << Year_Option_Character << ", --" << Year_Option_String << ": create year directories.";
606
607     islib::print_message ( help_message_stream.str () );
608   }
609
610 //
611 // Definition of static function
612 //
613 std::size_t
614 get_lexical_depth
615   (
616     char * const lexical_depth_string
617   )
618   {
619     class local
620       {
621       public:
622         local
623           (
624             char * const lexical_depth_string_
625           )
626           {
627             islib::throw_if ( std::invalid_argument ( "get_lexical_depth: !lexical_depth_string_" ), !lexical_depth_string_ );
628             islib::throw_if ( std::invalid_argument ( "get_lexical_depth: *lexical_depth_string_ == 0" ), *lexical_depth_string_ == 0 );
629           }
630         
631         ~local
632           (
633           )
634           throw
635             (
636             )
637           {
638           }
639       }
640     local_ ( lexical_depth_string );
641
642     std::size_t lexical_depth = 0;
643
644     try
645       {
646         lexical_depth = boost::lexical_cast < std::size_t > ( lexical_depth_string );
647       }
648     catch ( boost::bad_lexical_cast const &bad_lexical_cast )
649       {
650         std::stringstream error_message_stream;
651
652         error_message_stream
653           << Program_Name << ": invalid lexical depth.\n"
654           << islib::get_try_help_message ( Program_Name );
655
656         islib::print_error_message ( error_message_stream.str () );
657
658         throw islib::normal_termination ( EXIT_FAILURE );
659       }
660
661     if ( lexical_depth == 0 )
662       {
663         std::stringstream error_message_stream;
664
665         error_message_stream
666           << Program_Name << ": lexical depth is 0.\n"
667           << islib::get_try_help_message ( Program_Name );
668
669         islib::print_error_message ( error_message_stream.str () );
670
671         throw islib::normal_termination ( EXIT_FAILURE );
672       }
673
674     return lexical_depth;
675   }
676
677 //
678 // Definition of static function
679 //
680 void
681 check_flags
682   (
683   )
684   {
685     if ( !Year_Mode_Flag && Month_Mode_Flag )
686       {
687         std::stringstream error_message_stream;
688
689         error_message_stream
690           << Program_Name << ": -" << Month_Option_Character << " or --" << Month_Option_String << " is specified although -" << Year_Option_Character << " or --" << Year_Option_String << " is not specified.\n"
691           << islib::get_try_help_message ( Program_Name );
692
693         islib::print_error_message ( error_message_stream.str () );
694
695         throw islib::normal_termination ( EXIT_FAILURE );
696       }
697
698     if ( !Month_Mode_Flag && Day_Mode_Flag )
699       {
700         std::stringstream error_message_stream;
701
702         error_message_stream
703           << Program_Name << ": -" << Day_Option_Character << " or --" << Day_Option_String << " is specified although -" << Month_Option_Character << " or --" << Month_Option_String << " is not specified.\n"
704           << islib::get_try_help_message ( Program_Name );
705
706         islib::print_error_message ( error_message_stream.str () );
707
708         throw islib::normal_termination ( EXIT_FAILURE );
709       }
710
711     if ( !Day_Mode_Flag && Hour_Mode_Flag )
712       {
713         std::stringstream error_message_stream;
714
715         error_message_stream
716           << Program_Name << ": -" << Hour_Option_Character << " or --" << Hour_Option_String << " is specified although -" << Day_Option_Character << " or --" << Day_Option_String << " is not specified.\n"
717           << islib::get_try_help_message ( Program_Name );
718
719         islib::print_error_message ( error_message_stream.str () );
720
721         throw islib::normal_termination ( EXIT_FAILURE );
722       }
723
724     if ( !Hour_Mode_Flag && Minute_Mode_Flag )
725       {
726         std::stringstream error_message_stream;
727
728         error_message_stream
729           << Program_Name << ": -" << Minute_Option_Character << " or --" << Minute_Option_String << " is specified although -" << Hour_Option_Character << " or --" << Hour_Option_String << " is not specified.\n"
730           << islib::get_try_help_message ( Program_Name );
731
732         islib::print_error_message ( error_message_stream.str () );
733
734         throw islib::normal_termination ( EXIT_FAILURE );
735       }
736
737     if ( !Minute_Mode_Flag && Second_Mode_Flag )
738       {
739         std::stringstream error_message_stream;
740
741         error_message_stream
742           << Program_Name << ": -" << Second_Option_Character << " or --" << Second_Option_String << " is specified although -" << Minute_Option_Character << " or --" << Minute_Option_String << " is not specified.\n"
743           << islib::get_try_help_message ( Program_Name );
744
745         islib::print_error_message ( error_message_stream.str () );
746
747         throw islib::normal_termination ( EXIT_FAILURE );
748       }
749   }
750
751 //
752 // Definition of static function
753 //
754 void
755 check_number_of_arguments
756   (
757     int const number_of_arguments,
758     char ** const argument_array,
759     int const option_index
760   )
761   {
762     class local
763       {
764       public:
765         local
766           (
767             int const number_of_arguments_,
768             char ** const argument_array_,
769             int const option_index_
770           )
771           {
772             islib::throw_if ( std::invalid_argument ( "check_number_of_arguments: number_of_arguments_ < 1" ), number_of_arguments_ < 1 );
773             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_ ) );
774             islib::throw_if ( std::invalid_argument ( "check_number_of_arguments: option_index_ < 1" ), option_index_ < 0 );
775           }
776         
777         ~local
778           (
779           )
780           throw
781             (
782             )
783           {
784           }
785       }
786     local_ ( number_of_arguments, argument_array, option_index );
787
788     if ( option_index + Number_Of_Static_Arguments < number_of_arguments )
789       {
790         std::stringstream error_message_stream;
791
792         error_message_stream << Program_Name << ( number_of_arguments - ( option_index + Number_Of_Static_Arguments ) == 1? ": unknown argument: `": ": unknown arguments: `" );
793
794         for ( int index_of_argument = option_index + Number_Of_Static_Arguments; index_of_argument != number_of_arguments; ++index_of_argument )
795           {
796             if ( index_of_argument != option_index + Number_Of_Static_Arguments )
797               error_message_stream << " ";
798
799             error_message_stream << argument_array [ index_of_argument ];
800           }
801
802         error_message_stream
803           << "'.\n"
804           << islib::get_try_help_message ( Program_Name );
805
806         islib::print_error_message ( error_message_stream.str () );
807
808         throw islib::normal_termination ( EXIT_FAILURE );
809       }
810     else if ( option_index == number_of_arguments )
811       {
812         std::stringstream error_message_stream;
813
814         error_message_stream
815           << Program_Name << ": source directory and destination directory are not specified.\n"
816           << islib::get_try_help_message ( Program_Name );
817
818         islib::print_error_message ( error_message_stream.str () );
819
820         throw islib::normal_termination ( EXIT_FAILURE );
821       }
822     else if ( option_index == number_of_arguments - 1 )
823       {
824         std::stringstream error_message_stream;
825
826         error_message_stream
827           << Program_Name << ": destination directory is not specified.\n"
828           << islib::get_try_help_message ( Program_Name );
829
830         islib::print_error_message ( error_message_stream.str () );
831
832         throw islib::normal_termination ( EXIT_FAILURE );
833       }
834   }
835
836 //
837 // Definition of static function
838 //
839 boost::filesystem::path
840 get_directory_path
841   (
842     char * const directory_path_string,
843     std::string const &kind_name_of_directory
844   )
845   {
846     boost::filesystem::path directory_path;
847
848     class local
849       {
850       public:
851         local
852           (
853             char * const directory_path_string_,
854             std::string const &kind_name_of_directory_,
855             boost::filesystem::path const &directory_path__
856           ):
857           directory_path_ ( directory_path__ )
858           {
859             islib::throw_if ( std::invalid_argument ( "get_directory_path: !directory_path_string_" ), !directory_path_string_ );
860             islib::throw_if ( std::invalid_argument ( "get_directory_path: *directory_path_string_ == 0" ), *directory_path_string_ == 0 );
861             islib::throw_if ( std::invalid_argument ( "get_directory_path: kind_name_of_directory_.empty ()" ), kind_name_of_directory_.empty () );
862           }
863         
864         ~local
865           (
866           )
867           throw
868             (
869             )
870           {
871             islib::assert_ ( !this->directory_path_.empty (), "get_directory_path: `!this->directory_path_.empty ()' has failed." );
872           }
873
874       private:
875         boost::filesystem::path const &directory_path_;
876       }
877     local_ ( directory_path_string, kind_name_of_directory, directory_path );
878
879     directory_path = directory_path_string;
880
881     if ( !boost::filesystem::exists ( directory_path ) )
882       {
883         islib::print_error_message ( Program_Name + ": " + kind_name_of_directory + " directory `" + directory_path.string () + "' does not exist." );
884
885         throw islib::normal_termination ( EXIT_FAILURE );
886       }
887
888     if ( !boost::filesystem::is_directory ( directory_path ) )
889       {
890         std::stringstream error_message_stream;
891
892         error_message_stream
893           << Program_Name << ": " << kind_name_of_directory << " directory `" << directory_path.string () << "' is not a directory.\n"
894           << islib::get_try_help_message ( Program_Name );
895
896         islib::print_error_message ( error_message_stream.str () );
897
898         throw islib::normal_termination ( EXIT_FAILURE );
899       }
900
901     return directory_path;
902   }
903
904 //
905 // Definition of static function
906 //
907 void
908 check_source_directory_path_and_destination_directory_path
909   (
910   )
911   {
912     if ( Source_Directory_Path == Destination_Directory_Path )
913       {
914         islib::print_error_message ( Program_Name + ": source directory `" + Source_Directory_Path.string () + "' and destination directory `" + Destination_Directory_Path.string () + "' equal to each other." );
915
916         throw islib::normal_termination ( EXIT_FAILURE );
917       }
918
919     struct stat source_directory_status;
920     struct stat destination_directory_status;
921
922     islib::stat_ ( Source_Directory_Path, &source_directory_status );
923     islib::stat_ ( Destination_Directory_Path, &destination_directory_status );
924
925     if ( source_directory_status.st_dev == destination_directory_status.st_dev && source_directory_status.st_ino == destination_directory_status.st_ino )
926       {
927         islib::print_error_message ( Program_Name + ": source directory `" + Source_Directory_Path.string () + "' and destination directory `" + Destination_Directory_Path.string () + "' equal to each other." );
928
929         throw islib::normal_termination ( EXIT_FAILURE );
930       }
931   }
932
933 //
934 // Definition of static function
935 //
936 void
937 process_file
938   (
939     boost::filesystem::path const &file_path
940   )
941   {
942     class local
943       {
944       public:
945         local
946           (
947             boost::filesystem::path const &file_path_
948           )
949           {
950             islib::throw_if ( std::invalid_argument ( "process_file: file_path_.empty ()" ), file_path_.empty () );
951           }
952         
953         ~local
954           (
955           )
956           throw
957             (
958             )
959           {
960           }
961       }
962     local_ ( file_path );
963
964     std::string const file_name ( file_path.leaf () );
965
966     if ( file_name.find ( '.' ) != std::string::npos && std::find ( Extension_Vector.begin (), Extension_Vector.end (), boost::filesystem::extension ( file_path ) ) != Extension_Vector.end () )
967       {
968         if ( Year_Mode_Flag || Lexical_Mode_Flag )
969           {
970             if ( Year_Mode_Flag )
971               process_year_mode ( file_path );
972
973             if ( Lexical_Mode_Flag )
974               process_lexical_mode ( file_path );
975           }
976         else
977           link_or_copy_file ( file_path, Destination_Directory_Path / file_name );
978       }
979
980     if ( Delete_Mode_Flag )
981       unlink_file ( file_path );
982   }
983
984 //
985 // Definition of static function
986 //
987 bool
988 is_valid_argument_array
989   (
990     char ** const argument_array,
991     int const number_of_arguments
992   )
993   {
994     if ( !argument_array )
995       return false;
996
997     for ( int index_of_argument = 0; index_of_argument != number_of_arguments; ++index_of_argument )
998       if ( !argument_array [ index_of_argument ] )
999         return false;
1000
1001     return true;
1002   }
1003
1004 //
1005 // Definition of static function
1006 //
1007 void
1008 process_year_mode
1009   (
1010     boost::filesystem::path const &source_file_path
1011   )
1012   {
1013     class local
1014       {
1015       public:
1016         local
1017           (
1018             boost::filesystem::path const &source_file_path_
1019           )
1020           {
1021             islib::throw_if ( std::invalid_argument ( "process_year_mode: source_file_path_.empty ()" ), source_file_path_.empty () );
1022           }
1023         
1024         ~local
1025           (
1026           )
1027           throw
1028             (
1029             )
1030           {
1031           }
1032       }
1033     local_ ( source_file_path );
1034
1035     boost::filesystem::path destination_directory_path ( Destination_Directory_Path );
1036     struct stat source_file_status_information;
1037
1038     islib::stat_ ( source_file_path, &source_file_status_information );
1039
1040     tzset ();
1041
1042     struct tm source_file_modified_time_information;
1043
1044     islib::localtime_r_ ( &source_file_status_information.st_mtime, &source_file_modified_time_information );
1045
1046     destination_directory_path /= boost::lexical_cast < std::string > ( source_file_modified_time_information.tm_year + 1900 );
1047
1048     if ( !boost::filesystem::exists ( destination_directory_path ) )
1049       create_directory ( destination_directory_path, "year" );
1050
1051     if ( Month_Mode_Flag )
1052       process_month_mode ( destination_directory_path, source_file_modified_time_information );
1053
1054     std::string const destination_file_name ( get_destination_file_name ( source_file_path, destination_directory_path ) );
1055
1056     if ( !destination_file_name.empty () )
1057       link_or_copy_file ( source_file_path, destination_directory_path / destination_file_name );
1058   }
1059
1060 //
1061 // Definition of static function
1062 //
1063 void
1064 process_lexical_mode
1065   (
1066     boost::filesystem::path const &source_file_path
1067   )
1068   {
1069     class local
1070       {
1071       public:
1072         local
1073           (
1074             boost::filesystem::path const &source_file_path_
1075           )
1076           {
1077             islib::throw_if ( std::invalid_argument ( "process_lexical_mode: source_file_path_.empty ()" ), source_file_path_.empty () );
1078           }
1079         
1080         ~local
1081           (
1082           )
1083           throw
1084             (
1085             )
1086           {
1087           }
1088       }
1089     local_ ( source_file_path );
1090    
1091     boost::filesystem::path destination_directory_path ( Destination_Directory_Path );
1092     std::string const file_basename ( boost::filesystem::basename ( source_file_path ) );
1093     std::size_t const lexical_depth = std::min ( Lexical_Depth, file_basename.length () );
1094
1095     for ( std::size_t index_of_file_basename = 0; index_of_file_basename != lexical_depth; ++index_of_file_basename )
1096       {
1097         if ( !std::isgraph ( file_basename [ index_of_file_basename ] ) || file_basename [ index_of_file_basename ] == '.' )
1098           break;
1099
1100         destination_directory_path /= std::string ( 1, file_basename [ index_of_file_basename ] );
1101
1102         if ( !boost::filesystem::exists ( destination_directory_path ) )
1103           create_directory ( destination_directory_path, "lexical" );
1104       }
1105
1106     std::string const destination_file_name ( get_destination_file_name ( source_file_path, destination_directory_path ) );
1107
1108     if ( !destination_file_name.empty () )
1109       link_or_copy_file ( source_file_path, destination_directory_path / destination_file_name );
1110   }
1111
1112 //
1113 // Definition of static function
1114 //
1115 void
1116 unlink_file
1117   (
1118     boost::filesystem::path const &file_path
1119   )
1120   {
1121     class local
1122       {
1123       public:
1124         local
1125           (
1126             boost::filesystem::path const &file_path_
1127           )
1128           {
1129             islib::throw_if ( std::invalid_argument ( "unlink_file: file_path_.empty ()" ), file_path_.empty () );
1130           }
1131         
1132         ~local
1133           (
1134           )
1135           throw
1136             (
1137             )
1138           {
1139           }
1140       }
1141     local_ ( file_path );
1142
1143     try
1144       {
1145         islib::unlink_ ( file_path );
1146       }
1147     catch
1148       (
1149         ...
1150       )
1151       {
1152         islib::print_error_message ( Program_Name + ": unlinking file `" + file_path.string () + "' has failed." );
1153
1154         throw islib::normal_termination ( EXIT_FAILURE );
1155       }
1156
1157     if ( Verbose_Mode_Flag )
1158       islib::print_message ( Program_Name + ": file `" + file_path.string () + "' has been unlinked." );
1159   }
1160
1161 //
1162 // Definition of static function
1163 //
1164 // Return value: std::string (): there is identical file in destination_directory_path.
1165 //
1166 std::string
1167 get_destination_file_name
1168   (
1169     boost::filesystem::path const &source_file_path,
1170     boost::filesystem::path const &destination_directory_path
1171   )
1172   {
1173     class local
1174       {
1175       public:
1176         local
1177           (
1178             boost::filesystem::path const &source_file_path_,
1179             boost::filesystem::path const &destination_directory_path_
1180           )
1181           {
1182             islib::throw_if ( std::invalid_argument ( "get_destination_file_name: source_file_path_.empty ()" ), source_file_path_.empty () );
1183             islib::throw_if ( std::invalid_argument ( "get_destination_file_name: destination_directory_path_.empty ()" ), destination_directory_path_.empty () );
1184           }
1185         
1186         ~local
1187           (
1188           )
1189           throw
1190             (
1191             )
1192           {
1193           }
1194       }
1195     local_ ( source_file_path, destination_directory_path );
1196
1197     std::string destination_file_name;
1198     std::size_t repetition_number = 0;
1199
1200     destination_file_name = source_file_path.leaf ();
1201
1202     while ( boost::filesystem::exists ( destination_directory_path / destination_file_name ) )
1203       {
1204         if ( islib::binary_compare ( source_file_path, destination_directory_path / destination_file_name ) == 0 )
1205           return std::string ();
1206
1207         if ( repetition_number == std::numeric_limits < std::size_t >::max () )
1208           {
1209             islib::print_error_message ( Program_Name + ": repetition number of file `" + source_file_path.string () + "' has overflowen." );
1210
1211             throw islib::normal_termination ( EXIT_FAILURE );
1212           }
1213
1214         ++repetition_number;
1215
1216         destination_file_name = boost::filesystem::basename ( source_file_path ) + " (" + boost::lexical_cast < std::string > ( repetition_number ) + ")" + boost::filesystem::extension ( source_file_path );
1217       }
1218
1219     return destination_file_name;
1220   }
1221
1222 //
1223 // Definition of static function
1224 //
1225 void
1226 process_month_mode
1227   (
1228     boost::filesystem::path &destination_directory_path,
1229     struct tm const &source_file_modified_time_information
1230   )
1231   {
1232     class local
1233       {
1234       public:
1235         local
1236           (
1237             boost::filesystem::path const &destination_directory_path_
1238           )
1239           {
1240             islib::throw_if ( std::invalid_argument ( "process_month_mode: destination_directory_path_.empty ()" ), destination_directory_path_.empty () );
1241           }
1242         
1243         ~local
1244           (
1245           )
1246           throw
1247             (
1248             )
1249           {
1250           }
1251       }
1252     local_ ( destination_directory_path );
1253
1254     destination_directory_path /= ( boost::format ( "%02d" ) % ( source_file_modified_time_information.tm_mon + 1 ) ).str ();
1255
1256     if ( !boost::filesystem::exists ( destination_directory_path ) )
1257       create_directory ( destination_directory_path, "month" );
1258
1259     if ( Day_Mode_Flag )
1260       process_day_mode ( destination_directory_path, source_file_modified_time_information );
1261   }
1262
1263 //
1264 // Definition of static function
1265 //
1266 void
1267 process_day_mode
1268   (
1269     boost::filesystem::path &destination_directory_path,
1270     struct tm const &source_file_modified_time_information
1271   )
1272   {
1273     class local
1274       {
1275       public:
1276         local
1277           (
1278             boost::filesystem::path const &destination_directory_path_
1279           )
1280           {
1281             islib::throw_if ( std::invalid_argument ( "process_day_mode: destination_directory_path_.empty ()" ), destination_directory_path_.empty () );
1282           }
1283         
1284         ~local
1285           (
1286           )
1287           throw
1288             (
1289             )
1290           {
1291           }
1292       }
1293     local_ ( destination_directory_path );
1294
1295     destination_directory_path /= ( boost::format ( "%02d" ) % source_file_modified_time_information.tm_mday ).str ();
1296
1297     if ( !boost::filesystem::exists ( destination_directory_path ) )
1298       create_directory ( destination_directory_path, "day" );
1299
1300     if ( Hour_Mode_Flag )
1301       process_hour_mode ( destination_directory_path, source_file_modified_time_information );
1302   }
1303
1304 //
1305 // Definition of static function
1306 //
1307 void
1308 process_hour_mode
1309   (
1310     boost::filesystem::path &destination_directory_path,
1311     struct tm const &source_file_modified_time_information
1312   )
1313   {
1314     class local
1315       {
1316       public:
1317         local
1318           (
1319             boost::filesystem::path const &destination_directory_path_
1320           )
1321           {
1322             islib::throw_if ( std::invalid_argument ( "process_hour_mode: destination_directory_path_.empty ()" ), destination_directory_path_.empty () );
1323           }
1324         
1325         ~local
1326           (
1327           )
1328           throw
1329             (
1330             )
1331           {
1332           }
1333       }
1334     local_ ( destination_directory_path );
1335
1336     destination_directory_path /= ( boost::format ( "%02d" ) % source_file_modified_time_information.tm_hour ).str ();
1337
1338     if ( !boost::filesystem::exists ( destination_directory_path ) )
1339       create_directory ( destination_directory_path, "hour" );
1340
1341     if ( Minute_Mode_Flag )
1342       process_minute_mode ( destination_directory_path, source_file_modified_time_information );
1343   }
1344
1345 //
1346 // Definition of static function
1347 //
1348 void
1349 process_minute_mode
1350   (
1351     boost::filesystem::path &destination_directory_path,
1352     struct tm const &source_file_modified_time_information
1353   )
1354   {
1355     class local
1356       {
1357       public:
1358         local
1359           (
1360             boost::filesystem::path const &destination_directory_path_
1361           )
1362           {
1363             islib::throw_if ( std::invalid_argument ( "process_minute_mode: destination_directory_path_.empty ()" ), destination_directory_path_.empty () );
1364           }
1365         
1366         ~local
1367           (
1368           )
1369           throw
1370             (
1371             )
1372           {
1373           }
1374       }
1375     local_ ( destination_directory_path );
1376
1377     destination_directory_path /= ( boost::format ( "%02d" ) % source_file_modified_time_information.tm_min ).str ();
1378
1379     if ( !boost::filesystem::exists ( destination_directory_path ) )
1380       create_directory ( destination_directory_path, "minute" );
1381
1382     if ( Second_Mode_Flag )
1383       process_second_mode ( destination_directory_path, source_file_modified_time_information );
1384   }
1385
1386 //
1387 // Definition of static function
1388 //
1389 void
1390 process_second_mode
1391   (
1392     boost::filesystem::path &destination_directory_path,
1393     struct tm const &source_file_modified_time_information
1394   )
1395   {
1396     class local
1397       {
1398       public:
1399         local
1400           (
1401             boost::filesystem::path const &destination_directory_path_
1402           )
1403           {
1404             islib::throw_if ( std::invalid_argument ( "process_second_mode: destination_directory_path_.empty ()" ), destination_directory_path_.empty () );
1405           }
1406         
1407         ~local
1408           (
1409           )
1410           throw
1411             (
1412             )
1413           {
1414           }
1415       }
1416     local_ ( destination_directory_path );
1417
1418     destination_directory_path /= ( boost::format ( "%02d" ) % source_file_modified_time_information.tm_sec ).str ();
1419
1420     if ( !boost::filesystem::exists ( destination_directory_path ) )
1421       create_directory ( destination_directory_path, "second" );
1422   }
1423
1424 //
1425 // Definition of static function
1426 //
1427 void
1428 create_directory
1429   (
1430     boost::filesystem::path const &directory_path,
1431     std::string const &kind_name_of_directory
1432   )
1433   {
1434     class local
1435       {
1436       public:
1437         local
1438           (
1439             boost::filesystem::path const &directory_path_,
1440             std::string const &kind_name_of_directory_
1441           )
1442           {
1443             islib::throw_if ( std::invalid_argument ( "create_directory: directory_path_.empty ()" ), directory_path_.empty () );
1444             islib::throw_if ( std::invalid_argument ( "create_directory: kind_name_of_directory_.empty ()" ), kind_name_of_directory_.empty () );
1445           }
1446         
1447         ~local
1448           (
1449           )
1450           throw
1451             (
1452             )
1453           {
1454           }
1455       }
1456     local_ ( directory_path, kind_name_of_directory );
1457
1458     try
1459       {
1460         islib::mkdir_ ( directory_path, 0755 );
1461       }
1462     catch
1463       (
1464         ...
1465       )
1466       {
1467         islib::print_error_message ( Program_Name + ": creating directory `" + directory_path.string () + "' has failed." );
1468
1469         throw islib::normal_termination ( EXIT_FAILURE );
1470       }
1471
1472     if ( Verbose_Mode_Flag )
1473       islib::print_message ( Program_Name + ": " + kind_name_of_directory + " directory `" + directory_path.string () + "' has been created." );
1474   }
1475
1476 //
1477 // Definition of static function
1478 //
1479 void
1480 link_or_copy_file
1481   (
1482     boost::filesystem::path const &source_file_path,
1483     boost::filesystem::path const &destination_file_path
1484   )
1485   {
1486     class local
1487       {
1488       public:
1489         local
1490           (
1491             boost::filesystem::path const &source_file_path_,
1492             boost::filesystem::path const &destination_file_path_
1493           )
1494           {
1495             islib::throw_if ( std::invalid_argument ( "link_or_copy_file: source_file_path_.empty ()" ), source_file_path_.empty () );
1496             islib::throw_if ( std::invalid_argument ( "link_or_copy_file: destination_file_path_.empty ()" ), destination_file_path_.empty () );
1497           }
1498         
1499         ~local
1500           (
1501           )
1502           throw
1503             (
1504             )
1505           {
1506           }
1507       }
1508     local_ ( source_file_path, destination_file_path );
1509
1510     int link_return_value = link ( source_file_path.string ().c_str (), destination_file_path.string ().c_str () );
1511
1512     if ( link_return_value != 0 )
1513       {
1514         int const saved_errno = errno;
1515
1516         if ( saved_errno == EPERM || saved_errno == EXDEV )
1517           {
1518             try
1519               {
1520                 boost::filesystem::copy_file ( source_file_path, destination_file_path );
1521               }
1522             catch
1523               (
1524                 ...
1525               )
1526               {
1527                 islib::print_error_message ( Program_Name + ": copying file `" + source_file_path.string () + "' to `" + destination_file_path.string () + "' has failed." );
1528
1529                 throw islib::normal_termination ( EXIT_FAILURE );
1530               }
1531
1532             keep_same_accessed_time_and_modified_time ( source_file_path, destination_file_path );
1533
1534             if ( Verbose_Mode_Flag )
1535               islib::print_message ( Program_Name + ": file `" + source_file_path.string () + "' has been copied to `" + destination_file_path.string () + "'." );
1536
1537             return;
1538           }
1539         else
1540           {
1541             islib::print_error_message ( Program_Name + ": linking file `" + source_file_path.string () + "' to `" + destination_file_path.string () + "' has failed." );
1542
1543             throw islib::normal_termination ( EXIT_FAILURE );
1544           }
1545       }
1546
1547     if ( Verbose_Mode_Flag )
1548       islib::print_message ( Program_Name + ": file `" + source_file_path.string () + "' has been linked to `" + destination_file_path.string () + "'." );
1549   }
1550
1551 //
1552 // Definition of static function
1553 //
1554 void
1555 keep_same_accessed_time_and_modified_time
1556   (
1557     boost::filesystem::path const &source_file_path,
1558     boost::filesystem::path const &destination_file_path
1559   )
1560   {
1561     class local
1562       {
1563       public:
1564         local
1565           (
1566             boost::filesystem::path const &source_file_path_,
1567             boost::filesystem::path const &destination_file_path_
1568           )
1569           {
1570             islib::throw_if ( std::invalid_argument ( "keep_same_accessed_time_and_modified_time: source_file_path_.empty ()" ), source_file_path_.empty () );
1571             islib::throw_if ( std::invalid_argument ( "keep_same_accessed_time_and_modified_time: destination_file_path_.empty ()" ), destination_file_path_.empty () );
1572           }
1573         
1574         ~local
1575           (
1576           )
1577           throw
1578             (
1579             )
1580           {
1581           }
1582       }
1583     local_ ( source_file_path, destination_file_path );
1584
1585     struct stat source_file_status_information;
1586
1587     try
1588       {
1589         islib::stat_ ( source_file_path, &source_file_status_information );
1590       }
1591     catch
1592       (
1593         ...
1594       )
1595       {
1596         return;
1597       }
1598
1599     struct utimbuf utime_information;
1600
1601     utime_information.actime = source_file_status_information.st_atime;
1602     utime_information.modtime = source_file_status_information.st_mtime;
1603
1604     try
1605       {
1606         islib::utime_ ( destination_file_path, &utime_information );
1607       }
1608     catch
1609       (
1610         ...
1611       )
1612       {
1613         return;
1614       }
1615   }
1616
1617 //
1618 // End of file
1619 //