diff options
Diffstat (limited to 'rc.cc')
-rw-r--r-- | rc.cc | 229 |
1 files changed, 229 insertions, 0 deletions
@@ -0,0 +1,229 @@ +/* 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 <http://www.gnu.org/licenses/>. +*/ + +#define _FILE_OFFSET_BITS 64 + +#include <cstdio> +#include <cstdlib> +#include <string> +#include <vector> +#include <stdint.h> + +#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]; + } |