src/cline.c

Wed, 22 May 2013 13:00:36 +0200

author
Mike Becker <universe@uap-core.de>
date
Wed, 22 May 2013 13:00:36 +0200
changeset 44
9574a181ec26
parent 36
a7ff583e153f
child 48
0d2c13c24fd0
permissions
-rw-r--r--

line sum per directory now displayed + directories without matching files are no longer displayed when -m is used + new buffering strategy replaces stream hack when -V is used

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 
     3  * Copyright 2013 Mike Becker. All rights reserved.
     4  * 
     5  * Redistribution and use in source and binary forms, with or without
     6  * modification, are permitted provided that the following conditions are met:
     7  * 
     8  * 1. Redistributions of source code must retain the above copyright
     9  * notice, this list of conditions and the following disclaimer.
    10  * 
    11  * 2. Redistributions in binary form must reproduce the above copyright
    12  * notice, this list of conditions and the following disclaimer in the
    13  * documentation and/or other materials provided with the distribution.
    14  * 
    15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    22  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
    25  *
    26  * cline.c
    27  *
    28  *  Created on: 23.05.2011
    29  *      Author: Mike
    30  */
    32 #include "cline.h"
    33 #include "scanner.h"
    34 #include "settings.h"
    35 #include "arguments.h"
    36 #include "regex_parser.h"
    38 void printHelpText() {
    39   printf(
    40     "\nUsage:"
    41     "\n      cline [Options] [Directories...]"
    42     "\n      cline [Options] [Directories...]"
    43     "\n\nCounts the line terminator characters (\\n) within all"
    44     " files in the specified\ndirectories."
    45     "\n\nOptions:"
    46     "\n  -b <level>          - binary file heuristics level (default medium)"
    47     "\n                        One of: ignore low medium high"
    48     "\n  -E <pattern>        - Excludes any line matching the <pattern>"
    49     "\n  -e <start> <end>    - Excludes lines between <start> and <end>"
    50     "\n                        You may use these options multiple times"
    51     "\n  -h, --help          - this help text"
    52     "\n  -m                  - print information about matching files only"
    53     "\n  -s <suffixes>       - only count files with these suffixes (separated"
    54     "\n                        by commas)"
    55     "\n  -S <suffixes>       - count any file except those with these suffixes"
    56     "\n                        (separated by commas)"
    57     "\n  -r, -R              - includes subdirectories"
    58     "\n  -v, --version       - print out version information"
    59     "\n  -V                  - turn verbose output off, print the result only"
    60     "\n\nShortcuts:"
    61     "\n  --exclude-cstyle-comments"
    62     "\n = -E \"\\s*//\" -e \"\\s*/\\*\" \"\\*/\\s*\""
    63     "\n\n"
    64     "The default call without any options is:"    
    65     "\n  cline ./\n\n"
    66     "So each file in the working directory is counted. If you want to count C"
    67     "\nsource code in your working directory and its subdirectories, type:"
    68     "\n  cline -rs .c\n"
    69     "\nIf you want to exclude comment lines, you may use the -e/-E option."
    70     "\nAfter a line matches the regex pattern <start> any following line is"
    71     "\nnot counted unless a line matches the <end> pattern. A line is still "
    72     "\ncounted when it does not start or end with the respective patterns."
    73     "\nPlease note, that cline does not remove whitespace characters as this"
    74     "\nmight not be reasonable in some cases."
    75     "\n\nExample (C without comments):"
    76     "\n  cline -s .c,.h --exclude-cstyle-comments"
    77     "\n");
    78 }
    80 int exit_with_version(settings_t* settings) {
    81   printf("cline - Version: %s\n", VERSION);
    82   destroy_settings_t(settings);
    83   return 0;
    84 }
    86 int exit_with_help(settings_t* settings, int code) {
    87   printHelpText();
    88   destroy_settings_t(settings);
    89   return code;
    90 }
    92 int main(int argc, char** argv) {
    94   /* Settings */
    95   settings_t *settings = new_settings_t();
    96   if (settings == NULL) {
    97     fprintf(stderr, "Memory allocation failed.\n");
    98     return 1;
    99   }
   101   /* Get arguments */
   102   string_list_t *directories = new_string_list_t();
   103   if (directories == NULL) {
   104     fprintf(stderr, "Memory allocation failed.\n");
   105     return 1;
   106   }
   107   char* includeSuffix = NULL;
   108   char* excludeSuffix = NULL;
   109   int checked = 0;
   111   for (int t = 1 ; t < argc ; t++) {
   113     int argflags = checkArgument(argv[t], "hsSrRmvVbeE");
   114     int paropt = 0;
   116     /* s */
   117     if ((argflags & 2) > 0) {
   118       if (!checkParamOpt(&paropt) || registerArgument(&checked, 2)) {
   119         return exit_with_help(settings, 1);
   120       }
   121       t++;
   122       if (t >= argc) {
   123         return exit_with_help(settings, 1);
   124       }
   125       includeSuffix = argv[t];
   126     }
   127     /* S */
   128     if ((argflags & 4) > 0) {
   129       if (!checkParamOpt(&paropt) || registerArgument(&checked, 4)) {
   130         return exit_with_help(settings, 1);
   131       }
   132       t++;
   133       if (t >= argc) {
   134         return exit_with_help(settings, 1);
   135       }
   136       excludeSuffix = argv[t];
   137     }
   138     /* h */
   139     if ((argflags & 1) > 0 || strcmp(argv[t], "--help") == 0) {
   140       return exit_with_help(settings, 0);
   141     }
   142     /* r, R */
   143     if ((argflags & 24) > 0) {
   144       if (registerArgument(&checked, 24)) {
   145         return exit_with_help(settings, 1);
   146       }
   147       settings->recursive = true;
   148     }
   149     /* m */
   150     if ((argflags & 32) > 0) {
   151       if (registerArgument(&checked, 32)) {
   152         return exit_with_help(settings, 1);
   153       }
   154       settings->matchesOnly = true;
   155     }
   156     /* v */
   157     if ((argflags & 64) > 0 || strcmp(argv[t], "--version") == 0) {
   158       return exit_with_version(settings);
   159     }
   160     /* V */
   161     if ((argflags & 128) > 0) {
   162       if (registerArgument(&checked, 128)) {
   163         return exit_with_help(settings, 1);
   164       }
   165       settings->verbose = false;
   166     }
   167     /* b */
   168     if ((argflags & 256) > 0) {
   169       if (!checkParamOpt(&paropt) || registerArgument(&checked, 256)) {
   170         return exit_with_help(settings, 1);
   171       }
   172       t++;
   173       if (t >= argc) {
   174         return exit_with_help(settings, 1);
   175       }
   176       if (strcasecmp(argv[t], "ignore") == 0) {
   177         settings->bfileHeuristics->level = BFILE_IGNORE;
   178       } else if (strcasecmp(argv[t], "low") == 0) {
   179         settings->bfileHeuristics->level = BFILE_LOW_ACCURACY;
   180       } else if (strcasecmp(argv[t], "medium") == 0) {
   181         settings->bfileHeuristics->level = BFILE_MEDIUM_ACCURACY;
   182       } else if (strcasecmp(argv[t], "high") == 0) {
   183         settings->bfileHeuristics->level = BFILE_HIGH_ACCURACY;
   184       } else {
   185         return exit_with_help(settings, 1);
   186       }
   187     }
   188     /* e */
   189     if ((argflags & 512) > 0) {
   190       if (!checkParamOpt(&paropt) || t + 2 >= argc) {
   191         return exit_with_help(settings, 1);
   192       }
   193       t++; add_string(settings->regex->pattern_list, argv[t]);
   194       t++; add_string(settings->regex->pattern_list, argv[t]);
   195     }
   196     /* E */
   197     if ((argflags & 1024) > 0) {
   198       t++;
   199       if (!checkParamOpt(&paropt) || t >= argc) {
   200         return exit_with_help(settings, 1);
   201       }
   202       add_string(settings->regex->pattern_list, argv[t]);
   203       add_string(settings->regex->pattern_list, "$");
   204     }
   205     if (argflags == 0) {
   206       /* SHORTCUTS */
   207       /* exclude-cstyle-comments */
   208       if (strcmp(argv[t], "--exclude-cstyle-comments") == 0) {
   209         add_string(settings->regex->pattern_list, "\\s*//");
   210         add_string(settings->regex->pattern_list, "$");
   211         add_string(settings->regex->pattern_list, "\\s*/\\*");
   212         add_string(settings->regex->pattern_list, "\\*/\\s*");
   213       }
   214       /* Path */
   215       else {
   216         add_string(directories, argv[t]);
   217       }
   218     }
   219   }
   221   /* Find tokens */
   222   parseCSL(includeSuffix, settings->includeSuffixes);
   223   parseCSL(excludeSuffix, settings->excludeSuffixes);
   225   /* Scan directories */
   226   if (regex_compile_all(settings->regex)) {
   227     /* Don't waste memory when only the total sum is needed */
   228     string_list_t *output = settings->verbose ? new_string_list_t() : NULL;
   229     char *outbuf;
   231     int lineSum = 0, lines;
   232     if (directories->count == 0) {
   233         add_string(directories, ".");
   234     }
   235     for (int t = 0 ; t < directories->count ; t++) {
   236       lines = scanDirectory((scanner_t){directories->items[t], 0}, settings,
   237           output);
   238       lineSum += lines;
   239       if (directories->count > 1 ) {
   240         outbuf = (char*) malloc(81);
   241         memset(outbuf, '-', 79);
   242         outbuf[79] = '\n';
   243         outbuf[80] = 0;
   244         add_string(output, outbuf);
   245         outbuf = (char*) malloc(81);
   246         snprintf(outbuf, 81, "%-63s%10d lines\n", directories->items[t], lines);
   247         add_string(output, outbuf);
   248         outbuf = (char*) malloc(81);
   249         memset(outbuf, '-', 79);
   250         outbuf[79] = '\n';
   251         outbuf[80] = 0;
   252         add_string(output, outbuf);
   253       }
   254     }
   255     destroy_string_list_t(directories);
   257     /* Print result */
   258     if (settings->verbose) {
   259       for (int i = 0 ; i < output->count ; i++) {
   260         printf("%s", output->items[i]);
   261         free(output->items[i]);
   262       }
   264       for (int t = 0 ; t < 79 ; t++) {
   265         printf("=");
   266       }
   267       printf("\n%73d lines\n", lineSum);
   269       if (settings->confusing_lnlen &&
   270           settings->regex->pattern_list->count > 0) {
   272         printf("\nSome files contain too long lines.\n"
   273           "The regex parser currently supports a maximum line length of %d."
   274           "\nThe result might be wrong.\n", REGEX_MAX_LINELENGTH);
   275       }
   276     } else {
   277       printf("%d", lineSum);
   278     }
   279     destroy_string_list_t(output);
   280     destroy_settings_t(settings);
   281   }
   283   fflush(stdout);
   284   fflush(stderr);
   285   return 0;
   286 }

mercurial