1 /* 2 * Copyright 2002-2008, Haiku. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <dirent.h> 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <stdlib.h> 11 #include <stdio.h> 12 #include <string.h> 13 #include <sys/stat.h> 14 #include <unistd.h> 15 16 #include <OS.h> 17 18 19 #define FORTUNES "/etc/fortunes" 20 21 22 static int 23 choose_file(const char *path) 24 { 25 struct dirent *dirent; 26 int count = 0; 27 int chosen; 28 29 DIR *dir = opendir(path); 30 if (dir == NULL) 31 return -1; 32 33 // count directory entries 34 35 while ((dirent = readdir(dir)) != NULL) { 36 if (dirent->d_name[0] == '.') 37 continue; 38 39 count++; 40 } 41 42 // choose and open entry 43 44 chosen = rand() % count; 45 count = 0; 46 rewinddir(dir); 47 48 while ((dirent = readdir(dir)) != NULL) { 49 if (dirent->d_name[0] == '.') 50 continue; 51 52 if (chosen <= count) { 53 char name[PATH_MAX]; 54 int fd; 55 56 // build full path 57 strlcpy(name, path, sizeof(name)); 58 strlcat(name, "/", sizeof(name)); 59 strlcat(name, dirent->d_name, sizeof(name)); 60 61 fd = open(name, O_RDONLY); 62 if (fd >= 0) { 63 closedir(dir); 64 return fd; 65 } 66 } 67 count++; 68 } 69 70 closedir(dir); 71 return -1; 72 } 73 74 75 int 76 main(int argc, char **argv) 77 { 78 char *file = FORTUNES; 79 int fd; 80 char *buffer; 81 unsigned start, i; 82 unsigned count; 83 struct stat stat; 84 85 srand(system_time() % INT_MAX); 86 87 if (argc > 1) { 88 // if there are arguments, choose one randomly 89 file = argv[1 + (rand() % (argc - 1))]; 90 } 91 92 fd = open(file, O_RDONLY, 0); 93 if (fd < 0) { 94 fprintf(stderr, "Couldn't open %s: %s\n", file, strerror(errno)); 95 return 1; 96 } 97 98 if (fstat(fd, &stat) < 0) { 99 fprintf(stderr, "stat() failed: %s\n", strerror(errno)); 100 return 1; 101 } 102 103 if (S_ISDIR(stat.st_mode)) { 104 close(fd); 105 106 fd = choose_file(file); 107 if (fd < 0) { 108 fprintf(stderr, "Could not find any fortune file.\n"); 109 return 1; 110 } 111 112 if (fstat(fd, &stat) < 0) { 113 fprintf(stderr, "stat() failed: %s\n", strerror(errno)); 114 return 1; 115 } 116 } 117 118 buffer = malloc(stat.st_size + 1); 119 if (buffer == NULL) { 120 fprintf(stderr, "Not enough memory.\n"); 121 return 1; 122 } 123 124 if (read(fd, buffer, stat.st_size) < 0) { 125 fprintf(stderr, "Could not read from fortune file: %s\n", 126 strerror(errno)); 127 return -1; 128 } 129 130 buffer[stat.st_size] = '\0'; 131 close(fd); 132 133 // count fortunes 134 135 count = 0; 136 for (i = 0; i < stat.st_size - 2; i++) { 137 if (!strncmp(buffer + i, "\n%\n", 3)) { 138 count++; 139 i += 3; 140 } 141 } 142 143 if (!count) { 144 printf("Out of cookies...\n"); 145 return 0; 146 } 147 148 count = rand() % count; 149 start = 0; 150 151 // find beginning & end 152 for (i = 0; i < stat.st_size - 2; i++) { 153 if (!strncmp(buffer + i, "\n%\n", 3)) { 154 if (count-- <= 0) { 155 buffer[i] = '\0'; 156 break; 157 } 158 159 i += 3; 160 start = i; 161 } 162 } 163 164 puts(buffer + start); 165 return 0; 166 } 167