From 0ecf32be69d2f1fd9c1eb82588b881b4c2b670ea Mon Sep 17 00:00:00 2001 From: Rob Harbaugh Date: Wed, 5 Nov 2025 20:12:09 -0500 Subject: [PATCH] getting fancy with command line args --- src/args.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ src/args.h | 26 +++++++++++++ src/main.c | 110 +++++++++++++++++++++++------------------------------ 3 files changed, 177 insertions(+), 62 deletions(-) create mode 100644 src/args.c create mode 100644 src/args.h diff --git a/src/args.c b/src/args.c new file mode 100644 index 0000000..2dd6e59 --- /dev/null +++ b/src/args.c @@ -0,0 +1,103 @@ +#include "args.h" +#include +#include +#include + +void print_usage(const char *program_name) { + printf("Usage: %s [OPTIONS]\n", program_name); + printf("Calculate the church calendar for the current year.\n\n"); + printf("Options:\n"); + printf(" --all Print all days in the current liturgical year\n"); + printf(" --date MM-DD-YYYY Print the liturgical day for the specified date\n"); + printf(" --year YYYY Print all days in the specified year\n"); + printf(" --help Display this help message\n"); + printf("\nWith no options, prints only today's liturgical day.\n"); +} + +static int parse_date(const char *date_str, struct tm *date) { + int month, day, year; + + if (sscanf(date_str, "%d-%d-%d", &month, &day, &year) != 3) { + return -1; + } + + // Validate ranges + if (month < 1 || month > 12 || day < 1 || day > 31 || year < 1900 || year > 9999) { + return -1; + } + + memset(date, 0, sizeof(struct tm)); + date->tm_mon = month - 1; + date->tm_mday = day; + date->tm_year = year - 1900; + + // Normalize the date + if (mktime(date) == -1) { + return -1; + } + + return 0; +} + +int parse_args(int argc, char *argv[], ProgramArgs *args) { + // Initialize with defaults + args->mode = MODE_TODAY; + time_t now = time(NULL); + struct tm *today = localtime(&now); + args->target_date = *today; + args->target_year = today->tm_year + 1900; + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--help") == 0) { + print_usage(argv[0]); + return 1; + } else if (strcmp(argv[i], "--all") == 0) { + args->mode = MODE_ALL; + } else if (strcmp(argv[i], "--date") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "Error: --date requires a date argument (MM-DD-YYYY)\n"); + return -1; + } + + if (parse_date(argv[i + 1], &args->target_date) != 0) { + fprintf(stderr, "Error: Invalid date format '%s'. Use MM-DD-YYYY\n", argv[i + 1]); + return -1; + } + + args->mode = MODE_DATE; + args->target_year = args->target_date.tm_year + 1900; + i++; // Skip the date argument + } else if (strcmp(argv[i], "--year") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "Error: --year requires a year argument\n"); + return -1; + } + + char *endptr; + long year = strtol(argv[i + 1], &endptr, 10); + + if (*endptr != '\0' || year < 1900 || year > 9999) { + fprintf(stderr, "Error: Invalid year '%s'\n", argv[i + 1]); + return -1; + } + + args->mode = MODE_YEAR; + args->target_year = (int)year; + + // Set target_date to January 1 of that year for calendar generation + memset(&args->target_date, 0, sizeof(struct tm)); + args->target_date.tm_year = (int)(year - 1900); + args->target_date.tm_mon = 0; + args->target_date.tm_mday = 1; + mktime(&args->target_date); + + i++; // Skip the year argument + } else { + fprintf(stderr, "Unknown option: %s\n", argv[i]); + print_usage(argv[0]); + return -1; + } + } + + return 0; +} diff --git a/src/args.h b/src/args.h new file mode 100644 index 0000000..d63a599 --- /dev/null +++ b/src/args.h @@ -0,0 +1,26 @@ +#ifndef ARGS_H +#define ARGS_H + +#include + +typedef enum { + MODE_TODAY, + MODE_ALL, + MODE_DATE, + MODE_YEAR +} OutputMode; + +typedef struct { + OutputMode mode; + struct tm target_date; + int target_year; +} ProgramArgs; + +// Parse command line arguments +// Returns 0 on success, -1 on error, 1 if help was shown +int parse_args(int argc, char *argv[], ProgramArgs *args); + +// Print usage information +void print_usage(const char *program_name); + +#endif // ARGS_H diff --git a/src/main.c b/src/main.c index dfa89e5..d4899d6 100644 --- a/src/main.c +++ b/src/main.c @@ -1,17 +1,8 @@ #include -#include #include #include "church_day.h" #include "builder.h" - -static void print_usage(const char *program_name) { - printf("Usage: %s [OPTIONS]\n", program_name); - printf("Calculate the church calendar for the current year.\n\n"); - printf("Options:\n"); - printf(" --all Print all days in the liturgical year\n"); - printf(" --help Display this help message\n"); - printf("\nWith no options, prints only today's liturgical day.\n"); -} +#include "args.h" static int compare_dates(struct tm d1, struct tm d2) { if (d1.tm_year != d2.tm_year) return d1.tm_year - d2.tm_year; @@ -19,64 +10,59 @@ static int compare_dates(struct tm d1, struct tm d2) { return d1.tm_mday - d2.tm_mday; } -int main(int argc, char *argv[]) { - int print_all = 0; +static void print_day(const ChurchDay *day) { + printf("%s, %s %d, %d - %s - %s in %s\n", + church_day_weekday_string(day), + church_day_month_name(day), + day->date.tm_mday, + day->date.tm_year + 1900, + day->description, + day_class_to_string(day->class), + season_to_string(day->season)); +} - // Parse arguments - for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "--all") == 0) { - print_all = 1; - } else if (strcmp(argv[i], "--help") == 0) { - print_usage(argv[0]); - return 0; - } else { - fprintf(stderr, "Unknown option: %s\n", argv[i]); - print_usage(argv[0]); - return 1; - } +int main(int argc, char *argv[]) { + ProgramArgs args; + int parse_result = parse_args(argc, argv, &args); + + if (parse_result == 1) { + // Help was shown + return 0; + } else if (parse_result == -1) { + // Error occurred + return 1; } - time_t now = time(NULL); - struct tm *today = localtime(&now); + ChurchYear seasons = proper_of_seasons(args.target_date); - ChurchYear seasons = proper_of_seasons(*today); - - if (print_all) { - // Print all days - for (size_t i = 0; i < seasons.count; i++) { - ChurchDay *day = &seasons.days[i]; - printf("%s, %s %d, %d - %s - %s in %s\n", - church_day_weekday_string(day), - church_day_month_name(day), - day->date.tm_mday, - day->date.tm_year + 1900, - day->description, - day_class_to_string(day->class), - season_to_string(day->season)); - } - } else { - // Print only today - ChurchDay *found = NULL; - for (size_t i = 0; i < seasons.count; i++) { - if (compare_dates(seasons.days[i].date, *today) == 0) { - found = &seasons.days[i]; - break; + switch (args.mode) { + case MODE_ALL: + case MODE_YEAR: + // Print all days + for (size_t i = 0; i < seasons.count; i++) { + print_day(&seasons.days[i]); } - } + break; - if (found) { - printf("%s, %s %d, %d - %s - %s in %s\n", - church_day_weekday_string(found), - church_day_month_name(found), - found->date.tm_mday, - found->date.tm_year + 1900, - found->description, - day_class_to_string(found->class), - season_to_string(found->season)); - } else { - fprintf(stderr, "Could not find today's date in the liturgical calendar.\n"); - church_year_free(&seasons); - return 1; + case MODE_TODAY: + case MODE_DATE: { + // Print only the specified day + ChurchDay *found = NULL; + for (size_t i = 0; i < seasons.count; i++) { + if (compare_dates(seasons.days[i].date, args.target_date) == 0) { + found = &seasons.days[i]; + break; + } + } + + if (found) { + print_day(found); + } else { + fprintf(stderr, "Could not find the specified date in the liturgical calendar.\n"); + church_year_free(&seasons); + return 1; + } + break; } }