amath/src/lib/aengine.cpp

395 lines
8.4 KiB
C++
Raw Normal View History

2017-02-27 22:23:06 +00:00
/*-
2021-01-11 19:37:42 +00:00
* Copyright (c) 2014-2021 Carsten Sonne Larsen <cs@innolan.net>
2015-03-08 22:14:50 +00:00
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
2017-02-27 22:23:06 +00:00
* Project homepage:
2017-07-14 09:30:24 +00:00
* https://amath.innolan.net
2021-01-11 19:37:42 +00:00
*
2015-03-08 22:14:50 +00:00
*/
2017-02-27 22:23:06 +00:00
#include "amath.h"
#include "amathc.h"
#include "charbuf.h"
#include "charval.h"
#include "aengine.h"
2015-03-08 22:14:50 +00:00
2017-03-24 19:09:05 +00:00
#define CURSORFORWARD "\x1B[1C"
#define CURSORBACKWARD "\x1B[1D"
#define ERASEINLINE "\x1B[K"
#define INSERT1CHAR "\x1B[1@"
#define DELETE1CHAR "\x1B[1P"
#define DELETELINE "\x0D\x1B[K"
2017-04-12 22:50:51 +00:00
#define DELETE1CHARASC "\b \b"
2017-03-24 19:09:05 +00:00
2017-02-27 22:23:06 +00:00
AnsiConoleEngine::AnsiConoleEngine(const char* prompt, CharValidator* validator)
2015-03-08 22:14:50 +00:00
{
2017-01-24 19:48:02 +00:00
this->validator = validator;
2015-04-01 12:43:50 +00:00
AllocAndCopy(&this->prompt, prompt);
2015-03-08 22:14:50 +00:00
linebuf = new CharBuffer();
out = new CharBuffer();
lines = new char*[maxLines];
2017-02-27 22:23:06 +00:00
for (int i = 0; i < maxLines; i++)
{
lines[i] = nullptr;
2015-03-08 22:14:50 +00:00
}
2017-02-27 22:23:06 +00:00
editline = nullptr;
2015-03-08 22:14:50 +00:00
curline = -1;
2017-04-12 22:50:51 +00:00
enabled = true;
2015-03-08 22:14:50 +00:00
}
AnsiConoleEngine::~AnsiConoleEngine()
{
2017-02-27 22:23:06 +00:00
for (int i = 0; i < maxLines; i++)
{
if (lines[i] != nullptr)
{
2015-03-08 22:14:50 +00:00
delete [] lines[i];
}
}
delete [] lines;
delete linebuf;
delete out;
2015-04-01 12:43:50 +00:00
delete prompt;
2015-03-08 22:14:50 +00:00
}
2017-04-12 22:50:51 +00:00
void AnsiConoleEngine::Enable()
{
enabled = true;
}
void AnsiConoleEngine::Disable()
{
enabled = false;
}
2015-03-08 22:14:50 +00:00
void AnsiConoleEngine::StartInput()
{
linebuf->ClearAndAlloc(lineSize + 1);
len = lineSize;
cursor = linebuf->buf;
endpos = cursor;
*endpos = '\0';
lineswap = false;
escmode = false;
csimode = false;
delmode = false;
linedone = false;
}
const char* AnsiConoleEngine::ProcessChar(const unsigned char character)
{
unsigned char ch = character;
out->Empty();
2017-02-27 22:23:06 +00:00
if (len == 0)
{
2017-03-24 19:09:05 +00:00
out->EnsureGrowth(lineSize);
len = lineSize;
2015-03-08 22:14:50 +00:00
}
bool processed = false;
2017-02-27 22:23:06 +00:00
if (ch == 0)
{
2015-03-08 22:14:50 +00:00
processed = true;
2017-02-27 22:23:06 +00:00
}
else if (ch == 27)
{
2015-03-08 22:14:50 +00:00
escmode = true;
processed = true;
2017-02-27 22:23:06 +00:00
}
2017-03-24 19:09:05 +00:00
else if (ch == 155 || (escmode && ch == 79) || (escmode && ch == 91))
2017-02-27 22:23:06 +00:00
{
2015-03-08 22:14:50 +00:00
csimode = true;
processed = true;
2017-02-27 22:23:06 +00:00
}
else if (csimode)
{
switch (ch)
{
2015-03-08 22:14:50 +00:00
case 65: // Arrow up (27 91 65)
ShowLast();
break;
case 66: // Arrow down (27 91 66)
ShowNext();
break;
case 67: // Arrow right (27 91 67)
2017-02-27 22:23:06 +00:00
if (cursor != endpos)
{
2015-03-08 22:14:50 +00:00
cursor++;
out->Append(CURSORFORWARD);
}
break;
case 68: // Arrow left (27 91 68)
2017-02-27 22:23:06 +00:00
if (cursor != linebuf->buf)
{
2015-03-08 22:14:50 +00:00
cursor--;
out->Append(CURSORBACKWARD);
}
break;
case 51: // DEL 27 91 51 126
delmode = true;
default:
// F1 27 79 80
// F2 27 79 81
break;
}
escmode = false;
csimode = false;
processed = true;
2017-02-27 22:23:06 +00:00
}
else
{
2015-03-08 22:14:50 +00:00
escmode = false;
csimode = false;
}
// Delete one character to the right
2017-02-27 22:23:06 +00:00
if (delmode && ch == 126)
{
if (cursor != endpos)
{
char* i = cursor;
do
{
2015-03-08 22:14:50 +00:00
*i = *(i + 1);
i++;
2017-02-27 22:23:06 +00:00
}
while (i != endpos);
2015-03-08 22:14:50 +00:00
len++;
2017-04-12 22:50:51 +00:00
if (enabled)
{
out->Append(DELETE1CHAR);
}
else
{
2021-01-11 19:37:42 +00:00
out->Append(DELETE1CHARASC);
2017-04-12 22:50:51 +00:00
}
2015-03-08 22:14:50 +00:00
endpos--;
linebuf->ptr = endpos;
}
processed = true;
delmode = false;
}
2017-02-27 22:23:06 +00:00
if (processed)
{
2015-03-08 22:14:50 +00:00
return out->GetString();
}
2017-02-27 22:23:06 +00:00
if (ch == 13 || ch == 10)
{
2015-03-08 22:14:50 +00:00
out->Append(NEWLINE);
linebuf->ptr = endpos;
CopyLine();
linedone = true;
2017-02-27 22:23:06 +00:00
}
else if (cursor != linebuf->buf && (ch == 8 || ch == 127))
{
2015-03-08 22:14:50 +00:00
// Deleting in middle of line
2017-02-27 22:23:06 +00:00
if (cursor != endpos)
{
char* i = cursor - 1;
do
{
2015-03-08 22:14:50 +00:00
*i = *(i + 1);
i++;
2017-02-27 22:23:06 +00:00
}
while (i != endpos);
2015-03-08 22:14:50 +00:00
}
len++;
2017-04-12 22:50:51 +00:00
if (enabled)
{
out->Append(CURSORBACKWARD);
out->Append(DELETE1CHAR);
}
else
{
2021-01-11 19:37:42 +00:00
out->Append(DELETE1CHARASC);
2017-04-12 22:50:51 +00:00
}
2015-03-08 22:14:50 +00:00
cursor--;
endpos--;
linebuf->ptr = endpos;
2017-02-27 22:23:06 +00:00
}
else if (validator->Validate(ch))
{
2015-03-08 22:14:50 +00:00
// Insert in middle of line
2017-02-27 22:23:06 +00:00
if (cursor != endpos)
{
char* i = endpos;
do
{
2015-03-08 22:14:50 +00:00
*i = *(i - 1);
i--;
2017-02-27 22:23:06 +00:00
}
while (i != cursor);
2015-03-08 22:14:50 +00:00
out->Append(INSERT1CHAR);
}
len--;
out->Append(ch);
*cursor++ = ch;
endpos++;
linebuf->ptr = endpos;
}
return out->GetString();
}
void AnsiConoleEngine::CopyLine()
{
curline++;
2017-02-27 22:23:06 +00:00
if (curline == maxLines)
{
2015-03-08 22:14:50 +00:00
curline--;
delete [] lines[0];
2017-02-27 22:23:06 +00:00
for (int i = 0; i < maxLines - 1; i++)
{
2015-03-08 22:14:50 +00:00
lines[i] = lines[i + 1];
}
}
AllocAndCopy(&(lines[curline]), linebuf->GetString());
2017-02-27 22:23:06 +00:00
if (editline != nullptr)
{
2015-03-08 22:14:50 +00:00
delete [] editline;
2017-02-27 22:23:06 +00:00
editline = nullptr;
2015-03-08 22:14:50 +00:00
}
}
void AnsiConoleEngine::ShowLast()
{
2017-02-27 22:23:06 +00:00
if (curline == -1)
{
2015-03-08 22:14:50 +00:00
return;
}
2017-02-27 22:23:06 +00:00
if (!lineswap)
{
2015-03-08 22:14:50 +00:00
AllocAndCopy(&editline, linebuf->GetString());
lineswap = true;
showline = curline + 1;
2017-02-27 22:23:06 +00:00
}
else if (showline == curline + 1)
{
2015-03-08 22:14:50 +00:00
delete editline;
AllocAndCopy(&editline, linebuf->GetString());
}
showline--;
2017-02-27 22:23:06 +00:00
if (showline < 0)
{
2015-03-08 22:14:50 +00:00
showline = 0;
}
out->Empty();
out->EnsureSize(
StrLen(DELETELINE) +
2015-04-01 12:43:50 +00:00
StrLen(prompt) +
2015-03-08 22:14:50 +00:00
StrLen(lines[showline]) + 1);
out->Append(DELETELINE);
2015-04-01 12:43:50 +00:00
out->Append(prompt);
2015-03-08 22:14:50 +00:00
out->Append(lines[showline]);
linebuf->Empty();
linebuf->EnsureSize(StrLen(lines[showline]));
linebuf->Append(lines[showline]);
unsigned int linelen = StrLen(linebuf->GetString());
cursor = linebuf->buf + linelen;
endpos = cursor;
len = lineSize - linelen;
}
void AnsiConoleEngine::ShowNext()
{
2017-02-27 22:23:06 +00:00
if (!lineswap)
{
2015-03-08 22:14:50 +00:00
return;
}
showline++;
2017-02-27 22:23:06 +00:00
if (showline > curline + 1)
{
2015-03-08 22:14:50 +00:00
showline = curline + 1;
return;
}
out->Empty();
out->Append(DELETELINE);
2015-04-01 12:43:50 +00:00
out->Append(prompt);
2015-03-08 22:14:50 +00:00
2017-02-27 22:23:06 +00:00
if (showline > curline)
{
2015-03-08 22:14:50 +00:00
out->EnsureGrowth(StrLen(editline) + 1);
out->Append(editline);
linebuf->Empty();
linebuf->EnsureSize(StrLen(editline));
linebuf->Append(editline);
2017-02-27 22:23:06 +00:00
}
else
{
2015-03-08 22:14:50 +00:00
out->EnsureGrowth(StrLen(lines[showline]) + 1);
out->Append(lines[showline]);
linebuf->Empty();
linebuf->EnsureSize(StrLen(lines[showline]));
linebuf->Append(lines[showline]);
}
unsigned int linelen = StrLen(linebuf->GetString());
cursor = linebuf->buf + linelen;
endpos = cursor;
len = lineSize - linelen;
}
2017-02-27 22:23:06 +00:00
bool AnsiConoleEngine::InputDone() const
2015-03-08 22:14:50 +00:00
{
return linedone;
}
2017-02-27 22:23:06 +00:00
const char* AnsiConoleEngine::GetLine() const
2015-03-08 22:14:50 +00:00
{
return linebuf->GetString();
}
2015-04-01 12:43:50 +00:00
void AnsiConoleEngine::SetPrompt(const char* string)
{
delete prompt;
AllocAndCopy(&prompt, string);
}