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