// Jonas Altrock <ew20b126@technikum-wien.at>
//
// [To overview](../).
//
// [The whole source file `ppal.c`.](./ppal.c)
/* compile with `clang -std=c99 -Wall -o ppal ppal.c` */

// Include C-libraries for input/output and allocation of memory.
#include <stdio.h>
#include <stdlib.h>

// ## Task
// Read a string and find out whether it is a palindrome.
// Use pointer arithmetics.

// ## Solution

// Pre-processor macro that defines the length of our input buffer.
// The longest we will read in is 80 characters, plus 1 for null-termination.
#define MAX_CHARS_WITH_NUL 81

// `main()` takes no arguments for this program.
int main() {
    // `calloc` initializes the memory to all 0s, so we always have a
    // null-terminated string.
    char *buffer = calloc(MAX_CHARS_WITH_NUL, sizeof(char));
    char c;
    int length = 0;

    // Read in one character at a time, until newline.
    // This is written a bit complicated, because we use the assignment
    // to `c` as an expression here by wrapping it in parentheses.
    //
    // <small>
    // Usually it is not good style to have a side-effect like this
    // (side-effect meaning the program state changes) in a context
    // where we are asking a question and want a true or false answer.
    // It can cause bugs due to being sensitive to the order
    // in which the parts of the condition are evaluated.
    // </small>
    while ((c = getchar()) != '\n' && length < MAX_CHARS_WITH_NUL) {
        // Ignore everything that is not a-z.
        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
            // If it is an uppercase character, transform it to lowercase.
            if ((c >= 'A' && c <= 'Z')) {
                // Lowercase a-z are exactly 32 positions above the
                // uppercase variants, see [`man ascii`](https://man7.org/linux/man-pages/man7/ascii.7.html).
                c += 32;
            }

            buffer[length] = c;
            length += 1;
        }
    }

    // Now to check whether the input string is a palindrome.
    // By default we assume it is a palindrome, until we find a
    // contradiction.
    int is_palindrome = 1;

    // Empty string and single char are palindromes.
    // For everything longer than 1 char we use two pointers,
    // from the start and end of the string, and move them towards
    // each other until they meet.
    if (length > 1) {
        char *left, *right;
        left = buffer;
        right = buffer + (length - 1);

        // Iterate until pointers meet or go past each other.
        while (left < right) {
            // If the characters at the mirrored positions are
            // unequal, we know we do not have a palindrome.
            if (*left != *right) {
                is_palindrome = 0;
            }

            left += 1;
            right -= 1;
        }
    }

    // Print the result.
    if (is_palindrome) {
        printf("palindrome\n");
    } else {
        printf("not a palindrome\n");
    }

    // Don't forget to `free` the allocated memory.
    free(buffer);
    return 0;
}
