#!/usr/bin/env perl # # This is Menu layout table -> C struct compiler. # # Compiler is designed to parse structured menu definition files. Compiler # lacks advanced error and syntax checking and such, but it works. # # Copyright (c) 2016-2025, Jani Salonen # All rights reserved. # use 5.10.0; use utf8; use warnings; # This is version tag for output file and must match with the engine's # PACKAGE_VERSION # my $DSL_COMPILER_VER = "0.2.9"; # my $on_cnt = 0; my $on_dnr = 1; my $on_bar = ""; my $on_wnd = ""; my $on_ext = ""; my %BARPOS_ID = (); my @BARPOS_ID = (); my @WINDOW_ID = (); my %WINDOW_ST = (); my %LOCALE_ST = (); my %LOCALE_NR = (); my @UNVEIL_ST = (); # my %HEADER_ST = ( '@MENU_DEFAULT_TITLE_ORIENTATION' => '' ); my %HEADER_ST_MENU_DEFAULT_TITLE_ORIENTATION = ( 'default' => 1, 'left_to_right' => 1, 'right_to_left' => 1 ); # my @file_inc = (); binmode(STDOUT, ":utf8"); &menu_def({ file => $ARGV[0] }); &menu_out({ this => $0, file => $ARGV[0] }); exit(0); # sub menu_cmd_translate { my ($arg) = @_; $on_ext = ""; } sub menu_cmd_keyword { my ($arg) = @_; my $p = $arg->{line}; $p =~ s/^\s*['"]//; $p =~ s/['"]\s*{*\s*$//; if($p eq "") { &msg_fail({ mess => "Empty translation keyword " . "is not allowed" }); return; } $on_ext = $p; $LOCALE_NR{$on_ext} = $on_dnr++; $LOCALE_ST{$on_ext} = {}; } sub menu_cmd_locale { my ($arg) = @_; if($on_ext eq "") { &msg_fail({ mess => "Translation keyword must be " . "inside translate block" }); return; } my ($k, $v) = split(/\s*:\s*/, $arg->{line}, 2); return if(!$k || !$v); $v =~ s/^\s*['"]//; $v =~ s/['"]\s*$//; $LOCALE_ST{$on_ext}{$k} = $v; } # sub menu_cmd_window { my ($arg) = @_; my ($p) = $arg->{line} =~ /"(.*?)"/; if($p == 0) { &msg_fail({ mess => "Invalid window identified, " . "it cannot be zero" }); return; } if($p !~ /^\d+$/) { &msg_fail({ mess => "Invalid window identifier '" . $p . "', positive integer was expected" }); return; } if($WINDOW_ST{$p}) { &msg_fail({ mess => "Window definition '" . $p . "' already exists" }); return; } push @{ $BARPOS_ID{$on_bar} }, $arg->{deep} . "\t" . "END" if($on_bar ne ""); $on_bar = ""; $on_wnd = $p; push @WINDOW_ID, $on_wnd; } sub menu_cmd_widget { my ($arg) = @_; my ($p) = $arg->{line} =~ /"(.*?)"/; if($p !~ /^\w+$/) { &msg_fail({ mess => "Invalid widget identifier '" . $p . "', character string was expected" }); return; } if($on_wnd == 0) { &msg_fail({ mess => "Widget definition '" . $p . "' must be placed in window block with nonzero id" }); return; } push @{ $BARPOS_ID{$on_bar} }, $arg->{deep} . "\t" . "END" if($on_bar ne ""); $on_bar = ""; $on_wnd = $p; push @WINDOW_ID, $on_wnd; } sub menu_cmd_menu { my ($arg) = @_; my ($p) = $arg->{line} =~ /"(.*?)"/; my ($t) = $arg->{line} =~ /\[\s*(.*?)\s*\]/; $arg->{line} =~ s/\s*\[.*\]\s*//; my (@p) = split(/\s?{\s?/, $arg->{line}); if($p eq "" || !@p) { return; } my @r = &menu_cmd_op_one_with_quote({ line => \@p }); $p =~ s/\t/ /go; if($t) { # Handle attributes # my %r = &menu_cmd_op_attr({ item => "menu", attr => $t }); $t = ""; foreach my $k (sort { lc($a) cmp lc($b) } keys %r) { $t .= $k . ":" . $r{$k} . ","; } $t =~ s/,$//; } else { # No attributes for this menu # $t = "NONE"; } push @{ $BARPOS_ID{$on_bar} }, $arg->{deep} . "\t" . "STOP" . "\t" . $p; $on_bar = ($arg->{deep} + 1) . "\t" . $p . "\t" . $r[0] . "\t" . $t . "\t" . ++$on_cnt; push @{ $WINDOW_ST{$on_wnd} }, $on_bar; } # sub menu_cmd_item { my ($arg) = @_; my ($p) = $arg->{line} =~ /"(.*?)"/; my ($t) = $arg->{line} =~ /\[\s*(.*?)\s*\]/; $arg->{line} =~ s/\s*\[.*\]\s*//; # Split the line by comma, but not by commas inside parentheses # my (@p) = split(/\s?,\s?(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/, $arg->{line}); if($p eq "" || !@p) { return; } my @r = &menu_cmd_op_five_with_quote({ line => \@p }); if($t) { # Handle attributes # my %r = &menu_cmd_op_attr({ item => "item", attr => $t }); $t = ""; foreach my $k (sort { lc($a) cmp lc($b) } keys %r) { $t .= $k . ":" . $r{$k} . ","; } $t =~ s/,$//; push @r, $t if($t ne ""); } push @{ $BARPOS_ID{$on_bar} }, $arg->{deep} . "\t" . "ITEM" . "\t" . $p . "\t" . join("\t", @r); } sub menu_cmd_check { my ($arg) = @_; my ($p) = $arg->{line} =~ /"(.*?)"/; my ($t) = $arg->{line} =~ /\[\s*(.*?)\s*\]/; $arg->{line} =~ s/\s*\[.*\]\s*//; # Split the line by comma, but not by commas inside parentheses # my (@p) = split(/\s?,\s?(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/, $arg->{line}); if($p eq "" || !@p) { return; } my @r = &menu_cmd_op_five_with_quote({ line => \@p }); if($t) { # Handle attributes # my %r = &menu_cmd_op_attr({ item => "check", attr => $t }); $t = ""; foreach my $k (sort { lc($a) cmp lc($b) } keys %r) { $t .= $k . ":" . $r{$k} . ","; } $t =~ s/,$//; push @r, $t if($t ne ""); } push @{ $BARPOS_ID{$on_bar} }, $arg->{deep} . "\t" . "CHECK" . "\t" . $p . "\t" . join("\t", @r); } sub menu_cmd_radio { my ($arg) = @_; my ($p) = $arg->{line} =~ /"(.*?)"/; my ($t) = $arg->{line} =~ /\[\s*(.*?)\s*\]/; $arg->{line} =~ s/\s*\[.*\]\s*//; # Split the line by comma, but not by commas inside parentheses # my (@p) = split(/\s?,\s?(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/, $arg->{line}); if($p eq "" || !@p) { return; } my @r = &menu_cmd_op_five_with_quote({ line => \@p }); if($t) { # Handle attributes # my %r = &menu_cmd_op_attr({ item => "radio", attr => $t }); $t = ""; foreach my $k (sort { lc($a) cmp lc($b) } keys %r) { $t .= $k . ":" . $r{$k} . ","; } $t =~ s/,$//; push @r, $t if($t ne ""); } push @{ $BARPOS_ID{$on_bar} }, $arg->{deep} . "\t" . "RADIO" . "\t" . $p . "\t" . join("\t", @r); } sub menu_cmd_title { my ($arg) = @_; my ($p) = $arg->{line} =~ /"(.*?)"/; $p =~ s/\t/ /go; push @{ $BARPOS_ID{$on_bar} }, $arg->{deep} . "\t" . "TITLE" . "\t" . $p; } sub menu_cmd_delim { my ($arg) = @_; push @{ $BARPOS_ID{$on_bar} }, $arg->{deep} . "\t" . "DELIM"; } sub menu_cmd_space { my ($arg) = @_; push @{ $BARPOS_ID{$on_bar} }, $arg->{deep} . "\t" . "SPACE"; } # sub menu_cmd_op_attr { my ($arg) = @_; # Attribute aliases # my %c = ( 'bg' => 'background' ); my %r = (); if($arg->{attr}) { my @p = split(/\s*,\s*/, $arg->{attr}); foreach my $p (@p) { my ($e, $o) = split(/\s*[:=]\s*/, $p, 2); $e = $c{lc($e)} if($c{lc($e)}); my $f = "menu_cmd_op_attr_at_" . lc($e); if(defined &$f) { $r{lc($e)} = &$f({ attr => $o }); } else { &msg_fail({ mess => "Unknown attribute '" . $e . "' for statement '" . $arg->{item} . "'" }); return; } } } return %r; } sub menu_cmd_op_attr_at_background { my ($arg) = @_; return $arg->{attr}; } sub menu_cmd_op_attr_at_disabled { my ($arg) = @_; return &menu_cmd_op_attr_bool({ attr => $arg->{attr} }); } sub menu_cmd_op_attr_at_hidden { my ($arg) = @_; return &menu_cmd_op_attr_bool({ attr => $arg->{attr} }); } sub menu_cmd_op_attr_at_hilight { my ($arg) = @_; return $arg->{attr}; } sub menu_cmd_op_attr_at_icon { my ($arg) = @_; return $arg->{attr}; } sub menu_cmd_op_attr_at_icon_hue { my ($arg) = @_; my $r = &menu_cmd_op_attr_num({ attr => $arg->{attr} }); if($r < 0) { &msg_warn({ mess => "Icon hue " . $r . " is out of range, setting it to zero" }); $r = 0; } elsif($r > 359) { &msg_warn({ mess => "Icon hue " . $r . " is out of range, setting it to 359" }); $r = 359; } return $r; } sub menu_cmd_op_attr_at_icon_saturation { my ($arg) = @_; my $r = &menu_cmd_op_attr_num({ attr => $arg->{attr} }); if($r < -100) { &msg_warn({ mess => "Icon saturation " . $r . " is out of range, setting it to -100" }); $r = -100; } elsif($r > 100) { &msg_warn({ mess => "Icon saturation " . $r . " is out of range, setting it to 100" }); $r = 100; } return $r; } sub menu_cmd_op_attr_at_icon_value { my ($arg) = @_; my $r = &menu_cmd_op_attr_num({ attr => $arg->{attr} }); if($r < -100) { &msg_warn({ mess => "Icon value " . $r . " is out of range, setting it to -100" }); $r = -100; } elsif($r > 100) { &msg_warn({ mess => "Icon value " . $r . " is out of range, setting it to 100" }); $r = 100; } return $r; } sub menu_cmd_op_attr_bool { my ($arg) = @_; my %o = ( # (n)o # "n" => "n", # (d)isable # "d" => "n", # (f)alse # "f" => "n", # (0) # "0" => "n", # (y)es # "y" => "y", # (e)nable # "e" => "y", # (t)rue # "t" => "y", # (1) # "1" => "y" ); my $p = lc(substr($arg->{attr}, 0, 1)); if(!$o{$p}) { &msg_fail({ mess => "Unknown attribute bool value '" . $arg->{attr} . "'" }); return; } return $o{$p}; } sub menu_cmd_op_attr_num { my ($arg) = @_; if($arg->{attr} !~ /^([+-])?[0-9.]+([eE][0-9]+)?$/) { &msg_fail({ mess => "Unknown attribute number value '" . $arg->{attr} . "'" }); return; } return $arg->{attr}; } # sub menu_cmd_op_one_with_quote { my ($arg) = @_; my @p = @{ $arg->{line} }; shift @p; return &menu_cmd_at({ line => \@p, loop => 1 }); } sub menu_cmd_op_five_with_quote { my ($arg) = @_; my @p = @{ $arg->{line} }; shift @p; return &menu_cmd_at({ line => \@p, loop => 5 }); } sub menu_cmd_at { my ($arg) = @_; my @p = @{ $arg->{line} }; my @r = (); for(my $i = 0; $i < $arg->{loop}; $i++) { if(!$p[$i] || ($p[$i] && ($p[$i] eq "" || $p[$i] eq "-"))) { push @r, "NONE"; } else { push @r, $p[$i]; } } return @r; } sub menu_cmd { my ($arg) = @_; my @f = @{ $arg->{file} }; my $n = 0; foreach my $f (@f) { if($f =~ /^\w+\s?{/) { # This is translate block # my $c = $f; $c =~ s/\s*{.*$//; &menu_cmd_op({ cmds => $c, line => "", deep => $n }); } elsif($f =~ /^"(.*)"\s*{/) { # This is keyword to be translated # &menu_cmd_op({ cmds => "keyword", line => $f, deep => $n }); } elsif($f =~ /\w+\s*:\s*"(.*)"/) { # This is translated keyword for above # &menu_cmd_op({ cmds => "locale", line => $f, deep => $n }); } elsif($f =~ /^\w+(\s*\[\s*(.*)\s*\])?\s*"(.*)"\s*[,{]/ || $f =~ /^\w+\s*"(.*)"$/) { # This is either window, widget, menu, title, # or one of the menu items # my ($c, $p) = split(/\s/, $f, 2); &menu_cmd_op({ cmds => $c, line => $p, deep => $n }); } elsif($f =~ /^\w+$/) { # This is either delim or space # &menu_cmd_op({ cmds => $f, line => "", deep => $n }); } $n += $f =~ tr/{$//; $n -= $f =~ tr/}$//; } } sub menu_cmd_op { my ($arg) = @_; my $s = "menu_cmd_" . lc($arg->{cmds}); if(defined &$s) { &$s({ line => $arg->{line}, deep => $arg->{deep} }); } else { &msg_fail({ mess => "Unknown identifier '" . $arg->{cmds} . "'" }); return; } } sub menu_pre { my ($arg) = @_; my @f = @{ $arg->{file} }; my @r = (); my $o = ""; foreach my $f (@f) { $f =~ s/\r+|\n+//g; $f =~ s/^\s+//; $f =~ s/\s+$//; $f =~ s/\s\s+/ /g; next if($f eq ""); # Check for header tags first... # if($f =~ /^;/ || $f =~ /^#/) { $f =~ s/^[;#]\s*//; next if($f eq ""); if($f =~ /^\@MENU_/i) { my @k = split(/\s+/, $f, 2); $HEADER_ST{uc($k[0])} = $k[1] if($k[1]); } next; } # ...and then check if this is multiline... # if($f =~ /\\$/) { $f =~ s/\\$//; $o .= $f; next; } else { $o .= $f; } # ...or preprocessor command # if($o =~ /^include\s"(.*)"/i) { my ($p) = $o =~ /"(.*)"/; push @r, &menu_get({ file => $p }); } else { push @r, $o; } $o = ""; } return @r; } sub menu_get { my ($arg) = @_; my @f = (); my @r = (); my %m = (); if(!$arg->{file}) { &msg_fail({ mess => "Please provide source file to process" }); return @r; } if(!stat($arg->{file})) { &msg_fail({ mess => "Failed to open source file '" . $arg->{file} . "'" }); return @r; } # Try to detect include loop first... # push @file_inc, $arg->{file}; for(my $i = 0; $i < @file_inc; $i++) { if(defined($file_inc[$i + 1]) && $m{$file_inc[$i + 1]}) { &msg_fail({ mess => "Include loop detected, '" . $file_inc[$i] . "' to include '" . $arg->{file} . "'" }); return; } $m{$file_inc[$i]} = 1; } # ...then open and process the file # if(open(FILE, '<:encoding(UTF-8)', $arg->{file})) { @f = ; close(FILE); } else { &msg_fail({ mess => "Failed to open file '" . $arg->{file} . "'" }); return; } @r = &menu_pre({ file => \@f }); return @r; } sub menu_def { my ($arg) = @_; # if(!$arg->{file} || ($arg->{file} && !stat($arg->{file}))) { &menu_out_min(); } my @r = &menu_get({ file => $arg->{file} }); &menu_cmd({ file => \@r }); } # sub menu_out { my ($arg) = @_; &menu_out_bg({ this => $arg->{this}, file => $arg->{file} }); &menu_out_tr(); # Loop through windows and widgets... # foreach my $c (@WINDOW_ID) { my $d = 1; my $k = 0; my @p = (); # ...then loop through menu bars for this window or widget... # foreach my $x (@{ $WINDOW_ST{$c} }) { my $e = 1; my $m = 0; my $n = 0; my @s = (); my @e = split(/\t+/, $x); # ...and the actual menu items # for(my $j = 0; $j < @{ $WINDOW_ST{$c} }; $j++) { last unless(@{ $WINDOW_ST{$c} }[$j + $k]); my $y = @{ $WINDOW_ST{$c} }[$j + $k]; foreach my $z (@{ $BARPOS_ID{$y} }) { my @f = split(/\t+/, $z); # Stop here if level decrements and there # is stop command next in line... # if($f[0] < $n) { # If e0 and f0 equals, this was the end of # submenu, do not stop then as we need to # process the rest of the parent menu # if($e[0] != $f[0] || $f[1] eq "STOP") { $j = @{ $WINDOW_ST{$c} }; last; } } # ...otherwise get current level of depth... # $n = $f[0]; # ...and handle this item only if level of # depth matches to parent # if($e[0] == $f[0]) { if($f[1] eq "SPACE") { &menu_out_it({ type => "MENU_ITEM_TYPE_GAP", mbar => $c, drop => $d, item => $e, mtag => 0 }); } elsif($f[1] eq "DELIM") { &menu_out_it({ type => "MENU_ITEM_TYPE_SEPARATOR", mbar => $c, drop => $d, item => $e, mtag => 0 }); } elsif($f[1] eq "TITLE") { &menu_out_it({ type => "MENU_ITEM_TYPE_TITLE", name => $f[2], mbar => $c, drop => $d, item => $e, mtag => 0 }); } elsif($f[1] eq "CHECK") { &menu_out_it({ type => "MENU_ITEM_TYPE_SELECT_TOGGLE", name => $f[2], cbfn => "menu_cb_item_select", skey => $f[4], cbfb => $f[5], flag => $f[6], icon => $f[7], mbar => $c, drop => $d, item => $e, mtag => $f[3], attr => $f[8] }); } elsif($f[1] eq "RADIO") { &menu_out_it({ type => "MENU_ITEM_TYPE_SELECT_RADIO", name => $f[2], cbfn => "menu_cb_item_select", skey => $f[4], cbfb => $f[5], flag => $f[6], icon => $f[7], mbar => $c, drop => $d, item => $e, mtag => $f[3], attr => $f[8] }); } elsif($f[1] eq "ITEM") { &menu_out_it({ type => "MENU_ITEM_TYPE_SELECT_ONCE", name => $f[2], cbfn => "menu_cb_item_select", skey => $f[4], cbfb => $f[5], flag => $f[6], icon => $f[7], mbar => $c, drop => $d, item => $e, mtag => $f[3], attr => $f[8] }); } elsif($f[1] eq "STOP") { # Add one more to each submenu offset # &menu_out_it({ type => "MENU_ITEM_TYPE_SUBMENU", name => $f[2], icon => $f[3], msub => $d + $m++, mbar => $c, drop => $d, item => $e, mtag => 0 }); } # Create item to parent container only if it is # real, selectable item # push @s, $e++ if($f[1] ne "END"); } } } $k++; # Checking level is naive way to test if this is submenu, # and if so, remove name and icon from it to prevent it # to appear on menu bar... # if($e[0] > 2) { if($e[0] > 3) { # ...if level is more than three, is is # submenu for sure... # $e[1] = "NONE"; $e[2] = "NONE"; } # ...but remove name and icon only if this menu is # not attached to widget # elsif($c =~ /^[0-9]+$/) { $e[1] = "NONE"; $e[2] = "NONE"; } } &menu_out_op({ mbar => $c, mids => \@s, drop => $d, name => $e[1], icon => $e[2], attr => $e[3] }); push @p, $d++; } # &menu_out_at({ mbar => $c, mids => \@p }); } # print STDOUT "/* Root of all menu definitions */" . "\n"; print STDOUT "static struct menu_stack menu_stack_t[" . (@WINDOW_ID + 1) . "] = {" . "\n"; foreach my $c (@WINDOW_ID) { if($c =~ /^[0-9]+$/) { print STDOUT "\t" . "/* Menu attached to window id " . $c . " */" . "\n"; print STDOUT "\t" . "{ 0, " . $c . ", NULL, 0, &menu_bar_" . $c . " }," . "\n"; } else { print STDOUT "\t" . "/* Menu attached to widget id " . $c . " */" . "\n"; print STDOUT "\t" . "{ 0, 0, (\"" . &menu_out_hex_bytes({ str => $c }) . "\"), " . &menu_out_len_bytes({ str => $c }) . ", &menu_bar_" . $c . " }," . "\n"; } } print STDOUT "\n\t" . "{ 0, 0, NULL, 0, NULL }" . "\n"; print STDOUT "};\n\n"; # &menu_out_eg({ file => $arg->{file} }); } sub menu_out_it { my ($arg) = @_; # Known attributes for item # my %c = ( 'disabled' => '', 'hidden' => '', 'icon' => '', 'icon_hue' => '', 'icon_saturation' => '', 'icon_value' => '' ); # Known menu flags as attributes # my @c = ( 'disabled', 'hidden' ); if($arg->{attr} && $arg->{attr} ne "NONE") { my @p = split(/\s*,\s*/, $arg->{attr}); foreach my $p (@p) { my ($e, $o) = split(/\s*[:=]\s*/, $p, 2); if(defined $c{$e}) { $c{$e} = $o; } else { &msg_fail({ mess => "Unknown attribute '" . $e . "' for item '" . $arg->{name} . "'" }); return; } } } # my $s = 0; my %f = (); if($arg->{mtag} !~ /^[0-9]+$/) { &msg_fail({ mess => "Definition for '" . $arg->{name} . "' needs proper id tag, not '" . $arg->{mtag} . "'" }); return; } # $s = $arg->{msub} if($arg->{msub} && $arg->{msub} =~ /^[0-9]+$/); if($arg->{flag} && $arg->{flag} !~ /^NONE$/i) { my @f = split(/\|/, $arg->{flag}); foreach my $f (@f) { $f =~ s/^\s+//; $f =~ s/\s+$//; $f{$f} = 1; } } # print STDOUT "/* Menu item " . $arg->{item} . " for drop down menu " . $arg->{drop} . ", in menu bar " . $arg->{mbar} . " */" . "\n"; print STDOUT "static struct menu_item menu_item_" . $arg->{mbar} . "_" . $arg->{drop} . "_" . $arg->{item} . " = {" . "\n"; print STDOUT "\t" . $arg->{type} . ", IS_NO," . "\n"; # &menu_out_it_op({ name => $arg->{name}, flag => \%f }); # my @j = (); foreach my $i (@c) { if($c{$i} && $c{$i} =~ /^y/) { push @j, "MENU_ITEM_FLAG_" . uc($i); } } if(@j) { print STDOUT "\t\t" . join(" |\n\t\t\t", @j) . "," . "\n"; } else { print STDOUT "\t\t" . "0," . "\n"; } # print STDOUT "\t" . "0, " . $arg->{mtag} . ", " . $s . ", 0, 0, 0," . "\n"; if($arg->{skey} && $arg->{skey} !~ /^NONE$/i) { print STDOUT "\t" . "(\"" . &menu_out_hex_bytes({ str => $arg->{skey} }) . "\"), IS_NO, IS_NO," . "\n"; } else { print STDOUT "\t" . "NULL, IS_NO, IS_NO," . "\n"; } # print STDOUT "\t" . "/* This is struct menu_coords */" . "\n"; print STDOUT "\t" . "{ 0, 0, 0, 0, 0, 0 }," . "\n"; # print STDOUT "\t" . "/* This is struct menu_label */" . "\n"; if($arg->{name} && $arg->{name} !~ /^NONE$/i) { print STDOUT "\t" . "{ (\"" . &menu_out_hex_bytes({ str => $arg->{name} }) . "\"), NULL, " . &menu_out_len_chars({ str => $arg->{name} }) . "," . "\n"; } else { print STDOUT "\t" . "{ NULL, NULL, 0," . "\n"; } if($HEADER_ST{'@MENU_DEFAULT_TITLE_ORIENTATION'}) { my $w = $HEADER_ST{'@MENU_DEFAULT_TITLE_ORIENTATION'}; if($HEADER_ST_MENU_DEFAULT_TITLE_ORIENTATION{$w}) { print STDOUT "\t\t" . "MENU_TITLE_ORIENTATION_" . uc($w) . "," . "\n"; } else { &msg_fail({ mess => "Invalid title orientation '" . $w . "' for menu item '" . $arg->{name} . "'" }); } } else { print STDOUT "\t\t" . "MENU_TITLE_ORIENTATION_DEFAULT," . "\n"; } print STDOUT "\t\t" . "{ 0, 0, 0 }," . "\n"; print STDOUT "\t\t" . "{ 0, 0, 0 }," . "\n"; if($arg->{name} && $LOCALE_ST{$arg->{name}}) { print STDOUT "\t\t" . "menu_locale_" . $LOCALE_NR{$arg->{name}} . "\n"; } else { print STDOUT "\t\t" . "NULL" . "\n"; } print STDOUT "\t" . "}," . "\n"; # print STDOUT "\t" . "/* This is struct menu_icon */" . "\n"; if(($arg->{icon} && $arg->{icon} !~ /^NONE$/i) || $c{'icon'}) { my $n = ""; if($c{'icon'}) { $n = $c{'icon'}; } else { $n = $arg->{icon}; } # Store icon path to be used later by unveil() # push @UNVEIL_ST, $n; print STDOUT "\t" . "{ 0, (\"" . &menu_out_hex_bytes({ str => $n }) . "\")," . "\n"; } else { print STDOUT "\t" . "{ 0, NULL," . "\n"; } if($c{'icon_hue'}) { print STDOUT "\t\t" . $c{'icon_hue'} . "f, "; } else { print STDOUT "\t\t" . "0.0f, "; } if($c{'icon_saturation'}) { print STDOUT $c{'icon_saturation'} . "f, "; } else { print STDOUT "0.0f, "; } if($c{'icon_value'}) { print STDOUT $c{'icon_value'} . "f," . "\n"; } else { print STDOUT "0.0f," . "\n"; } print STDOUT "\t\t" . "{ 0, 0, 0, 0, 0, 0 }," . "\n"; print STDOUT "\t\t" . "NULL" . "\n"; print STDOUT "\t" . "}," . "\n"; print STDOUT "\t" . "/* This is struct menu_cb */" . "\n"; print STDOUT "\t" . "{" . "\n"; # if($arg->{cbfn} && $arg->{cbfn} !~ /^NONE$/i) { print STDOUT "\t\t" . $arg->{cbfn} . "," . "\n"; } else { print STDOUT "\t\t" . "NULL," . "\n"; } print STDOUT "\t\t" . "/* This is struct d_par */" . "\n"; if($arg->{cbfb} && $arg->{cbfb} !~ /^NONE$/i) { print STDOUT "\t\t" . "{ (\"" . &menu_out_hex_bytes({ str => $arg->{cbfb} }) . "\"), 0, 0, 0, 0, {" . "\n"; } else { print STDOUT "\t\t" . "{ NULL, 0, 0, 0, 0, {" . "\n"; } # print STDOUT "\t\t\t" . "/* This is struct d_par_t */" . "\n"; for(my $i = 0; $i < 15; $i++) { print STDOUT "\t\t\t" . "{ 0, 0, 0, { 0 } }," . "\n"; } print STDOUT "\t\t\t" . "{ 0, 0, 0, { 0 } } }" . "\n"; print STDOUT "\t\t" . "}," . "\n"; print STDOUT "\t\t" . "/* This is struct w_par */" . "\n"; print STDOUT "\t\t" . "{ 0, " . "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, " . "0, 0, 0, " . "0, 0, " . "0.0f, " . "0, 0," . "\n"; print STDOUT "#if ! defined(PROG_DISABLE_WIDGET)" . "\n"; print STDOUT "\t\t\t" . "0, 0, NULL," . "\n"; print STDOUT "#endif" . "\n"; print STDOUT "\t\t\t" . "0," . "\n"; print STDOUT "\t\t\t" . "{ 0, 0, 0, 0, 0, 0, 0, 0 }," . "\n"; print STDOUT "\t\t\t" . "0, NULL, 0, NULL, { { 0, 0, 0, 0 } }" . "\n"; print STDOUT "\t\t" . "}" . "\n"; print STDOUT "\t" . "}" . "\n"; print STDOUT "};" . "\n\n"; } sub menu_out_it_op { my ($arg) = @_; my @d = ( 'disabled', 'norun_callback_onload', 'follow_settings_saving', 'sync_settings_on_change', 'sync_settings_on_set', 'sync_settings_on_unset' ); my %e = ( 'disabled' => 'DISABLED', 'norun_callback_onload' => 'NORUN_CB_ONLOAD', 'follow_settings_saving' => 'FOLLOW_SETTINGS_SAVING', 'sync_settings_on_change' => 'SYNC_SETTINGS_ON_CHANGE', 'sync_settings_on_set' => 'SYNC_SETTINGS_ON_SET', 'sync_settings_on_unset' => 'SYNC_SETTINGS_ON_UNSET' ); my %f = %{ $arg->{flag} }; # Check the flags # while(my ($o, $p) = each %f) { if(!$e{$o}) { &msg_fail({ mess => "Unknown flag '" . $o . "' for menu '" . $arg->{name} . "'" }); return; } } my @r = (); foreach my $d (@d) { if($f{$d}) { push @r, "MENU_ITEM_FLAG_" . $e{$d}; } } # Menu item initial toggle state... # if($f{'checked'}) { print STDOUT "\t" . "IS_YES," . "\n"; } else { print STDOUT "\t" . "IS_NO," . "\n"; } # ...and rest of the flags # if(@r) { print STDOUT "\t" . join(" |\n\t\t", @r) . " |" . "\n"; } else { print STDOUT "\t" . "0 |" . "\n"; } } sub menu_out_op { my ($arg) = @_; # Known attributes for menu # my %c = ( 'background' => '', 'disabled' => '', 'hidden' => '', 'hilight' => '', 'icon' => '', 'icon_hue' => '', 'icon_saturation' => '', 'icon_value' => '' ); # Known menu flags as attributes # my @c = ( 'disabled', 'hidden' ); if($arg->{attr} && $arg->{attr} ne "NONE") { my @p = split(/\s*,\s*/, $arg->{attr}); foreach my $p (@p) { my ($e, $o) = split(/\s*[:=]\s*/, $p, 2); if(defined $c{$e}) { $c{$e} = $o; } else { &msg_fail({ mess => "Unknown attribute '" . $e . "' for menu '" . $arg->{name} . "'" }); return; } } } # my @p = @{ $arg->{mids} }; print STDOUT "/* Menu items for drop down menu " . $arg->{drop} . ", in menu bar " . $arg->{mbar} . " */" . "\n"; print STDOUT "static struct menu_item *menu_item_" . $arg->{mbar} . "_" . $arg->{drop} . "_t[" . @p . "] = {" . "\n"; for(my $i = 0; $i < @p; $i++) { print STDOUT "\t" . "&menu_item_" . $arg->{mbar} . "_" . $arg->{drop} . "_" . $p[$i]; print STDOUT "," . "\n" if($i != @p - 1); } print STDOUT "\n" . "};" . "\n\n"; # print STDOUT "/* Drop down menu " . $arg->{drop} . ", in menu bar " . $arg->{mbar} . " */" . "\n"; print STDOUT "static struct menu_drop menu_drop_" . $arg->{mbar} . "_" . $arg->{drop} . " = {" . "\n"; # print STDOUT "\t" . "/* This is struct menu_coords */" . "\n"; print STDOUT "\t" . "{ 0, 0, 0, 0, 0, 0 }," . "\n"; # print STDOUT "\t" . "IS_NO, 0," . "\n"; # my @j = (); foreach my $i (@c) { if($c{$i} && $c{$i} =~ /^y/) { push @j, "MENU_ITEM_FLAG_" . uc($i); } } if(@j) { print STDOUT "\t" . join(" |\n\t\t", @j) . "," . "\n"; } else { print STDOUT "\t" . "0," . "\n"; } # print STDOUT "\t" . "0, 0, 0, 0, 0, 0," . "\n"; # if($c{'hilight'}) { print STDOUT &menu_out_op_color({ line => $c{'hilight'} }) . "\n"; } else { print STDOUT "\t" . "{ { { 0, 0, 0, 0 } } }," . "\n"; } if($c{'background'}) { print STDOUT &menu_out_op_color({ line => $c{'background'} }) . "\n"; } else { print STDOUT "\t" . "{ { { 0, 0, 0, 0 } } }," . "\n"; } # print STDOUT "\t" . "/* This is struct menu_coords */" . "\n"; print STDOUT "\t" . "{ 0, 0, 0, 0, 0, 0 }," . "\n"; # print STDOUT "\t" . "/* This is struct menu_label */" . "\n"; if($arg->{name} && $arg->{name} !~ /^NONE$/i) { print STDOUT "\t" . "{ (\"" . &menu_out_hex_bytes({ str => $arg->{name} }) . "\"), NULL, " . &menu_out_len_chars({ str => $arg->{name} }) . "," . "\n"; } else { print STDOUT "\t" . "{ NULL, NULL, 0," . "\n"; } if($HEADER_ST{'@MENU_DEFAULT_TITLE_ORIENTATION'}) { my $w = $HEADER_ST{'@MENU_DEFAULT_TITLE_ORIENTATION'}; if($HEADER_ST_MENU_DEFAULT_TITLE_ORIENTATION{$w}) { print STDOUT "\t\t" . "MENU_TITLE_ORIENTATION_" . uc($w) . "," . "\n"; } else { &msg_fail({ mess => "Invalid title orientation '" . $w . "' for drop down menu '" . $arg->{name} . "'" }); } } else { print STDOUT "\t\t" . "MENU_TITLE_ORIENTATION_DEFAULT," . "\n"; } print STDOUT "\t\t" . "{ 0, 0, 0 }," . "\n"; print STDOUT "\t\t" . "{ 0, 0, 0 }," . "\n"; if($arg->{name} && $LOCALE_ST{$arg->{name}}) { print STDOUT "\t\t" . "menu_locale_" . $LOCALE_NR{$arg->{name}} . "\n"; } else { print STDOUT "\t\t" . "NULL" . "\n"; } print STDOUT "\t" . "}," . "\n"; # print STDOUT "\t" . "/* This is struct menu_icon */" . "\n"; if(($arg->{icon} && $arg->{icon} !~ /^NONE$/i) || $c{'icon'}) { my $n = ""; if($c{'icon'}) { $n = $c{'icon'}; } else { $n = $arg->{icon}; } # Store icon path to be used later by unveil() # push @UNVEIL_ST, $n; print STDOUT "\t" . "{ 0, (\"" . &menu_out_hex_bytes({ str => $n }) . "\")," . "\n"; } else { print STDOUT "\t" . "{ 0, NULL," . "\n"; } if($c{'icon_hue'}) { print STDOUT "\t\t" . $c{'icon_hue'} . "f, "; } else { print STDOUT "\t\t" . "0.0f, "; } if($c{'icon_saturation'}) { print STDOUT $c{'icon_saturation'} . "f, "; } else { print STDOUT "0.0f, "; } if($c{'icon_value'}) { print STDOUT $c{'icon_value'} . "f," . "\n"; } else { print STDOUT "0.0f," . "\n"; } print STDOUT "\t\t" . "{ 0, 0, 0, 0, 0, 0 }," . "\n"; print STDOUT "\t\t" . "NULL" . "\n"; print STDOUT "\t" . "}," . "\n"; print STDOUT "\t" . "NULL, NULL, NULL," . "\n"; print STDOUT "\t" . @p . "," . "\n"; print STDOUT "\t" . "menu_item_" . $arg->{mbar} . "_" . $arg->{drop} . "_t" . "\n"; print STDOUT "};" . "\n\n"; } sub menu_out_op_color { my ($arg) = @_; my @c = split(/:/, $arg->{line}); if(@c < 2) { my $c = &menu_colors_x11(); my %c = %{ $c }; if($c{lc($c[0])}) { $c[1] = $c{lc($c[0])}; } else { $c[1] = $arg->{line}; } $c[0] = "rgb"; } # substr($c[1], 0, 1, "") if($c[1] =~ /^#/); substr($c[1], 0, 2, "") if($c[1] =~ /^0x/i); # my @r = (0, 0, 0, 255); foreach my $c (split(//, $c[0])) { my $d = substr($c[1], 0, 2, ""); if($d eq "") { &msg_fail({ mess => "Color definition '" . $arg->{line} . "' is invalid" }); return; } $d = "0x" . $d; if($c =~ /r/i) { $r[0] = $d; } elsif($c =~ /g/i) { $r[1] = $d; } elsif($c =~ /b/i) { $r[2] = $d; } elsif($c =~ /a/i) { $r[3] = $d; } } # return "#if defined(IS_BIGENDIAN)" . "\n" . "\t" . "{ { { " . join(", ", @r) . " } } }," . "\n" . "#else" . "\n" . "\t" . "{ { { " . join(", ", reverse(@r)) . " } } }," . "\n" . "#endif"; } sub menu_out_at { my ($arg) = @_; my @p = @{ $arg->{mids} }; # print STDOUT "/* Drop down menus for menu bar " . $arg->{mbar} . " */" . "\n"; print STDOUT "static struct menu_drop *menu_drop_" . $arg->{mbar} . "_t[" . @p . "] = {" . "\n"; for(my $i = 0; $i < @p; $i++) { print STDOUT "\t" . "&menu_drop_" . $arg->{mbar} . "_" . $p[$i]; print STDOUT "," . "\n" if($i != @p - 1); } print STDOUT "\n" . "};" . "\n\n"; # print STDOUT "/* Menu bar " . $arg->{mbar} . " */" . "\n"; print STDOUT "static struct menu_bar menu_bar_" . $arg->{mbar} . " = {" . "\n"; print STDOUT "\t" . "{ 0, 0, 0, 0, 0, 0 }," . "\n"; print STDOUT "\t" . "IS_NO, 0, 0, 0, 0," . "\n"; print STDOUT "\t" . "{ { { 0, 0, 0, 0 } } }," . "\n"; print STDOUT "\t" . "{ { { 0, 0, 0, 0 } } }," . "\n"; print STDOUT "\t" . "NULL," . "\n"; print STDOUT "\t" . @p . "," . "\n"; print STDOUT "\t" . "menu_drop_" . $arg->{mbar} . "_t" . "\n"; print STDOUT "};" . "\n\n"; } # sub menu_out_bg { my ($arg) = @_; print STDOUT "/**" . "\n"; print STDOUT " *" . " This file is automatically generated." . " To make changes, edit the source file" . "\n"; print STDOUT " *" . "\n"; print STDOUT " *" . " " . $arg->{file} . "\n"; print STDOUT " *" . "\n"; print STDOUT " *" . " and regenerate this file by running:" . "\n"; print STDOUT " *" . "\n"; print STDOUT " *" . " \$ " . $arg->{this} . " " . $arg->{file} . " > engine/menu_defs.h" . "\n"; print STDOUT " *" . "\n"; print STDOUT " */" . "\n\n"; } sub menu_out_eg { my ($arg) = @_; print STDOUT "#if defined(HAVE_UNVEIL) && defined(PROG_HAS_UNVEIL)" . "\n"; print STDOUT "static const struct t_rst t_rst_t[" . (@UNVEIL_ST + 1) . "] = {" . "\n"; my @s = &menu_out_eg_st(@UNVEIL_ST); foreach my $f (sort { lc($a) cmp lc($b) } @s) { print STDOUT "\t" . "{ \"" . $f . "\", \"r\" }," . "\n"; } print STDOUT "\n\t" . "{ NULL, NULL }" . "\n"; print STDOUT "};" . "\n"; print STDOUT "#endif" . "\n\n"; # my $e = $arg->{file}; $e =~ s/"/\\"/go; print STDOUT "#define DSL_COMPILER_VER \"" . $DSL_COMPILER_VER . "\"" . "\n\n"; print STDOUT "/* Check the Makefile before changing this in any way */" . "\n"; print STDOUT "#define DSL_EMBEDDED_M2C \"" . $e . "\"" . "\n\n"; # print STDOUT "/* " . @WINDOW_ID . " top level items processed at " . localtime() . " */" . "\n"; } sub menu_out_eg_st { my %s; grep !$s{$_}++, @_; } sub menu_out_tr { my ($arg) = @_; my @n = (); my %f = (); foreach my $k (sort { lc($a) cmp lc($b) } keys %LOCALE_ST) { %f = %{ $LOCALE_ST{$k} }; print STDOUT "static const struct menu_locale menu_locale_" . $LOCALE_NR{$k} . "[" . (values(%f) + 2) . "] = {" . "\n"; print STDOUT "\t" . "{ NULL, 0, (\"" . &menu_out_hex_bytes({ str => $k }) . "\"), " . &menu_out_len_bytes({ str => $k }) . " }," . "\n"; foreach my $v (sort { lc($a) cmp lc($b) } keys %f) { print STDOUT "\t" . "{ (\"" . &menu_out_hex_bytes({ str => $v }) . "\"), " . &menu_out_len_bytes({ str => $v }) . "," . "\n" . "\t\t" . "(\"" . &menu_out_hex_bytes({ str => $f{$v} }) . "\"), " . &menu_out_len_chars({ str => $f{$v} }) . " }," . "\n"; } print STDOUT "\n"; print STDOUT "\t" . "{ NULL, 0, NULL, 0 }" . "\n"; print STDOUT "};" . "\n\n"; push @n, "menu_locale_" . $LOCALE_NR{$k}; } if(@n) { print STDOUT "static const struct menu_locale *menu_locales[" . (@n + 1) . "] = {" . "\n"; print STDOUT "\t" . join(",\n\t", @n) . "," . "\n\n"; print STDOUT "\t" . "NULL" . "\n"; print STDOUT "};" . "\n\n"; print STDOUT "#define MENU_LOCALES " . @n . "\n\n"; } } # sub menu_out_min { my ($arg) = @_; print STDOUT "static struct menu_stack menu_stack_t[1] = {" . "\n"; print STDOUT "\t" . "{ 0, 0, NULL, 0, NULL }" . "\n"; print STDOUT "};" . "\n\n"; print STDOUT "#if defined(HAVE_UNVEIL) && defined(PROG_HAS_UNVEIL)" . "\n"; print STDOUT "static const struct t_rst t_rst_t[1] = {" . "\n"; print STDOUT "\t" . "{ NULL, NULL }" . "\n"; print STDOUT "};" . "\n"; print STDOUT "#endif" . "\n\n"; print STDOUT "#define DSL_COMPILER_VER \"" . $DSL_COMPILER_VER . "\"" . "\n"; print STDOUT "#define DSL_EMBEDDED_M2C \"" . "empty" . "\"" . "\n"; exit(0); } # sub menu_colors_x11 { my ($arg) = @_; my %c = ( 'aliceblue' => '0xf0f8ff00', 'alizarincrimson' => '0xe3263600', 'antiquewhite1' => '0xffefdb00', 'antiquewhite2' => '0xeedfcc00', 'antiquewhite3' => '0xcdc0b000', 'antiquewhite4' => '0x8b837800', 'antiquewhite' => '0xfaebd700', 'aquamarine1' => '0x7fffd400', 'aquamarine2' => '0x76eec600', 'aquamarine3' => '0x66cdaa00', 'aquamarine4' => '0x458b7400', 'aquamarinemedium' => '0x66cdaa00', 'aquamarine' => '0x7fffd400', 'aqua' => '0x00ffff00', 'aureolineyellow' => '0xffa82400', 'azure1' => '0xf0ffff00', 'azure2' => '0xe0eeee00', 'azure3' => '0xc1cdcd00', 'azure4' => '0x838b8b00', 'azure' => '0xf0ffff00', 'banana' => '0xe3cf5700', 'beige' => '0xa3948000', 'bisque1' => '0xffe4c400', 'bisque2' => '0xeed5b700', 'bisque3' => '0xcdb79e00', 'bisque4' => '0x8b7d6b00', 'bisque' => '0xffe4c400', 'black' => '0x00000000', 'blanchedalmond' => '0xffebcd00', 'blue1' => '0x0000ff00', 'blue2' => '0x0000ee00', 'blue3' => '0x0000cd00', 'blue4' => '0x00008b00', 'bluelight' => '0xadd8e600', 'bluemedium' => '0x0000cd00', 'blueviolet' => '0x8a2be200', 'blue' => '0x0000ff00', 'brick' => '0x9c661f00', 'brown1' => '0xff404000', 'brown2' => '0xee3b3b00', 'brown3' => '0xcd333300', 'brown4' => '0x8b232300', 'brownmadder' => '0xdb292900', 'brownochre' => '0x87421f00', 'brown' => '0x802a2a00', 'burlywood1' => '0xffd39b00', 'burlywood2' => '0xeec59100', 'burlywood3' => '0xcdaa7d00', 'burlywood4' => '0x8b735500', 'burlywood' => '0xdeb88700', 'burntsienna' => '0x8a360f00', 'burntumber' => '0x8a332400', 'cadetblue1' => '0x98f5ff00', 'cadetblue2' => '0x8ee5ee00', 'cadetblue3' => '0x7ac5cd00', 'cadetblue4' => '0x53868b00', 'cadetblue' => '0x7e7da000', 'cadet' => '0x5f9ea000', 'cadmiumlemon' => '0xffe30300', 'cadmiumorange' => '0xff610300', 'cadmiumreddeep' => '0xe3170d00', 'cadmiumredlight' => '0xff030d00', 'cadmiumyellowlight' => '0xffb00f00', 'cadmiumyellow' => '0xff991200', 'carrot' => '0xed912100', 'cerulean' => '0x05b8cc00', 'chartreuse1' => '0x7fff0000', 'chartreuse2' => '0x76ee0000', 'chartreuse3' => '0x66cd0000', 'chartreuse4' => '0x458b0000', 'chartreuse' => '0x7fff0000', 'chocolate1' => '0xff7f2400', 'chocolate2' => '0xee762100', 'chocolate3' => '0xcd661d00', 'chocolate4' => '0x8b451300', 'chocolate' => '0xd2691e00', 'chromeoxidegreen' => '0x66801400', 'cinnabargreen' => '0x61b32900', 'cobaltgreen' => '0x3d914000', 'cobaltvioletdeep' => '0x91219e00', 'cobalt' => '0x3d59ab00', 'coldgray' => '0x808a8700', 'coral1' => '0xff725600', 'coral2' => '0xee6a5000', 'coral3' => '0xcd5b4500', 'coral4' => '0x8b3e2f00', 'corallight' => '0xf0808000', 'coral' => '0xff7f5000', 'cornflowerblue' => '0x6495ed00', 'cornflower' => '0x6495ed00', 'cornsilk1' => '0xfff8dc00', 'cornsilk2' => '0xeee8cd00', 'cornsilk3' => '0xcdc8b100', 'cornsilk4' => '0x8b887800', 'cornsilk' => '0xfff8dc00', 'cyan1' => '0x00ffff00', 'cyan2' => '0x00eeee00', 'cyan3' => '0x00cdcd00', 'cyan4' => '0x008b8b00', 'cyanwhite' => '0xe0ffff00', 'cyan' => '0x00ffff00', 'darkblue' => '0x00008b00', 'darkcyan' => '0x008b8b00', 'darkgoldenrod1' => '0xffb90f00', 'darkgoldenrod2' => '0xeead0e00', 'darkgoldenrod3' => '0xcd950c00', 'darkgoldenrod4' => '0x8b650800', 'darkgray' => '0xa9a9a900', 'darkgreen' => '0x00530000', 'darkkhaki' => '0xbdb76b00', 'darkmagenta' => '0x8b008b00', 'darkolivegreen1' => '0xcaff7000', 'darkolivegreen2' => '0xbcee6800', 'darkolivegreen3' => '0xa2cd5a00', 'darkolivegreen4' => '0x6e8b3d00', 'darkolivegreen' => '0x4f4f2f00', 'darkorange1' => '0xff7f0000', 'darkorange2' => '0xee760000', 'darkorange3' => '0xcd660000', 'darkorange4' => '0x8b450000', 'darkorange' => '0xff8c0000', 'darkorchid1' => '0xbf3eff00', 'darkorchid2' => '0xb23aee00', 'darkorchid3' => '0x9a32cd00', 'darkorchid4' => '0x68228b00', 'darkorchid' => '0x6a256600', 'darkred' => '0x8b000000', 'darksalmon' => '0xe9967a00', 'darkseagreen1' => '0xc1ffc100', 'darkseagreen2' => '0xb4eeb400', 'darkseagreen3' => '0x9bcd9b00', 'darkseagreen4' => '0x698b6900', 'darkseagreen' => '0x8fbc8f00', 'darkslateblue' => '0x333e6300', 'darkslategray1' => '0x97ffff00', 'darkslategray2' => '0x8deeee00', 'darkslategray3' => '0x79cdcd00', 'darkslategray4' => '0x528b8b00', 'darkslategray' => '0x3c404a00', 'darkturquoise' => '0x1d6f7500', 'darkviolet' => '0x9400d300', 'deepochre' => '0x733d1a00', 'deeppink1' => '0xff149300', 'deeppink2' => '0xee128900', 'deeppink3' => '0xcd107600', 'deeppink4' => '0x8b0a5000', 'deeppink' => '0xff149300', 'deepskyblue1' => '0x00bfff00', 'deepskyblue2' => '0x00b2ee00', 'deepskyblue3' => '0x009acd00', 'deepskyblue4' => '0x00688b00', 'deepskyblue' => '0x00bfff00', 'dimgray' => '0x69696900', 'dodgerblue1' => '0x1e90ff00', 'dodgerblue2' => '0x1c86ee00', 'dodgerblue3' => '0x1874cd00', 'dodgerblue4' => '0x104e8b00', 'dodgerblue' => '0x1e90ff00', 'eggshell' => '0xfce6c900', 'emeraldgreen' => '0x00c95700', 'englishred' => '0xd43d1a00', 'firebrick1' => '0xff303000', 'firebrick2' => '0xee2c2c00', 'firebrick3' => '0xcd262600', 'firebrick4' => '0x8b1a1a00', 'firebrick' => '0xb2222200', 'fleshochre' => '0xff572100', 'flesh' => '0xff7d4000', 'floralwhite' => '0xfffaf000', 'forestgreen' => '0x55c03400', 'fuchsia' => '0xff00ff00', 'gainsboro' => '0xdcdcdc00', 'geraniumlake' => '0xe3123000', 'ghostwhite' => '0xf8f8ff00', 'gold1' => '0xffd70000', 'gold2' => '0xeec90000', 'gold3' => '0xcdad0000', 'gold4' => '0x8b750000', 'goldenrod1' => '0xffc12500', 'goldenrod2' => '0xeeb42200', 'goldenrod3' => '0xcd9b1d00', 'goldenrod4' => '0x8b691400', 'goldenroddark' => '0xb8860b00', 'goldenrodlight' => '0xfafad200', 'goldenrodpale' => '0xeee8aa00', 'goldenrod' => '0xdaa52000', 'goldochre' => '0xc7782600', 'gold' => '0xffd70000', 'gray0' => '0x00000000', 'gray100' => '0xffffff00', 'gray10' => '0x1a1a1a00', 'gray11' => '0x1c1c1c00', 'gray12' => '0x1f1f1f00', 'gray13' => '0x21212100', 'gray14' => '0x24242400', 'gray15' => '0x26262600', 'gray16' => '0x29292900', 'gray17' => '0x2b2b2b00', 'gray18' => '0x2e2e2e00', 'gray19' => '0x30303000', 'gray1' => '0x03030300', 'gray20' => '0x33333300', 'gray21' => '0x36363600', 'gray22' => '0x38383800', 'gray23' => '0x3b3b3b00', 'gray24' => '0x3d3d3d00', 'gray25' => '0x40404000', 'gray26' => '0x42424200', 'gray27' => '0x45454500', 'gray28' => '0x47474700', 'gray29' => '0x4a4a4a00', 'gray2' => '0x05050500', 'gray30' => '0x4d4d4d00', 'gray31' => '0x4f4f4f00', 'gray32' => '0x52525200', 'gray33' => '0x54545400', 'gray34' => '0x57575700', 'gray35' => '0x59595900', 'gray36' => '0x5c5c5c00', 'gray37' => '0x5e5e5e00', 'gray38' => '0x61616100', 'gray39' => '0x63636300', 'gray3' => '0x08080800', 'gray40' => '0x66666600', 'gray41' => '0x69696900', 'gray42' => '0x6b6b6b00', 'gray43' => '0x6e6e6e00', 'gray44' => '0x70707000', 'gray45' => '0x73737300', 'gray46' => '0x75757500', 'gray47' => '0x78787800', 'gray48' => '0x7a7a7a00', 'gray49' => '0x7d7d7d00', 'gray4' => '0x0a0a0a00', 'gray50' => '0x7f7f7f00', 'gray51' => '0x82828200', 'gray52' => '0x85858500', 'gray53' => '0x87878700', 'gray54' => '0x8a8a8a00', 'gray55' => '0x8c8c8c00', 'gray56' => '0x8f8f8f00', 'gray57' => '0x91919100', 'gray58' => '0x94949400', 'gray59' => '0x96969600', 'gray5' => '0x0d0d0d00', 'gray60' => '0x99999900', 'gray61' => '0x9c9c9c00', 'gray62' => '0x9e9e9e00', 'gray63' => '0xa1a1a100', 'gray64' => '0xa3a3a300', 'gray65' => '0xa6a6a600', 'gray66' => '0xa8a8a800', 'gray67' => '0xababab00', 'gray68' => '0xadadad00', 'gray69' => '0xb0b0b000', 'gray6' => '0x0f0f0f00', 'gray70' => '0xb3b3b300', 'gray71' => '0xb5b5b500', 'gray72' => '0xb8b8b800', 'gray73' => '0xbababa00', 'gray74' => '0xbdbdbd00', 'gray75' => '0xbfbfbf00', 'gray76' => '0xc2c2c200', 'gray77' => '0xc4c4c400', 'gray78' => '0xc7c7c700', 'gray79' => '0xc9c9c900', 'gray7' => '0x12121200', 'gray80' => '0xcccccc00', 'gray81' => '0xcfcfcf00', 'gray82' => '0xd1d1d100', 'gray83' => '0xd4d4d400', 'gray84' => '0xd6d6d600', 'gray85' => '0xd9d9d900', 'gray86' => '0xdbdbdb00', 'gray87' => '0xdedede00', 'gray88' => '0xe0e0e000', 'gray89' => '0xe3e3e300', 'gray8' => '0x14141400', 'gray90' => '0xe5e5e500', 'gray91' => '0xe8e8e800', 'gray92' => '0xebebeb00', 'gray93' => '0xededed00', 'gray94' => '0xf0f0f000', 'gray95' => '0xf2f2f200', 'gray96' => '0xf5f5f500', 'gray97' => '0xf7f7f700', 'gray98' => '0xfafafa00', 'gray99' => '0xfcfcfc00', 'gray9' => '0x17171700', 'gray' => '0x80808000', 'green1' => '0x00ff0000', 'green2' => '0x00ee0000', 'green3' => '0x00cd0000', 'green4' => '0x008b0000', 'greendark' => '0x00640000', 'greenishumber' => '0xff3d0d00', 'greenpale' => '0x98fb9800', 'greenyellow' => '0xadff2f00', 'green' => '0x00800000', 'honeydew1' => '0xf0fff000', 'honeydew2' => '0xe0eee000', 'honeydew3' => '0xc1cdc100', 'honeydew4' => '0x838b8300', 'honeydew' => '0xf0fff000', 'hotpink1' => '0xff6eb400', 'hotpink2' => '0xee6aa700', 'hotpink3' => '0xcd609000', 'hotpink4' => '0x8b3a6200', 'hotpink' => '0xff69b400', 'indianred1' => '0xff6a6a00', 'indianred2' => '0xee636300', 'indianred3' => '0xcd555500', 'indianred4' => '0x8b3a3a00', 'indianred' => '0xb0171f00', 'indigo' => '0x2e085400', 'ivory1' => '0xfffff000', 'ivory2' => '0xeeeee000', 'ivory3' => '0xcdcdc100', 'ivory4' => '0x8b8b8300', 'ivoryblack' => '0x29242100', 'ivory' => '0xfffff000', 'khaki1' => '0xfff68f00', 'khaki2' => '0xeee68500', 'khaki3' => '0xcdc67300', 'khaki4' => '0x8b864e00', 'khakidark' => '0xbdb76b00', 'khaki' => '0xf0e68c00', 'lampblack' => '0x2e473b00', 'lavenderblush1' => '0xfff0f500', 'lavenderblush2' => '0xeee0e500', 'lavenderblush3' => '0xcdc1c500', 'lavenderblush4' => '0x8b838600', 'lavenderblush' => '0xfff0f500', 'lavender' => '0xe6e6fa00', 'lawngreen' => '0x7cfc0000', 'lemonchiffon1' => '0xfffacd00', 'lemonchiffon2' => '0xeee9bf00', 'lemonchiffon3' => '0xcdc9a500', 'lemonchiffon4' => '0x8b897000', 'lemonchiffon' => '0xfffacd00', 'lightbeige' => '0xf5f5dc00', 'lightblue1' => '0xbfefff00', 'lightblue2' => '0xb2dfee00', 'lightblue3' => '0x9ac0cd00', 'lightblue4' => '0x68838b00', 'lightblue' => '0xabc5ff00', 'lightcoral' => '0xf0808000', 'lightcyan1' => '0xe0ffff00', 'lightcyan2' => '0xd1eeee00', 'lightcyan3' => '0xb4cdcd00', 'lightcyan4' => '0x7a8b8b00', 'lightcyan' => '0xe0ffff00', 'lightgoldenrod1' => '0xffec8b00', 'lightgoldenrod2' => '0xeedc8200', 'lightgoldenrod3' => '0xcdbe7000', 'lightgoldenrod4' => '0x8b814c00', 'lightgoldenrodyellow' => '0xfafad200', 'lightgoldenrod' => '0xeedd8200', 'lightgray' => '0xd3d3d300', 'lightgreen' => '0x90ee9000', 'lightpink1' => '0xffaeb900', 'lightpink2' => '0xeea2ad00', 'lightpink3' => '0xcd8c9500', 'lightpink4' => '0x8b5f6500', 'lightpink' => '0xffb6c100', 'lightsalmon1' => '0xffa07a00', 'lightsalmon2' => '0xee957200', 'lightsalmon3' => '0xcd816200', 'lightsalmon4' => '0x8b574200', 'lightsalmon' => '0xffa07a00', 'lightseagreen' => '0x20b2aa00', 'lightskyblue1' => '0xb0e2ff00', 'lightskyblue2' => '0xa4d3ee00', 'lightskyblue3' => '0x8db6cd00', 'lightskyblue4' => '0x607b8b00', 'lightskyblue' => '0x87cefa00', 'lightslateblue' => '0x8470ff00', 'lightslategray' => '0x77889900', 'lightsteelblue1' => '0xcae1ff00', 'lightsteelblue2' => '0xbcd2ee00', 'lightsteelblue3' => '0xa2b5cd00', 'lightsteelblue4' => '0x6e7b8b00', 'lightsteelblue' => '0x3498ca00', 'lightyellow1' => '0xffffe000', 'lightyellow2' => '0xeeeed100', 'lightyellow3' => '0xcdcdb400', 'lightyellow4' => '0x8b8b7a00', 'lightyellow' => '0xffffe000', 'limegreen' => '0x32cd3200', 'lime' => '0x00ff0000', 'linen' => '0xfaf0e600', 'madderlakedeep' => '0xe32e3000', 'magenta1' => '0xff00ff00', 'magenta2' => '0xee00ee00', 'magenta3' => '0xcd00cd00', 'magenta4' => '0x8b008b00', 'magenta' => '0xff00d300', 'manganeseblue' => '0x03a89e00', 'maroon1' => '0xff34b300', 'maroon2' => '0xee30a700', 'maroon3' => '0xcd299000', 'maroon4' => '0x8b1c6200', 'maroon' => '0x80000000', 'marsorange' => '0x96451400', 'marsyellow' => '0xe3701a00', 'mediumaquamarine' => '0x15877600', 'mediumblue' => '0x3d62d000', 'mediumforestgreen' => '0x6b8e2300', 'mediumgoldenrod' => '0xb8860b00', 'mediumorchid1' => '0xe066ff00', 'mediumorchid2' => '0xd15fee00', 'mediumorchid3' => '0xb452cd00', 'mediumorchid4' => '0x7a378b00', 'mediumorchid' => '0xac4da600', 'mediumpurple1' => '0xab82ff00', 'mediumpurple2' => '0x9f79ee00', 'mediumpurple3' => '0x8968cd00', 'mediumpurple4' => '0x5d478b00', 'mediumpurple' => '0x9370db00', 'mediumseagreen' => '0x1b865600', 'mediumslateblue' => '0x5f6d9a00', 'mediumspringgreen' => '0x3c8d2300', 'mediumturquoise' => '0x3eacb500', 'mediumvioletred' => '0xc7158500', 'melon' => '0xe3a86900', 'midnightblue' => '0x19197000', 'mintcream' => '0xf5fffa00', 'mint' => '0xbdfcc900', 'mistyrose1' => '0xffe4e100', 'mistyrose2' => '0xeed5d200', 'mistyrose3' => '0xcdb7b500', 'mistyrose4' => '0x8b7d7b00', 'mistyrose' => '0xffe4e100', 'moccasin' => '0xffe4b500', 'naplesyellowdeep' => '0xffa81200', 'navajowhite1' => '0xffdead00', 'navajowhite2' => '0xeecfa100', 'navajowhite3' => '0xcdb38b00', 'navajowhite4' => '0x8b795e00', 'navajowhite' => '0xffdead00', 'navyblue' => '0x00008e00', 'navy' => '0x00008000', 'oldlace' => '0xfdf5e600', 'olivedrab1' => '0xc0ff3e00', 'olivedrab2' => '0xb3ee3a00', 'olivedrab3' => '0x9acd3200', 'olivedrab4' => '0x698b2200', 'olivedrab' => '0x6b8e2300', 'olivegreendark' => '0x556b2f00', 'olive' => '0x80800000', 'orange1' => '0xffa50000', 'orange2' => '0xee9a0000', 'orange3' => '0xcd850000', 'orange4' => '0x8b5a0000', 'orangered1' => '0xff450000', 'orangered2' => '0xee400000', 'orangered3' => '0xcd370000', 'orangered4' => '0x8b250000', 'orangered' => '0xe2412a00', 'orange' => '0xff8a0000', 'orchid1' => '0xff83fa00', 'orchid2' => '0xee7ae900', 'orchid3' => '0xcd69c900', 'orchid4' => '0x8b478900', 'orchiddark' => '0x9932cc00', 'orchidmedium' => '0xba55d300', 'orchid' => '0xda6bd400', 'palegoldenrod' => '0xeee8aa00', 'palegreen1' => '0x9aff9a00', 'palegreen2' => '0x90ee9000', 'palegreen3' => '0x7ccd7c00', 'palegreen4' => '0x548b5400', 'palegreen' => '0x98ff9800', 'paleturquoise1' => '0xbbffff00', 'paleturquoise2' => '0xaeeeee00', 'paleturquoise3' => '0x96cdcd00', 'paleturquoise4' => '0x668b8b00', 'paleturquoise' => '0xafeeee00', 'palevioletred1' => '0xff82ab00', 'palevioletred2' => '0xee799f00', 'palevioletred3' => '0xcd688900', 'palevioletred4' => '0x8b475d00', 'palevioletred' => '0xdb709300', 'papayawhip' => '0xffefd500', 'peachpuff1' => '0xffdab900', 'peachpuff2' => '0xeecbad00', 'peachpuff3' => '0xcdaf9500', 'peachpuff4' => '0x8b776500', 'peachpuff' => '0xffdab900', 'peacock' => '0x33a1c900', 'permanentgreen' => '0x0ac92b00', 'permanentredviolet' => '0xdb264500', 'peru' => '0xcd853f00', 'pink1' => '0xffb5c500', 'pink2' => '0xeea9b800', 'pink3' => '0xcd919e00', 'pink4' => '0x8b636c00', 'pinklight' => '0xffb6c100', 'pink' => '0xffc0cb00', 'plum1' => '0xffbbff00', 'plum2' => '0xeeaeee00', 'plum3' => '0xcd96cd00', 'plum4' => '0x8b668b00', 'plum' => '0xdda0dd00', 'powderblue' => '0xb0e0e600', 'purple1' => '0x9b30ff00', 'purple2' => '0x912cee00', 'purple3' => '0x7d26cd00', 'purple4' => '0x551a8b00', 'purplemedium' => '0x9370db00', 'purple' => '0x80008000', 'raspberry' => '0x87265700', 'rawsienna' => '0xc7611400', 'rawumber' => '0x734a1200', 'red1' => '0xff000000', 'red2' => '0xee000000', 'red3' => '0xcd000000', 'red4' => '0x8b000000', 'red' => '0xff000000', 'rosemadder' => '0xe3363800', 'rosybrown1' => '0xffc1c100', 'rosybrown2' => '0xeeb4b400', 'rosybrown3' => '0xcd9b9b00', 'rosybrown4' => '0x8b696900', 'rosybrown' => '0xbc8f8f00', 'royalblue1' => '0x4876ff00', 'royalblue2' => '0x436eee00', 'royalblue3' => '0x3a5fcd00', 'royalblue4' => '0x27408b00', 'royalblue' => '0x4169e100', 'saddlebrown' => '0x8b451300', 'salmon1' => '0xff8c6900', 'salmon2' => '0xee826200', 'salmon3' => '0xcd705400', 'salmon4' => '0x8b4c3900', 'salmon' => '0xf86d6800', 'sandybrown' => '0xb28f5600', 'sapgreen' => '0x30801400', 'seagreen1' => '0x54ff9f00', 'seagreen2' => '0x4eee9400', 'seagreen3' => '0x43cd8000', 'seagreen4' => '0x2e8b5700', 'seagreendark' => '0x8fbc8f00', 'seagreenlight' => '0x20b2aa00', 'seagreenmedium' => '0x3cb37100', 'seagreen' => '0x2e8b5700', 'seashell1' => '0xfff5ee00', 'seashell2' => '0xeee5de00', 'seashell3' => '0xcdc5bf00', 'seashell4' => '0x8b868200', 'seashell' => '0xfff5ee00', 'sepia' => '0x5e261200', 'sienna1' => '0xff824700', 'sienna2' => '0xee794200', 'sienna3' => '0xcd683900', 'sienna4' => '0x8b472600', 'sienna' => '0x8e6b2300', 'silver' => '0xc0c0c000', 'skyblue1' => '0x87ceff00', 'skyblue2' => '0x7ec0ee00', 'skyblue3' => '0x6ca6cd00', 'skyblue4' => '0x4a708b00', 'skybluedeep' => '0x00bfff00', 'skybluelight' => '0x87cefa00', 'skyblue' => '0x87ceeb00', 'slateblue1' => '0x836fff00', 'slateblue2' => '0x7a67ee00', 'slateblue3' => '0x6959cd00', 'slateblue4' => '0x473c8b00', 'slatebluedark' => '0x483d8b00', 'slatebluelight' => '0x8470ff00', 'slatebluemedium' => '0x7b68ee00', 'slateblue' => '0x7586be00', 'slategray1' => '0xc6e2ff00', 'slategray2' => '0xb9d3ee00', 'slategray3' => '0x9fb6cd00', 'slategray4' => '0x6c7b8b00', 'slategraydark' => '0x2f4f4f00', 'slategraylight' => '0x77889900', 'slategray' => '0x70809000', 'snow1' => '0xfffafa00', 'snow2' => '0xeee9e900', 'snow3' => '0xcdc9c900', 'snow4' => '0x8b898900', 'snow' => '0xfffafa00', 'springgreen1' => '0x00ff7f00', 'springgreen2' => '0x00ee7600', 'springgreen3' => '0x00cd6600', 'springgreen4' => '0x008b4500', 'springgreenmedium' => '0x00fa9a00', 'springgreen' => '0x00ff7f00', 'steelblue1' => '0x63b8ff00', 'steelblue2' => '0x5cacee00', 'steelblue3' => '0x4f94cd00', 'steelblue4' => '0x36648b00', 'steelbluelight' => '0xb0c4de00', 'steelblue' => '0x4682b400', 'tan1' => '0xffa54f00', 'tan2' => '0xee9a4900', 'tan3' => '0xcd853f00', 'tan4' => '0x8b5a2b00', 'tan' => '0xd2b48c00', 'teal' => '0x00808000', 'terreverte' => '0x385e0f00', 'thistle1' => '0xffe1ff00', 'thistle2' => '0xeed2ee00', 'thistle3' => '0xcdb5cd00', 'thistle4' => '0x8b7b8b00', 'thistle' => '0xd8bfd800', 'titaniumwhite' => '0xfcfff000', 'tomato1' => '0xff634700', 'tomato2' => '0xee5c4200', 'tomato3' => '0xcd4f3900', 'tomato4' => '0x8b362600', 'tomato' => '0xff634700', 'turquoise1' => '0x00f5ff00', 'turquoise2' => '0x00e5ee00', 'turquoise3' => '0x00c5cd00', 'turquoise4' => '0x00868b00', 'turquoiseblue' => '0x00c78c00', 'turquoisedark' => '0x00ced100', 'turquoisemedium' => '0x48d1cc00', 'turquoisepale' => '0xafeeee00', 'turquoise' => '0x48d1cc00', 'ultramarineviolet' => '0x5c246e00', 'ultramarine' => '0x120a8f00', 'vandykebrown' => '0x5e260500', 'venetianred' => '0xd41a1f00', 'violetdark' => '0x9400d300', 'violetred1' => '0xff3e9600', 'violetred2' => '0xee3a8c00', 'violetred3' => '0xcd327800', 'violetred4' => '0x8b225200', 'violetredmedium' => '0xc7158500', 'violetredpale' => '0xdb709300', 'violetred' => '0xff009400', 'violet' => '0x9400d300', 'viridianlight' => '0x6eff7000', 'warmgray' => '0x80806900', 'wheat1' => '0xffe7ba00', 'wheat2' => '0xeed8ae00', 'wheat3' => '0xcdba9600', 'wheat4' => '0x8b7e6600', 'wheat' => '0xf5deb300', 'whitesmoke' => '0xf5f5f500', 'white' => '0xffffff00', 'yellow1' => '0xffff0000', 'yellow2' => '0xeeee0000', 'yellow3' => '0xcdcd0000', 'yellow4' => '0x8b8b0000', 'yellowgreen' => '0x9acd3200', 'yellowlight' => '0xffffe000', 'yellowochre' => '0xe3821700', 'yellow' => '0xffff0000', 'zincwhite' => '0xfdf8ff00' ); return \%c; } # sub menu_out_hex_bytes { my ($arg) = @_; my $r = $arg->{str}; my $t = "\t" x 2; use bytes; $r =~ s/(.)/sprintf "\\x%2x", ord $1/seg; my @r = $r =~ /(.{1,64})/g; use utf8; return join("\"\n$t\"", @r); } sub menu_out_len_bytes { my ($arg) = @_; use bytes; my $r = length($arg->{str}); use utf8; return $r; } sub menu_out_len_chars { my ($arg) = @_; return length($arg->{str}); } # sub msg_fail { my ($arg) = @_; if($arg->{line}) { print STDERR $0 . ": " . $arg->{mess} . " at line " . $arg->{line} . ". Abort." . "\n"; } else { print STDERR $0 . ": " . $arg->{mess} . ". Abort." . "\n"; } exit(1); }