/* Zutils - Utilities dealing with compressed files Copyright (C) 2009, 2010, 2011, 2012, 2013 Antonio Diaz Diaz. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include "arg_parser.h" #include "zutils.h" #include "rc.h" namespace { std::string compressor_names[num_formats] = { "bzip2", "gzip", "lzip", "xz" }; // default compressor names // args to compressors, maybe empty std::vector< std::string > compressor_args[num_formats]; int my_fgetc( FILE * const f ) { int ch; bool comment = false; do { ch = std::fgetc( f ); if( ch == '#' ) comment = true; else if( ch == '\n' || ch == EOF ) comment = false; else if( ch == '\\' && comment ) { const int c = std::fgetc( f ); if( c == '\n' ) { std::ungetc( c, f ); comment = false; } } } while( comment ); return ch; } // Returns the parity of escapes (backslashes) at the end of a string. bool trailing_escape( const std::string & s ) { unsigned len = s.size(); bool odd_escape = false; while( len > 0 && s[--len] == '\\' ) odd_escape = !odd_escape; return odd_escape; } // Read a line discarding comments, leading whitespace and blank lines. // Escaped newlines are discarded. // Returns the empty string if at EOF. // const std::string & my_fgets( FILE * const f, int & linenum ) { static std::string s; bool strip = true; // strip leading whitespace s.clear(); while( true ) { int ch = my_fgetc( f ); if( strip ) { strip = false; while( std::isspace( ch ) ) { if( ch == '\n' ) { ++linenum; } ch = my_fgetc( f ); } } if( ch == EOF ) { if( s.size() > 0 ) { ++linenum; } break; } else if( ch == '\n' ) { ++linenum; strip = true; if( trailing_escape( s ) ) s.erase( s.size() - 1 ); else if( s.size() > 0 ) break; } else s += ch; } return s; } bool parse_rc_line( const std::string & line, const char * const filename, const int linenum ) { const int len = line.size(); int i = 0; while( i < len && std::isspace( line[i] ) ) ++i; // strip spaces int l = i; while( i < len && line[i] != '=' && !std::isspace( line[i] ) ) ++i; if( l >= i ) { if( verbosity >= 0 ) std::fprintf( stderr, "%s %d: missing format name.\n", filename, linenum ); return false; } const std::string name( line, l, i - l ); int format_index = -1; for( int i = 0; i < num_formats; ++i ) if( name == format_names[i] ) { format_index = i; break; } if( format_index < 0 ) { if( verbosity >= 0 ) std::fprintf( stderr, "%s %d: bad format name '%s'\n", filename, linenum, name.c_str() ); return false; } while( i < len && std::isspace( line[i] ) ) ++i; // strip spaces if( i <= 0 || i >= len || line[i] != '=' ) { if( verbosity >= 0 ) std::fprintf( stderr, "%s %d: missing '='.\n", filename, linenum ); return false; } ++i; // skip the '=' while( i < len && std::isspace( line[i] ) ) ++i; // strip spaces l = i; while( i < len && !std::isspace( line[i] ) ) ++i; if( l >= i ) { if( verbosity >= 0 ) std::fprintf( stderr, "%s %d: missing compressor name.\n", filename, linenum ); return false; } compressor_names[format_index].assign( line, l, i - l ); compressor_args[format_index].clear(); while( i < len ) { while( i < len && std::isspace( line[i] ) ) ++i; // strip spaces l = i; while( i < len && !std::isspace( line[i] ) ) ++i; if( l < i ) compressor_args[format_index].push_back( std::string( line, l, i - l ) ); } return true; } // Returns 0 for success, 1 for file not found, 2 for syntax error. int process_rcfile( const std::string & name ) { FILE * const f = std::fopen( name.c_str(), "r" ); if( !f ) return 1; int linenum = 0; int retval = 0; while( true ) { const std::string & line = my_fgets( f, linenum ); if( line.size() == 0 ) break; // EOF if( !parse_rc_line( line, name.c_str(), linenum ) ) { retval = 2; break; } } std::fclose( f ); return retval; } } // end namespace void maybe_process_config_file( const Arg_parser & parser ) { for( int i = 0; i < parser.arguments(); ++i ) if( parser.code( i ) == 'N' ) return; std::string name; const char * p = std::getenv( "HOME" ); if( p ) name = p; if( name.size() ) { name += "/."; name += config_file_name; const int retval = process_rcfile( name ); if( retval == 0 ) return; if( retval == 2 ) std::exit( 2 ); } name = SYSCONFDIR; name += '/'; name += config_file_name; const int retval = process_rcfile( name ); if( retval == 2 ) std::exit( 2 ); } void parse_compressor( const std::string & arg, const int format_index, const int eretval ) { const int len = arg.size(); int i = 0; while( i < len && std::isspace( arg[i] ) ) ++i; // strip spaces int l = i; while( i < len && !std::isspace( arg[i] ) ) ++i; if( l >= i ) { show_error( "Missing compressor name." ); std::exit( eretval ); } compressor_names[format_index].assign( arg, l, i - l ); compressor_args[format_index].clear(); while( i < len ) { while( i < len && std::isspace( arg[i] ) ) ++i; // strip spaces l = i; while( i < len && !std::isspace( arg[i] ) ) ++i; if( l < i ) compressor_args[format_index].push_back( std::string( arg, l, i - l ) ); } } const char * get_compressor_name( const int format_index ) { if( format_index >= 0 && format_index < num_formats ) return compressor_names[format_index].c_str(); return 0; } const std::vector< std::string > & get_compressor_args( const int format_index ) { return compressor_args[format_index]; }