/* License: AGPLv3 or later. https://www.gnu.org/licenses/licenses.html
 * 
 * Exercise 1 - Implementing a Stack (Week 2)
 * Name: Manish
 * Student Login: *****
 * 
 * Compile as:
 * $ gcc -std=c11 -Wall -o ex1 ex1.c
 */ 


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


// 20 character + 1 for null-terminating character '\0'
char stack[1000][21];
const size_t stack_size = 1000;
const size_t word_len = 20;
size_t stack_index = 0; // index pointer to 0 implies empty


void push(char * string);
char* pop();
char* top();
bool isEmpty();
void input_line(char* string[], size_t *size);
void readline(FILE* file, char* string[], size_t *size);
// void input_word(char* string[], size_t *size);
// void readword(FILE* file, char* string[], size_t *size);
void baseread(
    FILE* file,
    char* string[],
    size_t *size,
    const char * terminating_characters);


int main (void)
{
    printf("Enter file name: ");
    char* filename;
    size_t filename_len = 0;
    input_line(&filename, &filename_len);
    
    FILE* file = fopen(filename, "r");
    if (!file)
    {
        perror(filename);
        exit(EXIT_FAILURE);
    }
    
    // Read and push words to stack
    char word[word_len+1];
    size_t index;
    char c;
    while(!feof(file) && !ferror(file))
    {
        index = 0;
        while(
            (c = fgetc(file)) != EOF
            && !ferror(file)
            && memchr("\n\r ", c, 4) == NULL)
        {
            if (index < word_len)
            {
                word[index++] = c;
            }
        }
        word[index] = '\0';
        
        if (index > 0) // non-empty string
        {
            push(word);
        }
    }
    
    fclose(file);
    
    // Print and pop words from stack
    while(!isEmpty())
    {
        printf("%s ", pop());
    }
    printf("\n");
    
    return 0;
}


void push(char * string)
{
    if (stack_index < stack_size)
    {
        strcpy(stack[stack_index++], string);
    }
}


char* pop()
{
    if (!isEmpty())
    {
        return stack[--stack_index];
    }
    return "";
}


char* top()
{
    if (!isEmpty())
    {
        return stack[stack_index-1];
    }
    return "";
}


bool isEmpty()
{
    return stack_index <= 0;
}


inline void input_line(char* string[], size_t *size)
{
    readline(stdin, string, size);
}


inline void readline(FILE* file, char* string[], size_t *size)
{  
    baseread(file, string, size, "\n\r");
}


// inline void input_word(char* string[], size_t *size)
// {
//     readword(stdin, string, size);
// }


// inline void readword(FILE* file, char* string[], size_t *size)
// {
//     baseread(file, string, size, "\n\r ");
// }


// Used only for receiving filename
void baseread(
    FILE* file,
    char* string[],
    size_t *size,
    const char * terminating_characters)
{
    size_t term_chars_len = strlen(terminating_characters);
    size[0] = 32;
    *string = malloc(size[0]);
    // 1 reserved for null-terminating character '\0'
    size_t memory_free = *size - 1;
    size_t str_index = 0;
    char c;
    while ((c = fgetc(file)) != EOF
        && !ferror(file)
        && memchr(terminating_characters, c, term_chars_len) == NULL)
    {
        if (--memory_free <= 0)
        {
            memory_free = *size;
            *size *= 2;
            *string = realloc(*string, *size);
            if (!*string)
            {
                perror("ERROR: Not enough memory to read entire stdin");
                exit(EXIT_FAILURE);
            }
        }
        string[0][str_index++] = c;
    }
    string[0][str_index++] = '\0';
    *size = str_index;
    *string = realloc(*string, *size); // free extra memory
}
