Below is my attempt at the logfind project from exercise number 26. It seems to be working, but I’m wondering if there’s any way to make it smaller or more efficient… I’d really appreciate any suggestions.
The other problem is that Valgrind says there are two memory leaks, but I’m pretty sure I freed everything. Any ideas where this is occurring?
==16550== Memcheck, a memory error detector
==16550== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16550== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==16550== Command: ./logfind felix
==16550==
[/etc/testlogs/logwithfelix.log] [010101] Felix is terrible
[/etc/testlogs/logwithfelix.log] [020202] Felix is awesome
==16550==
==16550== HEAP SUMMARY:
==16550== in use at exit: 134 bytes in 3 blocks
==16550== total heap usage: 16 allocs, 13 frees, 48,030 bytes allocated
==16550==
==16550== 21 bytes in 1 blocks are definitely lost in loss record 1 of 2
==16550== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16550== by 0x108E8D: get_file (logfind.c:32)
==16550== by 0x1093E1: main (logfind.c:125)
==16550==
==16550== 113 bytes in 2 blocks are definitely lost in loss record 2 of 2
==16550== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16550== by 0x108E8D: get_file (logfind.c:32)
==16550== by 0x109079: do_finding (logfind.c:68)
==16550== by 0x109308: do_globbing (logfind.c:113)
==16550== by 0x1093FC: main (logfind.c:127)
==16550==
==16550== LEAK SUMMARY:
==16550== definitely lost: 134 bytes in 3 blocks
==16550== indirectly lost: 0 bytes in 0 blocks
==16550== possibly lost: 0 bytes in 0 blocks
==16550== still reachable: 0 bytes in 0 blocks
==16550== suppressed: 0 bytes in 0 blocks
==16550==
==16550== For counts of detected and suppressed errors, rerun with: -v
==16550== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
#define _GNU_SOURCE // Needed to get strcasestr()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <glob.h>
#include "dbg.h"
#define HOME "/home/felix"
int is_empty(const char *string) {
int i = 0;
for (i = 0; i < strlen(string); i++) {
if (!isspace(string[i])) return 0;
}
return 1;
}
char *get_file(char *location) {
if (is_empty(location)) return "";
FILE *file = fopen(location, "rb");
check(file, "The file %s couldn't be opened", location);
fseek(file, 0, SEEK_END);
long size = ftell(file); // Get size of memory needed to store file content
rewind(file);
char *content = malloc(size + 1); // Allocate memory for file content
check_mem(content);
fread(content, size, 1, file); // Read file into memory buffer
fclose(file);
content[size] = '\0';
return content;
error:
exit(1);
}
int has_and_or(char *string, int argc, char *argv[]) {
int i = 0;
int found = -1;
int or = 0;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-o") == 0) {
or = 1;
continue;
}
int found_this_time = strcasestr(string, argv[i]) ? 1 : 0;
if (or) {
found = found == -1 ? 0 : found;
found = found || found_this_time;
} else {
found = found == -1 ? 1 : found;
found = found && found_this_time;
}
}
return found;
}
void do_finding(char *file, int argc, char *argv[]) {
char *logs = get_file(file);
char *line;
while ((line = strsep(&logs, "\n"))) {
if (is_empty(line)) continue;
if (has_and_or(line, argc, argv)) {
printf("[");
printf("\x1B[31m"); // Color red
printf("%s", file);
printf("\x1B[0m"); // Color normal
printf("] ");
printf("%s\n", line);
}
}
free(logs);
}
char *clean_glob_err(int rc) {
switch(rc) {
case GLOB_ABORTED:
return "Filesystem problem";
case GLOB_NOMATCH:
return "No matches";
case GLOB_NOSPACE:
return "Out of memory";
default:
return "Unknown error";
}
}
int glob_warn(const char *path, int _) {
log_warn("Trouble with glob: %s", path);
return 0;
}
void do_globbing(char *glob_in, int argc, char *argv[]) {
if (is_empty(glob_in)) return;
glob_t results;
int i = 0;
int rc = glob(glob_in, 0, glob_warn, &results);
check(rc == 0, "Bad glob: %s (%s)", glob_in, clean_glob_err(rc));
for (i = 0; i < results.gl_pathc; i++) {
do_finding(results.gl_pathv[i], argc, argv);
}
globfree(&results);
error:
globfree(&results); // Free the glob results
return;
}
int main(int argc, char *argv[]) {
check(argc >= 2, "You must specify at least one search term");
char *config = get_file(HOME "/.logfind");
char *glob_in;
while ((glob_in = strsep(&config, "\n"))) do_globbing(glob_in, argc, argv);
free(config);
return 0;
error:
if (config) free(config);
return 1;
}