quakeforge/libs/util/cbuf.c
Bill Currie b84bf16cab [util] Add a function to reverse delete cbuf stacks
I'm not 100% sure this is the best fix for the issue, but the way the
cbuf interpreter stack works (especially in the console code) meant that
the stack was built in the order opposite to how it could be safely
deleted with the existing function. Yeah, more leaks :P
2023-03-05 18:31:30 +09:00

238 lines
4.6 KiB
C

/*
#FILENAME#
#DESCRIPTION#
Copyright (C) 2002 #AUTHOR#
Author: #AUTHOR#
Date: #DATE#
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; either version 2
of the License, or (at your option) any later version.
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, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include "QF/sys.h"
#include "QF/cbuf.h"
#include "QF/cmd.h"
#include "QF/dstring.h"
#include "QF/qtypes.h"
#include "compat.h"
VISIBLE cbuf_t *cbuf_active = NULL;
VISIBLE cbuf_args_t *
Cbuf_ArgsNew (void)
{
return calloc (1, sizeof (cbuf_args_t));
}
VISIBLE void
Cbuf_ArgsDelete (cbuf_args_t *args)
{
int i;
for (i = 0; i < args->argv_size; i++)
dstring_delete (args->argv[i]);
free (args->argv);
free ((void*)args->args);
free (args->argm);
free (args);
}
VISIBLE void
Cbuf_ArgsAdd (cbuf_args_t *args, const char *arg)
{
int i;
if (args->argc == args->argv_size) {
args->argv_size += 4;
args->argv = realloc (args->argv,
args->argv_size * sizeof (dstring_t *));
args->args = realloc ((void*)args->args, args->argv_size * sizeof (char *));
args->argm = realloc (args->argm, args->argv_size * sizeof (void *));
for (i = args->argv_size - 4; i < args->argv_size; i++) {
args->argv[i] = dstring_newstr ();
args->args[i] = 0;
}
}
dstring_copystr (args->argv[args->argc], arg);
args->argc++;
}
VISIBLE cbuf_t *
Cbuf_New (cbuf_interpreter_t *interp)
{
cbuf_t *cbuf = calloc (1, sizeof (cbuf_t));
cbuf->args = Cbuf_ArgsNew ();
cbuf->interpreter = interp;
if (interp->construct)
interp->construct (cbuf);
return cbuf;
}
VISIBLE void
Cbuf_Delete (cbuf_t *cbuf)
{
if (!cbuf)
return;
Cbuf_ArgsDelete (cbuf->args);
if (cbuf->interpreter->destruct)
cbuf->interpreter->destruct (cbuf);
free (cbuf);
}
VISIBLE void
Cbuf_DeleteStack (cbuf_t *stack)
{
cbuf_t *next;
for (; stack; stack = next) {
next = stack->down;
Cbuf_Delete (stack);
}
}
VISIBLE void
Cbuf_DeleteStackReverse (cbuf_t *stack)
{
cbuf_t *next;
for (; stack; stack = next) {
next = stack->up;
Cbuf_Delete (stack);
}
}
void
Cbuf_Reset (cbuf_t *cbuf)
{
cbuf->resumetime = 0.0;
cbuf->args->argc = 0;
cbuf->state = CBUF_STATE_NORMAL;
if (cbuf->interpreter->reset)
cbuf->interpreter->reset (cbuf);
}
VISIBLE cbuf_t *
Cbuf_PushStack (cbuf_interpreter_t *interp)
{
cbuf_t *new;
if (cbuf_active->down) {
new = cbuf_active->down;
if (new->interpreter != interp) {
new->interpreter->destruct (new);
new->interpreter = interp;
new->interpreter->construct (new);
}
Cbuf_Reset (new);
} else
new = Cbuf_New (interp);
cbuf_active->down = new;
new->up = cbuf_active;
cbuf_active->state = CBUF_STATE_STACK;
return new;
}
VISIBLE void
Cbuf_AddText (cbuf_t *cbuf, const char *text)
{
if (cbuf->state == CBUF_STATE_JUNK)
cbuf->state = CBUF_STATE_NORMAL;
cbuf->interpreter->add (cbuf, text);
}
VISIBLE void
Cbuf_InsertText (cbuf_t *cbuf, const char *text)
{
if (cbuf->state == CBUF_STATE_JUNK)
cbuf->state = CBUF_STATE_NORMAL;
cbuf->interpreter->insert (cbuf, text);
}
VISIBLE void
Cbuf_Execute (cbuf_t *cbuf)
{
cbuf_t *old = cbuf_active;
cbuf_active = cbuf;
cbuf->interpreter->execute (cbuf);
cbuf_active = old;
}
VISIBLE void
Cbuf_Execute_Stack (cbuf_t *cbuf)
{
cbuf_t *sp;
if (cbuf->resumetime) {
if (cbuf->resumetime < Sys_DoubleTime())
cbuf->resumetime = 0;
else
return;
}
for (sp = cbuf; sp->down && sp->down->state != CBUF_STATE_JUNK; sp = sp->down);
if (sp->state == CBUF_STATE_BLOCKED)
return;
while (sp) {
Cbuf_Execute (sp);
if (sp->state) {
if (sp->state == CBUF_STATE_STACK) {
sp->state = CBUF_STATE_NORMAL;
sp = sp->down;
continue;
} else if (sp->state == CBUF_STATE_ERROR)
break;
else if (sp->state == CBUF_STATE_BLOCKED)
return;
else {
sp->state = CBUF_STATE_NORMAL;
return;
}
}
sp->state = CBUF_STATE_JUNK;
sp = sp->up;
}
if (cbuf->down) {
Cbuf_DeleteStack (cbuf->down);
cbuf->down = 0;
}
if (sp)
Cbuf_Reset (cbuf);
}
VISIBLE void
Cbuf_Execute_Sets (cbuf_t *cbuf)
{
cbuf->interpreter->execute_sets (cbuf);
}