ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra/bin/cf-slotutil
Revision: 1.4
Committed: Sun Sep 28 15:08:20 2008 UTC (15 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rel-1_29, rel-1_24, rel-1_25, rel-1_23, rel-1_30
Changes since 1.3: +7 -4 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 sub scan_files($$) {
11 my ($path, $cb) = @_;
12
13 aio_scandir $path, 3, sub {
14 my ($dirs, $nondirs) = @_;
15
16 scan_files("$path/$_", $cb) for @$dirs;
17
18 for my $file (@$nondirs) {
19 next unless $file =~ /\.arc$/;
20
21 my $data;
22 aio_load "$path/$file", $data, sub {
23 $cb->("$path/$file", read_arch \$data);
24 };
25 }
26 };
27 }
28
29 sub for_all_arc($) {
30 scan_files $ENV{DELIANTRA_ARCHDIR} || ".", $_[0];
31
32 IO::AIO::flush;
33 }
34
35 sub extract {
36 my (undef, $filter, @slots) = @ARGV;
37
38 $filter =~ s/%(\w+)/\$_{$1}/g;
39 $filter = eval "sub { $filter }"
40 or die $@;
41
42 my @res;
43
44 unshift @slots, "_name";
45
46 my @sort = grep /^\d+$/, @slots;
47 my @widths = map s/\=(\d+)$// && $1, grep !/^\d+$/, @slots;
48 my @align = map s/>$// ? "" : "-", @slots;
49 my @big;
50
51 local *_;
52 for (sort keys %ARCH) {
53 *_ = $ARCH{$_};
54 next unless &$filter;
55 push @res, [@_{@slots}];
56 };
57
58 @res = sort {
59 "$a->[$_]$b->[$_]" =~ /^\d+$/
60 ? $a->[$_] <=> $b->[$_]
61 : $a->[$_] cmp $b->[$_]
62 } @res
63 for @sort;
64
65 for my $row (@res) {
66 for (0 .. $#$row) {
67 $big[$_] =1 if $row->[$_] =~ /\n/;
68 }
69 }
70 for my $i (0 .. $#widths) {
71 $widths[$i] ||= List::Util::max map length $_->[$i], \@slots, @res;
72 }
73
74 for (0 .. $#big) {
75 $widths[$_] = length $slots[$_] if $big[$_];
76 }
77
78 my $format = join " ", map "%$align[$_]$widths[$_]s", 0..$#widths;
79
80 printf "$format\n", map "A$_", map $_ + 1, @widths;
81 printf "$format\n", @slots;
82 for my $row (@res) {
83 print "\n" if @big;
84
85 printf "$format\n", map $big[$_] ? "\x{fffc}" : $row->[$_], 0 .. $#$row;
86
87 for (grep $big[$_], 0 .. $#big) {
88 print "$row->[$_]%%\n";
89 }
90 }
91 }
92
93 sub insert {
94 my ($apply) = @_;
95
96 shift @ARGV;
97 my $format = <STDIN>;
98 my @slots = unpack $format, <STDIN>;
99 s/^\s+// for @slots;
100
101 my %res;
102
103 while (<STDIN>) {
104 next unless /\S/;
105
106 my @row = unpack $format, $_;
107 s/^\s+// for @row;
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 Deliantra::load_archetypes;
161 extract;
162 } elsif ($ARGV[0] eq "diff") {
163 Deliantra::load_archetypes;
164 insert 0;
165 } elsif ($ARGV[0] eq "patch") {
166 Deliantra::load_archetypes;
167 insert 1;
168 } else {
169 die <<EOF;
170 Usage:
171
172 $0 extract 'filter' slot...
173
174 extract slots from server archetypes file (NOT the .arc files!)
175 Example: $0 extract '%type == 101' level
176
177 $0 diff
178
179 generates a diff against the .arc files found
180 in \$DELIANTRA_ARCHDIR or ".".
181
182 Example: $0 diff <file
183
184 $0 patch
185
186 like diff, but applies it in-place
187
188 EOF
189 }
190
191
192