(rpc) make our generated JSON more human-readable.

This commit is contained in:
Charles Kerr 2008-05-22 16:41:16 +00:00
parent 7b209acc1b
commit 90e151cd4d
2 changed files with 76 additions and 28 deletions

View File

@ -1,3 +1,4 @@
#include <ctype.h>
#include <stdio.h>
#include "transmission.h"
#include "bencode.h"
@ -150,6 +151,10 @@ testString( const char * str, int isGood )
check( err );
} else {
check( !err );
#if 0
fprintf( stderr, "in: [%s]\n", str );
fprintf( stderr, "out:\n%s", tr_bencSaveAsJSON(&val,NULL) );
#endif
check( end == (const uint8_t*)str + len );
saved = tr_bencSave( &val, &savedLen );
check( !strcmp( saved, str ) );
@ -219,6 +224,8 @@ testParse( void )
return err;
if(( err = testString( "d4:spaml1:a1:bee", TRUE )))
return err;
if(( err = testString( "d5:greenli1ei2ei3ee4:spamd1:ai123e3:keyi214eee", TRUE )))
return err;
if(( err = testString( "d9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee", TRUE )))
return err;
if(( err = testString( "d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e", TRUE )))
@ -271,6 +278,16 @@ testParse( void )
return 0;
}
static void
stripWhitespace( char * in )
{
char * out;
for( out=in; *in; ++in )
if( !isspace( *in ) )
*out++ = *in;
*out = '\0';
}
static int
testJSONSnippet( const char * benc_str, const char * expected )
{
@ -278,9 +295,11 @@ testJSONSnippet( const char * benc_str, const char * expected )
char * serialized;
tr_bencLoad( benc_str, strlen( benc_str ), &top, NULL );
serialized = tr_bencSaveAsJSON( &top, NULL );
stripWhitespace( serialized );
#if 0
fprintf( stderr, " expected: [%s]\n", expected );
fprintf( stderr, " got: [%s]\n", serialized );
fprintf( stderr, "benc: %s\n", benc_str );
fprintf( stderr, "json: %s\n", serialized );
fprintf( stderr, "want: %s\n", expected );
#endif
check( !strcmp( serialized, expected ) );
tr_free( serialized );
@ -301,22 +320,22 @@ testJSON( void )
return val;
benc_str = "d5:helloi1e5:worldi2ee";
expected = "{ \"hello\": 1, \"world\": 2 }";
expected = "{\"hello\":1,\"world\":2}";
if(( val = testJSONSnippet( benc_str, expected )))
return val;
benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ee";
expected = "{ \"foo\": [ 1, 2, 3 ], \"hello\": 1, \"world\": 2 }";
expected = "{\"foo\":[1,2,3],\"hello\":1,\"world\":2}";
if(( val = testJSONSnippet( benc_str, expected )))
return val;
benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eee";
expected = "{ \"foo\": [ 1, 2, 3, { \"a\": 0 } ], \"hello\": 1, \"world\": 2 }";
expected = "{\"foo\":[1,2,3,{\"a\":0}],\"hello\":1,\"world\":2}";
if(( val = testJSONSnippet( benc_str, expected )))
return val;
benc_str = "d4:argsd6:statuslee6:result7:successe";
expected = "{ \"args\": { \"status\": [ ] }, \"result\": \"success\" }";
benc_str = "d4:argsd6:statusle7:status2lee6:result7:successe";
expected = "{\"args\":{\"status\":[],\"status2\":[]},\"result\":\"success\"}";
if(( val = testJSONSnippet( benc_str, expected )))
return val;

View File

@ -23,7 +23,7 @@
*****************************************************************************/
#include <assert.h>
#include <ctype.h> /* isdigit, isprint */
#include <ctype.h> /* isdigit, isprint, isspace */
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
@ -1023,6 +1023,13 @@ struct jsonWalk
struct evbuffer * out;
};
static void
jsonIndent( struct jsonWalk * data )
{
const int width = tr_list_size( data->parents ) * 4;
evbuffer_add_printf( data->out, "\n%*.*s", width, width, " " );
}
static void
jsonChildFunc( struct jsonWalk * data )
{
@ -1036,14 +1043,17 @@ jsonChildFunc( struct jsonWalk * data )
const int i = parentState->childIndex++;
if( ! ( i % 2 ) )
evbuffer_add_printf( data->out, ": " );
else
else {
evbuffer_add_printf( data->out, ", " );
jsonIndent( data );
}
break;
}
case TYPE_LIST: {
++parentState->childIndex;
evbuffer_add_printf( data->out, ", " );
jsonIndent( data );
break;
}
@ -1085,14 +1095,14 @@ jsonStringFunc( const tr_benc * val, void * vdata )
for( it=val->val.s.s, end=it+val->val.s.i; it!=end; ++it )
{
switch( *it ) {
case '"' : evbuffer_add_printf( data->out, "\\\"" ); break;
case '/' : evbuffer_add_printf( data->out, "\\/" ); break;
case '\b': evbuffer_add_printf( data->out, "\\b" ); break;
case '\f': evbuffer_add_printf( data->out, "\\f" ); break;
case '\n': evbuffer_add_printf( data->out, "\\n" ); break;
case '\r': evbuffer_add_printf( data->out, "\\n" ); break;
case '\t': evbuffer_add_printf( data->out, "\\n" ); break;
case '\\': evbuffer_add_printf( data->out, "\\\\" ); break;
case '"' :
case '/' :
case '\b':
case '\f':
case '\n':
case '\r':
case '\t':
case '\\': evbuffer_add_printf( data->out, "\\%c", *it ); break;
default: {
if( isascii( *it ) )
evbuffer_add_printf( data->out, "%c", *it );
@ -1110,29 +1120,46 @@ jsonDictBeginFunc( const tr_benc * val, void * vdata )
{
struct jsonWalk * data = vdata;
jsonPushParent( data, val );
evbuffer_add_printf( data->out, "{ " );
if( !val->val.l.count )
evbuffer_add_printf( data->out, " " );
evbuffer_add_printf( data->out, "{" );
if( val->val.l.count )
jsonIndent( data );
}
static void
jsonListBeginFunc( const tr_benc * val, void * vdata )
{
const int nChildren = tr_bencListSize( val );
struct jsonWalk * data = vdata;
jsonPushParent( data, val );
evbuffer_add_printf( data->out, "[ " );
if( !val->val.l.count )
evbuffer_add_printf( data->out, " " );
evbuffer_add_printf( data->out, "[" );
if( nChildren )
jsonIndent( data );
}
static void
jsonContainerEndFunc( const tr_benc * val, void * vdata )
{
size_t i;
struct jsonWalk * data = vdata;
EVBUFFER_LENGTH( data->out ) -= 2;
if( tr_bencIsDict( val ) )
evbuffer_add_printf( data->out, " }" );
else /* list */
evbuffer_add_printf( data->out, " ]" );
char * str;
int emptyContainer = FALSE;
/* trim out the trailing comma, if any */
str = (char*) EVBUFFER_DATA( data->out );
for( i=EVBUFFER_LENGTH( data->out )-1; i>0; --i ) {
if( isspace( str[i] ) ) continue;
if( str[i]==',' )
EVBUFFER_LENGTH( data->out ) = i;
if( str[i]=='{' || str[i]=='[' )
emptyContainer = TRUE;
break;
}
jsonPopParent( data );
if( !emptyContainer )
jsonIndent( data );
if( tr_bencIsDict( val ) )
evbuffer_add_printf( data->out, "}" );
else /* list */
evbuffer_add_printf( data->out, "]" );
jsonChildFunc( data );
}
char*
@ -1153,6 +1180,8 @@ tr_bencSaveAsJSON( const tr_benc * top, int * len )
bencWalk( top, &walkFuncs, &data );
if( EVBUFFER_LENGTH( data.out ) )
evbuffer_add_printf( data.out, "\n" );
if( len != NULL )
*len = EVBUFFER_LENGTH( data.out );
ret = tr_strndup( (char*) EVBUFFER_DATA( data.out ), EVBUFFER_LENGTH( data.out ) );