+
+ my ($default_key, $keyAliasProps) = &$find_schema_default_key($format);
+
+ my $res = '';
+ my $add_sep = 0;
+
+ my $add_option_string = sub {
+ my ($text) = @_;
+
+ $res .= ',' if $add_sep;
+ $res .= $text;
+ $add_sep = 1;
+ };
+
+ my $format_value = sub {
+ my ($key, $value, $format) = @_;
+
+ if (defined($format) && ($format eq 'disk-size')) {
+ return format_size($value);
+ } else {
+ die "illegal value with commas for $key\n" if $value =~ /,/;
+ return $value;
+ }
+ };
+
+ my $done = { map { $_ => 1 } @$skip };
+
+ my $cond_add_key = sub {
+ my ($key, $isdefault) = @_;
+
+ return if $done->{$key}; # avoid duplicates
+
+ $done->{$key} = 1;
+
+ my $value = $data->{$key};
+
+ return if !defined($value);
+
+ my $phash = $format->{$key};
+
+ # try to combine values if we have key aliases
+ if (my $combine = $keyAliasProps->{$key}) {
+ if (defined(my $combine_value = $data->{$combine})) {
+ my $combine_format = $format->{$combine}->{format};
+ my $value_str = &$format_value($key, $value, $phash->{format});
+ my $combine_str = &$format_value($combine, $combine_value, $combine_format);
+ &$add_option_string("${value_str}=${combine_str}");
+ $done->{$combine} = 1;
+ return;
+ }
+ }
+
+ if ($phash && $phash->{alias}) {
+ $phash = $format->{$phash->{alias}};
+ }
+
+ die "invalid key '$key'\n" if !$phash;
+ die "internal error" if defined($phash->{alias});
+
+ my $value_str = &$format_value($key, $value, $phash->{format});
+ if ($isdefault) {
+ &$add_option_string($value_str);
+ } else {
+ &$add_option_string("$key=${value_str}");
+ }
+ };
+
+ # add default key first
+ &$cond_add_key($default_key, 1) if defined($default_key);
+
+ # add required keys first
+ foreach my $key (sort keys %$data) {
+ my $phash = $format->{$key};
+ &$cond_add_key($key) if $phash && !$phash->{optional};
+ }
+
+ # add the rest
+ foreach my $key (sort keys %$data) {
+ &$cond_add_key($key);
+ }
+
+ return $res;
+}
+
+sub schema_get_type_text {
+ my ($phash, $style) = @_;
+
+ my $type = $phash->{type} || 'string';
+
+ if ($phash->{typetext}) {
+ return $phash->{typetext};
+ } elsif ($phash->{format_description}) {
+ return "<$phash->{format_description}>";
+ } elsif ($phash->{enum}) {
+ return "<" . join(' | ', sort @{$phash->{enum}}) . ">";
+ } elsif ($phash->{pattern}) {
+ return $phash->{pattern};
+ } elsif ($type eq 'integer' || $type eq 'number') {
+ # NOTE: always access values as number (avoid converion to string)
+ if (defined($phash->{minimum}) && defined($phash->{maximum})) {
+ return "<$type> (" . ($phash->{minimum} + 0) . " - " .
+ ($phash->{maximum} + 0) . ")";
+ } elsif (defined($phash->{minimum})) {
+ return "<$type> (" . ($phash->{minimum} + 0) . " - N)";
+ } elsif (defined($phash->{maximum})) {
+ return "<$type> (-N - " . ($phash->{maximum} + 0) . ")";
+ }
+ } elsif ($type eq 'string') {
+ if (my $format = $phash->{format}) {
+ $format = get_format($format) if ref($format) ne 'HASH';
+ if (ref($format) eq 'HASH') {
+ my $list_enums = 0;
+ $list_enums = 1 if $style && $style eq 'config-sub';
+ return generate_typetext($format, $list_enums);
+ }
+ }
+ }
+
+ return "<$type>";