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		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
76int
77main(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