I'm trying to emulate a specific feature of terminal emulators, the ability to parse through previous commands.
My real naive approach was to try and create a cyclical buffer and navigate through it with a next and prev command where it essentially changes view to the current line in the history buffer.
typedef struct {
char buffer[GT_SCQUEUE_SIZE][GT_SCQUEUE_STRING_SIZE];
int front;
int rear;
int view;
} GT_SCQueue;
GT_SCQueue scq = {{{0}}, -1, -1, 0};
void GT_SCQueue_Push(GT_SCQueue* scq, const char* string) {
if (++scq->rear == GT_SCQUEUE_SIZE) {
scq->rear = 0;
}
if (scq->front == scq->rear) {
scq->front = (scq->rear + 1) % GT_SCQUEUE_SIZE;
}
if (scq->front == -1) {
scq->front = 0;
}
strncpy(scq->buffer[scq->rear], string, GT_SCQUEUE_STRING_SIZE - 1);
scq->buffer[scq->rear][GT_SCQUEUE_STRING_SIZE - 1] = '\0';
}
Not at all workable, my code has gotten messy and I'm about to do a rewrite, what are some ways of implementing this feature? is a cyclical buffer the correct way to do this? I wasn't sure how to place the constraints on the functions that traverse up and down the buffer. I'm more so looking for ideas and simple resources/implementations of the desired feature.
As requested, here is how you can implement a stack solution in your code.
I've not found use for structure members front, rear, view
but I left them intact in the structure. Perhaps my addition of global variable stack_top
replaces the intent of one or two of those structure members?
I'm not a fan of globals, but a stack pointer (stack_top
) needs to be shared by two functions, so here we are. You can certainly code it differently if a global is too horrible. It can certainly be added as a member of GT_SCQueue, and that is an easy mod, yes?
Tested, runnable code is here: https://godbolt.org/z/bfr4bfr5o
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define GT_SCQUEUE_SIZE 1000
/* Only one modification to the structure ... */
typedef struct {
char *buffer[GT_SCQUEUE_SIZE]; /* ... here. */
int front; /* unused */
int rear; /* unused */
int view; /* unused */
} GT_SCQueue;
GT_SCQueue scq = {{0}, -1, -1, 0};
int stack_top = -1;
/*---------------------------------------------------------------------------------------------
GT_SCQueue_Push()
Places the item in param string onto the stack.
*---------------------------------------------------------------------------------------------*/
int GT_SCQueue_Push(GT_SCQueue* scq, const char* string)
{
if(stack_top < GT_SCQUEUE_SIZE-1)
{
stack_top++;
}
else
{
printf("Stack Overflow items: %d Max: %d .... moving 1st item out of stack.\n", stack_top+1, GT_SCQUEUE_SIZE);
return 0;
}
/*Add new item on the right */
scq->buffer[stack_top] = strdup(string);
if(!scq->buffer[stack_top])
{
printf("GT_SCQueue_Push() memory error!\n");
return 0;
}
printf("GT_SCQueue_Push() added element [%s]. Elements on the stack: %d Available: %d\n",
string, stack_top+1, GT_SCQUEUE_SIZE-(stack_top+1) );
/* Return success */
return 1;
}
/*---------------------------------------------------------------------------------------------
GT_SCQueue_Pop()
Pops an item off the stack and into param string.
*---------------------------------------------------------------------------------------------*/
int GT_SCQueue_Pop(GT_SCQueue* scq, char *string)
{
if(stack_top < 0)
{
printf("UNDO Stack Underflow -- index: %d", stack_top);
return 0;
}
strcpy(string, scq->buffer[stack_top] );
free(scq->buffer[stack_top]);
scq->buffer[stack_top] = NULL;
printf("GT_SCQueue_Pop() popped element index: %d of string [%s]\n", stack_top, string);
stack_top--;
return 1;
}
int main()
{
char b1[20];
GT_SCQueue_Push(&scq, "Hello You!");
GT_SCQueue_Pop(&scq, b1);
printf("Report from main() -- Popped [%s]\n", b1);
}
Output:
T_SCQueue_Push() added element [Hello You!]. Elements on the stack: 1 Available: 999
GT_SCQueue_Pop() popped element index: 0 of string [Hello You!]
Report from main() -- Popped [Hello You!]