Skip to content

Commit 1364829

Browse files
committed
revise arg parser
1 parent 0f6f858 commit 1364829

File tree

4 files changed

+136
-23
lines changed

4 files changed

+136
-23
lines changed

NOTES

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,13 @@
99

1010
- PPM saver as well
1111

12+
- no, option_string is alreadyed used by "thumbnail", we need a new stabdard
13+
arg to detect and set ... how about "string_arguments"
14+
15+
need to add this to ForeignSave so buffer and target can see it
16+
17+
hide from introspection? eg. tag as DEPRECATED
18+
19+
- something in pytest is taking FOREVER ... find it and fix it
20+
21+
uses enough memory to kill the laptop

libvips/iofuncs/object.c

Lines changed: 116 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,26 @@ vips_object_get_argument( VipsObject *object, const char *name,
794794
return( 0 );
795795
}
796796

797+
/**
798+
* vips_object_argument_has:
799+
* @object: the object to fetch the args from
800+
* @name: arg name
801+
*
802+
* Convenience: true if the object has the named argument.
803+
*
804+
* Returns: %TRUE if the argument exists.
805+
*/
806+
static gboolean
807+
vips_object_argument_has( VipsObject *object, const char *name )
808+
{
809+
GParamSpec *pspec;
810+
VipsArgumentClass *argument_class;
811+
VipsArgumentInstance *argument_instance;
812+
813+
return( !vips_object_get_argument( object, name,
814+
&pspec, &argument_class, &argument_instance ) );
815+
}
816+
797817
/**
798818
* vips_object_argument_isset:
799819
* @object: the object to fetch the args from
@@ -2468,12 +2488,43 @@ vips_object_set( VipsObject *object, ... )
24682488
return( result );
24692489
}
24702490

2471-
/* Set object args from a string. The string is something like
2491+
/* Set object args from a string. Syntax:
2492+
*
2493+
* args:
2494+
* optional-open arg-list optional-close
2495+
*
2496+
* optional-open:
2497+
* '[' |
2498+
* empty
2499+
*
2500+
* optional-close:
2501+
* ']' |
2502+
* empty
2503+
*
2504+
* arg-list:
2505+
* arg |
2506+
* arg ',' arg-list
2507+
*
2508+
* arg:
2509+
* segment |
2510+
* segment '=' segment
2511+
*
2512+
* segment:
2513+
* string |
2514+
* string '[' arg-list ']'
2515+
*
2516+
* eg.
2517+
*
24722518
* ""
24732519
* "a=12"
24742520
* "a = 12, b = fred[jim]"
2521+
* "[a = 12, b = fred[jim]]"
2522+
*
24752523
* etc.
24762524
*/
2525+
2526+
#define NEXT() (p = vips__token_get( p, &token, string, VIPS_PATH_MAX ))
2527+
24772528
static int
24782529
vips_object_set_args( VipsObject *object, const char *p )
24792530
{
@@ -2482,13 +2533,31 @@ vips_object_set_args( VipsObject *object, const char *p )
24822533
VipsToken token;
24832534
char string[VIPS_PATH_MAX];
24842535
char string2[VIPS_PATH_MAX];
2536+
const char *q;
2537+
GParamSpec *pspec;
2538+
VipsArgumentClass *argument_class;
2539+
VipsArgumentInstance *argument_instance;
24852540

2486-
while( vips__token_get( p, &token, string, VIPS_PATH_MAX ) &&
2487-
token == VIPS_TOKEN_STRING ) {
2488-
const char *q;
2489-
GParamSpec *pspec;
2490-
VipsArgumentClass *argument_class;
2491-
VipsArgumentInstance *argument_instance;
2541+
/* p point to the current token, q points to the start of the next
2542+
* token.
2543+
*/
2544+
if( !(q = vips__token_get( p, &token, string, VIPS_PATH_MAX )) )
2545+
return( 0 );
2546+
2547+
/* '['? Step forward.
2548+
*/
2549+
if( token == VIPS_TOKEN_LEFT ) {
2550+
p = q;
2551+
if( !(q = vips__token_get( p, &token, string, VIPS_PATH_MAX )) )
2552+
return( -1 );
2553+
}
2554+
2555+
for(;;) {
2556+
if( token != VIPS_TOKEN_STRING ) {
2557+
vips_error( class->nickname,
2558+
"%s", _( "not string at start of argument" ) );
2559+
return( -1 );
2560+
}
24922561

24932562
/* Read "string[options]".
24942563
*/
@@ -2497,10 +2566,11 @@ vips_object_set_args( VipsObject *object, const char *p )
24972566
return( -1 );
24982567

24992568
/* Peek the next token. "=" means we need a value, "," means
2500-
* move on to the next arg.
2569+
* move on to the next arg, end-of-string means we're done.
25012570
*/
25022571
if( !(q = vips__token_get( p, &token, string, VIPS_PATH_MAX )) )
2503-
break;
2572+
return( 0 );
2573+
25042574
if( token == VIPS_TOKEN_EQUALS ) {
25052575
/* Get "string[options]" again for the value.
25062576
*/
@@ -2510,6 +2580,10 @@ vips_object_set_args( VipsObject *object, const char *p )
25102580
if( vips_object_set_argument_from_string( object,
25112581
string, string2 ) )
25122582
return( -1 );
2583+
2584+
if( !(q = vips__token_get( p, &token,
2585+
string, VIPS_PATH_MAX )) )
2586+
return( 0 );
25132587
}
25142588
else if( g_object_class_find_property(
25152589
G_OBJECT_GET_CLASS( object ), string ) &&
@@ -2535,18 +2609,32 @@ vips_object_set_args( VipsObject *object, const char *p )
25352609
return( -1 );
25362610
}
25372611

2538-
/* Now step over any ",".
2612+
/* Something other than ','? We must be at the end of the args.
25392613
*/
2540-
if( !(p = vips__token_get( p, &token, string, VIPS_PATH_MAX )) )
2614+
if( token != VIPS_TOKEN_COMMA )
25412615
break;
2542-
if( token != VIPS_TOKEN_COMMA ) {
2543-
vips_error( class->nickname,
2544-
"%s", _( "not , after parameter" ) );
2545-
return( -1 );
2546-
}
2616+
p = q;
2617+
if( !(q = vips__token_get( p, &token, string, VIPS_PATH_MAX )) )
2618+
return( 0 );
25472619
}
25482620

2549-
return( 0 );
2621+
/* An optional ']', and we should be at the end of the string.
2622+
*/
2623+
if( token != VIPS_TOKEN_RIGHT ) {
2624+
vips_error( class->nickname,
2625+
"%s", _( "not ']' at end of arg list" ) );
2626+
return( -1 );
2627+
}
2628+
2629+
/* And that should be the end of the tokens.
2630+
*/
2631+
p = q;
2632+
if( !(q = vips__token_get( p, &token, string, VIPS_PATH_MAX )) )
2633+
return( 0 );
2634+
2635+
vips_error( class->nickname,
2636+
"%s", _( "unexpected tokens at end of arg list" ) );
2637+
return( -1 );
25502638
}
25512639

25522640
/**
@@ -2571,6 +2659,17 @@ vips_object_set_from_string( VipsObject *object, const char *string )
25712659
char filename[VIPS_PATH_MAX];
25722660
char option_string[VIPS_PATH_MAX];
25732661

2662+
/* Note the string on the operation. Eg. ppm save can use the filename
2663+
* component to pick a save subtype.
2664+
*
2665+
* We can't use option_string, unfortunately (the obvious name) since
2666+
* "thumbnail" uses that for something else.
2667+
*/
2668+
if( vips_object_argument_has( object, "string_arguments" ) )
2669+
g_object_set( object,
2670+
"string_arguments", string,
2671+
NULL );
2672+
25742673
/* If the string is of the form "xxxxx[args]", get just args into
25752674
* option_string.
25762675
*/

libvips/iofuncs/util.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,13 +1283,13 @@ vips__token_get( const char *p, VipsToken *token, char *string, int size )
12831283

12841284
/* Parse this token with p.
12851285
*/
1286-
if( !p )
1286+
if( !p )
12871287
return( NULL );
12881288

12891289
/* Skip initial whitespace.
12901290
*/
12911291
p += strspn( p, " \t\n\r" );
1292-
if( !p[0] )
1292+
if( !p[0] )
12931293
return( NULL );
12941294

12951295
switch( (ch = p[0]) ) {
@@ -1338,13 +1338,16 @@ vips__token_get( const char *p, VipsToken *token, char *string, int size )
13381338
* string was not truncated, swap the preceding
13391339
* backslash for a quote.
13401340
*/
1341-
if( p[n + 1] == ch && p[n] == '\\' && i == n )
1341+
if( p[n + 1] == ch &&
1342+
p[n] == '\\' &&
1343+
i == n )
13421344
string[i - 1] = ch;
13431345

13441346
string += i;
13451347
size -= i;
13461348
p += n + 1;
1347-
} while( p[0] && p[-1] == '\\' );
1349+
} while( p[0] &&
1350+
p[-1] == '\\' );
13481351

13491352
p += 1;
13501353

@@ -1367,7 +1370,8 @@ vips__token_get( const char *p, VipsToken *token, char *string, int size )
13671370
* hasn't been truncated.
13681371
*/
13691372
if( i != size )
1370-
while( i > 0 && isspace( string[i - 1] ) ) {
1373+
while( i > 0 &&
1374+
isspace( string[i - 1] ) ) {
13711375
string[i - 1] = '\0';
13721376
i--;
13731377
}

test/test-suite/test_resample.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def test_thumbnail(self):
179179
im2 = pyvips.Image.thumbnail(OME_FILE + "[page=1]", 100)
180180
assert im2.width == 100
181181
assert im2.height == 38
182-
assert (im1 - im2).abs().max() != 0
182+
assert (im1 - im2).abs().max() != 0
183183

184184
# should be able to thumbnail entire many-page tiff as a toilet-roll
185185
# image

0 commit comments

Comments
 (0)