amath  1.8.5
Simple command line calculator
aengine.cpp
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 2014-2018 Carsten Sonne Larsen <cs@innolan.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * Project homepage:
26  * https://amath.innolan.net
27  *
28  */
29 
30 #include "amath.h"
31 #include "amathc.h"
32 #include "charbuf.h"
33 #include "charval.h"
34 #include "aengine.h"
35 
36 #define CURSORFORWARD "\x1B[1C"
37 #define CURSORBACKWARD "\x1B[1D"
38 #define ERASEINLINE "\x1B[K"
39 #define INSERT1CHAR "\x1B[1@"
40 #define DELETE1CHAR "\x1B[1P"
41 #define DELETELINE "\x0D\x1B[K"
42 #define DELETE1CHARASC "\b \b"
43 
44 AnsiConoleEngine::AnsiConoleEngine(const char* prompt, CharValidator* validator)
45 {
46  this->validator = validator;
47  AllocAndCopy(&this->prompt, prompt);
48  linebuf = new CharBuffer();
49  out = new CharBuffer();
50 
51  lines = new char*[maxLines];
52 
53  for (int i = 0; i < maxLines; i++)
54  {
55  lines[i] = nullptr;
56  }
57 
58  editline = nullptr;
59  curline = -1;
60  enabled = true;
61 }
62 
64 {
65  for (int i = 0; i < maxLines; i++)
66  {
67  if (lines[i] != nullptr)
68  {
69  delete [] lines[i];
70  }
71  }
72 
73  delete [] lines;
74  delete linebuf;
75  delete out;
76  delete prompt;
77 }
78 
80 {
81  enabled = true;
82 }
83 
85 {
86  enabled = false;
87 }
88 
90 {
92  len = lineSize;
94  endpos = cursor;
95  *endpos = '\0';
96 
97  lineswap = false;
98  escmode = false;
99  csimode = false;
100  delmode = false;
101  linedone = false;
102 }
103 
104 const char* AnsiConoleEngine::ProcessChar(const unsigned char character)
105 {
106  unsigned char ch = character;
107  out->Empty();
108 
109  if (len == 0)
110  {
112  len = lineSize;
113  }
114 
115  bool processed = false;
116 
117  if (ch == 0)
118  {
119  processed = true;
120  }
121  else if (ch == 27)
122  {
123  escmode = true;
124  processed = true;
125  }
126  else if (ch == 155 || (escmode && ch == 79) || (escmode && ch == 91))
127  {
128  csimode = true;
129  processed = true;
130  }
131  else if (csimode)
132  {
133  switch (ch)
134  {
135  case 65: // Arrow up (27 91 65)
136  ShowLast();
137  break;
138  case 66: // Arrow down (27 91 66)
139  ShowNext();
140  break;
141  case 67: // Arrow right (27 91 67)
142  if (cursor != endpos)
143  {
144  cursor++;
146  }
147  break;
148  case 68: // Arrow left (27 91 68)
149  if (cursor != linebuf->buf)
150  {
151  cursor--;
153  }
154  break;
155  case 51: // DEL 27 91 51 126
156  delmode = true;
157  default:
158  // F1 27 79 80
159  // F2 27 79 81
160  break;
161  }
162 
163  escmode = false;
164  csimode = false;
165  processed = true;
166  }
167  else
168  {
169  escmode = false;
170  csimode = false;
171  }
172 
173  // Delete one character to the right
174  if (delmode && ch == 126)
175  {
176  if (cursor != endpos)
177  {
178  char* i = cursor;
179  do
180  {
181  *i = *(i + 1);
182  i++;
183  }
184  while (i != endpos);
185 
186  len++;
187  if (enabled)
188  {
190  }
191  else
192  {
194  }
195  endpos--;
197  }
198 
199  processed = true;
200  delmode = false;
201  }
202 
203  if (processed)
204  {
205  return out->GetString();
206  }
207 
208  if (ch == 13 || ch == 10)
209  {
212  CopyLine();
213  linedone = true;
214  }
215  else if (cursor != linebuf->buf && (ch == 8 || ch == 127))
216  {
217  // Deleting in middle of line
218  if (cursor != endpos)
219  {
220  char* i = cursor - 1;
221  do
222  {
223  *i = *(i + 1);
224  i++;
225  }
226  while (i != endpos);
227  }
228 
229  len++;
230  if (enabled)
231  {
234  }
235  else
236  {
238  }
239  cursor--;
240  endpos--;
242  }
243  else if (validator->Validate(ch))
244  {
245  // Insert in middle of line
246  if (cursor != endpos)
247  {
248  char* i = endpos;
249  do
250  {
251  *i = *(i - 1);
252  i--;
253  }
254  while (i != cursor);
256  }
257 
258  len--;
259  out->Append(ch);
260  *cursor++ = ch;
261  endpos++;
263  }
264 
265  return out->GetString();
266 }
267 
269 {
270  curline++;
271 
272  if (curline == maxLines)
273  {
274  curline--;
275 
276  delete [] lines[0];
277  for (int i = 0; i < maxLines - 1; i++)
278  {
279  lines[i] = lines[i + 1];
280  }
281  }
282 
284 
285  if (editline != nullptr)
286  {
287  delete [] editline;
288  editline = nullptr;
289  }
290 }
291 
293 {
294  if (curline == -1)
295  {
296  return;
297  }
298 
299  if (!lineswap)
300  {
302  lineswap = true;
303  showline = curline + 1;
304  }
305  else if (showline == curline + 1)
306  {
307  delete editline;
309  }
310 
311  showline--;
312  if (showline < 0)
313  {
314  showline = 0;
315  }
316 
317  out->Empty();
322 
326 
330 
331  unsigned int linelen = StrLen(linebuf->GetString());
332  cursor = linebuf->buf + linelen;
333  endpos = cursor;
334  len = lineSize - linelen;
335 }
336 
338 {
339  if (!lineswap)
340  {
341  return;
342  }
343 
344  showline++;
345  if (showline > curline + 1)
346  {
347  showline = curline + 1;
348  return;
349  }
350 
351  out->Empty();
354 
355  if (showline > curline)
356  {
359 
363  }
364  else
365  {
368 
372  }
373 
374  unsigned int linelen = StrLen(linebuf->GetString());
375  cursor = linebuf->buf + linelen;
376  endpos = cursor;
377  len = lineSize - linelen;
378 }
379 
381 {
382  return linedone;
383 }
384 
385 const char* AnsiConoleEngine::GetLine() const
386 {
387  return linebuf->GetString();
388 }
389 
390 void AnsiConoleEngine::SetPrompt(const char* string)
391 {
392  delete prompt;
393  AllocAndCopy(&prompt, string);
394 }
void Append(const char c)
Definition: charbuf.cpp:245
char ** lines
Definition: aengine.h:71
bool InputDone() const
Definition: aengine.cpp:380
#define NEWLINE
Definition: amath.h:222
unsigned int len
Definition: aengine.h:74
void Empty()
Definition: charbuf.cpp:218
char * GetString() const
Definition: charbuf.cpp:306
#define DELETE1CHAR
Definition: aengine.cpp:40
const char * GetLine() const
Definition: aengine.cpp:385
char * endpos
Definition: aengine.h:76
void Append(const char *source)
Definition: charbuf.cpp:262
CharBuffer()
Initialize without allocating memory.
Definition: charbuf.cpp:38
CharBuffer * linebuf
Definition: aengine.h:72
ANSI console controller.
Definition: aengine.h:47
AnsiConoleEngine(const char *prompt, CharValidator *validator)
Definition: aengine.cpp:44
CharBuffer * out
Definition: aengine.h:87
void Disable()
Definition: aengine.cpp:84
#define CURSORFORWARD
Definition: aengine.cpp:36
static const int maxLines
Definition: aengine.h:69
#define INSERT1CHAR
Definition: aengine.cpp:39
void StartInput()
Definition: aengine.cpp:89
void SetPrompt(const char *string)
Definition: aengine.cpp:390
CharValidator * validator
Definition: aengine.h:73
void EnsureGrowth(unsigned int size)
Definition: charbuf.cpp:169
#define DELETELINE
Definition: aengine.cpp:41
#define CURSORBACKWARD
Definition: aengine.cpp:37
int StrLen(const char *string)
Get the length of a null terminated string.
Definition: strlen.c:34
const char * ProcessChar(const unsigned char character)
Definition: aengine.cpp:104
static const int lineSize
Definition: aengine.h:70
char * prompt
Definition: aengine.h:66
char * ptr
Definition: charbuf.h:82
char * buf
Definition: charbuf.h:81
char * cursor
Definition: aengine.h:75
unsigned int AllocAndCopy(char **destination, const char *source)
Allocate memory and copy a string into the array.
Definition: alloccpy.c:40
Encapsulate an character array which can be used as a string.
Definition: charbuf.h:44
void EnsureSize(unsigned int size)
Ensure a memory block of specified size is allocated.
Definition: charbuf.cpp:114
virtual bool Validate(char c)=0
char * editline
Definition: aengine.h:81
#define DELETE1CHARASC
Definition: aengine.cpp:42
void ClearAndAlloc(unsigned int size)
Release memory and allocate new size.
Definition: charbuf.cpp:92