/* * C_lib Copyright (C) 2021 Wael Karram. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* This file contains the function implementations for a stack. */ /* Include guards + includes. */ #ifndef STACK_C #define STACK_C /* Include statements. */ #include "stack.h" #endif /* STACK_C */ /* This function initializes a new empty stack. */ /* Returns a valid pointer on success, and NULL on failure. */ static inline stack_t* initialize_stack() { /* Variables. */ stack_t *result; /* Attempt to allocate. */ result = (stack_t*) malloc(sizeof(stack_t)); if (!result) return NULL; /* Allocation succeeded, initialize and return. */ result->size = INITIAL_STACK_SIZE; result->head = NULL; return result; } /* This function pops the current head node out, if it exists, otherwise will return NULL. */ static inline node_t* pop(stack_t *stack) { /* Sanity check. */ assert(stack && (stack->head)); /* Remove the head. */ node_t *head = stack->head; stack->head = head->next; (stack->size) -= 1L; /* Return the head.*/ return head; } /* This function "peeks" at the top of the stack. */ static inline const void* peek(stack_t *stack) { /* Sanity check. */ assert(stack && (stack->head)); /* Return the data in the head. */ return stack->head->data; } /* This function pushes a node in. */ /* Will fail for a NULL stack or node! */ static inline void push(stack_t *stack, node_t *node) { /* Sanity check. */ assert(stack && node); /* Try to push. */ /* Increase the count. */ (stack->size) += 1; /* Check if the head is NULL or not. */ if (!(stack->head)) { stack->head = node; node->next = NULL; return; } /* Relink the head. */ node->next = stack->head; stack->head = node; } /* This function creates a node, stores the given data and pushes it into the stack, will fail on a NULL stack or allocation errors. */ /* Returns PUSH_SUCCESS on success, and PUSH_FAIL on failure. */ static inline int push_data(stack_t *stack, void *data) { /* Sanity check. */ assert(stack); /* Try to allocate the new node. */ node_t *node = (node_t*) malloc(sizeof(node_t)); if (!node) return PUSH_FAIL; /* Store the data in the node. */ node->data = data; /* Delegate. */ push(stack, node); return PUSH_SUCCESS; } /* This function returns the stack's size, will return INVALID_SIZE for a NULL stack. */ static inline const size_t stack_size(stack_t *stack) { return (stack == NULL) ? INVALID_SIZE : stack->size; } /* This function frees a stack, doesn't touch the data. */ /* Takes a pointer to a pointer so it can set the original pointer to NULL. */ static inline void free_stack(stack_t **stack) { /* Sanity check. */ assert(stack && *stack); /* Start by freeing node after node. */ node_t *current = (*stack)->head; node_t *tmp; while (current) { tmp = current->next; free(current); current = tmp; } /* Free the stack. */ free(*stack); *stack = NULL; } /* This function frees a stack and the data stored within the nodes thereof, if free_function is NULL will use STDLIB's free() instead to free the data. */ /* Takes a pointer to a pointer so it can set the original pointer to NULL. */ static inline void free_stack_data(stack_t **stack, void (*free_function)(const void*)) { /* Sanity check. */ assert(stack && *stack); /* Start by freeing node after node. */ node_t *current = (*stack)->head; node_t *tmp; while (current) { tmp = current->next; if (free_function) free_function(current->data); else free(current->data); free(current); current = tmp; } /* Free the stack. */ free(*stack); *stack = NULL; }