📄 parsesource.pm
字号:
return \%constants;}sub handle_constant { my ($self, $constants) = @_; my $keys = keys %defines_wanted_re; #XXX broken bleedperl ? return if /^($defines_unwanted)/o; while (my ($class, $groups) = each %defines_wanted_re) { my $keys = keys %$groups; #XXX broken bleedperl ? while (my ($group, $re) = each %$groups) { next unless /^($re)/; push @{ $constants->{$class}->{$group} }, $_; return; } }}sub handle_enum { my ($self, $fh, $constants) = @_; my ($name, $e) = $self->parse_enum($fh); return unless $name; $name =~ s/^ap_//; $name =~ s/_(e|t)$//; my $class; for (keys %enums_wanted) { next unless $enums_wanted{$_}->{$name}; $class = $_; } return unless $class; $name =~ s/^apr_//; push @{ $constants->{$class}->{$name} }, @$e if $e;}#this should win an award for worlds lamest parsersub parse_enum { my ($self, $fh) = @_; my $code = $_; my @e; unless ($code =~ /;\s*$/) { local $_; while (<$fh>) { $code .= $_; last if /;\s*$/; } } my $name; if ($code =~ s/^\s*enum\s+(\w*)\s*//) { $name = $1; } elsif ($code =~ s/^\s*typedef\s+enum\s+//) { $code =~ s/\s*(\w+)\s*;\s*$//; $name = $1; } $code =~ s:/\*.*?\*/::sg; $code =~ s/\s*=\s*\w+//g; $code =~ s/^[^\{]*\{//s; $code =~ s/\}[^;]*;?//s; $code =~ s/^\s*\n//gm; while ($code =~ /\b(\w+)\b,?/g) { push @e, $1; } return ($name, \@e);}sub wanted_functions { shift->{prefix_re} }sub wanted_structures { shift->{prefix_re} }sub get_functions { my $self = shift; my $key = 'parsed_fdecls'; return $self->{$key} if $self->{$key}; my $c = $self->{c}; my $fdecls = $c->get($key); my %seen; my $wanted = $self->wanted_functions; my @functions; for my $entry (@$fdecls) { my ($rtype, $name, $args) = @$entry; next unless $name =~ $wanted; next if $seen{$name}++; my @attr; for (qw(static __inline__)) { if ($rtype =~ s/^($_)\s+//) { push @attr, $1; } } #XXX: working around ModPerl::CScan confusion here #macro defines ap_run_error_log causes #cpp filename:linenumber to be included as part of the type for (@$args) { next unless $_->[0]; $_->[0] =~ s/^\#.*?\"\s+//; $_->[0] =~ s/^register //; } my $func = { name => $name, return_type => $rtype, args => [map { { type => $_->[0], name => $_->[1] } } @$args], }; $func->{attr} = \@attr if @attr; push @functions, $func; } # sort the functions by the 'name' attribute to ensure a # consistent output on different systems. $self->{$key} = [sort { $a->{name} cmp $b->{name} } @functions];}sub get_structs { my $self = shift; my $key = 'typedef_structs'; return $self->{$key} if $self->{$key}; my $c = $self->{c}; my $typedef_structs = $c->get($key); my %seen; my $wanted = $self->wanted_structures; my $other = join '|', qw(_rec module piped_log uri_t htaccess_result cmd_parms cmd_func cmd_how); my @structures; my $sx = qr(^struct\s+); while (my ($type, $elts) = each %$typedef_structs) { next unless $type =~ $wanted or $type =~ /($other)$/o; $type =~ s/$sx//; next if $seen{$type}++; my $struct = { type => $type, elts => [map { my $type = $_->[0]; $type =~ s/$sx//; $type .= $_->[1] if $_->[1]; $type =~ s/:\d+$//; #unsigned:1 { type => $type, name => $_->[2] } } @$elts], }; push @structures, $struct; } # sort the structs by the 'type' attribute to ensure a consistent # output on different systems. $self->{$key} = [sort { $a->{type} cmp $b->{type} } @structures];}sub write_functions_pm { my $self = shift; my $file = shift || 'FunctionTable.pm'; my $name = shift || 'Apache2::FunctionTable'; $self->write_pm($file, $name, $self->get_functions);}sub write_structs_pm { my $self = shift; my $file = shift || 'StructureTable.pm'; my $name = shift || 'Apache2::StructureTable'; $self->write_pm($file, $name, $self->get_structs);}sub write_constants_pm { my $self = shift; my $file = shift || 'ConstantsTable.pm'; my $name = shift || 'Apache2::ConstantsTable'; $self->write_pm($file, $name, $self->get_constants);}sub write_pm { my ($self, $file, $name, $data) = @_; require Data::Dumper; local $Data::Dumper::Indent = 1; my ($subdir) = (split '::', $name)[0]; my $tdir = 'xs/tables/current'; if (-d "$tdir/$subdir") { $file = "$tdir/$subdir/$file"; } # sort the hashes (including nested ones) for a consistent dump canonsort(\$data); my $dump = Data::Dumper->new([$data], [$name])->Dump; my $package = ref($self) || $self; my $version = $self->VERSION; my $date = scalar localtime; my $new_content = << "EOF";package $name;# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!# ! WARNING: generated by $package/$version# ! $date# ! do NOT edit, any changes will be lost !# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$dump1;EOF my $old_content = ''; if (-e $file) { open my $pm, '<', $file or die "open $file: $!"; local $/ = undef; # slurp the file $old_content = <$pm>; close $pm; } my $overwrite = 1; if ($old_content) { # strip the date line, which will never be the same before # comparing my $table_header = qr{^\#\s!.*}; (my $old = $old_content) =~ s/$table_header//mg; (my $new = $new_content) =~ s/$table_header//mg; $overwrite = 0 if $old eq $new; } if ($overwrite) { open my $pm, '>', $file or die "open $file: $!"; print $pm $new_content; close $pm; }}# canonsort(\$data);# sort nested hashes in the data structure.# the data structure itself gets modifiedsub canonsort { my $ref = shift; my $type = ref $$ref; return unless $type; require Tie::IxHash; my $data = $$ref; if ($type eq 'ARRAY') { for (@$data) { canonsort(\$_); } } elsif ($type eq 'HASH') { for (keys %$data) { canonsort(\$data->{$_}); } tie my %ixhash, 'Tie::IxHash'; # reverse sort so we get the order of: # return_type, name, args { type, name } for functions # type, elts { type, name } for structures for (sort { $b cmp $a } keys %$data) { $ixhash{$_} = $data->{$_}; } $$ref = \%ixhash; }}1;__END__
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -