Определение числа строк кода и комментариев

Материал из BSDHome

Перейти к: навигация, поиск

Имеется дерево исходных кодов на нескольких ЯП, определить число строк кода и комментариев. Для этих целей была написана программа на Си.

/* The program makes statistics
* of using various programming
* language constructs in source
* file(s) of any type on given
* location(s).
* -------------------------------
* Author: MATAH
* Date: Mon, 29 Mar 2006 10:34:48
* License: GNU GPL v3
* Vein: idleness =>
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define _GNU_SOURCE
#include <string.h>
#include <getopt.h>
 
void dirtraverse (const char *);
void collect (const char *);
void parse (const char *, int);
void parse_init (void);
 
struct entry
{
  char *type;
  char *mask;
  long count;
  long linec;
  char *comments_delimiters;
  long commc;
} ents[] =
{
  {
  "C++ files in the path", ".cpp", 0, 0, "/*...*/ //", 0},
  {
  "C++ files in the path", ".cc", 0, 0, "/*...*/ //", 0},
  {
  "C files in the path", ".c", 0, 0, "/*...*/ //", 0},
  {
  "assembler files in the path", ".S", 0, 0, "/*...*/ // ;", 0},
  {
  "header files in the path", ".h", 0, 0, "/*...*/ //", 0},
  {
  "header files in the path", ".hh", 0, 0, "/*...*/ //", 0},
  {
  "incidental files in the path", "", 0, 0, NULL, 0},
  {
  NULL, NULL, 0, 0, NULL, 0}
};
 
static char comdels[sizeof (ents) / sizeof (struct entry)][5][2][7];
 
int
main (int ac, char **av)
{
 
  struct
  {
    unsigned int print_comments:1;
    unsigned int print_code:1;
    unsigned int print_all:1;
  } opts;
 
  short i, j;
  short pathindex[32];
 
  for (i = 1, j = 0; i < ac; i++)
    if (*av[i] != '-')
      pathindex[j++] = i;
 
  if (!*pathindex)
    {
      printf ("Error: Missing path string\n");
      exit (1);
    }
 
  static const char *const shortopts = "mac";
 
  static const struct option longopts[] = {
    {"code", 0, NULL, 'c'},
    {"comment", 0, NULL, 'm'},
    {"all", 0, NULL, 'a'},
    {NULL, 0, NULL, 0}
  }; 
 
  extern int optind;
  register int len;
  register char opt;
 
  while ((opt = getopt_long (ac, av, shortopts, longopts, NULL)) != EOF)
    {
      switch (opt)
	{
	case 'a':
	  opts.print_all = 1;
	  break;
	case 'm':
	  opts.print_comments = 1;
	  break;
	case 'c':
	  opts.print_code = 1;
	  break;
	}
    }
 
  parse_init ();
 
  for (; j-- > 0;)
    collect (av[pathindex[j]]);
 
  int longest;
  for (j = 0, longest = len = 0; ents[j].type != NULL; j++)
    if ((len = strlen (ents[j].type)) > longest)
      longest = len;
  char *banner = (char *) malloc ((longest + 27) * 3 + 1);
  int pos = 0;
  char *bantext = "Statistics:";
  banner[pos] = 0x0;
  strncat (banner, "+", 1);
  pos++;
  for (j = 0; j < longest + 27; j++, pos++)
    strncat (banner, "-", 1);
  strncat (banner, "+\n", 2);
  short even = (longest % 2) ? 0 : 1;
  strncat (banner, "|", 1);
  for (j = 0; j < ((even) ? ((longest + 27) - strlen (bantext)) / 2 :
		   ((longest + 27) - strlen (bantext) - 1) / 2); j++)
    strncat (banner, " ", 1);
  strcat (banner, bantext);
  for (j = 0; j < ((even) ? ((longest + 27) - strlen (bantext)) / 2 :
		   ((longest + 27) - strlen (bantext) + 1) / 2); j++)
    strncat (banner, " ", 1);
  strncat (banner, "|\n+", 3);
  for (j = 0; j < longest + 14; j++)
    strncat (banner, "-", 1);
  strncat (banner, "+", 1);
  for (j = 0; j < 10 + 2; j++)
    strncat (banner, "-", 1);
  strncat (banner, "+\n", 1);
  printf ("%s\n", banner);
  j = 0;
  short entnum = 0, k;
 
  while (ents[j].type)
    {
      if (!ents[j].count)
	{
	  j++;
	  continue;
	}
      else
	{
 
	  entnum++;
 
	  printf ("| %d)For %s:", entnum, ents[j].type);
	  for (k = 0; k < longest - strlen (ents[j].type) + 6; k++)
	    putchar (' ');
	  putchar ('|');
	  for (k = 0; k++ < 12;)
	    putchar (' ');
	  printf ("|\n");
	  printf ("|    Quantity");
	  for (k = 0; k < longest + 5 + 6 - 10; k++)
	    putchar ('.');
	  printf (" | ");
	  printf ("%10ld", ents[j].count);
	  printf (" |\n");
	  if (ents[j].linec)
	    {
	      printf ("|    Codelines");
	      for (k = 0; k < longest + 5 + 6 - 11; k++)
		putchar ('.');
	      printf (" | ");
	      printf ("%10ld", ents[j].linec);
	      printf (" |\n");
	    }
	  if (ents[j].commc)
	    {
	      printf ("|    Commentlines");
	      for (k = 0; k < longest + 5 + 6 - 14; k++)
		putchar ('.');
	      printf (" | ");
	      printf ("%10ld", ents[j].commc);
	      printf (" |\n");
	    }
	  j++;
	}
    }
  putchar ('+');
  for (k = 0; k < longest + 14; k++)
    putchar ('-');
  putchar ('+');
  for (k = 0; k < 10 + 2; k++)
    putchar ('-');
  printf ("+\n");
 
  return EXIT_SUCCESS;
}
 
void
collect (const char *path)
{
  int i;
 
  struct stat *stbuf = (void *) malloc (sizeof (struct stat));
 
  if (stat (path, stbuf) == EOF)
    {
      perror (path);
      return;
    }
 
  if (stbuf->st_mode & S_IFDIR)
    dirtraverse (path);
  else
    {
      for (i = 0; ents[i].type != NULL; ++i)
	{
	  if ((unsigned) strcasestr (path, ents[i].mask)
	      == (unsigned) path + strlen (path) - strlen (ents[i].mask))
	    {
	      parse (path, i);
 
 
	      break;
	    }
	  else
	    if ((unsigned) strcasestr (path, ents[i].mask) == (unsigned) path)
	    ++(ents[i].count);
	}
    }
  free (stbuf);
}
 
void
dirtraverse (const char *path)
{
  DIR *dirpnt;
 
  if (!(dirpnt = opendir (path)))
    perror ("Oops");
 
  char fullpath[1024];
 
  struct dirent *de;
 
  while ((de = readdir (dirpnt)))
    {
      if (strcmp (de->d_name, ".") == 0 || strcmp (de->d_name, "..") == 0)
	continue;
      else
	{
	  sprintf (fullpath, "%s/%s", path, de->d_name);
	  collect (fullpath);
	}
    }
  closedir (dirpnt);
}
 
void
parse (const char *path, int pos)
{
  (ents[pos].count)++;
  FILE *fptr = fopen (path, "r");
  char *str = (char *) malloc (4096);
  int si = 0, ai;
  char *strpos = str, *t = NULL;
  long prev;
  short incom = 0;
 
  while (fgets (str, 4096, fptr) != NULL)
    {
      prev = ents[pos].commc;
      si = 0;
      while (str[si++] == ' ' || str[si - 1] == '\t')
	;
      if (!incom)
	ai = 0;
      for (strpos = (str + si - 1); **comdels[pos][ai]; ai++)
	{
	  if ((t = strstr (strpos, comdels[pos][ai][incom])))
	    {
	      strpos = t;
	      if (incom)
		{
		  incom = 0;
		  ai--;
		  continue;
		}
	      if (*comdels[pos][ai][1])
		{
		  if (strpos == str + si - 1)
		    ents[pos].commc++;
		  ai--;
		  incom = 1;
		}
	      else if (t == (str + si - 1))
		{
		  ents[pos].commc++;
		  break;
		}
	    }
	  else if (incom)
	    {
	      ents[pos].commc++;
	      break;
	    }
	}
      if (prev == ents[pos].commc)
	ents[pos].linec++;
    }
  fclose (fptr);
}
 
void
parse_init (void)
{
  memset (comdels, 0, sizeof (comdels));
  int pos;
 
  for (pos = 0; ents[pos].comments_delimiters; pos++)
    {
      char *p = ents[pos].comments_delimiters;
      int ta = 0, tb = 0, tc = 0;
      while (*p)
	{
	  if (*p == '.')
	    {
	      comdels[pos][ta][tb++][tc] = '\0';
	      tc = 0;
	      while (*(++p) == '.')
		;
	    }
	  if (*p == ' ')
	    {
	      comdels[pos][ta++][tb][tc] = '\0';
	      p++;
	      tb = tc = 0;
	      continue;
	    }
	  comdels[pos][ta][tb][tc++] = *(p++);
	}
    }
}

Скопировать исходник в файл locc.c Компилировать командой:

$ gcc locc.c -o locc

Запускать командой:

$ ./locc адрес дерева исходных кодов