/*
 * Native Windows Program, does not need libc.
 *
 * Compile with:
 * cl -nologo -W3 -O2 -GA -Zl -GS- test_uk1.c \
 *    memcpy64.obj strlen64.obj strcmp64.obj \
 *    -link -release -nodefaultlib -entry:xmain -subsystem:console -map kernel32.lib
 */
#define UNICODE
#define _UNICODE

#include <windows.h>
#include <tchar.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>


static INT fill_buf(HANDLE fh, BYTE *buf, SIZE_T len)
{
    DWORD n;

    if (!ReadFile(fh, buf, (DWORD)len, &n, NULL))
        return -1;
    return n;
}


static INT write_buf(HANDLE fh, BYTE *buf, SIZE_T len)
{
    DWORD n;

    if (!WriteFile(fh, buf, (DWORD)len, &n, NULL))
        return -1;
    return 0;
}


static PVOID SysAlloc(SIZE_T size)
{
#define NtCurrentProcess() ((HANDLE)-1)
    return VirtualAllocEx(NtCurrentProcess(),
            NULL, size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
}


#define NELEM(ar) (sizeof(ar)/sizeof(*ar))
#define FIELDLEN 4096
#define BUFLEN (16*4096)
#define IBUFLEN (BUFLEN + FIELDLEN)


VOID xmain()
{
    SIZE_T i, n, m;
    HANDLE fin, fout;
    PBYTE p, s, ptr, end, buf, outbuf, field[64];

    fin = CreateFile(TEXT("list.txt"), GENERIC_READ, 0, NULL,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (fin == INVALID_HANDLE_VALUE)
E:      ExitProcess(-1);

    fout = CreateFile(TEXT("nodup.txt"), GENERIC_WRITE, 0, NULL,
            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (fout == INVALID_HANDLE_VALUE)
        goto E;

    buf = SysAlloc(2*IBUFLEN + BUFLEN);
    if (!buf)
        goto E;

    outbuf = buf + 2*IBUFLEN;

    s = outbuf;

    end = ptr = buf;
    i = 1;
    field[0] = buf;

    for (;;) {

        if (ptr == end) {
            n = ptr - field[i - 1];
            p = buf + IBUFLEN;

            if (end <= p)
                ptr = p;
            else
                ptr = buf;

            memcpy(ptr, field[i - 1], n);
            field[i - 1] = ptr;
            ptr += n;

            if ((n = fill_buf(fin, ptr, BUFLEN)) <= 0)
                break;

            end = ptr + n;
        }

        if (*ptr == ';') {
            *ptr++ = 0;
            field[i++] = ptr;
        }
        else if (*ptr == '\n') {

            i--;
#if 1
            if (i > 3) {
                for (n = 3; n < i - 1; n++) {
                    for (m = n + 1; m < i; m++) {
                        if (strcmp(field[n], field[m]) == 0)
                            field[m][0] = 0;
                    }
                }
            }
#endif

            for (n = 0; n < i; n++) {
                if (!(p = field[n]))
                    continue;
                m = strlen(p);
                memcpy(s, p, m);
                s += m;
                *s++ = ';';
            }
            *s++ = '\n';

            m = s - outbuf;
            if (m > BUFLEN - FIELDLEN) {
                write_buf(fout, outbuf, m);
                s = outbuf;
            }

            i = 1;
            field[0] = ++ptr;
        }
        else
            ptr++;
    }

    write_buf(fout, outbuf, s - outbuf);

    ExitProcess(0);
}
