#include #include #include #include #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; }