a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
0
|
// Copyright (C) 2021, Jakob Wakeling |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
1
|
// All rights reserved. |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
2
|
|
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
3
|
#include "../util/log.h" |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
4
|
#include "../util/util.h" |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
5
|
#include "lineread.h" |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
6
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
7
|
#include <sys/ioctl.h> |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
8
|
#include <termios.h> |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
9
|
#include <unistd.h> |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
10
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
11
|
#include <errno.h> |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
12
|
#include <stdbool.h> |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
13
|
#include <stddef.h> |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
14
|
#include <stdio.h> |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
15
|
#include <stdlib.h> |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
16
|
#include <string.h> |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
17
|
|
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
18
|
typedef struct { char *s; uptr sp, sl, sc; } line; |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
19
|
typedef struct { line *a; uptr ap, ah, at, al, ac; } hist; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
20
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
21
|
static struct termios tco, tcn; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
22
|
static bool rawflag = false, ateflag = false; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
23
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
24
|
static hist h = { NULL, 0, 0, 0, 0 }; |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
25
|
static const char *const prompt = "$ "; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
26
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
27
|
static char *linentty(void); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
28
|
static char *lineedit(void); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
29
|
static void line_esc(line *l, register int c); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
30
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
31
|
static inline void tcraw(void); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
32
|
static inline void tcrestore(void); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
33
|
static size_t getcols(void); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
34
|
static void clearscreen(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
35
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
36
|
static void line_refresh(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
37
|
static void line_reset(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
38
|
static void line_move_left(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
39
|
static void line_move_right(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
40
|
static void line_move_word_home(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
41
|
static void line_move_word_end(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
42
|
static void line_move_home(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
43
|
static void line_move_end(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
44
|
static void line_push(line *l, char c); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
45
|
static int line_insert(line *l, char c); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
46
|
static void line_backspace(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
47
|
static void line_delete(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
48
|
static void line_delete_word_home(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
49
|
static void line_delete_word_end(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
50
|
static void line_delete_home(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
51
|
static void line_delete_end(line *l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
52
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
53
|
static int hist_init(hist *h); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
54
|
static void hist_free(hist *h); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
55
|
static void hist_move_prior(hist *h); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
56
|
static void hist_move_next(hist *h); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
57
|
static void hist_move_home(hist *h); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
58
|
static void hist_move_end(hist *h); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
59
|
static void hist_push(hist *h, line l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
60
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
61
|
/* Read a line from stdin */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
62
|
char *lineread(void) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
63
|
if (!isatty(STDIN_FILENO)) { errno = 0; return linentty(); } |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
64
|
else { return lineedit(); } |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
65
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
66
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
67
|
/* Free memory allocated by lineread */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
68
|
void linefree(void) { hist_free(&h); } |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
69
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
70
|
/* Read from a non-terminal stdin */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
71
|
static char *linentty(void) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
72
|
line l; register char *r; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
73
|
l.sp = 0; l.sl = 0; l.sc = 1024; |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
74
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
75
|
if (!(l.s = xmalloc(l.sc * sizeof (*l.s)))) { return NULL; } |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
76
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
77
|
for (register int c; (c = fgetc(stdin));) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
78
|
if (c == EOF) { if (l.sl) { break; } r = NULL; goto ret; } |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
79
|
else { line_push(&l, c); } continue; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
80
|
} |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
81
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
82
|
end:; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
83
|
r = strndup(l.s, l.sl); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
84
|
ret:; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
85
|
free(l.s); return r; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
86
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
87
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
88
|
#define l h.a[h.ap] |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
89
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
90
|
/* Dynamically read a line from stdin */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
91
|
static char *lineedit(void) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
92
|
register char *r; |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
93
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
94
|
{ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
95
|
if (h.a == NULL) { if (hist_init(&h)) { return NULL; } } |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
96
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
97
|
line m = { NULL, 0, 0, 1024 }; |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
98
|
|
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
99
|
// if (!(m.cols = getcols())) { return NULL; } |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
100
|
if (!(m.s = xmalloc(m.sc * sizeof (*m.s)))) { return NULL; } m.s[0] = 0; |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
101
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
102
|
hist_push(&h, m); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
103
|
} |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
104
|
|
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
105
|
tcraw(); fputs(prompt, stdout); |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
106
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
107
|
for (register int c; (c = fgetc(stdin));) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
108
|
if (errno) { log_warn("FIXME: %s", strerror(errno)); errno = 0; } |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
109
|
// printf("%02X\n", c); continue; |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
110
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
111
|
switch (c) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
112
|
case '\x01': { line_move_home(&l); } continue; // CTRL + A |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
113
|
case '\x02': { line_move_left(&l); } continue; // CTRL + B |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
114
|
case '\x03': { line_reset(&l); } continue; // CTRL + C |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
115
|
case '\x04': { r = NULL; } goto ret; // CTRL + D |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
116
|
case '\x05': { line_move_end(&l); } continue; // CTRL + E |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
117
|
case '\x06': { line_move_right(&l); } continue; // CTRL + F |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
118
|
case '\x07': {} continue; // IGNORE CTRL + G |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
119
|
case '\x08': { line_backspace(&l); } continue; // CTRL + H |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
120
|
case '\x09': {} continue; // IGNORE CTRL + I |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
121
|
case '\x0A': {} goto end; // CTRL + J |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
122
|
case '\x0B': { line_delete_end(&l); } continue; // CTRL + K |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
123
|
case '\x0C': { clearscreen(&l); } continue; // CTRL + L |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
124
|
case '\x0D': {} goto end; // ENTER or CTRL + M |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
125
|
case '\x0E': { /* Next history */ } continue; // CTRL + N |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
126
|
case '\x0F': {} goto end; // CTRL + O |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
127
|
case '\x10': { /* Prior history */ } continue; // CTRL + P |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
128
|
case '\x11': { /* Start output */ } continue; // CTRL + Q |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
129
|
case '\x12': {} continue; // IGNORE CTRL + R |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
130
|
case '\x13': { /* Stop output */ } continue; // CTRL + S |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
131
|
case '\x14': { /* Swap with prior */ } continue; // CTRL + T |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
132
|
case '\x15': { line_delete_home(&l); } continue; // CTRL + U |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
133
|
case '\x16': { /* Insert char code */ } continue; // CTRL + V |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
134
|
case '\x17': { line_delete_word_home(&l); } continue; // CTRL + W |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
135
|
case '\x18': {} continue; // IGNORE CTRL + X |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
136
|
case '\x19': { /* Paste deleted */ } continue; // CTRL + Y |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
137
|
case '\x1B': switch ((c = fgetc(stdin))) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
138
|
case 'b': { line_move_word_home(&l); } continue; // ALT + B |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
139
|
case 'd': { line_delete_word_end(&l); } continue; // ALT + D |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
140
|
case 'f': { line_move_word_end(&l); } continue; // ALT + F |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
141
|
case '[': switch ((c = fgetc(stdin))) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
142
|
case '1': case '2': case '3': case '4': case '5': case '6': |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
143
|
case '7': case '8': case '9': { line_esc(&l, c); } continue; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
144
|
case 'A': { hist_move_prior(&h); } continue; // UP |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
145
|
case 'B': { hist_move_next(&h); } continue; // DOWN |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
146
|
case 'C': { line_move_right(&l); } continue; // RIGHT |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
147
|
case 'D': { line_move_left(&l); } continue; // LEFT |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
148
|
case 'F': { line_move_end(&l); } continue; // END |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
149
|
case 'H': { line_move_home(&l); } continue; // HOME |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
150
|
default: {} continue; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
151
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
152
|
default: {} continue; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
153
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
154
|
case '\x7F': { line_backspace(&l); } continue; // BACKSPACE |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
155
|
default: { line_insert(&l, c); } continue; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
156
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
157
|
} |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
158
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
159
|
end:; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
160
|
r = strndup(l.s, l.sl); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
161
|
ret:; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
162
|
tcrestore(); fputc('\n', stdout); return r; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
163
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
164
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
165
|
#undef l // h.a[h.ap] |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
166
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
167
|
/* Handle an extended ^[ sequence */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
168
|
static void line_esc(line *l, register int c) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
169
|
switch (c) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
170
|
case '2': switch ((c = fgetc(stdin))) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
171
|
case '~': { /* Insert char code */ } return; // INSERT |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
172
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
173
|
case '3': switch ((c = fgetc(stdin))) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
174
|
case '~': { line_delete(l); } return; // DELETE |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
175
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
176
|
case '5': switch ((c = fgetc(stdin))) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
177
|
case '~': { hist_move_home(&h); } return; // PAGE UP |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
178
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
179
|
case '6': switch ((c = fgetc(stdin))) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
180
|
case '~': { hist_move_end(&h); } return; // PAGE DOWN |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
181
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
182
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
183
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
184
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
185
|
/* Put stdin into raw mode */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
186
|
static inline void tcraw(void) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
187
|
if (rawflag) { return; } |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
188
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
189
|
tcgetattr(STDIN_FILENO, &tco); tcn = tco; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
190
|
if (!ateflag) { atexit(tcrestore); ateflag = true; } |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
191
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
192
|
/* No break, no CR to NL, no parity check, no strip bit, no flow control */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
193
|
tcn.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
194
|
/* No post process, 8-bit chars */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
195
|
tcn.c_oflag &= ~(OPOST); tcn.c_cflag |= (CS8); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
196
|
/* Canonical off, echo off, no extensions, no signal characters */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
197
|
tcn.c_lflag &= ~(ICANON | ECHO | IEXTEN | ISIG); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
198
|
/* Read every byte with no delay */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
199
|
tcn.c_cc[VMIN] = 1; tcn.c_cc[VTIME] = 0; |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
200
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
201
|
tcsetattr(STDIN_FILENO, TCSAFLUSH, &tcn); rawflag = true; return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
202
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
203
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
204
|
/* Restore stdin to canonical mode */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
205
|
static inline void tcrestore(void) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
206
|
tcsetattr(STDIN_FILENO, TCSAFLUSH, &tco); rawflag = false; return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
207
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
208
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
209
|
/* Get the number of columns in the terminal */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
210
|
static size_t getcols(void) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
211
|
struct winsize ws; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
212
|
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1) { return 0; } |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
213
|
return ws.ws_col; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
214
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
215
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
216
|
/* Clear the screen */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
217
|
static void clearscreen(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
218
|
fputs("\x1B[H\x1B[2J", stdout); line_refresh(l); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
219
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
220
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
221
|
/* Refresh line */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
222
|
static void line_refresh(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
223
|
fputs("\r\x1B[0K", stdout); |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
224
|
fputs(prompt, stdout); fputs(l->s, stdout); |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
225
|
fprintf(stdout, "\r\x1B[%zuC", strlen(prompt) + l->sp); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
226
|
return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
227
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
228
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
229
|
/* Reset line */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
230
|
static void line_reset(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
231
|
l->s[0] = 0; l->sp = 0; l->sl = 0; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
232
|
fputs("^C\n", stdout); line_refresh(l); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
233
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
234
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
235
|
/* Move cursor left */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
236
|
static void line_move_left(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
237
|
if (l->sp) { --l->sp; fputs("\x1B[D", stdout); } return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
238
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
239
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
240
|
/* Move cursor right */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
241
|
static void line_move_right(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
242
|
if (l->sp != l->sl) { ++l->sp; fputs("\x1B[C", stdout); } return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
243
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
244
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
245
|
/* Move cursor to the word home */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
246
|
static void line_move_word_home(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
247
|
for (; l->sp && l->s[l->sp - 1] == ' '; --l->sp); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
248
|
for (; l->sp && l->s[l->sp - 1] != ' '; --l->sp); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
249
|
line_refresh(l); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
250
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
251
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
252
|
/* Move cursor to the word end */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
253
|
static void line_move_word_end(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
254
|
for (; l->sp != l->sl && l->s[l->sp] == ' '; ++l->sp); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
255
|
for (; l->sp != l->sl && l->s[l->sp] != ' '; ++l->sp); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
256
|
line_refresh(l); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
257
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
258
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
259
|
/* Move cursor to the line home */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
260
|
static void line_move_home(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
261
|
l->sp = 0; line_refresh(l); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
262
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
263
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
264
|
/* Move cursor to the line end */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
265
|
static void line_move_end(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
266
|
l->sp = l->sl; line_refresh(l); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
267
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
268
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
269
|
/* Push character onto end of line */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
270
|
static void line_push(line *l, char c) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
271
|
if (l->sl + 1 > l->sc) { l->sc *= 2; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
272
|
l->s = xrealloc(l->s, l->sc * sizeof (*l->s)); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
273
|
} l->s[l->sl] = c; l->s[++l->sl] = 0; return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
274
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
275
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
276
|
/* Insert character at cursor */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
277
|
static int line_insert(line *l, char c) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
278
|
if (l->sl + 1 == l->sc) { /* TODO expand string */ } |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
279
|
if (l->sp == l->sl) { // Cursor is at line end |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
280
|
l->s[l->sp++] = c; l->s[++l->sl] = 0; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
281
|
return fputc(c, stdout); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
282
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
283
|
else { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
284
|
memmove(l->s + l->sp + 1, l->s + l->sp, l->sl - l->sp); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
285
|
l->s[l->sp++] = c; l->s[++l->sl] = 0; line_refresh(l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
286
|
} return c; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
287
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
288
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
289
|
/* Delete character before cursor */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
290
|
static void line_backspace(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
291
|
if (l->sp) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
292
|
memmove(l->s + l->sp - 1, l->s + l->sp, l->sl - l->sp); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
293
|
--l->sp; l->s[--l->sl] = 0; line_refresh(l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
294
|
} return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
295
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
296
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
297
|
/* Delete character at cursor */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
298
|
static void line_delete(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
299
|
if (l->sp != l->sl) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
300
|
memmove(l->s + l->sp, l->s + l->sp + 1, l->sl - l->sp); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
301
|
l->s[--l->sl] = 0; line_refresh(l); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
302
|
} return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
303
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
304
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
305
|
/* Delete the word preceeding the cursor */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
306
|
static void line_delete_word_home(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
307
|
size_t p = l->sp; |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
308
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
309
|
for (; l->sp && l->s[l->sp - 1] == ' '; --l->sp); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
310
|
for (; l->sp && l->s[l->sp - 1] != ' '; --l->sp); |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
311
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
312
|
memmove(l->s + l->sp, l->s + p, l->sl - p + 1); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
313
|
l->sl -= p - l->sp; line_refresh(l); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
314
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
315
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
316
|
/* Delete the word following the cursor */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
317
|
static void line_delete_word_end(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
318
|
size_t p = l->sp; |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
319
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
320
|
for (; p != l->sl && l->s[p] == ' '; ++p); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
321
|
for (; p != l->sl && l->s[p] != ' '; ++p); |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
322
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
323
|
memmove(l->s + l->sp, l->s + p, l->sl - p + 1); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
324
|
l->sl -= p - l->sp; line_refresh(l); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
325
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
326
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
327
|
/* Delete characters from cursor to home */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
328
|
static void line_delete_home(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
329
|
memmove(l->s, l->s + l->sp, l->sl - l->sp + 1); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
330
|
l->sl -= l->sp; l->sp = 0; line_refresh(l); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
331
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
332
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
333
|
/* Delete characters from cursor to end */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
334
|
static void line_delete_end(line *l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
335
|
l->s[(l->sl = l->sp)] = 0; line_refresh(l); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
336
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
337
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
338
|
/* Initialise history */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
339
|
static int hist_init(hist *h) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
340
|
/* FIXME do not hardcode history size */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
341
|
h->ap = 0; h->ah = 0; h->at = 0; h->al = 0; h->ac = 1000 + 1; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
342
|
if (!(h->a = xcalloc(h->ac, sizeof (*h->a)))) { return 1; } |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
343
|
/* TODO load history from file */ return 0; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
344
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
345
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
346
|
/* Free history */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
347
|
static void hist_free(hist *h) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
348
|
for (size_t i = 0; i != h->ac; ++i) { free(h->a[i].s); } free(h->a); |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
349
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
350
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
351
|
/* Move backwards in history */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
352
|
static void hist_move_prior(hist *h) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
353
|
if (h->ap != h->ah) { h->ap == 0 ? h->ap = h->ac - 1 : --h->ap; } |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
354
|
line_refresh(&h->a[h->ap]); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
355
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
356
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
357
|
/* Move forwards in history */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
358
|
static void hist_move_next(hist *h) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
359
|
register size_t an = h->ap == h->ac - 1 ? 0 : h->ap + 1; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
360
|
if (an != h->at) { h->ap = an; } |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
361
|
line_refresh(&h->a[h->ap]); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
362
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
363
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
364
|
/* Move to the start of history */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
365
|
static void hist_move_home(hist *h) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
366
|
/* TODO */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
367
|
h->ap = h->ah; line_refresh(&h->a[h->ap]); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
368
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
369
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
370
|
/* Move to the end of history */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
371
|
static void hist_move_end(hist *h) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
372
|
/* TODO */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
373
|
// h->ap = h->at; lineRefresh(&h->a[h->ap]); return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
374
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
375
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
376
|
/* Push a line onto the end of history */ |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
377
|
static void hist_push(hist *h, line l) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
378
|
if (h->al != h->ac) { |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
379
|
++h->al; h->ap = h->at; if (++h->at == h->ac) { h->at = 0; } |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
380
|
} |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
381
|
else { h->ap = h->at; if (++h->at == h->ac) { h->at = 0; } h->ah = h->at; } |
4a1246f |
Jakob Wakeling |
2023-12-28 14:53:40 |
382
|
|
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
383
|
free(h->a[h->ap].s); h->a[h->ap] = l; return; |
a1eb486 |
Jakob Wakeling |
2023-12-27 13:01:35 |
384
|
} |
|
|
|
385
|
|