src/cline.c

Thu, 23 Aug 2018 19:45:36 +0200

author
Mike Becker <universe@uap-core.de>
date
Thu, 23 Aug 2018 19:45:36 +0200
changeset 57
68018eac46c3
parent 50
63477d92411d
child 59
c5409c8be36f
permissions
-rw-r--r--

adds simple tiny test suite and updates license headers

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 
     3  * Copyright 2018 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  */
    27 #include "cline.h"
    28 #include "scanner.h"
    29 #include "settings.h"
    30 #include "arguments.h"
    31 #include "regex_parser.h"
    33 void printHelpText() {
    34   printf(
    35     "\nUsage:"
    36     "\n      cline [Options] [Directories...]"
    37     "\n      cline [Options] [Directories...]"
    38     "\n\nCounts the line terminator characters (\\n) within all"
    39     " files in the specified\ndirectories."
    40     "\n\nOptions:"
    41     "\n  -b <level>          - binary file heuristics level (default medium)"
    42     "\n                        One of: ignore low medium high"
    43     "\n  -E <pattern>        - Excludes any line matching the <pattern>"
    44     "\n  -e <start> <end>    - Excludes lines between <start> and <end>"
    45     "\n                        You may use these options multiple times"
    46     "\n  -h, --help          - this help text"
    47     "\n  -m                  - print information about matching files only"
    48     "\n  -s <suffixes>       - only count files with these suffixes (separated"
    49     "\n                        by commas)"
    50     "\n  -S <suffixes>       - count any file except those with these suffixes"
    51     "\n                        (separated by commas)"
    52     "\n  -r, -R              - includes subdirectories"
    53     "\n  -v, --version       - print out version information"
    54     "\n  -V                  - turn verbose output off, print the result only"
    55     "\n\nShortcuts:"
    56     "\n  --exclude-cstyle-comments : -E '\\s*//' -e '\\s*/\\*' '\\*/\\s*'"
    57     "\n  --exclude-blank-lines     : -E '^\\s*$'"
    58     "\n\n"
    59     "The default call without any options is:"    
    60     "\n  cline ./\n\n"
    61     "So each file in the working directory is counted. If you want to count C"
    62     "\nsource code in your working directory and its subdirectories, type:"
    63     "\n  cline -rs .c\n"
    64     "\nIf you want to exclude comment lines, you may use the -e/-E option."
    65     "\nAfter a line matches the regex pattern <start> any following line is"
    66     "\nnot counted unless a line matches the <end> pattern. A line is still "
    67     "\ncounted when it does not start or end with the respective patterns."
    68     "\nPlease note, that cline does not remove whitespace characters as this"
    69     "\nmight not be reasonable in some cases."
    70     "\n\nExample (C without comments):"
    71     "\n  cline -s .c,.h --exclude-cstyle-comments"
    72     "\n");
    73 }
    75 int exit_with_version(settings_t* settings) {
    76   printf("cline - Version: " VERSION "\n");
    77   destroy_settings_t(settings);
    78   return 0;
    79 }
    81 int exit_with_help(settings_t* settings, int code) {
    82   printf("cline - Version: " VERSION "\n");
    83   printHelpText();
    84   destroy_settings_t(settings);
    85   return code;
    86 }
    88 int main(int argc, char** argv) {
    90   /* Settings */
    91   settings_t *settings = new_settings_t();
    92   if (settings == NULL) {
    93     fprintf(stderr, "Memory allocation failed.\n");
    94     return 1;
    95   }
    97   /* Get arguments */
    98   string_list_t *directories = new_string_list_t();
    99   if (directories == NULL) {
   100     fprintf(stderr, "Memory allocation failed.\n");
   101     return 1;
   102   }
   103   char* includeSuffix = NULL;
   104   char* excludeSuffix = NULL;
   105   int checked = 0;
   107   for (int t = 1 ; t < argc ; t++) {
   109     int argflags = checkArgument(argv[t], "hsSrRmvVbeE");
   110     int paropt = 0;
   112     /* s */
   113     if ((argflags & 2) > 0) {
   114       if (!checkParamOpt(&paropt) || registerArgument(&checked, 2)) {
   115         return exit_with_help(settings, 1);
   116       }
   117       t++;
   118       if (t >= argc) {
   119         return exit_with_help(settings, 1);
   120       }
   121       includeSuffix = argv[t];
   122     }
   123     /* S */
   124     if ((argflags & 4) > 0) {
   125       if (!checkParamOpt(&paropt) || registerArgument(&checked, 4)) {
   126         return exit_with_help(settings, 1);
   127       }
   128       t++;
   129       if (t >= argc) {
   130         return exit_with_help(settings, 1);
   131       }
   132       excludeSuffix = argv[t];
   133     }
   134     /* h */
   135     if ((argflags & 1) > 0 || strcmp(argv[t], "--help") == 0) {
   136       return exit_with_help(settings, 0);
   137     }
   138     /* r, R */
   139     if ((argflags & 24) > 0) {
   140       if (registerArgument(&checked, 24)) {
   141         return exit_with_help(settings, 1);
   142       }
   143       settings->recursive = true;
   144     }
   145     /* m */
   146     if ((argflags & 32) > 0) {
   147       if (registerArgument(&checked, 32)) {
   148         return exit_with_help(settings, 1);
   149       }
   150       settings->matchesOnly = true;
   151     }
   152     /* v */
   153     if ((argflags & 64) > 0 || strcmp(argv[t], "--version") == 0) {
   154       return exit_with_version(settings);
   155     }
   156     /* V */
   157     if ((argflags & 128) > 0) {
   158       if (registerArgument(&checked, 128)) {
   159         return exit_with_help(settings, 1);
   160       }
   161       settings->verbose = false;
   162     }
   163     /* b */
   164     if ((argflags & 256) > 0) {
   165       if (!checkParamOpt(&paropt) || registerArgument(&checked, 256)) {
   166         return exit_with_help(settings, 1);
   167       }
   168       t++;
   169       if (t >= argc) {
   170         return exit_with_help(settings, 1);
   171       }
   172       if (strcasecmp(argv[t], "ignore") == 0) {
   173         settings->bfileHeuristics->level = BFILE_IGNORE;
   174       } else if (strcasecmp(argv[t], "low") == 0) {
   175         settings->bfileHeuristics->level = BFILE_LOW_ACCURACY;
   176       } else if (strcasecmp(argv[t], "medium") == 0) {
   177         settings->bfileHeuristics->level = BFILE_MEDIUM_ACCURACY;
   178       } else if (strcasecmp(argv[t], "high") == 0) {
   179         settings->bfileHeuristics->level = BFILE_HIGH_ACCURACY;
   180       } else {
   181         return exit_with_help(settings, 1);
   182       }
   183     }
   184     /* e */
   185     if ((argflags & 512) > 0) {
   186       if (!checkParamOpt(&paropt) || t + 2 >= argc) {
   187         return exit_with_help(settings, 1);
   188       }
   189       t++; add_string(settings->regex->pattern_list, argv[t]);
   190       t++; add_string(settings->regex->pattern_list, argv[t]);
   191     }
   192     /* E */
   193     if ((argflags & 1024) > 0) {
   194       t++;
   195       if (!checkParamOpt(&paropt) || t >= argc) {
   196         return exit_with_help(settings, 1);
   197       }
   198       add_string(settings->regex->pattern_list, argv[t]);
   199       add_string(settings->regex->pattern_list, "$");
   200     }
   201     if (argflags == 0) {
   202       /* SHORTCUTS */
   203       if (strcmp(argv[t], "--exclude-cstyle-comments") == 0) {
   204         add_string(settings->regex->pattern_list, "\\s*//");
   205         add_string(settings->regex->pattern_list, "$");
   206         add_string(settings->regex->pattern_list, "\\s*/\\*");
   207         add_string(settings->regex->pattern_list, "\\*/\\s*");
   208       } else if (strcmp(argv[t], "--exclude-blank-lines") == 0) {
   209         add_string(settings->regex->pattern_list, "^\\s*$");
   210         add_string(settings->regex->pattern_list, "$");
   211       }
   212       /* Path */
   213       else {
   214         add_string(directories, argv[t]);
   215       }
   216     }
   217   }
   219   /* Find tokens */
   220   parseCSL(includeSuffix, settings->includeSuffixes);
   221   parseCSL(excludeSuffix, settings->excludeSuffixes);
   223   /* Scan directories */
   224   if (regex_compile_all(settings->regex)) {
   225     /* Don't waste memory when only the total sum is needed */
   226     string_list_t *output = settings->verbose ? new_string_list_t() : NULL;
   227     char *outbuf;
   229     int lineSum = 0, lines;
   230     if (directories->count == 0) {
   231         add_string(directories, ".");
   232     }
   233     for (int t = 0 ; t < directories->count ; t++) {
   234       lines = scanDirectory((scanner_t){directories->items[t], 0}, settings,
   235           output);
   236       lineSum += lines;
   237       if (directories->count > 1 ) {
   238         outbuf = (char*) malloc(81);
   239         memset(outbuf, '-', 79);
   240         outbuf[79] = '\n';
   241         outbuf[80] = 0;
   242         add_string(output, outbuf);
   243         outbuf = (char*) malloc(81);
   244         snprintf(outbuf, 81, "%-63s%10d lines\n", directories->items[t], lines);
   245         add_string(output, outbuf);
   246         outbuf = (char*) malloc(81);
   247         memset(outbuf, '-', 79);
   248         outbuf[79] = '\n';
   249         outbuf[80] = 0;
   250         add_string(output, outbuf);
   251       }
   252     }
   253     destroy_string_list_t(directories);
   255     /* Print result */
   256     if (settings->verbose) {
   257       for (int i = 0 ; i < output->count ; i++) {
   258         printf("%s", output->items[i]);
   259         free(output->items[i]);
   260       }
   262       for (int t = 0 ; t < 79 ; t++) {
   263         printf("=");
   264       }
   265       printf("\n%73d lines\n", lineSum);
   267       if (settings->confusing_lnlen &&
   268           settings->regex->pattern_list->count > 0) {
   270         printf("\nSome files contain too long lines.\n"
   271           "The regex parser currently supports a maximum line length of %d."
   272           "\nThe result might be wrong.\n", REGEX_MAX_LINELENGTH);
   273       }
   274     } else {
   275       printf("%d", lineSum);
   276     }
   277     destroy_string_list_t(output);
   278     destroy_settings_t(settings);
   279   }
   281   fflush(stdout);
   282   fflush(stderr);
   283   return 0;
   284 }

mercurial