http://blockdiag.com/blockdiag-ja/build/html/index.html
を見て、なにかできないだろうかって考えてみて、cflowの結果から
コールフローが作れるなって思って、コードを書いてみた。
準備
cflow, blockdiagをインストールします
% sudo aptitude install cflow # Ubuntu, debian % sudo brew install cflow # Mac OSX % sudo easy_install blockdiag
コード
blockdiagのことを考えると Pythonの方がって思ったけど、
すぐには書けなかったので Perlで。
#!/usr/bin/env perl use strict; use warnings; package App::cflow2blockdiag; use Carp (); use File::Which (); sub new { my ($class, $files_ref, $ignores_regexp) = @_; Carp::croak("Please install cflow\n") unless File::Which::which('cflow'); bless { files => $files_ref, ignore => $ignores_regexp }, $class; } sub run { my $self = shift; my $cflow_ref = $self->_exec_cflow; $self->cflow_to_blockdiag($cflow_ref); } sub cflow_to_blockdiag { my ($self, $cflow_ref) = @_; my (@flows, @current_flow); my $prev_indent = -1; open my $fh, "<", $cflow_ref or Carp::croak("Can't open strref\n"); while ( my $line = <$fh> ) { chomp $line; my $indent_num = $line =~ s{\s{4}}{}gxms; $indent_num ||= 0; my ($func) = $line =~ m{^(\w+)\(\)}; next if $func =~ $self->{ignore}; if ($indent_num <= $prev_indent) { push @flows, join ' -> ', @current_flow; pop @current_flow for 0..($prev_indent - $indent_num); } push @current_flow, $func; $prev_indent = $indent_num; } close $fh; my $flow = join ";\n\t", @flows; print <<__DIAG__ diagram { fontsize = 20; default_shape = roundedbox; \t$flow } __DIAG__ } sub _exec_cflow { my $self = shift; my @cmd = ('cflow', '--omit-arguments', @{$self->{files}}); open my $cflow, "-|", @cmd or Carp::croak("Can't exec cflow\n"); my $output = do { local $/; <$cflow>; }; close $cflow; return \$output; } package main; use Regexp::Assemble; my $ra = Regexp::Assemble->new; $ra->add('printf$'); $ra->add('^[mc]alloc$', 'free'); $ra->add('^strn?(?:cmp|cpy)$'); $ra->add('^mem(?:set|cpy)$'); unless (caller) { my $app = App::cflow2blockdiag->new(\@ARGV, $ra->re); $app->run; }
実行
コールフローを生成したい, Cファイルを指定します
% perl cflow2blockdiag.pl hoge.c
結果
NetBSD 5.1の bin/mkdir/mkdir.cで試してみると以下のようになります
% perl cflow2blockdiag.pl mkdir.c diagram { fontsize = 20; default_shape = roundedbox; main -> setprogname; main -> setlocale; main -> umask; main -> getopt; main -> setmode; main -> err; main -> getmode; main -> usage -> getprogname; main -> usage -> exit; main -> strrchr; main -> mkpath -> strspn; main -> mkpath -> strcspn; main -> mkpath -> mkdir; main -> mkpath -> stat; main -> mkpath -> warn; main -> mkpath -> S_ISDIR; main -> mkpath -> chmod; main -> mkdir; main -> warn; main -> chmod }
この出力をリダイレクトし、blockdiagに与えるとコールフローを図として
得ることができます。
% perl cflow2blockdiag.pl mkdir.c > mkdir.diag % blockdiag mkdir.diag
以下のような画像が得られました.
![]() |
送信者 blog |
まとめ
cflowの出力から, blockdiag形式で出力できるようにするための
変換プログラムを紹介しました。コールフローであれば専用のツールが
多数あるだろうから、別に blockdiagを使う必要はないかなと思いますけど、
いろいろ応用できるものはあるんじゃないかなと思いました。