/*******************************************************************************/ /* Copyright (C) 2008 Jonathan Moore Liles */ /* */ /* 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 2 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; see the file COPYING. If not,write to the Free Software */ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*******************************************************************************/ #include "Log_Entry.H" #include "const.h" #include "util/debug.h" Log_Entry::Log_Entry ( ) { _sa = (char**)malloc( sizeof( char * ) ); *_sa = NULL; _i = 0; } Log_Entry::Log_Entry ( char **sa ) { _sa = sa; _i = 0; if ( _sa ) while ( _sa[ _i ] ) ++_i; } Log_Entry::Log_Entry ( const char *s ) { _i = 0; _sa = s ? parse_alist( s ) : NULL; if ( _sa ) while ( _sa[ _i ] ) ++_i; } Log_Entry::~Log_Entry ( ) { if ( ! _sa ) return; for ( _i = 0; _sa[ _i ]; ++_i ) { free( _sa[ _i ] ); } free( _sa ); } /** remove escapes from string /s/ in-place */ static void unescape ( char *s ) { char *r = s; for ( ; *s; s++, r++ ) { if ( '\\' == *s ) { switch ( *(++s) ) { case 'n': *r = '\n'; break; case '"': *r = '"'; break; default: break; } } else *r = *s; } *r = '\0'; } /** sigh. parse a string of ":name value :name value" pairs into an * array of strings, one per pair */ // FIXME: doesn't handle the case of :name ":foo bar", nested quotes // or other things it should. char ** Log_Entry::parse_alist( const char *s ) { // FIXME: bogus over allocation... int tl = strlen( s ); char **r = (char**)malloc( sizeof( char* ) * tl ); bool quote = false; bool value = false; const char *c = NULL; int i = 0; for ( ; ; s++ ) { switch ( *s ) { case '\0': case ' ': if ( ! quote && c ) { if ( ! value ) { value = true; break; } int l = s - c; char *pair = (char*)malloc( l + 1 ); /* remove trailing space */ if ( c[ l - 1 ] == ' ' ) --l; strncpy( pair, c, l ); pair[ l ] = '\0'; r[ i++ ] = pair; /* split */ strtok( pair, " " ); /* remove quotes */ char *v = pair + strlen( pair ) + 1; unescape( v ); if ( *v == '"' ) { // v++; if ( v[ strlen( v ) - 1 ] != '"' ) WARNING( "invalid quoting in log entry!" ); else { v[ strlen( v ) - 1 ] = '\0'; memmove( v, v + 1, strlen( v ) + 1 ); } } c = NULL; } break; case ':': /* this is a key */ if ( ! quote && ! c ) { c = s; value = false; } break; case '"': quote = !quote; break; case '\\': s++; break; } if ( *s == '\0' ) break; } r[ i ] = NULL; return r; } /** compare elements of dumps s1 and s2, removing those elements of dst which are not changed from src */ bool Log_Entry::diff ( Log_Entry *e1, Log_Entry *e2 ) { if ( ! e1 ) return true; char **sa1 = e1->_sa; char **sa2 = e2->_sa; if ( ! sa1 ) return true; int w = 0; for ( int i = 0; sa1[ i ]; ++i ) { const char *v1 = sa1[ i ] + strlen( sa1[ i ] ) + 1; const char *v2 = sa2[ i ] + strlen( sa2[ i ] ) + 1; if ( ! strcmp( sa1[ i ], sa2[ i ] ) && ! strcmp( v1, v2 ) ) { free( sa2[ i ] ); free( sa1[ i ] ); } else { sa2[ w ] = sa2[ i ]; sa1[ w ] = sa1[ i ]; w++; } } sa1[ w ] = NULL; sa2[ w ] = NULL; e1->_i = w; e2->_i = w; return w == 0 ? false : true; } void Log_Entry::grow ( ) { _sa = (char**)realloc( _sa, sizeof( char * ) * (_i + 2) ); _sa[ _i + 1 ] = NULL; } int Log_Entry::size ( void ) const { return _i; } void Log_Entry::get ( int n, const char **name, const char **value ) const { *name = _sa[ n ]; *value = *name + strlen( *name ) + 1; } char ** Log_Entry::sa ( void ) { return _sa; /* char **sa = _sa; */ /* // _sa = NULL; */ /* return sa; */ /* } */ }