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