@@ -182,6 +182,24 @@ static int parse_option_bool(const char *name, const char *value, int *ret)
182182 return 0 ;
183183}
184184
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+
185203static int parse_option_size (const char * name , const char * value , uint64_t * ret )
186204{
187205 char * postfix ;
@@ -444,3 +462,299 @@ void print_option_help(QEMUOptionParameter *list)
444462 list ++ ;
445463 }
446464}
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