|
|
nono 1.5.0
#
# nono
# Copyright (C) 2021 nono project
# Licensed under nono-license.txt
#
# monitor_id.txt から monitor_id.h, monitor_id.cpp を作る。
#
# usage: perl monitor_id.pl monitor_id.txt
{
$defs = "";
$body = "";
$first_mon_id = "";
$first_sub_id = "";
@maxes = ();
# $#ARGV は引数の数-1。ここでいう引数は monitor_id.pl の後ろから。
if ($#ARGV != 0) {
die "usage: $0 <id.txt>\n";
}
# ファイル名
$infile = $ARGV[0];
$hdrfile = $infile;
$srcfile = $infile;
$hdrfile =~ s/txt$/h/;
$srcfile =~ s/txt$/cpp/;
# 先頭に一つダミーエントリを入れる。
# (あまりサポートしてないけど) wxMac ではメニュー ID が 0 だと死ぬので。
$id = "ID_MONITOR_zeroth_dummy_for_wxmac";
$mon_defs .= "\t$id = 0,\n";
$mon_body .= "\t{ $id, },\n";
open(IN, $infile) || die "Cannot open infile: ${infile}\n";
while (<IN>) {
# Remove comments.
chomp;
s/#.*$//;
next if /^$/;
@names = split(/\s+/);
if ($names[0] =~ /([^%]+)%(\d+)/) {
# %n なら 0..(n-1) に展開
$basename = $1;
$atnum = $2 + 0;
# モニタの最大数はここが一次情報なので、これから定数を作る
push(@maxes, "MAX_${basename}_MONITOR = ${atnum}");
for ($i = 0; $i < $atnum; $i++) {
@rep_names = ();
foreach $n (@names) {
$r = $n;
$r =~ s/%${atnum}/${i}/g;
$r =~ s/%/${i}/g;
push(@rep_names, $r);
}
parse_line(@rep_names);
}
} else {
# default
parse_line(@names);
}
}
close(IN);
# 文字列として出力
$hdrnew = "";
$srcnew = "";
$hdrnew .= "// Generated from ${0}\n";
$hdrnew .= "\n";
$hdrnew .= $mon_defs;
$hdrnew .= "\n";
$hdrnew .= $sub_defs;
$hdrnew .= "\n";
$hdrnew .= "\tID_MONITOR_START = ${first_mon_id},\n";
$hdrnew .= "\tID_MONITOR_END = ${last_mon_id},\n";
$hdrnew .= "\tID_MONITOR_MAX = ID_MONITOR_END + 1,\n";
$hdrnew .= "\tID_SUBWIN_START = ${first_sub_id},\n";
$hdrnew .= "\tID_SUBWIN_END = ${last_sub_id},\n";
$hdrnew .= "\tID_SUBWIN_MAX = ID_SUBWIN_END + 1,\n";
$hdrnew .= "\n";
$hdrnew .= "\t// これは enum じゃないけど自動生成の都合でここに置く\n";
foreach $str (@maxes) {
$hdrnew .= "\t${str},\n";
}
$srcnew .= "// Generated from ${0}\n";
$srcnew .= "\n";
$srcnew .= "#include \"monitor.h\"\n";
$srcnew .= "\n";
$srcnew .= "/*static*/ const std::vector<MonitorManager::MonitorInfo>\n";
$srcnew .= "MonitorManager::info {\n";
$srcnew .= $mon_body;
$srcnew .= "\n";
$srcnew .= $sub_body;
$srcnew .= "};\n";
$srcnew .= "\n";
$srcnew .= "/*static*/ const std::vector<std::pair<uint, const char *>>\n";
$srcnew .= "Monitor::idtext {\n";
$srcnew .= $label_body;
$srcnew .= "};\n";
# 更新があれば書き出す
do_update($hdrfile, $hdrnew);
do_update($srcfile, $srcnew);
exit 0;
}
sub parse_line()
{
local @names = @_;
local $id = shift(@names);
local $type = shift(@names);
local $flag = shift(@names);
local $first;
if ($#names == -1) {
# If <names...> are ommited, use ID instead.
$first = lc $id;
} else {
# If <names...> are specified, use it.
$first = shift(@names);
}
if ($type eq "m") {
$id = "ID_MONITOR_${id}";
if ($first_mon_id eq "") {
$first_mon_id = $id;
}
$last_mon_id = $id;
} else {
$id = "ID_SUBWIN_${id}";
if ($first_sub_id eq "") {
$first_sub_id = $id;
}
$last_sub_id = $id;
}
if ($flag eq ".") {
# フラグ省略時(モニタの場合)は vmcap を参照することはないはず
$flag = "NONE";
}
# フラグは '|' で並べることが出来る。
@flags = split(/\|/, $flag);
@caps = map { "VMCap::".$_ } @flags;
$cap = join('|', @caps);
$defs = "\t${id},\n";
$body = "\t{ ${id},\t${cap},\t{ \"${first}\"";
foreach $name (@names) {
$body .= ", \"${name}\"";
}
$body .= " } },\n";
if ($type eq "m") {
$mon_defs .= $defs;
$mon_body .= $body;
} else {
$sub_defs .= $defs;
$sub_body .= $body;
}
# デバッグ用の ID と文字列の対応表
$label_body .= "\t{ ${id}, \"${id}\" },\n";
}
sub do_update()
{
local $filename = $_[0];
local $filebody = $_[1];
local $old;
local @contents;
# まず出力先ファイルを文字列として読み込む
$old = "";
if (open(IN, $filename)) {
@contents = <IN>;
$old = join("", @contents);
close(IN);
}
# 全文を比較して変更があれば出力
if ($filebody ne $old) {
open(OUT, ">${filename}") || die "Cannot open ${filename}\n";
print OUT $filebody;
close(OUT);
print "Updated ${filename}\n";
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.