src/cline.c

changeset 34
fa9bda32de17
parent 33
1a2d7298bc82
child 35
35120de6ee53
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/cline.c	Fri Dec 28 15:44:28 2012 +0100
     1.3 @@ -0,0 +1,269 @@
     1.4 +/*
     1.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 
     1.6 + * Copyright 2011 Mike Becker. All rights reserved.
     1.7 + * 
     1.8 + * Redistribution and use in source and binary forms, with or without
     1.9 + * modification, are permitted provided that the following conditions are met:
    1.10 + * 
    1.11 + * 1. Redistributions of source code must retain the above copyright
    1.12 + * notice, this list of conditions and the following disclaimer.
    1.13 + * 
    1.14 + * 2. Redistributions in binary form must reproduce the above copyright
    1.15 + * notice, this list of conditions and the following disclaimer in the
    1.16 + * documentation and/or other materials provided with the distribution.
    1.17 + * 
    1.18 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    1.19 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    1.20 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    1.21 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    1.22 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    1.23 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    1.24 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    1.25 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    1.26 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    1.27 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
    1.28 + *
    1.29 + * cline.c
    1.30 + *
    1.31 + *  Created on: 23.05.2011
    1.32 + *      Author: Mike
    1.33 + */
    1.34 +
    1.35 +#include "cline.h"
    1.36 +#include "scanner.h"
    1.37 +#include "settings.h"
    1.38 +#include "arguments.h"
    1.39 +#include "stream.h"
    1.40 +#include "regex_parser.h"
    1.41 +
    1.42 +void printHelpText() {
    1.43 +  printf(
    1.44 +    "\nUsage:"
    1.45 +    "\n      cline [Options] [Directories...]"
    1.46 +    "\n      cline [Options] [Directories...]"
    1.47 +    "\n\nCounts the line terminator characters (\\n) within all"
    1.48 +    " files in the specified\ndirectories."
    1.49 +    "\n\nOptions:"
    1.50 +    "\n  -b <level>          - binary file heuristics level (default medium)"
    1.51 +    "\n                        One of: ignore low medium high"
    1.52 +    "\n  -E <pattern>        - Excludes any line matching the <pattern>"
    1.53 +    "\n  -e <start> <end>    - Excludes lines between <start> and <end>"
    1.54 +    "\n                        You may use these options multiple times"
    1.55 +    "\n  -h, --help          - this help text"
    1.56 +    "\n  -m                  - print information about matching files only"
    1.57 +    "\n  -s <suffixes>       - only count files with these suffixes (separated"
    1.58 +    "\n                        by commas)"
    1.59 +    "\n  -S <suffixes>       - count any file except those with these suffixes"
    1.60 +    "\n                        (separated by commas)"
    1.61 +    "\n  -r, -R              - includes subdirectories"
    1.62 +    "\n  -v, --version       - print out version information"
    1.63 +    "\n  -V                  - turn verbose output off, print the result only"
    1.64 +    "\n\nShortcuts:"
    1.65 +    "\n  --exclude-cstyle-comments"
    1.66 +    "\n = -E \"\\s*//\" -e \"\\s*/\\*\" \"\\*/\\s*\""
    1.67 +    "\n\n"
    1.68 +    "The default call without any options is:"    
    1.69 +    "\n  cline ./\n\n"
    1.70 +    "So each file in the working directory is counted. If you want to count C"
    1.71 +    "\nsource code in your working directory and its subdirectories, type:"
    1.72 +    "\n  cline -rs .c\n"
    1.73 +    "\nIf you want to exclude comment lines, you may use the -e/-E option."
    1.74 +    "\nAfter a line matches the regex pattern <start> any following line is"
    1.75 +    "\nnot counted unless a line matches the <end> pattern. A line is still "
    1.76 +    "\ncounted when it does not start or end with the respective patterns."
    1.77 +    "\nPlease note, that cline does not remove whitespace characters as this"
    1.78 +    "\nmight not be reasonable in some cases."
    1.79 +    "\n\nExample (C without comments):"
    1.80 +    "\n  cline -s .c,.h --exclude-cstyle-comments");
    1.81 +}
    1.82 +
    1.83 +int exit_with_version(settings_t* settings) {
    1.84 +  printf("cline - Revision: %s\n", VERSION);
    1.85 +  destroy_settings_t(settings);
    1.86 +  return 0;
    1.87 +}
    1.88 +
    1.89 +int exit_with_help(settings_t* settings, int code) {
    1.90 +  printHelpText();
    1.91 +  destroy_settings_t(settings);
    1.92 +  return code;
    1.93 +}
    1.94 +
    1.95 +int main(int argc, char** argv) {
    1.96 +
    1.97 +  /* Settings */
    1.98 +  settings_t *settings = new_settings_t();
    1.99 +  if (settings == NULL) {
   1.100 +    fprintf(stderr, "Memory allocation failed.\n");
   1.101 +    return 1;
   1.102 +  }
   1.103 +
   1.104 +  /* Get arguments */
   1.105 +  string_list_t *directories = new_string_list_t();
   1.106 +  if (directories == NULL) {
   1.107 +    fprintf(stderr, "Memory allocation failed.\n");
   1.108 +    return 1;
   1.109 +  }
   1.110 +  char* includeSuffix = NULL;
   1.111 +  char* excludeSuffix = NULL;
   1.112 +  int checked = 0;
   1.113 +
   1.114 +  for (int t = 1 ; t < argc ; t++) {
   1.115 +
   1.116 +    int argflags = checkArgument(argv[t], "hsSrRmvVbeE");
   1.117 +    int paropt = 0;
   1.118 +
   1.119 +    /* s */
   1.120 +    if ((argflags & 2) > 0) {
   1.121 +      if (!checkParamOpt(&paropt) || registerArgument(&checked, 2)) {
   1.122 +        return exit_with_help(settings, 1);
   1.123 +      }
   1.124 +      t++;
   1.125 +      if (t >= argc) {
   1.126 +        return exit_with_help(settings, 1);
   1.127 +      }
   1.128 +      includeSuffix = argv[t];
   1.129 +    }
   1.130 +    /* S */
   1.131 +    if ((argflags & 4) > 0) {
   1.132 +      if (!checkParamOpt(&paropt) || registerArgument(&checked, 4)) {
   1.133 +        return exit_with_help(settings, 1);
   1.134 +      }
   1.135 +      t++;
   1.136 +      if (t >= argc) {
   1.137 +        return exit_with_help(settings, 1);
   1.138 +      }
   1.139 +      excludeSuffix = argv[t];
   1.140 +    }
   1.141 +    /* h */
   1.142 +    if ((argflags & 1) > 0 || strcmp(argv[t], "--help") == 0) {
   1.143 +      return exit_with_help(settings, 0);
   1.144 +    }
   1.145 +    /* r, R */
   1.146 +    if ((argflags & 24) > 0) {
   1.147 +      if (registerArgument(&checked, 24)) {
   1.148 +        return exit_with_help(settings, 1);
   1.149 +      }
   1.150 +      settings->recursive = true;
   1.151 +    }
   1.152 +    /* m */
   1.153 +    if ((argflags & 32) > 0) {
   1.154 +      if (registerArgument(&checked, 32)) {
   1.155 +        return exit_with_help(settings, 1);
   1.156 +      }
   1.157 +      settings->matchesOnly = true;
   1.158 +    }
   1.159 +    /* v */
   1.160 +    if ((argflags & 64) > 0 || strcmp(argv[t], "--version") == 0) {
   1.161 +      return exit_with_version(settings);
   1.162 +    }
   1.163 +    /* V */
   1.164 +    if ((argflags & 128) > 0) {
   1.165 +      if (registerArgument(&checked, 128)) {
   1.166 +        return exit_with_help(settings, 1);
   1.167 +      }
   1.168 +      settings->verbose = false;
   1.169 +    }
   1.170 +    /* b */
   1.171 +    if ((argflags & 256) > 0) {
   1.172 +      if (!checkParamOpt(&paropt) || registerArgument(&checked, 256)) {
   1.173 +        return exit_with_help(settings, 1);
   1.174 +      }
   1.175 +      t++;
   1.176 +      if (t >= argc) {
   1.177 +        return exit_with_help(settings, 1);
   1.178 +      }
   1.179 +      if (strcasecmp(argv[t], "ignore") == 0) {
   1.180 +        settings->bfileHeuristics->level = BFILE_IGNORE;
   1.181 +      } else if (strcasecmp(argv[t], "low") == 0) {
   1.182 +        settings->bfileHeuristics->level = BFILE_LOW_ACCURACY;
   1.183 +      } else if (strcasecmp(argv[t], "medium") == 0) {
   1.184 +        settings->bfileHeuristics->level = BFILE_MEDIUM_ACCURACY;
   1.185 +      } else if (strcasecmp(argv[t], "high") == 0) {
   1.186 +        settings->bfileHeuristics->level = BFILE_HIGH_ACCURACY;
   1.187 +      } else {
   1.188 +        return exit_with_help(settings, 1);
   1.189 +      }
   1.190 +    }
   1.191 +    /* e */
   1.192 +    if ((argflags & 512) > 0) {
   1.193 +      if (!checkParamOpt(&paropt) || t + 2 >= argc) {
   1.194 +        return exit_with_help(settings, 1);
   1.195 +      }
   1.196 +      t++; add_string(settings->regex->pattern_list, argv[t]);
   1.197 +      t++; add_string(settings->regex->pattern_list, argv[t]);
   1.198 +    }
   1.199 +    /* E */
   1.200 +    if ((argflags & 1024) > 0) {
   1.201 +      t++;
   1.202 +      if (!checkParamOpt(&paropt) || t >= argc) {
   1.203 +        return exit_with_help(settings, 1);
   1.204 +      }
   1.205 +      add_string(settings->regex->pattern_list, argv[t]);
   1.206 +      add_string(settings->regex->pattern_list, "$");
   1.207 +    }
   1.208 +    if (argflags == 0) {
   1.209 +      /* SHORTCUTS */
   1.210 +      /* exclude-cstyle-comments */
   1.211 +      if (strcmp(argv[t], "--exclude-cstyle-comments") == 0) {
   1.212 +        add_string(settings->regex->pattern_list, "\\s*//");
   1.213 +        add_string(settings->regex->pattern_list, "$");
   1.214 +        add_string(settings->regex->pattern_list, "\\s*/\\*");
   1.215 +        add_string(settings->regex->pattern_list, "\\*/\\s*");
   1.216 +      }
   1.217 +      /* Path */
   1.218 +      else {
   1.219 +        add_string(directories, argv[t]);
   1.220 +      }
   1.221 +    }
   1.222 +  }
   1.223 +
   1.224 +  /* Configure output */
   1.225 +  if (!settings->verbose) {
   1.226 +    close_stdout();
   1.227 +  }
   1.228 +
   1.229 +  /* Find tokens */
   1.230 +  parseCSL(includeSuffix, settings->includeSuffixes);
   1.231 +  parseCSL(excludeSuffix, settings->excludeSuffixes);
   1.232 +
   1.233 +  /* Scan directories */
   1.234 +  if (regex_compile_all(settings->regex)) {
   1.235 +    int lines = 0;
   1.236 +    if (directories->count == 0) {
   1.237 +        add_string(directories, ".");
   1.238 +    }
   1.239 +    for (int t = 0 ; t < directories->count ; t++) {
   1.240 +      if (t > 0) {
   1.241 +          for (int u = 0 ; u < 79 ; u++) {
   1.242 +              printf("-");
   1.243 +          }
   1.244 +          printf("\n");
   1.245 +      }
   1.246 +      lines += scanDirectory((scanner_t){directories->items[t], 0}, settings);
   1.247 +    }
   1.248 +    destroy_string_list_t(directories);
   1.249 +
   1.250 +    /* Print double line and line count */
   1.251 +    for (int t = 0 ; t < 79 ; t++) {
   1.252 +      printf("=");
   1.253 +    }
   1.254 +    printf("\n%73d lines\n", lines);
   1.255 +
   1.256 +    if (settings->confusing_lnlen && settings->regex->pattern_list->count > 0) {
   1.257 +      printf("\nSome files contain too long lines.\n"
   1.258 +        "The regex parser currently supports a maximum line length of %d."
   1.259 +        "\nThe result might be wrong.\n", REGEX_MAX_LINELENGTH);
   1.260 +    }
   1.261 +
   1.262 +    if (!settings->verbose) {
   1.263 +      reopen_stdout();
   1.264 +      printf("%d", lines);
   1.265 +    }
   1.266 +    destroy_settings_t(settings);
   1.267 +  }
   1.268 +
   1.269 +  fflush(stdout);
   1.270 +  fflush(stderr);
   1.271 +  return 0;
   1.272 +}

mercurial