@@ -182,6 +182,24 @@ static int parse_option_bool(const char *name, const char *value, int *ret)
182
182
return 0 ;
183
183
}
184
184
185
+ static int parse_option_number (const char * name , const char * value , uint64_t * ret )
186
+ {
187
+ char * postfix ;
188
+ uint64_t number ;
189
+
190
+ if (value != NULL ) {
191
+ number = strtoull (value , & postfix , 0 );
192
+ if (* postfix != '\0' ) {
193
+ fprintf (stderr , "Option '%s' needs a number as parameter\n" , name );
194
+ return -1 ;
195
+ }
196
+ } else {
197
+ fprintf (stderr , "Option '%s' needs a parameter\n" , name );
198
+ return -1 ;
199
+ }
200
+ return 0 ;
201
+ }
202
+
185
203
static int parse_option_size (const char * name , const char * value , uint64_t * ret )
186
204
{
187
205
char * postfix ;
@@ -444,3 +462,299 @@ void print_option_help(QEMUOptionParameter *list)
444
462
list ++ ;
445
463
}
446
464
}
465
+
466
+ /* ------------------------------------------------------------------ */
467
+
468
+ struct QemuOpt {
469
+ const char * name ;
470
+ const char * str ;
471
+
472
+ QemuOptDesc * desc ;
473
+ union {
474
+ int bool ;
475
+ uint64_t uint ;
476
+ } value ;
477
+
478
+ QemuOpts * opts ;
479
+ TAILQ_ENTRY (QemuOpt ) next ;
480
+ };
481
+
482
+ struct QemuOpts {
483
+ const char * id ;
484
+ QemuOptsList * list ;
485
+ TAILQ_HEAD (, QemuOpt ) head ;
486
+ TAILQ_ENTRY (QemuOpts ) next ;
487
+ };
488
+
489
+ static QemuOpt * qemu_opt_find (QemuOpts * opts , const char * name )
490
+ {
491
+ QemuOpt * opt ;
492
+
493
+ TAILQ_FOREACH (opt , & opts -> head , next ) {
494
+ if (strcmp (opt -> name , name ) != 0 )
495
+ continue ;
496
+ return opt ;
497
+ }
498
+ return NULL ;
499
+ }
500
+
501
+ const char * qemu_opt_get (QemuOpts * opts , const char * name )
502
+ {
503
+ QemuOpt * opt = qemu_opt_find (opts , name );
504
+ return opt ? opt -> str : NULL ;
505
+ }
506
+
507
+ int qemu_opt_get_bool (QemuOpts * opts , const char * name , int defval )
508
+ {
509
+ QemuOpt * opt = qemu_opt_find (opts , name );
510
+
511
+ if (opt == NULL )
512
+ return defval ;
513
+ assert (opt -> desc && opt -> desc -> type == QEMU_OPT_BOOL );
514
+ return opt -> value .bool ;
515
+ }
516
+
517
+ uint64_t qemu_opt_get_number (QemuOpts * opts , const char * name , uint64_t defval )
518
+ {
519
+ QemuOpt * opt = qemu_opt_find (opts , name );
520
+
521
+ if (opt == NULL )
522
+ return defval ;
523
+ assert (opt -> desc && opt -> desc -> type == QEMU_OPT_NUMBER );
524
+ return opt -> value .uint ;
525
+ }
526
+
527
+ uint64_t qemu_opt_get_size (QemuOpts * opts , const char * name , uint64_t defval )
528
+ {
529
+ QemuOpt * opt = qemu_opt_find (opts , name );
530
+
531
+ if (opt == NULL )
532
+ return defval ;
533
+ assert (opt -> desc && opt -> desc -> type == QEMU_OPT_SIZE );
534
+ return opt -> value .uint ;
535
+ }
536
+
537
+ static int qemu_opt_parse (QemuOpt * opt )
538
+ {
539
+ if (opt -> desc == NULL )
540
+ return 0 ;
541
+ switch (opt -> desc -> type ) {
542
+ case QEMU_OPT_STRING :
543
+ /* nothing */
544
+ return 0 ;
545
+ case QEMU_OPT_BOOL :
546
+ return parse_option_bool (opt -> name , opt -> str , & opt -> value .bool );
547
+ case QEMU_OPT_NUMBER :
548
+ return parse_option_number (opt -> name , opt -> str , & opt -> value .uint );
549
+ case QEMU_OPT_SIZE :
550
+ return parse_option_size (opt -> name , opt -> str , & opt -> value .uint );
551
+ default :
552
+ abort ();
553
+ }
554
+ }
555
+
556
+ static void qemu_opt_del (QemuOpt * opt )
557
+ {
558
+ TAILQ_REMOVE (& opt -> opts -> head , opt , next );
559
+ qemu_free ((/* !const */ char * )opt -> name );
560
+ qemu_free ((/* !const */ char * )opt -> str );
561
+ qemu_free (opt );
562
+ }
563
+
564
+ int qemu_opt_set (QemuOpts * opts , const char * name , const char * value )
565
+ {
566
+ QemuOpt * opt ;
567
+
568
+ opt = qemu_opt_find (opts , name );
569
+ if (!opt ) {
570
+ QemuOptDesc * desc = opts -> list -> desc ;
571
+ int i ;
572
+
573
+ for (i = 0 ; desc [i ].name != NULL ; i ++ ) {
574
+ if (strcmp (desc [i ].name , name ) == 0 ) {
575
+ break ;
576
+ }
577
+ }
578
+ if (desc [i ].name == NULL ) {
579
+ if (i == 0 ) {
580
+ /* empty list -> allow any */ ;
581
+ } else {
582
+ fprintf (stderr , "option \"%s\" is not valid for %s\n" ,
583
+ name , opts -> list -> name );
584
+ return -1 ;
585
+ }
586
+ }
587
+ opt = qemu_mallocz (sizeof (* opt ));
588
+ opt -> name = qemu_strdup (name );
589
+ opt -> opts = opts ;
590
+ TAILQ_INSERT_TAIL (& opts -> head , opt , next );
591
+ if (desc [i ].name != NULL ) {
592
+ opt -> desc = desc + i ;
593
+ }
594
+ }
595
+ qemu_free ((/* !const */ char * )opt -> str );
596
+ opt -> str = NULL ;
597
+ if (value ) {
598
+ opt -> str = qemu_strdup (value );
599
+ }
600
+ if (qemu_opt_parse (opt ) < 0 ) {
601
+ fprintf (stderr , "Failed to parse \"%s\" for \"%s.%s\"\n" , opt -> str ,
602
+ opts -> list -> name , opt -> name );
603
+ qemu_opt_del (opt );
604
+ return -1 ;
605
+ }
606
+ return 0 ;
607
+ }
608
+
609
+ QemuOpts * qemu_opts_find (QemuOptsList * list , const char * id )
610
+ {
611
+ QemuOpts * opts ;
612
+
613
+ TAILQ_FOREACH (opts , & list -> head , next ) {
614
+ if (!opts -> id ) {
615
+ continue ;
616
+ }
617
+ if (strcmp (opts -> id , id ) != 0 ) {
618
+ continue ;
619
+ }
620
+ return opts ;
621
+ }
622
+ return NULL ;
623
+ }
624
+
625
+ QemuOpts * qemu_opts_create (QemuOptsList * list , const char * id , int fail_if_exists )
626
+ {
627
+ QemuOpts * opts = NULL ;
628
+
629
+ if (id ) {
630
+ opts = qemu_opts_find (list , id );
631
+ if (opts != NULL ) {
632
+ if (fail_if_exists ) {
633
+ fprintf (stderr , "tried to create id \"%s\" twice for \"%s\"\n" ,
634
+ id , list -> name );
635
+ return NULL ;
636
+ } else {
637
+ return opts ;
638
+ }
639
+ }
640
+ }
641
+ opts = qemu_mallocz (sizeof (* opts ));
642
+ if (id ) {
643
+ opts -> id = qemu_strdup (id );
644
+ }
645
+ opts -> list = list ;
646
+ TAILQ_INIT (& opts -> head );
647
+ TAILQ_INSERT_TAIL (& list -> head , opts , next );
648
+ return opts ;
649
+ }
650
+
651
+ int qemu_opts_set (QemuOptsList * list , const char * id ,
652
+ const char * name , const char * value )
653
+ {
654
+ QemuOpts * opts ;
655
+
656
+ opts = qemu_opts_create (list , id , 1 );
657
+ if (opts == NULL ) {
658
+ fprintf (stderr , "id \"%s\" not found for \"%s\"\n" ,
659
+ id , list -> name );
660
+ return -1 ;
661
+ }
662
+ return qemu_opt_set (opts , name , value );
663
+ }
664
+
665
+ void qemu_opts_del (QemuOpts * opts )
666
+ {
667
+ QemuOpt * opt ;
668
+
669
+ for (;;) {
670
+ opt = TAILQ_FIRST (& opts -> head );
671
+ if (opt == NULL )
672
+ break ;
673
+ qemu_opt_del (opt );
674
+ }
675
+ TAILQ_REMOVE (& opts -> list -> head , opts , next );
676
+ qemu_free (opts );
677
+ }
678
+
679
+ int qemu_opts_print (QemuOpts * opts , void * dummy )
680
+ {
681
+ QemuOpt * opt ;
682
+
683
+ fprintf (stderr , "%s: %s:" , opts -> list -> name ,
684
+ opts -> id ? opts -> id : "<noid>" );
685
+ TAILQ_FOREACH (opt , & opts -> head , next ) {
686
+ fprintf (stderr , " %s=\"%s\"" , opt -> name , opt -> str );
687
+ }
688
+ fprintf (stderr , "\n" );
689
+ return 0 ;
690
+ }
691
+
692
+ QemuOpts * qemu_opts_parse (QemuOptsList * list , const char * params , const char * firstname )
693
+ {
694
+ char option [128 ], value [128 ], * id = NULL ;
695
+ QemuOpts * opts ;
696
+ const char * p ,* pe ,* pc ;
697
+
698
+ if (get_param_value (value , sizeof (value ), "id" , params ))
699
+ id = qemu_strdup (value );
700
+ opts = qemu_opts_create (list , id , 1 );
701
+ if (opts == NULL )
702
+ return NULL ;
703
+
704
+ p = params ;
705
+ for (;;) {
706
+ pe = strchr (p , '=' );
707
+ pc = strchr (p , ',' );
708
+ if (!pe || (pc && pc < pe )) {
709
+ /* found "foo,more" */
710
+ if (p == params && firstname ) {
711
+ /* implicitly named first option */
712
+ pstrcpy (option , sizeof (option ), firstname );
713
+ p = get_opt_value (value , sizeof (value ), p );
714
+ } else {
715
+ /* option without value, probably a flag */
716
+ p = get_opt_name (option , sizeof (option ), p , ',' );
717
+ if (strncmp (p , "no" , 2 ) == 0 ) {
718
+ memmove (option , option + 2 , strlen (option + 2 )+ 1 );
719
+ pstrcpy (value , sizeof (value ), "off" );
720
+ } else {
721
+ pstrcpy (value , sizeof (value ), "on" );
722
+ }
723
+ }
724
+ } else {
725
+ /* found "foo=bar,more" */
726
+ p = get_opt_name (option , sizeof (option ), p , '=' );
727
+ if (* p != '=' ) {
728
+ break ;
729
+ }
730
+ p ++ ;
731
+ p = get_opt_value (value , sizeof (value ), p );
732
+ }
733
+ if (strcmp (option , "id" ) != 0 ) {
734
+ /* store and parse */
735
+ if (-1 == qemu_opt_set (opts , option , value )) {
736
+ qemu_opts_del (opts );
737
+ return NULL ;
738
+ }
739
+ }
740
+ if (* p != ',' ) {
741
+ break ;
742
+ }
743
+ p ++ ;
744
+ }
745
+ return opts ;
746
+ }
747
+
748
+ int qemu_opts_foreach (QemuOptsList * list , qemu_opts_loopfunc func , void * opaque ,
749
+ int abort_on_failure )
750
+ {
751
+ QemuOpts * opts ;
752
+ int rc = 0 ;
753
+
754
+ TAILQ_FOREACH (opts , & list -> head , next ) {
755
+ rc = func (opts , opaque );
756
+ if (abort_on_failure && rc != 0 )
757
+ break ;
758
+ }
759
+ return rc ;
760
+ }
0 commit comments