ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra/bin/cf-slotutil
Revision: 1.3
Committed: Sun Sep 28 13:41:57 2008 UTC (15 years, 8 months ago) by root
Branch: MAIN
Changes since 1.2: +12 -2 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #!/opt/bin/perl
2
3 use utf8;
4 use strict qw(vars subs);
5
6 use Deliantra;
7 use IO::AIO;
8 use List::Util;
9
10 Deliantra::load_archetypes;
11
12 sub scan_files($$) {
13 my ($path, $cb) = @_;
14
15 aio_scandir $path, 3, sub {
16 my ($dirs, $nondirs) = @_;
17
18 scan_files("$path/$_", $cb) for @$dirs;
19
20 for my $file (@$nondirs) {
21 next unless $file =~ /\.arc$/;
22
23 my $data;
24 aio_load "$path/$file", $data, sub {
25 $cb->("$path/$file", read_arch \$data);
26 };
27 }
28 };
29 }
30
31 sub for_all_arc($) {
32 scan_files $ENV{DELIANTRA_ARCHDIR} || ".", $_[0];
33
34 IO::AIO::flush;
35 }
36
37 sub extract {
38 my (undef, $filter, @slots) = @ARGV;
39
40 $filter =~ s/%(\w+)/\$_{$1}/g;
41 $filter = eval "sub { $filter }"
42 or die $@;
43
44 my @res;
45
46 unshift @slots, "_name";
47
48 my @sort = grep /^\d+$/, @slots;
49 my @widths = map s/\=(\d+)$// && $1, grep !/^\d+$/, @slots;
50 my @align = map s/>$// ? "" : "-", @slots;
51 my @big;
52
53 local *_;
54 for (sort keys %ARCH) {
55 *_ = $ARCH{$_};
56 next unless &$filter;
57 push @res, [@_{@slots}];
58 };
59
60 @res = sort {
61 "$a->[$_]$b->[$_]" =~ /^\d+$/
62 ? $a->[$_] <=> $b->[$_]
63 : $a->[$_] cmp $b->[$_]
64 } @res
65 for @sort;
66
67 for my $row (@res) {
68 for (0 .. $#$row) {
69 $big[$_] =1 if $row->[$_] =~ /\n/;
70 }
71 }
72 for my $i (0 .. $#widths) {
73 $widths[$i] ||= List::Util::max map length $_->[$i], \@slots, @res;
74 }
75
76 for (0 .. $#big) {
77 $widths[$_] = length $slots[$_] if $big[$_];
78 }
79
80 my $format = join " ", map "%$align[$_]$widths[$_]s", 0..$#widths;
81
82 printf "$format\n", map "A$_", map $_ + 1, @widths;
83 printf "$format\n", @slots;
84 for my $row (@res) {
85 print "\n" if @big;
86
87 printf "$format\n", map $big[$_] ? "\x{fffc}" : $row->[$_], 0 .. $#$row;
88
89 for (grep $big[$_], 0 .. $#big) {
90 print "$row->[$_]%%\n";
91 }
92 }
93 }
94
95 sub insert {
96 my ($apply) = @_;
97
98 shift @ARGV;
99 my $format = <STDIN>;
100 my @slots = unpack $format, <STDIN>;
101
102 my %res;
103
104 while (<STDIN>) {
105 next unless /\S/;
106
107 my @row = unpack $format, $_;
108
109 for (0 .. $#row) {
110 next unless $row[$_] eq "\x{fffc}";
111
112 local $/ = "%%\n";
113 chomp ($row[$_] = <STDIN>);
114 }
115
116 $res{$row[0]} = \@row;
117 }
118
119 for_all_arc sub {
120 my ($path, $arch) = @_;
121
122 my $chg;
123
124 for (keys %$arch) {
125 my $data = $res{$_}
126 or next;
127
128 my $arch = $arch->{$_};
129
130 for (0 .. $#$data) {
131 next if $data->[$_] eq $arch->{$slots[$_]};
132 $chg = 1;
133 $arch->{$slots[$_]} = $data->[$_];
134 }
135 }
136
137 if ($chg) {
138 open my $fh, ">:raw:utf8", "$path~"
139 or die "$path~: $!";
140 print $fh Deliantra::archlist_to_string [
141 map $arch->{$_},
142 sort keys %$arch
143 ];
144 close $fh;
145
146 if ($apply) {
147 rename "$path~", $path;
148 } else {
149 system "diff", "-u", $path, "$path~";
150 unlink "$path~";
151 }
152 }
153 };
154 }
155
156 binmode STDIN, ":utf8";
157 binmode STDOUT, ":utf8";
158
159 if ($ARGV[0] eq "extract") {
160 extract;
161 } elsif ($ARGV[0] eq "diff") {
162 insert 0;
163 } elsif ($ARGV[0] eq "apply") {
164 insert 1;
165 } else {
166 die <<EOF;
167 Usage:
168
169 $0 extract 'filter' slot...
170
171 extract slots from server archetypes file (NOT the .arc files!)
172 Example: $0 extract '%type == 101' level
173
174 $0 diff
175
176 generates a diff against the .arc files found
177 in \$DELIANTRA_ARCHDIR or ".".
178
179 Example: $0 diff <file
180
181 $0 apply
182
183 like diff, but applies it in-place
184
185 EOF
186 }
187
188
189