/*

reinhard@finalmedia.de
20260915
PUBLIC DOMAIN


musl-gcc -O3 -static-pie -fPIE -fstack-protector-strong -o hashline32 hashline32.c

using simple and fast 32bit non-cryptographic djb2 hash

*/

#include <unistd.h>

#define BUFSIZE 65536

typedef unsigned long long uint64;

uint64 djb2_64(const char *s, int len) {
    uint64 hash = 5381;
    while (len--) {
        hash = ((hash << 5) + hash) + (unsigned char)*s++;
    }
    return hash;
}

char out_buf[BUFSIZE];
int out_pos = 0;

void flush_out(void) {
    if (out_pos == 0) return;
    int pos = 0;
    while (pos < out_pos) {
        int w = write(1, out_buf + pos, out_pos - pos);
        if (w <= 0) _exit(111);
        pos += w;
    }
    out_pos = 0;
}

void put_buffered(const char *s, int len) {
    while (len > 0) {
        int space = BUFSIZE - out_pos;
        if (space == 0) {
            flush_out();
            space = BUFSIZE;
        }
        int chunk = (len < space) ? len : space;
        int i;
        for (i = 0; i < chunk; i++) {
            out_buf[out_pos++] = *s++;
        }
        len -= chunk;
    }
}

void put_hex64_buffered(uint64 n) {
    char buf[16];
    static const char hex[] = "0123456789abcdef";
    int i = 16;
    while (i > 0) {
        buf[--i] = hex[n & 15];
        n >>= 4;
    }
    put_buffered(buf, 16);
}

int main(void) {
    char in_buf[BUFSIZE];
    int rlen = 0;
    int pos = 0;

    while (1) {
        if (pos >= rlen) {
            int n = read(0, in_buf, BUFSIZE);
            if (n <= 0) break;
            rlen = n;
            pos = 0;
        }

        int start = pos;
        while (pos < rlen && in_buf[pos] != '\n') {
            pos++;
        }

        if (pos < rlen && in_buf[pos] == '\n') {
            pos++;
            put_hex64_buffered(djb2_64(in_buf + start, pos - start));
            put_buffered(" ", 1);
            put_buffered(in_buf + start, pos - start);
        } else {
            int left = rlen - start;
            if (left > 0 && start > 0) {
                int i;
                for (i = 0; i < left; i++) {
                    in_buf[i] = in_buf[start + i];
                }
            }
            int n = read(0, in_buf + left, BUFSIZE - left);
            if (n <= 0) {
                if (left > 0) {
                    put_hex64_buffered(djb2_64(in_buf, left));
                    put_buffered(" ", 1);
                    put_buffered(in_buf, left);
                    if (in_buf[left - 1] != '\n') put_buffered("\n", 1);
                }
                break;
            }
            rlen = left + n;
            pos = 0;
        }
    }

    flush_out();
    _exit(0);
}

