src/cline.c

Fri, 03 Jun 2022 17:51:59 +0200

author
Mike Becker <universe@uap-core.de>
date
Fri, 03 Jun 2022 17:51:59 +0200
changeset 64
21a2db0c9f63
parent 62
7f5f9f43d0c0
child 66
be2084398c37
permissions
-rw-r--r--

simplify .hgignore file

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

mercurial