157f911a4SAxel Dörfler/*
2c6106a59SAxel Dörfler * Copyright 2002-2009, Haiku. All rights reserved.
33cb77ecfSAxel Dörfler * Distributed under the terms of the MIT License.
43cb77ecfSAxel Dörfler */
557f911a4SAxel Dörfler
63cb77ecfSAxel Dörfler
73cb77ecfSAxel Dörfler#include <dirent.h>
83cb77ecfSAxel Dörfler#include <errno.h>
93cb77ecfSAxel Dörfler#include <fcntl.h>
1057f911a4SAxel Dörfler#include <stdlib.h>
1157f911a4SAxel Dörfler#include <stdio.h>
123cb77ecfSAxel Dörfler#include <string.h>
1357f911a4SAxel Dörfler#include <sys/stat.h>
143cb77ecfSAxel Dörfler#include <unistd.h>
1557f911a4SAxel Dörfler
16c6106a59SAxel Dörfler#include <FindDirectory.h>
17338b8dc3SIngo Weinhold#include <OS.h>
18338b8dc3SIngo Weinhold
193cb77ecfSAxel Dörfler
203cb77ecfSAxel Dörflerstatic int
213cb77ecfSAxel Dörflerchoose_file(const char *path)
223cb77ecfSAxel Dörfler{
233cb77ecfSAxel Dörfler	struct dirent *dirent;
243cb77ecfSAxel Dörfler	int count = 0;
253cb77ecfSAxel Dörfler	int chosen;
263cb77ecfSAxel Dörfler
273cb77ecfSAxel Dörfler	DIR *dir = opendir(path);
283cb77ecfSAxel Dörfler	if (dir == NULL)
293cb77ecfSAxel Dörfler		return -1;
303cb77ecfSAxel Dörfler
313cb77ecfSAxel Dörfler	// count directory entries
323cb77ecfSAxel Dörfler
333cb77ecfSAxel Dörfler	while ((dirent = readdir(dir)) != NULL) {
343cb77ecfSAxel Dörfler		if (dirent->d_name[0] == '.')
353cb77ecfSAxel Dörfler			continue;
363cb77ecfSAxel Dörfler
373cb77ecfSAxel Dörfler		count++;
383cb77ecfSAxel Dörfler	}
393cb77ecfSAxel Dörfler
40c5666be3SPhilippe Saint-Pierre	if (count == 0) {
41c5666be3SPhilippe Saint-Pierre		closedir(dir);
42c6106a59SAxel Dörfler		return -1;
43c5666be3SPhilippe Saint-Pierre	}
443cb77ecfSAxel Dörfler	// choose and open entry
453cb77ecfSAxel Dörfler
463cb77ecfSAxel Dörfler	chosen = rand() % count;
473cb77ecfSAxel Dörfler	count = 0;
483cb77ecfSAxel Dörfler	rewinddir(dir);
493cb77ecfSAxel Dörfler
503cb77ecfSAxel Dörfler	while ((dirent = readdir(dir)) != NULL) {
513cb77ecfSAxel Dörfler		if (dirent->d_name[0] == '.')
523cb77ecfSAxel Dörfler			continue;
533cb77ecfSAxel Dörfler
543cb77ecfSAxel Dörfler		if (chosen <= count) {
553cb77ecfSAxel Dörfler			char name[PATH_MAX];
563cb77ecfSAxel Dörfler			int fd;
573cb77ecfSAxel Dörfler
583cb77ecfSAxel Dörfler			// build full path
593cb77ecfSAxel Dörfler			strlcpy(name, path, sizeof(name));
603cb77ecfSAxel Dörfler			strlcat(name, "/", sizeof(name));
613cb77ecfSAxel Dörfler			strlcat(name, dirent->d_name, sizeof(name));
623cb77ecfSAxel Dörfler
633cb77ecfSAxel Dörfler			fd = open(name, O_RDONLY);
643cb77ecfSAxel Dörfler			if (fd >= 0) {
653cb77ecfSAxel Dörfler				closedir(dir);
663cb77ecfSAxel Dörfler				return fd;
673cb77ecfSAxel Dörfler			}
683cb77ecfSAxel Dörfler		}
693cb77ecfSAxel Dörfler		count++;
703cb77ecfSAxel Dörfler	}
713cb77ecfSAxel Dörfler
723cb77ecfSAxel Dörfler	closedir(dir);
733cb77ecfSAxel Dörfler	return -1;
743cb77ecfSAxel Dörfler}
753cb77ecfSAxel Dörfler
763cb77ecfSAxel Dörfler
7757f911a4SAxel Dörflerint
783cb77ecfSAxel Dörflermain(int argc, char **argv)
7957f911a4SAxel Dörfler{
80c6106a59SAxel Dörfler	char path[PATH_MAX] = {'\0'};
81c6106a59SAxel Dörfler	const char *file = path;
8257f911a4SAxel Dörfler	int fd;
833cb77ecfSAxel Dörfler	char *buffer;
843cb77ecfSAxel Dörfler	unsigned start, i;
853cb77ecfSAxel Dörfler	unsigned count;
8657f911a4SAxel Dörfler	struct stat stat;
8757f911a4SAxel Dörfler
883cb77ecfSAxel Dörfler	srand(system_time() % INT_MAX);
893cb77ecfSAxel Dörfler
903cb77ecfSAxel Dörfler	if (argc > 1) {
913cb77ecfSAxel Dörfler		// if there are arguments, choose one randomly
923cb77ecfSAxel Dörfler		file = argv[1 + (rand() % (argc - 1))];
93c6106a59SAxel Dörfler	} else if (find_directory(B_SYSTEM_DATA_DIRECTORY, -1, false, path,
94c6106a59SAxel Dörfler			sizeof(path)) == B_OK) {
95c6106a59SAxel Dörfler		strlcat(path, "/fortunes", sizeof(path));
963cb77ecfSAxel Dörfler	}
973cb77ecfSAxel Dörfler
983cb77ecfSAxel Dörfler	fd = open(file, O_RDONLY, 0);
9957f911a4SAxel Dörfler	if (fd < 0) {
1003cb77ecfSAxel Dörfler		fprintf(stderr, "Couldn't open %s: %s\n", file, strerror(errno));
1013cb77ecfSAxel Dörfler		return 1;
10257f911a4SAxel Dörfler	}
10357f911a4SAxel Dörfler
1043cb77ecfSAxel Dörfler	if (fstat(fd, &stat) < 0) {
1053cb77ecfSAxel Dörfler		fprintf(stderr, "stat() failed: %s\n", strerror(errno));
1063cb77ecfSAxel Dörfler		return 1;
10757f911a4SAxel Dörfler	}
10857f911a4SAxel Dörfler
1093cb77ecfSAxel Dörfler	if (S_ISDIR(stat.st_mode)) {
1103cb77ecfSAxel Dörfler		close(fd);
1113cb77ecfSAxel Dörfler
1123cb77ecfSAxel Dörfler		fd = choose_file(file);
1133cb77ecfSAxel Dörfler		if (fd < 0) {
1143cb77ecfSAxel Dörfler			fprintf(stderr, "Could not find any fortune file.\n");
1153cb77ecfSAxel Dörfler			return 1;
1163cb77ecfSAxel Dörfler		}
1173cb77ecfSAxel Dörfler
1183cb77ecfSAxel Dörfler		if (fstat(fd, &stat) < 0) {
1193cb77ecfSAxel Dörfler			fprintf(stderr, "stat() failed: %s\n", strerror(errno));
1203cb77ecfSAxel Dörfler			return 1;
1213cb77ecfSAxel Dörfler		}
1223cb77ecfSAxel Dörfler	}
1233cb77ecfSAxel Dörfler
1243cb77ecfSAxel Dörfler	buffer = malloc(stat.st_size + 1);
1253cb77ecfSAxel Dörfler	if (buffer == NULL) {
1263cb77ecfSAxel Dörfler		fprintf(stderr, "Not enough memory.\n");
1273cb77ecfSAxel Dörfler		return 1;
1283cb77ecfSAxel Dörfler	}
1293cb77ecfSAxel Dörfler
1303cb77ecfSAxel Dörfler	if (read(fd, buffer, stat.st_size) < 0) {
1313cb77ecfSAxel Dörfler		fprintf(stderr, "Could not read from fortune file: %s\n",
1323cb77ecfSAxel Dörfler			strerror(errno));
13357f911a4SAxel Dörfler		return -1;
13457f911a4SAxel Dörfler	}
13557f911a4SAxel Dörfler
1363cb77ecfSAxel Dörfler	buffer[stat.st_size] = '\0';
13757f911a4SAxel Dörfler	close(fd);
13857f911a4SAxel Dörfler
1393cb77ecfSAxel Dörfler	// count fortunes
1403cb77ecfSAxel Dörfler
1413cb77ecfSAxel Dörfler	count = 0;
1423cb77ecfSAxel Dörfler	for (i = 0; i < stat.st_size - 2; i++) {
1433cb77ecfSAxel Dörfler		if (!strncmp(buffer + i, "\n%\n", 3)) {
1443cb77ecfSAxel Dörfler			count++;
1453cb77ecfSAxel Dörfler			i += 3;
1463cb77ecfSAxel Dörfler		}
14757f911a4SAxel Dörfler	}
14857f911a4SAxel Dörfler
1493cb77ecfSAxel Dörfler	if (!count) {
15057f911a4SAxel Dörfler		printf("Out of cookies...\n");
1513cb77ecfSAxel Dörfler		return 0;
15257f911a4SAxel Dörfler	}
15357f911a4SAxel Dörfler
1543cb77ecfSAxel Dörfler	count = rand() % count;
1553cb77ecfSAxel Dörfler	start = 0;
15657f911a4SAxel Dörfler
1573cb77ecfSAxel Dörfler	// find beginning & end
1583cb77ecfSAxel Dörfler	for (i = 0; i < stat.st_size - 2; i++) {
1593cb77ecfSAxel Dörfler		if (!strncmp(buffer + i, "\n%\n", 3)) {
1603cb77ecfSAxel Dörfler			if (count-- <= 0) {
1613cb77ecfSAxel Dörfler				buffer[i] = '\0';
1623cb77ecfSAxel Dörfler				break;
16357f911a4SAxel Dörfler			}
16457f911a4SAxel Dörfler
1653cb77ecfSAxel Dörfler			i += 3;
1663cb77ecfSAxel Dörfler			start = i;
16757f911a4SAxel Dörfler		}
16857f911a4SAxel Dörfler	}
16957f911a4SAxel Dörfler
1703cb77ecfSAxel Dörfler	puts(buffer + start);
17157f911a4SAxel Dörfler	return 0;
17257f911a4SAxel Dörfler}