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

#define MAXNODES 1024
#define MAXPATHSIZE 32768

void iterate(char *dir);

int count;

int main (int argc, char* argv[]) {

  if (argc != 2) {
    fprintf(stderr, "%s <directory>\n", argv[0]);
    return 1;
  }

  count = 0;
  iterate(argv[1]);
  printf ("%d\n", count);

  return 0;

}

void iterate(char *dir) {

  struct dirent* b;
  struct stat s;
  int dirlen, fnlen, depth;
  char* paths[MAXNODES];
  DIR* dirs[MAXNODES];
  int lens[MAXNODES];
  DIR* curdir;
  
  memset((void*)dirs, 0, (size_t)MAXNODES);
  memset((void*)paths, 0, (size_t)MAXNODES);
  
  depth = 1;
  paths[0] = dir;
  dirs[0] = opendir(dir);
  lens[0] = strlen(paths[0]);
  
  while (depth > 0) {
    
    /*printf ("DEPTH = %d\n", depth);*/

    curdir = dirs[depth-1];
    dirlen = lens[depth-1];
    /* printf("Entering '%s' [len=%d] [dir=%d]\n", paths[depth-1], dirlen, (int)curdir); */

    if (curdir == NULL) {
      fprintf(stderr, "Unable to read directory %s: %s\n", paths[depth-1], strerror(errno));
    } else {
      
      for (b = readdir(curdir); b != NULL; b = readdir(curdir)) {
	/* printf(" * %s\n", b->d_name); */
	fnlen = strlen(b->d_name);
	if ((fnlen == 1) && (strcmp(b->d_name, ".") == 0)){
	  continue;
	}
	if ((fnlen == 2) && (strcmp(b->d_name, "..") == 0)) {
	  continue;
	}
	if (paths[depth] == (void*)0) {
	  /* printf("MALLOC\n"); */
	  paths[depth] = malloc(MAXPATHSIZE);
	}
	if ((dirlen + fnlen + 2) > MAXPATHSIZE) {
	  fprintf(stderr, "Path buffer overflow detected [%d]\n", (dirlen + fnlen + 2));
	  exit(1);
	}
	strcpy(paths[depth], paths[depth-1]);
	strcpy(paths[depth] + lens[depth-1], "/");
	strcpy(paths[depth] + lens[depth-1] + 1, b->d_name);
	paths[depth][lens[depth-1] + fnlen + 1] = '\0';
	if (stat(paths[depth], &s) < 0) {
	  fprintf(stderr, "Unable to stat %s: %s\n", paths[depth], strerror(errno));
	  continue;
	} else {
	  if (S_ISDIR(s.st_mode)) {
	    /*printf(" cd %s\n", paths[depth]);*/
	    dirs[depth] = opendir(paths[depth]);
	    lens[depth] = dirlen + fnlen + 1;
	    curdir = NULL;
	    depth++;
	    break;
	  } else {
	    /*printf(" COUNT\n");*/
	    count++;
	  }
	}
	/* printf("READDIR [%d]\n", depth); */
      }
      if (curdir != NULL) {
	/*printf ("CLOSEDIR [%d]\n", depth);*/
	closedir(curdir);
	depth--;
      }
    }
  }
}
