ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra/bin/cf-slotutil
Revision: 1.5
Committed: Sat May 15 00:22:26 2010 UTC (14 years ago) by root
Branch: MAIN
CVS Tags: rel-2_01, rel-2_0, HEAD
Changes since 1.4: +1 -2 lines
Log Message:
*** empty log message ***

File Contents

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