[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5 Handling Recursive Calls.

Sometimes programs contain functions that recursively call themselves. GNU output format provides a special indication for such functions. The definition of the recursive function is marked with an ‘(R)’ at the end of line (before terminating colon). Subsequent recursive calls to this function are marked with a ‘(recursive: see refline)’ at the end of line. Here, refline stands for the reference line number where the recursion root definition was displayed.

To illustrate this, let’s consider the following program, that prints recursive listing of a directory, allowing to cut off at the arbitrary nesting level:

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>

/* 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;
}

Running cflow on this program produces the following graph:

$ cflow --number d.c
    1 main() <int main (int argc,char **argv) at d.c:85>:
    2     fprintf()
    3     atoi()
    4     printdir() <void printdir (int level,char *name) at d.c:42> (R):
    5         getcwd()
    6         perror()
    7         chdir()
    8         opendir()
    9         readdir()
   10         printf()
   11         ignorent() <int ignorent (char *name) at d.c:28>:
   12             strcmp()
   13         isdir() <int isdir (char *name) at d.c:12>:
   14             stat()
   15             perror()
   16             S_ISDIR()
   17         putchar()
   18         printdir()
                <void printdir (int level,char *name) at d.c:42>
                (recursive: see 4)
   19         closedir()

The printdir description in line 4 shows that the function is recursive. The recursion call is shown in line 18.


[ << ] [ < ] [ Up ] [ > ] [ >> ]

This document was generated on March 24, 2021 using texi2html 5.0.