#include <com32.h>
#include <string.h>
#include "ctime.h"

static uint8_t frombcd(uint8_t v)
{
    uint8_t a = v & 0x0f;
    uint8_t b = v >> 4;

    return a + b*10;
}

uint32_t posix_time(void)
{
    /* Days from March 1 for a specific month, starting in March */
    static const unsigned int yday[12] =
	{ 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337 };
    com32sys_t ir, d0, d1, t0;
    unsigned int c, y, mo, d, h, m, s;
    uint32_t t;

    memset(&ir, 0, sizeof ir);

    ir.eax.b[1] = 0x04;
    __intcall(0x1A, &ir, &d0);

    ir.eax.b[1] = 0x02;
    __intcall(0x1A, &ir, &t0);

    ir.eax.b[1] = 0x04;
    __intcall(0x1A, &ir, &d1);

    if (t0.ecx.b[1] < 0x12)
	d0 = d1;

    c  = frombcd(d0.ecx.b[1]);
    y  = frombcd(d0.ecx.b[0]);
    mo = frombcd(d0.edx.b[1]);
    d  = frombcd(d0.edx.b[0]);

    h  = frombcd(t0.ecx.b[1]);
    m  = frombcd(t0.ecx.b[0]);
    s  = frombcd(t0.edx.b[1]);

    /* We of course have no idea about the timezone, so ignore it */

    /*
     * Look for impossible dates... this code was written in 2010, so
     * assume any century less than 20 is just broken.
     */
    if (c < 20)
	c = 20;
    y += c*100;

    /* Consider Jan and Feb as the last months of the previous year */
    if (mo < 3) {
	y--;
	mo += 12;
    }

    /*
     * Just in case: if the month is nonsense, don't read off the end
     * of the table...
     */
    if (mo-3 > 11)
	return 0;

    t = y*365 + y/4 - y/100 + y/400 + yday[mo-3] + d - 719469;
    t *= 24;
    t += h;
    t *= 60;
    t += m;
    t *= 60;
    t += s;

    return t;
}
