commit 49fdf75c4198301a27bfa39606cc0b57a8ec8fc9 Author: Nathan Fisher Date: Mon Feb 5 11:23:45 2024 -0500 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..38088da --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +test/output/ +test/* +!test/*.c +!test/Makefile +*.o +*.a +*.so +*.so.* +*.core diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..31333f3 --- /dev/null +++ b/Makefile @@ -0,0 +1,93 @@ +# _,.---._ .-._ .--.-. ,--.--------. +# _,..---._ ,-.' , - `. /==/ \ .-._/==/ //==/, - , -\ +# /==/, - \ /==/_, , - \|==|, \/ /, |==\ -\\==\.-. - ,-./ +# |==| _ _\==| .=. |==|- \| | \==\- \`--`\==\- \ +# |==| .=. |==|_ : ;=: - |==| , | -| `--`-' \==\_ \ +# |==|,| | -|==| , '=' |==| - _ | |==|- | +# |==| '=' /\==\ - ,_ /|==| /\ , | |==|, | +# |==|-, _`/ '.='. - .' /==/, | |- | /==/ -/ +# `-.`.____.' `--`--'' `--`./ `--` `--`--` +# _ __ ,---. .-._ .=-.-. _,.----. +# .-`.' ,`..--.' \ /==/ \ .-._ /==/_ /.' .' - \ +# /==/, - \==\-/\ \ |==|, \/ /, /==|, |/==/ , ,-' +# |==| _ .=. /==/-|_\ | |==|- \| ||==| ||==|- | . +# |==| , '=',\==\, - \ |==| , | -||==|- ||==|_ `-' \ +# |==|- '..'/==/ - ,| |==| - _ ||==| ,||==| _ , | +# |==|, | /==/- /\ - \|==| /\ , ||==|- |\==\. / +# /==/ - | \==\ _.\=\.-'/==/, | |- |/==/. / `-.`.___.-' +# `--`---' `--` `--`./ `--``--`-` +# +# @(#)Copyright (c) 2024, Nathan D. Fisher. +# +# This is free software. It comes with NO WARRANTY. +# Permission to use, modify and distribute this source code +# is granted subject to the following conditions. +# 1/ that the above copyright notice and this notice +# are preserved in all copies and that due credit be given +# to the author. +# 2/ that any changes to this code are clearly commented +# as such so that the author does not get blamed for bugs +# other than his own. +# + +include config.mk + +.SUFFIXES: +.SUFFIXES: .o .c + +libname = epoch + +CFLAGS += -Wall -Werror +CFLAGS += -Iinclude +CFLAGS += -fPIC + +hdrs += include/epoch.h + +srcs += epoch.c +srcs += month.c +srcs += weekday.c +srcs += year.c +srcs += zone.c + +objs = $(srcs:.c=.o) + +all: shared static + +shared: lib$(libname).so + +static: lib$(libname).a + +$(srcs): $(hdrs) + +lib$(libname).a: $(objs) + $(AR) rcs $@ $? + +lib$(libname).so: $(objs) + $(CC) -shared -o $@ $? $(LIBS) + +install: install_include install_shared install_static + +install_include: include/$(libname).h + @[ -d $(includedir) ] || install -d $(includedir) + install -m644 include/$(libname).h $(includedir)/ + +install_static: lib$(libname).a + @[ -d $(libdir) ] || install -d $(libdir) + install -m644 lib$(libname) $(libdir)/ + +install_shared: lib$(libname).so + @[ -d $(libdir) ] || install -d $(libdir) + install -m755 lib$(libname).so $(libdir)/ + +test: lib$(libname).a + $(MAKE) -C test + +testclean: + $(MAKE) -C test clean + +clean: + rm -rf *.a *.so *.o haggis + $(MAKE) -C test clean + +.PHONY: all shared static clean install install_include install_static \ + install_shared testclean test diff --git a/compile_flags.txt b/compile_flags.txt new file mode 100644 index 0000000..49d52dd --- /dev/null +++ b/compile_flags.txt @@ -0,0 +1,3 @@ +-I +include + diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..e69de29 diff --git a/epoch.c b/epoch.c new file mode 100644 index 0000000..e69de29 diff --git a/include/epoch.h b/include/epoch.h new file mode 100644 index 0000000..d237424 --- /dev/null +++ b/include/epoch.h @@ -0,0 +1,88 @@ +#ifndef LIBEPOCH_H +#define LIBEPOCH_H 1 + +#include + +#define SECONDS_PER_MINUTE 60 +#define SECONDS_PER_HOUR 60 * 60 +#define SECONDS_PER_DAY 60 * 60 * 24 + +typedef enum { + normalYear, + leapYear, +} yearTag; + +typedef struct { + yearTag tag; + uint32_t year; +} Year; + +typedef enum { + January = 1, + February = 2, + March = 3, + April = 4, + May = 5, + June = 6, + July = 7, + August = 8, + September = 9, + October = 10, + November = 11, + December = 12, +} Month; + +typedef enum { + Thursday = 0, + Friday = 1, + Saturday = 2, + Sunday = 3, + Monday = 4, + Tuesday = 5, + Wednesday = 6, +} Weekday; + +typedef enum { + Offset, + UTC, +} timeZoneTag; + +typedef enum { + Positive, + Negative, +} offsetSign; + +typedef struct { + offsetSign sign; + uint8_t hours; + uint8_t minutes; +} TzOffset; + +typedef struct { + timeZoneTag tag; + TzOffset *offset; +} TimeZone; + +void yearNew(Year *year, int32_t inner); +uint16_t yearGetDays(Year *year); +int64_t yearGetSeconds(Year *year); +int32_t yearGetInner(Year *year); +void yearIncrement(Year *year); +void yearDecrement(Year *year); + +uint8_t monthGetDays(Month month, Year *year); +uint32_t monthGetSeconds(Month month, Year *year); +int monthIncrement(Month *month); +int monthDecrement(Month *month); +const char* monthName(Month month); +const char* monthAbbr(Month month); +int parseMonth(const char *s); + +const char* weekdayName(Weekday day); +const char* weekdayAbbr(Weekday day); +int parseWeekday(const char *s); + +int offsetNew(TzOffset *offs, offsetSign sign, uint8_t hours, uint8_t minutes); +void printTz(TimeZone *zone); + +#endif // !LIBEPOCH_H diff --git a/month.c b/month.c new file mode 100644 index 0000000..d28fa0a --- /dev/null +++ b/month.c @@ -0,0 +1,69 @@ +#include +#include // NULL +#include // memcmp +#include +#include "epoch.h" + +uint8_t monthGetDays(Month month, Year *year) { + switch (month) { + case January: + case March: + case May: + case July: + case August: + case October: + case December: + return 31; + case February: + switch (year->tag) { + case leapYear: + return 28; + default: + return 29; + } + default: + return 30; + } +} + +uint32_t monthGetSeconds(Month month, Year *year) { + return (int64_t)monthGetDays(month, year) * SECONDS_PER_DAY; +} + +int monthIncrement(Month *month) { + if (*month == December) + return 1; + else + *month += 1; + return 0; +} + +int monthDecrement(Month *month) { + if (*month == January) + return 1; + else + *month -= 1; + return 0; +} + +const char *MonthNames[] = { "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" }; +const char *MonthAbbrs[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", + "Aug", "Sep", "Oct", "Nov", "Dec" }; + +const char* monthName(Month month) { + return MonthNames[month - 1]; +} + +const char* monthAbbr(Month month) { + return MonthAbbrs[month - 1]; +} + +int parseMonth(const char *s) { + int i; + for (i = 0; i < 12; i++) { + if (strncasecmp(s, MonthAbbrs[i], 4) == 0 || strncasecmp(s, MonthNames[i], 10) == 0) + return i + 1; + } + return -1; +} diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..1b492c1 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,110 @@ +# _,.---._ .-._ .--.-. ,--.--------. +# _,..---._ ,-.' , - `. /==/ \ .-._/==/ //==/, - , -\ +# /==/, - \ /==/_, , - \|==|, \/ /, |==\ -\\==\.-. - ,-./ +# |==| _ _\==| .=. |==|- \| | \==\- \`--`\==\- \ +# |==| .=. |==|_ : ;=: - |==| , | -| `--`-' \==\_ \ +# |==|,| | -|==| , '=' |==| - _ | |==|- | +# |==| '=' /\==\ - ,_ /|==| /\ , | |==|, | +# |==|-, _`/ '.='. - .' /==/, | |- | /==/ -/ +# `-.`.____.' `--`--'' `--`./ `--` `--`--` +# _ __ ,---. .-._ .=-.-. _,.----. +# .-`.' ,`..--.' \ /==/ \ .-._ /==/_ /.' .' - \ +# /==/, - \==\-/\ \ |==|, \/ /, /==|, |/==/ , ,-' +# |==| _ .=. /==/-|_\ | |==|- \| ||==| ||==|- | . +# |==| , '=',\==\, - \ |==| , | -||==|- ||==|_ `-' \ +# |==|- '..'/==/ - ,| |==| - _ ||==| ,||==| _ , | +# |==|, | /==/- /\ - \|==| /\ , ||==|- |\==\. / +# /==/ - | \==\ _.\=\.-'/==/, | |- |/==/. / `-.`.___.-' +# `--`---' `--` `--`./ `--``--`-` +# +# @(#)Copyright (c) 2023, Nathan D. Fisher. +# +# This is free software. It comes with NO WARRANTY. +# Permission to use, modify and distribute this source code +# is granted subject to the following conditions. +# 1/ that the above copyright notice and this notice +# are preserved in all copies and that due credit be given +# to the author. +# 2/ that any changes to this code are clearly commented +# as such so that the author does not get blamed for bugs +# other than his own. +# + +include ../config.mk + +CFLAGS += -I../include +LDLIBS += ../libhaggis.a +LDLIBS += $(LIBS) + +tests += store_u16 +tests += load_u16 +tests += store_u32 +tests += load_u32 +tests += store_u64 +tests += load_u64 +tests += store_header +tests += check_header +tests += store_device +tests += load_device +tests += store_md5 +tests += load_md5 +tests += store_sha1 +tests += load_sha1 +tests += store_sha256 +tests += load_sha256 +tests += init_file_md5 +tests += init_file_sha1 +tests += init_file_sha256 +tests += store_file_md5 +tests += load_file_md5 +tests += store_file_sha1 +tests += load_file_sha1 +tests += store_file_sha256 +tests += load_file_sha256 +tests += fnv1a_hash_inode +tests += fnv1a_hash_str +tests += linkmap_init +tests += linkmap_put +tests += create_dir_node +tests += create_symlink_node +tests += create_fifo_node +tests += create_dev_node +tests += create_file_node +tests += mq_push_pop +tests += extract_dev_node +tests += extract_dir_node +tests += extract_fifo_node +tests += extract_file_node +tests += extract_symlink_node +tests += extract_hardlink_node + +total != echo $(tests) | wc -w | awk '{ print $$1 }' + +.PHONY: test +test: $(tests) output + @echo -e "\n\t=== \e[0;33mRunning $(total) tests\e[0m ===\n" + @idx=1 ; success=0 ; fail=0; skip=0; for t in $(tests) ; \ + do printf "[%02i/$(total)] %-25s" $${idx} $${t} ; \ + idx=$$(expr $${idx} + 1) ; \ + ./$${t} ; \ + retval=$$? ; \ + if [ $${retval} -eq 0 ] ; \ + then echo -e '\e[0;32mSuccess\e[0m' ; \ + success=$$(expr $${success} + 1) ; \ + elif [ $${retval} -eq 255 ] ; \ + then echo Skipped ; \ + skip=$$(expr $${skip} + 1) ; \ + else echo -e '\e[0;31mFailure\e[0m' ; \ + fail=$$(expr $${fail} + 1) ; \ + fi ; done || true ; \ + if [ $${fail} == 0 ] ; \ + then echo -e '\nResults: \e[0;32mOk\e[0m.' "$${success} succeeded; $${fail} failed; $${skip} skipped" ; \ + else echo -e '\nResults: \e[0;31mFAILED\e[0m.' "$${success} succeeded; $${fail} failed; $${skip} skipped" ; \ + fi + +output: + @ [-d $@ ] 2>/dev/null || install -d $@ + +.PHONY: clean +clean: + rm -rf $(tests) output/* diff --git a/weekday.c b/weekday.c new file mode 100644 index 0000000..abed36a --- /dev/null +++ b/weekday.c @@ -0,0 +1,24 @@ +#include "epoch.h" +#include + +const char *WeekdayNames[] = { "Thursday", "Friday", "Saturday", "Sunday", "Monday", + "Tuesday", "Wednesday" }; +const char *WeekdayAbbrs[] = { "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed" }; + +const char* weekdayName(Weekday day) { + return WeekdayNames[day]; +} + +const char* weekdayAbbr(Weekday day) { + return WeekdayAbbrs[day]; +} + +int parseWeekday(const char *s) { + int i; + for (i = 0; i < 7; i++) { + if (strncasecmp(s, WeekdayAbbrs[i], 4) == 0 || strncasecmp(s, WeekdayNames[i], 10) == 0) { + return i; + } + } + return -1; +} diff --git a/year.c b/year.c new file mode 100644 index 0000000..63b1949 --- /dev/null +++ b/year.c @@ -0,0 +1,45 @@ +#include +#include "epoch.h" + +void yearNew(Year *year, int32_t inner) { + year->year = inner; + if (inner % 4 == 0 && (inner % 100 != 0 || inner % 400 == 0)) + year->tag = leapYear; + else + year->tag = normalYear; +} + +uint16_t yearGetDays(Year *year) { + switch (year->tag) { + case normalYear: + return 365; + case leapYear: + return 366; + default: + return 365; + } +} + +int64_t yearGetSeconds(Year *year) { + return (int64_t)yearGetDays(year) * SECONDS_PER_DAY; +} + +int32_t yearGetInner(Year *year) { + return year->year; +} + +void yearIncrement(Year *year) { + year->year += 1; + if (year->year % 4 == 0 && (year->year % 100 != 0 || year->year % 400 == 0)) + year->tag = leapYear; + else + year->tag = normalYear; +} + +void yearDecrement(Year *year) { + year->year -= 1; + if (year->year % 4 == 0 && (year->year % 100 != 0 || year->year % 400 == 0)) + year->tag = leapYear; + else + year->tag = normalYear; +} diff --git a/zone.c b/zone.c new file mode 100644 index 0000000..ea9aa96 --- /dev/null +++ b/zone.c @@ -0,0 +1,33 @@ +#include "epoch.h" +#include +#include +#include + +int offsetNew(TzOffset *offs, offsetSign sign, uint8_t hours, uint8_t minutes) { + if (offs == NULL) return 1; + if (hours > 12) return 2; + if (hours > 11 && minutes > 0) return 3; + if (minutes > 59) return 4; + offs->sign = sign; + offs->hours = hours; + offs->minutes = minutes; + return 0; +} + +void printTz(TimeZone *zone) { + switch (zone->tag) { + case UTC: printf("UTC"); + case Offset: + switch (zone->offset->sign) { + case Positive: + puts("+"); + break; + case Negative: + puts("-"); + break; + } + default: + break; + printf("%.2u:%.2u", zone->offset->hours, zone->offset->minutes); + } +}