/* * Programmieraufgabe vom 18Jul22 (T03) * https://sys.cs.fau.de/extern/lehre/ss22/sp1/pruefung/klausuren/2021w-GSP-Klausur_www.pdf */ #include #include #include #include #include #include #include #include #include #include #include #define MAXTHREAD 8 typedef struct sem SEM; struct fileinfo { char *path; unsigned print, line; int valid; }; /* * @brief Prints error message based on ‘errno‘ and terminates the * process. @param msg Part of the error message */ static void die(const char *const msg); /* * @brief Prints short usage and and exits indicating an error */ static void exit_usage(void); /* * @brief Creates a new semaphore. @param initVal The initial value of the * semaphore. @return Hanlde for the created sempahore, or NULL if an * error occured. */ SEM *semCreate(initVal); /* * @brief Destroys a semaphore and frees all associated ressources. @param * sem Handle of the semaphore to destroy. */ void semDestroy(SEM * sem); /* * @brief P-operation @param sem Handle of the semaphore to decrement */ P(SEM * sem); /* * @brief V-operation @param sem Handle of the semaphore to increment */ V(SEM * sem); // Vorausdeklarationen static int compare(const void *a, const void *b); static void find_files(char *path); static void dispatch_file(char *path); static void *gather_fileinfo(void *arg); // Glob. Variablen static struct fileinfo **fileinfos; static SEM *threads; static SEM *completed; /* war nicht notwendig */ static char *pattern; static unsigned count; static int compare(const void *a, const void *b) { struct fileinfo *fa, *fb; fa = (struct fileinfo *) a; fb = (struct fileinfo *) b; return strcmp(fa->path, fb->path); } int main(int argc, char *argv[]) { // Argumente prüfen if (argc < 2) exit_usage(); // Globalen Zustand initialisieren threads = semCreate(MAXTHREAD); if (!threads) { die("semCreate"); } completed = semCreate(0); if (!completed) { die("semCreate"); } pattern = argv[1]; // Verzeichnisse durchsuchen if (argc == 2) { find_files("."); } else { for (int i = 2; i < argc; i++) { find_files(argv[i]); } } /* * MAXTHREADS-faches P(threads) fehlt -1.5P */ // Informationen sortieren und ausgeben qsort(fileinfos, count, sizeof(struct fileinfo), compare); for (unsigned i = 0; i < count; i++) { struct fileinfo *f = fileinfos[i]; if (f->valid) { if (printf("%s: %d %d\n", f->path, f->print, f->line) < 0) { die("printf"); } } /* * free(f->name) fehlt -0.5 */ /* * free(f) fehlt -0.5 */ } /* * free(fileinfos) fehlt -0.5P */ /* * semDestroy fehlt -0.5P */ if (EOF == fflush(stdout)) { die("fflush"); } } static void find_files(char *path) { // Verzeichnis öffnen DIR *dirp = opendir(path); if (!dirp) { die("opendir"); } // Einträge verarbeiten struct dirent *e; while (errno = 0, (e = readdir(dirp)) != NULL) { /* * pruefen ob . oder .. fehlt -1P */ char file[strlen(path) + 1 + strlen(e->d_name) + 1]; sprintf(file, "%s/%s", path, e->d_name); struct stat buf; if (0 != lstat(file, &buf)) { die("lstat"); /* sollte nicht fatal sein */ } if (S_ISDIR(buf.st_mode)) { find_files(file); } else if (S_ISREG(buf.st_mode)) { dispatch_file(file); } } if (errno) { die("readdir"); /* sollte nicht fatal sein */ } closedir(dirp); } static void dispatch_file(char *path) { switch (fnmatch(pattern, path, FNM_PERIOD)) { case 0: /* match */ break; case FNM_NOMATCH: /* no match */ return; default: /* error */ die("fnmatch"); } struct fileinfo *fi = malloc(sizeof(struct fileinfo)); if (!fi) { die("malloc"); } *fi = (struct fileinfo) { .path = strdup(path), }; if (!fi->path) { die("strdup"); } fileinfos = realloc(fileinfos, count + 1); /* (count + 1) * * sizeof(*fi) */ if (!fileinfos) { die("realloc"); } fileinfos[count] = fi; count += 1; P(threads); pthread_t id; if ((errno = pthread_create(&id, NULL, gather_fileinfo, fi))) { die("pthread_create"); } } static void * gather_fileinfo(void *arg) { if (!pthread_detach(pthread_self())) { die("pthread_detach"); } struct fileinfo *fi = (struct fileinfo *) arg; FILE *f = fopen(fi->path, "r"); if (!f) { /* * V(threads) fehlt -1P */ die("fopen"); /* sollte nicht fatal sein */ } int c; while (EOF != (c = fgetc(f))) { if (isprint(c)) fi->print++; if ('\n' == c) fi->line++; } if (ferror(f)) { die("fgetc"); /* sollte nicht fatal sein */ } fi->valid = !0; /* * V(threads) fehlt -1P */ /* * fclose fehlt -0.5 */ return NULL; }