universe@10: /* universe@34: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. universe@48: * Copyright 2017 Mike Becker. All rights reserved. universe@34: * universe@34: * Redistribution and use in source and binary forms, with or without universe@34: * modification, are permitted provided that the following conditions are met: universe@34: * universe@34: * 1. Redistributions of source code must retain the above copyright universe@34: * notice, this list of conditions and the following disclaimer. universe@34: * universe@34: * 2. Redistributions in binary form must reproduce the above copyright universe@34: * notice, this list of conditions and the following disclaimer in the universe@34: * documentation and/or other materials provided with the distribution. universe@34: * universe@34: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" universe@34: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE universe@34: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE universe@34: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE universe@34: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL universe@34: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR universe@34: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER universe@34: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, universe@34: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE universe@34: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. universe@34: * universe@20: * scanner.c universe@10: * universe@10: * Created on: 23.05.2011 universe@20: * Author: Mike universe@10: */ universe@1: universe@1: universe@10: #include "scanner.h" universe@10: #include "suffix_fnc.h" universe@21: #include "bfile_heuristics.h" universe@27: #include "regex_parser.h" universe@23: #include universe@3: universe@41: typedef struct filelist filelist_t; universe@23: universe@41: struct filelist { universe@41: char *displayname; universe@41: int displayname_len; universe@41: char *filename; universe@41: int st_mode; universe@41: filelist_t *next; universe@41: }; universe@41: universe@41: filelist_t *buildFileList(scanner_t scanner, settings_t* settings, universe@41: filelist_t* list) { universe@41: universe@23: DIR *dirf; universe@3: struct dirent *entry; universe@23: struct stat statbuf; universe@41: universe@23: if ((dirf = opendir(scanner.dir)) == NULL) { universe@34: printf("%s", scanner.dir); universe@23: perror(" Directory access failed"); universe@23: return 0; universe@23: } universe@23: universe@23: while ((entry = readdir(dirf)) != NULL) { universe@3: if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { universe@41: universe@41: /* Create new filelist entry */ universe@41: filelist_t *newentry = (filelist_t*) malloc(sizeof(filelist_t)); universe@42: newentry->next = NULL; universe@41: universe@42: newentry->displayname_len = strlen(entry->d_name); universe@42: newentry->displayname = (char*) malloc(newentry->displayname_len+1); universe@42: memcpy(newentry->displayname, entry->d_name, newentry->displayname_len); universe@42: newentry->displayname[newentry->displayname_len] = 0; universe@41: universe@42: newentry->st_mode = 0; universe@41: universe@40: /* Construct absolute pathname string */ universe@41: size_t dirnamelen = strlen(scanner.dir); universe@42: char *filename = (char*) malloc(2+dirnamelen+newentry->displayname_len); universe@41: memcpy(filename, scanner.dir, dirnamelen); universe@41: filename[dirnamelen] = settings->fileSeparator; universe@42: memcpy(filename+dirnamelen+1, entry->d_name, newentry->displayname_len); universe@42: filename[1+dirnamelen+newentry->displayname_len] = 0; universe@42: newentry->filename = filename; universe@14: universe@22: /* Check for subdirectory */ universe@23: if (stat(filename, &statbuf) == 0) { universe@42: newentry->st_mode = statbuf.st_mode; universe@23: } else { universe@23: perror(" Error in stat call"); universe@3: continue; universe@3: } universe@42: universe@42: if (list) { universe@42: // create fake root to have a pointer on the true root universe@42: filelist_t root; universe@42: root.next = list; universe@42: filelist_t *parent = &root; universe@42: while (parent->next && universe@42: (strcasecmp(parent->next->displayname, newentry->displayname) < 0 || universe@42: (!S_ISDIR(newentry->st_mode) && S_ISDIR(parent->next->st_mode)) universe@42: ) && universe@42: (!S_ISDIR(newentry->st_mode) || S_ISDIR(parent->next->st_mode)) universe@42: ) { universe@42: parent = parent->next; universe@42: } universe@42: newentry->next = parent->next; universe@42: parent->next = newentry; universe@42: list = root.next; universe@42: } else { universe@42: list = newentry; universe@42: } universe@41: } universe@41: } universe@41: universe@41: closedir(dirf); universe@41: universe@41: return list; universe@41: } universe@3: universe@44: int scanDirectory(scanner_t scanner, settings_t* settings, universe@44: string_list_t* output) { universe@41: universe@41: int lines, a; universe@41: int lineSum = 0; universe@41: bool bfile; universe@44: char *outbuf; universe@41: universe@41: filelist_t *filelist = buildFileList(scanner, settings, NULL); universe@41: universe@41: while (filelist != NULL) { universe@41: universe@41: /* Scan subdirectories */ universe@42: if (!S_ISREG(filelist->st_mode)) { universe@44: if (settings->recursive && S_ISDIR(filelist->st_mode)) { universe@44: string_list_t *recoutput = new_string_list_t(); universe@44: lines = scanDirectory( universe@44: (scanner_t) {filelist->filename, scanner.spaces+1}, universe@44: settings, recoutput); universe@44: lineSum += lines; universe@44: if (!settings->matchesOnly || recoutput->count > 0) { universe@44: outbuf = (char*) malloc(81); universe@44: snprintf(outbuf, 81, "%*s/%*s%13d lines\n", universe@44: filelist->displayname_len+scanner.spaces, filelist->displayname, universe@44: 60-filelist->displayname_len-scanner.spaces-1, "", lines); universe@44: add_string(output, outbuf); universe@44: for (int i = 0 ; i < recoutput->count ; i++) { universe@44: add_string(output, recoutput->items[i]); universe@44: } universe@44: } universe@44: destroy_string_list_t(recoutput); universe@44: } else { universe@44: outbuf = (char*) malloc(81); universe@44: snprintf(outbuf, 81, "%*s\n", filelist->displayname_len+scanner.spaces, universe@41: filelist->displayname); universe@44: add_string(output, outbuf); universe@41: } universe@41: } else { universe@30: if ((settings->includeSuffixes->count == 0 universe@41: || testSuffix(filelist->displayname, settings->includeSuffixes)) universe@41: && !testSuffix(filelist->displayname, settings->excludeSuffixes)) { universe@41: universe@25: /* Count lines */ universe@25: lines = 0; universe@25: bfile = false; universe@25: bfile_reset(settings->bfileHeuristics); universe@27: char line_buffer[REGEX_MAX_LINELENGTH]; universe@25: int line_buffer_offset = 0; universe@25: universe@41: FILE *file = fopen(filelist->filename, "r"); universe@3: if (file == NULL) { universe@44: outbuf = (char*) malloc(81); universe@44: snprintf(outbuf, 81, "%*s", filelist->displayname_len+scanner.spaces, universe@41: filelist->displayname); universe@44: add_string(output, outbuf); universe@3: perror(" File acces failed"); universe@41: } else { universe@41: do { universe@41: a = fgetc(file); universe@3: universe@41: bfile = bfile_check(settings->bfileHeuristics, a); universe@3: universe@41: if (a == 10 || a == EOF) { universe@41: line_buffer[line_buffer_offset] = 0; universe@41: if (regex_parser_do(settings->regex, line_buffer) == 0) { universe@41: /* Only subtract lines when matching has finished */ universe@41: if (!regex_parser_matching(settings->regex)) { universe@41: lines -= settings->regex->matched_lines; universe@41: } universe@41: } universe@21: universe@41: line_buffer_offset = 0; universe@41: lines++; universe@41: } else { universe@41: if (line_buffer_offset < REGEX_MAX_LINELENGTH) { universe@41: line_buffer[line_buffer_offset] = a; universe@41: line_buffer_offset++; universe@41: } else { universe@41: line_buffer[line_buffer_offset-1] = 0; universe@41: settings->confusing_lnlen = true; universe@28: } universe@28: } universe@41: } while (!bfile && a != EOF); universe@41: fclose(file); universe@25: universe@41: /* Print and sum line count */ universe@41: if (bfile) { universe@41: if (!settings->matchesOnly) { universe@44: outbuf = (char*) malloc(81); universe@44: snprintf(outbuf, 81, universe@44: "%*s%*s%19s\n", filelist->displayname_len+scanner.spaces, universe@41: filelist->displayname, universe@41: 60-filelist->displayname_len-scanner.spaces, "", "binary"); universe@44: add_string(output, outbuf); universe@41: } universe@25: } else { universe@41: lineSum += lines; universe@44: outbuf = (char*) malloc(81); universe@44: snprintf(outbuf, 81, "%*s%*s%13d lines\n", universe@41: filelist->displayname_len+scanner.spaces, filelist->displayname, universe@41: 60-filelist->displayname_len-scanner.spaces, "", lines); universe@44: add_string(output, outbuf); universe@3: } universe@21: } universe@16: } else { universe@3: if (!settings->matchesOnly) { universe@22: /* Print hint */ universe@44: outbuf = (char*) malloc(81); universe@44: snprintf(outbuf, 81, "%*s%*s%19s\n", universe@41: filelist->displayname_len+scanner.spaces, filelist->displayname, universe@41: 60-filelist->displayname_len-scanner.spaces, "", "no match"); universe@44: add_string(output, outbuf); universe@3: } universe@3: } universe@3: } universe@41: universe@41: free(filelist->filename); universe@41: free(filelist->displayname); universe@41: filelist_t *freethis = filelist; universe@41: filelist = filelist->next; universe@41: free(freethis); universe@3: } universe@23: universe@3: return lineSum; universe@3: }