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
20static int
21choose_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
77int
78main(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		free(buffer);
134		return -1;
135	}
136
137	buffer[stat.st_size] = '\0';
138	close(fd);
139
140	// count fortunes
141
142	count = 0;
143	for (i = 0; i < stat.st_size - 2; i++) {
144		if (!strncmp(buffer + i, "\n%\n", 3)) {
145			count++;
146			i += 3;
147		}
148	}
149
150	if (!count) {
151		printf("Out of cookies...\n");
152		free(buffer);
153		return 0;
154	}
155
156	count = rand() % count;
157	start = 0;
158
159	// find beginning & end
160	for (i = 0; i < stat.st_size - 2; i++) {
161		if (!strncmp(buffer + i, "\n%\n", 3)) {
162			if (count-- <= 0) {
163				buffer[i] = '\0';
164				break;
165			}
166
167			i += 3;
168			start = i;
169		}
170	}
171
172	puts(buffer + start);
173	free(buffer);
174	return 0;
175}
176