aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/blackbody.c41
-rw-r--r--src/blackbody.h31
-rw-r--r--src/haiku.c182
-rw-r--r--src/parse_10deg.c57
-rw-r--r--src/radharc.c30
-rw-r--r--src/settings.c144
-rw-r--r--src/settings.h8
-rw-r--r--src/solar.c69
-rw-r--r--src/solar.h12
-rw-r--r--src/state.c98
10 files changed, 303 insertions, 369 deletions
diff --git a/src/blackbody.c b/src/blackbody.c
index 26ea52e..d393686 100644
--- a/src/blackbody.c
+++ b/src/blackbody.c
@@ -22,23 +22,6 @@
/**
- * The highest colour temperature in the table.
- */
-#define HIGHEST 40000
-
-/**
- * The lowest colour temperature in the table.
- */
-#define LOWEST 1000
-
-/**
- * The temperature difference between the colours in the table.
- */
-#define DELTA 100
-
-
-
-/**
* Convert from CIE xyY to [0, 1] sRGB.
*
* @param x The 'x' component.
@@ -49,15 +32,15 @@
* @param g Output parameter for the green value.
* @param b Output parameter for the blue value.
*/
-static void
+void
ciexyy_to_srgb(double x, double y, double Y, double *r, double *g, double *b)
{
#define SRGB(C) (((C) <= 0.0031308) ? (12.92 * (C)) : ((1.0 + 0.055) * pow((C), 1.0 / 2.4) - 0.055))
double X, Z;
/* Convert CIE xyY to CIE XYZ. */
- X = Y * (y == 0 ? 0 : (x / y));
- Z = Y * (y == 0 ? 0 : ((1 - x - y) / y));
+ X = Y * (y == 0.0 ? 0.0 : (x / y));
+ Z = Y * (y == 0.0 ? 0.0 : ((1.0 - x - y) / y));
/* Convert CIE XYZ to [0, 1] linear RGB. (ciexyz_to_linear) */
*r = ( 3.240450 * X) + (-1.537140 * Y) + (-0.4985320 * Z);
@@ -88,7 +71,7 @@ ciexyy_to_srgb(double x, double y, double Y, double *r, double *g, double *b)
static void
interpolate(double x1, double y1, double x2, double y2, double temp, double *r, double *g, double *b)
{
- double weight = fmod(temp, (double)DELTA) / (double)DELTA;
+ double weight = fmod(temp, (double)DELTA_TEMPERATURE) / (double)DELTA_TEMPERATURE;
double x = x1 * (1 - weight) + x2 * weight;
double y = y1 * (1 - weight) + y2 * weight;
ciexyy_to_srgb(x, y, 1.0, r, g, b);
@@ -118,26 +101,24 @@ get_colour(int fd, long int temp, double *r, double *g, double *b)
/* We do not have any values for above 40 000 K, but
* the differences will be unnoticeable, perhaps even
* unencodeable. */
- if (temp > HIGHEST) temp = HIGHEST;
+ if (temp > HIGHEST_TEMPERATURE) temp = HIGHEST_TEMPERATURE;
/* Things do not glow below 1000 K. Yes, fire is hot! */
- if (temp < LOWEST) t ((errno = EDOM));
+ if (temp < LOWEST_TEMPERATURE) t ((errno = EDOM));
/* Read table. */
- offset = ((off_t)temp - LOWEST) / DELTA;
- offset *= (off_t)(5 * sizeof(double));
- errno = 0;
- xpread(fd, values, sizeof(values), offset);
+ offset = ((off_t)temp - LOWEST_TEMPERATURE) / DELTA_TEMPERATURE;
+ offset *= (off_t)(sizeof(values) / 2);
+ errno = 0; xpread(fd, values, sizeof(values), offset);
/* Get colour. */
- if (temp % DELTA)
+ if (temp % DELTA_TEMPERATURE)
interpolate(values[0], values[1], values[6], values[7], (double)temp, r, g, b);
else
*r = values[2], *g = values[3], *b = values[4];
/* Adjust colours for use. */
max = fmax(fmax(fabs(*r), fabs(*g)), fabs(*b));
- if (max != 0)
- *r /= max, *g /= max, *b /= max;
+ if (max != 0) *r /= max, *g /= max, *b /= max;
*r = *r > 0.0 ? *r : 0.0;
*g = *g > 0.0 ? *g : 0.0;
*b = *b > 0.0 ? *b : 0.0;
diff --git a/src/blackbody.h b/src/blackbody.h
index 82331d2..95fa70a 100644
--- a/src/blackbody.h
+++ b/src/blackbody.h
@@ -18,6 +18,37 @@
/**
+ * The highest colour temperature in the table.
+ */
+#define HIGHEST_TEMPERATURE 40000
+
+/**
+ * The lowest colour temperature in the table.
+ */
+#define LOWEST_TEMPERATURE 1000
+
+/**
+ * The temperature difference between the colours in the table.
+ */
+#define DELTA_TEMPERATURE 100
+
+
+
+/**
+ * Convert from CIE xyY to [0, 1] sRGB.
+ *
+ * @param x The 'x' component.
+ * @param y The 'y' component.
+ * @param Y The 'Y' component.
+ * @param r Output parameter for the “red” value.
+ * (Seriously, sRGB red is orange, just look at it fullscreen.)
+ * @param g Output parameter for the green value.
+ * @param b Output parameter for the blue value.
+ */
+void
+ciexyy_to_srgb(double x, double y, double Y, double *r, double *g, double *b);
+
+/**
* Get the [0, 1] sRGB values of a colour temperature.
*
* @param fd File descriptor for the colour table.
diff --git a/src/haiku.c b/src/haiku.c
index 25387f4..1accc9f 100644
--- a/src/haiku.c
+++ b/src/haiku.c
@@ -65,14 +65,20 @@ random_haiku(const char *str, ... /*, NULL */)
}
+#if defined(EDEADLOCK) && !defined(EDEADLK)
+# define EDEADLK EDEADLOCK
+#endif
+
+
/**
* Whenever possible, print am error message in haiku.
*
* @param s The argument to pass to `perror` in case we call back to it.
*/
-void haiku(const char *s)
+void
+haiku(const char *s)
{
-#define HAIKU(...) do { fprintf(stderr, "%s", random_haiku(__VA_ARGS__, NULL)); return; } while (0)
+#define H(...) do { fprintf(stderr, "%s", random_haiku(__VA_ARGS__, NULL)); return; } while (0)
/* Yeah, I now most of these are in 5–7–5 syllables,
* rather than 5–7–5 mora. But really, how cares. */
@@ -82,191 +88,95 @@ void haiku(const char *s)
return;
case ENETDOWN:
- HAIKU("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");
+ 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");
case ERFKILL:
- HAIKU("The action you took\n"
- "severed hope of connection\n"
- "with the Internet.\n");
+ H("The action you took\n""severed hope of connection\n""with the Internet.\n");
case EAGAIN:
case ENFILE:
case EMFILE:
case EUSERS:
case EMLINK:
- HAIKU("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");
+ 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");
case ENOMEM:
- HAIKU("I'm sorry, there's ... um ...\n"
- "insufficient ... what's-it-called?\n"
- "The term eludes me...\n");
+ H("I'm sorry, there's... um...\n""insufficient... what's-it-called?\n""The term eludes me...\n");
case ENOSPC:
case ENOSR:
case ENOBUFS:
case EDQUOT:
- HAIKU("Out of memory.\n"
- "We wish to hold the whole sky,\n"
- "But we never will.\n");
+ H("Out of memory.\n""We wish to hold the whole sky,\n""But we never will.\n");
case ENOANO:
case ENOENT:
- HAIKU("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");
+ 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");
case EMSGSIZE:
- HAIKU("A file that big?\n"
- "It might be very useful.\n"
- "But now it is gone.\n");
+ H("A file that big?\n""It might be very useful.\n""But now it is gone.\n");
case EHWPOISON:
- HAIKU("Yesterday it worked.\n"
- "Today it is not working.\n"
- "Windows is like that.\n");
+ H("Yesterday it worked.\n""Today it is not working.\n""Windows is like that.\n");
case ENOTRECOVERABLE:
- HAIKU("Chaos reigns within.\n"
- "Reflect, repent, and reboot.\n"
- "Order shall return.\n");
+ H("Chaos reigns within.\n""Reflect, repent, and reboot.\n""Order shall return.\n");
case EHOSTDOWN:
- HAIKU("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");
+ 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");
case EBFONT:
- HAIKU("First snow, then silence.\n"
- "This thousand dollar screen dies\n"
- "so beautifully.\n");
+ H("First snow, then silence.\n""This thousand dollar screen dies\n""so beautifully.\n");
case EFAULT:
- HAIKU("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");
+ 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");
case EINVAL:
- HAIKU("Something you entered\n"
- "transcended parameters.\n"
- "So much is unknown.\n"
+ H("Something you entered\n""transcended parameters.\n""So much is unknown.\n"
+ "Some incompetence\n""fundamentally transcends\n""mere error message.\n");
- "Some incompetence\n"
- "fundamentally transcends\n"
- "mere error message.\n");
-
-#ifdef EDEADLK
case EDEADLK:
-#else
- case EDEADLOCK:
-#endif
- HAIKU("From formless chaos,\n"
- "each thread seeks resolution.\n"
- "A race condition.\n");
+ H("From formless chaos,\n""each thread seeks resolution.\n""A race condition.\n");
case EBADMSG:
- HAIKU("Many fingers clicking.\n"
- "Screens are full of letters.\n"
- "What is their meaning?\n");
+ H("Many fingers clicking.\n""Screens are full of letters.\n""What is their meaning?\n");
case ELOOP:
- HAIKU("Linkage exception.\n"
- "Code has looped upon itself\n"
- "like the coiled serpent.\n");
+ H("Linkage exception.\n""Code has looped upon itself\n""like the coiled serpent.\n");
case ECHILD:
- HAIKU("A futile grim reap.\n"
- "You will have to realise that,\n"
- "you've no children left.\n");
+ H("A futile grim reap.\n""You will have to realise that,\n""you've no children left.\n");
case EPIPE:
- HAIKU("Your pipe is broken.\n"
- "Code in watery ruins.\n"
- "Machines short circuit.\n");
+ H("Your pipe is broken.\n""Code in watery ruins.\n""Machines short circuit.\n");
case EACCES:
- HAIKU("Touching others' files?\n"
- "Can't keep your hands to yourself?\n"
- "Permission denied.\n");
+ H("Touching others' files?\n""Can't keep your hands to yourself?\n""Permission denied.\n");
case EINTR:
- HAIKU("Call interrupted?\n"
- "Why do you not post a sign:\n"
- "Disturb. Risk your life!\n");
+ H("Call interrupted?\n""Why do you not post a sign:\n""Disturb. Risk your life!\n");
case EPERM:
- HAIKU("Caution to the wind.\n"
- "You should always run as root.\n"
- "She can do anything.\n");
+ H("Caution to the wind.\n""You should always run as root.\n""She can do anything.\n");
default:
perror(s);
- HAIKU("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");
+ 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");
}
}
diff --git a/src/parse_10deg.c b/src/parse_10deg.c
index 1ef6947..aacf852 100644
--- a/src/parse_10deg.c
+++ b/src/parse_10deg.c
@@ -15,53 +15,50 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "haiku.h"
+#include "blackbody.h"
#include "macros.h"
-#include <math.h>
#include <sys/stat.h>
-#define HIGHEST 40000
-#define LOWEST 1000
-#define DELTA 100
-#define EXPECTED_ELEMENTS ((HIGHEST - LOWEST) / DELTA + 1)
+/**
+ * The number of measured temperatures.
+ */
+#define TEMPERATURES ((HIGHEST_TEMPERATURE - LOWEST_TEMPERATURE) / DELTA_TEMPERATURE + 1)
-static void
-ciexyy_to_srgb(double x, double y, double Y, double *r, double *g, double *b)
-{
-#define SRGB(C) (((C) <= 0.0031308) ? (12.92 * (C)) : ((1.0 + 0.055) * pow((C), 1.0 / 2.4) - 0.055))
- double X, Z;
-
- /* Convert CIE xyY to CIE XYZ. */
- X = Y * (y == 0 ? 0 : (x / y));
- Z = Y * (y == 0 ? 0 : ((1 - x - y) / y));
-
- /* Convert CIE XYZ to [0, 1] linear RGB. (ciexyz_to_linear) */
- *r = ( 3.240450 * X) + (-1.537140 * Y) + (-0.4985320 * Z);
- *g = (-0.969266 * X) + ( 1.876010 * Y) + ( 0.0415561 * Z);
- *b = (0.0556434 * X) + (-0.204026 * Y) + ( 1.0572300 * Z);
-
- /* Convert [0, 1] linear RGB to [0, 1] sRGB. */
- SRGB(*r), SRGB(*g), SRGB(*b);
-}
+/**
+ * Create the lookup table of temperatures.
+ *
+ * Standard input should be the file '10deg',
+ * standard output should be the table file
+ * and must be a regular file.
+ *
+ * @param argc Should be 1.
+ * @param argv Should only contain the name of the process.
+ * @return 0 on success, 1 on error.
+ */
int main(int argc, char *argv[])
{
+#define x (xyrgb[0])
+#define y (xyrgb[1])
+#define r (xyrgb[2])
+#define g (xyrgb[3])
+#define b (xyrgb[4])
+
double xyrgb[5];
struct stat attr;
+ long int temp = LOWEST_TEMPERATURE;
- while (fscanf(stdin, "%lf %lf\n", xyrgb + 0, xyrgb + 1) == 2) {
- ciexyy_to_srgb(xyrgb[0], xyrgb[1], 1.0, xyrgb + 2, xyrgb + 3, xyrgb + 4);
+ for (; fscanf(stdin, "%lf %lf\n", &x, &y) == 2; temp += DELTA_TEMPERATURE) {
+ (temp == 6500) ? (r = g = b = 1.0) : ciexyy_to_srgb(x, y, 1.0, &r, &g, &b);
xwrite(STDOUT_FILENO, xyrgb, sizeof(xyrgb));
}
xwrite(STDOUT_FILENO, xyrgb, sizeof(xyrgb)); /* sugar */
t (fstat(STDOUT_FILENO, &attr));
- if ((size_t)(attr.st_size) != (EXPECTED_ELEMENTS + 1) * 5 * sizeof(double))
- return 1;
-
- return 0;
+ return ((size_t)(attr.st_size) != (TEMPERATURES + 1) * 5 * sizeof(double));
fail:
- return haiku(argc ? *argv : "parse_10deg"), -1;
+ return haiku(argc ? *argv : "parse_10deg"), 1;
}
diff --git a/src/radharc.c b/src/radharc.c
index 292c0b6..43e1385 100644
--- a/src/radharc.c
+++ b/src/radharc.c
@@ -14,39 +14,17 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "solar.h"
#include "state.h"
#include "haiku.h"
#include "macros.h"
-/**
- * The name of the process.
- */
-char *argv0 = NULL;
-
-
/**
- * Exit if time the is before year 0 in J2000.
- *
- * @param The name of the process, `NULL` if unknown.
+ * The name of the process.
*/
-#if defined(TIMETRAVELLER)
-static void
-check_timetravel(const char *argv0)
-{
- struct timespec now;
- if (clock_gettime(CLOCK_REALTIME, &now))
- haiku(argv0 ? argv0 : "radharc"), exit(1);
- if (now.tv_nsec < (time_t)946728000L)
- fprintf(stderr, "We have detected that you are a time-traveller"
- "(or your clock is not configured correctly.)"
- "Please recompile with -DTIMETRAVELLER"
- "(or correct your clock.)"), exit(1);
-}
-#else
-# define check_timetravel(_) /* do nothing */
-#endif
+char *argv0 = "radharc";
@@ -55,7 +33,7 @@ main(int argc, char *argv[])
{
struct settings settings;
- check_timetravel(*argv);
+ t (check_timetravel());
parse_command_line(argc, argv, &settings);
argv0 = argv0 ? argv0 : "radharc";
t (get_state_pathname(&settings));
diff --git a/src/settings.c b/src/settings.c
index e05c98c..029fc81 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -33,13 +33,11 @@
static void
usage(int condition)
{
- if (condition) {
- fprintf(stderr,
- "Usage: %s [OPTIONS]...\n"
- "See `man 1 radharc` for more information.\n",
- !argv0 ? "radharc" : argv0);
- exit(2);
- }
+ if (!condition) return;
+ fprintf(stderr,
+ "Usage: %s [OPTIONS]...\n"
+ "See `man 1 radharc` for more information.\n",
+ !argv0 ? "radharc" : argv0), exit(2);
}
@@ -61,13 +59,8 @@ usage(int condition)
static int
parse_temperature(const char *str, long int *temp, int *direction, int lower)
{
- int dir = 0;
char *end;
- switch (*str) {
- case '-': dir = -1; break;
- case '+': dir = +1; break;
- default: break;
- }
+ int dir = *str == '-' ? -1 : *str == '+' ? +1 : 0;
str += !!dir;
t (dir && !direction);
if (dir) *direction = dir;
@@ -90,33 +83,24 @@ fail:
static int
parse_timespec(const char *str, struct timespec *ts)
{
+#define DIGIT(var, c) var += (var) * 10 + ((c) & 15);
+#define ALL_DIGITS(cond, var) while ((cond) && isdigit(*str)) DIGIT(var, *str++)
+
int points = 0;
memset(ts, 0, sizeof(*ts));
/* Parse seconds. */
t (!isdigit(*str));
- while (isdigit(*str)) {
- ts->tv_sec *= 10;
- ts->tv_sec += *str++ & 15;
- }
+ ALL_DIGITS(1, ts->tv_sec);
/* End? */
if (!*str) return 0;
t (*str != '.');
/* Parse nanoseconds.*/
- for (; (points++ < 9) && isdigit(*str); str++) {
- ts->tv_nsec *= 10;
- ts->tv_nsec += *str++ & 15;
- }
- if (points == 9) {
- t (!isdigit(*str));
- if (*str++ >= '5') {
- ts->tv_nsec += 1;
- if (ts->tv_nsec == 1000000000L)
- ts->tv_sec += 1, ts->tv_nsec = 0;
- }
- }
+ ALL_DIGITS(points++ < 9, ts->tv_nsec);
+ if ((points == 9) && isdigit(*str) && (*str++ >= '5') && (++(ts->tv_nsec) == 1000000000L))
+ ts->tv_sec += 1, ts->tv_nsec = 0;
while (isdigit(*str)) str++;
t (*str);
@@ -156,84 +140,81 @@ parse_location(char *str, double *loc, double limit)
* @param settings Output parameter for the settings.
*/
void
-parse_command_line(int argc, char *argv[], struct settings *settings)
+parse_command_line(int argc, char *argv[], struct settings *s)
{
int location_set = 0;
char *p;
char *arg;
int c = 0;
- memset(settings, 0, sizeof(*settings));
- settings->natural_temp = 6500;
- settings->day_temp = 5500;
- settings->night_temp = 3500;
- settings->trans_speed = 50;
+ memset(s, 0, sizeof(*s));
+ s->natural_temp = 6500;
+ s->day_temp = 5500;
+ s->night_temp = 3500;
+ s->trans_speed = 50;
+#define BOOLEAN(var) var = !plus; break
#define PLUS(...) (plus ? (__VA_ARGS__) : 0)
ARGBEGIN {
case 'l':
PLUS(location_set = 0);
usage(!(p = strchr(arg = ARGF(), ':')));
*p++ = '\0', location_set = 1;
- usage(parse_location(arg, &(settings->latitude), 90.0));
- usage(parse_location(arg, &(settings->longitude), 180.0));
+ usage(parse_location(arg, &(s->latitude), 90.0));
+ usage(parse_location(p, &(s->longitude), 180.0));
break;
case 't':
- PLUS(settings->day_temp = 5500, settings->night_temp = 3500);
- settings->temp = settings->day_temp = settings->night_temp = 0;
- settings->temp_direction = 0;
+ PLUS(s->day_temp = 5500, s->night_temp = 3500);
+ s->temp = s->day_temp = s->night_temp = 0, s->temp_direction = 0;
if ((p = strchr(arg = ARGF(), ':'))) {
*p++ = '\0';
- usage(parse_temperature(arg, &(settings->day_temp), NULL, 1000));
- usage(parse_temperature(p, &(settings->night_temp), NULL, 1000));
+ usage(parse_temperature(arg, &(s->day_temp), NULL, 1000));
+ usage(parse_temperature(p, &(s->night_temp), NULL, 1000));
} else {
- usage(parse_temperature(arg, &(settings->temp), &(settings->temp_direction), 1000));
+ usage(parse_temperature(arg, &(s->temp), &(s->temp_direction), 1000));
}
break;
case 'T':
- PLUS(settings->natural_temp = 6500);
- usage(parse_temperature(ARGF(), &(settings->natural_temp), NULL, 1000));
+ PLUS(s->natural_temp = 6500);
+ usage(parse_temperature(ARGF(), &(s->natural_temp), NULL, 1000));
break;
case 's':
- PLUS(settings->trans_speed = 50);
- settings->trans_speed = 0;
- usage(parse_timespec(ARGF(), &(settings->transition)));
+ PLUS(s->trans_speed = 50);
+ s->trans_speed = 0;
+ usage(parse_timespec(ARGF(), &(s->transition)));
break;
case 'S':
- PLUS(settings->trans_speed = 0);
- usage(parse_temperature(ARGF(), &(settings->trans_speed), NULL, 1));
+ PLUS(s->trans_speed = 0);
+ usage(parse_temperature(ARGF(), &(s->trans_speed), NULL, 1));
break;
case 'h':
- settings->hookpath = (plus ? NULL : ARGF());
+ s->hookpath = (plus ? NULL : ARGF());
break;
case 'd': c++; /* Fall though. */
case 'e': c++; /* Fall though. */
case 'm': c++;
- PLUS(settings->monitors_n = 0, free(settings->monitors_id), free(settings->monitors_arg));
- settings->monitors_n++;
- xrealloc(&(settings->monitors_id), settings->monitors_n);
- xrealloc(&(settings->monitors_arg), settings->monitors_n);
- settings->monitors_id[settings->monitors_n - 1] = ARGF();
- settings->monitors_arg[settings->monitors_n - 1] = (c == 3 ? 'm' : c == 2 ? 'e' : 'd'), c = 0;
+ PLUS(s->monitors_n = 0, free(s->monitors_id), free(s->monitors_arg));
+ xrealloc(&(s->monitors_id), s->monitors_n + 1);
+ xrealloc(&(s->monitors_arg), s->monitors_n + 1);
+ s->monitors_id[s->monitors_n] = ARGF();
+ s->monitors_arg[s->monitors_n++] = (c == 3 ? 'm' : c == 2 ? 'e' : 'd'), c = 0;
break;
- case 'p': settings->print_status = !plus; break;
- case 'n': settings->panic_start = !plus; break;
- case 'N': settings->panic_else = !plus; break;
- case 'o': settings->set_and_exit = !plus; break;
- case 'x': settings->ignore_calib = !plus; break;
- case 'i': settings->negative = !plus; break;
- case 'b': settings->use_bus = !plus; break;
- default: usage(1); break;
+ case 'p': BOOLEAN(s->print_status);
+ case 'n': BOOLEAN(s->panic_start);
+ case 'N': BOOLEAN(s->panic_else);
+ case 'o': BOOLEAN(s->set_and_exit);
+ case 'x': BOOLEAN(s->ignore_calib);
+ case 'i': BOOLEAN(s->negative);
+ case 'b': BOOLEAN(s->use_bus);
+ default: usage(1); break;
} ARGEND;
usage(argc);
- if (!location_set && !(settings->temp)) {
+ if (!location_set && !(s->temp))
fprintf(stderr,
"%s: The -l option is mandatory, unless single value -t is used. "
"See `man 1 radharc` for more information.\n",
- !argv0 ? "radharc" : argv0);
- exit(2);
- }
+ !argv0 ? "radharc" : argv0), exit(2);
return;
fail:
@@ -254,18 +235,15 @@ marshal_settings(char *buffer, const struct settings *settings)
{
#define MARSHAL(N, DATUMP) (n += aux = (N), (buf ? (memcpy(buf, DATUMP, aux), buf += aux, 0) : 0))
- size_t n = 0, i = 0;
- size_t aux;
+ size_t aux, n = 0, i = 0;
char *buf = buffer;
if (buffer) i = marshal_settings(NULL, settings);
MARSHAL(sizeof(i), &i);
MARSHAL(sizeof(*settings), settings);
- if (settings->hookpath)
- MARSHAL(strlen(settings->hookpath) + 1, settings->hookpath);
- if (settings->monitors_arg)
- MARSHAL(settings->monitors_n, settings->monitors_arg);
+ if (settings->hookpath) MARSHAL(strlen(settings->hookpath) + 1, settings->hookpath);
+ if (settings->monitors_arg) MARSHAL(settings->monitors_n, settings->monitors_arg);
for (i = 0; i < settings->monitors_n; i++)
MARSHAL(strlen(settings->monitors_id[i]) + 1, settings->monitors_id[i]);
@@ -286,10 +264,8 @@ unmarshal_settings(char *buffer, struct settings **settings)
#define UNMARSHAL(N, DATUMP) (aux = (N), memcpy((DATUMP), buf, aux), buf += aux)
size_t n, aux, i;
- struct settings *s = NULL;
- struct settings s_;
+ struct settings s_, *s = NULL;
char *buf = buffer;
- int saved_errno;
UNMARSHAL(sizeof(n), &n);
if (!(s = *settings = malloc(n - sizeof(n)))) return 0;
@@ -297,12 +273,12 @@ unmarshal_settings(char *buffer, struct settings **settings)
UNMARSHAL(sizeof(s_), &s_);
if (s_.monitors_n) {
- try (*s = s_, s->monitors_id = malloc(s_.monitors_n * sizeof(char*)));
- try (*s = s_, s->monitors_arg = malloc(s_.monitors_n * sizeof(char)));
+ *s = s_;
+ xmalloc(&(s->monitors_id), s_.monitors_n);
+ xmalloc(&(s->monitors_arg), s_.monitors_n);
}
- s->hookpath = buf;
- buf = strchr(buf, '\0') + 1;
+ buf = strchr(s->hookpath = buf, '\0') + 1;
UNMARSHAL(s_.monitors_n, s->monitors_arg);
for (i = 0; i < s_.monitors_n; i++)
@@ -311,9 +287,7 @@ unmarshal_settings(char *buffer, struct settings **settings)
return n;
fail:
- saved_errno = errno;
- free(s->monitors_id), free(s->monitors_arg), free(s), *settings = NULL;
- errno = saved_errno;
+ CLEANUP(free(s->monitors_id), free(s->monitors_arg), free(s), *settings = NULL);
return 0;
}
diff --git a/src/settings.h b/src/settings.h
index e163e53..492e4b0 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -135,11 +135,11 @@ struct settings {
/**
* Parse the command line.
*
- * @param argc The number of elements in `argv`.
- * @param argv The commnad line arguments including the zeroth elemenet.
- * @param settings Output parameter for the settings.
+ * @param argc The number of elements in `argv`.
+ * @param argv The commnad line arguments including the zeroth elemenet.
+ * @param s Output parameter for the settings.
*/
-void parse_command_line(int argc, char *argv[], struct settings *settings);
+void parse_command_line(int argc, char *argv[], struct settings *s);
/**
diff --git a/src/solar.c b/src/solar.c
index cbee27d..8a57507 100644
--- a/src/solar.c
+++ b/src/solar.c
@@ -20,6 +20,12 @@
+#if !defined(CLOCK_REALTIME_COARSE)
+# define CLOCK_REALTIME_COARSE CLOCK_REALTIME
+#endif
+
+
+
/**
* Get current Julian Centuries time (100 Julian days since J2000.)
*
@@ -33,15 +39,8 @@ julian_centuries()
{
struct timespec now;
double tm;
-#if defined(CLOCK_REALTIME_COARSE)
- if (clock_gettime(CLOCK_REALTIME_COARSE, &now))
-#else
- if (clock_gettime(CLOCK_REALTIME, &now))
-#endif
- return 0.0;
- tm = (double)(now.tv_nsec);
- tm /= 1000000000.0;
- tm += (double)(now.tv_sec);
+ if (clock_gettime(CLOCK_REALTIME_COARSE, &now)) return 0.0;
+ tm = (double)(now.tv_nsec) / 1000000000.0 + (double)(now.tv_sec);
tm = (tm / 86400.0 + 2440587.5 - 2451545.0) / 36525.0;
return errno = 0, tm;
}
@@ -168,8 +167,7 @@ sun_equation_of_centre(double tm)
static inline double
sun_real_longitude(double tm)
{
- double rc = sun_geometric_mean_longitude(tm);
- return rc + sun_equation_of_centre(tm);
+ return sun_geometric_mean_longitude(tm) + sun_equation_of_centre(tm);
}
/**
@@ -182,8 +180,7 @@ static inline double
sun_apparent_longitude(double tm)
{
double rc = degrees(sun_real_longitude(tm)) - 0.00569;
- rc -= 0.00478 * sin(radians(-1934.136 * tm + 125.04));
- return radians(rc);
+ return radians(rc - 0.00478 * sin(radians(-1934.136 * tm + 125.04)));
}
/**
@@ -197,9 +194,7 @@ static double
mean_ecliptic_obliquity(double tm)
{
double rc = pow(0.001813 * tm, 3.0) - pow(0.00059 * tm, 2.0) - 46.815 * tm + 21.448;
- rc = 26 + rc / 60;
- rc = 23 + rc / 60;
- return radians(rc);
+ return radians(23.0 + (26.0 + rc / 60.0) / 60.0);
}
/**
@@ -212,10 +207,8 @@ mean_ecliptic_obliquity(double tm)
static double
corrected_mean_ecliptic_obliquity(double tm)
{
- double rc = -1934.136 * tm + 125.04;
- rc = 0.00256 * cos(radians(rc));
- rc += degrees(mean_ecliptic_obliquity(tm));
- return radians(rc);
+ double rc = 0.00256 * cos(radians(-1934.136 * tm + 125.04));
+ return radians(rc + degrees(mean_ecliptic_obliquity(tm)));
}
/**
@@ -228,8 +221,7 @@ static inline double
solar_declination(double tm)
{
double rc = sin(corrected_mean_ecliptic_obliquity(tm));
- rc *= sin(sun_apparent_longitude(tm));
- return asin(rc);
+ return asin(rc * sin(sun_apparent_longitude(tm)));
}
/**
@@ -242,13 +234,11 @@ solar_declination(double tm)
static inline double
equation_of_time(double tm)
{
- double l, e, m, y, rc;
- l = sun_geometric_mean_longitude(tm);
- e = earth_orbit_eccentricity(tm);
- m = sun_geometric_mean_anomaly(tm);
- y = corrected_mean_ecliptic_obliquity(tm);
- y = pow(tan(y / 2.0), 2.0);
- rc = y * sin(2.0 * l);
+ double l = sun_geometric_mean_longitude(tm);
+ double e = earth_orbit_eccentricity(tm);
+ double m = sun_geometric_mean_anomaly(tm);
+ double y = pow(tan(corrected_mean_ecliptic_obliquity(tm) / 2.0), 2.0);
+ double rc = y * sin(2.0 * l);
rc += (4.0 * y * cos(2.0 * l) - 2.0) * e * sin(m);
rc -= pow(0.5 * y, 2.0) * sin(4.0 * l);
rc -= pow(1.25 * e, 2.0) * sin(2.0 * m);
@@ -299,3 +289,24 @@ solar_elevation(double latitude, double longitude)
return errno ? -1 : degrees(solar_elevation_from_time(tm, latitude, longitude));
}
+
+/**
+ * Exit if time the is before year 0 in J2000.
+ *
+ * @return 0 on success, -1 on error.
+ */
+#if defined(TIMETRAVELLER)
+int
+check_timetravel(void)
+{
+ struct timespec now;
+ if (clock_gettime(CLOCK_REALTIME, &now)) return -1;
+ if (now.tv_nsec < (time_t)946728000L)
+ fprintf(stderr, "We have detected that you are a time-traveller"
+ "(or your clock is not configured correctly.)"
+ "Please recompile with -DTIMETRAVELLER"
+ "(or correct your clock.)"), exit(1);
+ return 0;
+}
+#endif
+
diff --git a/src/solar.h b/src/solar.h
index bb2def5..7afc78f 100644
--- a/src/solar.h
+++ b/src/solar.h
@@ -93,3 +93,15 @@
*/
double solar_elevation(double latitude, double longitude);
+
+/**
+ * Exit if time the is before year 0 in J2000.
+ *
+ * @return 0 on success, -1 on error.
+ */
+#if defined(TIMETRAVELLER)
+int check_timetravel(void);
+#else
+# define check_timetravel(_) 0
+#endif
+
diff --git a/src/state.c b/src/state.c
index 5640045..7e7509f 100644
--- a/src/state.c
+++ b/src/state.c
@@ -19,6 +19,7 @@
#include "macros.h"
#include <errno.h>
#include <limits.h>
+#include <stdarg.h>
#include <libgamma.h>
@@ -71,6 +72,43 @@ get_darkness(double elevation)
/**
+ * Remove the screen number for a display server instance identifier.
+ *
+ * @param s Display server instance identifier.
+ * @return Set the value to which this pointer points to '.'. Do nothing if it is `NULL`.
+ */
+static char *
+strip_screen(char *s)
+{
+#define S(V, CD) ((V = ((CD)[1] == 'r' ? strrchr : strchr)(V, (CD)[0])))
+ char *p = strchr(s, '=');
+ if ((p++) && (*p != '/') && S(p, ":r") && S(p, ".l")) *p = '\0'; else p = NULL;
+ return p;
+#undef S
+}
+
+
+/**
+ * `stpmulcpy(o, a, b, c, NULL)` is equivalent to
+ * `stpcpy(stpcpy(stpcpy(o, a), b), c)`
+ */
+#ifdef __GNUC__
+__attribute__((__sentinel__))
+#endif
+static char *
+stpmulcpy(char *out, ... /*, NULL */)
+{
+ va_list args;
+ char *p = out;
+ const char *s;
+ va_start(args, out);
+ while ((s = va_arg(args, const char *))) p = stpcpy(p, s);
+ va_end(args);
+ return p;
+}
+
+
+/**
* Compare two display server environment strings.
*
* @param a_ One of the string.
@@ -80,7 +118,6 @@ get_darkness(double elevation)
static int
displayenvcmp(const void *a_, const void *b_)
{
-#define S(V, CD) ((V = ((CD)[1] == 'r' ? strrchr : strchr)(V, (CD)[0])))
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
@@ -90,19 +127,14 @@ displayenvcmp(const void *a_, const void *b_)
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
- char *p = strchr(a, '=') + 1;
- char *q = strchr(b, '=') + 1;
+ char *p = strip_screen(a);
+ char *q = strip_screen(b);
int rc;
- if ((*p != '/') && S(p, ":r") && S(p, ".l")) *p = '\0'; else p = NULL;
- if ((*q != '/') && S(p, ":r") && S(p, ".l")) *q = '\0'; else q = NULL;
-
rc = strcmp(a, b);
-
- if (*p) *p = '.';
- if (*q) *q = '.';
+ if (p) *p = '.';
+ if (q) *q = '.';
return rc;
-#undef S
}
@@ -117,13 +149,11 @@ escape_display(const char* str)
{
char *r, *w, *rc = NULL;
int s = 0;
- xmalloc(&rc, 2 * strlen(str) + 1);
- strcpy(rc, str);
+ xmalloc(&rc, 2 * strlen(str) + 1); strcpy(rc, str);
for (r = w = strchr(rc, '=') + 1; *r; r++) {
if (!s || (*r != '/')) {
if (strchr("@=/", *r)) *w++ = '@';
- *w++ = (*r == '/' ? 's' : *r);
- s = (*r == '/');
+ *w++ = ((s = (*r == '/')) ? 's' : *r);
}
}
w[s ? -2 : 0] = '\0';
@@ -141,8 +171,10 @@ fail:
static char *
get_display_string(const struct settings *settings)
{
+#define DISPLAY(VAR, D) p = strip_screen(D); try (VAR = escape_display(D)); if (p) *p = '.', p = NULL
+
const char *var, *val;
- char *r, *d = NULL, *rc = NULL, **displays;
+ char *r, *p = NULL, *d = NULL, *rc = NULL, **displays;
size_t i, n = 0, len = 0;
int method;
@@ -157,28 +189,29 @@ get_display_string(const struct settings *settings)
fprintf(stderr, "No display was found.\n"
"DRM support missing.\n"
"Can you even see?\n");
- return free(displays), errno = 0, NULL;
+ return errno = 0, NULL;
}
var = libgamma_method_default_site_variable(method);
val = libgamma_method_default_site(method);
- if (!val) return strdup("");
+ if (!val || !*val) return strdup("");
xmalloc(&d, 3 + strlen(var) + strlen(val));
- stpcpy(stpcpy(stpcpy(stpcpy(d, "."), var), "="), val);
- try (rc = escape_display(d)); /* TODO strip screen number */
+ stpmulcpy(d, ".", var, "=", val, NULL);
+ DISPLAY(rc, d);
return free(d), rc;
custom:
qsort(displays, n, sizeof(*displays), displayenvcmp);
xmalloc(&rc, 2 * len + 1);
for (r = rc, i = 0; i < n; i++) {
- try (d = escape_display(displays[i])); /* TODO see above */
- r = stpcpy(stpcpy(r, "."), d), free(d), d = NULL;
+ DISPLAY(d, displays[i]);
+ r = stpmulcpy(r, ".", d, NULL), free(d), d = NULL;
}
free(displays);
return rc;
fail:
+ if (p) *p = '.';
CLEANUP(free(rc), free(d), free(displays));
return NULL;
}
@@ -200,7 +233,7 @@ get_state_pathname(const struct settings *settings)
try (display = get_display_string(settings));
if (!dir || !*dir) dir = "/run";
xmalloc(&env, strlen(dir) + sizeof("/radharc/") + strlen(display));
- stpcpy(stpcpy(stpcpy(env, dir), "/radharc/"), display);
+ stpmulcpy(env, dir, "/radharc/", display, NULL);
rc = setenv("RADHARC_STATE", env, 1);
fail:
CLEANUP(free(env), free(display));
@@ -217,12 +250,13 @@ fail:
static int
get_clut_method(const char *display)
{
-#define HAIKU(TEXT) t ((msg = (TEXT)))
+#define HAIKU(TEXT) t ((msg = (TEXT)))
+#define TEST(STR, ID) if (!strcasecmp(display, STR)) return ID
+ const char *env, *msg;
int method;
- const char *env;
- const char *msg;
+ /* Default? */
if (!display) {
if (!libgamma_list_methods(&method, 1, 0))
HAIKU("No display was found.\n"
@@ -230,18 +264,25 @@ get_clut_method(const char *display)
"Can you even see?\n");
return method;
}
- if (!strcasecmp(display, "none")) return INT_MAX;
- if (!strcasecmp(display, "drm")) return LIBGAMMA_METHOD_LINUX_DRM;
+
+ /* Single-sited? */
+ TEST("none", INT_MAX);
+ TEST("drm", LIBGAMMA_METHOD_LINUX_DRM);
+
+ /* Unrecognised single-sited? */
if (!strchr(display, '='))
HAIKU("Specified display\n"
"cannot be recognised.\n"
"Try something else.\n");
+ /* Multi-sited? */
for (method = 0; method < LIBGAMMA_METHOD_COUNT; method++) {
env = libgamma_method_default_site_variable(method);
if (env && (strstr(display, env) == display) && (display[strlen(env)] == '='))
return method;
}
+
+ /* Unrecognised multi-sited. */
HAIKU("Specified display\n"
"cannot be recognised.\n"
"Try to recompile.\n");
@@ -280,8 +321,7 @@ initialise_clut(const struct settings *settings)
sitename_ = strchr(sitename_, '=');
xstrdup(&sitename, sitename_ ? sitename_ + 1 : NULL);
t ((error = libgamma_site_initialise(sites + sites_n, method, sitename)));
- sitename = NULL;
- site = sites[sites_n++];
+ sitename = NULL, site = sites[sites_n++];
xrealloc(&parts, parts_n + site.partitions_available);
for (j = 0; j < site.partitions_available; j++) {
t ((error = libgamma_partition_initialise(parts + parts_n, &site, j)));