/* 'checkit_tiff' is a conformance checker for baseline TIFFs
 *
 * author: Andreas Romeyke, 2015-2022
 * licensed under conditions of libtiff
 * (see http://libtiff.maptools.org/misc.html)
 *
 *  this module implements a recursive descent parser
 */
#include <assert.h>
#include <ctype.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    int ctx;
    size_t consumed;
    char * buff;
    size_t size;
} input_t;

const char eol='\n';

static input_t * dup_input(input_t * after) {
    input_t * dup = alloca( sizeof(input_t) );
    dup->consumed = after->consumed;
    dup->size = after->size;
    dup->ctx = after->ctx;
    dup->buff = after->buff;
    return dup;
}

static char * take (const input_t * before, const input_t * after) {
    ssize_t len = after->consumed - before->consumed;
    assert(len >= 0);
    char *newstr = calloc(sizeof(char), len + 1);
    if (NULL == newstr) {
        perror("could not allocate memory for string\n");
        exit(EXIT_FAILURE);
    }
    if (len > 0) {
        strncpy(newstr, before->buff + before->consumed, len);
    }
    return newstr;
}

static bool preview_if_ch(const input_t * input, const char ch) {
    if (input->size > 0 && input->consumed < input->size) {
        if (input->buff[input->consumed] == ch) {
            return true;
        }
    }
    return false;
}


static bool eat_if_ch(input_t * input, const char ch) {
    if (preview_if_ch(input, ch)) {
        input->consumed++;
        return true;
    }
    return false;
}

static bool preview_if(input_t * input, const char * string) {
    if (input->size > 0) {
        if (NULL != string) {
            size_t consumed = input->consumed;
            while (
                    (consumed < input->size)
                    && ( string[consumed - input->consumed] != '\0' )
                    && (input->buff[consumed] == string[consumed - input->consumed])
                    ) {
                consumed++;
            }
            if (consumed == strlen(string)) {
                return true;
            }
        }
    }
    return false;
}
static bool eat_if(input_t * input, const char * string) {
    if (input->size > 0) {
        if (NULL != string) {
            size_t consumed = input->consumed;
            while (
                    (consumed < input->size)
                    && ( string[consumed - input->consumed] != '\0' )
                    && (input->buff[consumed] == string[consumed - input->consumed])
                    ) {
                consumed++;
            }
            if (consumed == strlen(string)) {
                input->consumed = consumed;
                return true;
            }
        }
    }
    return false;
}

static bool preview_until(input_t * input, const char disgusting) {
    for (size_t i=input->consumed; i<input->size; i++) {
        if (input->buff[i] == disgusting) {
            return true;
        }
    }
    return false;
}

static bool eat_until(input_t * input, const char disgusting) {
    for (size_t i=input->consumed; i<input->size; i++) {
        if (input->buff[i] == disgusting) {
            if (i > input->consumed) {
                input->consumed=i-1;
            }
            return true;
        }
    }
    return false;
}

static bool prs_commentline(input_t * input) {
    if (eat_if_ch(input, eol)) {
        eat_until(input, eol);
        return true;
    }
    return false;
}

static bool prs_path(input_t * input) {
    /*
      [A-Z]
      [a-z]
      [0-9]
      '.'
      '_'
      '-'
      SlashorBackslash
    */
    for (size_t i=input->consumed; i<input->size; i++) {
        char ch = input->buff[i];
        if (!isalnum(ch) && ch != '.' && ch != '_' && ch != '-' && ch != '/' && ch != '\\') {
            if (i > input->consumed) {
                input->consumed=i-1;
            }
            return true;
        }
    }
    return false;
}


static bool prs_includeline(input_t * input) {
    if ( eat_if(input, "include(") ) {
        input_t * before = dup_input(input);
        if (prs_path(input)) {
            input_t * after = dup_input(input);
            if( eat_if_ch(input, ')') ) {
                /*  set_include PATH */
                char * path = take(before, after);
                printf("INCLUDE PATH:'%s'\n", path);
                return true;
            }
        }
    }
    return false;
}

static bool prs_tagline(input_t * input) {

}

static bool prs_linetype() {
    return (
            prs_tagline()
            || prs_modeline()
            || prs_includeline()
            || prs_commentline()
            || prs_spaceline()
            );
}

static bool prs_line() {
    return ( prs_line_type() && prs_eol() )
    || prs_error();
}


void * prs_start() {
    while(prs_line() );
    prs_eof() || prs_error();
}