/*
 * This is a simple tool to count the lines of code in your MUD and break them
 * down into actual code, comments, whitespace, and directives.  It was inspired
 * by the script-based one submitted to MudBytes by Darien after I realized it
 * was somewhat innacurate and didn't pick up line comments at all.
 *
 * To compile:
 *   gcc lines.c -o lines
 *
 * To use it:
 *   ./lines ../src
 *   ./lines ./QuickMUD/src
 *
 * Hopefully someone else finds it useful.
 *
 * - Midboss, 8/30/2007
 */
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <ctype.h>

int main (int argc, char *argv[])
{
    long lines = 0, comments = 0, directives = 0, whitespace = 0;
    char line[256], tmpname[64];
    int i = 0, in_comment = 0;
    struct dirent * fname;
    FILE * fp;
    DIR * src;

    /* Start by opening the directory. */
    src = opendir (argv[1]);

    if (src == NULL)
    {
        printf ("No such directory!\n");
        exit (1);
    }

    /* Now run through the directory. */
    while (fname = readdir (src))
    {
        /* Make sure this is part of the source code. */
        /* Not 100% accurate, probably, but it works for me. */
        if ((  !strstr (fname->d_name, ".cpp")
            && !strstr (fname->d_name, ".c")
            && !strstr (fname->d_name, ".hpp")
            && !strstr (fname->d_name, ".h"))
            || strstr (fname->d_name, ".bak")
            || strstr (fname->d_name, "~"))
            continue;

        printf ("Counting: %s", fname->d_name);

        /* Open up the file. */
        /* Only continue if it fails, we want to attempt every file. */
        sprintf (tmpname, "%s/%s", argv[1], fname->d_name);

        if ((fp = fopen (tmpname, "r")) == NULL)
        {
            printf (" (could not open!)\n");
            continue;
        }
        else
            printf ("\n");

        /* Now read it one line at a time. */
        while (fgets (line, 256, fp) != NULL)
        {
			i = 0;

            /* Already in a block comment? */
            if (in_comment > 0)
            {

				while (    line[i] != '/'
						&& line[i] != '\n'
						&& line[i] != '\0')
					++i;

                /* If we're at the end, break out of the comment block. */
                /* strlen() is always \0, strlen () - 1 is always \n */
                if (line[i] == '/')
                {
                    in_comment = -1;
                    comments++;
                }
                /* Otherwise just increment the comment line count. */
                else
                    comments++;
            }
            /* Otherwise... */
            else
            {
                /* Eat up all the leading whitespace. */
                while (isspace (line[i]))
					++i;

                /* If we're at the end, this is a whitespace line. */
                if (line[i] == '\0' || line[i] == '\n')
                    whitespace++;
                /* Directive? */
                else if (line[i] == '#')
                    directives++;
                /* C++ style comment? */
                else if (line[i] == '/' && line[i+1] == '/')
                    comments++;
                /* Beginning of a block comment? */
                else if (line[i] == '/' && line[i+1] == '*')
                {
                    in_comment = 1;
                    comments++;
                }
                else
                    lines++;
            }
        }

        /* If the file somehow ended in a comment, break out of it. */
        /* Also adds the final 'empty' line as whitespace. */
        in_comment = 0;
        whitespace++;
        fclose (fp);
    }

    closedir (src);

    printf ("\n----------------------------------------\n"
            "Total Lines: %ld\n"
            "Actual Code: %ld\n"
            "Directives:  %ld\n"
            "Whitespace:  %ld\n"
            "Comments:    %ld\n\n",
            lines + whitespace + comments + directives,
            lines, directives, whitespace, comments);

    return 0;
}