ESH

Executive Shell
git clone http://git.omkov.net/ESH
Log | Tree | Refs | README | Download

AuthorJamozed <[email protected]>
Date2021-08-19 03:46:23
Commit61d48de47e99fa859414d8ede55b49257fd1cefb
Parent6e65ba3c9750eae6dff2b5ac06a2c1f8b4de34af

Add command history

Diffstat

M src/lineread.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
M src/lineread.h | 1 +
M src/main.c | 2 +-

3 files changed, 90 insertions, 12 deletions

diff --git a/src/lineread.c b/src/lineread.c
index 24c6022..7180cce 100644
--- a/src/lineread.c
+++ b/src/lineread.c
@@ -30,6 +30,7 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 */
 
+#include "conf.h"
 #include "lineread.h"
 
 #include "lib/error.h"
@@ -40,18 +41,25 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 
 #include <errno.h>
 #include <stdbool.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 struct line {
-	char *s; size_t sp, sl, sc; size_t hi;
+	char *s; size_t sp, sl, sc;
 	char *prompt; size_t pl; size_t cols;
 };
 
+struct hist {
+	struct line *a; size_t ap, ah, at, al, ac;
+};
+
 static struct termios tco, tcn;
 static bool rawflag = false, ateflag = false;
 
+static struct hist h = { NULL, 0, 0, 0, 0 };
+
 static char *linentty(void);
 static char *lineedit(void);
 static void lineESC(struct line *l, register int c);
@@ -78,12 +86,23 @@ static void lineDeleteWordEnd(struct line *l);
 static void lineDeleteHome(struct line *l);
 static void lineDeleteEnd(struct line *l);
 
+static int  histInit(struct hist *h);
+static void histFree(struct hist *h);
+static void histMovePrior(struct hist *h);
+static void histMoveNext(struct hist *h);
+static void histMoveHome(struct hist *h);
+static void histMoveEnd(struct hist *h);
+static void histPush(struct hist *h, struct line l);
+
 /* Read a line from stdin */
 char *lineread(void) {
 	if (!isatty(STDIN_FILENO)) { errno = 0; return linentty(); }
 	else { return lineedit(); }
 }
 
+/* Free memory allocated by lineread */
+void linefree(void) { histFree(&h); }
+
 /* Read from a non-terminal stdin */
 static char *linentty(void) {
 	struct line l; register char *r;
@@ -102,15 +121,22 @@ ret:;
 	free(l.s); return r;
 }
 
+#define l h.a[h.ap]
 /* Dynamically read a line from stdin */
 static char *lineedit(void) {
-	struct line l; register char *r;
+	register char *r;
 
-	l.sp = 0; l.sl = 0; l.sc = 1024; l.hi = 0;
-	l.prompt = "$ "; l.pl = strlen(l.prompt);
-	
-	if (!(l.cols = getcols())) { return NULL; }
-	if (!(l.s = malloc(l.sc * sizeof (*l.s)))) { return NULL; } l.s[0] = 0;
+	{
+		if (h.a == NULL) { if (histInit(&h)) { return NULL; } }
+		
+		struct line m = { NULL, 0, 0, 1024 };
+		m.prompt = "$ "; m.pl = strlen(m.prompt);
+		
+		if (!(m.cols = getcols())) { return NULL; }
+		if (!(m.s = malloc(m.sc * sizeof (*m.s)))) { return NULL; } m.s[0] = 0;
+		
+		histPush(&h, m);
+	}
 
 	tcraw(); fputs(l.prompt, stdout);
 
@@ -151,8 +177,8 @@ static char *lineedit(void) {
 			case '[': switch ((c = fgetc(stdin))) {
 				case '1': case '2': case '3': case '4': case '5': case '6':
 				case '7': case '8': case '9': { lineESC(&l, c); continue; }
-				case 'A': { /* TODO */ continue; } // UP
-				case 'B': { /* TODO */ continue; } // DOWN
+				case 'A': { histMovePrior(&h); continue; } // UP
+				case 'B': { histMoveNext(&h); continue; }  // DOWN
 				case 'C': { lineMoveRight(&l); continue; } // RIGHT
 				case 'D': { lineMoveLeft(&l); continue; }  // LEFT
 				case 'F': { lineMoveEnd(&l); continue; }   // END
@@ -169,8 +195,9 @@ static char *lineedit(void) {
 end:;
 	r = strndup(l.s, l.sl);
 ret:;
-	free(l.s); tcrestore(); fputc('\n', stdout); return r;
+	tcrestore(); fputc('\n', stdout); return r;
 }
+#undef l // h.a[h.ap]
 
 /* Handle an extended ^[ sequence */
 static void lineESC(struct line *l, register int c) {
@@ -181,6 +208,12 @@ static void lineESC(struct line *l, register int c) {
 	case '3': switch ((c = fgetc(stdin))) {
 		case '~': { lineDelete(l); break; } // DELETE
 	}
+	case '5': switch ((c = fgetc(stdin))) {
+		case '~': { histMoveHome(&h); break; } // PAGE UP
+	}
+	case '6': switch ((c = fgetc(stdin))) {
+		case '~': { histMoveEnd(&h); break; } // PAGE DOWN
+	}
 	}
 }
 
@@ -330,10 +363,54 @@ static void lineDeleteWordEnd(struct line *l) {
 static void lineDeleteHome(struct line *l) {
 	memmove(l->s, l->s + l->sp, l->sl - l->sp + 1);
 	l->sl -= l->sp; l->sp = 0; lineRefresh(l); return;
-	
 }
 
 /* Delete characters from cursor to end */
 static void lineDeleteEnd(struct line *l) {
 	l->s[(l->sl = l->sp)] = 0; lineRefresh(l); return;
 }
+
+/* Initialise history */
+static int histInit(struct hist *h) {
+	h->ap = 0; h->ah = 0; h->at = 0; h->al = 0; h->ac = conf_histsize + 1;
+	if (!(h->a = malloc(h->ac * sizeof (*h->a)))) { return 1; }
+	/* TODO load history from file */ return 0;
+}
+
+/* Free history */
+static void histFree(struct hist *h) {
+	for (size_t i = 0; i != h->ac; ++i) { free(h->a[i].s); } free(h->a);
+}
+
+/* Move backwards in history */
+static void histMovePrior(struct hist *h) {
+	if (h->ap != h->ah) { h->ap == 0 ? h->ap = h->ac - 1 : --h->ap; }
+	lineRefresh(&h->a[h->ap]); return;
+}
+
+/* Move forwards in history */
+static void histMoveNext(struct hist *h) {
+	register size_t an = h->ap == h->ac - 1 ? 0 : h->ap + 1;
+	if (an != h->at) { h->ap = an; }
+	lineRefresh(&h->a[h->ap]); return;
+}
+
+/* Move to the start of history */
+static void histMoveHome(struct hist *h) {
+	/* TODO */
+	h->ap = h->ah; lineRefresh(&h->a[h->ap]); return;
+}
+
+/* Move to the end of history */
+static void histMoveEnd(struct hist *h) {
+	/* TODO */
+	// h->ap = h->at; lineRefresh(&h->a[h->ap]); return;
+}
+
+/* Push a line onto the end of history */
+static void histPush(struct hist *h, struct line l) {
+	if (h->al != h->ac) { ++h->al; h->ap = h->at; if (++h->at == h->ac) { h->at = 0; }}
+	else { h->ap = h->at; if (++h->at == h->ac) { h->at = 0; } h->ah = h->at; }
+	
+	free(h->a[h->ap].s); h->a[h->ap] = l; return;
+}
diff --git a/src/lineread.h b/src/lineread.h
index cc5fa15..c3713d9 100644
--- a/src/lineread.h
+++ b/src/lineread.h
@@ -34,5 +34,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
 #define OMKOV_ESH_LINEREAD_H_RPVXY3N7
 
 extern char *lineread(void);
+extern void linefree(void);
 
 #endif // OMKOV_ESH_LINEREAD_H_RPVXY3N7
diff --git a/src/main.c b/src/main.c
index 789bdf7..f8fe7ad 100644
--- a/src/main.c
+++ b/src/main.c
@@ -89,7 +89,7 @@ int main(int ac, char *av[]) { (void)(ac); A0 = av[0];
 		} free(line);
 	} while (_loop);
 
-	return warned;
+	linefree(); return warned;
 }
 
 static void reset(int signo) { (void)(signo);