带你走进Cflow (二)·输出格式和递归调用

目录

​编辑

1、各种输出格式

2、处理递归调用


1、各种输出格式

        前面所描述的输出格式被称为 GNU 类型。除此之外,cflow 也可以使用 POSIX 产生格式化的输出。这种格式,输出的每一行都以一个参考数字开始,比如,最开始是输出行的顺序号,后面跟随每一个嵌套层的固定长度的缩进。然后如果有的话依次是函数的名字、冒号、函数的原型。紧跟在函数原型后面的是定义的位置(包括文件名和行号)。函数顶一个位置都被尖括号围住。如果函数的定义没有找到,该行将会以一个空的尖括号结尾。

        使用格式化输出要么在命令行中通过--format=posix (-f posix)选项指定,要么设置环境变量 POSIXLY_CORRECT 。

        使用 POSIX 格式处理我们的样例文件,如下:

 1 main: int (int argc,char **argv), 
 2 fprintf: <>
 3 who_am_i: int (void), 
 4 getpwuid: <>
 5 geteuid: <>
 6 getenv: <>
 7 fprintf: <>
 8 printf: <>

        是否在输出中要包含函数的参数列表现在并不清楚。默认情况下 cflow 将会全部打印它们。然而一些程序使用 cflow 分析时希望省略参数列表,这可以使用--omit-arguments 选项实现。

        cflow 未来的版本中将会提供更多的输出格式,包括 XML 和 HTML 输出。目前你可以使用 VCG 工具来创建典型的图。根据 xvcg 来转变输出格式可以使用cflow2vcg 程序在 GPL 下都是可用的。

        Cflow2vcg 期望使用 POSIX 格式图,每层嵌套的缩进为一个水平制表符,第 0 层使用额外的 tab 字符,在函数声明中没有参数列表。这样用可兼容 cflow2vcg 产生的输出格式,调用 cflow 如下:

cflow --format=posix --omit-arguments \
 --level-indent='0=\t' --level-indent='1=\t' \
 --level-indent=start='\t'

你可以使用下面的脚本来虚拟调用这三个工具:

#! /bin/sh

cflow --format=posix --omit-arguments \
--level-indent='0=\t' --level-indent='1=\t' \
--level-indent=start='\t' $* |
cflow2vcg | xvcg -

2、处理递归调用

        有时候程序中包含调用自己的函数。GNU 输出格式为这种函数提供了特殊的表示。在结束字符-冒号之前,会有一个标号‘(R)’作为递归函数的标志。随后递归调用处会在行结尾使用‘(recursive: see refline)’标识出。这里的 refline 表示递归函数的跟定义所处的位置。

        为了说明这个,我们考虑下面的程序,他打印递归目录列表,允许在任意嵌套级截断:

 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 
 /* Return true if file NAME is a directory. */
 static int
 isdir (char *name)
 {
 struct stat st;
 
 if (stat (name, &st))
 {
 perror (name);
 return 0;
 }
 return S_ISDIR (st.st_mode);
 }
 
 static char *ignored_names[] = { ".", "..", NULL };
 
 /* Return true if NAME should not be recursed into */
 int
 ignorent (char *name)
 {
 char **p;
 for (p = ignored_names; *p; p++)
 if (strcmp (name, *p) == 0)
 return 1;
 return 0;
 }
 
 int max_level = -1;
 
 /* Print contents of the directory PREFIX/NAME.
 Prefix each output line with LEVEL spaces. */
 void
 printdir (int level, char *name)
 {
 DIR *dir;
 struct dirent *ent;
 char cwd[512];
 
 if (!getcwd(cwd, sizeof cwd)) 
 {
 perror ("cannot save cwd\n");
 _exit (1);
 }
 chdir (name);
 dir = opendir (".");
 if (!dir)
 {
 perror (name);
 _exit (1);
 }
 
 while ((ent = readdir (dir)))
 {
 printf ("%*.*s%s", level, level, "", ent->d_name);
 if (ignorent (ent->d_name))
 printf ("\n");
 else if (isdir (ent->d_name))
 {
 printf ("/");
 if (level + 1 == max_level)
 putchar ('\n');
 else
 {
 printf (" contains:\n");
 printdir (level + 1, ent->d_name);
 }
 }
 else
 printf ("\n");
 }
 closedir (dir);
 chdir (cwd);
 }
 
 int
 main (int argc, char **argv)
 {
 if (argc < 2)
 {
 fprintf (stderr, "usage: d [-MAX] DIR [DIR...]\n");
 return 1;
 }
 
 if (argv[1][0] == '-')
 {
 if (!(argv[1][1] == '-' && argv[1][2] == 0))
 max_level = atoi (&argv[1][1]);
 --argc;
 ++argv;
 }
 
 while (--argc)
 printdir (0, *++argv);
 
 return 1;
 }

运行 cflow 处理这个程序生成如下的图:

$ cflow --number d.c
 1 main() :
 2 fprintf()
 3 atoi()
 4 printdir()  (R):
 5 getcwd()
 6 perror()
 7 chdir()
 8 opendir()
 9 readdir()
 10 printf()
 11 ignorent() :
 12 strcmp()
 13 isdir() :
 14 stat()
 15 perror()
 16 S_ISDIR()
 17 putchar()
 18 printdir()
 
 (recursive: see 4)
 19 closedir()

        第 4 行的描述显示 printdir 是递归函数。递归调用是在第 18 行。

带你走进Cflow (一)-CSDN博客

带你走进Cflow (二)·输出格式和递归调用_第1张图片

你可能感兴趣的:(Cflow,javascript,开发语言,ecmascript)