summaryrefslogtreecommitdiffstats
path: root/rc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'rc.cc')
-rw-r--r--rc.cc229
1 files changed, 229 insertions, 0 deletions
diff --git a/rc.cc b/rc.cc
new file mode 100644
index 0000000..dac205c
--- /dev/null
+++ b/rc.cc
@@ -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];
+ }