143 lines
4.4 KiB
C
143 lines
4.4 KiB
C
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "reading_io.h"
|
|
#include "significance.h"
|
|
|
|
static void print_usage(const char *prog) {
|
|
fprintf(stderr,
|
|
"Usage: %s [reading.json]\n\n"
|
|
"Reads a DailyReading in deck-engine's --format json shape - from the\n"
|
|
"given file, or from stdin if no file is given (or it is \"-\") - and\n"
|
|
"prints a significance report: the day's overall level and the top\n"
|
|
"aspects driving it.\n\n"
|
|
"Typical use:\n"
|
|
" dist/deck-engine ... --format json | %s\n"
|
|
" dist/deck-engine ... --format json > reading.json && %s reading.json\n",
|
|
prog, prog, prog);
|
|
}
|
|
|
|
static char *read_all(FILE *f, size_t *out_length) {
|
|
size_t cap = 4096;
|
|
size_t len = 0;
|
|
char *buf = malloc(cap);
|
|
|
|
size_t n;
|
|
while ((n = fread(buf + len, 1, cap - len, f)) > 0) {
|
|
len += n;
|
|
if (len == cap) {
|
|
cap *= 2;
|
|
buf = realloc(buf, cap);
|
|
}
|
|
}
|
|
buf = realloc(buf, len + 1);
|
|
buf[len] = '\0';
|
|
*out_length = len;
|
|
return buf;
|
|
}
|
|
|
|
/* Display names for the report - deliberately a small local table rather
|
|
* than linking engine/src/astro.c's astro_body_name()/astro_aspect_name()
|
|
* (which would pull in the vendored Astronomy Engine just for cosmetic
|
|
* text). Same policy as reading_io.c's slug tables. */
|
|
static const char *body_display_name(Body body) {
|
|
static const char *const names[NUM_BODIES] = {
|
|
"Sun", "Moon", "Mercury", "Venus", "Mars",
|
|
"Jupiter", "Saturn", "Uranus", "Neptune", "Pluto",
|
|
};
|
|
return names[body];
|
|
}
|
|
|
|
static const char *aspect_display_name(AspectType type) {
|
|
static const char *const names[5] = {
|
|
"Conjunction", "Sextile", "Square", "Trine", "Opposition",
|
|
};
|
|
return names[type];
|
|
}
|
|
|
|
static const char *sign_display_name(ZodiacSign sign) {
|
|
static const char *const names[12] = {
|
|
"Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo",
|
|
"Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces",
|
|
};
|
|
return names[sign];
|
|
}
|
|
|
|
/* pos->house is 0 when reading_load_json had no sign/house data for this
|
|
* body (see parse_bodies() in reading_io.c) - a valid whole-sign house
|
|
* is always 1-12, so this is a safe "unknown, say nothing" sentinel. */
|
|
static void print_body_in_sign(const PlanetPosition *pos) {
|
|
if (pos->house < 1 || pos->house > 12) return;
|
|
printf(" in %s (house %d)", sign_display_name(pos->sign), pos->house);
|
|
}
|
|
|
|
static const char *day_level_name(DaySignificance level) {
|
|
switch (level) {
|
|
case DAY_QUIET: return "Quiet";
|
|
case DAY_NOTABLE: return "Notable";
|
|
case DAY_SIGNIFICANT: return "Significant";
|
|
case DAY_MAJOR: return "Major";
|
|
}
|
|
return "Unknown";
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
if (argc > 2 || (argc == 2 && (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0))) {
|
|
print_usage(argv[0]);
|
|
return argc > 2 ? 1 : 0;
|
|
}
|
|
|
|
FILE *in = stdin;
|
|
bool opened_file = false;
|
|
if (argc == 2 && strcmp(argv[1], "-") != 0) {
|
|
in = fopen(argv[1], "r");
|
|
if (!in) {
|
|
fprintf(stderr, "error: could not open %s\n", argv[1]);
|
|
return 1;
|
|
}
|
|
opened_file = true;
|
|
}
|
|
|
|
size_t length;
|
|
char *text = read_all(in, &length);
|
|
if (opened_file) fclose(in);
|
|
|
|
DailyReading reading;
|
|
bool loaded = reading_load_json(text, length, &reading);
|
|
free(text);
|
|
if (!loaded) {
|
|
fprintf(stderr, "error: could not parse input as deck-engine --format json output\n");
|
|
return 1;
|
|
}
|
|
|
|
DailyInterpretation interp;
|
|
interpret_daily_reading(&reading, &interp);
|
|
|
|
printf("Day significance: %s\n", day_level_name(interp.day_level));
|
|
if (interpretation_deserves_framing(&interp)) {
|
|
printf("(a major transit today - worth a deeper Celtic Cross look)\n");
|
|
}
|
|
printf("\n");
|
|
|
|
if (interp.top_item_count == 0) {
|
|
printf("No notable transits today.\n");
|
|
return 0;
|
|
}
|
|
|
|
printf("Top %d significant transit%s:\n", interp.top_item_count,
|
|
interp.top_item_count == 1 ? "" : "s");
|
|
for (int i = 0; i < interp.top_item_count; i++) {
|
|
const SignificantItem *item = &interp.top_items[i];
|
|
const Aspect *a = &item->aspect;
|
|
|
|
printf(" %d. Transiting %s", i + 1, body_display_name(a->transiting_planet));
|
|
print_body_in_sign(&reading.transits.bodies[a->transiting_planet]);
|
|
printf(" %s natal %s", aspect_display_name(a->type), body_display_name(a->natal_planet));
|
|
print_body_in_sign(&reading.natal.bodies[a->natal_planet]);
|
|
printf(" (orb %.1f\xc2\xb0, score %.2f)\n", a->orb, item->score);
|
|
}
|
|
return 0;
|
|
}
|