#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#include "kernel.h"

#define READATTR  5
#define READFILE  16
#define WRITEFILE 0

#define FILEFOUND 1

static void fail(char *errmsg, ...)
{
    va_list ap;

    va_start(ap, errmsg);
    vfprintf(stderr, errmsg, ap);
    va_end(ap);
    exit(1);
}

/* See Sedgewick: Algorithms 2nd edition P 108 */
static void sortstrings(char *a[], int n)
{
    int  h, i, j;
    char *v;

    h = 1;
    do
        h = h * 3 + 1;
    while (h <= n);
    do {
        h = h / 3;
        for (i = h + 1; i <= n; i++) {
            v = a[i];
            j = i;
            while (j > h && strcmp(a[j-h], v) > 0) {
                a[j] = a[j-h];
                j -= h;
            }
            a[j] = v;
        }
    } while (h > 1);
}

static void sortfile(char *infile, char *outfile)
{
    _kernel_osfile_block finfo;
    int size;
    char *finbuff, *foutbuff;
    char *cp;
    int  l, linestart;
    char **lbuff;
    int  i;

    if (_kernel_osfile(READATTR, infile, &finfo) != FILEFOUND)
        fail("Error opening %s\n", infile);
    size = finfo.start;
    finbuff = malloc(size + 1);
    foutbuff = malloc(size + 1);
    if ((finbuff == NULL) || (foutbuff == NULL))
        fail("Out of memory\n");
    finfo.load = (int) finbuff;
    finfo.exec = 0;
    if (_kernel_osfile(READFILE, infile, &finfo) < 0)
        fail("Error reading %s\n", infile);
    l = 0;
    cp = finbuff;
    linestart = 1;
    for (i = 0; i < size; i++) {
        if (linestart) {
            l++;
            linestart = 0;
        }
        if (!*cp || *cp == '\n') {
            *cp = 0;
            linestart = 1;
        }
        cp++;
    }
    *(finbuff + size) = 0;
    lbuff = malloc(l * sizeof(char *));
    if (lbuff == NULL)
        fail("Out of memory\n");
    cp = finbuff;
    for (i = 0; i < l; i++) {
        lbuff[i] = cp;
        cp += strlen(cp);
    }
    sortstrings(lbuff, l);
    cp = foutbuff;
    for (i = 0; i < l; i++) {
        strcpy(cp, lbuff[i]);
        cp += strlen(cp);
        *cp++ = '\n';
    }
    finfo.start = (int) foutbuff;
    finfo.end = (int) foutbuff + size;
    if (_kernel_osfile(WRITEFILE, outfile, &finfo) < 0)
        fail("Error writing %s\n", outfile);
    free(finbuff);
    free(foutbuff);
    free(lbuff);
}

int main(int argc, char *argv[])
{
    if (argc != 3)
        fail("Usage: Sort <infile> <outfile>");
    sortfile(argv[1], argv[2]);
    return 0;
}
