git/aika/main
c/neralie.c
154 lines4 KB last change raw · history
#define _POSIX_C_SOURCE 199309L

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <signal.h>
#include <sysexits.h>

static volatile sig_atomic_t keepRunning = 1;

void restoreCursor(int sig) {
    (void)sig;
    printf("\033[?25h\n");
    fflush(stdout);
    exit(0);
}

// Prints help/usage
void printHelp(const char *progName) {
    printf("Neralie %s\n", VERSION);
    printf("Usage: %s [OPTION]... [TIME]\n", progName);
    printf("Convert standard time to Neralie, or run a continuous clock.\n\n");
    printf("Options:\n");
    printf("  -c, --count    run in continuous count mode\n");
    printf("  -h, --help     display this help and exit\n");
    printf("  -v, --version  display version information and exit\n\n");
    printf("Arguments:\n");
    printf("  TIME           convert a specific time (formats: HH:MM:SS, HHMMSS, HH:MM, HHMM, HH)\n");
    printf("                 If omitted, prints the current local time.\n\n");
    printf("Examples:\n");
    printf("  %s             # Print current Neralie time\n", progName);
    printf("  %s -c          # Run live Neralie clock\n", progName);
    printf("  %s 14:30       # Convert 14:30:00 to Neralie\n", progName);
    printf("  %s 143000      # Convert 14:30:00 to Neralie\n", progName);
}

// Converts standard time to Neralie and prints it
void printNeralie(int h, int m, int s, long ns) {
    long ms = (h * 3600 + m * 60 + s) * 1000 + (ns / 1000000);
    long nera = (ms * 5) / 432;
    printf("%03ld:%03ld", nera / 1000, nera % 1000);
}

void prNera(void) {
    struct timespec ts;
    struct tm *tm;
    time_t t;

    clock_gettime(CLOCK_REALTIME, &ts);
    t = ts.tv_sec;
    tm = localtime(&t);

    printNeralie(tm->tm_hour, tm->tm_min, tm->tm_sec, ts.tv_nsec);
}

void countMode(void) {
    struct timespec req = {0, 86400000}; 
    printf("\033[?25l");

    signal(SIGINT, restoreCursor);
    signal(SIGTERM, restoreCursor);

    while (keepRunning) {
        printf("\r");
        prNera();
        fflush(stdout);
        nanosleep(&req, NULL);
    }

    restoreCursor(0);
}

void parseAndConvert(const char *input) {
    int h = 0, m = 0, s = 0;
    char clean[32];
    int j = 0;

    for (int i = 0; input[i] != '\0'; i++) {
        if (!isspace((unsigned char)input[i])) {
            if (j < (int)sizeof(clean) - 1) {
                clean[j++] = input[i];
            }
        }
    }
    clean[j] = '\0';

    if (strchr(clean, ':') != NULL) {
        int count = sscanf(clean, "%d:%d:%d", &h, &m, &s);
        if (count == 2) {
            s = 0;
        }
    } else {
        int len = strlen(clean);
        switch (len) {
            case 6: sscanf(clean, "%2d%2d%2d", &h, &m, &s); break;
            case 5: sscanf(clean, "%1d%2d%2d", &h, &m, &s); break;
            case 4: sscanf(clean, "%2d%2d", &h, &m); break;
            case 3: sscanf(clean, "%1d%2d", &h, &m); break;
            case 2: sscanf(clean, "%2d", &h); break;
            case 1: sscanf(clean, "%1d", &h); break;
            default:
                fprintf(stderr, "Error: Invalid time format. Use HH:MM[:SS] or HHMM[SS].\n");
                exit(EX_USAGE);
        }
    }

    if (h < 0 || h > 23 || m < 0 || m > 59 || s < 0 || s > 59) {
        fprintf(stderr, "Error: Invalid time values (Expected 00-23 for hours, 00-59 for min/sec).\n");
        exit(EX_DATAERR);
    }

    printNeralie(h, m, s, 0);
    printf("\n");
}

int main(int argc, char *argv[]) {
    if (argc > 1) {
        for (int i = 1; i < argc; i++) {
            if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
                printHelp(argv[0]);
                return 0;
            }
            if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
                printf("Neralie %s\n", VERSION);
                return 0;
            }
        }

        int countRequested = 0;
        if (argv[1][0] == '-' && argv[1][1] != '-') {
            for (int j = 1; argv[1][j] != '\0'; j++) {
                if (argv[1][j] == 'c') countRequested = 1;
            }
        } else if (strcmp(argv[1], "--count") == 0) {
            countRequested = 1;
        }

        if (countRequested) {
            countMode();
        } else if (argv[1][0] != '-') {
            parseAndConvert(argv[1]);
        } else {
            fprintf(stderr, "Error: Unknown argument '%s'\n", argv[1]);
            exit(EX_USAGE);
        }
    } else {
        prNera();
        printf("\n");
    }
    return 0;
}