aboutsummaryrefslogtreecommitdiffstats
path: root/libhaiku.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhaiku.c')
-rw-r--r--libhaiku.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/libhaiku.c b/libhaiku.c
new file mode 100644
index 0000000..04b94a9
--- /dev/null
+++ b/libhaiku.c
@@ -0,0 +1,310 @@
+/* See LICENSE file for copyright and license details. */
+#include "libhaiku.h"
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+#define H(...) return random_haiku(__VA_ARGS__, NULL)
+
+
+/* Synonyms. */
+#if defined(EDEADLOCK) && !defined(EDEADLK)
+# define EDEADLK EDEADLOCK
+#endif
+#if defined(EOPNOTSUPP) && !defined(ENOTSUP)
+# define ENOTSUP EOPNOTSUPP
+#endif
+
+
+
+/**
+ * Pick a random integer in [0, `n`[
+ *
+ * @param n The largest allowed return value plus one
+ * @return A random integer in [0, `n`[
+ */
+static int
+random_int(int n)
+{
+ static int initialised = 0;
+ double r, ri;
+ if (!initialised) {
+ srand((unsigned)time(NULL));
+ initialised = 1;
+ }
+ r = (double)rand() * (double)n / ((double)RAND_MAX + 1.0);
+ ri = ((int)r) % n;
+ return ri < 0 ? (ri + n) : ri;
+}
+
+
+/**
+ * Pick a random haiku
+ *
+ * @param str... `NULL`-terminated list of haiku
+ * Must contain at least one haiku
+ * @return One of the haiku, randomly selected
+ */
+#ifdef __GNUC__
+__attribute__((__sentinel__))
+#endif
+static const char *
+random_haiku(const char *str, ... /*, NULL */)
+{
+ int n = 1;
+ const char *s = str;
+ va_list args;
+
+ va_start(args, str);
+ while (va_arg(args, const char *))
+ n++;
+ va_end(args);
+
+ if (n == 1)
+ return str;
+ n = random_int(n);
+
+ va_start(args, str);
+ while (n--)
+ s = va_arg(args, const char *);
+ va_end(args);
+ return s;
+}
+
+
+/**
+ * Get a random generic poetic error message
+ *
+ * @return A random generic poetic error message
+ */
+const char *
+libhaiku_generic(void)
+{
+ H("Error messages\n""cannot completely convey.\n""We now know shared loss.\n",
+ "Errors have occurred.\n""We won't tell you where or why.\n""Lazy programmers.\n",
+ "To have no errors.\n""Would be life without meaning.\n""No struggle, no joy.\n",
+ "There is a chasm\n""of carbon and silicon\n""the software can't bridge.\n",
+ "Beauty, success, truth\n""He is blessed who has two.\n""Your program has none.\n",
+ "Technical support\n""would be a flowing source of\n""sweet commiseration.\n");
+}
+
+
+/**
+ * Get a poetic error message
+ *
+ * @param errnum `errno` value that the error message shall be selected for
+ * @param genericp Unless `NULL`, will be set to 1 if the function didn't have
+ * any haikus specific the the specified error, and had to
+ * return a generic haiku, and to 0 otherwise
+ * @return A poetic error message
+ */
+const char *
+libhaiku_strerror(int errnum, int *genericp)
+{
+ if (genericp)
+ *genericp = 0;
+
+ switch (errnum) {
+#ifdef ENETDOWN
+ case ENETDOWN:
+ H("Stay the patient course.\n""Of little worth is your ire.\n""The network is down.\n",
+ "Your vast achievements\n""are now only dreams.\n""The network is down.\n");
+#endif
+
+#ifdef ERFKILL
+ case ERFKILL:
+ H("The action you took\n""severed hope of connection\n""with the Internet.\n");
+#endif
+
+#ifdef EAGAIN
+ case EAGAIN:
+#endif
+#ifdef ENFILE
+ case ENFILE:
+#endif
+#ifdef EMFILE
+ case EMFILE:
+#endif
+#ifdef EUSERS
+ case EUSERS:
+#endif
+#ifdef EMLINK
+ case EMLINK:
+#endif
+#if defined(EAGAIN) || defined(ENFILE) || defined(EMFILE) || defined(EUSERS) || defined(EMLINK)
+ H("ABORTED effort:\n""Close all that you have.\n""You ask way too much.\n",
+ "The code was willing\n""It considered your request\n""But the chips were weak.\n");
+#endif
+
+#ifdef ENOMEM
+ case ENOMEM:
+ H("I'm sorry, there's... um...\n""insufficient... what's-it-called?\n""The term eludes me...\n");
+#endif
+
+#ifdef ENOSPC
+ case ENOSPC:
+#endif
+#ifdef ENOSR
+ case ENOSR:
+#endif
+#ifdef ENOBUFS
+ case ENOBUFS:
+#endif
+#ifdef EDQUOT
+ case EDQUOT:
+#endif
+#if defined(ENOSPC) || defined(ENOSR) || defined(ENOBUFS) || defined(EDQUOT)
+ H("Out of memory.\n""We wish to hold the whole sky,\n""But we never will.\n");
+#endif
+
+#ifdef ENOANO
+ case ENOANO:
+#endif
+#ifdef ENOENT
+ case ENOENT:
+#endif
+#if defined(ENOANO) || defined(ENOENT)
+ H("With searching comes loss\n""and the presence of absence:\n""'My Novel' not found.\n",
+ "Rather than a beep\n""Or a rude error message,\n""These words: “File not found.”\n",
+ "Three things are certain:\n""Death, taxes, and lost data.\n""Guess which has occurred.\n",
+ "Having been erased,\n""The document you're seeking\n""Must now be retyped.\n",
+ "Everything is gone.\n""Your life's work has been destroyed.\n""Squeeze trigger (yes/no)?\n",
+ "Spring will come again,\n""But it will not bring with it\n""Any of your files.\n");
+#endif
+
+#ifdef EOWNERDEAD
+ case EOWNERDEAD: /* Reusing haiku from ENOENT. */
+ H("Three things are certain:\n""Death, taxes, and lost data.\n""Guess which has occurred.\n");
+#endif
+
+#ifdef EMSGSIZE
+ case EMSGSIZE:
+ H("A file that big?\n""It might be very useful.\n""But now it is gone.\n");
+#endif
+
+#ifdef EHWPOISON
+ case EHWPOISON:
+ H("Yesterday it worked.\n""Today it is not working.\n""Windows is like that.\n");
+#endif
+
+#ifdef EUCLEAN
+ case EUCLEAN:
+#endif
+#ifdef ENOTRECOVERABLE
+ case ENOTRECOVERABLE:
+#endif
+#if defined(EUCLEAN) || defined(ENOTRECOVERABLE)
+ H("Chaos reigns within.\n""Reflect, repent, and reboot.\n""Order shall return.\n");
+#endif
+
+#ifdef EHOSTDOWN
+ case EHOSTDOWN:
+ H("Windows NT crashed.\n""I am the Blue Screen of Death.\n""Noone hears your screams.\n",
+ "Won't you please observe\n""a brief moment of silence\n""For the dead server?\n");
+#endif
+
+#ifdef EBFONT
+ case EBFONT:
+ H("First snow, then silence.\n""This thousand dollar screen dies\n""so beautifully.\n");
+#endif
+
+#ifdef EFAULT
+ case EFAULT:
+ H("A crash reduces\n""your expensive computer\n""to a simple stone.\n",
+ "Seeing my great fault.\n""Through a darkening red screen.\n""I begin again.\n",
+ "Memory shaken,\n""the San Andreas of all\n""invalid page faults.\n");
+#endif
+
+#ifdef EINVAL
+ case EINVAL:
+ H("Something you entered\n""transcended parameters.\n""So much is unknown.\n",
+ "Some incompetence\n""fundamentally transcends\n""mere error message.\n");
+#endif
+
+#ifdef EDEADLK
+ case EDEADLK:
+ H("From formless chaos,\n""each thread seeks resolution.\n""A race condition.\n");
+#endif
+
+#ifdef EBADMSG
+ case EBADMSG:
+ H("Many fingers clicking.\n""Screens are full of letters.\n""What is their meaning?\n");
+#endif
+
+#ifdef ELOOP
+ case ELOOP:
+ H("Linkage exception.\n""Code has looped upon itself\n""like the coiled serpent.\n");
+#endif
+
+#ifdef ECHILD
+ case ECHILD:
+ H("A futile, grim reap.\n""You will have to realise that,\n""you've no children left.\n");
+#endif
+
+#ifdef EPIPE
+ case EPIPE:
+ H("Your pipe is broken.\n""Code in watery ruins.\n""Machines short circuit.\n");
+#endif
+
+#ifdef EACCES
+ case EACCES:
+ H("Touching others' files?\n""Can't keep your hands to yourself?\n""Permission denied.\n");
+#endif
+
+#ifdef EINTR
+ case EINTR:
+ H("Call interrupted?\n""Why do you not post a sign:\n""Disturb. Risk your life!\n");
+#endif
+
+#ifdef EPERM
+ case EPERM:
+ H("Caution to the wind.\n""You should always run as root.\n""She can do anything.\n");
+#endif
+
+ default:
+ if (genericp)
+ *genericp = 1;
+ return libhaiku_generic();
+ }
+}
+
+
+/**
+ * Print a poetic error message
+ *
+ * @param prefix Unless `NULL` or empty, each line will be prefixed
+ * by the specified string followed by a colon and a space
+ * @param errnum `errno` value that the error message shall be selected for;
+ * if negative, a generic error message is printed
+ */
+void
+libhaiku_perror2(const char *prefix, int errnum)
+{
+ const char *line1, *line2, *line3;
+ int len1, len2;
+
+ line1 = libhaiku_strerror(errnum, NULL);
+
+ if (prefix && *prefix) {
+ line2 = &strchr(line1, '\n')[1];
+ line3 = &strchr(line2, '\n')[1];
+ len1 = (int)(line2 - line1);
+ len2 = (int)(line3 - line2);
+ fprintf(stderr, "%s: %.*s%s: %.*s%s: %s", prefix, len1, line1, prefix, len2, line2, prefix, line3);
+ } else {
+ fprintf(stderr, "%s", line1);
+ }
+}
+
+
+/**
+ * Print a poetic error message
+ *
+ * @param prefix Unless `NULL` or empty, each line will be prefixed
+ * by the specified string followed by a colon and a space
+ */
+extern void libhaiku_perror(const char *prefix);