xref: /haiku/src/bin/fortune.c (revision 246caab54870146b7c7997d18b693bf8849f04fe)
1338b8dc3SIngo Weinhold /*
2c6106a59SAxel Dörfler  * Copyright 2002-2009, Haiku. All rights reserved.
33cb77ecfSAxel Dörfler  * Distributed under the terms of the MIT License.
4338b8dc3SIngo Weinhold  */
5338b8dc3SIngo Weinhold 
63cb77ecfSAxel Dörfler 
73cb77ecfSAxel Dörfler #include <dirent.h>
83cb77ecfSAxel Dörfler #include <errno.h>
93cb77ecfSAxel Dörfler #include <fcntl.h>
10338b8dc3SIngo Weinhold #include <stdlib.h>
11338b8dc3SIngo Weinhold #include <stdio.h>
123cb77ecfSAxel Dörfler #include <string.h>
13338b8dc3SIngo Weinhold #include <sys/stat.h>
143cb77ecfSAxel Dörfler #include <unistd.h>
15338b8dc3SIngo Weinhold 
16c6106a59SAxel Dörfler #include <FindDirectory.h>
17338b8dc3SIngo Weinhold #include <OS.h>
18338b8dc3SIngo Weinhold 
193cb77ecfSAxel Dörfler 
203cb77ecfSAxel Dörfler static int
choose_file(const char * path)213cb77ecfSAxel Dörfler choose_file(const char *path)
22338b8dc3SIngo Weinhold {
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];
56338b8dc3SIngo Weinhold 			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 
773cb77ecfSAxel Dörfler int
main(int argc,char ** argv)783cb77ecfSAxel Dörfler main(int argc, char **argv)
793cb77ecfSAxel Dörfler {
80c6106a59SAxel Dörfler 	char path[PATH_MAX] = {'\0'};
81c6106a59SAxel Dörfler 	const char *file = path;
823cb77ecfSAxel Dörfler 	int fd;
833cb77ecfSAxel Dörfler 	char *buffer;
843cb77ecfSAxel Dörfler 	unsigned start, i;
853cb77ecfSAxel Dörfler 	unsigned count;
86338b8dc3SIngo Weinhold 	struct stat stat;
87338b8dc3SIngo Weinhold 
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);
99338b8dc3SIngo Weinhold 	if (fd < 0) {
1003cb77ecfSAxel Dörfler 		fprintf(stderr, "Couldn't open %s: %s\n", file, strerror(errno));
1013cb77ecfSAxel Dörfler 		return 1;
102338b8dc3SIngo Weinhold 	}
103338b8dc3SIngo Weinhold 
1043cb77ecfSAxel Dörfler 	if (fstat(fd, &stat) < 0) {
1053cb77ecfSAxel Dörfler 		fprintf(stderr, "stat() failed: %s\n", strerror(errno));
1063cb77ecfSAxel Dörfler 		return 1;
107338b8dc3SIngo Weinhold 	}
108338b8dc3SIngo Weinhold 
1093cb77ecfSAxel Dörfler 	if (S_ISDIR(stat.st_mode)) {
110338b8dc3SIngo Weinhold 		close(fd);
111338b8dc3SIngo Weinhold 
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;
116338b8dc3SIngo Weinhold 		}
117338b8dc3SIngo Weinhold 
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));
13340ee778cSRob Gill 		free(buffer);
134338b8dc3SIngo Weinhold 		return -1;
135338b8dc3SIngo Weinhold 	}
136338b8dc3SIngo Weinhold 
1373cb77ecfSAxel Dörfler 	buffer[stat.st_size] = '\0';
1383cb77ecfSAxel Dörfler 	close(fd);
139338b8dc3SIngo Weinhold 
1403cb77ecfSAxel Dörfler 	// count fortunes
141338b8dc3SIngo Weinhold 
1423cb77ecfSAxel Dörfler 	count = 0;
1433cb77ecfSAxel Dörfler 	for (i = 0; i < stat.st_size - 2; i++) {
1443cb77ecfSAxel Dörfler 		if (!strncmp(buffer + i, "\n%\n", 3)) {
1453cb77ecfSAxel Dörfler 			count++;
1463cb77ecfSAxel Dörfler 			i += 3;
1473cb77ecfSAxel Dörfler 		}
148338b8dc3SIngo Weinhold 	}
149338b8dc3SIngo Weinhold 
1503cb77ecfSAxel Dörfler 	if (!count) {
1513cb77ecfSAxel Dörfler 		printf("Out of cookies...\n");
15240ee778cSRob Gill 		free(buffer);
1533cb77ecfSAxel Dörfler 		return 0;
1543cb77ecfSAxel Dörfler 	}
1553cb77ecfSAxel Dörfler 
1563cb77ecfSAxel Dörfler 	count = rand() % count;
1573cb77ecfSAxel Dörfler 	start = 0;
1583cb77ecfSAxel Dörfler 
1593cb77ecfSAxel Dörfler 	// find beginning & end
1603cb77ecfSAxel Dörfler 	for (i = 0; i < stat.st_size - 2; i++) {
1613cb77ecfSAxel Dörfler 		if (!strncmp(buffer + i, "\n%\n", 3)) {
1623cb77ecfSAxel Dörfler 			if (count-- <= 0) {
1633cb77ecfSAxel Dörfler 				buffer[i] = '\0';
164338b8dc3SIngo Weinhold 				break;
165338b8dc3SIngo Weinhold 			}
1663cb77ecfSAxel Dörfler 
1673cb77ecfSAxel Dörfler 			i += 3;
1683cb77ecfSAxel Dörfler 			start = i;
1693cb77ecfSAxel Dörfler 		}
170338b8dc3SIngo Weinhold 	}
171338b8dc3SIngo Weinhold 
1723cb77ecfSAxel Dörfler 	puts(buffer + start);
173*246caab5SRyan Leavengood 	free(buffer);
174338b8dc3SIngo Weinhold 	return 0;
175338b8dc3SIngo Weinhold }
176