platypus/buffer.c

525 lines
14 KiB
C
Raw Normal View History

2017-01-30 17:29:09 +00:00
/*
* File Name: buffer.c
* Compiler: GCC 6.2.0
* Author: Victor Fernandes, 040772243
* Course: CST8152 - Compilers, Lab Section: 011
2017-01-30 19:29:38 +00:00
* Date: February 1, 2017
2017-01-30 17:29:09 +00:00
* Professor: Svillen Ravev
* A character buffer utility with three modes of self-incrementation
through dynamic memory allocation, and ability to set a mark flag.
* Function list:
* TODO: Function list and finish algorithm descriptions
*/
#include <limits.h>
#include <stdlib.h>
#include "buffer.h"
/* Initializes and allocates memory for the buffer descriptor
* Author: Victor Fernandes
* Version: 0.0.1
* Called functions: calloc(), malloc(), free()
* Parameters:
- short init_capacity (0 - SHRT_MAX)
- char inc_factor (1 - 255)
- char o_mode (-1, 0, 1)
* Return values: pBuffer or NULL
* Algorithm: Allocates memory for the buffer descriptor. If successful, do bound
2017-01-30 19:31:56 +00:00
checks on function parameters and assign them to the buffer's variables. If
all is clear, allocate the character buffer. Otherwise return NULL.
2017-01-30 17:29:09 +00:00
*/
Buffer* b_create(short init_capacity, char inc_factor, char o_mode) {
pBuffer pBD; /* Pointer to buffer descriptor */
/* BEGIN CONFIGURING BUFFER */
2017-01-30 19:29:38 +00:00
/* Check if init_capacity is within acceptable range */
2017-01-30 17:29:09 +00:00
if (init_capacity > SHRT_MAX || init_capacity < MIN_CAPACITY) {
return NULL;
}
2017-01-30 19:29:38 +00:00
/* Leaving cb_head allocation for last in the event of bad input */
2017-01-30 17:29:09 +00:00
2017-01-30 19:29:38 +00:00
2017-01-30 17:29:09 +00:00
/* Memory allocation */
pBD = (Buffer *) calloc(1, sizeof(Buffer));
if (!pBD) {
return NULL; /* Abort execution immediatelly if allocation fails */
}
/* Check and set operation mode */
if (o_mode == 'f' || inc_factor == FIX_INC_FACTOR) {
pBD->mode = FIX_OP_MODE;
pBD->inc_factor = FIX_INC_FACTOR;
2017-01-30 19:29:38 +00:00
} else if (o_mode == 'a'
&& (inc_factor >= MIN_INC_FACTOR)
&& (inc_factor <= MAX_ADD_INC_FACTOR)) {
2017-01-30 17:29:09 +00:00
pBD->mode = ADD_OP_MODE;
pBD->inc_factor = inc_factor;
2017-01-30 19:29:38 +00:00
} else if (o_mode == 'm'
&& (inc_factor >= MIN_MUL_INC_FACTOR)
&& (inc_factor <= MAX_MUL_INC_FACTOR)) {
2017-01-30 17:29:09 +00:00
pBD->mode = MUL_OP_MODE;
pBD->inc_factor = inc_factor;
2017-01-30 19:29:38 +00:00
} else { /* Abort everything if any parameters are bad */
2017-01-30 17:29:09 +00:00
free(pBD);
2017-01-30 19:29:38 +00:00
return NULL;
2017-01-30 17:29:09 +00:00
}
2017-01-30 19:29:38 +00:00
/* Attempt to initialize cb_head */
pBD->cb_head = (char *) malloc(sizeof(char) * init_capacity);
/* Abort configuration if allocation fails and release memory */
if (!pBD->cb_head) {
free(pBD);
return NULL;
}
2017-01-30 17:29:09 +00:00
pBD->capacity = init_capacity;
/* END CONFIGURING BUFFER */
return pBD;
}
/* Reports whether the character buffer is full or not
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return values: -1, 0, 1
*/
int b_isfull(Buffer* const pBD) {
if (!pBD) { return R_FAIL1; }
if (pBD->addc_offset == pBD->capacity) {
return TRUE;
} else {
return FALSE;
}
}
/* Reports if character buffer is empty
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: -1, 0, 1
*/
int b_isempty(Buffer* const pBD) {
if (!pBD) { return R_FAIL1; }
if (pBD->addc_offset == OFFSET_RESET) {
return TRUE;
} else {
return FALSE;
}
}
/* Reports the current size of the character buffer
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: short
*/
short b_size(Buffer* const pBD) {
if (!pBD) { return R_FAIL1; }
return pBD->addc_offset;
}
/* Reports the current capacity of the character buffer
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: short
*/
short b_capacity(Buffer* const pBD) {
if (!pBD) { return R_FAIL1; }
return pBD->capacity;
}
/* Reports the current character buffer's operational mode
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: -2, -1, 0, 1
*/
int b_mode(Buffer* const pBD) {
if (!pBD) { return R_FAIL2; }
return pBD->mode;
}
/* Returns the non-negative value of the increment factor of the buffer
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: size_t
*/
size_t b_incfactor(Buffer* const pBD) {
if (!pBD) { return 256; }
return (size_t) pBD->inc_factor;
}
/* Reports the current position of the mark offset in the character buffer
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: short
*/
short b_mark(Buffer* const pBD) {
if (!pBD) { return R_FAIL1; }
return pBD->mark_offset;
}
/* Reports if the character buffer's memory space was relocated after resizing
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: char
*/
char b_flag(Buffer* const pBD) {
if (!pBD) { return R_FAIL1; }
return pBD->r_flag;
}
/* Reports character buffer's current character offset
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: short
*/
short b_getcoffset(Buffer* const pBD) {
if (!pBD) { return R_FAIL1; }
return pBD->getc_offset;
}
/* Returns the buffer's actual character buffer address
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: short
*/
char* b_cbhead(Buffer* const pBD) {
if (!pBD || !pBD->cb_head) { return NULL; }
return pBD->cb_head;
}
/* Sets a mark offset on the buffer's mark flag
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: short
*/
short b_setmark(Buffer* const pBD, short mark) {
if (!pBD || mark < 0 || mark > pBD->addc_offset) { return R_FAIL1; }
pBD->mark_offset = mark;
return pBD->mark_offset;
}
/* Reports the end-of-buffer flag state of the character buffer
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: 1, 0
*/
2017-01-31 13:31:36 +00:00
int b_eob(Buffer* const pBD) {
2017-01-30 17:29:09 +00:00
if (!pBD) { return R_FAIL1; }
return pBD->eob;
}
/* Adds one character symbol to the character buffer, incrementing its size if
possible and needed
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: b_isfull(), realloc()
* Parameters:
- pBuffer const pBD
- char symbol (1-255)
* Return value: pBuffer or NULL
* Algorithm:
*/
Buffer* b_addc(Buffer* const pBD, char symbol) {
/* Variables used for calculating required space for reallocating cb_head
for additive or multiplicative modes */
short avail_space, new_inc, new_cap = 0;
/* These pointers are used to compare the address of cb_head, in the event it is
moved to a new address space in memory after reallocation*/
char *old_addr;
char *tmp_addr;
/* Check if pointers are valid before trying anything */
if (!pBD || !pBD->cb_head) {
return NULL;
}
/* Reset reallocation flag */
2017-01-30 17:29:09 +00:00
pBD->r_flag = UNSET_R_FLAG;
/* BEGIN BUFFER INCREMENT */
2017-01-30 17:29:09 +00:00
if (pBD->addc_offset == pBD->capacity){
if (pBD->mode == FIX_OP_MODE) { /* Fixed mode, won't increment */
2017-01-30 17:29:09 +00:00
return NULL;
}
else if (pBD->mode == ADD_OP_MODE) { /* Calculate new size for additive mode */
new_cap = pBD->capacity + pBD->inc_factor;
/* Make sure no short overflow happened */
2017-01-30 17:29:09 +00:00
if (new_cap < MIN_CAPACITY){
return NULL;
}
2017-01-30 17:29:09 +00:00
}
else if (pBD->mode == MUL_OP_MODE) { /* Calculate new size in multiplicative mode */
if (pBD->capacity == SHRT_MAX){ /* Do nothing if at maximum size */
2017-01-30 17:29:09 +00:00
return NULL;
}
avail_space = SHRT_MAX - pBD->capacity;
new_inc = (avail_space * (unsigned char) pBD->inc_factor / 100);
/* Check if there is enough space for the new increment and
"trim" it if needed */
if (new_inc >= avail_space) {
2017-01-30 17:29:09 +00:00
new_cap = SHRT_MAX;
}
else {
new_cap = pBD->capacity + new_inc;
}
}
/* Reallocate memory to character buffer */
old_addr = pBD->cb_head; /* Keep track of old pointer address to check if it changed */
2017-01-30 17:29:09 +00:00
tmp_addr = (char *)realloc(pBD->cb_head, sizeof(char) * new_cap);
2017-01-30 17:29:09 +00:00
if (tmp_addr == NULL){
return NULL; /* Abort everything if allocation fails */
}
2017-01-30 17:29:09 +00:00
pBD->cb_head = tmp_addr;
pBD->capacity = new_cap;
if (old_addr == pBD->cb_head) { /* Compare the old and new addresses and set flag appropriately */
pBD->r_flag = SET_R_FLAG;
}
} /* END BUFFER INCREASE */
/* Finally, add new symbol to the buffer after increasing it (or not) */
pBD->cb_head[pBD->addc_offset] = symbol;
pBD->addc_offset++;
return pBD;
}
/* Gets one character symbol from the buffer
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: char
*/
char b_getc(Buffer* const pBD) {
if (!pBD) { return R_FAIL2; }
if (b_getcoffset(pBD) == pBD->addc_offset) {
pBD->eob = SET_EOB_FLAG;
return R_FAIL1;
} else {
pBD->eob = UNSET_EOB_FLAG;
}
return pBD->cb_head[pBD->getc_offset++];
}
/* Prints the output of the buffer
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: b_isempty(), b_getc(), b_eob(), printf()
* Parameters:
- pBuffer const pBD
* Return value: int
*/
int b_print(Buffer* const pBD) {
int char_count = 0; /* Counter to track how many characters were sent to output */
char char_buf; /* "Buffer" character to load before output */
2017-01-30 21:35:51 +00:00
short tmp_offset = OFFSET_RESET;
2017-01-30 17:29:09 +00:00
if (!pBD || !pBD->cb_head) { return R_FAIL1; }
if (b_isempty(pBD) == TRUE) { printf("The Buffer is empty.\n"); }
else {
2017-01-30 21:35:51 +00:00
tmp_offset = pBD->getc_offset;
2017-01-30 17:29:09 +00:00
pBD->getc_offset = OFFSET_RESET;
do {
char_buf = b_getc(pBD);
printf("%c", (char) char_buf);
char_count++;
} while (b_eob(pBD) == FALSE);
printf("\n");
}
/* Restore the getc_offset after printing */
pBD->getc_offset = tmp_offset;
return char_count;
}
/* Loads symbols from a file to the buffer
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
2017-01-31 13:31:36 +00:00
* Called functions: fgetc, feof, b_addc
2017-01-30 17:29:09 +00:00
* Parameters:
- FILE* const fi
- pBuffer const pBD
* Return value: int
*/
int b_load(FILE* const fi, Buffer* const pBD) {
char char_buf; /* "Buffer" character to be loaded before adding to cb_head */
int char_count = 0; /* Character counter */
if (!fi || !pBD) {
return LOAD_FAIL;
}
2017-01-30 17:29:09 +00:00
do {
char_buf = (char) fgetc(fi);
if (char_buf == (char) EOF) {
2017-01-30 17:29:09 +00:00
break;
}
if (!b_addc(pBD, char_buf)) {
2017-01-30 17:29:09 +00:00
return LOAD_FAIL;
}
char_count++;
} while (!feof(fi));
2017-01-30 17:29:09 +00:00
return char_count;
}
/* Resets the buffer
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: int
*/
int b_reset(Buffer* const pBD) {
if (!pBD) { return R_FAIL1; }
pBD->addc_offset = OFFSET_RESET;
pBD->getc_offset = OFFSET_RESET;
pBD->mark_offset = OFFSET_RESET;
pBD->eob = UNSET_EOB_FLAG;
return TRUE;
}
/* Retracts the buffer's character offset to the mark
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: short
*/
short b_retract_to_mark(Buffer* const pBD) {
/* Check if any offsets are out of bounds */
if(!pBD ||
pBD->getc_offset < OFFSET_RESET || pBD->getc_offset > pBD->capacity ||
pBD->mark_offset < OFFSET_RESET || pBD->mark_offset > pBD->capacity) {
return R_FAIL1;
}
pBD->getc_offset = pBD->mark_offset;
return pBD->getc_offset;
}
/* Retracts the buffer's character offset one character backwards
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: short
*/
short b_retract(Buffer* const pBD) {
if (!pBD) { return R_FAIL1; }
else if (pBD->getc_offset > OFFSET_RESET) {
pBD->getc_offset--;
}
return pBD->getc_offset;
}
/* Returns the buffer's memory reallocation flag
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: N/A
* Parameters:
- pBuffer const pBD
* Return value: char
*/
char b_rflag(Buffer* const pBD) {
if (!pBD) { return R_FAIL1; }
return pBD->r_flag;
}
/* Reduce the size of the character buffer to free up memory
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: realloc()
* Parameters:
- pBuffer const pBD
* Return value: Buffer* const
*/
Buffer* b_pack(Buffer* const pBD) {
short new_cap; /* Used to set the new buffer capacity value */
/* Temporary pointers used to compare old and new pointer addresses */
char *old_addr;
char *tmp_addr;
if (!pBD || !pBD->cb_head) { return NULL; }
/* Configure new capacity value */
new_cap = pBD->addc_offset + 1;
old_addr = pBD->cb_head;
/* Reallocate cb_head to new size */
tmp_addr = realloc(pBD->cb_head, sizeof(char) * new_cap);
if (!tmp_addr){ return NULL; } /* Abort if realloc failed */
/* Assign new address to cb_head and reassign capacity value */
pBD->cb_head = tmp_addr;
pBD->capacity = new_cap;
/* Compare old and new addresses and set R_FLAG accordingly */
if (old_addr != pBD->cb_head){
pBD->r_flag = SET_R_FLAG;
}
return pBD;
}
/* Deallocate and release all memory used by the buffer.
* Author: Victor Fernandes, 040772243
* Version: 0.0.1
* Called functions: free()
* Parameters:
- pBuffer const pBD
* Return value: N/A
*/
void b_free(Buffer* const pBD) {
free(pBD->cb_head);
free(pBD);
}