cline.c

Mon, 13 Feb 2012 19:10:00 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 13 Feb 2012 19:10:00 +0100
changeset 31
27c3c1c6b768
parent 30
d642fdb6745e
child 32
51d6e45a7592
permissions
-rw-r--r--

added --exclude-cstyle-comments shortcut

/*
 * cline.c
 *
 *  Created on: 23.05.2011
 *      Author: Mike
 */

#include "cline.h"
#include "scanner.h"
#include "settings.h"
#include "arguments.h"
#include "stream.h"
#include "regex_parser.h"

void printHelpText() {
  const char* helpText = 
    "\nUsage:"
    "\n      cline [Options] [Directory]"
    "\n      cline [Options] [Directory]"
    "\n\nCounts the line terminator characters (\\n) within all"
    " files in the specified\ndirectory."
    "\n\nOptions:"
    "\n  -b <level>          - binary file heuristics level (default medium)"
    "\n                        One of: ignore low medium high"
    "\n  -E <pattern>        - Excludes any line matching the <pattern>"
    "\n  -e <start> <end>    - Excludes lines between <start> and <end>"
    "\n                        You may use these options multiple times"
    "\n  -h, --help          - this help text"
    "\n  -m                  - print information about matching files only"
    "\n  -s <suffixes>       - only count files with these suffixes (separated"
    "\n                        by commas)"
    "\n  -S <suffixes>       - count any file except those with these suffixes"
    "\n                        (separated by commas)"
    "\n  -r, -R              - includes subdirectories"
    "\n  -v, --version       - print out version information"
    "\n  -V                  - turn verbose output off, print the result only"
    "\n\nShortcuts:"
    "\n  --exclude-cstyle-comments"
    "\n = -E \"\\s*//\" -e \"\\s*/\\*\" \"\\*/\\s*\""
    "\n\n"
    "The default call without any options is:"    
    "\n  cline ./\n\n"
    "So each file in the working directory is counted. If you want to count C"
    "\nsource code in your working directory and its subdirectories, type:"
    "\n  cline -rs .c\n"
    "\nIf you want to exclude comment lines, you may use the -e/-E option."
    "\nAfter a line matches the regex pattern <start> any following line is"
    "\nnot counted unless a line matches the <end> pattern. A line is still "
    "\ncounted when it does not start or end with the respective patterns."
    "\nPlease note, that cline does not remove whitespace characters as this"
    "\nmight not be reasonable in some cases."
    "\n\nExample (C without comments):"
    "\n  cline -s .c,.h --exclude-cstyle-comments";
    
  printf(helpText);
}

int exit_with_version(settings_t* settings) {
  printf("cline - Revision: %s", VERSION);
  destroy_settings_t(settings);
  return 0;
}

int exit_with_help(settings_t* settings, int code) {
  printHelpText();
  destroy_settings_t(settings);
  return code;
}

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

  /* Settings */
  settings_t *settings = new_settings_t();
  if (settings == NULL) {
    fprintf(stderr, "Memory allocation failed.\n");
    return 1;
  }

  /* Get arguments */
  char* directory = "./";
  char* includeSuffix = NULL;
  char* excludeSuffix = NULL;
  int checked = 0;

  for (int t = 1 ; t < argc ; t++) {

    int argflags = checkArgument(argv[t], "hsSrRmvVbeE");
    int paropt = 0;

    /* s */
    if ((argflags & 2) > 0) {
      if (!checkParamOpt(&paropt) || registerArgument(&checked, 2)) {
        return exit_with_help(settings, 1);
      }
      t++;
      if (t >= argc) {
        return exit_with_help(settings, 1);
      }
      includeSuffix = argv[t];
    }
    /* S */
    if ((argflags & 4) > 0) {
      if (!checkParamOpt(&paropt) || registerArgument(&checked, 4)) {
        return exit_with_help(settings, 1);
      }
      t++;
      if (t >= argc) {
        return exit_with_help(settings, 1);
      }
      excludeSuffix = argv[t];
    }
    /* h */
    if ((argflags & 1) > 0 || strcmp(argv[t], "--help") == 0) {
      return exit_with_help(settings, 0);
    }
    /* r, R */
    if ((argflags & 24) > 0) {
      if (registerArgument(&checked, 24)) {
        return exit_with_help(settings, 1);
      }
      settings->recursive = true;
    }
    /* m */
    if ((argflags & 32) > 0) {
      if (registerArgument(&checked, 32)) {
        return exit_with_help(settings, 1);
      }
      settings->matchesOnly = true;
    }
    /* v */
    if ((argflags & 64) > 0 || strcmp(argv[t], "--version") == 0) {
      return exit_with_version(settings);
    }
    /* V */
    if ((argflags & 128) > 0) {
      if (registerArgument(&checked, 128)) {
        return exit_with_help(settings, 1);
      }
      settings->verbose = false;
    }
    /* b */
    if ((argflags & 256) > 0) {
      if (!checkParamOpt(&paropt) || registerArgument(&checked, 256)) {
        return exit_with_help(settings, 1);
      }
      t++;
      if (t >= argc) {
        return exit_with_help(settings, 1);
      }
      if (strcasecmp(argv[t], "ignore") == 0) {
        settings->bfileHeuristics->level = BFILE_IGNORE;
      } else if (strcasecmp(argv[t], "low") == 0) {
        settings->bfileHeuristics->level = BFILE_LOW_ACCURACY;
      } else if (strcasecmp(argv[t], "medium") == 0) {
        settings->bfileHeuristics->level = BFILE_MEDIUM_ACCURACY;
      } else if (strcasecmp(argv[t], "high") == 0) {
        settings->bfileHeuristics->level = BFILE_HIGH_ACCURACY;
      } else {
        return exit_with_help(settings, 1);
      }
    }
    /* e */
    if ((argflags & 512) > 0) {
      if (!checkParamOpt(&paropt) || t + 2 >= argc) {
        return exit_with_help(settings, 1);
      }
      t++; add_string(settings->regex->pattern_list, argv[t]);
      t++; add_string(settings->regex->pattern_list, argv[t]);
    }
    /* E */
    if ((argflags & 1024) > 0) {
      t++;
      if (!checkParamOpt(&paropt) || t >= argc) {
        return exit_with_help(settings, 1);
      }
      add_string(settings->regex->pattern_list, argv[t]);
      add_string(settings->regex->pattern_list, "$");
    }
    if (argflags == 0) {
      /* SHORTCUTS */
      /* exclude-cstyle-comments */
      if (strcmp(argv[t], "--exclude-cstyle-comments") == 0) {
        add_string(settings->regex->pattern_list, "\\s*//");
        add_string(settings->regex->pattern_list, "$");
        add_string(settings->regex->pattern_list, "\\s*/\\*");
        add_string(settings->regex->pattern_list, "\\*/\\s*");
      }
      /* Path */
      else if (registerArgument(&checked, 1024)) {
        return exit_with_help(settings, 1);
      }
      directory = argv[t];
    }
  }

  /* Configure output */
  if (!settings->verbose) {
    close_stdout();
  }

  /* Find tokens */
  parseCSL(includeSuffix, settings->includeSuffixes);
  parseCSL(excludeSuffix, settings->excludeSuffixes);

  /* Scan directory */
  if (regex_compile_all(settings->regex)) {
    int lines = scanDirectory((scanner_t){directory, 0}, settings);
    destroy_settings_t(settings);

    /* Print double line and line count */
    for (int t = 0 ; t < 79 ; t++) {
      printf("=");
    }
    printf("\n%73d lines\n", lines);

    if (settings->confusing_lnlen && settings->regex->pattern_list->count > 0) {
      printf("\nSome files contain too long lines.\n"
        "The regex parser currently supports a maximum line length of %d."
        "\nThe result might be wrong.\n", REGEX_MAX_LINELENGTH);
    }

    if (!settings->verbose) {
      reopen_stdout();
      printf("%d", lines);
    }
  }

  fflush(stdout);
  fflush(stderr);
  return 0;
}

mercurial