From 3cb77ecf339a2658f891f372d177ce9dc9ae8369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 30 Jan 2008 10:08:48 +0000 Subject: [PATCH] * Now checks if /etc/fortunes is a directory, and picks a random file out of that. This fixes bug #1475. * Now accepts file arguments (will pick a random one out of them) as fortune sources. * Minor cleanup and simplifications. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23788 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/bin/fortune.c | 195 +++++++++++++++++++++++++++++++++------------- 1 file changed, 140 insertions(+), 55 deletions(-) diff --git a/src/bin/fortune.c b/src/bin/fortune.c index 54d1be87da..254deb71ad 100644 --- a/src/bin/fortune.c +++ b/src/bin/fortune.c @@ -1,81 +1,166 @@ /* -** Copyright 2002-2004, The OpenBeOS Team. All rights reserved. -** Distributed under the terms of the OpenBeOS License. -*/ + * Copyright 2002-2008, Haiku. All rights reserved. + * Distributed under the terms of the MIT License. + */ -#include -#include + +#include +#include +#include #include #include -#include +#include #include -#include +#include #include + #define FORTUNES "/etc/fortunes" -int -main(void) + +static int +choose_file(const char *path) { + struct dirent *dirent; + int count = 0; + int chosen; + + DIR *dir = opendir(path); + if (dir == NULL) + return -1; + + // count directory entries + + while ((dirent = readdir(dir)) != NULL) { + if (dirent->d_name[0] == '.') + continue; + + count++; + } + + // choose and open entry + + chosen = rand() % count; + count = 0; + rewinddir(dir); + + while ((dirent = readdir(dir)) != NULL) { + if (dirent->d_name[0] == '.') + continue; + + if (chosen <= count) { + char name[PATH_MAX]; + int fd; + + // build full path + strlcpy(name, path, sizeof(name)); + strlcat(name, "/", sizeof(name)); + strlcat(name, dirent->d_name, sizeof(name)); + + fd = open(name, O_RDONLY); + if (fd >= 0) { + closedir(dir); + return fd; + } + } + count++; + } + + closedir(dir); + return -1; +} + + +int +main(int argc, char **argv) +{ + char *file = FORTUNES; int fd; - int rc; - char *buf; - unsigned i; - unsigned found; + char *buffer; + unsigned start, i; + unsigned count; struct stat stat; - fd = open(FORTUNES, O_RDONLY, 0); + srand(system_time() % INT_MAX); + + if (argc > 1) { + // if there are arguments, choose one randomly + file = argv[1 + (rand() % (argc - 1))]; + } + + fd = open(file, O_RDONLY, 0); if (fd < 0) { - printf("Couldn't open %s: %s\n", FORTUNES, strerror(errno)); - return -1; + fprintf(stderr, "Couldn't open %s: %s\n", file, strerror(errno)); + return 1; } - rc = fstat(fd, &stat); - if (rc < 0) { - printf("stat() failed: %s\n", strerror(errno)); - return -1; + if (fstat(fd, &stat) < 0) { + fprintf(stderr, "stat() failed: %s\n", strerror(errno)); + return 1; } - buf = malloc(stat.st_size + 1); - rc = read(fd, buf, stat.st_size); - if (rc < 0) { - printf("Could not read from fortune file: %s\n", strerror(errno)); - return -1; - } + if (S_ISDIR(stat.st_mode)) { + close(fd); - buf[stat.st_size] = 0; - close(fd); + fd = choose_file(file); + if (fd < 0) { + fprintf(stderr, "Could not find any fortune file.\n"); + return 1; + } - found = 0; - for (i = 0; i < stat.st_size; i++) { - if (!strncmp(buf + i, "#@#", 3)) - found += 1; - } - - if (found > 0) - found = 1 + ((system_time() + 3) % found); - else { - printf("Out of cookies...\n"); - return -1; - } - - for (i = 0; i < stat.st_size; i++) { - if (!strncmp(buf + i, "#@#", 3)) - found -= 1; - - if (found == 0) { - unsigned j; - - for (j = i + 1; j < stat.st_size; j++) { - if (!strncmp(buf + j, "#@#", 3)) - buf[j] = 0; - } - - printf("%s\n", buf + i + 3); - break; + if (fstat(fd, &stat) < 0) { + fprintf(stderr, "stat() failed: %s\n", strerror(errno)); + return 1; } } + buffer = malloc(stat.st_size + 1); + if (buffer == NULL) { + fprintf(stderr, "Not enough memory.\n"); + return 1; + } + + if (read(fd, buffer, stat.st_size) < 0) { + fprintf(stderr, "Could not read from fortune file: %s\n", + strerror(errno)); + return -1; + } + + buffer[stat.st_size] = '\0'; + close(fd); + + // count fortunes + + count = 0; + for (i = 0; i < stat.st_size - 2; i++) { + if (!strncmp(buffer + i, "\n%\n", 3)) { + count++; + i += 3; + } + } + + if (!count) { + printf("Out of cookies...\n"); + return 0; + } + + count = rand() % count; + start = 0; + + // find beginning & end + for (i = 0; i < stat.st_size - 2; i++) { + if (!strncmp(buffer + i, "\n%\n", 3)) { + if (count-- <= 0) { + buffer[i] = '\0'; + break; + } + + i += 3; + start = i; + } + } + + puts(buffer + start); return 0; }