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