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