@@ -794,6 +794,26 @@ vips_object_get_argument( VipsObject *object, const char *name,
794
794
return ( 0 );
795
795
}
796
796
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
+
797
817
/**
798
818
* vips_object_argument_isset:
799
819
* @object: the object to fetch the args from
@@ -2468,12 +2488,43 @@ vips_object_set( VipsObject *object, ... )
2468
2488
return ( result );
2469
2489
}
2470
2490
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
+ *
2472
2518
* ""
2473
2519
* "a=12"
2474
2520
* "a = 12, b = fred[jim]"
2521
+ * "[a = 12, b = fred[jim]]"
2522
+ *
2475
2523
* etc.
2476
2524
*/
2525
+
2526
+ #define NEXT () (p = vips__token_get( p, &token, string, VIPS_PATH_MAX ))
2527
+
2477
2528
static int
2478
2529
vips_object_set_args ( VipsObject * object , const char * p )
2479
2530
{
@@ -2482,13 +2533,31 @@ vips_object_set_args( VipsObject *object, const char *p )
2482
2533
VipsToken token ;
2483
2534
char string [VIPS_PATH_MAX ];
2484
2535
char string2 [VIPS_PATH_MAX ];
2536
+ const char * q ;
2537
+ GParamSpec * pspec ;
2538
+ VipsArgumentClass * argument_class ;
2539
+ VipsArgumentInstance * argument_instance ;
2485
2540
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
+ }
2492
2561
2493
2562
/* Read "string[options]".
2494
2563
*/
@@ -2497,10 +2566,11 @@ vips_object_set_args( VipsObject *object, const char *p )
2497
2566
return ( -1 );
2498
2567
2499
2568
/* 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 .
2501
2570
*/
2502
2571
if ( !(q = vips__token_get ( p , & token , string , VIPS_PATH_MAX )) )
2503
- break ;
2572
+ return ( 0 );
2573
+
2504
2574
if ( token == VIPS_TOKEN_EQUALS ) {
2505
2575
/* Get "string[options]" again for the value.
2506
2576
*/
@@ -2510,6 +2580,10 @@ vips_object_set_args( VipsObject *object, const char *p )
2510
2580
if ( vips_object_set_argument_from_string ( object ,
2511
2581
string , string2 ) )
2512
2582
return ( -1 );
2583
+
2584
+ if ( !(q = vips__token_get ( p , & token ,
2585
+ string , VIPS_PATH_MAX )) )
2586
+ return ( 0 );
2513
2587
}
2514
2588
else if ( g_object_class_find_property (
2515
2589
G_OBJECT_GET_CLASS ( object ), string ) &&
@@ -2535,18 +2609,32 @@ vips_object_set_args( VipsObject *object, const char *p )
2535
2609
return ( -1 );
2536
2610
}
2537
2611
2538
- /* Now step over any "," .
2612
+ /* Something other than ','? We must be at the end of the args .
2539
2613
*/
2540
- if ( !( p = vips__token_get ( p , & token , string , VIPS_PATH_MAX )) )
2614
+ if ( token != VIPS_TOKEN_COMMA )
2541
2615
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 );
2547
2619
}
2548
2620
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 );
2550
2638
}
2551
2639
2552
2640
/**
@@ -2571,6 +2659,17 @@ vips_object_set_from_string( VipsObject *object, const char *string )
2571
2659
char filename [VIPS_PATH_MAX ];
2572
2660
char option_string [VIPS_PATH_MAX ];
2573
2661
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
+
2574
2673
/* If the string is of the form "xxxxx[args]", get just args into
2575
2674
* option_string.
2576
2675
*/
0 commit comments